From 245bad8eb45fca36638da53fb0a361397a707001 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 1 Sep 2015 15:52:46 -0700 Subject: perf stat: Quieten failed to read counter message Since 3b3eb0445 running perf stat on a system without backend-stalled-cycles spits out ugly warnings by default. Since that is quite common, make the message a debug message only. We know anyways that the counter wasn't read by the normal output. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1441147966-14917-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index d46dbb1bc65d..a96fb5c3bedb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -215,7 +215,7 @@ static void read_counters(bool close_counters) evlist__for_each(evsel_list, counter) { if (read_counter(counter)) - pr_warning("failed to read counter %s\n", counter->name); + pr_debug("failed to read counter %s\n", counter->name); if (perf_stat_process_counter(&stat_config, counter)) pr_warning("failed to process counter %s\n", counter->name); -- cgit v1.2.3 From 19afd10410957b1c808c2c49a88e6dd8b23aa894 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 2 Oct 2015 05:04:34 -0400 Subject: perf stat: Reduce min --interval-print to 10ms The --interval-print parameter was limited to 100ms. However, for example, 10ms is required to do sophisticated bandwidth analysis using uncore events. The test shows that the overhead of the system-wide uncore monitoring with 10ms interval is only ~2%. So this patch reduces the minimal interval-print allowd to 10ms. But 10ms may not work well for all cases. For example, when the cpus/threads number is very large, for system-wide core event monitoring the overhead could be high. To handle this issue, a warning will be displayed when the interval-print is set between 10ms to 100ms. So users can make a decision according to their specific cases. # perf stat -e uncore_imc_1/cas_count_read/ -a --interval-print 10 -- sleep 1 print interval < 100ms. The overhead percentage could be high in some cases. Please proceed with caution. # time counts unit events 0.010200451 0.10 MiB uncore_imc_1/cas_count_read/ 0.020475117 0.02 MiB uncore_imc_1/cas_count_read/ 0.030692800 0.01 MiB uncore_imc_1/cas_count_read/ 0.040948161 0.02 MiB uncore_imc_1/cas_count_read/ 0.051159564 0.00 MiB uncore_imc_1/cas_count_read/ Signed-off-by: Kan Liang Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1443776674-42511-1-git-send-email-kan.liang@intel.com [ Added warning about overhead when using sub 100ms intervals to the man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 5 +++-- tools/perf/builtin-stat.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 47469abdcc1c..4e074a660826 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -128,8 +128,9 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m -I msecs:: --interval-print msecs:: - Print count deltas every N milliseconds (minimum: 100ms) - example: perf stat -I 1000 -e cycles -a sleep 5 +Print count deltas every N milliseconds (minimum: 10ms) +The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution. + example: 'perf stat -I 1000 -e cycles -a sleep 5' --per-socket:: Aggregate counts per processor socket for system-wide mode measurements. This diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a96fb5c3bedb..5ef88f760b12 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1179,7 +1179,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) OPT_STRING(0, "post", &post_cmd, "command", "command to run after to the measured command"), OPT_UINTEGER('I', "interval-print", &stat_config.interval, - "print counts at regular interval in ms (>= 100)"), + "print counts at regular interval in ms (>= 10)"), OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, "aggregate counts per processor socket", AGGR_SOCKET), OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, @@ -1332,9 +1332,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) thread_map__read_comms(evsel_list->threads); if (interval && interval < 100) { - pr_err("print interval must be >= 100ms\n"); - parse_options_usage(stat_usage, options, "I", 1); - goto out; + if (interval < 10) { + pr_err("print interval must be >= 10ms\n"); + parse_options_usage(stat_usage, options, "I", 1); + goto out; + } else + pr_warning("print interval < 100ms. " + "The overhead percentage could be high in some cases. " + "Please proceed with caution.\n"); } if (perf_evlist__alloc_stats(evsel_list, interval)) -- cgit v1.2.3 From 581cc8a2a2a00afc864840720186b0f6a38079d9 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:03 +0200 Subject: perf stat: Rename perf_stat struct into perf_stat_evsel It's used as the perf_evsel::priv data, so the name suits better. Also we'll need the perf_stat name free for more generic struct. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-29-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 4 ++-- tools/perf/util/stat.c | 10 +++++----- tools/perf/util/stat.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5ef88f760b12..184057295970 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -434,7 +434,7 @@ static void print_noise_pct(double total, double avg) static void print_noise(struct perf_evsel *evsel, double avg) { - struct perf_stat *ps; + struct perf_stat_evsel *ps; if (run_count == 1) return; @@ -671,7 +671,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix) static void print_counter_aggr(struct perf_evsel *counter, char *prefix) { FILE *output = stat_config.output; - struct perf_stat *ps = counter->priv; + struct perf_stat_evsel *ps = counter->priv; double avg = avg_stats(&ps->res_stats[0]); int scaled = counter->counts->scaled; double uval; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 2d065d065b67..93e6d697e574 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -67,7 +67,7 @@ double rel_stddev_stats(double stddev, double avg) bool __perf_evsel_stat__is(struct perf_evsel *evsel, enum perf_stat_evsel_id id) { - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; return ps->id == id; } @@ -84,7 +84,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { void perf_stat_evsel_id_init(struct perf_evsel *evsel) { - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; int i; /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */ @@ -100,7 +100,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) { int i; - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; for (i = 0; i < 3; i++) init_stats(&ps->res_stats[i]); @@ -110,7 +110,7 @@ void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) { - evsel->priv = zalloc(sizeof(struct perf_stat)); + evsel->priv = zalloc(sizeof(struct perf_stat_evsel)); if (evsel->priv == NULL) return -ENOMEM; perf_evsel__reset_stat_priv(evsel); @@ -304,7 +304,7 @@ int perf_stat_process_counter(struct perf_stat_config *config, struct perf_evsel *counter) { struct perf_counts_values *aggr = &counter->counts->aggr; - struct perf_stat *ps = counter->priv; + struct perf_stat_evsel *ps = counter->priv; u64 *count = counter->counts->aggr.values; int i, ret; diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 62448c8175d3..f8d9d5ce24a9 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -20,7 +20,7 @@ enum perf_stat_evsel_id { PERF_STAT_EVSEL_ID__MAX, }; -struct perf_stat { +struct perf_stat_evsel { struct stats res_stats[3]; enum perf_stat_evsel_id id; }; -- cgit v1.2.3 From 208df99ed07ca5e86ee41617e0384930fc9ca819 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:04 +0200 Subject: perf stat: Add AGGR_UNSET mode Adding AGGR_UNSET mode, so we could distinguish unset aggr_mode in following patches. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-30-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 5 +++++ tools/perf/util/stat.c | 1 + tools/perf/util/stat.h | 1 + 3 files changed, 7 insertions(+) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 184057295970..abeb15aebd12 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -479,6 +479,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) csv_sep); break; case AGGR_GLOBAL: + case AGGR_UNSET: default: break; } @@ -799,6 +800,8 @@ static void print_interval(char *prefix, struct timespec *ts) case AGGR_GLOBAL: default: fprintf(output, "# time counts %*s events\n", unit_width, "unit"); + case AGGR_UNSET: + break; } } @@ -880,6 +883,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) evlist__for_each(evsel_list, counter) print_counter(counter, prefix); break; + case AGGR_UNSET: default: break; } @@ -960,6 +964,7 @@ static int perf_stat_init_aggr_mode(void) case AGGR_NONE: case AGGR_GLOBAL: case AGGR_THREAD: + case AGGR_UNSET: default: break; } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 93e6d697e574..837374181ec7 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -272,6 +272,7 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel aggr->ena += count->ena; aggr->run += count->run; } + case AGGR_UNSET: default: break; } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index f8d9d5ce24a9..da1d11c4f8c1 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -31,6 +31,7 @@ enum aggr_mode { AGGR_SOCKET, AGGR_CORE, AGGR_THREAD, + AGGR_UNSET, }; struct perf_stat_config { -- cgit v1.2.3 From 1fe7a30028eeccd92e6fccfbeb8c5c3811b11b64 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:15 +0200 Subject: perf cpu_map: Add data arg to cpu_map__build_map callback Adding data arg to cpu_map__build_map callback, so we could pass data along to the callback. It'll be needed in following patches to retrieve topology info from perf.data. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-41-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 14 ++++++++++++-- tools/perf/tests/topology.c | 4 ++-- tools/perf/util/cpumap.c | 15 ++++++++------- tools/perf/util/cpumap.h | 7 ++++--- tools/perf/util/stat.c | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index abeb15aebd12..91e793a76929 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -944,6 +944,16 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } +static int perf_stat__get_socket(struct cpu_map *map, int cpu) +{ + return cpu_map__get_socket(map, cpu, NULL); +} + +static int perf_stat__get_core(struct cpu_map *map, int cpu) +{ + return cpu_map__get_core(map, cpu, NULL); +} + static int perf_stat_init_aggr_mode(void) { switch (stat_config.aggr_mode) { @@ -952,14 +962,14 @@ static int perf_stat_init_aggr_mode(void) perror("cannot build socket map"); return -1; } - aggr_get_id = cpu_map__get_socket; + aggr_get_id = perf_stat__get_socket; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = cpu_map__get_core; + aggr_get_id = perf_stat__get_core; break; case AGGR_NONE: case AGGR_GLOBAL: diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index c3aff53a976a..f5bb096c3bd9 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -73,10 +73,10 @@ static int check_cpu_topology(char *path, struct cpu_map *map) for (i = 0; i < map->nr; i++) { TEST_ASSERT_VAL("Core ID doesn't match", - (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i) & 0xffff))); + (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i, NULL) & 0xffff))); TEST_ASSERT_VAL("Socket ID doesn't match", - (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i))); + (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i, NULL))); } perf_session__delete(session); diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 70ec8d031f9d..b36845347f01 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -241,7 +241,7 @@ int cpu_map__get_socket_id(int cpu) return ret ?: value; } -int cpu_map__get_socket(struct cpu_map *map, int idx) +int cpu_map__get_socket(struct cpu_map *map, int idx, void *data __maybe_unused) { int cpu; @@ -259,7 +259,8 @@ static int cmp_ids(const void *a, const void *b) } int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu)) + int (*f)(struct cpu_map *map, int cpu, void *data), + void *data) { struct cpu_map *c; int nr = cpus->nr; @@ -271,7 +272,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, return -1; for (cpu = 0; cpu < nr; cpu++) { - s1 = f(cpus, cpu); + s1 = f(cpus, cpu, data); for (s2 = 0; s2 < c->nr; s2++) { if (s1 == c->map[s2]) break; @@ -295,7 +296,7 @@ int cpu_map__get_core_id(int cpu) return ret ?: value; } -int cpu_map__get_core(struct cpu_map *map, int idx) +int cpu_map__get_core(struct cpu_map *map, int idx, void *data) { int cpu, s; @@ -306,7 +307,7 @@ int cpu_map__get_core(struct cpu_map *map, int idx) cpu = cpu_map__get_core_id(cpu); - s = cpu_map__get_socket(map, idx); + s = cpu_map__get_socket(map, idx, data); if (s == -1) return -1; @@ -321,12 +322,12 @@ int cpu_map__get_core(struct cpu_map *map, int idx) int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) { - return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); + return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); } int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) { - return cpu_map__build_map(cpus, corep, cpu_map__get_core); + return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); } /* setup simple routines to easily access node numbers given a cpu number */ diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 6e36fc35eca6..f1bcd2cfa164 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -19,9 +19,9 @@ struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); -int cpu_map__get_socket(struct cpu_map *map, int idx); +int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); int cpu_map__get_core_id(int cpu); -int cpu_map__get_core(struct cpu_map *map, int idx); +int cpu_map__get_core(struct cpu_map *map, int idx, void *data); int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); @@ -88,5 +88,6 @@ static inline int cpu__get_node(int cpu) } int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu)); + int (*f)(struct cpu_map *map, int cpu, void *data), + void *data); #endif /* __PERF_CPUMAP_H */ diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 837374181ec7..2d9d8306dbd3 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -230,7 +230,7 @@ static int check_per_pkg(struct perf_evsel *counter, if (!(vals->run && vals->ena)) return 0; - s = cpu_map__get_socket(cpus, cpu); + s = cpu_map__get_socket(cpus, cpu, NULL); if (s < 0) return -1; -- cgit v1.2.3 From 1e5a29318ba8506f52a8d727b5c6a53143f9882a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 25 Oct 2015 15:51:18 +0100 Subject: perf stat: Cache aggregated map entries in extra cpumap Currently any time we need to access socket or core id for given cpu, we access the sysfs topology file. Adding a cpus_aggr_map cpu_map to cache those entries. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445784728-21732-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 59 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'tools/perf/builtin-stat.c') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 91e793a76929..2f438f76cceb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -100,6 +100,8 @@ static struct target target = { .uid = UINT_MAX, }; +typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; -static int (*aggr_get_id)(struct cpu_map *m, int cpu); +static aggr_get_id_t aggr_get_id; static volatile int done = 0; @@ -954,22 +956,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu) return cpu_map__get_core(map, cpu, NULL); } +static int cpu_map__get_max(struct cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} + +static struct cpu_map *cpus_aggr_map; + +static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx >= map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpus_aggr_map->map[cpu] == -1) + cpus_aggr_map->map[cpu] = get_id(map, idx); + + return cpus_aggr_map->map[cpu]; +} + +static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_socket, map, idx); +} + +static int perf_stat__get_core_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_core, map, idx); +} + static int perf_stat_init_aggr_mode(void) { + int nr; + switch (stat_config.aggr_mode) { case AGGR_SOCKET: if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { perror("cannot build socket map"); return -1; } - aggr_get_id = perf_stat__get_socket; + aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = perf_stat__get_core; + aggr_get_id = perf_stat__get_core_cached; break; case AGGR_NONE: case AGGR_GLOBAL: @@ -978,7 +1021,15 @@ static int perf_stat_init_aggr_mode(void) default: break; } - return 0; + + /* + * The evsel_list->cpus is the base we operate on, + * taking the highest cpu number to be the size of + * the aggregation translate cpumap. + */ + nr = cpu_map__get_max(evsel_list->cpus); + cpus_aggr_map = cpu_map__empty_new(nr + 1); + return cpus_aggr_map ? 0 : -ENOMEM; } /* -- cgit v1.2.3