// SPDX-License-Identifier: GPL-2.0-or-later /* * perf events self profiling example test case for hw breakpoints. * * This tests perf PERF_TYPE_BREAKPOINT parameters * 1) tests all variants of the break on read/write flags * 2) tests exclude_user == 0 and 1 * 3) test array matches (if DAWR is supported)) * 4) test different numbers of breakpoints matches * * Configure this breakpoint, then read and write the data a number of * times. Then check the output count from perf is as expected. * * Based on: * http://ozlabs.org/~anton/junkcode/perf_events_example1.c * * Copyright (C) 2018 Michael Neuling, IBM Corporation.
*/
if (sched_getaffinity(0, size, mask)) {
perror("sched_getaffinity");
ret = -1; goto done;
}
for (i = 0, cpu = 0; i < nprocs && cpu < ncpus; cpu++) { if (!CPU_ISSET_S(cpu, size, mask)) continue;
fd[i] = perf_cpu_event_open(cpu, type, addr, len); if (fd[i] < 0) {
perror("perf_systemwide_event_open");
close_fds(fd, i);
ret = fd[i]; goto done;
}
i++;
}
if (i < nprocs) {
printf("Error: Number of online cpus reduced since start of test: %d < %d\n", i, nprocs);
close_fds(fd, i);
ret = -1;
}
done:
CPU_FREE(mask); return ret;
}
staticinlinebool breakpoint_test(int len)
{ int fd;
/* bp_addr can point anywhere but needs to be aligned */
fd = perf_process_event_open(HW_BREAKPOINT_R, (__u64)(&fd) & 0xfffffffffffff800, len); if (fd < 0) returnfalse;
close(fd); returntrue;
}
staticint runtestsingle(int readwriteflag, int exclude_user, int arraytest)
{ int i,j;
size_t res; unsignedlonglong breaks, needed; int readint; int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)]; int *readintalign; volatileint *ptr; int break_fd; int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */ volatileint *k;
__u64 len;
/* align to 0x400 boundary as required by DAWR */
readintalign = (int *)(((unsignedlong)readintarraybig + 0x7ff) &
0xfffffffffffff800);
ptr = &readint; if (arraytest)
ptr = &readintalign[0];
/* Test a bunch of reads and writes */
k = &readint; for (i = 0; i < loop_num; i++) { if (arraytest)
k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
staticint test_process_multi_diff_addr_ro_wo(void)
{ unsignedlonglong breaks1 = 0, breaks2 = 0; int fd1, fd2; char *desc = "Process specific, Two events, diff addr, one is RO, other is WO";
size_t res;
staticint test_process_multi_same_addr_ro_wo(void)
{ unsignedlonglong breaks1 = 0, breaks2 = 0; int fd1, fd2; char *desc = "Process specific, Two events, same addr, one is RO, other is WO";
size_t res;
staticint test_syswide_multi_diff_addr_ro_wo(void)
{ unsignedlonglong breaks1 = 0, breaks2 = 0; int *fd1 = malloc(nprocs * sizeof(int)); int *fd2 = malloc(nprocs * sizeof(int)); char *desc = "Systemwide, Two events, diff addr, one is RO, other is WO"; int ret;
ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); if (ret) exit(EXIT_FAILURE);
ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_R, (__u64)&b, (__u64)sizeof(b)); if (ret) {
close_fds(fd1, nprocs); exit(EXIT_FAILURE);
}
staticint test_syswide_multi_same_addr_ro_wo(void)
{ unsignedlonglong breaks1 = 0, breaks2 = 0; int *fd1 = malloc(nprocs * sizeof(int)); int *fd2 = malloc(nprocs * sizeof(int)); char *desc = "Systemwide, Two events, same addr, one is RO, other is WO"; int ret;
ret = perf_systemwide_event_open(fd1, HW_BREAKPOINT_W, (__u64)&a, (__u64)sizeof(a)); if (ret) exit(EXIT_FAILURE);
ret = perf_systemwide_event_open(fd2, HW_BREAKPOINT_R, (__u64)&a, (__u64)sizeof(a)); if (ret) {
close_fds(fd1, nprocs); exit(EXIT_FAILURE);
}
ret |= test_process_multi_diff_addr();
ret |= test_process_multi_same_addr();
ret |= test_process_multi_diff_addr_ro_wo();
ret |= test_process_multi_same_addr_ro_wo();
ret |= test_syswide_multi_diff_addr();
ret |= test_syswide_multi_same_addr();
ret |= test_syswide_multi_diff_addr_ro_wo();
ret |= test_syswide_multi_same_addr_ro_wo();
/* There is no perf api to find number of available watchpoints. Use ptrace. */ staticint get_nr_wps(bool *arch_31)
{ struct ppc_debug_info dbginfo; int child_pid;
child_pid = fork(); if (!child_pid) { int ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); if (ret) {
perror("PTRACE_TRACEME failed\n"); exit(EXIT_FAILURE);
}
kill(getpid(), SIGUSR1);
sleep(1); exit(EXIT_SUCCESS);
}
wait(NULL); if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo)) {
perror("Can't get breakpoint info"); exit(EXIT_FAILURE);
}
staticint runtest(void)
{ int rwflag; int exclude_user; int ret; bool dawr = dawr_supported(); bool arch_31 = false; int nr_wps = get_nr_wps(&arch_31);
/* * perf defines rwflag as two bits read and write and at least * one must be set. So range 1-3.
*/ for (rwflag = 1 ; rwflag < 4; rwflag++) { for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
ret = runtestsingle(rwflag, exclude_user, 0); if (ret) return ret;
/* if we have the dawr, we can do an array test */ if (!dawr) continue;
ret = runtestsingle(rwflag, exclude_user, 1); if (ret) return ret;
}
}
ret = runtest_dar_outside(); if (ret) return ret;
if (dawr && nr_wps > 1) {
nprocs = get_nprocs();
ret = runtest_multi_dawr(); if (ret) return ret;
}
if (dawr && arch_31)
ret = runtest_unaligned_512bytes();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.