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 #include <unistd.h> 21 #include <assert.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/ioctl.h> 26 #include <elf.h> 27 #include <pthread.h> 28 #include <sys/syscall.h> 29 #include <linux/perf_event.h> 30 #include <linux/hw_breakpoint.h> 31 #include "utils.h" 32 33 #define MAX_LOOPS 10000 34 35 #define DAWR_LENGTH_MAX ((0x3f + 1) * 8) 36 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 45 static inline bool breakpoint_test(int len) 46 { 47 struct perf_event_attr attr; 48 int fd; 49 50 /* setup counters */ 51 memset(&attr, 0, sizeof(attr)); 52 attr.disabled = 1; 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; 57 attr.bp_len = len; 58 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 59 if (fd < 0) 60 return false; 61 close(fd); 62 return true; 63 } 64 65 static inline bool perf_breakpoint_supported(void) 66 { 67 return breakpoint_test(4); 68 } 69 70 static inline bool dawr_supported(void) 71 { 72 return breakpoint_test(DAWR_LENGTH_MAX); 73 } 74 75 static int runtestsingle(int readwriteflag, int exclude_user, int arraytest) 76 { 77 int i,j; 78 struct perf_event_attr attr; 79 size_t res; 80 unsigned long long breaks, needed; 81 int readint; 82 int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)]; 83 int *readintalign; 84 volatile int *ptr; 85 int break_fd; 86 int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */ 87 volatile int *k; 88 89 /* align to 0x400 boundary as required by DAWR */ 90 readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) & 91 0xfffffffffffff800); 92 93 ptr = &readint; 94 if (arraytest) 95 ptr = &readintalign[0]; 96 97 /* setup counters */ 98 memset(&attr, 0, sizeof(attr)); 99 attr.disabled = 1; 100 attr.type = PERF_TYPE_BREAKPOINT; 101 attr.bp_type = readwriteflag; 102 attr.bp_addr = (__u64)ptr; 103 attr.bp_len = sizeof(int); 104 if (arraytest) 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); 108 if (break_fd < 0) { 109 perror("sys_perf_event_open"); 110 exit(1); 111 } 112 113 /* start counters */ 114 ioctl(break_fd, PERF_EVENT_IOC_ENABLE); 115 116 /* Test a bunch of reads and writes */ 117 k = &readint; 118 for (i = 0; i < loop_num; i++) { 119 if (arraytest) 120 k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]); 121 122 j = *k; 123 *k = j; 124 } 125 126 /* stop counters */ 127 ioctl(break_fd, PERF_EVENT_IOC_DISABLE); 128 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 */ 133 needed = 0; 134 if (readwriteflag & HW_BREAKPOINT_R) 135 needed += loop_num; 136 if (readwriteflag & HW_BREAKPOINT_W) 137 needed += loop_num; 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); 144 return 1; 145 } 146 close(break_fd); 147 148 return 0; 149 } 150 151 static int runtest(void) 152 { 153 int rwflag; 154 int exclude_user; 155 int ret; 156 157 /* 158 * perf defines rwflag as two bits read and write and at least 159 * one must be set. So range 1-3. 160 */ 161 for (rwflag = 1 ; rwflag < 4; rwflag++) { 162 for (exclude_user = 0 ; exclude_user < 2; exclude_user++) { 163 ret = runtestsingle(rwflag, exclude_user, 0); 164 if (ret) 165 return ret; 166 167 /* if we have the dawr, we can do an array test */ 168 if (!dawr_supported()) 169 continue; 170 ret = runtestsingle(rwflag, exclude_user, 1); 171 if (ret) 172 return ret; 173 } 174 } 175 return 0; 176 } 177 178 179 static int perf_hwbreak(void) 180 { 181 srand ( time(NULL) ); 182 183 SKIP_IF(!perf_breakpoint_supported()); 184 185 return runtest(); 186 } 187 188 int main(int argc, char *argv[], char **envp) 189 { 190 return test_harness(perf_hwbreak, "perf_hwbreak"); 191 } 192