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 <inttypes.h> 4 #include <sched.h> 5 #include <stdio.h> 6 #include <stdarg.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 #include <linux/perf_event.h> 10 #include <linux/limits.h> 11 #include <sys/types.h> 12 #include <sys/wait.h> 13 #include <sys/prctl.h> 14 #include <perf/cpumap.h> 15 #include <perf/threadmap.h> 16 #include <perf/evlist.h> 17 #include <perf/evsel.h> 18 #include <perf/mmap.h> 19 #include <perf/event.h> 20 #include <internal/tests.h> 21 #include <api/fs/fs.h> 22 #include "tests.h" 23 #include <internal/evsel.h> 24 25 #define EVENT_NUM 15 26 #define WAIT_COUNT 100000000UL 27 28 static int libperf_print(enum libperf_print_level level, 29 const char *fmt, va_list ap) 30 { 31 return vfprintf(stderr, fmt, ap); 32 } 33 34 static int test_stat_cpu(void) 35 { 36 struct perf_cpu_map *cpus; 37 struct perf_evlist *evlist; 38 struct perf_evsel *evsel, *leader; 39 struct perf_event_attr attr1 = { 40 .type = PERF_TYPE_SOFTWARE, 41 .config = PERF_COUNT_SW_CPU_CLOCK, 42 }; 43 struct perf_event_attr attr2 = { 44 .type = PERF_TYPE_SOFTWARE, 45 .config = PERF_COUNT_SW_TASK_CLOCK, 46 }; 47 int err, idx; 48 49 cpus = perf_cpu_map__new_online_cpus(); 50 __T("failed to create cpus", cpus); 51 52 evlist = perf_evlist__new(); 53 __T("failed to create evlist", evlist); 54 55 evsel = leader = perf_evsel__new(&attr1); 56 __T("failed to create evsel1", evsel); 57 58 perf_evlist__add(evlist, evsel); 59 60 evsel = perf_evsel__new(&attr2); 61 __T("failed to create evsel2", evsel); 62 63 perf_evlist__add(evlist, evsel); 64 65 perf_evlist__set_leader(evlist); 66 __T("failed to set leader", leader->leader == leader); 67 __T("failed to set leader", evsel->leader == leader); 68 69 perf_evlist__set_maps(evlist, cpus, NULL); 70 71 err = perf_evlist__open(evlist); 72 __T("failed to open evlist", err == 0); 73 74 perf_evlist__for_each_evsel(evlist, evsel) { 75 cpus = perf_evsel__cpus(evsel); 76 77 for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { 78 struct perf_counts_values counts = { .val = 0 }; 79 80 perf_evsel__read(evsel, idx, 0, &counts); 81 __T("failed to read value for evsel", counts.val != 0); 82 } 83 } 84 85 perf_evlist__close(evlist); 86 perf_evlist__delete(evlist); 87 88 perf_cpu_map__put(cpus); 89 return 0; 90 } 91 92 static int test_stat_thread(void) 93 { 94 struct perf_counts_values counts = { .val = 0 }; 95 struct perf_thread_map *threads; 96 struct perf_evlist *evlist; 97 struct perf_evsel *evsel, *leader; 98 struct perf_event_attr attr1 = { 99 .type = PERF_TYPE_SOFTWARE, 100 .config = PERF_COUNT_SW_CPU_CLOCK, 101 }; 102 struct perf_event_attr attr2 = { 103 .type = PERF_TYPE_SOFTWARE, 104 .config = PERF_COUNT_SW_TASK_CLOCK, 105 }; 106 int err; 107 108 threads = perf_thread_map__new_dummy(); 109 __T("failed to create threads", threads); 110 111 perf_thread_map__set_pid(threads, 0, 0); 112 113 evlist = perf_evlist__new(); 114 __T("failed to create evlist", evlist); 115 116 evsel = leader = perf_evsel__new(&attr1); 117 __T("failed to create evsel1", evsel); 118 119 perf_evlist__add(evlist, evsel); 120 121 evsel = perf_evsel__new(&attr2); 122 __T("failed to create evsel2", evsel); 123 124 perf_evlist__add(evlist, evsel); 125 126 perf_evlist__set_leader(evlist); 127 __T("failed to set leader", leader->leader == leader); 128 __T("failed to set leader", evsel->leader == leader); 129 130 perf_evlist__set_maps(evlist, NULL, threads); 131 132 err = perf_evlist__open(evlist); 133 __T("failed to open evlist", err == 0); 134 135 perf_evlist__for_each_evsel(evlist, evsel) { 136 perf_evsel__read(evsel, 0, 0, &counts); 137 __T("failed to read value for evsel", counts.val != 0); 138 } 139 140 perf_evlist__close(evlist); 141 perf_evlist__delete(evlist); 142 143 perf_thread_map__put(threads); 144 return 0; 145 } 146 147 static int test_stat_thread_enable(void) 148 { 149 struct perf_counts_values counts = { .val = 0 }; 150 struct perf_thread_map *threads; 151 struct perf_evlist *evlist; 152 struct perf_evsel *evsel, *leader; 153 struct perf_event_attr attr1 = { 154 .type = PERF_TYPE_SOFTWARE, 155 .config = PERF_COUNT_SW_CPU_CLOCK, 156 .disabled = 1, 157 }; 158 struct perf_event_attr attr2 = { 159 .type = PERF_TYPE_SOFTWARE, 160 .config = PERF_COUNT_SW_TASK_CLOCK, 161 .disabled = 1, 162 }; 163 int err; 164 165 threads = perf_thread_map__new_dummy(); 166 __T("failed to create threads", threads); 167 168 perf_thread_map__set_pid(threads, 0, 0); 169 170 evlist = perf_evlist__new(); 171 __T("failed to create evlist", evlist); 172 173 evsel = leader = perf_evsel__new(&attr1); 174 __T("failed to create evsel1", evsel); 175 176 perf_evlist__add(evlist, evsel); 177 178 evsel = perf_evsel__new(&attr2); 179 __T("failed to create evsel2", evsel); 180 181 perf_evlist__add(evlist, evsel); 182 183 perf_evlist__set_leader(evlist); 184 __T("failed to set leader", leader->leader == leader); 185 __T("failed to set leader", evsel->leader == leader); 186 187 perf_evlist__set_maps(evlist, NULL, threads); 188 189 err = perf_evlist__open(evlist); 190 __T("failed to open evlist", err == 0); 191 192 perf_evlist__for_each_evsel(evlist, evsel) { 193 perf_evsel__read(evsel, 0, 0, &counts); 194 __T("failed to read value for evsel", counts.val == 0); 195 } 196 197 perf_evlist__enable(evlist); 198 199 perf_evlist__for_each_evsel(evlist, evsel) { 200 perf_evsel__read(evsel, 0, 0, &counts); 201 __T("failed to read value for evsel", counts.val != 0); 202 } 203 204 perf_evlist__disable(evlist); 205 206 perf_evlist__close(evlist); 207 perf_evlist__delete(evlist); 208 209 perf_thread_map__put(threads); 210 return 0; 211 } 212 213 static int test_mmap_thread(void) 214 { 215 struct perf_evlist *evlist; 216 struct perf_evsel *evsel; 217 struct perf_mmap *map; 218 struct perf_cpu_map *cpus; 219 struct perf_thread_map *threads; 220 struct perf_event_attr attr = { 221 .type = PERF_TYPE_TRACEPOINT, 222 .sample_period = 1, 223 .wakeup_watermark = 1, 224 .disabled = 1, 225 }; 226 char path[PATH_MAX]; 227 int id, err, pid, go_pipe[2]; 228 union perf_event *event; 229 int count = 0; 230 231 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 232 sysfs__mountpoint()); 233 234 if (filename__read_int(path, &id)) { 235 tests_failed++; 236 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 237 return -1; 238 } 239 240 attr.config = id; 241 242 err = pipe(go_pipe); 243 __T("failed to create pipe", err == 0); 244 245 fflush(NULL); 246 247 pid = fork(); 248 if (!pid) { 249 int i; 250 char bf; 251 252 read(go_pipe[0], &bf, 1); 253 254 /* Generate 100 prctl calls. */ 255 for (i = 0; i < 100; i++) 256 prctl(0, 0, 0, 0, 0); 257 258 exit(0); 259 } 260 261 threads = perf_thread_map__new_dummy(); 262 __T("failed to create threads", threads); 263 264 cpus = perf_cpu_map__new_any_cpu(); 265 __T("failed to create cpus", cpus); 266 267 perf_thread_map__set_pid(threads, 0, pid); 268 269 evlist = perf_evlist__new(); 270 __T("failed to create evlist", evlist); 271 272 evsel = perf_evsel__new(&attr); 273 __T("failed to create evsel1", evsel); 274 __T("failed to set leader", evsel->leader == evsel); 275 276 perf_evlist__add(evlist, evsel); 277 278 perf_evlist__set_maps(evlist, cpus, threads); 279 280 err = perf_evlist__open(evlist); 281 __T("failed to open evlist", err == 0); 282 283 err = perf_evlist__mmap(evlist, 4); 284 __T("failed to mmap evlist", err == 0); 285 286 perf_evlist__enable(evlist); 287 288 /* kick the child and wait for it to finish */ 289 write(go_pipe[1], "A", 1); 290 waitpid(pid, NULL, 0); 291 292 /* 293 * There's no need to call perf_evlist__disable, 294 * monitored process is dead now. 295 */ 296 297 perf_evlist__for_each_mmap(evlist, map, false) { 298 if (perf_mmap__read_init(map) < 0) 299 continue; 300 301 while ((event = perf_mmap__read_event(map)) != NULL) { 302 count++; 303 perf_mmap__consume(map); 304 } 305 306 perf_mmap__read_done(map); 307 } 308 309 /* calls perf_evlist__munmap/perf_evlist__close */ 310 perf_evlist__delete(evlist); 311 312 perf_thread_map__put(threads); 313 perf_cpu_map__put(cpus); 314 315 /* 316 * The generated prctl calls should match the 317 * number of events in the buffer. 318 */ 319 __T("failed count", count == 100); 320 321 return 0; 322 } 323 324 static int test_mmap_cpus(void) 325 { 326 struct perf_evlist *evlist; 327 struct perf_evsel *evsel; 328 struct perf_mmap *map; 329 struct perf_cpu_map *cpus; 330 struct perf_event_attr attr = { 331 .type = PERF_TYPE_TRACEPOINT, 332 .sample_period = 1, 333 .wakeup_watermark = 1, 334 .disabled = 1, 335 }; 336 cpu_set_t saved_mask; 337 char path[PATH_MAX]; 338 int id, err, tmp; 339 struct perf_cpu cpu; 340 union perf_event *event; 341 int count = 0; 342 343 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 344 sysfs__mountpoint()); 345 346 if (filename__read_int(path, &id)) { 347 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 348 return -1; 349 } 350 351 attr.config = id; 352 353 cpus = perf_cpu_map__new_online_cpus(); 354 __T("failed to create cpus", cpus); 355 356 evlist = perf_evlist__new(); 357 __T("failed to create evlist", evlist); 358 359 evsel = perf_evsel__new(&attr); 360 __T("failed to create evsel1", evsel); 361 __T("failed to set leader", evsel->leader == evsel); 362 363 perf_evlist__add(evlist, evsel); 364 365 perf_evlist__set_maps(evlist, cpus, NULL); 366 367 err = perf_evlist__open(evlist); 368 __T("failed to open evlist", err == 0); 369 370 err = perf_evlist__mmap(evlist, 4); 371 __T("failed to mmap evlist", err == 0); 372 373 perf_evlist__enable(evlist); 374 375 err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask); 376 __T("sched_getaffinity failed", err == 0); 377 378 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { 379 cpu_set_t mask; 380 381 CPU_ZERO(&mask); 382 CPU_SET(cpu.cpu, &mask); 383 384 err = sched_setaffinity(0, sizeof(mask), &mask); 385 __T("sched_setaffinity failed", err == 0); 386 387 prctl(0, 0, 0, 0, 0); 388 } 389 390 err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask); 391 __T("sched_setaffinity failed", err == 0); 392 393 perf_evlist__disable(evlist); 394 395 perf_evlist__for_each_mmap(evlist, map, false) { 396 if (perf_mmap__read_init(map) < 0) 397 continue; 398 399 while ((event = perf_mmap__read_event(map)) != NULL) { 400 count++; 401 perf_mmap__consume(map); 402 } 403 404 perf_mmap__read_done(map); 405 } 406 407 /* calls perf_evlist__munmap/perf_evlist__close */ 408 perf_evlist__delete(evlist); 409 410 /* 411 * The generated prctl events should match the 412 * number of cpus or be bigger (we are system-wide). 413 */ 414 __T("failed count", count >= perf_cpu_map__nr(cpus)); 415 416 perf_cpu_map__put(cpus); 417 418 return 0; 419 } 420 421 static double display_error(long long average, 422 long long high, 423 long long low, 424 long long expected) 425 { 426 double error; 427 428 error = (((double)average - expected) / expected) * 100.0; 429 430 __T_VERBOSE(" Expected: %lld\n", expected); 431 __T_VERBOSE(" High: %lld Low: %lld Average: %lld\n", 432 high, low, average); 433 434 __T_VERBOSE(" Average Error = %.2f%%\n", error); 435 436 return error; 437 } 438 439 static int test_stat_multiplexing(void) 440 { 441 struct perf_counts_values expected_counts = { .val = 0 }; 442 struct perf_counts_values counts[EVENT_NUM] = {{ .val = 0 },}; 443 struct perf_thread_map *threads; 444 struct perf_evlist *evlist; 445 struct perf_evsel *evsel; 446 struct perf_event_attr attr = { 447 .type = PERF_TYPE_HARDWARE, 448 .config = PERF_COUNT_HW_INSTRUCTIONS, 449 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 450 PERF_FORMAT_TOTAL_TIME_RUNNING, 451 .disabled = 1, 452 }; 453 int err, i, nonzero = 0; 454 unsigned long count; 455 long long max = 0, min = 0, avg = 0; 456 double error = 0.0; 457 s8 scaled = 0; 458 459 /* read for non-multiplexing event count */ 460 threads = perf_thread_map__new_dummy(); 461 __T("failed to create threads", threads); 462 463 perf_thread_map__set_pid(threads, 0, 0); 464 465 evsel = perf_evsel__new(&attr); 466 __T("failed to create evsel", evsel); 467 468 err = perf_evsel__open(evsel, NULL, threads); 469 __T("failed to open evsel", err == 0); 470 471 err = perf_evsel__enable(evsel); 472 __T("failed to enable evsel", err == 0); 473 474 /* wait loop */ 475 count = WAIT_COUNT; 476 while (count--) 477 ; 478 479 perf_evsel__read(evsel, 0, 0, &expected_counts); 480 __T("failed to read value for evsel", expected_counts.val != 0); 481 __T("failed to read non-multiplexing event count", 482 expected_counts.ena == expected_counts.run); 483 484 err = perf_evsel__disable(evsel); 485 __T("failed to enable evsel", err == 0); 486 487 perf_evsel__close(evsel); 488 perf_evsel__delete(evsel); 489 490 perf_thread_map__put(threads); 491 492 /* read for multiplexing event count */ 493 threads = perf_thread_map__new_dummy(); 494 __T("failed to create threads", threads); 495 496 perf_thread_map__set_pid(threads, 0, 0); 497 498 evlist = perf_evlist__new(); 499 __T("failed to create evlist", evlist); 500 501 for (i = 0; i < EVENT_NUM; i++) { 502 evsel = perf_evsel__new(&attr); 503 __T("failed to create evsel", evsel); 504 505 perf_evlist__add(evlist, evsel); 506 } 507 perf_evlist__set_maps(evlist, NULL, threads); 508 509 err = perf_evlist__open(evlist); 510 __T("failed to open evlist", err == 0); 511 512 perf_evlist__enable(evlist); 513 514 /* wait loop */ 515 count = WAIT_COUNT; 516 while (count--) 517 ; 518 519 i = 0; 520 perf_evlist__for_each_evsel(evlist, evsel) { 521 perf_evsel__read(evsel, 0, 0, &counts[i]); 522 __T("failed to read value for evsel", counts[i].val != 0); 523 i++; 524 } 525 526 perf_evlist__disable(evlist); 527 528 min = counts[0].val; 529 for (i = 0; i < EVENT_NUM; i++) { 530 __T_VERBOSE("Event %2d -- Raw count = %" PRIu64 ", run = %" PRIu64 ", enable = %" PRIu64 "\n", 531 i, counts[i].val, counts[i].run, counts[i].ena); 532 533 perf_counts_values__scale(&counts[i], true, &scaled); 534 if (scaled == 1) { 535 __T_VERBOSE("\t Scaled count = %" PRIu64 " (%.2lf%%, %" PRIu64 "/%" PRIu64 ")\n", 536 counts[i].val, 537 (double)counts[i].run / (double)counts[i].ena * 100.0, 538 counts[i].run, counts[i].ena); 539 } else if (scaled == -1) { 540 __T_VERBOSE("\t Not Running\n"); 541 } else { 542 __T_VERBOSE("\t Not Scaling\n"); 543 } 544 545 if (counts[i].val > max) 546 max = counts[i].val; 547 548 if (counts[i].val < min) 549 min = counts[i].val; 550 551 avg += counts[i].val; 552 553 if (counts[i].val != 0) 554 nonzero++; 555 } 556 557 if (nonzero != 0) 558 avg = avg / nonzero; 559 else 560 avg = 0; 561 562 error = display_error(avg, max, min, expected_counts.val); 563 564 __T("Error out of range!", ((error <= 1.0) && (error >= -1.0))); 565 566 perf_evlist__close(evlist); 567 perf_evlist__delete(evlist); 568 569 perf_thread_map__put(threads); 570 571 return 0; 572 } 573 574 int test_evlist(int argc, char **argv) 575 { 576 __T_START; 577 578 libperf_init(libperf_print); 579 580 test_stat_cpu(); 581 test_stat_thread(); 582 test_stat_thread_enable(); 583 test_mmap_thread(); 584 test_mmap_cpus(); 585 test_stat_multiplexing(); 586 587 __T_END; 588 return tests_failed == 0 ? 0 : -1; 589 } 590
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.