]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-stat.c
perf evlist: Move destruction of maps to evlist destructor
[~andy/linux] / tools / perf / builtin-stat.c
index ee0d565f83e300f57d21d465a9f65180f5a74618..6ca076660de5f38a282a196225e37b1e1d4ffbd0 100644 (file)
@@ -138,6 +138,7 @@ static const char           *post_cmd                       = NULL;
 static bool                    sync_run                        = false;
 static unsigned int            interval                        = 0;
 static unsigned int            initial_delay                   = 0;
+static unsigned int            unit_width                      = 4; /* strlen("unit") */
 static bool                    forever                         = false;
 static struct timespec         ref_time;
 static struct cpu_map          *aggr_map;
@@ -184,8 +185,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
 
 static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
 {
-       free(evsel->priv);
-       evsel->priv = NULL;
+       zfree(&evsel->priv);
 }
 
 static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
@@ -207,8 +207,7 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
 
 static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
 {
-       free(evsel->prev_raw_counts);
-       evsel->prev_raw_counts = NULL;
+       zfree(&evsel->prev_raw_counts);
 }
 
 static void perf_evlist__free_stats(struct perf_evlist *evlist)
@@ -461,17 +460,17 @@ static void print_interval(void)
        if (num_print_interval == 0 && !csv_output) {
                switch (aggr_mode) {
                case AGGR_SOCKET:
-                       fprintf(output, "#           time socket cpus             counts events\n");
+                       fprintf(output, "#           time socket cpus             counts %*s events\n", unit_width, "unit");
                        break;
                case AGGR_CORE:
-                       fprintf(output, "#           time core         cpus             counts events\n");
+                       fprintf(output, "#           time core         cpus             counts %*s events\n", unit_width, "unit");
                        break;
                case AGGR_NONE:
-                       fprintf(output, "#           time CPU                 counts events\n");
+                       fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
                        break;
                case AGGR_GLOBAL:
                default:
-                       fprintf(output, "#           time             counts events\n");
+                       fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
                }
        }
 
@@ -510,12 +509,26 @@ static void handle_initial_delay(void)
        }
 }
 
+static volatile int workload_exec_errno;
+
+/*
+ * perf_evlist__prepare_workload will send a SIGUSR1
+ * if the fork fails, since we asked by setting its
+ * want_signal to true.
+ */
+static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info,
+                                       void *ucontext __maybe_unused)
+{
+       workload_exec_errno = info->si_value.sival_int;
+}
+
 static int __run_perf_stat(int argc, const char **argv)
 {
        char msg[512];
        unsigned long long t0, t1;
        struct perf_evsel *counter;
        struct timespec ts;
+       size_t l;
        int status = 0;
        const bool forks = (argc > 0);
 
@@ -528,8 +541,8 @@ static int __run_perf_stat(int argc, const char **argv)
        }
 
        if (forks) {
-               if (perf_evlist__prepare_workload(evsel_list, &target, argv,
-                                                 false, false) < 0) {
+               if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
+                                                 workload_exec_failed_signal) < 0) {
                        perror("failed to prepare workload");
                        return -1;
                }
@@ -565,6 +578,10 @@ static int __run_perf_stat(int argc, const char **argv)
                        return -1;
                }
                counter->supported = true;
+
+               l = strlen(counter->unit);
+               if (l > unit_width)
+                       unit_width = l;
        }
 
        if (perf_evlist__apply_filters(evsel_list)) {
@@ -590,6 +607,13 @@ static int __run_perf_stat(int argc, const char **argv)
                        }
                }
                wait(&status);
