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 "util/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/color.h" 56 #include "util/stat.h" 57 #include "util/header.h" 58 #include "util/cpumap.h" 59 #include "util/thread.h" 60 #include "util/thread_map.h" 61 #include "util/counts.h" 62 63 #include <stdlib.h> 64 #include <sys/prctl.h> 65 #include <locale.h> 66 67 #define DEFAULT_SEPARATOR " " 68 #define CNTR_NOT_SUPPORTED "<not supported>" 69 #define CNTR_NOT_COUNTED "<not counted>" 70 71 static void print_counters(struct timespec *ts, int argc, const char **argv); 72 73 /* Default events used for perf stat -T */ 74 static const char *transaction_attrs = { 75 "task-clock," 76 "{" 77 "instructions," 78 "cycles," 79 "cpu/cycles-t/," 80 "cpu/tx-start/," 81 "cpu/el-start/," 82 "cpu/cycles-ct/" 83 "}" 84 }; 85 86 /* More limited version when the CPU does not have all events. */ 87 static const char * transaction_limited_attrs = { 88 "task-clock," 89 "{" 90 "instructions," 91 "cycles," 92 "cpu/cycles-t/," 93 "cpu/tx-start/" 94 "}" 95 }; 96 97 static struct perf_evlist *evsel_list; 98 99 static struct target target = { 100 .uid = UINT_MAX, 101 }; 102 103 typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); 104 105 static int run_count = 1; 106 static bool no_inherit = false; 107 static volatile pid_t child_pid = -1; 108 static bool null_run = false; 109 static int detailed_run = 0; 110 static bool transaction_run; 111 static bool big_num = true; 112 static int big_num_opt = -1; 113 static const char *csv_sep = NULL; 114 static bool csv_output = false; 115 static bool group = false; 116 static const char *pre_cmd = NULL; 117 static const char *post_cmd = NULL; 118 static bool sync_run = false; 119 static unsigned int initial_delay = 0; 120 static unsigned int unit_width = 4; /* strlen("unit") */ 121 static bool forever = false; 122 static struct timespec ref_time; 123 static struct cpu_map *aggr_map; 124 static aggr_get_id_t aggr_get_id; 125 static bool append_file; 126 static const char *output_name; 127 static int output_fd; 128 129 static volatile int done = 0; 130 131 static struct perf_stat_config stat_config = { 132 .aggr_mode = AGGR_GLOBAL, 133 .scale = true, 134 }; 135 136 static inline void diff_timespec(struct timespec *r, struct timespec *a, 137 struct timespec *b) 138 { 139 r->tv_sec = a->tv_sec - b->tv_sec; 140 if (a->tv_nsec < b->tv_nsec) { 141 r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec; 142 r->tv_sec--; 143 } else { 144 r->tv_nsec = a->tv_nsec - b->tv_nsec ; 145 } 146 } 147 148 static void perf_stat__reset_stats(void) 149 { 150 perf_evlist__reset_stats(evsel_list); 151 perf_stat__reset_shadow_stats(); 152 } 153 154 static int create_perf_stat_counter(struct perf_evsel *evsel) 155 { 156 struct perf_event_attr *attr = &evsel->attr; 157 158 if (stat_config.scale) 159 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 160 PERF_FORMAT_TOTAL_TIME_RUNNING; 161 162 attr->inherit = !no_inherit; 163 164 if (target__has_cpu(&target)) 165 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 166 167 if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) { 168 attr->disabled = 1; 169 if (!initial_delay) 170 attr->enable_on_exec = 1; 171 } 172 173 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 174 } 175 176 /* 177 * Does the counter have nsecs as a unit? 178 */ 179 static inline int nsec_counter(struct perf_evsel *evsel) 180 { 181 if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || 182 perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 183 return 1; 184 185 return 0; 186 } 187 188 /* 189 * Read out the results of a single counter: 190 * do not aggregate counts across CPUs in system-wide mode 191 */ 192 static int read_counter(struct perf_evsel *counter) 193 { 194 int nthreads = thread_map__nr(evsel_list->threads); 195 int ncpus = perf_evsel__nr_cpus(counter); 196 int cpu, thread; 197 198 if (!counter->supported) 199 return -ENOENT; 200 201 if (counter->system_wide) 202 nthreads = 1; 203 204 for (thread = 0; thread < nthreads; thread++) { 205 for (cpu = 0; cpu < ncpus; cpu++) { 206 struct perf_counts_values *count; 207 208 count = perf_counts(counter->counts, cpu, thread); 209 if (perf_evsel__read(counter, cpu, thread, count)) 210 return -1; 211 } 212 } 213 214 return 0; 215 } 216 217 static void read_counters(bool close_counters) 218 { 219 struct perf_evsel *counter; 220 221 evlist__for_each(evsel_list, counter) { 222 if (read_counter(counter)) 223 pr_debug("failed to read counter %s\n", counter->name); 224 225 if (perf_stat_process_counter(&stat_config, counter)) 226 pr_warning("failed to process counter %s\n", counter->name); 227 228 if (close_counters) { 229 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 230 thread_map__nr(evsel_list->threads)); 231 } 232 } 233 } 234 235 static void process_interval(void) 236 { 237 struct timespec ts, rs; 238 239 read_counters(false); 240 241 clock_gettime(CLOCK_MONOTONIC, &ts); 242 diff_timespec(&rs, &ts, &ref_time); 243 244 print_counters(&rs, 0, NULL); 245 } 246 247 static void handle_initial_delay(void) 248 { 249 struct perf_evsel *counter; 250 251 if (initial_delay) { 252 const int ncpus = cpu_map__nr(evsel_list->cpus), 253 nthreads = thread_map__nr(evsel_list->threads); 254 255 usleep(initial_delay * 1000); 256 evlist__for_each(evsel_list, counter) 257 perf_evsel__enable(counter, ncpus, nthreads); 258 } 259 } 260 261 static volatile int workload_exec_errno; 262 263 /* 264 * perf_evlist__prepare_workload will send a SIGUSR1 265 * if the fork fails, since we asked by setting its 266 * want_signal to true. 267 */ 268 static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info, 269 void *ucontext __maybe_unused) 270 { 271 workload_exec_errno = info->si_value.sival_int; 272 } 273 274 static int __run_perf_stat(int argc, const char **argv) 275 { 276 int interval = stat_config.interval; 277 char msg[512]; 278 unsigned long long t0, t1; 279 struct perf_evsel *counter; 280 struct timespec ts; 281 size_t l; 282 int status = 0; 283 const bool forks = (argc > 0); 284 285 if (interval) { 286 ts.tv_sec = interval / 1000; 287 ts.tv_nsec = (interval % 1000) * 1000000; 288 } else { 289 ts.tv_sec = 1; 290 ts.tv_nsec = 0; 291 } 292 293 if (forks) { 294 if (perf_evlist__prepare_workload(evsel_list, &target, argv, false, 295 workload_exec_failed_signal) < 0) { 296 perror("failed to prepare workload"); 297 return -1; 298 } 299 child_pid = evsel_list->workload.pid; 300 } 301 302 if (group) 303 perf_evlist__set_leader(evsel_list); 304 305 evlist__for_each(evsel_list, counter) { 306 if (create_perf_stat_counter(counter) < 0) { 307 /* 308 * PPC returns ENXIO for HW counters until 2.6.37 309 * (behavior changed with commit b0a873e). 310 */ 311 if (errno == EINVAL || errno == ENOSYS || 312 errno == ENOENT || errno == EOPNOTSUPP || 313 errno == ENXIO) { 314 if (verbose) 315 ui__warning("%s event is not supported by the kernel.\n", 316 perf_evsel__name(counter)); 317 counter->supported = false; 318 319 if ((counter->leader != counter) || 320 !(counter->leader->nr_members > 1)) 321 continue; 322 } 323 324 perf_evsel__open_strerror(counter, &target, 325 errno, msg, sizeof(msg)); 326 ui__error("%s\n", msg); 327 328 if (child_pid != -1) 329 kill(child_pid, SIGTERM); 330 331 return -1; 332 } 333 counter->supported = true; 334 335 l = strlen(counter->unit); 336 if (l > unit_width) 337 unit_width = l; 338 } 339 340 if (perf_evlist__apply_filters(evsel_list, &counter)) { 341 error("failed to set filter \"%s\" on event %s with %d (%s)\n", 342 counter->filter, perf_evsel__name(counter), errno, 343 strerror_r(errno, msg, sizeof(msg))); 344 return -1; 345 } 346 347 /* 348 * Enable counters and exec the command: 349 */ 350 t0 = rdclock(); 351 clock_gettime(CLOCK_MONOTONIC, &ref_time); 352 353 if (forks) { 354 perf_evlist__start_workload(evsel_list); 355 handle_initial_delay(); 356 357 if (interval) { 358 while (!waitpid(child_pid, &status, WNOHANG)) { 359 nanosleep(&ts, NULL); 360 process_interval(); 361 } 362 } 363 wait(&status); 364 365 if (workload_exec_errno) { 366 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 367 pr_err("Workload failed: %s\n", emsg); 368 return -1; 369 } 370 371 if (WIFSIGNALED(status)) 372 psignal(WTERMSIG(status), argv[0]); 373 } else { 374 handle_initial_delay(); 375 while (!done) { 376 nanosleep(&ts, NULL); 377 if (interval) 378 process_interval(); 379 } 380 } 381 382 t1 = rdclock(); 383 384 update_stats(&walltime_nsecs_stats, t1 - t0); 385 386 read_counters(true); 387 388 return WEXITSTATUS(status); 389 } 390 391 static int run_perf_stat(int argc, const char **argv) 392 { 393 int ret; 394 395 if (pre_cmd) { 396 ret = system(pre_cmd); 397 if (ret) 398 return ret; 399 } 400 401 if (sync_run) 402 sync(); 403 404 ret = __run_perf_stat(argc, argv); 405 if (ret) 406 return ret; 407 408 if (post_cmd) { 409 ret = system(post_cmd); 410 if (ret) 411 return ret; 412 } 413 414 return ret; 415 } 416 417 static void print_running(u64 run, u64 ena) 418 { 419 if (csv_output) { 420 fprintf(stat_config.output, "%s%" PRIu64 "%s%.2f", 421 csv_sep, 422 run, 423 csv_sep, 424 ena ? 100.0 * run / ena : 100.0); 425 } else if (run != ena) { 426 fprintf(stat_config.output, " (%.2f%%)", 100.0 * run / ena); 427 } 428 } 429 430 static void print_noise_pct(double total, double avg) 431 { 432 double pct = rel_stddev_stats(total, avg); 433 434 if (csv_output) 435 fprintf(stat_config.output, "%s%.2f%%", csv_sep, pct); 436 else if (pct) 437 fprintf(stat_config.output, " ( +-%6.2f%% )", pct); 438 } 439 440 static void print_noise(struct perf_evsel *evsel, double avg) 441 { 442 struct perf_stat_evsel *ps; 443 444 if (run_count == 1) 445 return; 446 447 ps = evsel->priv; 448 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 449 } 450 451 static void aggr_printout(struct perf_evsel *evsel, int id, int nr) 452 { 453 switch (stat_config.aggr_mode) { 454 case AGGR_CORE: 455 fprintf(stat_config.output, "S%d-C%*d%s%*d%s", 456 cpu_map__id_to_socket(id), 457 csv_output ? 0 : -8, 458 cpu_map__id_to_cpu(id), 459 csv_sep, 460 csv_output ? 0 : 4, 461 nr, 462 csv_sep); 463 break; 464 case AGGR_SOCKET: 465 fprintf(stat_config.output, "S%*d%s%*d%s", 466 csv_output ? 0 : -5, 467 id, 468 csv_sep, 469 csv_output ? 0 : 4, 470 nr, 471 csv_sep); 472 break; 473 case AGGR_NONE: 474 fprintf(stat_config.output, "CPU%*d%s", 475 csv_output ? 0 : -4, 476 perf_evsel__cpus(evsel)->map[id], csv_sep); 477 break; 478 case AGGR_THREAD: 479 fprintf(stat_config.output, "%*s-%*d%s", 480 csv_output ? 0 : 16, 481 thread_map__comm(evsel->threads, id), 482 csv_output ? 0 : -8, 483 thread_map__pid(evsel->threads, id), 484 csv_sep); 485 break; 486 case AGGR_GLOBAL: 487 case AGGR_UNSET: 488 default: 489 break; 490 } 491 } 492 493 static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 494 { 495 FILE *output = stat_config.output; 496 double msecs = avg / 1e6; 497 const char *fmt_v, *fmt_n; 498 char name[25]; 499 500 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; 501 fmt_n = csv_output ? "%s" : "%-25s"; 502 503 aggr_printout(evsel, id, nr); 504 505 scnprintf(name, sizeof(name), "%s%s", 506 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 507 508 fprintf(output, fmt_v, msecs, csv_sep); 509 510 if (csv_output) 511 fprintf(output, "%s%s", evsel->unit, csv_sep); 512 else 513 fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep); 514 515 fprintf(output, fmt_n, name); 516 517 if (evsel->cgrp) 518 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 519 } 520 521 static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) 522 { 523 FILE *output = stat_config.output; 524 double sc = evsel->scale; 525 const char *fmt; 526 527 if (csv_output) { 528 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; 529 } else { 530 if (big_num) 531 fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s"; 532 else 533 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; 534 } 535 536 aggr_printout(evsel, id, nr); 537 538 fprintf(output, fmt, avg, csv_sep); 539 540 if (evsel->unit) 541 fprintf(output, "%-*s%s", 542 csv_output ? 0 : unit_width, 543 evsel->unit, csv_sep); 544 545 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel)); 546 547 if (evsel->cgrp) 548 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 549 } 550 551 static void printout(int id, int nr, struct perf_evsel *counter, double uval) 552 { 553 int cpu = cpu_map__id_to_cpu(id); 554 555 if (stat_config.aggr_mode == AGGR_GLOBAL) 556 cpu = 0; 557 558 if (nsec_counter(counter)) 559 nsec_printout(id, nr, counter, uval); 560 else 561 abs_printout(id, nr, counter, uval); 562 563 if (!csv_output && !stat_config.interval) 564 perf_stat__print_shadow_stats(stat_config.output, counter, 565 uval, cpu, 566 stat_config.aggr_mode); 567 } 568 569 static void print_aggr(char *prefix) 570 { 571 FILE *output = stat_config.output; 572 struct perf_evsel *counter; 573 int cpu, s, s2, id, nr; 574 double uval; 575 u64 ena, run, val; 576 577 if (!(aggr_map || aggr_get_id)) 578 return; 579 580 for (s = 0; s < aggr_map->nr; s++) { 581 id = aggr_map->map[s]; 582 evlist__for_each(evsel_list, counter) { 583 val = ena = run = 0; 584 nr = 0; 585 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 586 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu); 587 if (s2 != id) 588 continue; 589 val += perf_counts(counter->counts, cpu, 0)->val; 590 ena += perf_counts(counter->counts, cpu, 0)->ena; 591 run += perf_counts(counter->counts, cpu, 0)->run; 592 nr++; 593 } 594 if (prefix) 595 fprintf(output, "%s", prefix); 596 597 if (run == 0 || ena == 0) { 598 aggr_printout(counter, id, nr); 599 600 fprintf(output, "%*s%s", 601 csv_output ? 0 : 18, 602 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 603 csv_sep); 604 605 fprintf(output, "%-*s%s", 606 csv_output ? 0 : unit_width, 607 counter->unit, csv_sep); 608 609 fprintf(output, "%*s", 610 csv_output ? 0 : -25, 611 perf_evsel__name(counter)); 612 613 if (counter->cgrp) 614 fprintf(output, "%s%s", 615 csv_sep, counter->cgrp->name); 616 617 print_running(run, ena); 618 fputc('\n', output); 619 continue; 620 } 621 uval = val * counter->scale; 622 printout(id, nr, counter, uval); 623 if (!csv_output) 624 print_noise(counter, 1.0); 625 626 print_running(run, ena); 627 fputc('\n', output); 628 } 629 } 630 } 631 632 static void print_aggr_thread(struct perf_evsel *counter, char *prefix) 633 { 634 FILE *output = stat_config.output; 635 int nthreads = thread_map__nr(counter->threads); 636 int ncpus = cpu_map__nr(counter->cpus); 637 int cpu, thread; 638 double uval; 639 640 for (thread = 0; thread < nthreads; thread++) { 641 u64 ena = 0, run = 0, val = 0; 642 643 for (cpu = 0; cpu < ncpus; cpu++) { 644 val += perf_counts(counter->counts, cpu, thread)->val; 645 ena += perf_counts(counter->counts, cpu, thread)->ena; 646 run += perf_counts(counter->counts, cpu, thread)->run; 647 } 648 649 if (prefix) 650 fprintf(output, "%s", prefix); 651 652 uval = val * counter->scale; 653 printout(thread, 0, counter, uval); 654 655 if (!csv_output) 656 print_noise(counter, 1.0); 657 658 print_running(run, ena); 659 fputc('\n', output); 660 } 661 } 662 663 /* 664 * Print out the results of a single counter: 665 * aggregated counts in system-wide mode 666 */ 667 static void print_counter_aggr(struct perf_evsel *counter, char *prefix) 668 { 669 FILE *output = stat_config.output; 670 struct perf_stat_evsel *ps = counter->priv; 671 double avg = avg_stats(&ps->res_stats[0]); 672 int scaled = counter->counts->scaled; 673 double uval; 674 double avg_enabled, avg_running; 675 676 avg_enabled = avg_stats(&ps->res_stats[1]); 677 avg_running = avg_stats(&ps->res_stats[2]); 678 679 if (prefix) 680 fprintf(output, "%s", prefix); 681 682 if (scaled == -1 || !counter->supported) { 683 fprintf(output, "%*s%s", 684 csv_output ? 0 : 18, 685 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 686 csv_sep); 687 fprintf(output, "%-*s%s", 688 csv_output ? 0 : unit_width, 689 counter->unit, csv_sep); 690 fprintf(output, "%*s", 691 csv_output ? 0 : -25, 692 perf_evsel__name(counter)); 693 694 if (counter->cgrp) 695 fprintf(output, "%s%s", csv_sep, counter->cgrp->name); 696 697 print_running(avg_running, avg_enabled); 698 fputc('\n', output); 699 return; 700 } 701 702 uval = avg * counter->scale; 703 printout(-1, 0, counter, uval); 704 705 print_noise(counter, avg); 706 707 print_running(avg_running, avg_enabled); 708 fprintf(output, "\n"); 709 } 710 711 /* 712 * Print out the results of a single counter: 713 * does not use aggregated count in system-wide 714 */ 715 static void print_counter(struct perf_evsel *counter, char *prefix) 716 { 717 FILE *output = stat_config.output; 718 u64 ena, run, val; 719 double uval; 720 int cpu; 721 722 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 723 val = perf_counts(counter->counts, cpu, 0)->val; 724 ena = perf_counts(counter->counts, cpu, 0)->ena; 725 run = perf_counts(counter->counts, cpu, 0)->run; 726 727 if (prefix) 728 fprintf(output, "%s", prefix); 729 730 if (run == 0 || ena == 0) { 731 fprintf(output, "CPU%*d%s%*s%s", 732 csv_output ? 0 : -4, 733 perf_evsel__cpus(counter)->map[cpu], csv_sep, 734 csv_output ? 0 : 18, 735 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 736 csv_sep); 737 738 fprintf(output, "%-*s%s", 739 csv_output ? 0 : unit_width, 740 counter->unit, csv_sep); 741 742 fprintf(output, "%*s", 743 csv_output ? 0 : -25, 744 perf_evsel__name(counter)); 745 746 if (counter->cgrp) 747 fprintf(output, "%s%s", 748 csv_sep, counter->cgrp->name); 749 750 print_running(run, ena); 751 fputc('\n', output); 752 continue; 753 } 754 755 uval = val * counter->scale; 756 printout(cpu, 0, counter, uval); 757 if (!csv_output) 758 print_noise(counter, 1.0); 759 print_running(run, ena); 760 761 fputc('\n', output); 762 } 763 } 764 765 static void print_interval(char *prefix, struct timespec *ts) 766 { 767 FILE *output = stat_config.output; 768 static int num_print_interval; 769 770 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 771 772 if (num_print_interval == 0 && !csv_output) { 773 switch (stat_config.aggr_mode) { 774 case AGGR_SOCKET: 775 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); 776 break; 777 case AGGR_CORE: 778 fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit"); 779 break; 780 case AGGR_NONE: 781 fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit"); 782 break; 783 case AGGR_THREAD: 784 fprintf(output, "# time comm-pid counts %*s events\n", unit_width, "unit"); 785 break; 786 case AGGR_GLOBAL: 787 default: 788 fprintf(output, "# time counts %*s events\n", unit_width, "unit"); 789 case AGGR_UNSET: 790 break; 791 } 792 } 793 794 if (++num_print_interval == 25) 795 num_print_interval = 0; 796 } 797 798 static void print_header(int argc, const char **argv) 799 { 800 FILE *output = stat_config.output; 801 int i; 802 803 fflush(stdout); 804 805 if (!csv_output) { 806 fprintf(output, "\n"); 807 fprintf(output, " Performance counter stats for "); 808 if (target.system_wide) 809 fprintf(output, "\'system wide"); 810 else if (target.cpu_list) 811 fprintf(output, "\'CPU(s) %s", target.cpu_list); 812 else if (!target__has_task(&target)) { 813 fprintf(output, "\'%s", argv[0]); 814 for (i = 1; i < argc; i++) 815 fprintf(output, " %s", argv[i]); 816 } else if (target.pid) 817 fprintf(output, "process id \'%s", target.pid); 818 else 819 fprintf(output, "thread id \'%s", target.tid); 820 821 fprintf(output, "\'"); 822 if (run_count > 1) 823 fprintf(output, " (%d runs)", run_count); 824 fprintf(output, ":\n\n"); 825 } 826 } 827 828 static void print_footer(void) 829 { 830 FILE *output = stat_config.output; 831 832 if (!null_run) 833 fprintf(output, "\n"); 834 fprintf(output, " %17.9f seconds time elapsed", 835 avg_stats(&walltime_nsecs_stats)/1e9); 836 if (run_count > 1) { 837 fprintf(output, " "); 838 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 839 avg_stats(&walltime_nsecs_stats)); 840 } 841 fprintf(output, "\n\n"); 842 } 843 844 static void print_counters(struct timespec *ts, int argc, const char **argv) 845 { 846 int interval = stat_config.interval; 847 struct perf_evsel *counter; 848 char buf[64], *prefix = NULL; 849 850 if (interval) 851 print_interval(prefix = buf, ts); 852 else 853 print_header(argc, argv); 854 855 switch (stat_config.aggr_mode) { 856 case AGGR_CORE: 857 case AGGR_SOCKET: 858 print_aggr(prefix); 859 break; 860 case AGGR_THREAD: 861 evlist__for_each(evsel_list, counter) 862 print_aggr_thread(counter, prefix); 863 break; 864 case AGGR_GLOBAL: 865 evlist__for_each(evsel_list, counter) 866 print_counter_aggr(counter, prefix); 867 break; 868 case AGGR_NONE: 869 evlist__for_each(evsel_list, counter) 870 print_counter(counter, prefix); 871 break; 872 case AGGR_UNSET: 873 default: 874 break; 875 } 876 877 if (!interval && !csv_output) 878 print_footer(); 879 880 fflush(stat_config.output); 881 } 882 883 static volatile int signr = -1; 884 885 static void skip_signal(int signo) 886 { 887 if ((child_pid == -1) || stat_config.interval) 888 done = 1; 889 890 signr = signo; 891 /* 892 * render child_pid harmless 893 * won't send SIGTERM to a random 894 * process in case of race condition 895 * and fast PID recycling 896 */ 897 child_pid = -1; 898 } 899 900 static void sig_atexit(void) 901 { 902 sigset_t set, oset; 903 904 /* 905 * avoid race condition with SIGCHLD handler 906 * in skip_signal() which is modifying child_pid 907 * goal is to avoid send SIGTERM to a random 908 * process 909 */ 910 sigemptyset(&set); 911 sigaddset(&set, SIGCHLD); 912 sigprocmask(SIG_BLOCK, &set, &oset); 913 914 if (child_pid != -1) 915 kill(child_pid, SIGTERM); 916 917 sigprocmask(SIG_SETMASK, &oset, NULL); 918 919 if (signr == -1) 920 return; 921 922 signal(signr, SIG_DFL); 923 kill(getpid(), signr); 924 } 925 926 static int stat__set_big_num(const struct option *opt __maybe_unused, 927 const char *s __maybe_unused, int unset) 928 { 929 big_num_opt = unset ? 0 : 1; 930 return 0; 931 } 932 933 static const struct option stat_options[] = { 934 OPT_BOOLEAN('T', "transaction", &transaction_run, 935 "hardware transaction statistics"), 936 OPT_CALLBACK('e', "event", &evsel_list, "event", 937 "event selector. use 'perf list' to list available events", 938 parse_events_option), 939 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 940 "event filter", parse_filter), 941 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 942 "child tasks do not inherit counters"), 943 OPT_STRING('p', "pid", &target.pid, "pid", 944 "stat events on existing process id"), 945 OPT_STRING('t', "tid", &target.tid, "tid", 946 "stat events on existing thread id"), 947 OPT_BOOLEAN('a', "all-cpus", &target.system_wide, 948 "system-wide collection from all CPUs"), 949 OPT_BOOLEAN('g', "group", &group, 950 "put the counters into a counter group"), 951 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), 952 OPT_INCR('v', "verbose", &verbose, 953 "be more verbose (show counter open errors, etc)"), 954 OPT_INTEGER('r', "repeat", &run_count, 955 "repeat command and print average + stddev (max: 100, forever: 0)"), 956 OPT_BOOLEAN('n', "null", &null_run, 957 "null run - dont start any counters"), 958 OPT_INCR('d', "detailed", &detailed_run, 959 "detailed run - start a lot of events"), 960 OPT_BOOLEAN('S', "sync", &sync_run, 961 "call sync() before starting a run"), 962 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 963 "print large numbers with thousands\' separators", 964 stat__set_big_num), 965 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 966 "list of cpus to monitor in system-wide"), 967 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 968 "disable CPU count aggregation", AGGR_NONE), 969 OPT_STRING('x', "field-separator", &csv_sep, "separator", 970 "print counts with custom separator"), 971 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 972 "monitor event in cgroup name only", parse_cgroups), 973 OPT_STRING('o', "output", &output_name, "file", "output file name"), 974 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), 975 OPT_INTEGER(0, "log-fd", &output_fd, 976 "log output to fd, instead of stderr"), 977 OPT_STRING(0, "pre", &pre_cmd, "command", 978 "command to run prior to the measured command"), 979 OPT_STRING(0, "post", &post_cmd, "command", 980 "command to run after to the measured command"), 981 OPT_UINTEGER('I', "interval-print", &stat_config.interval, 982 "print counts at regular interval in ms (>= 10)"), 983 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, 984 "aggregate counts per processor socket", AGGR_SOCKET), 985 OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, 986 "aggregate counts per physical processor core", AGGR_CORE), 987 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, 988 "aggregate counts per thread", AGGR_THREAD), 989 OPT_UINTEGER('D', "delay", &initial_delay, 990 "ms to wait before starting measurement after program start"), 991 OPT_END() 992 }; 993 994 static int perf_stat__get_socket(struct cpu_map *map, int cpu) 995 { 996 return cpu_map__get_socket(map, cpu, NULL); 997 } 998 999 static int perf_stat__get_core(struct cpu_map *map, int cpu) 1000 { 1001 return cpu_map__get_core(map, cpu, NULL); 1002 } 1003 1004 static int cpu_map__get_max(struct cpu_map *map) 1005 { 1006 int i, max = -1; 1007 1008 for (i = 0; i < map->nr; i++) { 1009 if (map->map[i] > max) 1010 max = map->map[i]; 1011 } 1012 1013 return max; 1014 } 1015 1016 static struct cpu_map *cpus_aggr_map; 1017 1018 static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) 1019 { 1020 int cpu; 1021 1022 if (idx >= map->nr) 1023 return -1; 1024 1025 cpu = map->map[idx]; 1026 1027 if (cpus_aggr_map->map[cpu] == -1) 1028 cpus_aggr_map->map[cpu] = get_id(map, idx); 1029 1030 return cpus_aggr_map->map[cpu]; 1031 } 1032 1033 static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) 1034 { 1035 return perf_stat__get_aggr(perf_stat__get_socket, map, idx); 1036 } 1037 1038 static int perf_stat__get_core_cached(struct cpu_map *map, int idx) 1039 { 1040 return perf_stat__get_aggr(perf_stat__get_core, map, idx); 1041 } 1042 1043 static int perf_stat_init_aggr_mode(void) 1044 { 1045 int nr; 1046 1047 switch (stat_config.aggr_mode) { 1048 case AGGR_SOCKET: 1049 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { 1050 perror("cannot build socket map"); 1051 return -1; 1052 } 1053 aggr_get_id = perf_stat__get_socket_cached; 1054 break; 1055 case AGGR_CORE: 1056 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { 1057 perror("cannot build core map"); 1058 return -1; 1059 } 1060 aggr_get_id = perf_stat__get_core_cached; 1061 break; 1062 case AGGR_NONE: 1063 case AGGR_GLOBAL: 1064 case AGGR_THREAD: 1065 case AGGR_UNSET: 1066 default: 1067 break; 1068 } 1069 1070 /* 1071 * The evsel_list->cpus is the base we operate on, 1072 * taking the highest cpu number to be the size of 1073 * the aggregation translate cpumap. 1074 */ 1075 nr = cpu_map__get_max(evsel_list->cpus); 1076 cpus_aggr_map = cpu_map__empty_new(nr + 1); 1077 return cpus_aggr_map ? 0 : -ENOMEM; 1078 } 1079 1080 /* 1081 * Add default attributes, if there were no attributes specified or 1082 * if -d/--detailed, -d -d or -d -d -d is used: 1083 */ 1084 static int add_default_attributes(void) 1085 { 1086 struct perf_event_attr default_attrs[] = { 1087 1088 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1089 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 1090 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, 1091 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 1092 1093 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 1094 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, 1095 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, 1096 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 1097 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 1098 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 1099 1100 }; 1101 1102 /* 1103 * Detailed stats (-d), covering the L1 and last level data caches: 1104 */ 1105 struct perf_event_attr detailed_attrs[] = { 1106 1107 { .type = PERF_TYPE_HW_CACHE, 1108 .config = 1109 PERF_COUNT_HW_CACHE_L1D << 0 | 1110 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1111 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1112 1113 { .type = PERF_TYPE_HW_CACHE, 1114 .config = 1115 PERF_COUNT_HW_CACHE_L1D << 0 | 1116 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1117 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1118 1119 { .type = PERF_TYPE_HW_CACHE, 1120 .config = 1121 PERF_COUNT_HW_CACHE_LL << 0 | 1122 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1123 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1124 1125 { .type = PERF_TYPE_HW_CACHE, 1126 .config = 1127 PERF_COUNT_HW_CACHE_LL << 0 | 1128 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1129 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1130 }; 1131 1132 /* 1133 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: 1134 */ 1135 struct perf_event_attr very_detailed_attrs[] = { 1136 1137 { .type = PERF_TYPE_HW_CACHE, 1138 .config = 1139 PERF_COUNT_HW_CACHE_L1I << 0 | 1140 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1141 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1142 1143 { .type = PERF_TYPE_HW_CACHE, 1144 .config = 1145 PERF_COUNT_HW_CACHE_L1I << 0 | 1146 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1147 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1148 1149 { .type = PERF_TYPE_HW_CACHE, 1150 .config = 1151 PERF_COUNT_HW_CACHE_DTLB << 0 | 1152 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1153 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1154 1155 { .type = PERF_TYPE_HW_CACHE, 1156 .config = 1157 PERF_COUNT_HW_CACHE_DTLB << 0 | 1158 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1159 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1160 1161 { .type = PERF_TYPE_HW_CACHE, 1162 .config = 1163 PERF_COUNT_HW_CACHE_ITLB << 0 | 1164 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1165 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1166 1167 { .type = PERF_TYPE_HW_CACHE, 1168 .config = 1169 PERF_COUNT_HW_CACHE_ITLB << 0 | 1170 (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1171 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1172 1173 }; 1174 1175 /* 1176 * Very, very detailed stats (-d -d -d), adding prefetch events: 1177 */ 1178 struct perf_event_attr very_very_detailed_attrs[] = { 1179 1180 { .type = PERF_TYPE_HW_CACHE, 1181 .config = 1182 PERF_COUNT_HW_CACHE_L1D << 0 | 1183 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 1184 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, 1185 1186 { .type = PERF_TYPE_HW_CACHE, 1187 .config = 1188 PERF_COUNT_HW_CACHE_L1D << 0 | 1189 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 1190 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 1191 }; 1192 1193 /* Set attrs if no event is selected and !null_run: */ 1194 if (null_run) 1195 return 0; 1196 1197 if (transaction_run) { 1198 int err; 1199 if (pmu_have_event("cpu", "cycles-ct") && 1200 pmu_have_event("cpu", "el-start")) 1201 err = parse_events(evsel_list, transaction_attrs, NULL); 1202 else 1203 err = parse_events(evsel_list, transaction_limited_attrs, NULL); 1204 if (err) { 1205 fprintf(stderr, "Cannot set up transaction events\n"); 1206 return -1; 1207 } 1208 return 0; 1209 } 1210 1211 if (!evsel_list->nr_entries) { 1212 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1213 return -1; 1214 } 1215 1216 /* Detailed events get appended to the event list: */ 1217 1218 if (detailed_run < 1) 1219 return 0; 1220 1221 /* Append detailed run extra attributes: */ 1222 if (perf_evlist__add_default_attrs(evsel_list, detailed_attrs) < 0) 1223 return -1; 1224 1225 if (detailed_run < 2) 1226 return 0; 1227 1228 /* Append very detailed run extra attributes: */ 1229 if (perf_evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0) 1230 return -1; 1231 1232 if (detailed_run < 3) 1233 return 0; 1234 1235 /* Append very, very detailed run extra attributes: */ 1236 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); 1237 } 1238 1239 int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1240 { 1241 const char * const stat_usage[] = { 1242 "perf stat [<options>] [<command>]", 1243 NULL 1244 }; 1245 int status = -EINVAL, run_idx; 1246 const char *mode; 1247 FILE *output = stderr; 1248 unsigned int interval; 1249 1250 setlocale(LC_ALL, ""); 1251 1252 evsel_list = perf_evlist__new(); 1253 if (evsel_list == NULL) 1254 return -ENOMEM; 1255 1256 argc = parse_options(argc, argv, stat_options, stat_usage, 1257 PARSE_OPT_STOP_AT_NON_OPTION); 1258 1259 interval = stat_config.interval; 1260 1261 if (output_name && strcmp(output_name, "-")) 1262 output = NULL; 1263 1264 if (output_name && output_fd) { 1265 fprintf(stderr, "cannot use both --output and --log-fd\n"); 1266 parse_options_usage(stat_usage, stat_options, "o", 1); 1267 parse_options_usage(NULL, stat_options, "log-fd", 0); 1268 goto out; 1269 } 1270 1271 if (output_fd < 0) { 1272 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 1273 parse_options_usage(stat_usage, stat_options, "log-fd", 0); 1274 goto out; 1275 } 1276 1277 if (!output) { 1278 struct timespec tm; 1279 mode = append_file ? "a" : "w"; 1280 1281 output = fopen(output_name, mode); 1282 if (!output) { 1283 perror("failed to create output file"); 1284 return -1; 1285 } 1286 clock_gettime(CLOCK_REALTIME, &tm); 1287 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); 1288 } else if (output_fd > 0) { 1289 mode = append_file ? "a" : "w"; 1290 output = fdopen(output_fd, mode); 1291 if (!output) { 1292 perror("Failed opening logfd"); 1293 return -errno; 1294 } 1295 } 1296 1297 stat_config.output = output; 1298 1299 if (csv_sep) { 1300 csv_output = true; 1301 if (!strcmp(csv_sep, "\\t")) 1302 csv_sep = "\t"; 1303 } else 1304 csv_sep = DEFAULT_SEPARATOR; 1305 1306 /* 1307 * let the spreadsheet do the pretty-printing 1308 */ 1309 if (csv_output) { 1310 /* User explicitly passed -B? */ 1311 if (big_num_opt == 1) { 1312 fprintf(stderr, "-B option not supported with -x\n"); 1313 parse_options_usage(stat_usage, stat_options, "B", 1); 1314 parse_options_usage(NULL, stat_options, "x", 1); 1315 goto out; 1316 } else /* Nope, so disable big number formatting */ 1317 big_num = false; 1318 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1319 big_num = false; 1320 1321 if (!argc && target__none(&target)) 1322 usage_with_options(stat_usage, stat_options); 1323 1324 if (run_count < 0) { 1325 pr_err("Run count must be a positive number\n"); 1326 parse_options_usage(stat_usage, stat_options, "r", 1); 1327 goto out; 1328 } else if (run_count == 0) { 1329 forever = true; 1330 run_count = 1; 1331 } 1332 1333 if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { 1334 fprintf(stderr, "The --per-thread option is only available " 1335 "when monitoring via -p -t options.\n"); 1336 parse_options_usage(NULL, stat_options, "p", 1); 1337 parse_options_usage(NULL, stat_options, "t", 1); 1338 goto out; 1339 } 1340 1341 /* 1342 * no_aggr, cgroup are for system-wide only 1343 * --per-thread is aggregated per thread, we dont mix it with cpu mode 1344 */ 1345 if (((stat_config.aggr_mode != AGGR_GLOBAL && 1346 stat_config.aggr_mode != AGGR_THREAD) || nr_cgroups) && 1347 !target__has_cpu(&target)) { 1348 fprintf(stderr, "both cgroup and no-aggregation " 1349 "modes only available in system-wide mode\n"); 1350 1351 parse_options_usage(stat_usage, stat_options, "G", 1); 1352 parse_options_usage(NULL, stat_options, "A", 1); 1353 parse_options_usage(NULL, stat_options, "a", 1); 1354 goto out; 1355 } 1356 1357 if (add_default_attributes()) 1358 goto out; 1359 1360 target__validate(&target); 1361 1362 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 1363 if (target__has_task(&target)) { 1364 pr_err("Problems finding threads of monitor\n"); 1365 parse_options_usage(stat_usage, stat_options, "p", 1); 1366 parse_options_usage(NULL, stat_options, "t", 1); 1367 } else if (target__has_cpu(&target)) { 1368 perror("failed to parse CPUs map"); 1369 parse_options_usage(stat_usage, stat_options, "C", 1); 1370 parse_options_usage(NULL, stat_options, "a", 1); 1371 } 1372 goto out; 1373 } 1374 1375 /* 1376 * Initialize thread_map with comm names, 1377 * so we could print it out on output. 1378 */ 1379 if (stat_config.aggr_mode == AGGR_THREAD) 1380 thread_map__read_comms(evsel_list->threads); 1381 1382 if (interval && interval < 100) { 1383 if (interval < 10) { 1384 pr_err("print interval must be >= 10ms\n"); 1385 parse_options_usage(stat_usage, stat_options, "I", 1); 1386 goto out; 1387 } else 1388 pr_warning("print interval < 100ms. " 1389 "The overhead percentage could be high in some cases. " 1390 "Please proceed with caution.\n"); 1391 } 1392 1393 if (perf_evlist__alloc_stats(evsel_list, interval)) 1394 goto out; 1395 1396 if (perf_stat_init_aggr_mode()) 1397 goto out; 1398 1399 /* 1400 * We dont want to block the signals - that would cause 1401 * child tasks to inherit that and Ctrl-C would not work. 1402 * What we want is for Ctrl-C to work in the exec()-ed 1403 * task, but being ignored by perf stat itself: 1404 */ 1405 atexit(sig_atexit); 1406 if (!forever) 1407 signal(SIGINT, skip_signal); 1408 signal(SIGCHLD, skip_signal); 1409 signal(SIGALRM, skip_signal); 1410 signal(SIGABRT, skip_signal); 1411 1412 status = 0; 1413 for (run_idx = 0; forever || run_idx < run_count; run_idx++) { 1414 if (run_count != 1 && verbose) 1415 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1416 run_idx + 1); 1417 1418 status = run_perf_stat(argc, argv); 1419 if (forever && status != -1) { 1420 print_counters(NULL, argc, argv); 1421 perf_stat__reset_stats(); 1422 } 1423 } 1424 1425 if (!forever && status != -1 && !interval) 1426 print_counters(NULL, argc, argv); 1427 1428 perf_evlist__free_stats(evsel_list); 1429 out: 1430 perf_evlist__delete(evsel_list); 1431 return status; 1432 } 1433