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_dar_outside(void) 152 { 153 void *target; 154 volatile __u16 temp16; 155 volatile __u64 temp64; 156 struct perf_event_attr attr; 157 int break_fd; 158 unsigned long long breaks; 159 int fail = 0; 160 size_t res; 161 162 target = malloc(8); 163 if (!target) { 164 perror("malloc failed"); 165 exit(EXIT_FAILURE); 166 } 167 168 /* setup counters */ 169 memset(&attr, 0, sizeof(attr)); 170 attr.disabled = 1; 171 attr.type = PERF_TYPE_BREAKPOINT; 172 attr.exclude_kernel = 1; 173 attr.exclude_hv = 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); 178 attr.bp_len = 4; 179 break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 180 if (break_fd < 0) { 181 free(target); 182 perror("sys_perf_event_open"); 183 exit(EXIT_FAILURE); 184 } 185 186 /* Shouldn't hit. */ 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)); 194 if (breaks == 0) { 195 printf("TESTED: No overlap\n"); 196 } else { 197 printf("FAILED: No overlap: %lld != 0\n", breaks); 198 fail = 1; 199 } 200 201 /* Hit */ 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)); 209 if (breaks == 2) { 210 printf("TESTED: Partial overlap\n"); 211 } else { 212 printf("FAILED: Partial overlap: %lld != 2\n", breaks); 213 fail = 1; 214 } 215 216 /* Hit */ 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)); 224 if (breaks == 2) { 225 printf("TESTED: Partial overlap\n"); 226 } else { 227 printf("FAILED: Partial overlap: %lld != 2\n", breaks); 228 fail = 1; 229 } 230 231 /* Shouldn't Hit */ 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)); 239 if (breaks == 0) { 240 printf("TESTED: No overlap\n"); 241 } else { 242 printf("FAILED: No overlap: %lld != 0\n", breaks); 243 fail = 1; 244 } 245 246 /* Hit */ 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)); 254 if (breaks == 2) { 255 printf("TESTED: Full overlap\n"); 256 } else { 257 printf("FAILED: Full overlap: %lld != 2\n", breaks); 258 fail = 1; 259 } 260 261 free(target); 262 close(break_fd); 263 return fail; 264 } 265 266 static int runtest(void) 267 { 268 int rwflag; 269 int exclude_user; 270 int ret; 271 272 /* 273 * perf defines rwflag as two bits read and write and at least 274 * one must be set. So range 1-3. 275 */ 276 for (rwflag = 1 ; rwflag < 4; rwflag++) { 277 for (exclude_user = 0 ; exclude_user < 2; exclude_user++) { 278 ret = runtestsingle(rwflag, exclude_user, 0); 279 if (ret) 280 return ret; 281 282 /* if we have the dawr, we can do an array test */ 283 if (!dawr_supported()) 284 continue; 285 ret = runtestsingle(rwflag, exclude_user, 1); 286 if (ret) 287 return ret; 288 } 289 } 290 291 ret = runtest_dar_outside(); 292 return ret; 293 } 294 295 296 static int perf_hwbreak(void) 297 { 298 srand ( time(NULL) ); 299 300 SKIP_IF(!perf_breakpoint_supported()); 301 302 return runtest(); 303 } 304 305 int main(int argc, char *argv[], char **envp) 306 { 307 return test_harness(perf_hwbreak, "perf_hwbreak"); 308 } 309