1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * perf events self profiling example test case for hw breakpoints.
4 *
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
10 *
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.
13 *
14 * Based on:
15 * http://ozlabs.org/~anton/junkcode/perf_events_example1.c
16 *
17 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
18 */
19
20#define _GNU_SOURCE
21
22#include <unistd.h>
23#include <assert.h>
24#include <sched.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <signal.h>
28#include <string.h>
29#include <sys/ioctl.h>
30#include <sys/wait.h>
31#include <sys/ptrace.h>
32#include <sys/resource.h>
33#include <sys/sysinfo.h>
34#include <asm/ptrace.h>
35#include <elf.h>
36#include <pthread.h>
37#include <sys/syscall.h>
38#include <linux/perf_event.h>
39#include <linux/hw_breakpoint.h>
40#include "utils.h"
41
42#ifndef PPC_DEBUG_FEATURE_DATA_BP_ARCH_31
43#define PPC_DEBUG_FEATURE_DATA_BP_ARCH_31 0x20
44#endif
45
46#define MAX_LOOPS 10000
47
48#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)
49
50int nprocs;
51
52static volatile int a = 10;
53static volatile int b = 10;
54static volatile char c[512 + 8] __attribute__((aligned(512)));
55
56static void perf_event_attr_set(struct perf_event_attr *attr,
57 __u32 type, __u64 addr, __u64 len,
58 bool exclude_user)
59{
60 memset(attr, 0, sizeof(struct perf_event_attr));
61 attr->type = PERF_TYPE_BREAKPOINT;
62 attr->size = sizeof(struct perf_event_attr);
63 attr->bp_type = type;
64 attr->bp_addr = addr;
65 attr->bp_len = len;
66 attr->exclude_kernel = 1;
67 attr->exclude_hv = 1;
68 attr->exclude_guest = 1;
69 attr->exclude_user = exclude_user;
70 attr->disabled = 1;
71}
72
73static int
74perf_process_event_open_exclude_user(__u32 type, __u64 addr, __u64 len, bool exclude_user)
75{
76 struct perf_event_attr attr;
77
78 perf_event_attr_set(attr: &attr, type, addr, len, exclude_user);
79 return syscall(__NR_perf_event_open, &attr, getpid(), -1, -1, 0);
80}
81
82static int perf_process_event_open(__u32 type, __u64 addr, __u64 len)
83{
84 struct perf_event_attr attr;
85
86 perf_event_attr_set(attr: &attr, type, addr, len, exclude_user: 0);
87 return syscall(__NR_perf_event_open, &attr, getpid(), -1, -1, 0);
88}
89
90static int perf_cpu_event_open(long cpu, __u32 type, __u64 addr, __u64 len)
91{
92 struct perf_event_attr attr;
93
94 perf_event_attr_set(attr: &attr, type, addr, len, exclude_user: 0);
95 return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
96}
97
98static void close_fds(int *fd, int n)
99{
100 int i;
101
102 for (i = 0; i < n; i++)
103 close(fd[i]);
104}
105
106static unsigned long read_fds(int *fd, int n)
107{
108 int i;
109 unsigned long c = 0;
110 unsigned long count = 0;
111 size_t res;
112
113 for (i = 0; i < n; i++) {
114 res = read(fd[i], &c, sizeof(c));
115 assert(res == sizeof(unsigned long long));
116 count += c;
117 }
118 return count;
119}
120
121static void reset_fds(int *fd, int n)
122{
123 int i;
124
125 for (i = 0; i < n; i++)
126 ioctl(fd[i], PERF_EVENT_IOC_RESET);
127}
128
129static void enable_fds(int *fd, int n)
130{
131 int i;
132
133 for (i = 0; i < n; i++)
134 ioctl(fd[i], PERF_EVENT_IOC_ENABLE);
135}
136
137static void disable_fds(int *fd, int n)
138{
139 int i;
140
141 for (i = 0; i < n; i++)
142 ioctl(fd[i], PERF_EVENT_IOC_DISABLE);
143}
144
145static int perf_systemwide_event_open(int *fd, __u32 type, __u64 addr, __u64 len)
146{
147 int i, ncpus, cpu, ret = 0;
148 struct rlimit rlim;
149 cpu_set_t *mask;
150 size_t size;
151
152 if (getrlimit(RLIMIT_NOFILE, &rlim)) {
153 perror("getrlimit");
154 return -1;
155 }
156 rlim.rlim_cur = 65536;
157 if (setrlimit(RLIMIT_NOFILE, &rlim)) {
158 perror("setrlimit");
159 return -1;
160 }
161
162 ncpus = get_nprocs_conf();
163 size = CPU_ALLOC_SIZE(ncpus);
164 mask = CPU_ALLOC(ncpus);
165 if (!mask) {
166 perror("malloc");
167 return -1;
168 }
169
170 CPU_ZERO_S(size, mask);
171
172 if (sched_getaffinity(pid: 0, mask: size, mask)) {
173 perror("sched_getaffinity");
174 ret = -1;
175 goto done;
176 }
177
178 for (i = 0, cpu = 0; i < nprocs && cpu < ncpus; cpu++) {
179 if (!CPU_ISSET_S(cpu, size, mask))
180 continue;
181 fd[i] = perf_cpu_event_open(cpu, type, addr, len);
182 if (fd[i] < 0) {
183 perror("perf_systemwide_event_open");
184 close_fds(fd, n: i);
185 ret = fd[i];
186 goto done;
187 }
188 i++;
189 }
190
191 if (i < nprocs) {
192 printf("Error: Number of online cpus reduced since start of test: %d < %d\n", i, nprocs);
193 close_fds(fd, n: i);
194 ret = -1;
195 }
196
197done:
198 CPU_FREE(mask);
199 return ret;
200}
201
202static inline bool breakpoint_test(int len)
203{
204 int fd;
205
206 /* bp_addr can point anywhere but needs to be aligned */
207 fd = perf_process_event_open(type: HW_BREAKPOINT_R, addr: (__u64)(&fd) & 0xfffffffffffff800, len);
208 if (fd < 0)
209 return false;
210 close(fd);
211 return true;
212}
213
214static inline bool perf_breakpoint_supported(void)
215{
216 return breakpoint_test(len: 4);
217}
218
219static inline bool dawr_supported(void)
220{
221 return breakpoint_test(DAWR_LENGTH_MAX);
222}
223
224static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
225{
226 int i,j;
227 size_t res;
228 unsigned long long breaks, needed;
229 int readint;
230 int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
231 int *readintalign;
232 volatile int *ptr;
233 int break_fd;
234 int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
235 volatile int *k;
236 __u64 len;
237
238 /* align to 0x400 boundary as required by DAWR */
239 readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
240 0xfffffffffffff800);
241
242 ptr = &readint;
243 if (arraytest)
244 ptr = &readintalign[0];
245
246 len = arraytest ? DAWR_LENGTH_MAX : sizeof(int);
247 break_fd = perf_process_event_open_exclude_user(type: readwriteflag, addr: (__u64)ptr,
248 len, exclude_user);
249 if (break_fd < 0) {
250 perror("perf_process_event_open_exclude_user");
251 exit(1);
252 }
253
254 /* start counters */
255 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
256
257 /* Test a bunch of reads and writes */
258 k = &readint;
259 for (i = 0; i < loop_num; i++) {
260 if (arraytest)
261 k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
262
263 j = *k;
264 *k = j;
265 }
266
267 /* stop counters */
268 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
269
270 /* read and check counters */
271 res = read(break_fd, &breaks, sizeof(unsigned long long));
272 assert(res == sizeof(unsigned long long));
273 /* we read and write each loop, so subtract the ones we are counting */
274 needed = 0;
275 if (readwriteflag & HW_BREAKPOINT_R)
276 needed += loop_num;
277 if (readwriteflag & HW_BREAKPOINT_W)
278 needed += loop_num;
279 needed = needed * (1 - exclude_user);
280 printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
281 (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
282 if (breaks != needed) {
283 printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
284 (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
285 return 1;
286 }
287 close(break_fd);
288
289 return 0;
290}
291
292static int runtest_dar_outside(void)
293{
294 void *target;
295 volatile __u16 temp16;
296 volatile __u64 temp64;
297 int break_fd;
298 unsigned long long breaks;
299 int fail = 0;
300 size_t res;
301
302 target = malloc(8);
303 if (!target) {
304 perror("malloc failed");
305 exit(EXIT_FAILURE);
306 }
307
308 /* watch middle half of target array */
309 break_fd = perf_process_event_open(type: HW_BREAKPOINT_RW, addr: (__u64)(target + 2), len: 4);
310 if (break_fd < 0) {
311 free(target);
312 perror("perf_process_event_open");
313 exit(EXIT_FAILURE);
314 }
315
316 /* Shouldn't hit. */
317 ioctl(break_fd, PERF_EVENT_IOC_RESET);
318 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
319 temp16 = *((__u16 *)target);
320 *((__u16 *)target) = temp16;
321 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
322 res = read(break_fd, &breaks, sizeof(unsigned long long));
323 assert(res == sizeof(unsigned long long));
324 if (breaks == 0) {
325 printf("TESTED: No overlap\n");
326 } else {
327 printf("FAILED: No overlap: %lld != 0\n", breaks);
328 fail = 1;
329 }
330
331 /* Hit */
332 ioctl(break_fd, PERF_EVENT_IOC_RESET);
333 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
334 temp16 = *((__u16 *)(target + 1));
335 *((__u16 *)(target + 1)) = temp16;
336 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
337 res = read(break_fd, &breaks, sizeof(unsigned long long));
338 assert(res == sizeof(unsigned long long));
339 if (breaks == 2) {
340 printf("TESTED: Partial overlap\n");
341 } else {
342 printf("FAILED: Partial overlap: %lld != 2\n", breaks);
343 fail = 1;
344 }
345
346 /* Hit */
347 ioctl(break_fd, PERF_EVENT_IOC_RESET);
348 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
349 temp16 = *((__u16 *)(target + 5));
350 *((__u16 *)(target + 5)) = temp16;
351 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
352 res = read(break_fd, &breaks, sizeof(unsigned long long));
353 assert(res == sizeof(unsigned long long));
354 if (breaks == 2) {
355 printf("TESTED: Partial overlap\n");
356 } else {
357 printf("FAILED: Partial overlap: %lld != 2\n", breaks);
358 fail = 1;
359 }
360
361 /* Shouldn't Hit */
362 ioctl(break_fd, PERF_EVENT_IOC_RESET);
363 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
364 temp16 = *((__u16 *)(target + 6));
365 *((__u16 *)(target + 6)) = temp16;
366 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
367 res = read(break_fd, &breaks, sizeof(unsigned long long));
368 assert(res == sizeof(unsigned long long));
369 if (breaks == 0) {
370 printf("TESTED: No overlap\n");
371 } else {
372 printf("FAILED: No overlap: %lld != 0\n", breaks);
373 fail = 1;
374 }
375
376 /* Hit */
377 ioctl(break_fd, PERF_EVENT_IOC_RESET);
378 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
379 temp64 = *((__u64 *)target);
380 *((__u64 *)target) = temp64;
381 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
382 res = read(break_fd, &breaks, sizeof(unsigned long long));
383 assert(res == sizeof(unsigned long long));
384 if (breaks == 2) {
385 printf("TESTED: Full overlap\n");
386 } else {
387 printf("FAILED: Full overlap: %lld != 2\n", breaks);
388 fail = 1;
389 }
390
391 free(target);
392 close(break_fd);
393 return fail;
394}
395
396static void multi_dawr_workload(void)
397{
398 a += 10;
399 b += 10;
400 c[512 + 1] += 'a';
401}
402
403static int test_process_multi_diff_addr(void)
404{
405 unsigned long long breaks1 = 0, breaks2 = 0;
406 int fd1, fd2;
407 char *desc = "Process specific, Two events, diff addr";
408 size_t res;
409
410 fd1 = perf_process_event_open(type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
411 if (fd1 < 0) {
412 perror("perf_process_event_open");
413 exit(EXIT_FAILURE);
414 }
415
416 fd2 = perf_process_event_open(type: HW_BREAKPOINT_RW, addr: (__u64)&b, len: (__u64)sizeof(b));
417 if (fd2 < 0) {
418 close(fd1);
419 perror("perf_process_event_open");
420 exit(EXIT_FAILURE);
421 }
422
423 ioctl(fd1, PERF_EVENT_IOC_RESET);
424 ioctl(fd2, PERF_EVENT_IOC_RESET);
425 ioctl(fd1, PERF_EVENT_IOC_ENABLE);
426 ioctl(fd2, PERF_EVENT_IOC_ENABLE);
427 multi_dawr_workload();
428 ioctl(fd1, PERF_EVENT_IOC_DISABLE);
429 ioctl(fd2, PERF_EVENT_IOC_DISABLE);
430
431 res = read(fd1, &breaks1, sizeof(breaks1));
432 assert(res == sizeof(unsigned long long));
433 res = read(fd2, &breaks2, sizeof(breaks2));
434 assert(res == sizeof(unsigned long long));
435
436 close(fd1);
437 close(fd2);
438
439 if (breaks1 != 2 || breaks2 != 2) {
440 printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2);
441 return 1;
442 }
443
444 printf("TESTED: %s\n", desc);
445 return 0;
446}
447
448static int test_process_multi_same_addr(void)
449{
450 unsigned long long breaks1 = 0, breaks2 = 0;
451 int fd1, fd2;
452 char *desc = "Process specific, Two events, same addr";
453 size_t res;
454
455 fd1 = perf_process_event_open(type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
456 if (fd1 < 0) {
457 perror("perf_process_event_open");
458 exit(EXIT_FAILURE);
459 }
460
461 fd2 = perf_process_event_open(type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
462 if (fd2 < 0) {
463 close(fd1);
464 perror("perf_process_event_open");
465 exit(EXIT_FAILURE);
466 }
467
468 ioctl(fd1, PERF_EVENT_IOC_RESET);
469 ioctl(fd2, PERF_EVENT_IOC_RESET);
470 ioctl(fd1, PERF_EVENT_IOC_ENABLE);
471 ioctl(fd2, PERF_EVENT_IOC_ENABLE);
472 multi_dawr_workload();
473 ioctl(fd1, PERF_EVENT_IOC_DISABLE);
474 ioctl(fd2, PERF_EVENT_IOC_DISABLE);
475
476 res = read(fd1, &breaks1, sizeof(breaks1));
477 assert(res == sizeof(unsigned long long));
478 res = read(fd2, &breaks2, sizeof(breaks2));
479 assert(res == sizeof(unsigned long long));
480
481 close(fd1);
482 close(fd2);
483
484 if (breaks1 != 2 || breaks2 != 2) {
485 printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2);
486 return 1;
487 }
488
489 printf("TESTED: %s\n", desc);
490 return 0;
491}
492
493static int test_process_multi_diff_addr_ro_wo(void)
494{
495 unsigned long long breaks1 = 0, breaks2 = 0;
496 int fd1, fd2;
497 char *desc = "Process specific, Two events, diff addr, one is RO, other is WO";
498 size_t res;
499
500 fd1 = perf_process_event_open(type: HW_BREAKPOINT_W, addr: (__u64)&a, len: (__u64)sizeof(a));
501 if (fd1 < 0) {
502 perror("perf_process_event_open");
503 exit(EXIT_FAILURE);
504 }
505
506 fd2 = perf_process_event_open(type: HW_BREAKPOINT_R, addr: (__u64)&b, len: (__u64)sizeof(b));
507 if (fd2 < 0) {
508 close(fd1);
509 perror("perf_process_event_open");
510 exit(EXIT_FAILURE);
511 }
512
513 ioctl(fd1, PERF_EVENT_IOC_RESET);
514 ioctl(fd2, PERF_EVENT_IOC_RESET);
515 ioctl(fd1, PERF_EVENT_IOC_ENABLE);
516 ioctl(fd2, PERF_EVENT_IOC_ENABLE);
517 multi_dawr_workload();
518 ioctl(fd1, PERF_EVENT_IOC_DISABLE);
519 ioctl(fd2, PERF_EVENT_IOC_DISABLE);
520
521 res = read(fd1, &breaks1, sizeof(breaks1));
522 assert(res == sizeof(unsigned long long));
523 res = read(fd2, &breaks2, sizeof(breaks2));
524 assert(res == sizeof(unsigned long long));
525
526 close(fd1);
527 close(fd2);
528
529 if (breaks1 != 1 || breaks2 != 1) {
530 printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2);
531 return 1;
532 }
533
534 printf("TESTED: %s\n", desc);
535 return 0;
536}
537
538static int test_process_multi_same_addr_ro_wo(void)
539{
540 unsigned long long breaks1 = 0, breaks2 = 0;
541 int fd1, fd2;
542 char *desc = "Process specific, Two events, same addr, one is RO, other is WO";
543 size_t res;
544
545 fd1 = perf_process_event_open(type: HW_BREAKPOINT_R, addr: (__u64)&a, len: (__u64)sizeof(a));
546 if (fd1 < 0) {
547 perror("perf_process_event_open");
548 exit(EXIT_FAILURE);
549 }
550
551 fd2 = perf_process_event_open(type: HW_BREAKPOINT_W, addr: (__u64)&a, len: (__u64)sizeof(a));
552 if (fd2 < 0) {
553 close(fd1);
554 perror("perf_process_event_open");
555 exit(EXIT_FAILURE);
556 }
557
558 ioctl(fd1, PERF_EVENT_IOC_RESET);
559 ioctl(fd2, PERF_EVENT_IOC_RESET);
560 ioctl(fd1, PERF_EVENT_IOC_ENABLE);
561 ioctl(fd2, PERF_EVENT_IOC_ENABLE);
562 multi_dawr_workload();
563 ioctl(fd1, PERF_EVENT_IOC_DISABLE);
564 ioctl(fd2, PERF_EVENT_IOC_DISABLE);
565
566 res = read(fd1, &breaks1, sizeof(breaks1));
567 assert(res == sizeof(unsigned long long));
568 res = read(fd2, &breaks2, sizeof(breaks2));
569 assert(res == sizeof(unsigned long long));
570
571 close(fd1);
572 close(fd2);
573
574 if (breaks1 != 1 || breaks2 != 1) {
575 printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2);
576 return 1;
577 }
578
579 printf("TESTED: %s\n", desc);
580 return 0;
581}
582
583static int test_syswide_multi_diff_addr(void)
584{
585 unsigned long long breaks1 = 0, breaks2 = 0;
586 int *fd1 = malloc(nprocs * sizeof(int));
587 int *fd2 = malloc(nprocs * sizeof(int));
588 char *desc = "Systemwide, Two events, diff addr";
589 int ret;
590
591 ret = perf_systemwide_event_open(fd: fd1, type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
592 if (ret)
593 exit(EXIT_FAILURE);
594
595 ret = perf_systemwide_event_open(fd: fd2, type: HW_BREAKPOINT_RW, addr: (__u64)&b, len: (__u64)sizeof(b));
596 if (ret) {
597 close_fds(fd: fd1, n: nprocs);
598 exit(EXIT_FAILURE);
599 }
600
601 reset_fds(fd: fd1, n: nprocs);
602 reset_fds(fd: fd2, n: nprocs);
603 enable_fds(fd: fd1, n: nprocs);
604 enable_fds(fd: fd2, n: nprocs);
605 multi_dawr_workload();
606 disable_fds(fd: fd1, n: nprocs);
607 disable_fds(fd: fd2, n: nprocs);
608
609 breaks1 = read_fds(fd: fd1, n: nprocs);
610 breaks2 = read_fds(fd: fd2, n: nprocs);
611
612 close_fds(fd: fd1, n: nprocs);
613 close_fds(fd: fd2, n: nprocs);
614
615 free(fd1);
616 free(fd2);
617
618 if (breaks1 != 2 || breaks2 != 2) {
619 printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2);
620 return 1;
621 }
622
623 printf("TESTED: %s\n", desc);
624 return 0;
625}
626
627static int test_syswide_multi_same_addr(void)
628{
629 unsigned long long breaks1 = 0, breaks2 = 0;
630 int *fd1 = malloc(nprocs * sizeof(int));
631 int *fd2 = malloc(nprocs * sizeof(int));
632 char *desc = "Systemwide, Two events, same addr";
633 int ret;
634
635 ret = perf_systemwide_event_open(fd: fd1, type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
636 if (ret)
637 exit(EXIT_FAILURE);
638
639 ret = perf_systemwide_event_open(fd: fd2, type: HW_BREAKPOINT_RW, addr: (__u64)&a, len: (__u64)sizeof(a));
640 if (ret) {
641 close_fds(fd: fd1, n: nprocs);
642 exit(EXIT_FAILURE);
643 }
644
645 reset_fds(fd: fd1, n: nprocs);
646 reset_fds(fd: fd2, n: nprocs);
647 enable_fds(fd: fd1, n: nprocs);
648 enable_fds(fd: fd2, n: nprocs);
649 multi_dawr_workload();
650 disable_fds(fd: fd1, n: nprocs);
651 disable_fds(fd: fd2, n: nprocs);
652
653 breaks1 = read_fds(fd: fd1, n: nprocs);
654 breaks2 = read_fds(fd: fd2, n: nprocs);
655
656 close_fds(fd: fd1, n: nprocs);
657 close_fds(fd: fd2, n: nprocs);
658
659 free(fd1);
660 free(fd2);
661
662 if (breaks1 != 2 || breaks2 != 2) {
663 printf("FAILED: %s: %lld != 2 || %lld != 2\n", desc, breaks1, breaks2);
664 return 1;
665 }
666
667 printf("TESTED: %s\n", desc);
668 return 0;
669}
670
671static int test_syswide_multi_diff_addr_ro_wo(void)
672{
673 unsigned long long breaks1 = 0, breaks2 = 0;
674 int *fd1 = malloc(nprocs * sizeof(int));
675 int *fd2 = malloc(nprocs * sizeof(int));
676 char *desc = "Systemwide, Two events, diff addr, one is RO, other is WO";
677 int ret;
678
679 ret = perf_systemwide_event_open(fd: fd1, type: HW_BREAKPOINT_W, addr: (__u64)&a, len: (__u64)sizeof(a));
680 if (ret)
681 exit(EXIT_FAILURE);
682
683 ret = perf_systemwide_event_open(fd: fd2, type: HW_BREAKPOINT_R, addr: (__u64)&b, len: (__u64)sizeof(b));
684 if (ret) {
685 close_fds(fd: fd1, n: nprocs);
686 exit(EXIT_FAILURE);
687 }
688
689 reset_fds(fd: fd1, n: nprocs);
690 reset_fds(fd: fd2, n: nprocs);
691 enable_fds(fd: fd1, n: nprocs);
692 enable_fds(fd: fd2, n: nprocs);
693 multi_dawr_workload();
694 disable_fds(fd: fd1, n: nprocs);
695 disable_fds(fd: fd2, n: nprocs);
696
697 breaks1 = read_fds(fd: fd1, n: nprocs);
698 breaks2 = read_fds(fd: fd2, n: nprocs);
699
700 close_fds(fd: fd1, n: nprocs);
701 close_fds(fd: fd2, n: nprocs);
702
703 free(fd1);
704 free(fd2);
705
706 if (breaks1 != 1 || breaks2 != 1) {
707 printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2);
708 return 1;
709 }
710
711 printf("TESTED: %s\n", desc);
712 return 0;
713}
714
715static int test_syswide_multi_same_addr_ro_wo(void)
716{
717 unsigned long long breaks1 = 0, breaks2 = 0;
718 int *fd1 = malloc(nprocs * sizeof(int));
719 int *fd2 = malloc(nprocs * sizeof(int));
720 char *desc = "Systemwide, Two events, same addr, one is RO, other is WO";
721 int ret;
722
723 ret = perf_systemwide_event_open(fd: fd1, type: HW_BREAKPOINT_W, addr: (__u64)&a, len: (__u64)sizeof(a));
724 if (ret)
725 exit(EXIT_FAILURE);
726
727 ret = perf_systemwide_event_open(fd: fd2, type: HW_BREAKPOINT_R, addr: (__u64)&a, len: (__u64)sizeof(a));
728 if (ret) {
729 close_fds(fd: fd1, n: nprocs);
730 exit(EXIT_FAILURE);
731 }
732
733 reset_fds(fd: fd1, n: nprocs);
734 reset_fds(fd: fd2, n: nprocs);
735 enable_fds(fd: fd1, n: nprocs);
736 enable_fds(fd: fd2, n: nprocs);
737 multi_dawr_workload();
738 disable_fds(fd: fd1, n: nprocs);
739 disable_fds(fd: fd2, n: nprocs);
740
741 breaks1 = read_fds(fd: fd1, n: nprocs);
742 breaks2 = read_fds(fd: fd2, n: nprocs);
743
744 close_fds(fd: fd1, n: nprocs);
745 close_fds(fd: fd2, n: nprocs);
746
747 free(fd1);
748 free(fd2);
749
750 if (breaks1 != 1 || breaks2 != 1) {
751 printf("FAILED: %s: %lld != 1 || %lld != 1\n", desc, breaks1, breaks2);
752 return 1;
753 }
754
755 printf("TESTED: %s\n", desc);
756 return 0;
757}
758
759static int runtest_multi_dawr(void)
760{
761 int ret = 0;
762
763 ret |= test_process_multi_diff_addr();
764 ret |= test_process_multi_same_addr();
765 ret |= test_process_multi_diff_addr_ro_wo();
766 ret |= test_process_multi_same_addr_ro_wo();
767 ret |= test_syswide_multi_diff_addr();
768 ret |= test_syswide_multi_same_addr();
769 ret |= test_syswide_multi_diff_addr_ro_wo();
770 ret |= test_syswide_multi_same_addr_ro_wo();
771
772 return ret;
773}
774
775static int runtest_unaligned_512bytes(void)
776{
777 unsigned long long breaks = 0;
778 int fd;
779 char *desc = "Process specific, 512 bytes, unaligned";
780 __u64 addr = (__u64)&c + 8;
781 size_t res;
782
783 fd = perf_process_event_open(type: HW_BREAKPOINT_RW, addr, len: 512);
784 if (fd < 0) {
785 perror("perf_process_event_open");
786 exit(EXIT_FAILURE);
787 }
788
789 ioctl(fd, PERF_EVENT_IOC_RESET);
790 ioctl(fd, PERF_EVENT_IOC_ENABLE);
791 multi_dawr_workload();
792 ioctl(fd, PERF_EVENT_IOC_DISABLE);
793
794 res = read(fd, &breaks, sizeof(breaks));
795 assert(res == sizeof(unsigned long long));
796
797 close(fd);
798
799 if (breaks != 2) {
800 printf("FAILED: %s: %lld != 2\n", desc, breaks);
801 return 1;
802 }
803
804 printf("TESTED: %s\n", desc);
805 return 0;
806}
807
808/* There is no perf api to find number of available watchpoints. Use ptrace. */
809static int get_nr_wps(bool *arch_31)
810{
811 struct ppc_debug_info dbginfo;
812 int child_pid;
813
814 child_pid = fork();
815 if (!child_pid) {
816 int ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
817 if (ret) {
818 perror("PTRACE_TRACEME failed\n");
819 exit(EXIT_FAILURE);
820 }
821 kill(getpid(), SIGUSR1);
822
823 sleep(1);
824 exit(EXIT_SUCCESS);
825 }
826
827 wait(NULL);
828 if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo)) {
829 perror("Can't get breakpoint info");
830 exit(EXIT_FAILURE);
831 }
832
833 *arch_31 = !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_ARCH_31);
834 return dbginfo.num_data_bps;
835}
836
837static int runtest(void)
838{
839 int rwflag;
840 int exclude_user;
841 int ret;
842 bool dawr = dawr_supported();
843 bool arch_31 = false;
844 int nr_wps = get_nr_wps(arch_31: &arch_31);
845
846 /*
847 * perf defines rwflag as two bits read and write and at least
848 * one must be set. So range 1-3.
849 */
850 for (rwflag = 1 ; rwflag < 4; rwflag++) {
851 for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
852 ret = runtestsingle(readwriteflag: rwflag, exclude_user, arraytest: 0);
853 if (ret)
854 return ret;
855
856 /* if we have the dawr, we can do an array test */
857 if (!dawr)
858 continue;
859 ret = runtestsingle(readwriteflag: rwflag, exclude_user, arraytest: 1);
860 if (ret)
861 return ret;
862 }
863 }
864
865 ret = runtest_dar_outside();
866 if (ret)
867 return ret;
868
869 if (dawr && nr_wps > 1) {
870 nprocs = get_nprocs();
871 ret = runtest_multi_dawr();
872 if (ret)
873 return ret;
874 }
875
876 if (dawr && arch_31)
877 ret = runtest_unaligned_512bytes();
878
879 return ret;
880}
881
882
883static int perf_hwbreak(void)
884{
885 srand ( time(NULL) );
886
887 SKIP_IF_MSG(!perf_breakpoint_supported(), "Perf breakpoints not supported");
888
889 return runtest();
890}
891
892int main(int argc, char *argv[], char **envp)
893{
894 return test_harness(perf_hwbreak, "perf_hwbreak");
895}
896

source code of linux/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c