1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * perf events self profiling example test case for hw breakpoints.
5 * This tests perf PERF_TYPE_BREAKPOINT parameters
6 * 1) tests all variants of the break on read/write flags
7 * 2) tests exclude_user == 0 and 1
8 * 3) test array matches (if DAWR is supported))
9 * 4) test different numbers of breakpoints matches
11 * Configure this breakpoint, then read and write the data a number of
12 * times. Then check the output count from perf is as expected.
15 * http://ozlabs.org/~anton/junkcode/perf_events_example1.c
17 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
25 #include <sys/ioctl.h>
28 #include <sys/syscall.h>
29 #include <linux/perf_event.h>
30 #include <linux/hw_breakpoint.h>
33 #define MAX_LOOPS 10000
35 #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
,
41 attr
->size
= sizeof(*attr
);
42 return syscall(__NR_perf_event_open
, attr
, pid
, cpu
, group_fd
, flags
);
45 static inline bool breakpoint_test(int len
)
47 struct perf_event_attr attr
;
51 memset(&attr
, 0, sizeof(attr
));
53 attr
.type
= PERF_TYPE_BREAKPOINT
;
54 attr
.bp_type
= HW_BREAKPOINT_R
;
55 /* bp_addr can point anywhere but needs to be aligned */
56 attr
.bp_addr
= (__u64
)(&attr
) & 0xfffffffffffff800;
58 fd
= sys_perf_event_open(&attr
, 0, -1, -1, 0);
65 static inline bool perf_breakpoint_supported(void)
67 return breakpoint_test(4);
70 static inline bool dawr_supported(void)
72 return breakpoint_test(DAWR_LENGTH_MAX
);
75 static int runtestsingle(int readwriteflag
, int exclude_user
, int arraytest
)
78 struct perf_event_attr attr
;
80 unsigned long long breaks
, needed
;
82 int readintarraybig
[2*DAWR_LENGTH_MAX
/sizeof(int)];
86 int loop_num
= MAX_LOOPS
- (rand() % 100); /* provide some variability */
89 /* align to 0x400 boundary as required by DAWR */
90 readintalign
= (int *)(((unsigned long)readintarraybig
+ 0x7ff) &
95 ptr
= &readintalign
[0];
98 memset(&attr
, 0, sizeof(attr
));
100 attr
.type
= PERF_TYPE_BREAKPOINT
;
101 attr
.bp_type
= readwriteflag
;
102 attr
.bp_addr
= (__u64
)ptr
;
103 attr
.bp_len
= sizeof(int);
105 attr
.bp_len
= DAWR_LENGTH_MAX
;
106 attr
.exclude_user
= exclude_user
;
107 break_fd
= sys_perf_event_open(&attr
, 0, -1, -1, 0);
109 perror("sys_perf_event_open");
114 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
116 /* Test a bunch of reads and writes */
118 for (i
= 0; i
< loop_num
; i
++) {
120 k
= &(readintalign
[i
% (DAWR_LENGTH_MAX
/sizeof(int))]);
127 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
129 /* read and check counters */
130 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
131 assert(res
== sizeof(unsigned long long));
132 /* we read and write each loop, so subtract the ones we are counting */
134 if (readwriteflag
& HW_BREAKPOINT_R
)
136 if (readwriteflag
& HW_BREAKPOINT_W
)
138 needed
= needed
* (1 - exclude_user
);
139 printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
140 (unsigned long int)ptr
, breaks
, loop_num
, readwriteflag
, exclude_user
, arraytest
);
141 if (breaks
!= needed
) {
142 printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
143 (unsigned long int)ptr
, breaks
, needed
, loop_num
, readwriteflag
, exclude_user
);
151 static int runtest_dar_outside(void)
154 volatile __u16 temp16
;
155 volatile __u64 temp64
;
156 struct perf_event_attr attr
;
158 unsigned long long breaks
;
164 perror("malloc failed");
169 memset(&attr
, 0, sizeof(attr
));
171 attr
.type
= PERF_TYPE_BREAKPOINT
;
172 attr
.exclude_kernel
= 1;
174 attr
.exclude_guest
= 1;
175 attr
.bp_type
= HW_BREAKPOINT_RW
;
176 /* watch middle half of target array */
177 attr
.bp_addr
= (__u64
)(target
+ 2);
179 break_fd
= sys_perf_event_open(&attr
, 0, -1, -1, 0);
182 perror("sys_perf_event_open");
187 ioctl(break_fd
, PERF_EVENT_IOC_RESET
);
188 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
189 temp16
= *((__u16
*)target
);
190 *((__u16
*)target
) = temp16
;
191 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
192 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
193 assert(res
== sizeof(unsigned long long));
195 printf("TESTED: No overlap\n");
197 printf("FAILED: No overlap: %lld != 0\n", breaks
);
202 ioctl(break_fd
, PERF_EVENT_IOC_RESET
);
203 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
204 temp16
= *((__u16
*)(target
+ 1));
205 *((__u16
*)(target
+ 1)) = temp16
;
206 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
207 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
208 assert(res
== sizeof(unsigned long long));
210 printf("TESTED: Partial overlap\n");
212 printf("FAILED: Partial overlap: %lld != 2\n", breaks
);
217 ioctl(break_fd
, PERF_EVENT_IOC_RESET
);
218 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
219 temp16
= *((__u16
*)(target
+ 5));
220 *((__u16
*)(target
+ 5)) = temp16
;
221 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
222 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
223 assert(res
== sizeof(unsigned long long));
225 printf("TESTED: Partial overlap\n");
227 printf("FAILED: Partial overlap: %lld != 2\n", breaks
);
232 ioctl(break_fd
, PERF_EVENT_IOC_RESET
);
233 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
234 temp16
= *((__u16
*)(target
+ 6));
235 *((__u16
*)(target
+ 6)) = temp16
;
236 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
237 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
238 assert(res
== sizeof(unsigned long long));
240 printf("TESTED: No overlap\n");
242 printf("FAILED: No overlap: %lld != 0\n", breaks
);
247 ioctl(break_fd
, PERF_EVENT_IOC_RESET
);
248 ioctl(break_fd
, PERF_EVENT_IOC_ENABLE
);
249 temp64
= *((__u64
*)target
);
250 *((__u64
*)target
) = temp64
;
251 ioctl(break_fd
, PERF_EVENT_IOC_DISABLE
);
252 res
= read(break_fd
, &breaks
, sizeof(unsigned long long));
253 assert(res
== sizeof(unsigned long long));
255 printf("TESTED: Full overlap\n");
257 printf("FAILED: Full overlap: %lld != 2\n", breaks
);
266 static int runtest(void)
273 * perf defines rwflag as two bits read and write and at least
274 * one must be set. So range 1-3.
276 for (rwflag
= 1 ; rwflag
< 4; rwflag
++) {
277 for (exclude_user
= 0 ; exclude_user
< 2; exclude_user
++) {
278 ret
= runtestsingle(rwflag
, exclude_user
, 0);
282 /* if we have the dawr, we can do an array test */
283 if (!dawr_supported())
285 ret
= runtestsingle(rwflag
, exclude_user
, 1);
291 ret
= runtest_dar_outside();
296 static int perf_hwbreak(void)
298 srand ( time(NULL
) );
300 SKIP_IF(!perf_breakpoint_supported());
305 int main(int argc
, char *argv
[], char **envp
)
307 return test_harness(perf_hwbreak
, "perf_hwbreak");