perf-hwbreak.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * perf events self profiling example test case for hw breakpoints.
  3. *
  4. * This tests perf PERF_TYPE_BREAKPOINT parameters
  5. * 1) tests all variants of the break on read/write flags
  6. * 2) tests exclude_user == 0 and 1
  7. * 3) test array matches (if DAWR is supported))
  8. * 4) test different numbers of breakpoints matches
  9. *
  10. * Configure this breakpoint, then read and write the data a number of
  11. * times. Then check the output count from perf is as expected.
  12. *
  13. * Based on:
  14. * http://ozlabs.org/~anton/junkcode/perf_events_example1.c
  15. *
  16. * Copyright (C) 2018 Michael Neuling, IBM Corporation.
  17. *
  18. * This program is free software; you can redistribute it and/or
  19. * modify it under the terms of the GNU General Public License
  20. * as published by the Free Software Foundation; either version
  21. * 2 of the License, or (at your option) any later version.
  22. */
  23. #include <unistd.h>
  24. #include <assert.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/ioctl.h>
  29. #include <elf.h>
  30. #include <pthread.h>
  31. #include <sys/syscall.h>
  32. #include <linux/perf_event.h>
  33. #include <linux/hw_breakpoint.h>
  34. #include "utils.h"
  35. #define MAX_LOOPS 10000
  36. #define DAWR_LENGTH_MAX ((0x3f + 1) * 8)
  37. static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
  38. int cpu, int group_fd,
  39. unsigned long flags)
  40. {
  41. attr->size = sizeof(*attr);
  42. return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
  43. }
  44. static inline bool breakpoint_test(int len)
  45. {
  46. struct perf_event_attr attr;
  47. int fd;
  48. /* setup counters */
  49. memset(&attr, 0, sizeof(attr));
  50. attr.disabled = 1;
  51. attr.type = PERF_TYPE_BREAKPOINT;
  52. attr.bp_type = HW_BREAKPOINT_R;
  53. /* bp_addr can point anywhere but needs to be aligned */
  54. attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800;
  55. attr.bp_len = len;
  56. fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
  57. if (fd < 0)
  58. return false;
  59. close(fd);
  60. return true;
  61. }
  62. static inline bool perf_breakpoint_supported(void)
  63. {
  64. return breakpoint_test(4);
  65. }
  66. static inline bool dawr_supported(void)
  67. {
  68. return breakpoint_test(DAWR_LENGTH_MAX);
  69. }
  70. static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
  71. {
  72. int i,j;
  73. struct perf_event_attr attr;
  74. size_t res;
  75. unsigned long long breaks, needed;
  76. int readint;
  77. int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
  78. int *readintalign;
  79. volatile int *ptr;
  80. int break_fd;
  81. int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
  82. volatile int *k;
  83. /* align to 0x400 boundary as required by DAWR */
  84. readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
  85. 0xfffffffffffff800);
  86. ptr = &readint;
  87. if (arraytest)
  88. ptr = &readintalign[0];
  89. /* setup counters */
  90. memset(&attr, 0, sizeof(attr));
  91. attr.disabled = 1;
  92. attr.type = PERF_TYPE_BREAKPOINT;
  93. attr.bp_type = readwriteflag;
  94. attr.bp_addr = (__u64)ptr;
  95. attr.bp_len = sizeof(int);
  96. if (arraytest)
  97. attr.bp_len = DAWR_LENGTH_MAX;
  98. attr.exclude_user = exclude_user;
  99. break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
  100. if (break_fd < 0) {
  101. perror("sys_perf_event_open");
  102. exit(1);
  103. }
  104. /* start counters */
  105. ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
  106. /* Test a bunch of reads and writes */
  107. k = &readint;
  108. for (i = 0; i < loop_num; i++) {
  109. if (arraytest)
  110. k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
  111. j = *k;
  112. *k = j;
  113. }
  114. /* stop counters */
  115. ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
  116. /* read and check counters */
  117. res = read(break_fd, &breaks, sizeof(unsigned long long));
  118. assert(res == sizeof(unsigned long long));
  119. /* we read and write each loop, so subtract the ones we are counting */
  120. needed = 0;
  121. if (readwriteflag & HW_BREAKPOINT_R)
  122. needed += loop_num;
  123. if (readwriteflag & HW_BREAKPOINT_W)
  124. needed += loop_num;
  125. needed = needed * (1 - exclude_user);
  126. printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
  127. (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
  128. if (breaks != needed) {
  129. printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
  130. (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
  131. return 1;
  132. }
  133. close(break_fd);
  134. return 0;
  135. }
  136. static int runtest(void)
  137. {
  138. int rwflag;
  139. int exclude_user;
  140. int ret;
  141. /*
  142. * perf defines rwflag as two bits read and write and at least
  143. * one must be set. So range 1-3.
  144. */
  145. for (rwflag = 1 ; rwflag < 4; rwflag++) {
  146. for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
  147. ret = runtestsingle(rwflag, exclude_user, 0);
  148. if (ret)
  149. return ret;
  150. /* if we have the dawr, we can do an array test */
  151. if (!dawr_supported())
  152. continue;
  153. ret = runtestsingle(rwflag, exclude_user, 1);
  154. if (ret)
  155. return ret;
  156. }
  157. }
  158. return 0;
  159. }
  160. static int perf_hwbreak(void)
  161. {
  162. srand ( time(NULL) );
  163. SKIP_IF(!perf_breakpoint_supported());
  164. return runtest();
  165. }
  166. int main(int argc, char *argv[], char **envp)
  167. {
  168. return test_harness(perf_hwbreak, "perf_hwbreak");
  169. }