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