1 /* 2 * builtin-stat.c 3 * 4 * Builtin stat command: Give a precise performance counters summary 5 * overview about any workload, CPU or specific PID. 6 * 7 * Sample output: 8 9 $ perf stat ./hackbench 10 10 11 Time: 0.118 12 13 Performance counter stats for './hackbench 10': 14 15 1708.761321 task-clock # 11.037 CPUs utilized 16 41,190 context-switches # 0.024 M/sec 17 6,735 CPU-migrations # 0.004 M/sec 18 17,318 page-faults # 0.010 M/sec 19 5,205,202,243 cycles # 3.046 GHz 20 3,856,436,920 stalled-cycles-frontend # 74.09% frontend cycles idle 21 1,600,790,871 stalled-cycles-backend # 30.75% backend cycles idle 22 2,603,501,247 instructions # 0.50 insns per cycle 23 # 1.48 stalled cycles per insn 24 484,357,498 branches # 283.455 M/sec 25 6,388,934 branch-misses # 1.32% of all branches 26 27 0.154822978 seconds time elapsed 28 29 * 30 * Copyright (C) 2008-2011, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 31 * 32 * Improvements and fixes by: 33 * 34 * Arjan van de Ven <arjan@linux.intel.com> 35 * Yanmin Zhang <yanmin.zhang@intel.com> 36 * Wu Fengguang <fengguang.wu@intel.com> 37 * Mike Galbraith <efault@gmx.de> 38 * Paul Mackerras <paulus@samba.org> 39 * Jaswinder Singh Rajput <jaswinder@kernel.org> 40 * 41 * Released under the GPL v2. (and only v2, not any later version) 42 */ 43 44 #include "perf.h" 45 #include "builtin.h" 46 #include "util/cgroup.h" 47 #include "util/util.h" 48 #include <subcmd/parse-options.h> 49 #include "util/parse-events.h" 50 #include "util/pmu.h" 51 #include "util/event.h" 52 #include "util/evlist.h" 53 #include "util/evsel.h" 54 #include "util/debug.h" 55 #include "util/drv_configs.h" 56 #include "util/color.h" 57 #include "util/stat.h" 58 #include "util/header.h" 59 #include "util/cpumap.h" 60 #include "util/thread.h" 61 #include "util/thread_map.h" 62 #include "util/counts.h" 63 #include "util/group.h" 64 #include "util/session.h" 65 #include "util/tool.h" 66 #include "util/group.h" 67 #include "util/string2.h" 68 #include "util/metricgroup.h" 69 #include "asm/bug.h" 70 71 #include <linux/time64.h> 72 #include <api/fs/fs.h> 73 #include <errno.h> 74 #include <signal.h> 75 #include <stdlib.h> 76 #include <sys/prctl.h> 77 #include <inttypes.h> 78 #include <locale.h> 79 #include <math.h> 80 #include <sys/types.h> 81 #include <sys/stat.h> 82 #include <sys/wait.h> 83 #include <unistd.h> 84 85 #include "sane_ctype.h" 86 87 #define DEFAULT_SEPARATOR " " 88 #define CNTR_NOT_SUPPORTED "<not supported>" 89 #define CNTR_NOT_COUNTED "<not counted>" 90 #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" 91 92 static void print_counters(struct timespec *ts, int argc, const char **argv); 93 94 /* Default events used for perf stat -T */ 95 static const char *transaction_attrs = { 96 "task-clock," 97 "{" 98 "instructions," 99 "cycles," 100 "cpu/cycles-t/," 101 "cpu/tx-start/," 102 "cpu/el-start/," 103 "cpu/cycles-ct/" 104 "}" 105 }; 106 107 /* More limited version when the CPU does not have all events. */ 108 static const char * transaction_limited_attrs = { 109 "task-clock," 110 "{" 111 "instructions," 112 "cycles," 113 "cpu/cycles-t/," 114 "cpu/tx-start/" 115 "}" 116 }; 117 118 static const char * topdown_attrs[] = { 119 "topdown-total-slots", 120 "topdown-slots-retired", 121 "topdown-recovery-bubbles", 122 "topdown-fetch-bubbles", 123 "topdown-slots-issued", 124 NULL, 125 }; 126 127 static const char *smi_cost_attrs = { 128 "{" 129 "msr/aperf/," 130 "msr/smi/," 131 "cycles" 132 "}" 133 }; 134 135 static struct perf_evlist *evsel_list; 136 137 static struct rblist metric_events; 138 139 static struct target target = { 140 .uid = UINT_MAX, 141 }; 142 143 typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); 144 145 static int run_count = 1; 146 static bool no_inherit = false; 147 static volatile pid_t child_pid = -1; 148 static bool null_run = false; 149 static int detailed_run = 0; 150 static bool transaction_run; 151 static bool topdown_run = false; 152 static bool smi_cost = false; 153 static bool smi_reset = false; 154 static bool big_num = true; 155 static int big_num_opt = -1; 156 static const char *csv_sep = NULL; 157 static bool csv_output = false; 158 static bool group = false; 159 static const char *pre_cmd = NULL; 160 static const char *post_cmd = NULL; 161 static bool sync_run = false; 162 static unsigned int initial_delay = 0; 163 static unsigned int unit_width = 4; /* strlen("unit") */ 164 static bool forever = false; 165 static bool metric_only = false; 166 static bool force_metric_only = false; 167 static bool no_merge = false; 168 static struct timespec ref_time; 169 static struct cpu_map *aggr_map; 170 static aggr_get_id_t aggr_get_id; 171 static bool append_file; 172 static const char *output_name; 173 static int output_fd; 174 static int print_free_counters_hint; 175 176 struct perf_stat { 177 bool record; 178 struct perf_data data; 179 struct perf_session *session; 180 u64 bytes_written; 181 struct perf_tool tool; 182 bool maps_allocated; 183 struct cpu_map *cpus; 184 struct thread_map *threads; 185 enum aggr_mode aggr_mode; 186 }; 187 188 static struct perf_stat perf_stat; 189 #define STAT_RECORD perf_stat.record 190 191 static volatile int done = 0; 192 193 static struct perf_stat_config stat_config = { 194 .aggr_mode = AGGR_GLOBAL, 195 .scale = true, 196 }; 197 198 static bool is_duration_time(struct perf_evsel *evsel) 199 { 200 return !strcmp(evsel->name, "duration_time"); 201 } 202 203 static inline void diff_timespec(struct timespec *r, struct timespec *a, 204 struct timespec *b) 205 { 206 r->tv_sec = a->tv_sec - b->tv_sec; 207 if (a->tv_nsec < b->tv_nsec) { 208 r->tv_nsec = a->tv_nsec + NSEC_PER_SEC - b->tv_nsec; 209 r->tv_sec--; 210 } else { 211 r->tv_nsec = a->tv_nsec - b->tv_nsec ; 212 } 213 } 214 215 static void perf_stat__reset_stats(void) 216 { 217 perf_evlist__reset_stats(evsel_list); 218 perf_stat__reset_shadow_stats(); 219 } 220 221 static int create_perf_stat_counter(struct perf_evsel *evsel) 222 { 223 struct perf_event_attr *attr = &evsel->attr; 224 struct perf_evsel *leader = evsel->leader; 225 226 if (stat_config.scale) { 227 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 228 PERF_FORMAT_TOTAL_TIME_RUNNING; 229 } 230 231 /* 232 * The event is part of non trivial group, let's enable 233 * the group read (for leader) and ID retrieval for all 234 * members. 235 */ 236 if (leader->nr_members > 1) 237 attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP; 238 239 attr->inherit = !no_inherit; 240 241 /* 242 * Some events get initialized with sample_(period/type) set, 243 * like tracepoints. Clear it up for counting. 244 */ 245 attr->sample_period = 0; 246 247 /* 248 * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless 249 * while avoiding that older tools show confusing messages. 250 * 251 * However for pipe sessions we need to keep it zero, 252 * because script's perf_evsel__check_attr is triggered 253 * by attr->sample_type != 0, and we can't run it on 254 * stat sessions. 255 */ 256 if (!(STAT_RECORD && perf_stat.data.is_pipe)) 257 attr->sample_type = PERF_SAMPLE_IDENTIFIER; 258 259 /* 260 * Disabling all counters initially, they will be enabled 261 * either manually by us or by kernel via enable_on_exec 262 * set later. 263 */ 264 if (perf_evsel__is_group_leader(evsel)) { 265 attr->disabled = 1; 266 267 /* 268 * In case of initial_delay we enable tracee 269 * events manually. 270 */ 271 if (target__none(&target) && !initial_delay) 272 attr->enable_on_exec = 1; 273 } 274 275 if (target__has_cpu(&target)) 276 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 277 278 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 279 } 280 281 /* 282 * Does the counter have nsecs as a unit? 283 */ 284 static inline int nsec_counter(struct perf_evsel *evsel) 285 { 286 if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || 287 perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 288 return 1; 289 290 return 0; 291 } 292 293 static int process_synthesized_event(struct perf_tool *tool __maybe_unused, 294 union perf_event *event, 295 struct perf_sample *sample __maybe_unused, 296 struct machine *machine __maybe_unused) 297 { 298 if (perf_data__write(&perf_stat.data, event, event->header.size) < 0) { 299 pr_err("failed to write perf data, error: %m\n"); 300 return -1; 301 } 302 303 perf_stat.bytes_written += event->header.size; 304 return 0; 305 } 306 307 static int write_stat_round_event(u64 tm, u64 type) 308 { 309 return perf_event__synthesize_stat_round(NULL, tm, type, 310 process_synthesized_event, 311 NULL); 312 } 313 314 #define WRITE_STAT_ROUND_EVENT(time, interval) \ 315 write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval) 316 317 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) 318 319 static int 320 perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread, 321 struct perf_counts_values *count) 322 { 323 struct perf_sample_id *sid = SID(counter, cpu, thread); 324 325 return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count, 326 process_synthesized_event, NULL); 327 } 328 329 /* 330 * Read out the results of a single counter: 331 * do not aggregate counts across CPUs in system-wide mode 332 */ 333 static int read_counter(struct perf_evsel *counter) 334 { 335 int nthreads = thread_map__nr(evsel_list->threads); 336 int ncpus, cpu, thread; 337 338 if (target__has_cpu(&target)) 339 ncpus = perf_evsel__nr_cpus(counter); 340 else 341 ncpus = 1; 342 343 if (!counter->supported) 344 return -ENOENT; 345 346 if (counter->system_wide) 347 nthreads = 1; 348 349 for (thread = 0; thread < nthreads; thread++) { 350 for (cpu = 0; cpu < ncpus; cpu++) { 351 struct perf_counts_values *count; 352 353 count = perf_counts(counter->counts, cpu, thread); 354 355 /* 356 * The leader's group read loads data into its group members 357 * (via perf_evsel__read_counter) and sets threir count->loaded. 358 */ 359 if (!count->loaded && 360 perf_evsel__read_counter(counter, cpu, thread)) { 361 counter->counts->scaled = -1; 362 perf_counts(counter->counts, cpu, thread)->ena = 0; 363 perf_counts(counter->counts, cpu, thread)->run = 0; 364 return -1; 365 } 366 367 count->loaded = false; 368 369 if (STAT_RECORD) { 370 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { 371 pr_err("failed to write stat event\n"); 372 return -1; 373 } 374 } 375 376 if (verbose > 1) { 377 fprintf(stat_config.output, 378 "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 379 perf_evsel__name(counter), 380 cpu, 381 count->val, count->ena, count->run); 382 } 383 } 384 } 385 386 return 0; 387 } 388 389 static void read_counters(void) 390 { 391 struct perf_evsel *counter; 392 int ret; 393 394 evlist__for_each_entry(evsel_list, counter) { 395 ret = read_counter(counter); 396 if (ret) 397 pr_debug("failed to read counter %s\n", counter->name); 398 399 if (ret == 0 && perf_stat_process_counter(&stat_config, counter)) 400 pr_warning("failed to process counter %s\n", counter->name); 401 } 402 } 403 404 static void process_interval(void) 405 { 406 struct timespec ts, rs; 407 408 read_counters(); 409 410 clock_gettime(CLOCK_MONOTONIC, &ts); 411 diff_timespec(&rs, &ts, &ref_time); 412 413 if (STAT_RECORD) { 414 if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSEC_PER_SEC + rs.tv_nsec, INTERVAL)) 415 pr_err("failed to write stat round event\n"); 416 } 417 418 init_stats(&walltime_nsecs_stats); 419 update_stats(&walltime_nsecs_stats, stat_config.interval * 1000000); 420 print_counters(&rs, 0, NULL); 421 } 422 423 static void enable_counters(void) 424 { 425 if (initial_delay) 426 usleep(initial_delay * USEC_PER_MSEC); 427 428 /* 429 * We need to enable counters only if: 430 * - we don't have tracee (attaching to task or cpu) 431 * - we have initial delay configured 432 */ 433 if (!target__none(&target) || initial_delay) 434 perf_evlist__enable(evsel_list); 435 } 436 437 static void disable_counters(void) 438 { 439 /* 440 * If we don't have tracee (attaching to task or cpu), counters may 441 * still be running. To get accurate group ratios, we must stop groups 442 * from counting before reading their constituent counters. 443 */ 444 if (!target__none(&target)) 445 perf_evlist__disable(evsel_list); 446 } 447 448 static volatile int workload_exec_errno; 449 450 /* 451 * perf_evlist__prepare_workload will send a SIGUSR1 452 * if the fork fails, since we asked by setting its 453 * want_signal to true. 454 */ 455 static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info, 456 void *ucontext __maybe_unused) 457 { 458 workload_exec_errno = info->si_value.sival_int; 459 } 460 461 static bool has_unit(struct perf_evsel *counter) 462 { 463 return counter->unit && *counter->unit; 464 } 465 466 static bool has_scale(struct perf_evsel *counter) 467 { 468 return counter->scale != 1; 469 } 470 471 static int perf_stat_synthesize_config(bool is_pipe) 472 { 473 struct perf_evsel *counter; 474 int err; 475 476 if (is_pipe) { 477 err = perf_event__synthesize_attrs(NULL, perf_stat.session, 478 process_synthesized_event); 479 if (err < 0) { 480 pr_err("Couldn't synthesize attrs.\n"); 481 return err; 482 } 483 } 484 485 /* 486 * Synthesize other events stuff not carried within 487 * attr event - unit, scale, name 488 */ 489 evlist__for_each_entry(evsel_list, counter) { 490 if (!counter->supported) 491 continue; 492 493 /* 494 * Synthesize unit and scale only if it's defined. 495 */ 496 if (has_unit(counter)) { 497 err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event); 498 if (err < 0) { 499 pr_err("Couldn't synthesize evsel unit.\n"); 500 return err; 501 } 502 } 503 504 if (has_scale(counter)) { 505 err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event); 506 if (err < 0) { 507 pr_err("Couldn't synthesize evsel scale.\n"); 508 return err; 509 } 510 } 511 512 if (counter->own_cpus) { 513 err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event); 514 if (err < 0) { 515 pr_err("Couldn't synthesize evsel scale.\n"); 516 return err; 517 } 518 } 519 520 /* 521 * Name is needed only for pipe output, 522 * perf.data carries event names. 523 */ 524 if (is_pipe) { 525 err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event); 526 if (err < 0) { 527 pr_err("Couldn't synthesize evsel name.\n"); 528 return err; 529 } 530 } 531 } 532 533 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads, 534 process_synthesized_event, 535 NULL); 536 if (err < 0) { 537 pr_err("Couldn't synthesize thread map.\n"); 538 return err; 539 } 540 541 err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus, 542 process_synthesized_event, NULL); 543 if (err < 0) { 544 pr_err("Couldn't synthesize thread map.\n"); 545 return err; 546 } 547 548 err = perf_event__synthesize_stat_config(NULL, &stat_config, 549 process_synthesized_event, NULL); 550 if (err < 0) { 551 pr_err("Couldn't synthesize config.\n"); 552 return err; 553 } 554 555 return 0; 556 } 557 558 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 559 560 static int __store_counter_ids(struct perf_evsel *counter, 561 struct cpu_map *cpus, 562 struct thread_map *threads) 563 { 564 int cpu, thread; 565 566 for (cpu = 0; cpu < cpus->nr; cpu++) { 567 for (thread = 0; thread < threads->nr; thread++) { 568 int fd = FD(counter, cpu, thread); 569 570 if (perf_evlist__id_add_fd(evsel_list, counter, 571 cpu, thread, fd) < 0) 572 return -1; 573 } 574 } 575 576 return 0; 577 } 578 579 static int store_counter_ids(struct perf_evsel *counter) 580 { 581 struct cpu_map *cpus = counter->cpus; 582 struct thread_map *threads = counter->threads; 583 584 if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr)) 585 return -ENOMEM; 586 587 return __store_counter_ids(counter, cpus, threads); 588 } 589 590 static bool perf_evsel__should_store_id(struct perf_evsel *counter) 591 { 592 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; 593 } 594 595 static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel) 596 { 597 struct perf_evsel *c2, *leader; 598 bool is_open = true; 599 600 leader = evsel->leader; 601 pr_debug("Weak group for %s/%d failed\n", 602 leader->name, leader->nr_members); 603 604 /* 605 * for_each_group_member doesn't work here because it doesn't 606 * include the first entry. 607 */ 608 evlist__for_each_entry(evsel_list, c2) { 609 if (c2 == evsel) 610 is_open = false; 611 if (c2->leader == leader) { 612 if (is_open) 613 perf_evsel__close(c2); 614 c2->leader = c2; 615 c2->nr_members = 0; 616 } 617 } 618 return leader; 619 } 620 621 static int __run_perf_stat(int argc, const char **argv) 622 { 623 int interval = stat_config.interval; 624 char msg[BUFSIZ]; 625 unsigned long long t0, t1; 626 struct perf_evsel *counter; 627 struct timespec ts; 628 size_t l; 629 int status = 0; 630 const bool forks = (argc > 0); 631 bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false; 632 struct perf_evsel_config_term *err_term; 633 634 if (interval) { 635 ts.tv_sec = interval / USEC_PER_MSEC; 636 ts.tv_nsec = (interval % USEC_PER_MSEC) * NSEC_PER_MSEC; 637 } else { 638 ts.tv_sec = 1; 639 ts.tv_nsec = 0; 640 } 641 642 if (forks) { 643 if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe, 644 workload_exec_failed_signal) < 0) { 645 perror("failed to prepare workload"); 646 return -1; 647 } 648 child_pid = evsel_list->workload.pid; 649 } 650 651 if (group) 652 perf_evlist__set_leader(evsel_list); 653 654 evlist__for_each_entry(evsel_list, counter) { 655 try_again: 656 if (create_perf_stat_counter(counter) < 0) { 657 658 /* Weak group failed. Reset the group. */ 659 if ((errno == EINVAL || errno == EBADF) && 660 counter->leader != counter && 661 counter->weak_group) { 662 counter = perf_evsel__reset_weak_group(counter); 663 goto try_again; 664 } 665 666 /* 667 * PPC returns ENXIO for HW counters until 2.6.37 668 * (behavior changed with commit b0a873e). 669 */ 670 if (errno == EINVAL || errno == ENOSYS || 671 errno == ENOENT || errno == EOPNOTSUPP || 672 errno == ENXIO) { 673 if (verbose > 0) 674 ui__warning("%s event is not supported by the kernel.\n", 675 perf_evsel__name(counter)); 676 counter->supported = false; 677 678 if ((counter->leader != counter) || 679 !(counter->leader->nr_members > 1)) 680 continue; 681 } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { 682 if (verbose > 0) 683 ui__warning("%s\n", msg); 684 goto try_again; 685 } 686 687 perf_evsel__open_strerror(counter, &target, 688 errno, msg, sizeof(msg)); 689 ui__error("%s\n", msg); 690 691 if (child_pid != -1) 692 kill(child_pid, SIGTERM); 693 694 return -1; 695 } 696 counter->supported = true; 697 698 l = strlen(counter->unit); 699 if (l > unit_width) 700 unit_width = l; 701 702 if (perf_evsel__should_store_id(counter) && 703 store_counter_ids(counter)) 704 return -1; 705 } 706 707 if (perf_evlist__apply_filters(evsel_list, &counter)) { 708 pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", 709 counter->filter, perf_evsel__name(counter), errno, 710 str_error_r(errno, msg, sizeof(msg))); 711 return -1; 712 } 713 714 if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { 715 pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", 716 err_term->val.drv_cfg, perf_evsel__name(counter), errno, 717 str_error_r(errno, msg, sizeof(msg))); 718 return -1; 719 } 720 721 if (STAT_RECORD) { 722 int err, fd = perf_data__fd(&perf_stat.data); 723 724 if (is_pipe) { 725 err = perf_header__write_pipe(perf_data__fd(&perf_stat.data)); 726 } else { 727 err = perf_session__write_header(perf_stat.session, evsel_list, 728 fd, false); 729 } 730 731 if (err < 0) 732 return err; 733 734 err = perf_stat_synthesize_config(is_pipe); 735 if (err < 0) 736 return err; 737 } 738 739 /* 740 * Enable counters and exec the command: 741 */ 742 t0 = rdclock(); 743 clock_gettime(CLOCK_MONOTONIC, &ref_time); 744 745 if (forks) { 746 perf_evlist__start_workload(evsel_list); 747 enable_counters(); 748 749 if (interval) { 750 while (!waitpid(child_pid, &status, WNOHANG)) { 751 nanosleep(&ts, NULL); 752 process_interval(); 753 } 754 } 755 waitpid(child_pid, &status, 0); 756 757 if (workload_exec_errno) { 758 const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); 759 pr_err("Workload failed: %s\n", emsg); 760 return -1; 761 } 762 763 if (WIFSIGNALED(status)) 764 psignal(WTERMSIG(status), argv[0]); 765 } else { 766 enable_counters(); 767 while (!done) { 768 nanosleep(&ts, NULL); 769 if (interval) 770 process_interval(); 771 } 772 } 773 774 disable_counters(); 775 776 t1 = rdclock(); 777 778 update_stats(&walltime_nsecs_stats, t1 - t0); 779 780 /* 781 * Closing a group leader splits the group, and as we only disable 782 * group leaders, results in remaining events becoming enabled. To 783 * avoid arbitrary skew, we must read all counters before closing any 784 * group leaders. 785 */ 786 read_counters(); 787 perf_evlist__close(evsel_list); 788 789 return WEXITSTATUS(status); 790 } 791 792 static int run_perf_stat(int argc, const char **argv) 793 { 794 int ret; 795 796 if (pre_cmd) { 797 ret = system(pre_cmd); 798 if (ret) 799 return ret; 800 } 801 802 if (sync_run) 803 sync(); 804 805 ret = __run_perf_stat(argc, argv); 806 if (ret) 807 return ret; 808 809 if (post_cmd) { 810 ret = system(post_cmd); 811 if (ret) 812 return ret; 813 } 814 815 return ret; 816 } 817 818 static void print_running(u64 run, u64 ena) 819 { 820 if (csv_output) { 821 fprintf(stat_config.output, "%s%" PRIu64 "%s%.2f", 822 csv_sep, 823 run, 824 csv_sep, 825 ena ? 100.0 * run / ena : 100.0); 826 } else if (run != ena) { 827 fprintf(stat_config.output, " (%.2f%%)", 100.0 * run / ena); 828 } 829 } 830 831 static void print_noise_pct(double total, double avg) 832 { 833 double pct = rel_stddev_stats(total, avg); 834 835 if (csv_output) 836 fprintf(stat_config.output, "%s%.2f%%", csv_sep, pct); 837 else if (pct) 838 fprintf(stat_config.output, " ( +-%6.2f%% )", pct); 839 } 840 841 static void print_noise(struct perf_evsel *evsel, double avg) 842 { 843 struct perf_stat_evsel *ps; 844 845 if (run_count == 1) 846 return; 847 848 ps = evsel->stats; 849 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 850 } 851 852 static void aggr_printout(struct perf_evsel *evsel, int id, int nr) 853 { 854 switch (stat_config.aggr_mode) { 855 case AGGR_CORE: 856 fprintf(stat_config.output, "S%d-C%*d%s%*d%s", 857 cpu_map__id_to_socket(id), 858 csv_output ? 0 : -8, 859 cpu_map__id_to_cpu(id), 860 csv_sep, 861 csv_output ? 0 : 4, 862 nr, 863 csv_sep); 864 break; 865 case AGGR_SOCKET: 866 fprintf(stat_config.output, "S%*d%s%*d%s", 867 csv_output ? 0 : -5, 868 id, 869 csv_sep, 870 csv_output ? 0 : 4, 871 nr, 872 csv_sep); 873 break; 874 case AGGR_NONE: 875 fprintf(stat_config.output, "CPU%*d%s", 876 csv_output ? 0 : -4, 877 perf_evsel__cpus(evsel)->map[id], csv_sep); 878 break; 879 case AGGR_THREAD: 880 fprintf(stat_config.output, "%*s-%*d%s", 881 csv_output ? 0 : 16, 882 thread_map__comm(evsel->threads, id), 883 csv_output ? 0 : -8, 884 thread_map__pid(evsel->threads, id), 885 csv_sep); 886 break; 887 case AGGR_GLOBAL: 888 case AGGR_UNSET: 889 default: 890 break; 891 } 892 } 893 894 struct outstate { 895 FILE *fh; 896 bool newline; 897 const char *prefix; 898 int nfields; 899 int id, nr; 900 struct perf_evsel *evsel; 901 }; 902 903 #define METRIC_LEN 35 904 905 static void new_line_std(void *ctx) 906 { 907 struct outstate *os = ctx; 908 909 os->newline = true; 910 } 911 912 static void do_new_line_std(struct outstate *os) 913 { 914 fputc('\n', os->fh); 915 fputs(os->prefix, os->fh); 916 aggr_printout(os->evsel, os->id, os->nr); 917 if (stat_config.aggr_mode == AGGR_NONE) 918 fprintf(os->fh, " "); 919 fprintf(os->fh, " "); 920 } 921 922 static void print_metric_std(void *ctx, const char *color, const char *fmt, 923 const char *unit, double val) 924 { 925 struct outstate *os = ctx; 926 FILE *out = os->fh; 927 int n; 928 bool newline = os->newline; 929 930 os->newline = false; 931 932 if (unit == NULL || fmt == NULL) { 933 fprintf(out, "%-*s", METRIC_LEN, ""); 934 return; 935 } 936 937 if (newline) 938 do_new_line_std(os); 939 940 n = fprintf(out, " # "); 941 if (color) 942 n += color_fprintf(out, color, fmt, val); 943 else 944 n += fprintf(out, fmt, val); 945 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit); 946 } 947 948 static void new_line_csv(void *ctx) 949 { 950 struct outstate *os = ctx; 951 int i; 952 953 fputc('\n', os->fh); 954 if (os->prefix) 955 fprintf(os->fh, "%s%s", os->prefix, csv_sep); 956 aggr_printout(os->evsel, os->id, os->nr); 957 for (i = 0; i < os->nfields; i++) 958 fputs(csv_sep, os->fh); 959 } 960 961 static void print_metric_csv(void *ctx, 962 const char *color __maybe_unused, 963 const char *fmt, const char *unit, double val) 964 { 965 struct outstate *os = ctx; 966 FILE *out = os->fh; 967 char buf[64], *vals, *ends; 968 969 if (unit == NULL || fmt == NULL) { 970 fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep); 971 return; 972 } 973 snprintf(buf, sizeof(buf), fmt, val); 974 ends = vals = ltrim(buf); 975 while (isdigit(*ends) || *ends == '.') 976 ends++; 977 *ends = 0; 978 while (isspace(*unit)) 979 unit++; 980 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); 981 } 982 983 #define METRIC_ONLY_LEN 20 984 985 /* Filter out some columns that don't work well in metrics only mode */ 986 987 static bool valid_only_metric(const char *unit) 988 { 989 if (!unit) 990 return false; 991 if (strstr(unit, "/sec") || 992 strstr(unit, "hz") || 993 strstr(unit, "Hz") || 994 strstr(unit, "CPUs utilized")) 995 return false; 996 return true; 997 } 998 999 static const char *fixunit(char *buf, struct perf_evsel *evsel, 1000 const char *unit) 1001 { 1002 if (!strncmp(unit, "of all", 6)) { 1003 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel), 1004 unit); 1005 return buf; 1006 } 1007 return unit; 1008 } 1009 1010 static void print_metric_only(void *ctx, const char *color, const char *fmt, 1011 const char *unit, double val) 1012 { 1013 struct outstate *os = ctx; 1014 FILE *out = os->fh; 1015 int n; 1016 char buf[1024]; 1017 unsigned mlen = METRIC_ONLY_LEN; 1018 1019 if (!valid_only_metric(unit)) 1020 return; 1021 unit = fixunit(buf, os->evsel, unit); 1022 if (color) 1023 n = color_fprintf(out, color, fmt, val); 1024 else 1025 n = fprintf(out, fmt, val); 1026 if (n > METRIC_ONLY_LEN) 1027 n = METRIC_ONLY_LEN; 1028 if (mlen < strlen(unit)) 1029 mlen = strlen(unit) + 1; 1030 fprintf(out, "%*s", mlen - n, ""); 1031 } 1032 1033 static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, 1034 const char *fmt, 1035 const char *unit, double val) 1036 { 1037 struct outstate *os = ctx; 1038 FILE *out = os->fh; 1039 char buf[64], *vals, *ends; 1040 char tbuf[1024]; 1041 1042 if (!valid_only_metric(unit)) 1043 return; 1044 unit = fixunit(tbuf, os->evsel, unit); 1045 snprintf(buf, sizeof buf, fmt, val); 1046 ends = vals = ltrim(buf); 1047 while (isdigit(*ends) || *ends == '.') 1048 ends++; 1049 *ends = 0; 1050 fprintf(out, "%s%s", vals, csv_sep); 1051 } 1052 1053 static void new_line_metric(void *ctx __maybe_unused) 1054 { 1055 } 1056 1057 static void print_metric_header(void *ctx, const char *color __maybe_unused, 1058 const char *fmt __maybe_unused, 1059 const char *unit, double val __maybe_unused) 1060 { 1061 struct outstate *os = ctx; 1062 char tbuf[1024]; 1063 1064 if (!valid_only_metric(unit)) 1065 return; 1066 unit = fixunit(tbuf, os->evsel, unit); 1067 if (csv_output) 1068 fprintf(os->fh, "%s%s", unit, csv_sep); 1069 else 1070 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); 1071 } 1072 1073 static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 1074 { 1075 FILE *output = stat_config.output; 1076 double msecs = avg / NSEC_PER_MSEC; 1077 const char *fmt_v, *fmt_n; 1078 char name[25]; 1079 1080 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; 1081 fmt_n = csv_output ? "%s" : "%-25s"; 1082 1083 aggr_printout(evsel, id, nr); 1084 1085 scnprintf(name, sizeof(name), "%s%s", 1086 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 1087 1088 fprintf(output, fmt_v, msecs, csv_sep); 1089 1090 if (csv_output) 1091 fprintf(output, "%s%s", evsel->unit, csv_sep); 1092 else 1093 fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep); 1094 1095 fprintf(output, fmt_n, name); 1096 1097 if (evsel->cgrp) 1098 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1099 } 1100 1101 static int first_shadow_cpu(struct perf_evsel *evsel, int id) 1102 { 1103 int i; 1104 1105 if (!aggr_get_id) 1106 return 0; 1107 1108 if (stat_config.aggr_mode == AGGR_NONE) 1109 return id; 1110 1111 if (stat_config.aggr_mode == AGGR_GLOBAL) 1112 return 0; 1113 1114 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) { 1115 int cpu2 = perf_evsel__cpus(evsel)->map[i]; 1116 1117 if (aggr_get_id(evsel_list->cpus, cpu2) == id) 1118 return cpu2; 1119 } 1120 return 0; 1121 } 1122 1123 static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) 1124 { 1125 FILE *output = stat_config.output; 1126 double sc = evsel->scale; 1127 const char *fmt; 1128 1129 if (csv_output) { 1130 fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s"; 1131 } else { 1132 if (big_num) 1133 fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s"; 1134 else 1135 fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s"; 1136 } 1137 1138 aggr_printout(evsel, id, nr); 1139 1140 fprintf(output, fmt, avg, csv_sep); 1141 1142 if (evsel->unit) 1143 fprintf(output, "%-*s%s", 1144 csv_output ? 0 : unit_width, 1145 evsel->unit, csv_sep); 1146 1147 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel)); 1148 1149 if (evsel->cgrp) 1150 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1151 } 1152 1153 static void printout(int id, int nr, struct perf_evsel *counter, double uval, 1154 char *prefix, u64 run, u64 ena, double noise) 1155 { 1156 struct perf_stat_output_ctx out; 1157 struct outstate os = { 1158 .fh = stat_config.output, 1159 .prefix = prefix ? prefix : "", 1160 .id = id, 1161 .nr = nr, 1162 .evsel = counter, 1163 }; 1164 print_metric_t pm = print_metric_std; 1165 void (*nl)(void *); 1166 1167 if (metric_only) { 1168 nl = new_line_metric; 1169 if (csv_output) 1170 pm = print_metric_only_csv; 1171 else 1172 pm = print_metric_only; 1173 } else 1174 nl = new_line_std; 1175 1176 if (csv_output && !metric_only) { 1177 static int aggr_fields[] = { 1178 [AGGR_GLOBAL] = 0, 1179 [AGGR_THREAD] = 1, 1180 [AGGR_NONE] = 1, 1181 [AGGR_SOCKET] = 2, 1182 [AGGR_CORE] = 2, 1183 }; 1184 1185 pm = print_metric_csv; 1186 nl = new_line_csv; 1187 os.nfields = 3; 1188 os.nfields += aggr_fields[stat_config.aggr_mode]; 1189 if (counter->cgrp) 1190 os.nfields++; 1191 } 1192 if (run == 0 || ena == 0 || counter->counts->scaled == -1) { 1193 if (metric_only) { 1194 pm(&os, NULL, "", "", 0); 1195 return; 1196 } 1197 aggr_printout(counter, id, nr); 1198 1199 fprintf(stat_config.output, "%*s%s", 1200 csv_output ? 0 : 18, 1201 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1202 csv_sep); 1203 1204 if (counter->supported) 1205 print_free_counters_hint = 1; 1206 1207 fprintf(stat_config.output, "%-*s%s", 1208 csv_output ? 0 : unit_width, 1209 counter->unit, csv_sep); 1210 1211 fprintf(stat_config.output, "%*s", 1212 csv_output ? 0 : -25, 1213 perf_evsel__name(counter)); 1214 1215 if (counter->cgrp) 1216 fprintf(stat_config.output, "%s%s", 1217 csv_sep, counter->cgrp->name); 1218 1219 if (!csv_output) 1220 pm(&os, NULL, NULL, "", 0); 1221 print_noise(counter, noise); 1222 print_running(run, ena); 1223 if (csv_output) 1224 pm(&os, NULL, NULL, "", 0); 1225 return; 1226 } 1227 1228 if (metric_only) 1229 /* nothing */; 1230 else if (nsec_counter(counter)) 1231 nsec_printout(id, nr, counter, uval); 1232 else 1233 abs_printout(id, nr, counter, uval); 1234 1235 out.print_metric = pm; 1236 out.new_line = nl; 1237 out.ctx = &os; 1238 out.force_header = false; 1239 1240 if (csv_output && !metric_only) { 1241 print_noise(counter, noise); 1242 print_running(run, ena); 1243 } 1244 1245 perf_stat__print_shadow_stats(counter, uval, 1246 first_shadow_cpu(counter, id), 1247 &out, &metric_events); 1248 if (!csv_output && !metric_only) { 1249 print_noise(counter, noise); 1250 print_running(run, ena); 1251 } 1252 } 1253 1254 static void aggr_update_shadow(void) 1255 { 1256 int cpu, s2, id, s; 1257 u64 val; 1258 struct perf_evsel *counter; 1259 1260 for (s = 0; s < aggr_map->nr; s++) { 1261 id = aggr_map->map[s]; 1262 evlist__for_each_entry(evsel_list, counter) { 1263 val = 0; 1264 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1265 s2 = aggr_get_id(evsel_list->cpus, cpu); 1266 if (s2 != id) 1267 continue; 1268 val += perf_counts(counter->counts, cpu, 0)->val; 1269 } 1270 perf_stat__update_shadow_stats(counter, val, 1271 first_shadow_cpu(counter, id)); 1272 } 1273 } 1274 } 1275 1276 static void collect_all_aliases(struct perf_evsel *counter, 1277 void (*cb)(struct perf_evsel *counter, void *data, 1278 bool first), 1279 void *data) 1280 { 1281 struct perf_evsel *alias; 1282 1283 alias = list_prepare_entry(counter, &(evsel_list->entries), node); 1284 list_for_each_entry_continue (alias, &evsel_list->entries, node) { 1285 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) || 1286 alias->scale != counter->scale || 1287 alias->cgrp != counter->cgrp || 1288 strcmp(alias->unit, counter->unit) || 1289 nsec_counter(alias) != nsec_counter(counter)) 1290 break; 1291 alias->merged_stat = true; 1292 cb(alias, data, false); 1293 } 1294 } 1295 1296 static bool collect_data(struct perf_evsel *counter, 1297 void (*cb)(struct perf_evsel *counter, void *data, 1298 bool first), 1299 void *data) 1300 { 1301 if (counter->merged_stat) 1302 return false; 1303 cb(counter, data, true); 1304 if (!no_merge && counter->auto_merge_stats) 1305 collect_all_aliases(counter, cb, data); 1306 return true; 1307 } 1308 1309 struct aggr_data { 1310 u64 ena, run, val; 1311 int id; 1312 int nr; 1313 int cpu; 1314 }; 1315 1316 static void aggr_cb(struct perf_evsel *counter, void *data, bool first) 1317 { 1318 struct aggr_data *ad = data; 1319 int cpu, s2; 1320 1321 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1322 struct perf_counts_values *counts; 1323 1324 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu); 1325 if (s2 != ad->id) 1326 continue; 1327 if (first) 1328 ad->nr++; 1329 counts = perf_counts(counter->counts, cpu, 0); 1330 /* 1331 * When any result is bad, make them all to give 1332 * consistent output in interval mode. 1333 */ 1334 if (counts->ena == 0 || counts->run == 0 || 1335 counter->counts->scaled == -1) { 1336 ad->ena = 0; 1337 ad->run = 0; 1338 break; 1339 } 1340 ad->val += counts->val; 1341 ad->ena += counts->ena; 1342 ad->run += counts->run; 1343 } 1344 } 1345 1346 static void print_aggr(char *prefix) 1347 { 1348 FILE *output = stat_config.output; 1349 struct perf_evsel *counter; 1350 int s, id, nr; 1351 double uval; 1352 u64 ena, run, val; 1353 bool first; 1354 1355 if (!(aggr_map || aggr_get_id)) 1356 return; 1357 1358 aggr_update_shadow(); 1359 1360 /* 1361 * With metric_only everything is on a single line. 1362 * Without each counter has its own line. 1363 */ 1364 for (s = 0; s < aggr_map->nr; s++) { 1365 struct aggr_data ad; 1366 if (prefix && metric_only) 1367 fprintf(output, "%s", prefix); 1368 1369 ad.id = id = aggr_map->map[s]; 1370 first = true; 1371 evlist__for_each_entry(evsel_list, counter) { 1372 if (is_duration_time(counter)) 1373 continue; 1374 1375 ad.val = ad.ena = ad.run = 0; 1376 ad.nr = 0; 1377 if (!collect_data(counter, aggr_cb, &ad)) 1378 continue; 1379 nr = ad.nr; 1380 ena = ad.ena; 1381 run = ad.run; 1382 val = ad.val; 1383 if (first && metric_only) { 1384 first = false; 1385 aggr_printout(counter, id, nr); 1386 } 1387 if (prefix && !metric_only) 1388 fprintf(output, "%s", prefix); 1389 1390 uval = val * counter->scale; 1391 printout(id, nr, counter, uval, prefix, run, ena, 1.0); 1392 if (!metric_only) 1393 fputc('\n', output); 1394 } 1395 if (metric_only) 1396 fputc('\n', output); 1397 } 1398 } 1399 1400 static void print_aggr_thread(struct perf_evsel *counter, char *prefix) 1401 { 1402 FILE *output = stat_config.output; 1403 int nthreads = thread_map__nr(counter->threads); 1404 int ncpus = cpu_map__nr(counter->cpus); 1405 int cpu, thread; 1406 double uval; 1407 1408 for (thread = 0; thread < nthreads; thread++) { 1409 u64 ena = 0, run = 0, val = 0; 1410 1411 for (cpu = 0; cpu < ncpus; cpu++) { 1412 val += perf_counts(counter->counts, cpu, thread)->val; 1413 ena += perf_counts(counter->counts, cpu, thread)->ena; 1414 run += perf_counts(counter->counts, cpu, thread)->run; 1415 } 1416 1417 if (prefix) 1418 fprintf(output, "%s", prefix); 1419 1420 uval = val * counter->scale; 1421 printout(thread, 0, counter, uval, prefix, run, ena, 1.0); 1422 fputc('\n', output); 1423 } 1424 } 1425 1426 struct caggr_data { 1427 double avg, avg_enabled, avg_running; 1428 }; 1429 1430 static void counter_aggr_cb(struct perf_evsel *counter, void *data, 1431 bool first __maybe_unused) 1432 { 1433 struct caggr_data *cd = data; 1434 struct perf_stat_evsel *ps = counter->stats; 1435 1436 cd->avg += avg_stats(&ps->res_stats[0]); 1437 cd->avg_enabled += avg_stats(&ps->res_stats[1]); 1438 cd->avg_running += avg_stats(&ps->res_stats[2]); 1439 } 1440 1441 /* 1442 * Print out the results of a single counter: 1443 * aggregated counts in system-wide mode 1444 */ 1445 static void print_counter_aggr(struct perf_evsel *counter, char *prefix) 1446 { 1447 FILE *output = stat_config.output; 1448 double uval; 1449 struct caggr_data cd = { .avg = 0.0 }; 1450 1451 if (!collect_data(counter, counter_aggr_cb, &cd)) 1452 return; 1453 1454 if (prefix && !metric_only) 1455 fprintf(output, "%s", prefix); 1456 1457 uval = cd.avg * counter->scale; 1458 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled, cd.avg); 1459 if (!metric_only) 1460 fprintf(output, "\n"); 1461 } 1462 1463 static void counter_cb(struct perf_evsel *counter, void *data, 1464 bool first __maybe_unused) 1465 { 1466 struct aggr_data *ad = data; 1467 1468 ad->val += perf_counts(counter->counts, ad->cpu, 0)->val; 1469 ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena; 1470 ad->run += perf_counts(counter->counts, ad->cpu, 0)->run; 1471 } 1472 1473 /* 1474 * Print out the results of a single counter: 1475 * does not use aggregated count in system-wide 1476 */ 1477 static void print_counter(struct perf_evsel *counter, char *prefix) 1478 { 1479 FILE *output = stat_config.output; 1480 u64 ena, run, val; 1481 double uval; 1482 int cpu; 1483 1484 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1485 struct aggr_data ad = { .cpu = cpu }; 1486 1487 if (!collect_data(counter, counter_cb, &ad)) 1488 return; 1489 val = ad.val; 1490 ena = ad.ena; 1491 run = ad.run; 1492 1493 if (prefix) 1494 fprintf(output, "%s", prefix); 1495 1496 uval = val * counter->scale; 1497 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0); 1498 1499 fputc('\n', output); 1500 } 1501 } 1502 1503 static void print_no_aggr_metric(char *prefix) 1504 { 1505 int cpu; 1506 int nrcpus = 0; 1507 struct perf_evsel *counter; 1508 u64 ena, run, val; 1509 double uval; 1510 1511 nrcpus = evsel_list->cpus->nr; 1512 for (cpu = 0; cpu < nrcpus; cpu++) { 1513 bool first = true; 1514 1515 if (prefix) 1516 fputs(prefix, stat_config.output); 1517 evlist__for_each_entry(evsel_list, counter) { 1518 if (is_duration_time(counter)) 1519 continue; 1520 if (first) { 1521 aggr_printout(counter, cpu, 0); 1522 first = false; 1523 } 1524 val = perf_counts(counter->counts, cpu, 0)->val; 1525 ena = perf_counts(counter->counts, cpu, 0)->ena; 1526 run = perf_counts(counter->counts, cpu, 0)->run; 1527 1528 uval = val * counter->scale; 1529 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0); 1530 } 1531 fputc('\n', stat_config.output); 1532 } 1533 } 1534 1535 static int aggr_header_lens[] = { 1536 [AGGR_CORE] = 18, 1537 [AGGR_SOCKET] = 12, 1538 [AGGR_NONE] = 6, 1539 [AGGR_THREAD] = 24, 1540 [AGGR_GLOBAL] = 0, 1541 }; 1542 1543 static const char *aggr_header_csv[] = { 1544 [AGGR_CORE] = "core,cpus,", 1545 [AGGR_SOCKET] = "socket,cpus", 1546 [AGGR_NONE] = "cpu,", 1547 [AGGR_THREAD] = "comm-pid,", 1548 [AGGR_GLOBAL] = "" 1549 }; 1550 1551 static void print_metric_headers(const char *prefix, bool no_indent) 1552 { 1553 struct perf_stat_output_ctx out; 1554 struct perf_evsel *counter; 1555 struct outstate os = { 1556 .fh = stat_config.output 1557 }; 1558 1559 if (prefix) 1560 fprintf(stat_config.output, "%s", prefix); 1561 1562 if (!csv_output && !no_indent) 1563 fprintf(stat_config.output, "%*s", 1564 aggr_header_lens[stat_config.aggr_mode], ""); 1565 if (csv_output) { 1566 if (stat_config.interval) 1567 fputs("time,", stat_config.output); 1568 fputs(aggr_header_csv[stat_config.aggr_mode], 1569 stat_config.output); 1570 } 1571 1572 /* Print metrics headers only */ 1573 evlist__for_each_entry(evsel_list, counter) { 1574 if (is_duration_time(counter)) 1575 continue; 1576 os.evsel = counter; 1577 out.ctx = &os; 1578 out.print_metric = print_metric_header; 1579 out.new_line = new_line_metric; 1580 out.force_header = true; 1581 os.evsel = counter; 1582 perf_stat__print_shadow_stats(counter, 0, 1583 0, 1584 &out, 1585 &metric_events); 1586 } 1587 fputc('\n', stat_config.output); 1588 } 1589 1590 static void print_interval(char *prefix, struct timespec *ts) 1591 { 1592 FILE *output = stat_config.output; 1593 static int num_print_interval; 1594 1595 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1596 1597 if (num_print_interval == 0 && !csv_output) { 1598 switch (stat_config.aggr_mode) { 1599 case AGGR_SOCKET: 1600 fprintf(output, "# time socket cpus"); 1601 if (!metric_only) 1602 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1603 break; 1604 case AGGR_CORE: 1605 fprintf(output, "# time core cpus"); 1606 if (!metric_only) 1607 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1608 break; 1609 case AGGR_NONE: 1610 fprintf(output, "# time CPU"); 1611 if (!metric_only) 1612 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1613 break; 1614 case AGGR_THREAD: 1615 fprintf(output, "# time comm-pid"); 1616 if (!metric_only) 1617 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1618 break; 1619 case AGGR_GLOBAL: 1620 default: 1621 fprintf(output, "# time"); 1622 if (!metric_only) 1623 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1624 case AGGR_UNSET: 1625 break; 1626 } 1627 } 1628 1629 if (num_print_interval == 0 && metric_only) 1630 print_metric_headers(" ", true); 1631 if (++num_print_interval == 25) 1632 num_print_interval = 0; 1633 } 1634 1635 static void print_header(int argc, const char **argv) 1636 { 1637 FILE *output = stat_config.output; 1638 int i; 1639 1640 fflush(stdout); 1641 1642 if (!csv_output) { 1643 fprintf(output, "\n"); 1644 fprintf(output, " Performance counter stats for "); 1645 if (target.system_wide) 1646 fprintf(output, "\'system wide"); 1647 else if (target.cpu_list) 1648 fprintf(output, "\'CPU(s) %s", target.cpu_list); 1649 else if (!target__has_task(&target)) { 1650 fprintf(output, "\'%s", argv ? argv[0] : "pipe"); 1651 for (i = 1; argv && (i < argc); i++) 1652 fprintf(output, " %s", argv[i]); 1653 } else if (target.pid) 1654 fprintf(output, "process id \'%s", target.pid); 1655 else 1656 fprintf(output, "thread id \'%s", target.tid); 1657 1658 fprintf(output, "\'"); 1659 if (run_count > 1) 1660 fprintf(output, " (%d runs)", run_count); 1661 fprintf(output, ":\n\n"); 1662 } 1663 } 1664 1665 static void print_footer(void) 1666 { 1667 FILE *output = stat_config.output; 1668 int n; 1669 1670 if (!null_run) 1671 fprintf(output, "\n"); 1672 fprintf(output, " %17.9f seconds time elapsed", 1673 avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC); 1674 if (run_count > 1) { 1675 fprintf(output, " "); 1676 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 1677 avg_stats(&walltime_nsecs_stats)); 1678 } 1679 fprintf(output, "\n\n"); 1680 1681 if (print_free_counters_hint && 1682 sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 && 1683 n > 0) 1684 fprintf(output, 1685 "Some events weren't counted. Try disabling the NMI watchdog:\n" 1686 " echo 0 > /proc/sys/kernel/nmi_watchdog\n" 1687 " perf stat ...\n" 1688 " echo 1 > /proc/sys/kernel/nmi_watchdog\n"); 1689 } 1690 1691 static void print_counters(struct timespec *ts, int argc, const char **argv) 1692 { 1693 int interval = stat_config.interval; 1694 struct perf_evsel *counter; 1695 char buf[64], *prefix = NULL; 1696 1697 /* Do not print anything if we record to the pipe. */ 1698 if (STAT_RECORD && perf_stat.data.is_pipe) 1699 return; 1700 1701 if (interval) 1702 print_interval(prefix = buf, ts); 1703 else 1704 print_header(argc, argv); 1705 1706 if (metric_only) { 1707 static int num_print_iv; 1708 1709 if (num_print_iv == 0 && !interval) 1710 print_metric_headers(prefix, false); 1711 if (num_print_iv++ == 25) 1712 num_print_iv = 0; 1713 if (stat_config.aggr_mode == AGGR_GLOBAL && prefix) 1714 fprintf(stat_config.output, "%s", prefix); 1715 } 1716 1717 switch (stat_config.aggr_mode) { 1718 case AGGR_CORE: 1719 case AGGR_SOCKET: 1720 print_aggr(prefix); 1721 break; 1722 case AGGR_THREAD: 1723 evlist__for_each_entry(evsel_list, counter) { 1724 if (is_duration_time(counter)) 1725 continue; 1726 print_aggr_thread(counter, prefix); 1727 } 1728 break; 1729 case AGGR_GLOBAL: 1730 evlist__for_each_entry(evsel_list, counter) { 1731 if (is_duration_time(counter)) 1732 continue; 1733 print_counter_aggr(counter, prefix); 1734 } 1735 if (metric_only) 1736 fputc('\n', stat_config.output); 1737 break; 1738 case AGGR_NONE: 1739 if (metric_only) 1740 print_no_aggr_metric(prefix); 1741 else { 1742 evlist__for_each_entry(evsel_list, counter) { 1743 if (is_duration_time(counter)) 1744 continue; 1745 print_counter(counter, prefix); 1746 } 1747 } 1748 break; 1749 case AGGR_UNSET: 1750 default: 1751 break; 1752 } 1753 1754 if (!interval && !csv_output) 1755 print_footer(); 1756 1757 fflush(stat_config.output); 1758 } 1759 1760 static volatile int signr = -1; 1761 1762 static void skip_signal(int signo) 1763 { 1764 if ((child_pid == -1) || stat_config.interval) 1765 done = 1; 1766 1767 signr = signo; 1768 /* 1769 * render child_pid harmless 1770 * won't send SIGTERM to a random 1771 * process in case of race condition 1772 * and fast PID recycling 1773 */ 1774 child_pid = -1; 1775 } 1776 1777 static void sig_atexit(void) 1778 { 1779 sigset_t set, oset; 1780 1781 /* 1782 * avoid race condition with SIGCHLD handler 1783 * in skip_signal() which is modifying child_pid 1784 * goal is to avoid send SIGTERM to a random 1785 * process 1786 */ 1787 sigemptyset(&set); 1788 sigaddset(&set, SIGCHLD); 1789 sigprocmask(SIG_BLOCK, &set, &oset); 1790 1791 if (child_pid != -1) 1792 kill(child_pid, SIGTERM); 1793 1794 sigprocmask(SIG_SETMASK, &oset, NULL); 1795 1796 if (signr == -1) 1797 return; 1798 1799 signal(signr, SIG_DFL); 1800 kill(getpid(), signr); 1801 } 1802 1803 static int stat__set_big_num(const struct option *opt __maybe_unused, 1804 const char *s __maybe_unused, int unset) 1805 { 1806 big_num_opt = unset ? 0 : 1; 1807 return 0; 1808 } 1809 1810 static int enable_metric_only(const struct option *opt __maybe_unused, 1811 const char *s __maybe_unused, int unset) 1812 { 1813 force_metric_only = true; 1814 metric_only = !unset; 1815 return 0; 1816 } 1817 1818 static int parse_metric_groups(const struct option *opt, 1819 const char *str, 1820 int unset __maybe_unused) 1821 { 1822 return metricgroup__parse_groups(opt, str, &metric_events); 1823 } 1824 1825 static const struct option stat_options[] = { 1826 OPT_BOOLEAN('T', "transaction", &transaction_run, 1827 "hardware transaction statistics"), 1828 OPT_CALLBACK('e', "event", &evsel_list, "event", 1829 "event selector. use 'perf list' to list available events", 1830 parse_events_option), 1831 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 1832 "event filter", parse_filter), 1833 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1834 "child tasks do not inherit counters"), 1835 OPT_STRING('p', "pid", &target.pid, "pid", 1836 "stat events on existing process id"), 1837 OPT_STRING('t', "tid", &target.tid, "tid", 1838 "stat events on existing thread id"), 1839 OPT_BOOLEAN('a', "all-cpus", &target.system_wide, 1840 "system-wide collection from all CPUs"), 1841 OPT_BOOLEAN('g', "group", &group, 1842 "put the counters into a counter group"), 1843 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), 1844 OPT_INCR('v', "verbose", &verbose, 1845 "be more verbose (show counter open errors, etc)"), 1846 OPT_INTEGER('r', "repeat", &run_count, 1847 "repeat command and print average + stddev (max: 100, forever: 0)"), 1848 OPT_BOOLEAN('n', "null", &null_run, 1849 "null run - dont start any counters"), 1850 OPT_INCR('d', "detailed", &detailed_run, 1851 "detailed run - start a lot of events"), 1852 OPT_BOOLEAN('S', "sync", &sync_run, 1853 "call sync() before starting a run"), 1854 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 1855 "print large numbers with thousands\' separators", 1856 stat__set_big_num), 1857 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1858 "list of cpus to monitor in system-wide"), 1859 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 1860 "disable CPU count aggregation", AGGR_NONE), 1861 OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"), 1862 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1863 "print counts with custom separator"), 1864 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1865 "monitor event in cgroup name only", parse_cgroups), 1866 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1867 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), 1868 OPT_INTEGER(0, "log-fd", &output_fd, 1869 "log output to fd, instead of stderr"), 1870 OPT_STRING(0, "pre", &pre_cmd, "command", 1871 "command to run prior to the measured command"), 1872 OPT_STRING(0, "post", &post_cmd, "command", 1873 "command to run after to the measured command"), 1874 OPT_UINTEGER('I', "interval-print", &stat_config.interval, 1875 "print counts at regular interval in ms (>= 10)"), 1876 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, 1877 "aggregate counts per processor socket", AGGR_SOCKET), 1878 OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, 1879 "aggregate counts per physical processor core", AGGR_CORE), 1880 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, 1881 "aggregate counts per thread", AGGR_THREAD), 1882 OPT_UINTEGER('D', "delay", &initial_delay, 1883 "ms to wait before starting measurement after program start"), 1884 OPT_CALLBACK_NOOPT(0, "metric-only", &metric_only, NULL, 1885 "Only print computed metrics. No raw values", enable_metric_only), 1886 OPT_BOOLEAN(0, "topdown", &topdown_run, 1887 "measure topdown level 1 statistics"), 1888 OPT_BOOLEAN(0, "smi-cost", &smi_cost, 1889 "measure SMI cost"), 1890 OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list", 1891 "monitor specified metrics or metric groups (separated by ,)", 1892 parse_metric_groups), 1893 OPT_END() 1894 }; 1895 1896 static int perf_stat__get_socket(struct cpu_map *map, int cpu) 1897 { 1898 return cpu_map__get_socket(map, cpu, NULL); 1899 } 1900 1901 static int perf_stat__get_core(struct cpu_map *map, int cpu) 1902 { 1903 return cpu_map__get_core(map, cpu, NULL); 1904 } 1905 1906 static int cpu_map__get_max(struct cpu_map *map) 1907 { 1908 int i, max = -1; 1909 1910 for (i = 0; i < map->nr; i++) { 1911 if (map->map[i] > max) 1912 max = map->map[i]; 1913 } 1914 1915 return max; 1916 } 1917 1918 static struct cpu_map *cpus_aggr_map; 1919 1920 static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) 1921 { 1922 int cpu; 1923 1924 if (idx >= map->nr) 1925 return -1; 1926 1927 cpu = map->map[idx]; 1928 1929 if (cpus_aggr_map->map[cpu] == -1) 1930 cpus_aggr_map->map[cpu] = get_id(map, idx); 1931 1932 return cpus_aggr_map->map[cpu]; 1933 } 1934 1935 static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) 1936 { 1937 return perf_stat__get_aggr(perf_stat__get_socket, map, idx); 1938 } 1939 1940 static int perf_stat__get_core_cached(struct cpu_map *map, int idx) 1941 { 1942 return perf_stat__get_aggr(perf_stat__get_core, map, idx); 1943 } 1944 1945 static int perf_stat_init_aggr_mode(void) 1946 { 1947 int nr; 1948 1949 switch (stat_config.aggr_mode) { 1950 case AGGR_SOCKET: 1951 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { 1952 perror("cannot build socket map"); 1953 return -1; 1954 } 1955 aggr_get_id = perf_stat__get_socket_cached; 1956 break; 1957 case AGGR_CORE: 1958 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { 1959 perror("cannot build core map"); 1960 return -1; 1961 } 1962 aggr_get_id = perf_stat__get_core_cached; 1963 break; 1964 case AGGR_NONE: 1965 case AGGR_GLOBAL: 1966 case AGGR_THREAD: 1967 case AGGR_UNSET: 1968 default: 1969 break; 1970 } 1971 1972 /* 1973 * The evsel_list->cpus is the base we operate on, 1974 * taking the highest cpu number to be the size of 1975 * the aggregation translate cpumap. 1976 */ 1977 nr = cpu_map__get_max(evsel_list->cpus); 1978 cpus_aggr_map = cpu_map__empty_new(nr + 1); 1979 return cpus_aggr_map ? 0 : -ENOMEM; 1980 } 1981 1982 static void perf_stat__exit_aggr_mode(void) 1983 { 1984 cpu_map__put(aggr_map); 1985 cpu_map__put(cpus_aggr_map); 1986 aggr_map = NULL; 1987 cpus_aggr_map = NULL; 1988 } 1989 1990 static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx) 1991 { 1992 int cpu; 1993 1994 if (idx > map->nr) 1995 return -1; 1996 1997 cpu = map->map[idx]; 1998 1999 if (cpu >= env->nr_cpus_avail) 2000 return -1; 2001 2002 return cpu; 2003 } 2004 2005 static int perf_env__get_socket(struct cpu_map *map, int idx, void *data) 2006 { 2007 struct perf_env *env = data; 2008 int cpu = perf_env__get_cpu(env, map, idx); 2009 2010 return cpu == -1 ? -1 : env->cpu[cpu].socket_id; 2011 } 2012 2013 static int perf_env__get_core(struct cpu_map *map, int idx, void *data) 2014 { 2015 struct perf_env *env = data; 2016 int core = -1, cpu = perf_env__get_cpu(env, map, idx); 2017 2018 if (cpu != -1) { 2019 int socket_id = env->cpu[cpu].socket_id; 2020 2021 /* 2022 * Encode socket in upper 16 bits 2023 * core_id is relative to socket, and 2024 * we need a global id. So we combine 2025 * socket + core id. 2026 */ 2027 core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff); 2028 } 2029 2030 return core; 2031 } 2032 2033 static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus, 2034 struct cpu_map **sockp) 2035 { 2036 return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env); 2037 } 2038 2039 static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus, 2040 struct cpu_map **corep) 2041 { 2042 return cpu_map__build_map(cpus, corep, perf_env__get_core, env); 2043 } 2044 2045 static int perf_stat__get_socket_file(struct cpu_map *map, int idx) 2046 { 2047 return perf_env__get_socket(map, idx, &perf_stat.session->header.env); 2048 } 2049 2050 static int perf_stat__get_core_file(struct cpu_map *map, int idx) 2051 { 2052 return perf_env__get_core(map, idx, &perf_stat.session->header.env); 2053 } 2054 2055 static int perf_stat_init_aggr_mode_file(struct perf_stat *st) 2056 { 2057 struct perf_env *env = &st->session->header.env; 2058 2059 switch (stat_config.aggr_mode) { 2060 case AGGR_SOCKET: 2061 if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) { 2062 perror("cannot build socket map"); 2063 return -1; 2064 } 2065 aggr_get_id = perf_stat__get_socket_file; 2066 break; 2067 case AGGR_CORE: 2068 if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) { 2069 perror("cannot build core map"); 2070 return -1; 2071 } 2072 aggr_get_id = perf_stat__get_core_file; 2073 break; 2074 case AGGR_NONE: 2075 case AGGR_GLOBAL: 2076 case AGGR_THREAD: 2077 case AGGR_UNSET: 2078 default: 2079 break; 2080 } 2081 2082 return 0; 2083 } 2084 2085 static int topdown_filter_events(const char **attr, char **str, bool use_group) 2086 { 2087 int off = 0; 2088 int i; 2089 int len = 0; 2090 char *s; 2091 2092 for (i = 0; attr[i]; i++) { 2093 if (pmu_have_event("cpu", attr[i])) { 2094 len += strlen(attr[i]) + 1; 2095 attr[i - off] = attr[i]; 2096 } else 2097 off++; 2098 } 2099 attr[i - off] = NULL; 2100 2101 *str = malloc(len + 1 + 2); 2102 if (!*str) 2103 return -1; 2104 s = *str; 2105 if (i - off == 0) { 2106 *s = 0; 2107 return 0; 2108 } 2109 if (use_group) 2110 *s++ = '{'; 2111 for (i = 0; attr[i]; i++) { 2112 strcpy(s, attr[i]); 2113 s += strlen(s); 2114 *s++ = ','; 2115 } 2116 if (use_group) { 2117 s[-1] = '}'; 2118 *s = 0; 2119 } else 2120 s[-1] = 0; 2121 return 0; 2122 } 2123 2124 __weak bool arch_topdown_check_group(bool *warn) 2125 { 2126 *warn = false; 2127 return false; 2128 } 2129 2130 __weak void arch_topdown_group_warn(void) 2131 { 2132 } 2133 2134 /* 2135 * Add default attributes, if there were no attributes specified or 2136 * if -d/--detailed, -d -d or -d -d -d is used: 2137 */ 2138 static int add_default_attributes(void) 2139 { 2140 int err; 2141 struct perf_event_attr default_attrs0[] = { 2142 2143 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 2144 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 2145 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, 2146 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 2147 2148 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 2149 }; 2150 struct perf_event_attr frontend_attrs[] = { 2151 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, 2152 }; 2153 struct perf_event_attr backend_attrs[] = { 2154 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, 2155 }; 2156 struct perf_event_attr default_attrs1[] = { 2157 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 2158 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 2159 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 2160 2161 }; 2162 2163 /* 2164 * Detailed stats (-d), covering the L1 and last level data caches: 2165 */ 2166 struct perf_event_attr detailed_attrs[] = { 2167 2168 { .type = PERF_TYPE_HW_CACHE, 2169 .config = 2170 PERF_COUNT_HW_CACHE_L1D << 0 | 2171 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2172 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2173 2174 { .type = PERF_TYPE_HW_CACHE, 2175 .config = 2176 PERF_COUNT_HW_CACHE_L1D << 0 | 2177 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2178 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2179 2180 { .type = PERF_TYPE_HW_CACHE, 2181 .config = 2182 PERF_COUNT_HW_CACHE_LL << 0 | 2183 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2184 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2185 2186 { .type = PERF_TYPE_HW_CACHE, 2187 .config = 2188 PERF_COUNT_HW_CACHE_LL << 0 | 2189 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2190 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2191 }; 2192 2193 /* 2194 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: 2195 */ 2196 struct perf_event_attr very_detailed_attrs[] = { 2197 2198 { .type = PERF_TYPE_HW_CACHE, 2199 .config = 2200 PERF_COUNT_HW_CACHE_L1I << 0 | 2201 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2202 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2203 2204 { .type = PERF_TYPE_HW_CACHE, 2205 .config = 2206 PERF_COUNT_HW_CACHE_L1I << 0 | 2207 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2208 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2209 2210 { .type = PERF_TYPE_HW_CACHE, 2211 .config = 2212 PERF_COUNT_HW_CACHE_DTLB << 0 | 2213 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2214 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2215 2216 { .type = PERF_TYPE_HW_CACHE, 2217 .config = 2218 PERF_COUNT_HW_CACHE_DTLB << 0 | 2219 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2220 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2221 2222 { .type = PERF_TYPE_HW_CACHE, 2223 .config = 2224 PERF_COUNT_HW_CACHE_ITLB << 0 | 2225 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2226 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2227 2228 { .type = PERF_TYPE_HW_CACHE, 2229 .config = 2230 PERF_COUNT_HW_CACHE_ITLB << 0 | 2231 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2232 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2233 2234 }; 2235 2236 /* 2237 * Very, very detailed stats (-d -d -d), adding prefetch events: 2238 */ 2239 struct perf_event_attr very_very_detailed_attrs[] = { 2240 2241 { .type = PERF_TYPE_HW_CACHE, 2242 .config = 2243 PERF_COUNT_HW_CACHE_L1D << 0 | 2244 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 2245 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 2246 2247 { .type = PERF_TYPE_HW_CACHE, 2248 .config = 2249 PERF_COUNT_HW_CACHE_L1D << 0 | 2250 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 2251 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2252 }; 2253 2254 /* Set attrs if no event is selected and !null_run: */ 2255 if (null_run) 2256 return 0; 2257 2258 if (transaction_run) { 2259 if (pmu_have_event("cpu", "cycles-ct") && 2260 pmu_have_event("cpu", "el-start")) 2261 err = parse_events(evsel_list, transaction_attrs, NULL); 2262 else 2263 err = parse_events(evsel_list, transaction_limited_attrs, NULL); 2264 if (err) { 2265 fprintf(stderr, "Cannot set up transaction events\n"); 2266 return -1; 2267 } 2268 return 0; 2269 } 2270 2271 if (smi_cost) { 2272 int smi; 2273 2274 if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { 2275 fprintf(stderr, "freeze_on_smi is not supported.\n"); 2276 return -1; 2277 } 2278 2279 if (!smi) { 2280 if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { 2281 fprintf(stderr, "Failed to set freeze_on_smi.\n"); 2282 return -1; 2283 } 2284 smi_reset = true; 2285 } 2286 2287 if (pmu_have_event("msr", "aperf") && 2288 pmu_have_event("msr", "smi")) { 2289 if (!force_metric_only) 2290 metric_only = true; 2291 err = parse_events(evsel_list, smi_cost_attrs, NULL); 2292 } else { 2293 fprintf(stderr, "To measure SMI cost, it needs " 2294 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); 2295 return -1; 2296 } 2297 if (err) { 2298 fprintf(stderr, "Cannot set up SMI cost events\n"); 2299 return -1; 2300 } 2301 return 0; 2302 } 2303 2304 if (topdown_run) { 2305 char *str = NULL; 2306 bool warn = false; 2307 2308 if (stat_config.aggr_mode != AGGR_GLOBAL && 2309 stat_config.aggr_mode != AGGR_CORE) { 2310 pr_err("top down event configuration requires --per-core mode\n"); 2311 return -1; 2312 } 2313 stat_config.aggr_mode = AGGR_CORE; 2314 if (nr_cgroups || !target__has_cpu(&target)) { 2315 pr_err("top down event configuration requires system-wide mode (-a)\n"); 2316 return -1; 2317 } 2318 2319 if (!force_metric_only) 2320 metric_only = true; 2321 if (topdown_filter_events(topdown_attrs, &str, 2322 arch_topdown_check_group(&warn)) < 0) { 2323 pr_err("Out of memory\n"); 2324 return -1; 2325 } 2326 if (topdown_attrs[0] && str) { 2327 if (warn) 2328 arch_topdown_group_warn(); 2329 err = parse_events(evsel_list, str, NULL); 2330 if (err) { 2331 fprintf(stderr, 2332 "Cannot set up top down events %s: %d\n", 2333 str, err); 2334 free(str); 2335 return -1; 2336 } 2337 } else { 2338 fprintf(stderr, "System does not support topdown\n"); 2339 return -1; 2340 } 2341 free(str); 2342 } 2343 2344 if (!evsel_list->nr_entries) { 2345 if (target__has_cpu(&target)) 2346 default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK; 2347 2348 if (perf_evlist__add_default_attrs(evsel_list, default_attrs0) < 0) 2349 return -1; 2350 if (pmu_have_event("cpu", "stalled-cycles-frontend")) { 2351 if (perf_evlist__add_default_attrs(evsel_list, 2352 frontend_attrs) < 0) 2353 return -1; 2354 } 2355 if (pmu_have_event("cpu", "stalled-cycles-backend")) { 2356 if (perf_evlist__add_default_attrs(evsel_list, 2357 backend_attrs) < 0) 2358 return -1; 2359 } 2360 if (perf_evlist__add_default_attrs(evsel_list, default_attrs1) < 0) 2361 return -1; 2362 } 2363 2364 /* Detailed events get appended to the event list: */ 2365 2366 if (detailed_run < 1) 2367 return 0; 2368 2369 /* Append detailed run extra attributes: */ 2370 if (perf_evlist__add_default_attrs(evsel_list, detailed_attrs) < 0) 2371 return -1; 2372 2373 if (detailed_run < 2) 2374 return 0; 2375 2376 /* Append very detailed run extra attributes: */ 2377 if (perf_evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0) 2378 return -1; 2379 2380 if (detailed_run < 3) 2381 return 0; 2382 2383 /* Append very, very detailed run extra attributes: */ 2384 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); 2385 } 2386 2387 static const char * const stat_record_usage[] = { 2388 "perf stat record [<options>]", 2389 NULL, 2390 }; 2391 2392 static void init_features(struct perf_session *session) 2393 { 2394 int feat; 2395 2396 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 2397 perf_header__set_feat(&session->header, feat); 2398 2399 perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 2400 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 2401 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 2402 perf_header__clear_feat(&session->header, HEADER_AUXTRACE); 2403 } 2404 2405 static int __cmd_record(int argc, const char **argv) 2406 { 2407 struct perf_session *session; 2408 struct perf_data *data = &perf_stat.data; 2409 2410 argc = parse_options(argc, argv, stat_options, stat_record_usage, 2411 PARSE_OPT_STOP_AT_NON_OPTION); 2412 2413 if (output_name) 2414 data->file.path = output_name; 2415 2416 if (run_count != 1 || forever) { 2417 pr_err("Cannot use -r option with perf stat record.\n"); 2418 return -1; 2419 } 2420 2421 session = perf_session__new(data, false, NULL); 2422 if (session == NULL) { 2423 pr_err("Perf session creation failed.\n"); 2424 return -1; 2425 } 2426 2427 init_features(session); 2428 2429 session->evlist = evsel_list; 2430 perf_stat.session = session; 2431 perf_stat.record = true; 2432 return argc; 2433 } 2434 2435 static int process_stat_round_event(struct perf_tool *tool __maybe_unused, 2436 union perf_event *event, 2437 struct perf_session *session) 2438 { 2439 struct stat_round_event *stat_round = &event->stat_round; 2440 struct perf_evsel *counter; 2441 struct timespec tsh, *ts = NULL; 2442 const char **argv = session->header.env.cmdline_argv; 2443 int argc = session->header.env.nr_cmdline; 2444 2445 evlist__for_each_entry(evsel_list, counter) 2446 perf_stat_process_counter(&stat_config, counter); 2447 2448 if (stat_round->type == PERF_STAT_ROUND_TYPE__FINAL) 2449 update_stats(&walltime_nsecs_stats, stat_round->time); 2450 2451 if (stat_config.interval && stat_round->time) { 2452 tsh.tv_sec = stat_round->time / NSEC_PER_SEC; 2453 tsh.tv_nsec = stat_round->time % NSEC_PER_SEC; 2454 ts = &tsh; 2455 } 2456 2457 print_counters(ts, argc, argv); 2458 return 0; 2459 } 2460 2461 static 2462 int process_stat_config_event(struct perf_tool *tool, 2463 union perf_event *event, 2464 struct perf_session *session __maybe_unused) 2465 { 2466 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 2467 2468 perf_event__read_stat_config(&stat_config, &event->stat_config); 2469 2470 if (cpu_map__empty(st->cpus)) { 2471 if (st->aggr_mode != AGGR_UNSET) 2472 pr_warning("warning: processing task data, aggregation mode not set\n"); 2473 return 0; 2474 } 2475 2476 if (st->aggr_mode != AGGR_UNSET) 2477 stat_config.aggr_mode = st->aggr_mode; 2478 2479 if (perf_stat.data.is_pipe) 2480 perf_stat_init_aggr_mode(); 2481 else 2482 perf_stat_init_aggr_mode_file(st); 2483 2484 return 0; 2485 } 2486 2487 static int set_maps(struct perf_stat *st) 2488 { 2489 if (!st->cpus || !st->threads) 2490 return 0; 2491 2492 if (WARN_ONCE(st->maps_allocated, "stats double allocation\n")) 2493 return -EINVAL; 2494 2495 perf_evlist__set_maps(evsel_list, st->cpus, st->threads); 2496 2497 if (perf_evlist__alloc_stats(evsel_list, true)) 2498 return -ENOMEM; 2499 2500 st->maps_allocated = true; 2501 return 0; 2502 } 2503 2504 static 2505 int process_thread_map_event(struct perf_tool *tool, 2506 union perf_event *event, 2507 struct perf_session *session __maybe_unused) 2508 { 2509 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 2510 2511 if (st->threads) { 2512 pr_warning("Extra thread map event, ignoring.\n"); 2513 return 0; 2514 } 2515 2516 st->threads = thread_map__new_event(&event->thread_map); 2517 if (!st->threads) 2518 return -ENOMEM; 2519 2520 return set_maps(st); 2521 } 2522 2523 static 2524 int process_cpu_map_event(struct perf_tool *tool, 2525 union perf_event *event, 2526 struct perf_session *session __maybe_unused) 2527 { 2528 struct perf_stat *st = container_of(tool, struct perf_stat, tool); 2529 struct cpu_map *cpus; 2530 2531 if (st->cpus) { 2532 pr_warning("Extra cpu map event, ignoring.\n"); 2533 return 0; 2534 } 2535 2536 cpus = cpu_map__new_data(&event->cpu_map.data); 2537 if (!cpus) 2538 return -ENOMEM; 2539 2540 st->cpus = cpus; 2541 return set_maps(st); 2542 } 2543 2544 static const char * const stat_report_usage[] = { 2545 "perf stat report [<options>]", 2546 NULL, 2547 }; 2548 2549 static struct perf_stat perf_stat = { 2550 .tool = { 2551 .attr = perf_event__process_attr, 2552 .event_update = perf_event__process_event_update, 2553 .thread_map = process_thread_map_event, 2554 .cpu_map = process_cpu_map_event, 2555 .stat_config = process_stat_config_event, 2556 .stat = perf_event__process_stat_event, 2557 .stat_round = process_stat_round_event, 2558 }, 2559 .aggr_mode = AGGR_UNSET, 2560 }; 2561 2562 static int __cmd_report(int argc, const char **argv) 2563 { 2564 struct perf_session *session; 2565 const struct option options[] = { 2566 OPT_STRING('i', "input", &input_name, "file", "input file name"), 2567 OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode, 2568 "aggregate counts per processor socket", AGGR_SOCKET), 2569 OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode, 2570 "aggregate counts per physical processor core", AGGR_CORE), 2571 OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode, 2572 "disable CPU count aggregation", AGGR_NONE), 2573 OPT_END() 2574 }; 2575 struct stat st; 2576 int ret; 2577 2578 argc = parse_options(argc, argv, options, stat_report_usage, 0); 2579 2580 if (!input_name || !strlen(input_name)) { 2581 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) 2582 input_name = "-"; 2583 else 2584 input_name = "perf.data"; 2585 } 2586 2587 perf_stat.data.file.path = input_name; 2588 perf_stat.data.mode = PERF_DATA_MODE_READ; 2589 2590 session = perf_session__new(&perf_stat.data, false, &perf_stat.tool); 2591 if (session == NULL) 2592 return -1; 2593 2594 perf_stat.session = session; 2595 stat_config.output = stderr; 2596 evsel_list = session->evlist; 2597 2598 ret = perf_session__process_events(session); 2599 if (ret) 2600 return ret; 2601 2602 perf_session__delete(session); 2603 return 0; 2604 } 2605 2606 static void setup_system_wide(int forks) 2607 { 2608 /* 2609 * Make system wide (-a) the default target if 2610 * no target was specified and one of following 2611 * conditions is met: 2612 * 2613 * - there's no workload specified 2614 * - there is workload specified but all requested 2615 * events are system wide events 2616 */ 2617 if (!target__none(&target)) 2618 return; 2619 2620 if (!forks) 2621 target.system_wide = true; 2622 else { 2623 struct perf_evsel *counter; 2624 2625 evlist__for_each_entry(evsel_list, counter) { 2626 if (!counter->system_wide) 2627 return; 2628 } 2629 2630 if (evsel_list->nr_entries) 2631 target.system_wide = true; 2632 } 2633 } 2634 2635 int cmd_stat(int argc, const char **argv) 2636 { 2637 const char * const stat_usage[] = { 2638 "perf stat [<options>] [<command>]", 2639 NULL 2640 }; 2641 int status = -EINVAL, run_idx; 2642 const char *mode; 2643 FILE *output = stderr; 2644 unsigned int interval; 2645 const char * const stat_subcommands[] = { "record", "report" }; 2646 2647 setlocale(LC_ALL, ""); 2648 2649 evsel_list = perf_evlist__new(); 2650 if (evsel_list == NULL) 2651 return -ENOMEM; 2652 2653 parse_events__shrink_config_terms(); 2654 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2655 (const char **) stat_usage, 2656 PARSE_OPT_STOP_AT_NON_OPTION); 2657 perf_stat__collect_metric_expr(evsel_list); 2658 perf_stat__init_shadow_stats(); 2659 2660 if (csv_sep) { 2661 csv_output = true; 2662 if (!strcmp(csv_sep, "\\t")) 2663 csv_sep = "\t"; 2664 } else 2665 csv_sep = DEFAULT_SEPARATOR; 2666 2667 if (argc && !strncmp(argv[0], "rec", 3)) { 2668 argc = __cmd_record(argc, argv); 2669 if (argc < 0) 2670 return -1; 2671 } else if (argc && !strncmp(argv[0], "rep", 3)) 2672 return __cmd_report(argc, argv); 2673 2674 interval = stat_config.interval; 2675 2676 /* 2677 * For record command the -o is already taken care of. 2678 */ 2679 if (!STAT_RECORD && output_name && strcmp(output_name, "-")) 2680 output = NULL; 2681 2682 if (output_name && output_fd) { 2683 fprintf(stderr, "cannot use both --output and --log-fd\n"); 2684 parse_options_usage(stat_usage, stat_options, "o", 1); 2685 parse_options_usage(NULL, stat_options, "log-fd", 0); 2686 goto out; 2687 } 2688 2689 if (metric_only && stat_config.aggr_mode == AGGR_THREAD) { 2690 fprintf(stderr, "--metric-only is not supported with --per-thread\n"); 2691 goto out; 2692 } 2693 2694 if (metric_only && run_count > 1) { 2695 fprintf(stderr, "--metric-only is not supported with -r\n"); 2696 goto out; 2697 } 2698 2699 if (output_fd < 0) { 2700 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 2701 parse_options_usage(stat_usage, stat_options, "log-fd", 0); 2702 goto out; 2703 } 2704 2705 if (!output) { 2706 struct timespec tm; 2707 mode = append_file ? "a" : "w"; 2708 2709 output = fopen(output_name, mode); 2710 if (!output) { 2711 perror("failed to create output file"); 2712 return -1; 2713 } 2714 clock_gettime(CLOCK_REALTIME, &tm); 2715 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); 2716 } else if (output_fd > 0) { 2717 mode = append_file ? "a" : "w"; 2718 output = fdopen(output_fd, mode); 2719 if (!output) { 2720 perror("Failed opening logfd"); 2721 return -errno; 2722 } 2723 } 2724 2725 stat_config.output = output; 2726 2727 /* 2728 * let the spreadsheet do the pretty-printing 2729 */ 2730 if (csv_output) { 2731 /* User explicitly passed -B? */ 2732 if (big_num_opt == 1) { 2733 fprintf(stderr, "-B option not supported with -x\n"); 2734 parse_options_usage(stat_usage, stat_options, "B", 1); 2735 parse_options_usage(NULL, stat_options, "x", 1); 2736 goto out; 2737 } else /* Nope, so disable big number formatting */ 2738 big_num = false; 2739 } else if (big_num_opt == 0) /* User passed --no-big-num */ 2740 big_num = false; 2741 2742 setup_system_wide(argc); 2743 2744 if (run_count < 0) { 2745 pr_err("Run count must be a positive number\n"); 2746 parse_options_usage(stat_usage, stat_options, "r", 1); 2747 goto out; 2748 } else if (run_count == 0) { 2749 forever = true; 2750 run_count = 1; 2751 } 2752 2753 if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { 2754 fprintf(stderr, "The --per-thread option is only available " 2755 "when monitoring via -p -t options.\n"); 2756 parse_options_usage(NULL, stat_options, "p", 1); 2757 parse_options_usage(NULL, stat_options, "t", 1); 2758 goto out; 2759 } 2760 2761 /* 2762 * no_aggr, cgroup are for system-wide only 2763 * --per-thread is aggregated per thread, we dont mix it with cpu mode 2764 */ 2765 if (((stat_config.aggr_mode != AGGR_GLOBAL && 2766 stat_config.aggr_mode != AGGR_THREAD) || nr_cgroups) && 2767 !target__has_cpu(&target)) { 2768 fprintf(stderr, "both cgroup and no-aggregation " 2769 "modes only available in system-wide mode\n"); 2770 2771 parse_options_usage(stat_usage, stat_options, "G", 1); 2772 parse_options_usage(NULL, stat_options, "A", 1); 2773 parse_options_usage(NULL, stat_options, "a", 1); 2774 goto out; 2775 } 2776 2777 if (add_default_attributes()) 2778 goto out; 2779 2780 target__validate(&target); 2781 2782 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 2783 if (target__has_task(&target)) { 2784 pr_err("Problems finding threads of monitor\n"); 2785 parse_options_usage(stat_usage, stat_options, "p", 1); 2786 parse_options_usage(NULL, stat_options, "t", 1); 2787 } else if (target__has_cpu(&target)) { 2788 perror("failed to parse CPUs map"); 2789 parse_options_usage(stat_usage, stat_options, "C", 1); 2790 parse_options_usage(NULL, stat_options, "a", 1); 2791 } 2792 goto out; 2793 } 2794 2795 /* 2796 * Initialize thread_map with comm names, 2797 * so we could print it out on output. 2798 */ 2799 if (stat_config.aggr_mode == AGGR_THREAD) 2800 thread_map__read_comms(evsel_list->threads); 2801 2802 if (interval && interval < 100) { 2803 if (interval < 10) { 2804 pr_err("print interval must be >= 10ms\n"); 2805 parse_options_usage(stat_usage, stat_options, "I", 1); 2806 goto out; 2807 } else 2808 pr_warning("print interval < 100ms. " 2809 "The overhead percentage could be high in some cases. " 2810 "Please proceed with caution.\n"); 2811 } 2812 2813 if (perf_evlist__alloc_stats(evsel_list, interval)) 2814 goto out; 2815 2816 if (perf_stat_init_aggr_mode()) 2817 goto out; 2818 2819 /* 2820 * We dont want to block the signals - that would cause 2821 * child tasks to inherit that and Ctrl-C would not work. 2822 * What we want is for Ctrl-C to work in the exec()-ed 2823 * task, but being ignored by perf stat itself: 2824 */ 2825 atexit(sig_atexit); 2826 if (!forever) 2827 signal(SIGINT, skip_signal); 2828 signal(SIGCHLD, skip_signal); 2829 signal(SIGALRM, skip_signal); 2830 signal(SIGABRT, skip_signal); 2831 2832 status = 0; 2833 for (run_idx = 0; forever || run_idx < run_count; run_idx++) { 2834 if (run_count != 1 && verbose > 0) 2835 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 2836 run_idx + 1); 2837 2838 status = run_perf_stat(argc, argv); 2839 if (forever && status != -1) { 2840 print_counters(NULL, argc, argv); 2841 perf_stat__reset_stats(); 2842 } 2843 } 2844 2845 if (!forever && status != -1 && !interval) 2846 print_counters(NULL, argc, argv); 2847 2848 if (STAT_RECORD) { 2849 /* 2850 * We synthesize the kernel mmap record just so that older tools 2851 * don't emit warnings about not being able to resolve symbols 2852 * due to /proc/sys/kernel/kptr_restrict settings and instear provide 2853 * a saner message about no samples being in the perf.data file. 2854 * 2855 * This also serves to suppress a warning about f_header.data.size == 0 2856 * in header.c at the moment 'perf stat record' gets introduced, which 2857 * is not really needed once we start adding the stat specific PERF_RECORD_ 2858 * records, but the need to suppress the kptr_restrict messages in older 2859 * tools remain -acme 2860 */ 2861 int fd = perf_data__fd(&perf_stat.data); 2862 int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat, 2863 process_synthesized_event, 2864 &perf_stat.session->machines.host); 2865 if (err) { 2866 pr_warning("Couldn't synthesize the kernel mmap record, harmless, " 2867 "older tools may produce warnings about this file\n."); 2868 } 2869 2870 if (!interval) { 2871 if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL)) 2872 pr_err("failed to write stat round event\n"); 2873 } 2874 2875 if (!perf_stat.data.is_pipe) { 2876 perf_stat.session->header.data_size += perf_stat.bytes_written; 2877 perf_session__write_header(perf_stat.session, evsel_list, fd, true); 2878 } 2879 2880 perf_session__delete(perf_stat.session); 2881 } 2882 2883 perf_stat__exit_aggr_mode(); 2884 perf_evlist__free_stats(evsel_list); 2885 out: 2886 if (smi_cost && smi_reset) 2887 sysfs__write_int(FREEZE_ON_SMI_PATH, 0); 2888 2889 perf_evlist__delete(evsel_list); 2890 return status; 2891 } 2892