186470930SIngo Molnar /* 286470930SIngo Molnar * builtin-stat.c 386470930SIngo Molnar * 486470930SIngo Molnar * Builtin stat command: Give a precise performance counters summary 586470930SIngo Molnar * overview about any workload, CPU or specific PID. 686470930SIngo Molnar * 786470930SIngo Molnar * Sample output: 886470930SIngo Molnar 986470930SIngo Molnar $ perf stat ~/hackbench 10 1086470930SIngo Molnar Time: 0.104 1186470930SIngo Molnar 1286470930SIngo Molnar Performance counter stats for '/home/mingo/hackbench': 1386470930SIngo Molnar 1486470930SIngo Molnar 1255.538611 task clock ticks # 10.143 CPU utilization factor 1586470930SIngo Molnar 54011 context switches # 0.043 M/sec 1686470930SIngo Molnar 385 CPU migrations # 0.000 M/sec 1786470930SIngo Molnar 17755 pagefaults # 0.014 M/sec 1886470930SIngo Molnar 3808323185 CPU cycles # 3033.219 M/sec 1986470930SIngo Molnar 1575111190 instructions # 1254.530 M/sec 2086470930SIngo Molnar 17367895 cache references # 13.833 M/sec 2186470930SIngo Molnar 7674421 cache misses # 6.112 M/sec 2286470930SIngo Molnar 2386470930SIngo Molnar Wall-clock time elapsed: 123.786620 msecs 2486470930SIngo Molnar 2586470930SIngo Molnar * 2686470930SIngo Molnar * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 2786470930SIngo Molnar * 2886470930SIngo Molnar * Improvements and fixes by: 2986470930SIngo Molnar * 3086470930SIngo Molnar * Arjan van de Ven <arjan@linux.intel.com> 3186470930SIngo Molnar * Yanmin Zhang <yanmin.zhang@intel.com> 3286470930SIngo Molnar * Wu Fengguang <fengguang.wu@intel.com> 3386470930SIngo Molnar * Mike Galbraith <efault@gmx.de> 3486470930SIngo Molnar * Paul Mackerras <paulus@samba.org> 356e750a8fSJaswinder Singh Rajput * Jaswinder Singh Rajput <jaswinder@kernel.org> 3686470930SIngo Molnar * 3786470930SIngo Molnar * Released under the GPL v2. (and only v2, not any later version) 3886470930SIngo Molnar */ 3986470930SIngo Molnar 4086470930SIngo Molnar #include "perf.h" 4186470930SIngo Molnar #include "builtin.h" 4286470930SIngo Molnar #include "util/util.h" 4386470930SIngo Molnar #include "util/parse-options.h" 4486470930SIngo Molnar #include "util/parse-events.h" 458f28827aSFrederic Weisbecker #include "util/event.h" 468f28827aSFrederic Weisbecker #include "util/debug.h" 4760666c63SLiming Wang #include "util/header.h" 48a12b51c4SPaul Mackerras #include "util/cpumap.h" 49d6d901c2SZhang, Yanmin #include "util/thread.h" 5086470930SIngo Molnar 5186470930SIngo Molnar #include <sys/prctl.h> 5242202dd5SIngo Molnar #include <math.h> 535af52b51SStephane Eranian #include <locale.h> 5486470930SIngo Molnar 55cdd6c482SIngo Molnar static struct perf_event_attr default_attrs[] = { 5686470930SIngo Molnar 57f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 58f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 59f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, 60f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 6186470930SIngo Molnar 62f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 63f4dbfa8fSPeter Zijlstra { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 6412133affSTim Blechmann { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 6512133affSTim Blechmann { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 66dd86e72aSIngo Molnar { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES }, 67dd86e72aSIngo Molnar { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, 68f4dbfa8fSPeter Zijlstra 6986470930SIngo Molnar }; 7086470930SIngo Molnar 71c0555642SIan Munsie static bool system_wide = false; 72c45c6ea2SStephane Eranian static int nr_cpus = 0; 7342202dd5SIngo Molnar static int run_idx = 0; 7442202dd5SIngo Molnar 753d632595SJaswinder Singh Rajput static int run_count = 1; 762e6cdf99SStephane Eranian static bool no_inherit = false; 77c0555642SIan Munsie static bool scale = true; 78f5b4a9c3SStephane Eranian static bool no_aggr = false; 79933da83aSChris Wilson static pid_t target_pid = -1; 80d6d901c2SZhang, Yanmin static pid_t target_tid = -1; 81d6d901c2SZhang, Yanmin static pid_t *all_tids = NULL; 82d6d901c2SZhang, Yanmin static int thread_num = 0; 83933da83aSChris Wilson static pid_t child_pid = -1; 84c0555642SIan Munsie static bool null_run = false; 855af52b51SStephane Eranian static bool big_num = false; 86c45c6ea2SStephane Eranian static const char *cpu_list; 875af52b51SStephane Eranian 8842202dd5SIngo Molnar 89d6d901c2SZhang, Yanmin static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 9042202dd5SIngo Molnar 9163d40debSPeter Zijlstra static int event_scaled[MAX_COUNTERS]; 923d632595SJaswinder Singh Rajput 93f5b4a9c3SStephane Eranian static struct { 94f5b4a9c3SStephane Eranian u64 val; 95f5b4a9c3SStephane Eranian u64 ena; 96f5b4a9c3SStephane Eranian u64 run; 97f5b4a9c3SStephane Eranian } cpu_counts[MAX_NR_CPUS][MAX_COUNTERS]; 98f5b4a9c3SStephane Eranian 9960666c63SLiming Wang static volatile int done = 0; 10060666c63SLiming Wang 101506d4bc8SPeter Zijlstra struct stats 102506d4bc8SPeter Zijlstra { 1038a02631aSPeter Zijlstra double n, mean, M2; 104506d4bc8SPeter Zijlstra }; 10542202dd5SIngo Molnar 1069e9772c4SPeter Zijlstra static void update_stats(struct stats *stats, u64 val) 1079e9772c4SPeter Zijlstra { 1088a02631aSPeter Zijlstra double delta; 1099e9772c4SPeter Zijlstra 1108a02631aSPeter Zijlstra stats->n++; 1118a02631aSPeter Zijlstra delta = val - stats->mean; 1128a02631aSPeter Zijlstra stats->mean += delta / stats->n; 1138a02631aSPeter Zijlstra stats->M2 += delta*(val - stats->mean); 1149e9772c4SPeter Zijlstra } 1159e9772c4SPeter Zijlstra 116506d4bc8SPeter Zijlstra static double avg_stats(struct stats *stats) 117506d4bc8SPeter Zijlstra { 1188a02631aSPeter Zijlstra return stats->mean; 119506d4bc8SPeter Zijlstra } 12042202dd5SIngo Molnar 121506d4bc8SPeter Zijlstra /* 12263d40debSPeter Zijlstra * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance 12363d40debSPeter Zijlstra * 12463d40debSPeter Zijlstra * (\Sum n_i^2) - ((\Sum n_i)^2)/n 1258a02631aSPeter Zijlstra * s^2 = ------------------------------- 12663d40debSPeter Zijlstra * n - 1 12763d40debSPeter Zijlstra * 12863d40debSPeter Zijlstra * http://en.wikipedia.org/wiki/Stddev 12963d40debSPeter Zijlstra * 13063d40debSPeter Zijlstra * The std dev of the mean is related to the std dev by: 13163d40debSPeter Zijlstra * 13263d40debSPeter Zijlstra * s 13363d40debSPeter Zijlstra * s_mean = ------- 13463d40debSPeter Zijlstra * sqrt(n) 13563d40debSPeter Zijlstra * 136506d4bc8SPeter Zijlstra */ 137506d4bc8SPeter Zijlstra static double stddev_stats(struct stats *stats) 138506d4bc8SPeter Zijlstra { 1398a02631aSPeter Zijlstra double variance = stats->M2 / (stats->n - 1); 1408a02631aSPeter Zijlstra double variance_mean = variance / stats->n; 14142202dd5SIngo Molnar 14263d40debSPeter Zijlstra return sqrt(variance_mean); 143506d4bc8SPeter Zijlstra } 14442202dd5SIngo Molnar 145506d4bc8SPeter Zijlstra struct stats event_res_stats[MAX_COUNTERS][3]; 146f5b4a9c3SStephane Eranian struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 147f5b4a9c3SStephane Eranian struct stats runtime_cycles_stats[MAX_NR_CPUS]; 148f5b4a9c3SStephane Eranian struct stats runtime_branches_stats[MAX_NR_CPUS]; 149506d4bc8SPeter Zijlstra struct stats walltime_nsecs_stats; 15086470930SIngo Molnar 151b9ebdcc0SJaswinder Singh Rajput #define MATCH_EVENT(t, c, counter) \ 152b9ebdcc0SJaswinder Singh Rajput (attrs[counter].type == PERF_TYPE_##t && \ 153b9ebdcc0SJaswinder Singh Rajput attrs[counter].config == PERF_COUNT_##c) 154b9ebdcc0SJaswinder Singh Rajput 155cca03c0aSJaswinder Singh Rajput #define ERR_PERF_OPEN \ 156d9cf837eSCorey Ashford "counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." 157cca03c0aSJaswinder Singh Rajput 158d9cf837eSCorey Ashford static int create_perf_stat_counter(int counter, bool *perm_err) 15986470930SIngo Molnar { 160cdd6c482SIngo Molnar struct perf_event_attr *attr = attrs + counter; 161d6d901c2SZhang, Yanmin int thread; 162084ab9f8SArnaldo Carvalho de Melo int ncreated = 0; 16386470930SIngo Molnar 16486470930SIngo Molnar if (scale) 16586470930SIngo Molnar attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 16686470930SIngo Molnar PERF_FORMAT_TOTAL_TIME_RUNNING; 16786470930SIngo Molnar 16886470930SIngo Molnar if (system_wide) { 169c45c6ea2SStephane Eranian int cpu; 170f37a291cSIngo Molnar 17186470930SIngo Molnar for (cpu = 0; cpu < nr_cpus; cpu++) { 172d6d901c2SZhang, Yanmin fd[cpu][counter][0] = sys_perf_event_open(attr, 173d6d901c2SZhang, Yanmin -1, cpumap[cpu], -1, 0); 174d9cf837eSCorey Ashford if (fd[cpu][counter][0] < 0) { 175d9cf837eSCorey Ashford if (errno == EPERM || errno == EACCES) 176d9cf837eSCorey Ashford *perm_err = true; 177d9cf837eSCorey Ashford error(ERR_PERF_OPEN, counter, 178d6d901c2SZhang, Yanmin fd[cpu][counter][0], strerror(errno)); 179d9cf837eSCorey Ashford } else { 180084ab9f8SArnaldo Carvalho de Melo ++ncreated; 18186470930SIngo Molnar } 182d9cf837eSCorey Ashford } 18386470930SIngo Molnar } else { 1842e6cdf99SStephane Eranian attr->inherit = !no_inherit; 1852e6cdf99SStephane Eranian if (target_pid == -1 && target_tid == -1) { 18686470930SIngo Molnar attr->disabled = 1; 18757e7986eSPaul Mackerras attr->enable_on_exec = 1; 1886be2850eSZhang, Yanmin } 189d6d901c2SZhang, Yanmin for (thread = 0; thread < thread_num; thread++) { 190d6d901c2SZhang, Yanmin fd[0][counter][thread] = sys_perf_event_open(attr, 191d6d901c2SZhang, Yanmin all_tids[thread], -1, -1, 0); 192d9cf837eSCorey Ashford if (fd[0][counter][thread] < 0) { 193d9cf837eSCorey Ashford if (errno == EPERM || errno == EACCES) 194d9cf837eSCorey Ashford *perm_err = true; 195d9cf837eSCorey Ashford error(ERR_PERF_OPEN, counter, 196d6d901c2SZhang, Yanmin fd[0][counter][thread], 197d6d901c2SZhang, Yanmin strerror(errno)); 198d9cf837eSCorey Ashford } else { 199084ab9f8SArnaldo Carvalho de Melo ++ncreated; 200d6d901c2SZhang, Yanmin } 20186470930SIngo Molnar } 202d9cf837eSCorey Ashford } 203084ab9f8SArnaldo Carvalho de Melo 204084ab9f8SArnaldo Carvalho de Melo return ncreated; 20586470930SIngo Molnar } 20686470930SIngo Molnar 20786470930SIngo Molnar /* 20886470930SIngo Molnar * Does the counter have nsecs as a unit? 20986470930SIngo Molnar */ 21086470930SIngo Molnar static inline int nsec_counter(int counter) 21186470930SIngo Molnar { 212b9ebdcc0SJaswinder Singh Rajput if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 213b9ebdcc0SJaswinder Singh Rajput MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 21486470930SIngo Molnar return 1; 21586470930SIngo Molnar 21686470930SIngo Molnar return 0; 21786470930SIngo Molnar } 21886470930SIngo Molnar 21986470930SIngo Molnar /* 22086470930SIngo Molnar * Read out the results of a single counter: 221f5b4a9c3SStephane Eranian * aggregate counts across CPUs in system-wide mode 22286470930SIngo Molnar */ 223f5b4a9c3SStephane Eranian static void read_counter_aggr(int counter) 22486470930SIngo Molnar { 225849abde9SPeter Zijlstra u64 count[3], single_count[3]; 226c45c6ea2SStephane Eranian int cpu; 227f37a291cSIngo Molnar size_t res, nv; 22886470930SIngo Molnar int scaled; 229d6d901c2SZhang, Yanmin int i, thread; 23086470930SIngo Molnar 23186470930SIngo Molnar count[0] = count[1] = count[2] = 0; 23286470930SIngo Molnar 23386470930SIngo Molnar nv = scale ? 3 : 1; 23486470930SIngo Molnar for (cpu = 0; cpu < nr_cpus; cpu++) { 235d6d901c2SZhang, Yanmin for (thread = 0; thread < thread_num; thread++) { 236d6d901c2SZhang, Yanmin if (fd[cpu][counter][thread] < 0) 237743ee1f8SIngo Molnar continue; 238743ee1f8SIngo Molnar 239d6d901c2SZhang, Yanmin res = read(fd[cpu][counter][thread], 240d6d901c2SZhang, Yanmin single_count, nv * sizeof(u64)); 2419cffa8d5SPaul Mackerras assert(res == nv * sizeof(u64)); 242f37a291cSIngo Molnar 243d6d901c2SZhang, Yanmin close(fd[cpu][counter][thread]); 244d6d901c2SZhang, Yanmin fd[cpu][counter][thread] = -1; 24586470930SIngo Molnar 24686470930SIngo Molnar count[0] += single_count[0]; 24786470930SIngo Molnar if (scale) { 24886470930SIngo Molnar count[1] += single_count[1]; 24986470930SIngo Molnar count[2] += single_count[2]; 25086470930SIngo Molnar } 25186470930SIngo Molnar } 252d6d901c2SZhang, Yanmin } 25386470930SIngo Molnar 25486470930SIngo Molnar scaled = 0; 25586470930SIngo Molnar if (scale) { 25686470930SIngo Molnar if (count[2] == 0) { 2579e9772c4SPeter Zijlstra event_scaled[counter] = -1; 25886470930SIngo Molnar count[0] = 0; 25986470930SIngo Molnar return; 26086470930SIngo Molnar } 26186470930SIngo Molnar 26286470930SIngo Molnar if (count[2] < count[1]) { 2639e9772c4SPeter Zijlstra event_scaled[counter] = 1; 26486470930SIngo Molnar count[0] = (unsigned long long) 26586470930SIngo Molnar ((double)count[0] * count[1] / count[2] + 0.5); 26686470930SIngo Molnar } 26786470930SIngo Molnar } 2689e9772c4SPeter Zijlstra 2699e9772c4SPeter Zijlstra for (i = 0; i < 3; i++) 2709e9772c4SPeter Zijlstra update_stats(&event_res_stats[counter][i], count[i]); 2719e9772c4SPeter Zijlstra 2729e9772c4SPeter Zijlstra if (verbose) { 2739e9772c4SPeter Zijlstra fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), 2749e9772c4SPeter Zijlstra count[0], count[1], count[2]); 2759e9772c4SPeter Zijlstra } 2769e9772c4SPeter Zijlstra 27786470930SIngo Molnar /* 27886470930SIngo Molnar * Save the full runtime - to allow normalization during printout: 27986470930SIngo Molnar */ 280b9ebdcc0SJaswinder Singh Rajput if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 281f5b4a9c3SStephane Eranian update_stats(&runtime_nsecs_stats[0], count[0]); 282b9ebdcc0SJaswinder Singh Rajput if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 283f5b4a9c3SStephane Eranian update_stats(&runtime_cycles_stats[0], count[0]); 28411018201SAnton Blanchard if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) 285f5b4a9c3SStephane Eranian update_stats(&runtime_branches_stats[0], count[0]); 286f5b4a9c3SStephane Eranian } 287f5b4a9c3SStephane Eranian 288f5b4a9c3SStephane Eranian /* 289f5b4a9c3SStephane Eranian * Read out the results of a single counter: 290f5b4a9c3SStephane Eranian * do not aggregate counts across CPUs in system-wide mode 291f5b4a9c3SStephane Eranian */ 292f5b4a9c3SStephane Eranian static void read_counter(int counter) 293f5b4a9c3SStephane Eranian { 294f5b4a9c3SStephane Eranian u64 count[3]; 295f5b4a9c3SStephane Eranian int cpu; 296f5b4a9c3SStephane Eranian size_t res, nv; 297f5b4a9c3SStephane Eranian 298f5b4a9c3SStephane Eranian count[0] = count[1] = count[2] = 0; 299f5b4a9c3SStephane Eranian 300f5b4a9c3SStephane Eranian nv = scale ? 3 : 1; 301f5b4a9c3SStephane Eranian 302f5b4a9c3SStephane Eranian for (cpu = 0; cpu < nr_cpus; cpu++) { 303f5b4a9c3SStephane Eranian 304f5b4a9c3SStephane Eranian if (fd[cpu][counter][0] < 0) 305f5b4a9c3SStephane Eranian continue; 306f5b4a9c3SStephane Eranian 307f5b4a9c3SStephane Eranian res = read(fd[cpu][counter][0], count, nv * sizeof(u64)); 308f5b4a9c3SStephane Eranian 309f5b4a9c3SStephane Eranian assert(res == nv * sizeof(u64)); 310f5b4a9c3SStephane Eranian 311f5b4a9c3SStephane Eranian close(fd[cpu][counter][0]); 312f5b4a9c3SStephane Eranian fd[cpu][counter][0] = -1; 313f5b4a9c3SStephane Eranian 314f5b4a9c3SStephane Eranian if (scale) { 315f5b4a9c3SStephane Eranian if (count[2] == 0) { 316f5b4a9c3SStephane Eranian count[0] = 0; 317f5b4a9c3SStephane Eranian } else if (count[2] < count[1]) { 318f5b4a9c3SStephane Eranian count[0] = (unsigned long long) 319f5b4a9c3SStephane Eranian ((double)count[0] * count[1] / count[2] + 0.5); 320f5b4a9c3SStephane Eranian } 321f5b4a9c3SStephane Eranian } 322f5b4a9c3SStephane Eranian cpu_counts[cpu][counter].val = count[0]; /* scaled count */ 323f5b4a9c3SStephane Eranian cpu_counts[cpu][counter].ena = count[1]; 324f5b4a9c3SStephane Eranian cpu_counts[cpu][counter].run = count[2]; 325f5b4a9c3SStephane Eranian 326f5b4a9c3SStephane Eranian if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 327f5b4a9c3SStephane Eranian update_stats(&runtime_nsecs_stats[cpu], count[0]); 328f5b4a9c3SStephane Eranian if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 329f5b4a9c3SStephane Eranian update_stats(&runtime_cycles_stats[cpu], count[0]); 330f5b4a9c3SStephane Eranian if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) 331f5b4a9c3SStephane Eranian update_stats(&runtime_branches_stats[cpu], count[0]); 332f5b4a9c3SStephane Eranian } 33386470930SIngo Molnar } 33486470930SIngo Molnar 335f37a291cSIngo Molnar static int run_perf_stat(int argc __used, const char **argv) 33686470930SIngo Molnar { 33786470930SIngo Molnar unsigned long long t0, t1; 33842202dd5SIngo Molnar int status = 0; 339084ab9f8SArnaldo Carvalho de Melo int counter, ncreated = 0; 340051ae7f7SPaul Mackerras int child_ready_pipe[2], go_pipe[2]; 341d9cf837eSCorey Ashford bool perm_err = false; 3426be2850eSZhang, Yanmin const bool forks = (argc > 0); 343051ae7f7SPaul Mackerras char buf; 34486470930SIngo Molnar 34586470930SIngo Molnar if (!system_wide) 34686470930SIngo Molnar nr_cpus = 1; 34786470930SIngo Molnar 34860666c63SLiming Wang if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 349051ae7f7SPaul Mackerras perror("failed to create pipes"); 350051ae7f7SPaul Mackerras exit(1); 351051ae7f7SPaul Mackerras } 352051ae7f7SPaul Mackerras 35360666c63SLiming Wang if (forks) { 3546be2850eSZhang, Yanmin if ((child_pid = fork()) < 0) 355051ae7f7SPaul Mackerras perror("failed to fork"); 356051ae7f7SPaul Mackerras 3576be2850eSZhang, Yanmin if (!child_pid) { 358051ae7f7SPaul Mackerras close(child_ready_pipe[0]); 359051ae7f7SPaul Mackerras close(go_pipe[1]); 360051ae7f7SPaul Mackerras fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 361051ae7f7SPaul Mackerras 362051ae7f7SPaul Mackerras /* 363051ae7f7SPaul Mackerras * Do a dummy execvp to get the PLT entry resolved, 364051ae7f7SPaul Mackerras * so we avoid the resolver overhead on the real 365051ae7f7SPaul Mackerras * execvp call. 366051ae7f7SPaul Mackerras */ 367051ae7f7SPaul Mackerras execvp("", (char **)argv); 368051ae7f7SPaul Mackerras 369051ae7f7SPaul Mackerras /* 370051ae7f7SPaul Mackerras * Tell the parent we're ready to go 371051ae7f7SPaul Mackerras */ 372051ae7f7SPaul Mackerras close(child_ready_pipe[1]); 373051ae7f7SPaul Mackerras 374051ae7f7SPaul Mackerras /* 375051ae7f7SPaul Mackerras * Wait until the parent tells us to go. 376051ae7f7SPaul Mackerras */ 377a92bef0fSFrederic Weisbecker if (read(go_pipe[0], &buf, 1) == -1) 378a92bef0fSFrederic Weisbecker perror("unable to read pipe"); 379051ae7f7SPaul Mackerras 380051ae7f7SPaul Mackerras execvp(argv[0], (char **)argv); 381051ae7f7SPaul Mackerras 382051ae7f7SPaul Mackerras perror(argv[0]); 383051ae7f7SPaul Mackerras exit(-1); 384051ae7f7SPaul Mackerras } 385051ae7f7SPaul Mackerras 386d6d901c2SZhang, Yanmin if (target_tid == -1 && target_pid == -1 && !system_wide) 387d6d901c2SZhang, Yanmin all_tids[0] = child_pid; 388d6d901c2SZhang, Yanmin 389051ae7f7SPaul Mackerras /* 390051ae7f7SPaul Mackerras * Wait for the child to be ready to exec. 391051ae7f7SPaul Mackerras */ 392051ae7f7SPaul Mackerras close(child_ready_pipe[1]); 393051ae7f7SPaul Mackerras close(go_pipe[0]); 394a92bef0fSFrederic Weisbecker if (read(child_ready_pipe[0], &buf, 1) == -1) 395a92bef0fSFrederic Weisbecker perror("unable to read pipe"); 396051ae7f7SPaul Mackerras close(child_ready_pipe[0]); 39760666c63SLiming Wang } 398051ae7f7SPaul Mackerras 39986470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) 400d9cf837eSCorey Ashford ncreated += create_perf_stat_counter(counter, &perm_err); 401084ab9f8SArnaldo Carvalho de Melo 402d9cf837eSCorey Ashford if (ncreated < nr_counters) { 403d9cf837eSCorey Ashford if (perm_err) 404d9cf837eSCorey Ashford error("You may not have permission to collect %sstats.\n" 405d9cf837eSCorey Ashford "\t Consider tweaking" 406d9cf837eSCorey Ashford " /proc/sys/kernel/perf_event_paranoid or running as root.", 407084ab9f8SArnaldo Carvalho de Melo system_wide ? "system-wide " : ""); 408d9cf837eSCorey Ashford die("Not all events could be opened.\n"); 409084ab9f8SArnaldo Carvalho de Melo if (child_pid != -1) 410084ab9f8SArnaldo Carvalho de Melo kill(child_pid, SIGTERM); 411084ab9f8SArnaldo Carvalho de Melo return -1; 412084ab9f8SArnaldo Carvalho de Melo } 41386470930SIngo Molnar 41486470930SIngo Molnar /* 41586470930SIngo Molnar * Enable counters and exec the command: 41686470930SIngo Molnar */ 41786470930SIngo Molnar t0 = rdclock(); 41886470930SIngo Molnar 41960666c63SLiming Wang if (forks) { 420051ae7f7SPaul Mackerras close(go_pipe[1]); 42142202dd5SIngo Molnar wait(&status); 42260666c63SLiming Wang } else { 4236be2850eSZhang, Yanmin while(!done) sleep(1); 42460666c63SLiming Wang } 42586470930SIngo Molnar 42686470930SIngo Molnar t1 = rdclock(); 42786470930SIngo Molnar 4289e9772c4SPeter Zijlstra update_stats(&walltime_nsecs_stats, t1 - t0); 42942202dd5SIngo Molnar 430f5b4a9c3SStephane Eranian if (no_aggr) { 43142202dd5SIngo Molnar for (counter = 0; counter < nr_counters; counter++) 43242202dd5SIngo Molnar read_counter(counter); 433f5b4a9c3SStephane Eranian } else { 434f5b4a9c3SStephane Eranian for (counter = 0; counter < nr_counters; counter++) 435f5b4a9c3SStephane Eranian read_counter_aggr(counter); 436f5b4a9c3SStephane Eranian } 43742202dd5SIngo Molnar return WEXITSTATUS(status); 43842202dd5SIngo Molnar } 43942202dd5SIngo Molnar 440849abde9SPeter Zijlstra static void print_noise(int counter, double avg) 44142202dd5SIngo Molnar { 442849abde9SPeter Zijlstra if (run_count == 1) 443849abde9SPeter Zijlstra return; 444849abde9SPeter Zijlstra 445849abde9SPeter Zijlstra fprintf(stderr, " ( +- %7.3f%% )", 446849abde9SPeter Zijlstra 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 44742202dd5SIngo Molnar } 44842202dd5SIngo Molnar 449f5b4a9c3SStephane Eranian static void nsec_printout(int cpu, int counter, double avg) 45042202dd5SIngo Molnar { 451506d4bc8SPeter Zijlstra double msecs = avg / 1e6; 45242202dd5SIngo Molnar 453f5b4a9c3SStephane Eranian if (no_aggr) 454f5b4a9c3SStephane Eranian fprintf(stderr, "CPU%-4d %18.6f %-24s", 455f5b4a9c3SStephane Eranian cpumap[cpu], msecs, event_name(counter)); 456f5b4a9c3SStephane Eranian else 4575af52b51SStephane Eranian fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); 45842202dd5SIngo Molnar 459b9ebdcc0SJaswinder Singh Rajput if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 46042202dd5SIngo Molnar fprintf(stderr, " # %10.3f CPUs ", 461506d4bc8SPeter Zijlstra avg / avg_stats(&walltime_nsecs_stats)); 46242202dd5SIngo Molnar } 46342202dd5SIngo Molnar } 46442202dd5SIngo Molnar 465f5b4a9c3SStephane Eranian static void abs_printout(int cpu, int counter, double avg) 46642202dd5SIngo Molnar { 467c7f7fea3SIngo Molnar double total, ratio = 0.0; 468f5b4a9c3SStephane Eranian char cpustr[16] = { '\0', }; 469f5b4a9c3SStephane Eranian 470f5b4a9c3SStephane Eranian if (no_aggr) 471f5b4a9c3SStephane Eranian sprintf(cpustr, "CPU%-4d", cpumap[cpu]); 472f5b4a9c3SStephane Eranian else 473f5b4a9c3SStephane Eranian cpu = 0; 474c7f7fea3SIngo Molnar 4755af52b51SStephane Eranian if (big_num) 476f5b4a9c3SStephane Eranian fprintf(stderr, "%s %'18.0f %-24s", 477f5b4a9c3SStephane Eranian cpustr, avg, event_name(counter)); 4785af52b51SStephane Eranian else 479f5b4a9c3SStephane Eranian fprintf(stderr, "%s %18.0f %-24s", 480f5b4a9c3SStephane Eranian cpustr, avg, event_name(counter)); 48142202dd5SIngo Molnar 482506d4bc8SPeter Zijlstra if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 483f5b4a9c3SStephane Eranian total = avg_stats(&runtime_cycles_stats[cpu]); 484c7f7fea3SIngo Molnar 485c7f7fea3SIngo Molnar if (total) 486c7f7fea3SIngo Molnar ratio = avg / total; 487c7f7fea3SIngo Molnar 488c7f7fea3SIngo Molnar fprintf(stderr, " # %10.3f IPC ", ratio); 4897255fe2aSLucas De Marchi } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && 490f5b4a9c3SStephane Eranian runtime_branches_stats[cpu].n != 0) { 491f5b4a9c3SStephane Eranian total = avg_stats(&runtime_branches_stats[cpu]); 49211018201SAnton Blanchard 49311018201SAnton Blanchard if (total) 49411018201SAnton Blanchard ratio = avg * 100 / total; 49511018201SAnton Blanchard 49611018201SAnton Blanchard fprintf(stderr, " # %10.3f %% ", ratio); 49711018201SAnton Blanchard 498f5b4a9c3SStephane Eranian } else if (runtime_nsecs_stats[cpu].n != 0) { 499f5b4a9c3SStephane Eranian total = avg_stats(&runtime_nsecs_stats[cpu]); 500c7f7fea3SIngo Molnar 501c7f7fea3SIngo Molnar if (total) 502c7f7fea3SIngo Molnar ratio = 1000.0 * avg / total; 503c7f7fea3SIngo Molnar 504c7f7fea3SIngo Molnar fprintf(stderr, " # %10.3f M/sec", ratio); 50542202dd5SIngo Molnar } 50642202dd5SIngo Molnar } 50742202dd5SIngo Molnar 50842202dd5SIngo Molnar /* 50942202dd5SIngo Molnar * Print out the results of a single counter: 510f5b4a9c3SStephane Eranian * aggregated counts in system-wide mode 51142202dd5SIngo Molnar */ 512f5b4a9c3SStephane Eranian static void print_counter_aggr(int counter) 51342202dd5SIngo Molnar { 514849abde9SPeter Zijlstra double avg = avg_stats(&event_res_stats[counter][0]); 51563d40debSPeter Zijlstra int scaled = event_scaled[counter]; 51642202dd5SIngo Molnar 51742202dd5SIngo Molnar if (scaled == -1) { 5185af52b51SStephane Eranian fprintf(stderr, " %18s %-24s\n", 51942202dd5SIngo Molnar "<not counted>", event_name(counter)); 52042202dd5SIngo Molnar return; 52142202dd5SIngo Molnar } 52242202dd5SIngo Molnar 52342202dd5SIngo Molnar if (nsec_counter(counter)) 524f5b4a9c3SStephane Eranian nsec_printout(-1, counter, avg); 52542202dd5SIngo Molnar else 526f5b4a9c3SStephane Eranian abs_printout(-1, counter, avg); 527849abde9SPeter Zijlstra 528849abde9SPeter Zijlstra print_noise(counter, avg); 52942202dd5SIngo Molnar 530506d4bc8SPeter Zijlstra if (scaled) { 531506d4bc8SPeter Zijlstra double avg_enabled, avg_running; 532506d4bc8SPeter Zijlstra 533506d4bc8SPeter Zijlstra avg_enabled = avg_stats(&event_res_stats[counter][1]); 534506d4bc8SPeter Zijlstra avg_running = avg_stats(&event_res_stats[counter][2]); 535506d4bc8SPeter Zijlstra 536210ad39fSIngo Molnar fprintf(stderr, " (scaled from %.2f%%)", 537506d4bc8SPeter Zijlstra 100 * avg_running / avg_enabled); 538506d4bc8SPeter Zijlstra } 53942202dd5SIngo Molnar 54042202dd5SIngo Molnar fprintf(stderr, "\n"); 54142202dd5SIngo Molnar } 54242202dd5SIngo Molnar 543f5b4a9c3SStephane Eranian /* 544f5b4a9c3SStephane Eranian * Print out the results of a single counter: 545f5b4a9c3SStephane Eranian * does not use aggregated count in system-wide 546f5b4a9c3SStephane Eranian */ 547f5b4a9c3SStephane Eranian static void print_counter(int counter) 548f5b4a9c3SStephane Eranian { 549f5b4a9c3SStephane Eranian u64 ena, run, val; 550f5b4a9c3SStephane Eranian int cpu; 551f5b4a9c3SStephane Eranian 552f5b4a9c3SStephane Eranian for (cpu = 0; cpu < nr_cpus; cpu++) { 553f5b4a9c3SStephane Eranian val = cpu_counts[cpu][counter].val; 554f5b4a9c3SStephane Eranian ena = cpu_counts[cpu][counter].ena; 555f5b4a9c3SStephane Eranian run = cpu_counts[cpu][counter].run; 556f5b4a9c3SStephane Eranian if (run == 0 || ena == 0) { 557f5b4a9c3SStephane Eranian fprintf(stderr, "CPU%-4d %18s %-24s", cpumap[cpu], 558f5b4a9c3SStephane Eranian "<not counted>", event_name(counter)); 559f5b4a9c3SStephane Eranian 560f5b4a9c3SStephane Eranian fprintf(stderr, "\n"); 561f5b4a9c3SStephane Eranian continue; 562f5b4a9c3SStephane Eranian } 563f5b4a9c3SStephane Eranian 564f5b4a9c3SStephane Eranian if (nsec_counter(counter)) 565f5b4a9c3SStephane Eranian nsec_printout(cpu, counter, val); 566f5b4a9c3SStephane Eranian else 567f5b4a9c3SStephane Eranian abs_printout(cpu, counter, val); 568f5b4a9c3SStephane Eranian 569f5b4a9c3SStephane Eranian print_noise(counter, 1.0); 570f5b4a9c3SStephane Eranian 571f5b4a9c3SStephane Eranian if (run != ena) { 572f5b4a9c3SStephane Eranian fprintf(stderr, " (scaled from %.2f%%)", 573f5b4a9c3SStephane Eranian 100.0 * run / ena); 574f5b4a9c3SStephane Eranian } 575f5b4a9c3SStephane Eranian fprintf(stderr, "\n"); 576f5b4a9c3SStephane Eranian } 577f5b4a9c3SStephane Eranian } 578f5b4a9c3SStephane Eranian 57942202dd5SIngo Molnar static void print_stat(int argc, const char **argv) 58042202dd5SIngo Molnar { 58142202dd5SIngo Molnar int i, counter; 58242202dd5SIngo Molnar 58386470930SIngo Molnar fflush(stdout); 58486470930SIngo Molnar 58586470930SIngo Molnar fprintf(stderr, "\n"); 58660666c63SLiming Wang fprintf(stderr, " Performance counter stats for "); 587d6d901c2SZhang, Yanmin if(target_pid == -1 && target_tid == -1) { 58860666c63SLiming Wang fprintf(stderr, "\'%s", argv[0]); 58986470930SIngo Molnar for (i = 1; i < argc; i++) 59086470930SIngo Molnar fprintf(stderr, " %s", argv[i]); 591d6d901c2SZhang, Yanmin } else if (target_pid != -1) 592d6d901c2SZhang, Yanmin fprintf(stderr, "process id \'%d", target_pid); 593d6d901c2SZhang, Yanmin else 594d6d901c2SZhang, Yanmin fprintf(stderr, "thread id \'%d", target_tid); 59586470930SIngo Molnar 59642202dd5SIngo Molnar fprintf(stderr, "\'"); 59742202dd5SIngo Molnar if (run_count > 1) 59842202dd5SIngo Molnar fprintf(stderr, " (%d runs)", run_count); 59942202dd5SIngo Molnar fprintf(stderr, ":\n\n"); 60086470930SIngo Molnar 601f5b4a9c3SStephane Eranian if (no_aggr) { 60286470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) 60386470930SIngo Molnar print_counter(counter); 604f5b4a9c3SStephane Eranian } else { 605f5b4a9c3SStephane Eranian for (counter = 0; counter < nr_counters; counter++) 606f5b4a9c3SStephane Eranian print_counter_aggr(counter); 607f5b4a9c3SStephane Eranian } 60886470930SIngo Molnar 60986470930SIngo Molnar fprintf(stderr, "\n"); 6105af52b51SStephane Eranian fprintf(stderr, " %18.9f seconds time elapsed", 611506d4bc8SPeter Zijlstra avg_stats(&walltime_nsecs_stats)/1e9); 612566747e6SIngo Molnar if (run_count > 1) { 613566747e6SIngo Molnar fprintf(stderr, " ( +- %7.3f%% )", 614506d4bc8SPeter Zijlstra 100*stddev_stats(&walltime_nsecs_stats) / 615506d4bc8SPeter Zijlstra avg_stats(&walltime_nsecs_stats)); 616566747e6SIngo Molnar } 617566747e6SIngo Molnar fprintf(stderr, "\n\n"); 61886470930SIngo Molnar } 61986470930SIngo Molnar 620f7b7c26eSPeter Zijlstra static volatile int signr = -1; 621f7b7c26eSPeter Zijlstra 62286470930SIngo Molnar static void skip_signal(int signo) 62386470930SIngo Molnar { 6246be2850eSZhang, Yanmin if(child_pid == -1) 62560666c63SLiming Wang done = 1; 62660666c63SLiming Wang 627f7b7c26eSPeter Zijlstra signr = signo; 628f7b7c26eSPeter Zijlstra } 629f7b7c26eSPeter Zijlstra 630f7b7c26eSPeter Zijlstra static void sig_atexit(void) 631f7b7c26eSPeter Zijlstra { 632933da83aSChris Wilson if (child_pid != -1) 633933da83aSChris Wilson kill(child_pid, SIGTERM); 634933da83aSChris Wilson 635f7b7c26eSPeter Zijlstra if (signr == -1) 636f7b7c26eSPeter Zijlstra return; 637f7b7c26eSPeter Zijlstra 638f7b7c26eSPeter Zijlstra signal(signr, SIG_DFL); 639f7b7c26eSPeter Zijlstra kill(getpid(), signr); 64086470930SIngo Molnar } 64186470930SIngo Molnar 64286470930SIngo Molnar static const char * const stat_usage[] = { 64360666c63SLiming Wang "perf stat [<options>] [<command>]", 64486470930SIngo Molnar NULL 64586470930SIngo Molnar }; 64686470930SIngo Molnar 64786470930SIngo Molnar static const struct option options[] = { 64886470930SIngo Molnar OPT_CALLBACK('e', "event", NULL, "event", 64986470930SIngo Molnar "event selector. use 'perf list' to list available events", 65086470930SIngo Molnar parse_events), 6512e6cdf99SStephane Eranian OPT_BOOLEAN('i', "no-inherit", &no_inherit, 6522e6cdf99SStephane Eranian "child tasks do not inherit counters"), 65386470930SIngo Molnar OPT_INTEGER('p', "pid", &target_pid, 654d6d901c2SZhang, Yanmin "stat events on existing process id"), 655d6d901c2SZhang, Yanmin OPT_INTEGER('t', "tid", &target_tid, 656d6d901c2SZhang, Yanmin "stat events on existing thread id"), 65786470930SIngo Molnar OPT_BOOLEAN('a', "all-cpus", &system_wide, 65886470930SIngo Molnar "system-wide collection from all CPUs"), 659b26bc5a7SBrice Goglin OPT_BOOLEAN('c', "scale", &scale, 66086470930SIngo Molnar "scale/normalize counters"), 661c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 662743ee1f8SIngo Molnar "be more verbose (show counter open errors, etc)"), 66342202dd5SIngo Molnar OPT_INTEGER('r', "repeat", &run_count, 66442202dd5SIngo Molnar "repeat command and print average + stddev (max: 100)"), 6650cfb7a13SIngo Molnar OPT_BOOLEAN('n', "null", &null_run, 6660cfb7a13SIngo Molnar "null run - dont start any counters"), 6675af52b51SStephane Eranian OPT_BOOLEAN('B', "big-num", &big_num, 6685af52b51SStephane Eranian "print large numbers with thousands\' separators"), 669c45c6ea2SStephane Eranian OPT_STRING('C', "cpu", &cpu_list, "cpu", 670c45c6ea2SStephane Eranian "list of cpus to monitor in system-wide"), 671f5b4a9c3SStephane Eranian OPT_BOOLEAN('A', "no-aggr", &no_aggr, 672f5b4a9c3SStephane Eranian "disable CPU count aggregation"), 67386470930SIngo Molnar OPT_END() 67486470930SIngo Molnar }; 67586470930SIngo Molnar 676f37a291cSIngo Molnar int cmd_stat(int argc, const char **argv, const char *prefix __used) 67786470930SIngo Molnar { 67842202dd5SIngo Molnar int status; 679d6d901c2SZhang, Yanmin int i,j; 68042202dd5SIngo Molnar 6815af52b51SStephane Eranian setlocale(LC_ALL, ""); 6825af52b51SStephane Eranian 683a0541234SAnton Blanchard argc = parse_options(argc, argv, options, stat_usage, 684a0541234SAnton Blanchard PARSE_OPT_STOP_AT_NON_OPTION); 685d6d901c2SZhang, Yanmin if (!argc && target_pid == -1 && target_tid == -1) 68686470930SIngo Molnar usage_with_options(stat_usage, options); 6879e9772c4SPeter Zijlstra if (run_count <= 0) 68842202dd5SIngo Molnar usage_with_options(stat_usage, options); 68986470930SIngo Molnar 690f5b4a9c3SStephane Eranian /* no_aggr is for system-wide only */ 691f5b4a9c3SStephane Eranian if (no_aggr && !system_wide) 692f5b4a9c3SStephane Eranian usage_with_options(stat_usage, options); 693f5b4a9c3SStephane Eranian 694c3043569SJaswinder Singh Rajput /* Set attrs and nr_counters if no event is selected and !null_run */ 695c3043569SJaswinder Singh Rajput if (!null_run && !nr_counters) { 696c3043569SJaswinder Singh Rajput memcpy(attrs, default_attrs, sizeof(default_attrs)); 697c3043569SJaswinder Singh Rajput nr_counters = ARRAY_SIZE(default_attrs); 698c3043569SJaswinder Singh Rajput } 69986470930SIngo Molnar 700a12b51c4SPaul Mackerras if (system_wide) 701c45c6ea2SStephane Eranian nr_cpus = read_cpu_map(cpu_list); 702a12b51c4SPaul Mackerras else 703a12b51c4SPaul Mackerras nr_cpus = 1; 70486470930SIngo Molnar 705c45c6ea2SStephane Eranian if (nr_cpus < 1) 706c45c6ea2SStephane Eranian usage_with_options(stat_usage, options); 707c45c6ea2SStephane Eranian 708d6d901c2SZhang, Yanmin if (target_pid != -1) { 709d6d901c2SZhang, Yanmin target_tid = target_pid; 710d6d901c2SZhang, Yanmin thread_num = find_all_tid(target_pid, &all_tids); 711d6d901c2SZhang, Yanmin if (thread_num <= 0) { 712d6d901c2SZhang, Yanmin fprintf(stderr, "Can't find all threads of pid %d\n", 713d6d901c2SZhang, Yanmin target_pid); 714d6d901c2SZhang, Yanmin usage_with_options(stat_usage, options); 715d6d901c2SZhang, Yanmin } 716d6d901c2SZhang, Yanmin } else { 717d6d901c2SZhang, Yanmin all_tids=malloc(sizeof(pid_t)); 718d6d901c2SZhang, Yanmin if (!all_tids) 719d6d901c2SZhang, Yanmin return -ENOMEM; 720d6d901c2SZhang, Yanmin 721d6d901c2SZhang, Yanmin all_tids[0] = target_tid; 722d6d901c2SZhang, Yanmin thread_num = 1; 723d6d901c2SZhang, Yanmin } 724d6d901c2SZhang, Yanmin 725d6d901c2SZhang, Yanmin for (i = 0; i < MAX_NR_CPUS; i++) { 726d6d901c2SZhang, Yanmin for (j = 0; j < MAX_COUNTERS; j++) { 727d6d901c2SZhang, Yanmin fd[i][j] = malloc(sizeof(int)*thread_num); 728d6d901c2SZhang, Yanmin if (!fd[i][j]) 729d6d901c2SZhang, Yanmin return -ENOMEM; 730d6d901c2SZhang, Yanmin } 731d6d901c2SZhang, Yanmin } 732d6d901c2SZhang, Yanmin 73386470930SIngo Molnar /* 73486470930SIngo Molnar * We dont want to block the signals - that would cause 73586470930SIngo Molnar * child tasks to inherit that and Ctrl-C would not work. 73686470930SIngo Molnar * What we want is for Ctrl-C to work in the exec()-ed 73786470930SIngo Molnar * task, but being ignored by perf stat itself: 73886470930SIngo Molnar */ 739f7b7c26eSPeter Zijlstra atexit(sig_atexit); 74086470930SIngo Molnar signal(SIGINT, skip_signal); 74186470930SIngo Molnar signal(SIGALRM, skip_signal); 74286470930SIngo Molnar signal(SIGABRT, skip_signal); 74386470930SIngo Molnar 74442202dd5SIngo Molnar status = 0; 74542202dd5SIngo Molnar for (run_idx = 0; run_idx < run_count; run_idx++) { 74642202dd5SIngo Molnar if (run_count != 1 && verbose) 74742202dd5SIngo Molnar fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 74842202dd5SIngo Molnar status = run_perf_stat(argc, argv); 74942202dd5SIngo Molnar } 75042202dd5SIngo Molnar 751084ab9f8SArnaldo Carvalho de Melo if (status != -1) 75242202dd5SIngo Molnar print_stat(argc, argv); 75342202dd5SIngo Molnar 75442202dd5SIngo Molnar return status; 75586470930SIngo Molnar } 756