1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET) 3 #include <sched.h> 4 #include <stdio.h> 5 #include <stdarg.h> 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <linux/perf_event.h> 9 #include <linux/limits.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 #include <sys/prctl.h> 13 #include <perf/cpumap.h> 14 #include <perf/threadmap.h> 15 #include <perf/evlist.h> 16 #include <perf/evsel.h> 17 #include <perf/mmap.h> 18 #include <perf/event.h> 19 #include <internal/tests.h> 20 #include <api/fs/fs.h> 21 #include "tests.h" 22 23 static int libperf_print(enum libperf_print_level level, 24 const char *fmt, va_list ap) 25 { 26 return vfprintf(stderr, fmt, ap); 27 } 28 29 static int test_stat_cpu(void) 30 { 31 struct perf_cpu_map *cpus; 32 struct perf_evlist *evlist; 33 struct perf_evsel *evsel; 34 struct perf_event_attr attr1 = { 35 .type = PERF_TYPE_SOFTWARE, 36 .config = PERF_COUNT_SW_CPU_CLOCK, 37 }; 38 struct perf_event_attr attr2 = { 39 .type = PERF_TYPE_SOFTWARE, 40 .config = PERF_COUNT_SW_TASK_CLOCK, 41 }; 42 int err, cpu, tmp; 43 44 cpus = perf_cpu_map__new(NULL); 45 __T("failed to create cpus", cpus); 46 47 evlist = perf_evlist__new(); 48 __T("failed to create evlist", evlist); 49 50 evsel = perf_evsel__new(&attr1); 51 __T("failed to create evsel1", evsel); 52 53 perf_evlist__add(evlist, evsel); 54 55 evsel = perf_evsel__new(&attr2); 56 __T("failed to create evsel2", evsel); 57 58 perf_evlist__add(evlist, evsel); 59 60 perf_evlist__set_maps(evlist, cpus, NULL); 61 62 err = perf_evlist__open(evlist); 63 __T("failed to open evsel", err == 0); 64 65 perf_evlist__for_each_evsel(evlist, evsel) { 66 cpus = perf_evsel__cpus(evsel); 67 68 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { 69 struct perf_counts_values counts = { .val = 0 }; 70 71 perf_evsel__read(evsel, cpu, 0, &counts); 72 __T("failed to read value for evsel", counts.val != 0); 73 } 74 } 75 76 perf_evlist__close(evlist); 77 perf_evlist__delete(evlist); 78 79 perf_cpu_map__put(cpus); 80 return 0; 81 } 82 83 static int test_stat_thread(void) 84 { 85 struct perf_counts_values counts = { .val = 0 }; 86 struct perf_thread_map *threads; 87 struct perf_evlist *evlist; 88 struct perf_evsel *evsel; 89 struct perf_event_attr attr1 = { 90 .type = PERF_TYPE_SOFTWARE, 91 .config = PERF_COUNT_SW_CPU_CLOCK, 92 }; 93 struct perf_event_attr attr2 = { 94 .type = PERF_TYPE_SOFTWARE, 95 .config = PERF_COUNT_SW_TASK_CLOCK, 96 }; 97 int err; 98 99 threads = perf_thread_map__new_dummy(); 100 __T("failed to create threads", threads); 101 102 perf_thread_map__set_pid(threads, 0, 0); 103 104 evlist = perf_evlist__new(); 105 __T("failed to create evlist", evlist); 106 107 evsel = perf_evsel__new(&attr1); 108 __T("failed to create evsel1", evsel); 109 110 perf_evlist__add(evlist, evsel); 111 112 evsel = perf_evsel__new(&attr2); 113 __T("failed to create evsel2", evsel); 114 115 perf_evlist__add(evlist, evsel); 116 117 perf_evlist__set_maps(evlist, NULL, threads); 118 119 err = perf_evlist__open(evlist); 120 __T("failed to open evsel", err == 0); 121 122 perf_evlist__for_each_evsel(evlist, evsel) { 123 perf_evsel__read(evsel, 0, 0, &counts); 124 __T("failed to read value for evsel", counts.val != 0); 125 } 126 127 perf_evlist__close(evlist); 128 perf_evlist__delete(evlist); 129 130 perf_thread_map__put(threads); 131 return 0; 132 } 133 134 static int test_stat_thread_enable(void) 135 { 136 struct perf_counts_values counts = { .val = 0 }; 137 struct perf_thread_map *threads; 138 struct perf_evlist *evlist; 139 struct perf_evsel *evsel; 140 struct perf_event_attr attr1 = { 141 .type = PERF_TYPE_SOFTWARE, 142 .config = PERF_COUNT_SW_CPU_CLOCK, 143 .disabled = 1, 144 }; 145 struct perf_event_attr attr2 = { 146 .type = PERF_TYPE_SOFTWARE, 147 .config = PERF_COUNT_SW_TASK_CLOCK, 148 .disabled = 1, 149 }; 150 int err; 151 152 threads = perf_thread_map__new_dummy(); 153 __T("failed to create threads", threads); 154 155 perf_thread_map__set_pid(threads, 0, 0); 156 157 evlist = perf_evlist__new(); 158 __T("failed to create evlist", evlist); 159 160 evsel = perf_evsel__new(&attr1); 161 __T("failed to create evsel1", evsel); 162 163 perf_evlist__add(evlist, evsel); 164 165 evsel = perf_evsel__new(&attr2); 166 __T("failed to create evsel2", evsel); 167 168 perf_evlist__add(evlist, evsel); 169 170 perf_evlist__set_maps(evlist, NULL, threads); 171 172 err = perf_evlist__open(evlist); 173 __T("failed to open evsel", err == 0); 174 175 perf_evlist__for_each_evsel(evlist, evsel) { 176 perf_evsel__read(evsel, 0, 0, &counts); 177 __T("failed to read value for evsel", counts.val == 0); 178 } 179 180 perf_evlist__enable(evlist); 181 182 perf_evlist__for_each_evsel(evlist, evsel) { 183 perf_evsel__read(evsel, 0, 0, &counts); 184 __T("failed to read value for evsel", counts.val != 0); 185 } 186 187 perf_evlist__disable(evlist); 188 189 perf_evlist__close(evlist); 190 perf_evlist__delete(evlist); 191 192 perf_thread_map__put(threads); 193 return 0; 194 } 195 196 static int test_mmap_thread(void) 197 { 198 struct perf_evlist *evlist; 199 struct perf_evsel *evsel; 200 struct perf_mmap *map; 201 struct perf_cpu_map *cpus; 202 struct perf_thread_map *threads; 203 struct perf_event_attr attr = { 204 .type = PERF_TYPE_TRACEPOINT, 205 .sample_period = 1, 206 .wakeup_watermark = 1, 207 .disabled = 1, 208 }; 209 char path[PATH_MAX]; 210 int id, err, pid, go_pipe[2]; 211 union perf_event *event; 212 int count = 0; 213 214 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 215 sysfs__mountpoint()); 216 217 if (filename__read_int(path, &id)) { 218 tests_failed++; 219 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 220 return -1; 221 } 222 223 attr.config = id; 224 225 err = pipe(go_pipe); 226 __T("failed to create pipe", err == 0); 227 228 fflush(NULL); 229 230 pid = fork(); 231 if (!pid) { 232 int i; 233 char bf; 234 235 read(go_pipe[0], &bf, 1); 236 237 /* Generate 100 prctl calls. */ 238 for (i = 0; i < 100; i++) 239 prctl(0, 0, 0, 0, 0); 240 241 exit(0); 242 } 243 244 threads = perf_thread_map__new_dummy(); 245 __T("failed to create threads", threads); 246 247 cpus = perf_cpu_map__dummy_new(); 248 __T("failed to create cpus", cpus); 249 250 perf_thread_map__set_pid(threads, 0, pid); 251 252 evlist = perf_evlist__new(); 253 __T("failed to create evlist", evlist); 254 255 evsel = perf_evsel__new(&attr); 256 __T("failed to create evsel1", evsel); 257 258 perf_evlist__add(evlist, evsel); 259 260 perf_evlist__set_maps(evlist, cpus, threads); 261 262 err = perf_evlist__open(evlist); 263 __T("failed to open evlist", err == 0); 264 265 err = perf_evlist__mmap(evlist, 4); 266 __T("failed to mmap evlist", err == 0); 267 268 perf_evlist__enable(evlist); 269 270 /* kick the child and wait for it to finish */ 271 write(go_pipe[1], "A", 1); 272 waitpid(pid, NULL, 0); 273 274 /* 275 * There's no need to call perf_evlist__disable, 276 * monitored process is dead now. 277 */ 278 279 perf_evlist__for_each_mmap(evlist, map, false) { 280 if (perf_mmap__read_init(map) < 0) 281 continue; 282 283 while ((event = perf_mmap__read_event(map)) != NULL) { 284 count++; 285 perf_mmap__consume(map); 286 } 287 288 perf_mmap__read_done(map); 289 } 290 291 /* calls perf_evlist__munmap/perf_evlist__close */ 292 perf_evlist__delete(evlist); 293 294 perf_thread_map__put(threads); 295 perf_cpu_map__put(cpus); 296 297 /* 298 * The generated prctl calls should match the 299 * number of events in the buffer. 300 */ 301 __T("failed count", count == 100); 302 303 return 0; 304 } 305 306 static int test_mmap_cpus(void) 307 { 308 struct perf_evlist *evlist; 309 struct perf_evsel *evsel; 310 struct perf_mmap *map; 311 struct perf_cpu_map *cpus; 312 struct perf_event_attr attr = { 313 .type = PERF_TYPE_TRACEPOINT, 314 .sample_period = 1, 315 .wakeup_watermark = 1, 316 .disabled = 1, 317 }; 318 cpu_set_t saved_mask; 319 char path[PATH_MAX]; 320 int id, err, cpu, tmp; 321 union perf_event *event; 322 int count = 0; 323 324 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 325 sysfs__mountpoint()); 326 327 if (filename__read_int(path, &id)) { 328 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 329 return -1; 330 } 331 332 attr.config = id; 333 334 cpus = perf_cpu_map__new(NULL); 335 __T("failed to create cpus", cpus); 336 337 evlist = perf_evlist__new(); 338 __T("failed to create evlist", evlist); 339 340 evsel = perf_evsel__new(&attr); 341 __T("failed to create evsel1", evsel); 342 343 perf_evlist__add(evlist, evsel); 344 345 perf_evlist__set_maps(evlist, cpus, NULL); 346 347 err = perf_evlist__open(evlist); 348 __T("failed to open evlist", err == 0); 349 350 err = perf_evlist__mmap(evlist, 4); 351 __T("failed to mmap evlist", err == 0); 352 353 perf_evlist__enable(evlist); 354 355 err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask); 356 __T("sched_getaffinity failed", err == 0); 357 358 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { 359 cpu_set_t mask; 360 361 CPU_ZERO(&mask); 362 CPU_SET(cpu, &mask); 363 364 err = sched_setaffinity(0, sizeof(mask), &mask); 365 __T("sched_setaffinity failed", err == 0); 366 367 prctl(0, 0, 0, 0, 0); 368 } 369 370 err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask); 371 __T("sched_setaffinity failed", err == 0); 372 373 perf_evlist__disable(evlist); 374 375 perf_evlist__for_each_mmap(evlist, map, false) { 376 if (perf_mmap__read_init(map) < 0) 377 continue; 378 379 while ((event = perf_mmap__read_event(map)) != NULL) { 380 count++; 381 perf_mmap__consume(map); 382 } 383 384 perf_mmap__read_done(map); 385 } 386 387 /* calls perf_evlist__munmap/perf_evlist__close */ 388 perf_evlist__delete(evlist); 389 390 /* 391 * The generated prctl events should match the 392 * number of cpus or be bigger (we are system-wide). 393 */ 394 __T("failed count", count >= perf_cpu_map__nr(cpus)); 395 396 perf_cpu_map__put(cpus); 397 398 return 0; 399 } 400 401 int test_evlist(int argc, char **argv) 402 { 403 __T_START; 404 405 libperf_init(libperf_print); 406 407 test_stat_cpu(); 408 test_stat_thread(); 409 test_stat_thread_enable(); 410 test_mmap_thread(); 411 test_mmap_cpus(); 412 413 __T_END; 414 return tests_failed == 0 ? 0 : -1; 415 } 416