diff options
Diffstat (limited to 'tools/perf/builtin-stat.c')
| -rw-r--r-- | tools/perf/builtin-stat.c | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3e80aa10cfd8..891086376381 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -43,6 +43,7 @@ #include "perf.h" #include "builtin.h" +#include "util/cgroup.h" #include "util/util.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -387,20 +388,102 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_itlb_cache_stats[0], count[0]); } +static void zero_per_pkg(struct perf_evsel *counter) +{ + if (counter->per_pkg_mask) + memset(counter->per_pkg_mask, 0, MAX_NR_CPUS); +} + +static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip) +{ + unsigned long *mask = counter->per_pkg_mask; + struct cpu_map *cpus = perf_evsel__cpus(counter); + int s; + + *skip = false; + + if (!counter->per_pkg) + return 0; + + if (cpu_map__empty(cpus)) + return 0; + + if (!mask) { + mask = zalloc(MAX_NR_CPUS); + if (!mask) + return -ENOMEM; + + counter->per_pkg_mask = mask; + } + + s = cpu_map__get_socket(cpus, cpu); + if (s < 0) + return -1; + + *skip = test_and_set_bit(s, mask) == 1; + return 0; +} + +static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused, + struct perf_counts_values *count) +{ + struct perf_counts_values *aggr = &evsel->counts->aggr; + static struct perf_counts_values zero; + bool skip = false; + + if (check_per_pkg(evsel, cpu, &skip)) { + pr_err("failed to read per-pkg counter\n"); + return -1; + } + + if (skip) + count = &zero; + + switch (aggr_mode) { + case AGGR_CORE: + case AGGR_SOCKET: + case AGGR_NONE: + if (!evsel->snapshot) + perf_evsel__compute_deltas(evsel, cpu, count); + perf_counts_values__scale(count, scale, NULL); + evsel->counts->cpu[cpu] = *count; + update_shadow_stats(evsel, count->values); + break; + case AGGR_GLOBAL: + aggr->val += count->val; + if (scale) { + aggr->ena += count->ena; + aggr->run += count->run; + } + default: + break; + } + + return 0; +} + +static int read_counter(struct perf_evsel *counter); + /* * Read out the results of a single counter: * aggregate counts across CPUs in system-wide mode */ static int read_counter_aggr(struct perf_evsel *counter) { + struct perf_counts_values *aggr = &counter->counts->aggr; struct perf_stat *ps = counter->priv; u64 *count = counter->counts->aggr.values; int i; - if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), - thread_map__nr(evsel_list->threads), scale) < 0) + aggr->val = aggr->ena = aggr->run = 0; + + if (read_counter(counter)) return -1; + if (!counter->snapshot) + perf_evsel__compute_deltas(counter, -1, aggr); + perf_counts_values__scale(aggr, scale, &counter->counts->scaled); + for (i = 0; i < 3; i++) update_stats(&ps->res_stats[i], count[i]); @@ -423,16 +506,21 @@ static int read_counter_aggr(struct perf_evsel *counter) */ static int read_counter(struct perf_evsel *counter) { - u64 *count; - int cpu; + int nthreads = thread_map__nr(evsel_list->threads); + int ncpus = perf_evsel__nr_cpus(counter); + int cpu, thread; - for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { - if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) - return -1; + if (counter->system_wide) + nthreads = 1; - count = counter->counts->cpu[cpu].values; + if (counter->per_pkg) + zero_per_pkg(counter); - update_shadow_stats(counter, count); + for (thread = 0; thread < nthreads; thread++) { + for (cpu = 0; cpu < ncpus; cpu++) { + if (perf_evsel__read_cb(counter, cpu, thread, read_cb)) + return -1; + } } return 0; @@ -593,7 +681,7 @@ static int __run_perf_stat(int argc, const char **argv) if (perf_evlist__apply_filters(evsel_list)) { error("failed to set filter with %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, msg, sizeof(msg))); return -1; } @@ -732,7 +820,7 @@ 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) +static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) { double msecs = avg / 1e6; const char *fmt_v, *fmt_n; @@ -741,7 +829,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; fmt_n = csv_output ? "%s" : "%-25s"; - aggr_printout(evsel, cpu, nr); + aggr_printout(evsel, id, nr); scnprintf(name, sizeof(name), "%s%s", perf_evsel__name(evsel), csv_output ? "" : " (msec)"); @@ -947,11 +1035,12 @@ static void print_ll_cache_misses(int cpu, fprintf(output, " of all LL-cache hits "); } -static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) +static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0, total2; double sc = evsel->scale; const char *fmt; + int cpu = cpu_map__id_to_cpu(id); if (csv_output) { fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; @@ -962,7 +1051,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; } - aggr_printout(evsel, cpu, nr); + aggr_printout(evsel, id, nr); if (aggr_mode == AGGR_GLOBAL) cpu = 0; |