+
+               if (workload_exec_errno) {
+                       const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
+                       pr_err("Workload failed: %s\n", emsg);
+                       return -1;
+               }
+
                if (WIFSIGNALED(status))
                        psignal(WTERMSIG(status), argv[0]);
        } else {
@@ -704,14 +728,25 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
 static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 {
        double msecs = avg / 1e6;
-       const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
+       const char *fmt_v, *fmt_n;
        char name[25];
 
+       fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
+       fmt_n = csv_output ? "%s" : "%-25s";
+
        aggr_printout(evsel, cpu, nr);
 
        scnprintf(name, sizeof(name), "%s%s",
                  perf_evsel__name(evsel), csv_output ? "" : " (msec)");
-       fprintf(output, fmt, msecs, csv_sep, name);
+
+       fprintf(output, fmt_v, msecs, csv_sep);
+
+       if (csv_output)
+               fprintf(output, "%s%s", evsel->unit, csv_sep);
+       else
+               fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep);
+
+       fprintf(output, fmt_n, name);
 
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,21 +943,31 @@ static void print_ll_cache_misses(int cpu,
 static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 {
        double total, ratio = 0.0, total2;
+       double sc =  evsel->scale;
        const char *fmt;
 
-       if (csv_output)
-               fmt = "%.0f%s%s";
-       else if (big_num)
-               fmt = "%'18.0f%s%-25s";
-       else
-               fmt = "%18.0f%s%-25s";
+       if (csv_output) {
+               fmt = sc != 1.0 ?  "%.2f%s" : "%.0f%s";
+       } else {
+               if (big_num)
+                       fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s";
+               else
+                       fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
+       }
 
        aggr_printout(evsel, cpu, nr);
 
        if (aggr_mode == AGGR_GLOBAL)
                cpu = 0;
 
-       fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel));
+       fprintf(output, fmt, avg, csv_sep);
+
+       if (evsel->unit)
+               fprintf(output, "%-*s%s",
+                       csv_output ? 0 : unit_width,
+                       evsel->unit, csv_sep);
+
+       fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel));
 
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -941,7 +986,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 
                if (total && avg) {
                        ratio = total / avg;
-                       fprintf(output, "\n                                             #   %5.2f  stalled cycles per insn", ratio);
+                       fprintf(output, "\n");
+                       if (aggr_mode == AGGR_NONE)
+                               fprintf(output, "        ");
+                       fprintf(output, "                                                  #   %5.2f  stalled cycles per insn", ratio);
                }
 
        } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -1061,6 +1109,7 @@ static void print_aggr(char *prefix)
 {
        struct perf_evsel *counter;
        int cpu, cpu2, s, s2, id, nr;
+       double uval;
        u64 ena, run, val;
 
        if (!(aggr_map || aggr_get_id))
@@ -1087,11 +1136,17 @@ static void print_aggr(char *prefix)
                        if (run == 0 || ena == 0) {
                                aggr_printout(counter, id, nr);
 
-                               fprintf(output, "%*s%s%*s",
+                               fprintf(output, "%*s%s",
                                        csv_output ? 0 : 18,
                                        counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
-                                       csv_sep,
-                                       csv_output ? 0 : -24,
+                                       csv_sep);
+
+                               fprintf(output, "%-*s%s",
+                                       csv_output ? 0 : unit_width,
+                                       counter->unit, csv_sep);
+
+                               fprintf(output, "%*s",
+                                       csv_output ? 0 : -25,
                                        perf_evsel__name(counter));
 
                                if (counter->cgrp)
@@ -1101,11 +1156,12 @@ static void print_aggr(char *prefix)
                                fputc('\n', output);
                                continue;
                        }
+                       uval = val * counter->scale;
 
                        if (nsec_counter(counter))
-                               nsec_printout(id, nr, counter, val);
+                               nsec_printout(id, nr, counter, uval);
                        else
-                               abs_printout(id, nr, counter, val);
+                               abs_printout(id, nr, counter, uval);
 
                        if (!csv_output) {
                                print_noise(counter, 1.0);
@@ -1128,16 +1184,21 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
        struct perf_stat *ps = counter->priv;
        double avg = avg_stats(&ps->res_stats[0]);
        int scaled = counter->counts->scaled;
+       double uval;
 
        if (prefix)
                fprintf(output, "%s", prefix);
 
        if (scaled == -1) {
-               fprintf(output, "%*s%s%*s",
+               fprintf(output, "%*s%s",
                        csv_output ? 0 : 18,
                        counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
-                       csv_sep,
-                       csv_output ? 0 : -24,
+                       csv_sep);
+               fprintf(output, "%-*s%s",
+                       csv_output ? 0 : unit_width,
+                       counter->unit, csv_sep);
+               fprintf(output, "%*s",
+                       csv_output ? 0 : -25,
                        perf_evsel__name(counter));
 
                if (counter->cgrp)
@@ -1147,10 +1208,12 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
                return;
        }
 
+       uval = avg * counter->scale;
+
        if (nsec_counter(counter))
-               nsec_printout(-1, 0, counter, avg);
+               nsec_printout(-1, 0, counter, uval);
        else
-               abs_printout(-1, 0, counter, avg);
+               abs_printout(-1, 0, counter, uval);
 
        print_noise(counter, avg);
 
@@ -1177,6 +1240,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
 static void print_counter(struct perf_evsel *counter, char *prefix)
 {
        u64 ena, run, val;
+       double uval;
        int cpu;
 
        for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1188,14 +1252,20 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
                        fprintf(output, "%s", prefix);
 
                if (run == 0 || ena == 0) {
-                       fprintf(output, "CPU%*d%s%*s%s%*s",
+                       fprintf(output, "CPU%*d%s%*s%s",
                                csv_output ? 0 : -4,
                                perf_evsel__cpus(counter)->map[cpu], csv_sep,
                                csv_output ? 0 : 18,
                                counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
-                               csv_sep,
-                               csv_output ? 0 : -24,
-                               perf_evsel__name(counter));
+                               csv_sep);
+
+                               fprintf(output, "%-*s%s",
+                                       csv_output ? 0 : unit_width,
+                                       counter->unit, csv_sep);
+
+                               fprintf(output, "%*s",
+                                       csv_output ? 0 : -25,
+                                       perf_evsel__name(counter));
 
                        if (counter->cgrp)
                                fprintf(output, "%s%s",
@@ -1205,10 +1275,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
                        continue;
                }
 
+               uval = val * counter->scale;
+
                if (nsec_counter(counter))
-                       nsec_printout(cpu, 0, counter, val);
+                       nsec_printout(cpu, 0, counter, uval);
                else
-                       abs_printout(cpu, 0, counter, val);
+                       abs_printout(cpu, 0, counter, uval);
 
                if (!csv_output) {
                        print_noise(counter, 1.0);
@@ -1710,14 +1782,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
        if (interval && interval < 100) {
                pr_err("print interval must be >= 100ms\n");
                parse_options_usage(stat_usage, options, "I", 1);
-               goto out_free_maps;
+               goto out;
        }
 
        if (perf_evlist__alloc_stats(evsel_list, interval))
-               goto out_free_maps;
+               goto out;
 
        if (perf_stat_init_aggr_mode())
-               goto out_free_maps;
+               goto out;
 
        /*
         * We dont want to block the signals - that would cause
@@ -1749,8 +1821,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                print_stat(argc, argv);
 
        perf_evlist__free_stats(evsel_list);
-out_free_maps:
-       perf_evlist__delete_maps(evsel_list);
 out:
        perf_evlist__delete(evsel_list);
        return status;