From 36d19bbbdf9310699603203b332d69dc32c971d0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:00 -0800 Subject: perf pmu-events: Remove aggr_mode from pmu_event aggr_mode is used on Power to set a flag for metrics. For pmu_event it is unused. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu-events.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index accf44b3d968..9b4c94ba5460 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -331,12 +331,6 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event return -1; } - if (!is_same(e1->aggr_mode, e2->aggr_mode)) { - pr_debug2("testing event e1 %s: mismatched aggr_mode, %s vs %s\n", - e1->name, e1->aggr_mode, e2->aggr_mode); - return -1; - } - if (!is_same(e1->deprecated, e2->deprecated)) { pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", e1->name, e1->deprecated, e2->deprecated); -- cgit v1.2.3 From 9ed8b7dcb0e7816294b2f8d8ab907e8c5402008d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:02 -0800 Subject: perf pmu-events: Change deprecated to be a bool Switch to a more natural bool rather than string encoding, where NULL implicitly meant false. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jevents.py | 2 +- tools/perf/pmu-events/pmu-events.h | 4 +++- tools/perf/tests/pmu-events.c | 4 ++-- tools/perf/util/pmu.c | 10 ++++------ 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 2b08d7c18f4b..35ca34eca74a 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -678,7 +678,7 @@ static void decompress_event(int offset, struct pmu_event *pe) { \tconst char *p = &big_c_string[offset]; """) - enum_attributes = ['aggr_mode'] + enum_attributes = ['aggr_mode', 'deprecated'] for attr in _json_event_attributes: _args.output_file.write(f'\n\tpe->{attr} = ') if attr in enum_attributes: diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h index 7225efc4e4df..2434bc7cf92d 100644 --- a/tools/perf/pmu-events/pmu-events.h +++ b/tools/perf/pmu-events/pmu-events.h @@ -2,6 +2,8 @@ #ifndef PMU_EVENTS_H #define PMU_EVENTS_H +#include + struct perf_pmu; enum aggr_mode_class { @@ -22,7 +24,7 @@ struct pmu_event { const char *pmu; const char *unit; const char *perpkg; - const char *deprecated; + bool deprecated; }; struct pmu_metric { diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 9b4c94ba5460..937804c84e29 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -331,8 +331,8 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event return -1; } - if (!is_same(e1->deprecated, e2->deprecated)) { - pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", + if (e1->deprecated != e2->deprecated) { + pr_debug2("testing event e1 %s: mismatched deprecated, %d vs %d\n", e1->name, e1->deprecated, e2->deprecated); return -1; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index c256b29defad..80644e25a568 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -331,14 +331,15 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, int num; char newval[256]; char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL, - *deprecated = NULL, *pmu_name = NULL; + *pmu_name = NULL; + bool deprecated = false; if (pe) { long_desc = (char *)pe->long_desc; topic = (char *)pe->topic; unit = (char *)pe->unit; perpkg = (char *)pe->perpkg; - deprecated = (char *)pe->deprecated; + deprecated = pe->deprecated; pmu_name = (char *)pe->pmu; } @@ -351,7 +352,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, alias->unit[0] = '\0'; alias->per_pkg = false; alias->snapshot = false; - alias->deprecated = false; + alias->deprecated = deprecated; ret = parse_events_terms(&alias->terms, val); if (ret) { @@ -405,9 +406,6 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, alias->str = strdup(newval); alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; - if (deprecated) - alias->deprecated = true; - if (!perf_pmu_merge_alias(alias, list)) list_add_tail(&alias->list, list); -- cgit v1.2.3 From bd6808618ceb7d5bb4d5488afc030b48ae612f63 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:03 -0800 Subject: perf pmu-events: Change perpkg to be a bool Switch to a more natural bool rather than string encoding, where NULL implicitly meant false. The only value of 'PerPkg' in the event json is '1'. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jevents.py | 2 +- tools/perf/pmu-events/pmu-events.h | 2 +- tools/perf/tests/pmu-events.c | 4 ++-- tools/perf/util/pmu.c | 11 ++++------- 4 files changed, 8 insertions(+), 11 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 35ca34eca74a..2da55408398f 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -678,7 +678,7 @@ static void decompress_event(int offset, struct pmu_event *pe) { \tconst char *p = &big_c_string[offset]; """) - enum_attributes = ['aggr_mode', 'deprecated'] + enum_attributes = ['aggr_mode', 'deprecated', 'perpkg'] for attr in _json_event_attributes: _args.output_file.write(f'\n\tpe->{attr} = ') if attr in enum_attributes: diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h index 2434bc7cf92d..4d236bb32fd3 100644 --- a/tools/perf/pmu-events/pmu-events.h +++ b/tools/perf/pmu-events/pmu-events.h @@ -23,7 +23,7 @@ struct pmu_event { const char *long_desc; const char *pmu; const char *unit; - const char *perpkg; + bool perpkg; bool deprecated; }; diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 937804c84e29..521557c396bc 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -325,8 +325,8 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event return -1; } - if (!is_same(e1->perpkg, e2->perpkg)) { - pr_debug2("testing event e1 %s: mismatched perpkg, %s vs %s\n", + if (e1->perpkg != e2->perpkg) { + pr_debug2("testing event e1 %s: mismatched perpkg, %d vs %d\n", e1->name, e1->perpkg, e2->perpkg); return -1; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 80644e25a568..43b6182d96b7 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -328,17 +328,15 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, struct parse_events_term *term; struct perf_pmu_alias *alias; int ret; - int num; char newval[256]; - char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL, - *pmu_name = NULL; - bool deprecated = false; + char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL; + bool deprecated = false, perpkg = false; if (pe) { long_desc = (char *)pe->long_desc; topic = (char *)pe->topic; unit = (char *)pe->unit; - perpkg = (char *)pe->perpkg; + perpkg = pe->perpkg; deprecated = pe->deprecated; pmu_name = (char *)pe->pmu; } @@ -350,7 +348,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, INIT_LIST_HEAD(&alias->terms); alias->scale = 1.0; alias->unit[0] = '\0'; - alias->per_pkg = false; + alias->per_pkg = perpkg; alias->snapshot = false; alias->deprecated = deprecated; @@ -402,7 +400,6 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, return -1; snprintf(alias->unit, sizeof(alias->unit), "%s", unit); } - alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; alias->str = strdup(newval); alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; -- cgit v1.2.3 From 207f7df7271c346da4a421c5b8cdadda99a37964 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:04 -0800 Subject: perf expr: Make the online topology accessible globally Knowing the topology of online CPUs is useful for more than just expr literals. Move to a global function that caches the value. An additional upside is that this may also avoid computing the CPU topology in some situations. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 7 ++----- tools/perf/util/cputopo.c | 14 ++++++++++++++ tools/perf/util/cputopo.h | 5 +++++ tools/perf/util/expr.c | 16 ++++++---------- tools/perf/util/smt.c | 11 +++++------ tools/perf/util/smt.h | 12 ++++++------ 6 files changed, 38 insertions(+), 27 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index a9eb1ed6bd63..cbf0e0c74906 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -154,13 +154,10 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u /* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */ { - struct cpu_topology *topology = cpu_topology__new(); - bool smton = smt_on(topology); + bool smton = smt_on(); bool corewide = core_wide(/*system_wide=*/false, - /*user_requested_cpus=*/false, - topology); + /*user_requested_cpus=*/false); - cpu_topology__delete(topology); expr__ctx_clear(ctx); TEST_ASSERT_VAL("find ids", expr__find_ids("EVENT1 if #smt_on else EVENT2", diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c index e08797c3cdbc..ca1d833a0c26 100644 --- a/tools/perf/util/cputopo.c +++ b/tools/perf/util/cputopo.c @@ -238,6 +238,20 @@ static bool has_die_topology(void) return true; } +const struct cpu_topology *online_topology(void) +{ + static const struct cpu_topology *topology; + + if (!topology) { + topology = cpu_topology__new(); + if (!topology) { + pr_err("Error creating CPU topology"); + abort(); + } + } + return topology; +} + struct cpu_topology *cpu_topology__new(void) { struct cpu_topology *tp = NULL; diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h index 969e5920a00e..8d42f6102954 100644 --- a/tools/perf/util/cputopo.h +++ b/tools/perf/util/cputopo.h @@ -56,6 +56,11 @@ struct hybrid_topology { struct hybrid_topology_node nodes[]; }; +/* + * The topology for online CPUs, lazily created. + */ +const struct cpu_topology *online_topology(void); + struct cpu_topology *cpu_topology__new(void); void cpu_topology__delete(struct cpu_topology *tp); /* Determine from the core list whether SMT was enabled. */ diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index c1da20b868db..d46a1878bc9e 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -402,7 +402,7 @@ double arch_get_tsc_freq(void) double expr__get_literal(const char *literal, const struct expr_scanner_ctx *ctx) { - static struct cpu_topology *topology; + const struct cpu_topology *topology; double result = NAN; if (!strcmp("#num_cpus", literal)) { @@ -421,31 +421,27 @@ double expr__get_literal(const char *literal, const struct expr_scanner_ctx *ctx * these strings gives an indication of the number of packages, dies, * etc. */ - if (!topology) { - topology = cpu_topology__new(); - if (!topology) { - pr_err("Error creating CPU topology"); - goto out; - } - } if (!strcasecmp("#smt_on", literal)) { - result = smt_on(topology) ? 1.0 : 0.0; + result = smt_on() ? 1.0 : 0.0; goto out; } if (!strcmp("#core_wide", literal)) { - result = core_wide(ctx->system_wide, ctx->user_requested_cpu_list, topology) + result = core_wide(ctx->system_wide, ctx->user_requested_cpu_list) ? 1.0 : 0.0; goto out; } if (!strcmp("#num_packages", literal)) { + topology = online_topology(); result = topology->package_cpus_lists; goto out; } if (!strcmp("#num_dies", literal)) { + topology = online_topology(); result = topology->die_cpus_lists; goto out; } if (!strcmp("#num_cores", literal)) { + topology = online_topology(); result = topology->core_cpus_lists; goto out; } diff --git a/tools/perf/util/smt.c b/tools/perf/util/smt.c index 994e9e418227..650e804d0adc 100644 --- a/tools/perf/util/smt.c +++ b/tools/perf/util/smt.c @@ -4,7 +4,7 @@ #include "cputopo.h" #include "smt.h" -bool smt_on(const struct cpu_topology *topology) +bool smt_on(void) { static bool cached; static bool cached_result; @@ -16,22 +16,21 @@ bool smt_on(const struct cpu_topology *topology) if (sysfs__read_int("devices/system/cpu/smt/active", &fs_value) >= 0) cached_result = (fs_value == 1); else - cached_result = cpu_topology__smt_on(topology); + cached_result = cpu_topology__smt_on(online_topology()); cached = true; return cached_result; } -bool core_wide(bool system_wide, const char *user_requested_cpu_list, - const struct cpu_topology *topology) +bool core_wide(bool system_wide, const char *user_requested_cpu_list) { /* If not everything running on a core is being recorded then we can't use core_wide. */ if (!system_wide) return false; /* Cheap case that SMT is disabled and therefore we're inherently core_wide. */ - if (!smt_on(topology)) + if (!smt_on()) return true; - return cpu_topology__core_wide(topology, user_requested_cpu_list); + return cpu_topology__core_wide(online_topology(), user_requested_cpu_list); } diff --git a/tools/perf/util/smt.h b/tools/perf/util/smt.h index ae9095f2c38c..01441fd2c0a2 100644 --- a/tools/perf/util/smt.h +++ b/tools/perf/util/smt.h @@ -2,16 +2,16 @@ #ifndef __SMT_H #define __SMT_H 1 -struct cpu_topology; - -/* Returns true if SMT (aka hyperthreading) is enabled. */ -bool smt_on(const struct cpu_topology *topology); +/* + * Returns true if SMT (aka hyperthreading) is enabled. Determined via sysfs or + * the online topology. + */ +bool smt_on(void); /* * Returns true when system wide and all SMT threads for a core are in the * user_requested_cpus map. */ -bool core_wide(bool system_wide, const char *user_requested_cpu_list, - const struct cpu_topology *topology); +bool core_wide(bool system_wide, const char *user_requested_cpu_list); #endif /* __SMT_H */ -- cgit v1.2.3 From 62e10d937d6d5d0f100d6d13c17b4376d1466044 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:31 -0800 Subject: perf pmu-events: Test parsing metric thresholds with the fake PMU Test the correctness of metric thresholds by testing them all with the fake PMU logic. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-35-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu-events.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 521557c396bc..db2fed0c6993 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -1021,12 +1021,34 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused, return pmu_for_each_sys_metric(test__parsing_fake_callback, NULL); } +static int test__parsing_threshold_callback(const struct pmu_metric *pm, + const struct pmu_metrics_table *table __maybe_unused, + void *data __maybe_unused) +{ + if (!pm->metric_threshold) + return 0; + return metric_parse_fake(pm->metric_name, pm->metric_threshold); +} + +static int test__parsing_threshold(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int err = 0; + + err = pmu_for_each_core_metric(test__parsing_threshold_callback, NULL); + if (err) + return err; + + return pmu_for_each_sys_metric(test__parsing_threshold_callback, NULL); +} + static struct test_case pmu_events_tests[] = { TEST_CASE("PMU event table sanity", pmu_event_table), TEST_CASE("PMU event map aliases", aliases), TEST_CASE_REASON("Parsing of PMU event table metrics", parsing, "some metrics failed"), TEST_CASE("Parsing of PMU event table metrics with fake PMUs", parsing_fake), + TEST_CASE("Parsing of metric thresholds with fake PMUs", parsing_threshold), { .name = NULL, } }; -- cgit v1.2.3 From 1fd09e299bdd434b259da3ffcfdcae2dfeac9b2e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:35 -0800 Subject: perf metric: Add --metric-no-threshold option Thresholds may need additional events, this can impact things like sharing groups of events to avoid multiplexing. Add a flag to make the threshold calculations optional. The threshold will still be computed if no additional events are necessary. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-39-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 4 +++ tools/perf/tests/expand-cgroup.c | 3 +- tools/perf/tests/parse-metric.c | 1 - tools/perf/tests/pmu-events.c | 4 +-- tools/perf/util/metricgroup.c | 62 +++++++++++++++++++++++++--------------- tools/perf/util/metricgroup.h | 3 +- tools/perf/util/stat-shadow.c | 3 +- tools/perf/util/stat.h | 1 + 8 files changed, 49 insertions(+), 32 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5d18a5a6f662..5e13171a7bba 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1256,6 +1256,8 @@ static struct option stat_options[] = { "don't group metric events, impacts multiplexing"), OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge, "don't try to share events between metrics in a group"), + OPT_BOOLEAN(0, "metric-no-threshold", &stat_config.metric_no_threshold, + "don't try to share events between metrics in a group "), OPT_BOOLEAN(0, "topdown", &topdown_run, "measure top-down statistics"), OPT_UINTEGER(0, "td-level", &stat_config.topdown_level, @@ -1852,6 +1854,7 @@ static int add_default_attributes(void) return metricgroup__parse_groups(evsel_list, "transaction", stat_config.metric_no_group, stat_config.metric_no_merge, + stat_config.metric_no_threshold, stat_config.user_requested_cpu_list, stat_config.system_wide, &stat_config.metric_events); @@ -2519,6 +2522,7 @@ int cmd_stat(int argc, const char **argv) metricgroup__parse_groups(evsel_list, metrics, stat_config.metric_no_group, stat_config.metric_no_merge, + stat_config.metric_no_threshold, stat_config.user_requested_cpu_list, stat_config.system_wide, &stat_config.metric_events); diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index 672a27f37060..ec340880a848 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -187,8 +187,7 @@ static int expand_metric_events(void) rblist__init(&metric_events); pme_test = find_core_metrics_table("testarch", "testcpu"); - ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, - false, false, &metric_events); + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, &metric_events); if (ret < 0) { pr_debug("failed to parse '%s' metric\n", metric_str); goto out; diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 9fec6040950c..132c9b945a42 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -98,7 +98,6 @@ static int __compute_metric(const char *name, struct value *vals, /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); err = metricgroup__parse_groups_test(evlist, pme_test, name, - false, false, &metric_events); if (err) goto out; diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index db2fed0c6993..50b99a0f8f59 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -846,9 +846,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, perf_evlist__set_maps(&evlist->core, cpus, NULL); runtime_stat__init(&st); - err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, - false, false, - &metric_events); + err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events); if (err) { if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") || !strcmp(pm->metric_name, "M3")) { diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index d83885697125..afb6f2fdc24e 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -771,6 +771,7 @@ struct metricgroup_add_iter_data { int *ret; bool *has_match; bool metric_no_group; + bool metric_no_threshold; const char *user_requested_cpu_list; bool system_wide; struct metric *root_metric; @@ -786,6 +787,7 @@ static int add_metric(struct list_head *metric_list, const struct pmu_metric *pm, const char *modifier, bool metric_no_group, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct metric *root_metric, @@ -813,6 +815,7 @@ static int add_metric(struct list_head *metric_list, static int resolve_metric(struct list_head *metric_list, const char *modifier, bool metric_no_group, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct metric *root_metric, @@ -861,8 +864,8 @@ static int resolve_metric(struct list_head *metric_list, */ for (i = 0; i < pending_cnt; i++) { ret = add_metric(metric_list, &pending[i].pm, modifier, metric_no_group, - user_requested_cpu_list, system_wide, root_metric, visited, - table); + metric_no_threshold, user_requested_cpu_list, system_wide, + root_metric, visited, table); if (ret) break; } @@ -879,6 +882,7 @@ static int resolve_metric(struct list_head *metric_list, * @metric_no_group: Should events written to events be grouped "{}" or * global. Grouping is the default but due to multiplexing the * user may override. + * @metric_no_threshold: Should threshold expressions be ignored? * @runtime: A special argument for the parser only known at runtime. * @user_requested_cpu_list: Command line specified CPUs to record on. * @system_wide: Are events for all processes recorded. @@ -894,6 +898,7 @@ static int __add_metric(struct list_head *metric_list, const struct pmu_metric *pm, const char *modifier, bool metric_no_group, + bool metric_no_threshold, int runtime, const char *user_requested_cpu_list, bool system_wide, @@ -974,10 +979,12 @@ static int __add_metric(struct list_head *metric_list, * Threshold expressions are built off the actual metric. Switch * to use that in case of additional necessary events. Change * the visited node name to avoid this being flagged as - * recursion. + * recursion. If the threshold events are disabled, just use the + * metric's name as a reference. This allows metric threshold + * computation if there are sufficient events. */ assert(strstr(pm->metric_threshold, pm->metric_name)); - expr = pm->metric_threshold; + expr = metric_no_threshold ? pm->metric_name : pm->metric_threshold; visited_node.name = "__threshold__"; } if (expr__find_ids(expr, NULL, root_metric->pctx) < 0) { @@ -987,8 +994,8 @@ static int __add_metric(struct list_head *metric_list, if (!ret) { /* Resolve referenced metrics. */ ret = resolve_metric(metric_list, modifier, metric_no_group, - user_requested_cpu_list, system_wide, - root_metric, &visited_node, table); + metric_no_threshold, user_requested_cpu_list, + system_wide, root_metric, &visited_node, table); } if (ret) { if (is_root) @@ -1035,6 +1042,7 @@ static int add_metric(struct list_head *metric_list, const struct pmu_metric *pm, const char *modifier, bool metric_no_group, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct metric *root_metric, @@ -1046,9 +1054,9 @@ static int add_metric(struct list_head *metric_list, pr_debug("metric expr %s for %s\n", pm->metric_expr, pm->metric_name); if (!strstr(pm->metric_expr, "?")) { - ret = __add_metric(metric_list, pm, modifier, metric_no_group, 0, - user_requested_cpu_list, system_wide, root_metric, - visited, table); + ret = __add_metric(metric_list, pm, modifier, metric_no_group, + metric_no_threshold, 0, user_requested_cpu_list, + system_wide, root_metric, visited, table); } else { int j, count; @@ -1060,9 +1068,9 @@ static int add_metric(struct list_head *metric_list, */ for (j = 0; j < count && !ret; j++) - ret = __add_metric(metric_list, pm, modifier, metric_no_group, j, - user_requested_cpu_list, system_wide, - root_metric, visited, table); + ret = __add_metric(metric_list, pm, modifier, metric_no_group, + metric_no_threshold, j, user_requested_cpu_list, + system_wide, root_metric, visited, table); } return ret; @@ -1079,8 +1087,8 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_metric *pm, return 0; ret = add_metric(d->metric_list, pm, d->modifier, d->metric_no_group, - d->user_requested_cpu_list, d->system_wide, - d->root_metric, d->visited, d->table); + d->metric_no_threshold, d->user_requested_cpu_list, + d->system_wide, d->root_metric, d->visited, d->table); if (ret) goto out; @@ -1124,6 +1132,7 @@ struct metricgroup__add_metric_data { const char *modifier; const char *user_requested_cpu_list; bool metric_no_group; + bool metric_no_threshold; bool system_wide; bool has_match; }; @@ -1141,8 +1150,9 @@ static int metricgroup__add_metric_callback(const struct pmu_metric *pm, data->has_match = true; ret = add_metric(data->list, pm, data->modifier, data->metric_no_group, - data->user_requested_cpu_list, data->system_wide, - /*root_metric=*/NULL, /*visited_metrics=*/NULL, table); + data->metric_no_threshold, data->user_requested_cpu_list, + data->system_wide, /*root_metric=*/NULL, + /*visited_metrics=*/NULL, table); } return ret; } @@ -1163,7 +1173,7 @@ static int metricgroup__add_metric_callback(const struct pmu_metric *pm, * architecture perf is running upon. */ static int metricgroup__add_metric(const char *metric_name, const char *modifier, - bool metric_no_group, + bool metric_no_group, bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct list_head *metric_list, @@ -1179,6 +1189,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier .metric_name = metric_name, .modifier = modifier, .metric_no_group = metric_no_group, + .metric_no_threshold = metric_no_threshold, .user_requested_cpu_list = user_requested_cpu_list, .system_wide = system_wide, .has_match = false, @@ -1241,6 +1252,7 @@ out: * architecture perf is running upon. */ static int metricgroup__add_metric_list(const char *list, bool metric_no_group, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct list_head *metric_list, const struct pmu_metrics_table *table) @@ -1259,7 +1271,8 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group, *modifier++ = '\0'; ret = metricgroup__add_metric(metric_name, modifier, - metric_no_group, user_requested_cpu_list, + metric_no_group, metric_no_threshold, + user_requested_cpu_list, system_wide, metric_list, table); if (ret == -EINVAL) pr_err("Cannot find metric or group `%s'\n", metric_name); @@ -1449,6 +1462,7 @@ err_out: static int parse_groups(struct evlist *perf_evlist, const char *str, bool metric_no_group, bool metric_no_merge, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct perf_pmu *fake_pmu, @@ -1463,7 +1477,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, if (metric_events_list->nr_entries == 0) metricgroup__rblist_init(metric_events_list); - ret = metricgroup__add_metric_list(str, metric_no_group, + ret = metricgroup__add_metric_list(str, metric_no_group, metric_no_threshold, user_requested_cpu_list, system_wide, &metric_list, table); if (ret) @@ -1598,6 +1612,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, const char *str, bool metric_no_group, bool metric_no_merge, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct rblist *metric_events) @@ -1608,18 +1623,19 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, return -EINVAL; return parse_groups(perf_evlist, str, metric_no_group, metric_no_merge, - user_requested_cpu_list, system_wide, + metric_no_threshold, user_requested_cpu_list, system_wide, /*fake_pmu=*/NULL, metric_events, table); } int metricgroup__parse_groups_test(struct evlist *evlist, const struct pmu_metrics_table *table, const char *str, - bool metric_no_group, - bool metric_no_merge, struct rblist *metric_events) { - return parse_groups(evlist, str, metric_no_group, metric_no_merge, + return parse_groups(evlist, str, + /*metric_no_group=*/false, + /*metric_no_merge=*/false, + /*metric_no_threshold=*/false, /*user_requested_cpu_list=*/NULL, /*system_wide=*/false, &perf_pmu__fake, metric_events, table); diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 32eb3a5381fb..8d50052c5b4c 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -70,14 +70,13 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, const char *str, bool metric_no_group, bool metric_no_merge, + bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, struct rblist *metric_events); int metricgroup__parse_groups_test(struct evlist *evlist, const struct pmu_metrics_table *table, const char *str, - bool metric_no_group, - bool metric_no_merge, struct rblist *metric_events); void metricgroup__print(const struct print_callbacks *print_cb, void *print_state); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index a41f186c6ec8..77483eeda0d8 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -814,7 +814,8 @@ static void generic_metric(struct perf_stat_config *config, char metric_bf[64]; if (metric_threshold && - expr__parse(&threshold, pctx, metric_threshold) == 0) { + expr__parse(&threshold, pctx, metric_threshold) == 0 && + !isnan(threshold)) { color = fpclassify(threshold) == FP_ZERO ? PERF_COLOR_GREEN : PERF_COLOR_RED; } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index b1c29156c560..cf2d8aa445f3 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -159,6 +159,7 @@ struct perf_stat_config { bool no_csv_summary; bool metric_no_group; bool metric_no_merge; + bool metric_no_threshold; bool stop_read_counter; bool iostat_run; char *user_requested_cpu_list; -- cgit v1.2.3 From cc26ffaa01f04cbe5c958df5532f3c23599e7a04 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:44 -0800 Subject: perf stat: Hide runtime_stat runtime_stat is only shared for the sake of tests that don't care about its value. Move the definition into stat-shadow.c and have the tests also use the global version. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-48-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 6 +- tools/perf/builtin-stat.c | 4 +- tools/perf/tests/parse-metric.c | 19 ++--- tools/perf/tests/pmu-events.c | 8 +- tools/perf/util/stat-display.c | 5 +- tools/perf/util/stat-shadow.c | 165 +++++++++++++++++----------------------- tools/perf/util/stat.c | 2 +- tools/perf/util/stat.h | 17 +---- 8 files changed, 90 insertions(+), 136 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a792214d1af8..e9b5387161df 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2074,8 +2074,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, val = sample->period * evsel->scale; perf_stat__update_shadow_stats(evsel, val, - sample->cpu, - &rt_stat); + sample->cpu); evsel_script(evsel)->val = val; if (evsel_script(leader)->gnum == leader->core.nr_members) { for_each_group_member (ev2, leader) { @@ -2083,8 +2082,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, evsel_script(ev2)->val, sample->cpu, &ctx, - NULL, - &rt_stat); + NULL); } evsel_script(leader)->gnum = 0; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9c1fbf154ee3..619387459914 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -434,7 +434,7 @@ static void process_interval(void) clock_gettime(CLOCK_MONOTONIC, &ts); diff_timespec(&rs, &ts, &ref_time); - perf_stat__reset_shadow_per_stat(&rt_stat); + perf_stat__reset_shadow_per_stat(); evlist__reset_aggr_stats(evsel_list); if (read_counters(&rs) == 0) @@ -910,7 +910,7 @@ try_again_reset: evlist__copy_prev_raw_counts(evsel_list); evlist__reset_prev_raw_counts(evsel_list); evlist__reset_aggr_stats(evsel_list); - perf_stat__reset_shadow_per_stat(&rt_stat); + perf_stat__reset_shadow_per_stat(); } else { update_stats(&walltime_nsecs_stats, t1 - t0); update_rusage_stats(&ru_stats, &stat_config.ru_data); diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 132c9b945a42..37e3371d978e 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -30,8 +30,7 @@ static u64 find_value(const char *name, struct value *values) return 0; } -static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist, - struct value *vals) +static void load_runtime_stat(struct evlist *evlist, struct value *vals) { struct evsel *evsel; u64 count; @@ -39,14 +38,14 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist, perf_stat__reset_shadow_stats(); evlist__for_each_entry(evlist, evsel) { count = find_value(evsel->name, vals); - perf_stat__update_shadow_stats(evsel, count, 0, st); + perf_stat__update_shadow_stats(evsel, count, 0); if (!strcmp(evsel->name, "duration_time")) update_stats(&walltime_nsecs_stats, count); } } static double compute_single(struct rblist *metric_events, struct evlist *evlist, - struct runtime_stat *st, const char *name) + const char *name) { struct metric_expr *mexp; struct metric_event *me; @@ -58,7 +57,7 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, name)) continue; - return test_generic_metric(mexp, 0, st); + return test_generic_metric(mexp, 0); } } } @@ -74,7 +73,6 @@ static int __compute_metric(const char *name, struct value *vals, }; const struct pmu_metrics_table *pme_test; struct perf_cpu_map *cpus; - struct runtime_stat st; struct evlist *evlist; int err; @@ -93,7 +91,6 @@ static int __compute_metric(const char *name, struct value *vals, } perf_evlist__set_maps(&evlist->core, cpus, NULL); - runtime_stat__init(&st); /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); @@ -107,18 +104,17 @@ static int __compute_metric(const char *name, struct value *vals, goto out; /* Load the runtime stats with given numbers for events. */ - load_runtime_stat(&st, evlist, vals); + load_runtime_stat(evlist, vals); /* And execute the metric */ if (name1 && ratio1) - *ratio1 = compute_single(&metric_events, evlist, &st, name1); + *ratio1 = compute_single(&metric_events, evlist, name1); if (name2 && ratio2) - *ratio2 = compute_single(&metric_events, evlist, &st, name2); + *ratio2 = compute_single(&metric_events, evlist, name2); out: /* ... cleanup. */ metricgroup__rblist_exit(&metric_events); - runtime_stat__exit(&st); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); @@ -300,6 +296,7 @@ static int test_metric_group(void) static int test__parse_metric(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { + perf_stat__init_shadow_stats(); TEST_ASSERT_VAL("IPC failed", test_ipc() == 0); TEST_ASSERT_VAL("frontend failed", test_frontend() == 0); TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 50b99a0f8f59..122e74c282a7 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -816,7 +816,6 @@ static int test__parsing_callback(const struct pmu_metric *pm, int k; struct evlist *evlist; struct perf_cpu_map *cpus; - struct runtime_stat st; struct evsel *evsel; struct rblist metric_events = { .nr_entries = 0, @@ -844,7 +843,6 @@ static int test__parsing_callback(const struct pmu_metric *pm, } perf_evlist__set_maps(&evlist->core, cpus, NULL); - runtime_stat__init(&st); err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events); if (err) { @@ -867,7 +865,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, k = 1; perf_stat__reset_shadow_stats(); evlist__for_each_entry(evlist, evsel) { - perf_stat__update_shadow_stats(evsel, k, 0, &st); + perf_stat__update_shadow_stats(evsel, k, 0); if (!strcmp(evsel->name, "duration_time")) update_stats(&walltime_nsecs_stats, k); k++; @@ -881,7 +879,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, pm->metric_name)) continue; - pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st)); + pr_debug("Result %f\n", test_generic_metric(mexp, 0)); err = 0; (*failures)--; goto out_err; @@ -896,7 +894,6 @@ out_err: /* ... cleanup. */ metricgroup__rblist_exit(&metric_events); - runtime_stat__exit(&st); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); @@ -908,6 +905,7 @@ static int test__parsing(struct test_suite *test __maybe_unused, { int failures = 0; + perf_stat__init_shadow_stats(); pmu_for_each_core_metric(test__parsing_callback, &failures); pmu_for_each_sys_metric(test__parsing_callback, &failures); diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 1b5cb20efd23..6c065d0624c3 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -729,7 +729,7 @@ static void printout(struct perf_stat_config *config, struct outstate *os, if (ok) { perf_stat__print_shadow_stats(config, counter, uval, map_idx, - &out, &config->metric_events, &rt_stat); + &out, &config->metric_events); } else { pm(config, os, /*color=*/NULL, /*format=*/NULL, /*unit=*/"", /*val=*/0); } @@ -1089,8 +1089,7 @@ static void print_metric_headers(struct perf_stat_config *config, perf_stat__print_shadow_stats(config, counter, 0, 0, &out, - &config->metric_events, - &rt_stat); + &config->metric_events); } if (!config->json_output) diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index fc948a7e83b7..f80be6abac90 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -25,10 +25,13 @@ * AGGR_THREAD: Not supported? */ -struct runtime_stat rt_stat; struct stats walltime_nsecs_stats; struct rusage_stats ru_stats; +static struct runtime_stat { + struct rblist value_list; +} rt_stat; + enum { CTX_BIT_USER = 1 << 0, CTX_BIT_KERNEL = 1 << 1, @@ -125,7 +128,6 @@ static struct saved_value *saved_value_lookup(struct evsel *evsel, bool create, enum stat_type type, int ctx, - struct runtime_stat *st, struct cgroup *cgrp) { struct rblist *rblist; @@ -138,7 +140,7 @@ static struct saved_value *saved_value_lookup(struct evsel *evsel, .cgrp = cgrp, }; - rblist = &st->value_list; + rblist = &rt_stat.value_list; /* don't use context info for clock events */ if (type == STAT_NSECS) @@ -156,9 +158,9 @@ static struct saved_value *saved_value_lookup(struct evsel *evsel, return NULL; } -void runtime_stat__init(struct runtime_stat *st) +void perf_stat__init_shadow_stats(void) { - struct rblist *rblist = &st->value_list; + struct rblist *rblist = &rt_stat.value_list; rblist__init(rblist); rblist->node_cmp = saved_value_cmp; @@ -166,16 +168,6 @@ void runtime_stat__init(struct runtime_stat *st) rblist->node_delete = saved_value_delete; } -void runtime_stat__exit(struct runtime_stat *st) -{ - rblist__exit(&st->value_list); -} - -void perf_stat__init_shadow_stats(void) -{ - runtime_stat__init(&rt_stat); -} - static int evsel_context(struct evsel *evsel) { int ctx = 0; @@ -194,12 +186,12 @@ static int evsel_context(struct evsel *evsel) return ctx; } -static void reset_stat(struct runtime_stat *st) +void perf_stat__reset_shadow_per_stat(void) { struct rblist *rblist; struct rb_node *pos, *next; - rblist = &st->value_list; + rblist = &rt_stat.value_list; next = rb_first_cached(&rblist->entries); while (next) { pos = next; @@ -212,28 +204,22 @@ static void reset_stat(struct runtime_stat *st) void perf_stat__reset_shadow_stats(void) { - reset_stat(&rt_stat); + perf_stat__reset_shadow_per_stat(); memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); memset(&ru_stats, 0, sizeof(ru_stats)); } -void perf_stat__reset_shadow_per_stat(struct runtime_stat *st) -{ - reset_stat(st); -} - struct runtime_stat_data { int ctx; struct cgroup *cgrp; }; -static void update_runtime_stat(struct runtime_stat *st, - enum stat_type type, +static void update_runtime_stat(enum stat_type type, int map_idx, u64 count, struct runtime_stat_data *rsd) { struct saved_value *v = saved_value_lookup(NULL, map_idx, true, type, - rsd->ctx, st, rsd->cgrp); + rsd->ctx, rsd->cgrp); if (v) update_stats(&v->stats, count); @@ -245,7 +231,7 @@ static void update_runtime_stat(struct runtime_stat *st, * instruction rates, etc: */ void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, - int map_idx, struct runtime_stat *st) + int map_idx) { u64 count_ns = count; struct saved_value *v; @@ -253,43 +239,42 @@ void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, .ctx = evsel_context(counter), .cgrp = counter->cgrp, }; - count *= counter->scale; if (evsel__is_clock(counter)) - update_runtime_stat(st, STAT_NSECS, map_idx, count_ns, &rsd); + update_runtime_stat(STAT_NSECS, map_idx, count_ns, &rsd); else if (evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) - update_runtime_stat(st, STAT_CYCLES, map_idx, count, &rsd); + update_runtime_stat(STAT_CYCLES, map_idx, count, &rsd); else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) - update_runtime_stat(st, STAT_STALLED_CYCLES_FRONT, + update_runtime_stat(STAT_STALLED_CYCLES_FRONT, map_idx, count, &rsd); else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) - update_runtime_stat(st, STAT_STALLED_CYCLES_BACK, + update_runtime_stat(STAT_STALLED_CYCLES_BACK, map_idx, count, &rsd); else if (evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) - update_runtime_stat(st, STAT_BRANCHES, map_idx, count, &rsd); + update_runtime_stat(STAT_BRANCHES, map_idx, count, &rsd); else if (evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) - update_runtime_stat(st, STAT_CACHEREFS, map_idx, count, &rsd); + update_runtime_stat(STAT_CACHEREFS, map_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1D)) - update_runtime_stat(st, STAT_L1_DCACHE, map_idx, count, &rsd); + update_runtime_stat(STAT_L1_DCACHE, map_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1I)) - update_runtime_stat(st, STAT_L1_ICACHE, map_idx, count, &rsd); + update_runtime_stat(STAT_L1_ICACHE, map_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_LL)) - update_runtime_stat(st, STAT_LL_CACHE, map_idx, count, &rsd); + update_runtime_stat(STAT_LL_CACHE, map_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_DTLB)) - update_runtime_stat(st, STAT_DTLB_CACHE, map_idx, count, &rsd); + update_runtime_stat(STAT_DTLB_CACHE, map_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) - update_runtime_stat(st, STAT_ITLB_CACHE, map_idx, count, &rsd); + update_runtime_stat(STAT_ITLB_CACHE, map_idx, count, &rsd); if (counter->collect_stat) { - v = saved_value_lookup(counter, map_idx, true, STAT_NONE, 0, st, + v = saved_value_lookup(counter, map_idx, true, STAT_NONE, 0, rsd.cgrp); update_stats(&v->stats, count); if (counter->metric_leader) v->metric_total += count; } else if (counter->metric_leader && !counter->merged_stat) { v = saved_value_lookup(counter->metric_leader, - map_idx, true, STAT_NONE, 0, st, rsd.cgrp); + map_idx, true, STAT_NONE, 0, rsd.cgrp); v->metric_total += count; v->metric_other++; } @@ -322,26 +307,24 @@ static const char *get_ratio_color(enum grc_type type, double ratio) return color; } -static double runtime_stat_avg(struct runtime_stat *st, - enum stat_type type, int map_idx, +static double runtime_stat_avg(enum stat_type type, int map_idx, struct runtime_stat_data *rsd) { struct saved_value *v; - v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, st, rsd->cgrp); + v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, rsd->cgrp); if (!v) return 0.0; return avg_stats(&v->stats); } -static double runtime_stat_n(struct runtime_stat *st, - enum stat_type type, int map_idx, +static double runtime_stat_n(enum stat_type type, int map_idx, struct runtime_stat_data *rsd) { struct saved_value *v; - v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, st, rsd->cgrp); + v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, rsd->cgrp); if (!v) return 0.0; @@ -351,13 +334,12 @@ static double runtime_stat_n(struct runtime_stat *st, static void print_stalled_cycles_frontend(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_CYCLES, map_idx, rsd); + total = runtime_stat_avg(STAT_CYCLES, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -374,13 +356,12 @@ static void print_stalled_cycles_frontend(struct perf_stat_config *config, static void print_stalled_cycles_backend(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_CYCLES, map_idx, rsd); + total = runtime_stat_avg(STAT_CYCLES, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -393,13 +374,12 @@ static void print_stalled_cycles_backend(struct perf_stat_config *config, static void print_branch_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_BRANCHES, map_idx, rsd); + total = runtime_stat_avg(STAT_BRANCHES, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -412,13 +392,12 @@ static void print_branch_misses(struct perf_stat_config *config, static void print_l1_dcache_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_L1_DCACHE, map_idx, rsd); + total = runtime_stat_avg(STAT_L1_DCACHE, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -431,13 +410,12 @@ static void print_l1_dcache_misses(struct perf_stat_config *config, static void print_l1_icache_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_L1_ICACHE, map_idx, rsd); + total = runtime_stat_avg(STAT_L1_ICACHE, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -449,13 +427,12 @@ static void print_l1_icache_misses(struct perf_stat_config *config, static void print_dtlb_cache_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_DTLB_CACHE, map_idx, rsd); + total = runtime_stat_avg(STAT_DTLB_CACHE, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -467,13 +444,12 @@ static void print_dtlb_cache_misses(struct perf_stat_config *config, static void print_itlb_cache_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_ITLB_CACHE, map_idx, rsd); + total = runtime_stat_avg(STAT_ITLB_CACHE, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -485,13 +461,12 @@ static void print_itlb_cache_misses(struct perf_stat_config *config, static void print_ll_cache_misses(struct perf_stat_config *config, int map_idx, double avg, struct perf_stat_output_ctx *out, - struct runtime_stat *st, struct runtime_stat_data *rsd) { double total, ratio = 0.0; const char *color; - total = runtime_stat_avg(st, STAT_LL_CACHE, map_idx, rsd); + total = runtime_stat_avg(STAT_LL_CACHE, map_idx, rsd); if (total) ratio = avg / total * 100.0; @@ -503,8 +478,7 @@ static void print_ll_cache_misses(struct perf_stat_config *config, static int prepare_metric(struct evsel **metric_events, struct metric_ref *metric_refs, struct expr_parse_ctx *pctx, - int map_idx, - struct runtime_stat *st) + int map_idx) { double scale; char *n; @@ -543,7 +517,7 @@ static int prepare_metric(struct evsel **metric_events, } } else { v = saved_value_lookup(metric_events[i], map_idx, false, - STAT_NONE, 0, st, + STAT_NONE, 0, metric_events[i]->cgrp); if (!v) break; @@ -587,8 +561,7 @@ static void generic_metric(struct perf_stat_config *config, const char *metric_unit, int runtime, int map_idx, - struct perf_stat_output_ctx *out, - struct runtime_stat *st) + struct perf_stat_output_ctx *out) { print_metric_t print_metric = out->print_metric; struct expr_parse_ctx *pctx; @@ -605,7 +578,7 @@ static void generic_metric(struct perf_stat_config *config, pctx->sctx.user_requested_cpu_list = strdup(config->user_requested_cpu_list); pctx->sctx.runtime = runtime; pctx->sctx.system_wide = config->system_wide; - i = prepare_metric(metric_events, metric_refs, pctx, map_idx, st); + i = prepare_metric(metric_events, metric_refs, pctx, map_idx); if (i < 0) { expr__ctx_free(pctx); return; @@ -657,7 +630,7 @@ static void generic_metric(struct perf_stat_config *config, expr__ctx_free(pctx); } -double test_generic_metric(struct metric_expr *mexp, int map_idx, struct runtime_stat *st) +double test_generic_metric(struct metric_expr *mexp, int map_idx) { struct expr_parse_ctx *pctx; double ratio = 0.0; @@ -666,7 +639,7 @@ double test_generic_metric(struct metric_expr *mexp, int map_idx, struct runtime if (!pctx) return NAN; - if (prepare_metric(mexp->metric_events, mexp->metric_refs, pctx, map_idx, st) < 0) + if (prepare_metric(mexp->metric_events, mexp->metric_refs, pctx, map_idx) < 0) goto out; if (expr__parse(&ratio, pctx, mexp->metric_expr)) @@ -681,8 +654,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, struct evsel *evsel, double avg, int map_idx, struct perf_stat_output_ctx *out, - struct rblist *metric_events, - struct runtime_stat *st) + struct rblist *metric_events) { void *ctxp = out->ctx; print_metric_t print_metric = out->print_metric; @@ -697,7 +669,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, if (config->iostat_run) { iostat_print_metric(config, evsel, out); } else if (evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { - total = runtime_stat_avg(st, STAT_CYCLES, map_idx, &rsd); + total = runtime_stat_avg(STAT_CYCLES, map_idx, &rsd); if (total) { ratio = avg / total; @@ -707,10 +679,9 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0); } - total = runtime_stat_avg(st, STAT_STALLED_CYCLES_FRONT, map_idx, &rsd); + total = runtime_stat_avg(STAT_STALLED_CYCLES_FRONT, map_idx, &rsd); - total = max(total, runtime_stat_avg(st, - STAT_STALLED_CYCLES_BACK, + total = max(total, runtime_stat_avg(STAT_STALLED_CYCLES_BACK, map_idx, &rsd)); if (total && avg) { @@ -721,8 +692,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ratio); } } else if (evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) { - if (runtime_stat_n(st, STAT_BRANCHES, map_idx, &rsd) != 0) - print_branch_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_BRANCHES, map_idx, &rsd) != 0) + print_branch_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all branches", 0); } else if ( @@ -731,8 +702,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { - if (runtime_stat_n(st, STAT_L1_DCACHE, map_idx, &rsd) != 0) - print_l1_dcache_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_L1_DCACHE, map_idx, &rsd) != 0) + print_l1_dcache_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all L1-dcache accesses", 0); } else if ( @@ -741,8 +712,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { - if (runtime_stat_n(st, STAT_L1_ICACHE, map_idx, &rsd) != 0) - print_l1_icache_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_L1_ICACHE, map_idx, &rsd) != 0) + print_l1_icache_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all L1-icache accesses", 0); } else if ( @@ -751,8 +722,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { - if (runtime_stat_n(st, STAT_DTLB_CACHE, map_idx, &rsd) != 0) - print_dtlb_cache_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_DTLB_CACHE, map_idx, &rsd) != 0) + print_dtlb_cache_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all dTLB cache accesses", 0); } else if ( @@ -761,8 +732,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { - if (runtime_stat_n(st, STAT_ITLB_CACHE, map_idx, &rsd) != 0) - print_itlb_cache_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_ITLB_CACHE, map_idx, &rsd) != 0) + print_itlb_cache_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all iTLB cache accesses", 0); } else if ( @@ -771,27 +742,27 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { - if (runtime_stat_n(st, STAT_LL_CACHE, map_idx, &rsd) != 0) - print_ll_cache_misses(config, map_idx, avg, out, st, &rsd); + if (runtime_stat_n(STAT_LL_CACHE, map_idx, &rsd) != 0) + print_ll_cache_misses(config, map_idx, avg, out, &rsd); else print_metric(config, ctxp, NULL, NULL, "of all LL-cache accesses", 0); } else if (evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) { - total = runtime_stat_avg(st, STAT_CACHEREFS, map_idx, &rsd); + total = runtime_stat_avg(STAT_CACHEREFS, map_idx, &rsd); if (total) ratio = avg * 100 / total; - if (runtime_stat_n(st, STAT_CACHEREFS, map_idx, &rsd) != 0) + if (runtime_stat_n(STAT_CACHEREFS, map_idx, &rsd) != 0) print_metric(config, ctxp, NULL, "%8.3f %%", "of all cache refs", ratio); else print_metric(config, ctxp, NULL, NULL, "of all cache refs", 0); } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { - print_stalled_cycles_frontend(config, map_idx, avg, out, st, &rsd); + print_stalled_cycles_frontend(config, map_idx, avg, out, &rsd); } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { - print_stalled_cycles_backend(config, map_idx, avg, out, st, &rsd); + print_stalled_cycles_backend(config, map_idx, avg, out, &rsd); } else if (evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { - total = runtime_stat_avg(st, STAT_NSECS, map_idx, &rsd); + total = runtime_stat_avg(STAT_NSECS, map_idx, &rsd); if (total) { ratio = avg / total; @@ -805,11 +776,11 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, avg / (ratio * evsel->scale)); else print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0); - } else if (runtime_stat_n(st, STAT_NSECS, map_idx, &rsd) != 0) { + } else if (runtime_stat_n(STAT_NSECS, map_idx, &rsd) != 0) { char unit = ' '; char unit_buf[10] = "/sec"; - total = runtime_stat_avg(st, STAT_NSECS, map_idx, &rsd); + total = runtime_stat_avg(STAT_NSECS, map_idx, &rsd); if (total) ratio = convert_unit_double(1000000000.0 * avg / total, &unit); @@ -829,7 +800,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, generic_metric(config, mexp->metric_expr, mexp->metric_threshold, mexp->metric_events, mexp->metric_refs, evsel->name, mexp->metric_name, mexp->metric_unit, mexp->runtime, - map_idx, out, st); + map_idx, out); } } if (num == 0) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 8d83d2f4a082..0d7538670d67 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -659,7 +659,7 @@ static void evsel__update_shadow_stats(struct evsel *evsel) for (i = 0; i < ps->nr_aggr; i++) { struct perf_counts_values *aggr_counts = &ps->aggr[i].counts; - perf_stat__update_shadow_stats(evsel, aggr_counts->val, i, &rt_stat); + perf_stat__update_shadow_stats(evsel, aggr_counts->val, i); } } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 215c0f5c4db7..09975e098bd0 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -55,10 +55,6 @@ enum aggr_mode { AGGR_MAX }; -struct runtime_stat { - struct rblist value_list; -}; - struct rusage_stats { struct stats ru_utime_usec_stat; struct stats ru_stime_usec_stat; @@ -153,7 +149,6 @@ static inline void update_rusage_stats(struct rusage_stats *ru_stats, struct rus struct evsel; struct evlist; -extern struct runtime_stat rt_stat; extern struct stats walltime_nsecs_stats; extern struct rusage_stats ru_stats; @@ -162,13 +157,10 @@ typedef void (*print_metric_t)(struct perf_stat_config *config, const char *fmt, double val); typedef void (*new_line_t)(struct perf_stat_config *config, void *ctx); -void runtime_stat__init(struct runtime_stat *st); -void runtime_stat__exit(struct runtime_stat *st); void perf_stat__init_shadow_stats(void); void perf_stat__reset_shadow_stats(void); -void perf_stat__reset_shadow_per_stat(struct runtime_stat *st); -void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, - int map_idx, struct runtime_stat *st); +void perf_stat__reset_shadow_per_stat(void); +void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int map_idx); struct perf_stat_output_ctx { void *ctx; print_metric_t print_metric; @@ -180,8 +172,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, struct evsel *evsel, double avg, int map_idx, struct perf_stat_output_ctx *out, - struct rblist *metric_events, - struct runtime_stat *st); + struct rblist *metric_events); int evlist__alloc_stats(struct perf_stat_config *config, struct evlist *evlist, bool alloc_raw); @@ -220,5 +211,5 @@ void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *conf struct target *_target, struct timespec *ts, int argc, const char **argv); struct metric_expr; -double test_generic_metric(struct metric_expr *mexp, int map_idx, struct runtime_stat *st); +double test_generic_metric(struct metric_expr *mexp, int map_idx); #endif -- cgit v1.2.3 From 37cc8ad77cf81f3ffd226856c367b0e15333a738 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:46 -0800 Subject: perf metric: Directly use counts rather than saved_value Bugs with double aggregation have been introduced because of aggregation of counters and again with saved_value. Remove the generic metric use-case. Update parse-metric and pmu-events tests to update aggregate rather than saved_value counts. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-50-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-metric.c | 4 +-- tools/perf/tests/pmu-events.c | 4 +-- tools/perf/util/stat-shadow.c | 56 ++++++++++++++--------------------------- 3 files changed, 23 insertions(+), 41 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 37e3371d978e..b9b8a48289c4 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -35,10 +35,10 @@ static void load_runtime_stat(struct evlist *evlist, struct value *vals) struct evsel *evsel; u64 count; - perf_stat__reset_shadow_stats(); + evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { count = find_value(evsel->name, vals); - perf_stat__update_shadow_stats(evsel, count, 0); + evsel->stats->aggr->counts.val = count; if (!strcmp(evsel->name, "duration_time")) update_stats(&walltime_nsecs_stats, count); } diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 122e74c282a7..4ec2a4ca1a82 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -863,9 +863,9 @@ static int test__parsing_callback(const struct pmu_metric *pm, * zero when subtracted and so try to make them unique. */ k = 1; - perf_stat__reset_shadow_stats(); + evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { - perf_stat__update_shadow_stats(evsel, k, 0); + evsel->stats->aggr->counts.val = k; if (!strcmp(evsel->name, "duration_time")) update_stats(&walltime_nsecs_stats, k); k++; diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 7b48e2bd3ba1..eba98520cea2 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -234,7 +234,6 @@ void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int aggr_idx) { u64 count_ns = count; - struct saved_value *v; struct runtime_stat_data rsd = { .ctx = evsel_context(counter), .cgrp = counter->cgrp, @@ -265,19 +264,6 @@ void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, update_runtime_stat(STAT_DTLB_CACHE, aggr_idx, count, &rsd); else if (evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) update_runtime_stat(STAT_ITLB_CACHE, aggr_idx, count, &rsd); - - if (counter->collect_stat) { - v = saved_value_lookup(counter, aggr_idx, true, STAT_NONE, 0, - rsd.cgrp); - update_stats(&v->stats, count); - if (counter->metric_leader) - v->metric_total += count; - } else if (counter->metric_leader && !counter->merged_stat) { - v = saved_value_lookup(counter->metric_leader, - aggr_idx, true, STAT_NONE, 0, rsd.cgrp); - v->metric_total += count; - v->metric_other++; - } } /* used for get_ratio_color() */ @@ -480,18 +466,17 @@ static int prepare_metric(struct evsel **metric_events, struct expr_parse_ctx *pctx, int aggr_idx) { - double scale; - char *n; - int i, j, ret; + int i; for (i = 0; metric_events[i]; i++) { - struct saved_value *v; - struct stats *stats; - u64 metric_total = 0; - int source_count; + char *n; + double val; + int source_count = 0; if (evsel__is_tool(metric_events[i])) { - source_count = 1; + struct stats *stats; + double scale; + switch (metric_events[i]->tool_event) { case PERF_TOOL_DURATION_TIME: stats = &walltime_nsecs_stats; @@ -515,35 +500,32 @@ static int prepare_metric(struct evsel **metric_events, pr_err("Unknown tool event '%s'", evsel__name(metric_events[i])); abort(); } + val = avg_stats(stats) * scale; + source_count = 1; } else { - v = saved_value_lookup(metric_events[i], aggr_idx, false, - STAT_NONE, 0, - metric_events[i]->cgrp); - if (!v) + struct perf_stat_evsel *ps = metric_events[i]->stats; + struct perf_stat_aggr *aggr = &ps->aggr[aggr_idx]; + + if (!aggr) break; - stats = &v->stats; + /* * If an event was scaled during stat gathering, reverse * the scale before computing the metric. */ - scale = 1.0 / metric_events[i]->scale; - + val = aggr->counts.val * (1.0 / metric_events[i]->scale); source_count = evsel__source_count(metric_events[i]); - - if (v->metric_other) - metric_total = v->metric_total * scale; } n = strdup(evsel__metric_id(metric_events[i])); if (!n) return -ENOMEM; - expr__add_id_val_source_count(pctx, n, - metric_total ? : avg_stats(stats) * scale, - source_count); + expr__add_id_val_source_count(pctx, n, val, source_count); } - for (j = 0; metric_refs && metric_refs[j].metric_name; j++) { - ret = expr__add_ref(pctx, &metric_refs[j]); + for (int j = 0; metric_refs && metric_refs[j].metric_name; j++) { + int ret = expr__add_ref(pctx, &metric_refs[j]); + if (ret) return ret; } -- cgit v1.2.3 From aa0964e3ecebe92243bac30f9317117037adecb9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Feb 2023 01:28:48 -0800 Subject: perf stat: Remove saved_value/runtime_stat As saved_value/runtime_stat are only written to and not read, remove the associated logic and writes. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Torgue Cc: Andrii Nakryiko Cc: Athira Rajeev Cc: Caleb Biggers Cc: Eduard Zingerman Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Maxime Coquelin Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Link: https://lore.kernel.org/r/20230219092848.639226-52-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 5 - tools/perf/builtin-stat.c | 6 -- tools/perf/tests/parse-metric.c | 1 - tools/perf/tests/pmu-events.c | 1 - tools/perf/util/stat-shadow.c | 198 ---------------------------------------- tools/perf/util/stat.c | 24 ----- tools/perf/util/stat.h | 4 - 7 files changed, 239 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index e9b5387161df..522226114263 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2072,9 +2072,6 @@ static void perf_sample__fprint_metric(struct perf_script *script, if (evsel_script(leader)->gnum++ == 0) perf_stat__reset_shadow_stats(); val = sample->period * evsel->scale; - perf_stat__update_shadow_stats(evsel, - val, - sample->cpu); evsel_script(evsel)->val = val; if (evsel_script(leader)->gnum == leader->core.nr_members) { for_each_group_member (ev2, leader) { @@ -2792,8 +2789,6 @@ static int __cmd_script(struct perf_script *script) signal(SIGINT, sig_handler); - perf_stat__init_shadow_stats(); - /* override event processing functions */ if (script->show_task_events) { script->tool.comm = process_comm_event; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 619387459914..d70b1ec88594 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -424,7 +424,6 @@ static void process_counters(void) perf_stat_merge_counters(&stat_config, evsel_list); perf_stat_process_percore(&stat_config, evsel_list); - perf_stat_process_shadow_stats(&stat_config, evsel_list); } static void process_interval(void) @@ -434,7 +433,6 @@ static void process_interval(void) clock_gettime(CLOCK_MONOTONIC, &ts); diff_timespec(&rs, &ts, &ref_time); - perf_stat__reset_shadow_per_stat(); evlist__reset_aggr_stats(evsel_list); if (read_counters(&rs) == 0) @@ -910,7 +908,6 @@ try_again_reset: evlist__copy_prev_raw_counts(evsel_list); evlist__reset_prev_raw_counts(evsel_list); evlist__reset_aggr_stats(evsel_list); - perf_stat__reset_shadow_per_stat(); } else { update_stats(&walltime_nsecs_stats, t1 - t0); update_rusage_stats(&ru_stats, &stat_config.ru_data); @@ -2132,8 +2129,6 @@ static int __cmd_report(int argc, const char **argv) input_name = "perf.data"; } - perf_stat__init_shadow_stats(); - perf_stat.data.path = input_name; perf_stat.data.mode = PERF_DATA_MODE_READ; @@ -2413,7 +2408,6 @@ int cmd_stat(int argc, const char **argv) &stat_config.metric_events); zfree(&metrics); } - perf_stat__init_shadow_stats(); if (add_default_attributes()) goto out; diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index b9b8a48289c4..c43b056f9fa3 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -296,7 +296,6 @@ static int test_metric_group(void) static int test__parse_metric(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { - perf_stat__init_shadow_stats(); TEST_ASSERT_VAL("IPC failed", test_ipc() == 0); TEST_ASSERT_VAL("frontend failed", test_frontend() == 0); TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 4ec2a4ca1a82..6ccd413b5983 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -905,7 +905,6 @@ static int test__parsing(struct test_suite *test __maybe_unused, { int failures = 0; - perf_stat__init_shadow_stats(); pmu_for_each_core_metric(test__parsing_callback, &failures); pmu_for_each_sys_metric(test__parsing_callback, &failures); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 9d22cde09dc9..ef85f1ae1ab2 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -16,22 +16,9 @@ #include "iostat.h" #include "util/hashmap.h" -/* - * AGGR_GLOBAL: Use CPU 0 - * AGGR_SOCKET: Use first CPU of socket - * AGGR_DIE: Use first CPU of die - * AGGR_CORE: Use first CPU of core - * AGGR_NONE: Use matching CPU - * AGGR_THREAD: Not supported? - */ - struct stats walltime_nsecs_stats; struct rusage_stats ru_stats; -static struct runtime_stat { - struct rblist value_list; -} rt_stat; - enum { CTX_BIT_USER = 1 << 0, CTX_BIT_KERNEL = 1 << 1, @@ -65,117 +52,6 @@ enum stat_type { STAT_MAX }; -struct saved_value { - struct rb_node rb_node; - struct evsel *evsel; - enum stat_type type; - int ctx; - int map_idx; /* cpu or thread map index */ - struct cgroup *cgrp; - struct stats stats; - u64 metric_total; - int metric_other; -}; - -static int saved_value_cmp(struct rb_node *rb_node, const void *entry) -{ - struct saved_value *a = container_of(rb_node, - struct saved_value, - rb_node); - const struct saved_value *b = entry; - - if (a->map_idx != b->map_idx) - return a->map_idx - b->map_idx; - - /* - * Previously the rbtree was used to link generic metrics. - * The keys were evsel/cpu. Now the rbtree is extended to support - * per-thread shadow stats. For shadow stats case, the keys - * are cpu/type/ctx/stat (evsel is NULL). For generic metrics - * case, the keys are still evsel/cpu (type/ctx/stat are 0 or NULL). - */ - if (a->type != b->type) - return a->type - b->type; - - if (a->ctx != b->ctx) - return a->ctx - b->ctx; - - if (a->cgrp != b->cgrp) - return (char *)a->cgrp < (char *)b->cgrp ? -1 : +1; - - if (a->evsel == b->evsel) - return 0; - if ((char *)a->evsel < (char *)b->evsel) - return -1; - return +1; -} - -static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused, - const void *entry) -{ - struct saved_value *nd = malloc(sizeof(struct saved_value)); - - if (!nd) - return NULL; - memcpy(nd, entry, sizeof(struct saved_value)); - return &nd->rb_node; -} - -static void saved_value_delete(struct rblist *rblist __maybe_unused, - struct rb_node *rb_node) -{ - struct saved_value *v; - - BUG_ON(!rb_node); - v = container_of(rb_node, struct saved_value, rb_node); - free(v); -} - -static struct saved_value *saved_value_lookup(struct evsel *evsel, - int map_idx, - bool create, - enum stat_type type, - int ctx, - struct cgroup *cgrp) -{ - struct rblist *rblist; - struct rb_node *nd; - struct saved_value dm = { - .map_idx = map_idx, - .evsel = evsel, - .type = type, - .ctx = ctx, - .cgrp = cgrp, - }; - - rblist = &rt_stat.value_list; - - /* don't use context info for clock events */ - if (type == STAT_NSECS) - dm.ctx = 0; - - nd = rblist__find(rblist, &dm); - if (nd) - return container_of(nd, struct saved_value, rb_node); - if (create) { - rblist__add_node(rblist, &dm); - nd = rblist__find(rblist, &dm); - if (nd) - return container_of(nd, struct saved_value, rb_node); - } - return NULL; -} - -void perf_stat__init_shadow_stats(void) -{ - struct rblist *rblist = &rt_stat.value_list; - - rblist__init(rblist); - rblist->node_cmp = saved_value_cmp; - rblist->node_new = saved_value_new; - rblist->node_delete = saved_value_delete; -} - static int evsel_context(const struct evsel *evsel) { int ctx = 0; @@ -194,86 +70,12 @@ static int evsel_context(const struct evsel *evsel) return ctx; } -void perf_stat__reset_shadow_per_stat(void) -{ - struct rblist *rblist; - struct rb_node *pos, *next; - - rblist = &rt_stat.value_list; - next = rb_first_cached(&rblist->entries); - while (next) { - pos = next; - next = rb_next(pos); - memset(&container_of(pos, struct saved_value, rb_node)->stats, - 0, - sizeof(struct stats)); - } -} - void perf_stat__reset_shadow_stats(void) { - perf_stat__reset_shadow_per_stat(); memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); memset(&ru_stats, 0, sizeof(ru_stats)); } -struct runtime_stat_data { - int ctx; - struct cgroup *cgrp; -}; - -static void update_runtime_stat(enum stat_type type, - int map_idx, u64 count, - struct runtime_stat_data *rsd) -{ - struct saved_value *v = saved_value_lookup(NULL, map_idx, true, type, - rsd->ctx, rsd->cgrp); - - if (v) - update_stats(&v->stats, count); -} - -/* - * Update various tracking values we maintain to print - * more semantic information such as miss/hit ratios, - * instruction rates, etc: - */ -void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, - int aggr_idx) -{ - u64 count_ns = count; - struct runtime_stat_data rsd = { - .ctx = evsel_context(counter), - .cgrp = counter->cgrp, - }; - count *= counter->scale; - - if (evsel__is_clock(counter)) - update_runtime_stat(STAT_NSECS, aggr_idx, count_ns, &rsd); - else if (evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) - update_runtime_stat(STAT_CYCLES, aggr_idx, count, &rsd); - else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) - update_runtime_stat(STAT_STALLED_CYCLES_FRONT, - aggr_idx, count, &rsd); - else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) - update_runtime_stat(STAT_STALLED_CYCLES_BACK, - aggr_idx, count, &rsd); - else if (evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) - update_runtime_stat(STAT_BRANCHES, aggr_idx, count, &rsd); - else if (evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) - update_runtime_stat(STAT_CACHE_REFS, aggr_idx, count, &rsd); - else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1D)) - update_runtime_stat(STAT_L1_DCACHE, aggr_idx, count, &rsd); - else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1I)) - update_runtime_stat(STAT_L1_ICACHE, aggr_idx, count, &rsd); - else if (evsel__match(counter, HW_CACHE, HW_CACHE_LL)) - update_runtime_stat(STAT_LL_CACHE, aggr_idx, count, &rsd); - else if (evsel__match(counter, HW_CACHE, HW_CACHE_DTLB)) - update_runtime_stat(STAT_DTLB_CACHE, aggr_idx, count, &rsd); - else if (evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) - update_runtime_stat(STAT_ITLB_CACHE, aggr_idx, count, &rsd); -} - static enum stat_type evsel__stat_type(const struct evsel *evsel) { /* Fake perf_hw_cache_op_id values for use with evsel__match. */ diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 83dc4c1f4b12..4abfd87c5352 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -648,30 +648,6 @@ void perf_stat_process_percore(struct perf_stat_config *config, struct evlist *e evsel__process_percore(evsel); } -static void evsel__update_shadow_stats(struct evsel *evsel) -{ - struct perf_stat_evsel *ps = evsel->stats; - int aggr_idx; - - if (ps->aggr == NULL) - return; - - for (aggr_idx = 0; aggr_idx < ps->nr_aggr; aggr_idx++) { - struct perf_counts_values *aggr_counts = &ps->aggr[aggr_idx].counts; - - perf_stat__update_shadow_stats(evsel, aggr_counts->val, aggr_idx); - } -} - -void perf_stat_process_shadow_stats(struct perf_stat_config *config __maybe_unused, - struct evlist *evlist) -{ - struct evsel *evsel; - - evlist__for_each_entry(evlist, evsel) - evsel__update_shadow_stats(evsel); -} - int perf_event__process_stat_event(struct perf_session *session, union perf_event *event) { diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index b01c828c3799..41204547b76b 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -157,10 +157,7 @@ typedef void (*print_metric_t)(struct perf_stat_config *config, const char *fmt, double val); typedef void (*new_line_t)(struct perf_stat_config *config, void *ctx); -void perf_stat__init_shadow_stats(void); void perf_stat__reset_shadow_stats(void); -void perf_stat__reset_shadow_per_stat(void); -void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int aggr_idx); struct perf_stat_output_ctx { void *ctx; print_metric_t print_metric; @@ -189,7 +186,6 @@ int perf_stat_process_counter(struct perf_stat_config *config, struct evsel *counter); void perf_stat_merge_counters(struct perf_stat_config *config, struct evlist *evlist); void perf_stat_process_percore(struct perf_stat_config *config, struct evlist *evlist); -void perf_stat_process_shadow_stats(struct perf_stat_config *config, struct evlist *evlist); struct perf_tool; union perf_event; -- cgit v1.2.3 From 9d2dc632e09c0fe3a8a5890845bbd65b211fd662 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:42 -0800 Subject: perf evlist: Remove nr_groups Maintaining the number of groups during event parsing is problematic and since changing to sort/regroup events can only be computed by a linear pass over the evlist. As the value is generally only used in tests, rather than hold it in a variable compute it by passing over the evlist when necessary. This change highlights that libpfm's counting of groups with a single entry disagreed with regular event parsing. The libpfm tests are updated accordingly. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/evlist.c | 18 +++++++++++++++++- tools/lib/perf/include/internal/evlist.h | 1 - tools/lib/perf/include/perf/evlist.h | 1 + tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/tests/bpf.c | 1 - tools/perf/tests/parse-events.c | 22 +++++++++++----------- tools/perf/tests/pfm.c | 12 ++++++------ tools/perf/util/evlist.c | 2 +- tools/perf/util/evlist.h | 6 ++++++ tools/perf/util/header.c | 3 +-- tools/perf/util/parse-events.c | 1 - tools/perf/util/parse-events.h | 1 - tools/perf/util/parse-events.y | 10 ---------- tools/perf/util/pfm.c | 1 - 15 files changed, 45 insertions(+), 38 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c index 2d6121e89ccb..81e8b5fcd8ba 100644 --- a/tools/lib/perf/evlist.c +++ b/tools/lib/perf/evlist.c @@ -703,7 +703,23 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) struct perf_evsel *first = list_entry(evlist->entries.next, struct perf_evsel, node); - evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; __perf_evlist__set_leader(&evlist->entries, first); } } + +int perf_evlist__nr_groups(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + int nr_groups = 0; + + perf_evlist__for_each_evsel(evlist, evsel) { + /* + * evsels by default have a nr_members of 1, and they are their + * own leader. If the nr_members is >1 then this is an + * indication of a group. + */ + if (evsel->leader == evsel && evsel->nr_members > 1) + nr_groups++; + } + return nr_groups; +} diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h index 850f07070036..3339bc2f1765 100644 --- a/tools/lib/perf/include/internal/evlist.h +++ b/tools/lib/perf/include/internal/evlist.h @@ -17,7 +17,6 @@ struct perf_mmap_param; struct perf_evlist { struct list_head entries; int nr_entries; - int nr_groups; bool has_user_cpus; bool needs_map_propagation; /** diff --git a/tools/lib/perf/include/perf/evlist.h b/tools/lib/perf/include/perf/evlist.h index 9ca399d49bb4..e894b770779e 100644 --- a/tools/lib/perf/include/perf/evlist.h +++ b/tools/lib/perf/include/perf/evlist.h @@ -47,4 +47,5 @@ LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist, (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite)) LIBPERF_API void perf_evlist__set_leader(struct perf_evlist *evlist); +LIBPERF_API int perf_evlist__nr_groups(struct perf_evlist *evlist); #endif /* __LIBPERF_EVLIST_H */ diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fb8aab0cedd0..74388164a571 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2474,7 +2474,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) rec->tool.ordered_events = false; } - if (!rec->evlist->core.nr_groups) + if (evlist__nr_groups(rec->evlist) == 0) perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); if (data->is_pipe) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2ee2ecca208e..6400615b5e98 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1481,7 +1481,7 @@ repeat: setup_forced_leader(&report, session->evlist); - if (symbol_conf.group_sort_idx && !session->evlist->core.nr_groups) { + if (symbol_conf.group_sort_idx && evlist__nr_groups(session->evlist) == 0) { parse_options_usage(NULL, options, "group-sort-idx", 0); ret = -EINVAL; goto error; diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index ae9223f27cfb..8beb46066034 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -153,7 +153,6 @@ static int do_test(struct bpf_object *obj, int (*func)(void), } evlist__splice_list_tail(evlist, &parse_state.list); - evlist->core.nr_groups = parse_state.nr_groups; evlist__config(evlist, &opts, NULL); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 71a5cb343311..ffa6f0a90741 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -53,7 +53,7 @@ static int test__checkevent_tracepoint(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); @@ -66,7 +66,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", @@ -677,7 +677,7 @@ static int test__group1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* instructions:k */ evsel = leader = evlist__first(evlist); @@ -719,7 +719,7 @@ static int test__group2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* faults + :ku modifier */ evsel = leader = evlist__first(evlist); @@ -775,7 +775,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); /* group1 syscalls:sys_enter_openat:H */ evsel = leader = evlist__first(evlist); @@ -868,7 +868,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:u + p */ evsel = leader = evlist__first(evlist); @@ -912,7 +912,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); /* cycles + G */ evsel = leader = evlist__first(evlist); @@ -998,7 +998,7 @@ static int test__group_gh1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles + :H group modifier */ evsel = leader = evlist__first(evlist); @@ -1038,7 +1038,7 @@ static int test__group_gh2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles + :G group modifier */ evsel = leader = evlist__first(evlist); @@ -1078,7 +1078,7 @@ static int test__group_gh3(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:G + :u group modifier */ evsel = leader = evlist__first(evlist); @@ -1118,7 +1118,7 @@ static int test__group_gh4(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:G + :uG group modifier */ evsel = leader = evlist__first(evlist); diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index 71b76deb1f92..2e38dfa34b6c 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -76,7 +76,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused, count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->core.nr_groups, + evlist__nr_groups(evlist), 0); evlist__delete(evlist); @@ -103,22 +103,22 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, { .events = "{instructions}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{instructions},{}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{},{instructions}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{instructions},{instructions}", .nr_events = 2, - .nr_groups = 2, + .nr_groups = 0, }, { .events = "{instructions,cycles},{instructions,cycles}", @@ -161,7 +161,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->core.nr_groups, + evlist__nr_groups(evlist), table[i].nr_groups); evlist__delete(evlist); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 9e4b2bb0e6fa..b74e12239aec 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1777,7 +1777,7 @@ bool evlist__exclude_kernel(struct evlist *evlist) */ void evlist__force_leader(struct evlist *evlist) { - if (!evlist->core.nr_groups) { + if (evlist__nr_groups(evlist) == 0) { struct evsel *leader = evlist__first(evlist); evlist__set_leader(evlist); diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index d89d8f92802b..46cf402add93 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "events_stats.h" #include "evsel.h" #include @@ -255,6 +256,11 @@ static inline struct evsel *evlist__last(struct evlist *evlist) return container_of(evsel, struct evsel, core); } +static inline int evlist__nr_groups(struct evlist *evlist) +{ + return perf_evlist__nr_groups(&evlist->core); +} + int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size); int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 404d816ca124..276870221ce0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -786,7 +786,7 @@ static int write_pmu_mappings(struct feat_fd *ff, static int write_group_desc(struct feat_fd *ff, struct evlist *evlist) { - u32 nr_groups = evlist->core.nr_groups; + u32 nr_groups = evlist__nr_groups(evlist); struct evsel *evsel; int ret; @@ -2807,7 +2807,6 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) * Rebuild group relationship based on the group_desc */ session = container_of(ff->ph, struct perf_session, header); - session->evlist->core.nr_groups = nr_groups; i = nr = 0; evlist__for_each_entry(session->evlist, evsel) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 93a90651266f..9ec3c1dc81e0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2260,7 +2260,6 @@ int __parse_events(struct evlist *evlist, const char *str, if (!ret) { struct evsel *last; - evlist->core.nr_groups += parse_state.nr_groups; last = evlist__last(evlist); last->cmdline_group_boundary = true; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index fdac44dc696b..767ad1729228 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -122,7 +122,6 @@ struct parse_events_error { struct parse_events_state { struct list_head list; int idx; - int nr_groups; struct parse_events_error *error; struct evlist *evlist; struct list_head *terms; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index f1b153c72d67..3a04602d2982 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -49,14 +49,6 @@ static void free_list_evsel(struct list_head* list_evsel) free(list_evsel); } -static void inc_group_count(struct list_head *list, - struct parse_events_state *parse_state) -{ - /* Count groups only have more than 1 members */ - if (!list_is_last(list->next, list)) - parse_state->nr_groups++; -} - %} %token PE_START_EVENTS PE_START_TERMS @@ -201,7 +193,6 @@ PE_NAME '{' events '}' { struct list_head *list = $3; - inc_group_count(list, _parse_state); /* Takes ownership of $1. */ parse_events__set_leader($1, list); $$ = list; @@ -211,7 +202,6 @@ PE_NAME '{' events '}' { struct list_head *list = $2; - inc_group_count(list, _parse_state); parse_events__set_leader(NULL, list); $$ = list; } diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c index b59ba825ddc9..6c11914c179f 100644 --- a/tools/perf/util/pfm.c +++ b/tools/perf/util/pfm.c @@ -112,7 +112,6 @@ int parse_libpfm_events_option(const struct option *opt, const char *str, "cannot close a non-existing event group\n"); goto error; } - evlist->core.nr_groups++; grp_leader = NULL; grp_evt = -1; } -- cgit v1.2.3 From a4c7d7c502b935f3a8324d954de78aecf6940897 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 11 Mar 2023 18:15:43 -0800 Subject: perf parse-events: Warn when events are regrouped Use if an event is reordered or the number of groups increases to signal that regrouping has happened and warn about it. Disable the warning in the case wild card PMU names are used and for metrics. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Kim Phillips Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Stephane Eranian Cc: Suzuki Poulouse Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230312021543.3060328-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 2 +- tools/perf/tests/pmu-events.c | 2 +- tools/perf/util/metricgroup.c | 3 ++- tools/perf/util/parse-events.c | 39 +++++++++++++++++++++++++++++---------- tools/perf/util/parse-events.h | 7 ++++--- tools/perf/util/parse-events.y | 1 + 6 files changed, 38 insertions(+), 16 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index ffa6f0a90741..b1c2f0a20306 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -2103,7 +2103,7 @@ static int test_event_fake_pmu(const char *str) parse_events_error__init(&err); perf_pmu__test_parse_init(); - ret = __parse_events(evlist, str, &err, &perf_pmu__fake); + ret = __parse_events(evlist, str, &err, &perf_pmu__fake, /*warn_if_reordered=*/true); if (ret) { pr_debug("failed to parse event '%s', err %d, str '%s'\n", str, ret, err.str); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 6ccd413b5983..7f8e86452527 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -785,7 +785,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error, */ perf_pmu__test_parse_init(); } - ret = __parse_events(evlist, dup, error, fake_pmu); + ret = __parse_events(evlist, dup, error, fake_pmu, /*warn_if_reordered=*/true); free(dup); evlist__delete(evlist); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index de6dd527a2ba..5783f4c2d1ef 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1441,7 +1441,8 @@ static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, } pr_debug("Parsing metric events '%s'\n", events.buf); parse_events_error__init(&parse_error); - ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); + ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu, + /*warn_if_reordered=*/false); if (ret) { parse_events_error__print(&parse_error, events.buf); goto err_out; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9ec3c1dc81e0..3b2e5bb3e852 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2157,11 +2157,13 @@ static int evlist__cmp(void *state, const struct list_head *l, const struct list return arch_evlist__cmp(lhs, rhs); } -static void parse_events__sort_events_and_fix_groups(struct list_head *list) +static bool parse_events__sort_events_and_fix_groups(struct list_head *list) { - int idx = -1; + int idx = 0, unsorted_idx = -1; struct evsel *pos, *cur_leader = NULL; struct perf_evsel *cur_leaders_grp = NULL; + bool idx_changed = false; + int orig_num_leaders = 0, num_leaders = 0; /* * Compute index to insert ungrouped events at. Place them where the @@ -2170,15 +2172,22 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) list_for_each_entry(pos, list, core.node) { const struct evsel *pos_leader = evsel__leader(pos); - if (pos != pos_leader || pos->core.nr_members > 1) - continue; + if (pos == pos_leader) + orig_num_leaders++; - idx = pos->core.idx; - break; + /* + * Ensure indexes are sequential, in particular for multiple + * event lists being merged. The indexes are used to detect when + * the user order is modified. + */ + pos->core.idx = idx++; + + if (unsorted_idx == -1 && pos == pos_leader && pos->core.nr_members < 2) + unsorted_idx = pos->core.idx; } /* Sort events. */ - list_sort(&idx, list, evlist__cmp); + list_sort(&unsorted_idx, list, evlist__cmp); /* * Recompute groups, splitting for PMUs and adding groups for events @@ -2192,6 +2201,8 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) bool force_grouped = arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ + if (pos->core.idx != idx) + idx_changed = true; pos->core.idx = idx++; pos->core.nr_members = 0; @@ -2225,12 +2236,18 @@ static void parse_events__sort_events_and_fix_groups(struct list_head *list) } } list_for_each_entry(pos, list, core.node) { - pos->core.leader->nr_members++; + struct evsel *pos_leader = evsel__leader(pos); + + if (pos == pos_leader) + num_leaders++; + pos_leader->core.nr_members++; } + return idx_changed || num_leaders != orig_num_leaders; } int __parse_events(struct evlist *evlist, const char *str, - struct parse_events_error *err, struct perf_pmu *fake_pmu) + struct parse_events_error *err, struct perf_pmu *fake_pmu, + bool warn_if_reordered) { struct parse_events_state parse_state = { .list = LIST_HEAD_INIT(parse_state.list), @@ -2250,7 +2267,9 @@ int __parse_events(struct evlist *evlist, const char *str, return -1; } - parse_events__sort_events_and_fix_groups(&parse_state.list); + if (parse_events__sort_events_and_fix_groups(&parse_state.list) && + warn_if_reordered && !parse_state.wild_card_pmus) + pr_warning("WARNING: events were regrouped to match PMUs\n"); /* * Add list to the evlist even with errors to allow callers to clean up. diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 767ad1729228..46204c1a7916 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -26,13 +26,13 @@ int parse_events_option(const struct option *opt, const char *str, int unset); int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset); __attribute__((nonnull(1, 2, 3))) int __parse_events(struct evlist *evlist, const char *str, struct parse_events_error *error, - struct perf_pmu *fake_pmu); + struct perf_pmu *fake_pmu, bool warn_if_reordered); -__attribute__((nonnull)) +__attribute__((nonnull(1, 2, 3))) static inline int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *err) { - return __parse_events(evlist, str, err, NULL); + return __parse_events(evlist, str, err, /*fake_pmu=*/NULL, /*warn_if_reordered=*/true); } int parse_event(struct evlist *evlist, const char *str); @@ -128,6 +128,7 @@ struct parse_events_state { int stoken; struct perf_pmu *fake_pmu; char *hybrid_pmu_name; + bool wild_card_pmus; }; void parse_events__shrink_config_terms(void); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 3a04602d2982..4488443e506e 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -323,6 +323,7 @@ event_pmu_name opt_pmu_config if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, /*auto_merge_stats=*/true)) { ok++; + parse_state->wild_card_pmus = true; } parse_events_terms__delete(terms); } -- cgit v1.2.3 From 56d5229471ee1634bd0eb029f1aa82a8d87c6fed Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 15 Jan 2023 17:01:13 -0800 Subject: tools build: Pass libbpf feature only if libbpf 1.0+ libbpf 1.0 represented a cleanup and stabilization of APIs. Simplify development by only passing the feature test if libbpf 1.0 is installed. Committer notes: Change 'make -C tools/perf build-test' so that the LIBBPF_DYNAMIC=1 test runs only if libbpf is >= 1.0. Signed-off-by: Ian Rogers Tested-by: Jiri Olsa Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Andrii Nakryiko Cc: Christy Lee Cc: Ingo Molnar Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230116010115.490713-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/test-libbpf.c | 4 ++++ tools/perf/tests/make | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/build/feature/test-libbpf.c b/tools/build/feature/test-libbpf.c index a508756cf4cc..cd9989f52119 100644 --- a/tools/build/feature/test-libbpf.c +++ b/tools/build/feature/test-libbpf.c @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include +#if !defined(LIBBPF_MAJOR_VERSION) || (LIBBPF_MAJOR_VERSION < 1) +#error At least libbpf 1.0 is required for Linux tools. +#endif + int main(void) { return bpf_object__open("test") ? 0 : -1; diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 009d6efb673c..b4d64fdf4aef 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -150,7 +150,6 @@ run += make_no_libaudit run += make_no_libbionic run += make_no_auxtrace run += make_no_libbpf -run += make_libbpf_dynamic run += make_no_libbpf_DEBUG run += make_no_libcrypto run += make_no_sdt @@ -176,6 +175,12 @@ run += make_install_prefix_slash # run += make_install_pdf run += make_minimal +old_libbpf := $(shell echo "#include " | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") + +ifneq ($(old_libbpf),) +run += make_libbpf_dynamic +endif + ifneq ($(call has,ctags),) run += make_tags endif -- cgit v1.2.3 From 7a9b223ca0761a7c7c72e569b86b84a907aa0f92 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:41 -0800 Subject: perf build: Support python/perf.so testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a build target to echo the python/perf.so's name from Makefile.perf. Use it in tests/make so the correct target is built and tested for. Fixes: caec54705adb73b0 ("perf build: Fix python/perf.so library's name") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 7 +++++-- tools/perf/tests/make | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index bac9272682b7..2fcee585b225 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -647,13 +647,16 @@ all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) # Create python binding output directory if not already present _dummy := $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python') -$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBPERF) +$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBPERF) $(LIBSUBCMD) $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' \ $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/ +python_perf_target: + @echo "Target is: $(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX)" + please_set_SHELL_PATH_to_a_more_modern_shell: $(Q)$$(:) @@ -1152,7 +1155,7 @@ FORCE: .PHONY: all install clean config-clean strip install-gtk .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope FORCE prepare -.PHONY: archheaders +.PHONY: archheaders python_perf_target endif # force_fixdep diff --git a/tools/perf/tests/make b/tools/perf/tests/make index b4d64fdf4aef..f9f826c0df47 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -62,10 +62,11 @@ lib = lib endif has = $(shell which $1 2>/dev/null) +python_perf_so := $(shell $(MAKE) python_perf_target|grep "Target is:"|awk '{print $$3}') # standard single make variable specified make_clean_all := clean all -make_python_perf_so := python/perf.so +make_python_perf_so := $(python_perf_so) make_debug := DEBUG=1 make_no_libperl := NO_LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 @@ -209,7 +210,7 @@ test_make_doc := $(test_ok) test_make_help_O := $(test_ok) test_make_doc_O := $(test_ok) -test_make_python_perf_so := test -f $(PERF_O)/python/perf.so +test_make_python_perf_so := test -f $(PERF_O)/$(python_perf_so) test_make_perf_o := test -f $(PERF_O)/perf.o test_make_util_map_o := test -f $(PERF_O)/util/map.o -- cgit v1.2.3 From a980755beb5aca9002e1c95ba519b83a44242b5b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:42 -0800 Subject: perf build: Make BUILD_BPF_SKEL default, rename to NO_BPF_SKEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BPF skeleton support is now key to a number of perf features. Rather than making it so that BPF support must be enabled for the build, make this the default and error if the build lacks a clang and libbpf that are sufficient. To avoid the error and build without BPF skeletons the NO_BPF_SKEL=1 flag can be used. Add a build-options flag to 'perf version' to enable detection of the BPF skeleton support and use this in the offcpu shell test. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 19 ++++++++++++------- tools/perf/Makefile.perf | 8 ++++---- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-version.c | 1 + tools/perf/tests/shell/record_offcpu.sh | 2 +- 6 files changed, 20 insertions(+), 14 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 51a4e26bd030..318af7657225 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -415,6 +415,7 @@ ifdef NO_LIBELF NO_LIBUNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1 NO_LIBBPF := 1 + NO_BPF_SKEL := 1 NO_JVMTI := 1 else ifeq ($(feature-libelf), 0) @@ -662,18 +663,22 @@ ifndef NO_LIBBPF msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.) NO_LIBBPF := 1 endif +else + NO_BPF_SKEL := 1 endif -ifdef BUILD_BPF_SKEL +ifndef NO_BPF_SKEL $(call feature_check,clang-bpf-co-re) ifeq ($(feature-clang-bpf-co-re), 0) - dummy := $(error Error: clang too old/not installed. Please install recent clang to build with BUILD_BPF_SKEL) - endif - ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) - dummy := $(error Error: BPF skeleton support requires libbpf) + dummy := $(error: ERROR: BPF skeletons unsupported. clang too old/not installed or build with NO_BPF_SKEL=1.) + else + ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) + dummy := $(error: ERROR: BPF skeletons unsupported. BPF skeleton support requires libbpf or build with NO_BPF_SKEL=1.) + else + $(call detected,CONFIG_PERF_BPF_SKEL) + CFLAGS += -DHAVE_BPF_SKEL + endif endif - $(call detected,CONFIG_PERF_BPF_SKEL) - CFLAGS += -DHAVE_BPF_SKEL endif dwarf-post-unwind := 1 diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2fcee585b225..283ee4f56234 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -126,7 +126,7 @@ include ../scripts/utilities.mak # # Define NO_LIBDEBUGINFOD if you do not want support debuginfod # -# Define BUILD_BPF_SKEL to enable BPF skeletons +# Define NO_BPF_SKEL to disable BPF skeletons # # As per kernel Makefile, avoid funny character set dependencies @@ -1055,7 +1055,7 @@ SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): $(Q)$(MKDIR) -p $@ -ifdef BUILD_BPF_SKEL +ifndef NO_BPF_SKEL BPFTOOL := $(SKEL_TMP_OUT)/bootstrap/bpftool BPF_INCLUDE := -I$(SKEL_TMP_OUT)/.. -I$(LIBBPF_INCLUDE) @@ -1088,11 +1088,11 @@ bpf-skel: $(SKELETONS) .PRECIOUS: $(SKEL_TMP_OUT)/%.bpf.o -else # BUILD_BPF_SKEL +else # NO_BPF_SKEL bpf-skel: -endif # BUILD_BPF_SKEL +endif # NO_BPF_SKEL bpf-skel-clean: $(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 054997edd98b..240d49a85524 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2371,7 +2371,7 @@ int cmd_lock(int argc, const char **argv) #ifndef HAVE_BPF_SKEL set_option_nobuild(contention_options, 'b', "use-bpf", - "no BUILD_BPF_SKEL=1", false); + "NO_BPF_SKEL=1", false); #endif if (argc) { argc = parse_options(argc, argv, contention_options, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 74388164a571..33ebe42b025e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -3971,7 +3971,7 @@ int cmd_record(int argc, const char **argv) #ifndef HAVE_BPF_SKEL # define set_nobuild(s, l, m, c) set_option_nobuild(record_options, s, l, m, c) - set_nobuild('\0', "off-cpu", "no BUILD_BPF_SKEL=1", true); + set_nobuild('\0', "off-cpu", "NO_BPF_SKEL=1", true); # undef set_nobuild #endif diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index a886929ec6e5..0d9cda238c07 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c @@ -83,6 +83,7 @@ static void library_status(void) STATUS(HAVE_ZSTD_SUPPORT, zstd); STATUS(HAVE_LIBPFM, libpfm4); STATUS(HAVE_LIBTRACEEVENT, libtraceevent); + STATUS(HAVE_BPF_SKEL, BPF skeletons); } int cmd_version(int argc, const char **argv) diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index e01973d4e0fb..24f81ff85793 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -28,7 +28,7 @@ test_offcpu_priv() { err=2 return fi - if perf record --off-cpu -o /dev/null --quiet true 2>&1 | grep BUILD_BPF_SKEL + if perf version --build-options 2>&1 | grep HAVE_BPF_SKEL | grep -q OFF then echo "off-cpu test [Skipped missing BPF support]" err=2 -- cgit v1.2.3 From dd317df072071903031ab5f91b4823858445c4a0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:47 -0800 Subject: perf build: Make binutil libraries opt in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit binutils is GPLv3 so distributions cannot ship perf linked against libbfd and libiberty as the licenses are incompatible. Rather than defaulting the build to opting in to libbfd and libiberty support and opting out via NO_LIBBFD=1 and NO_DEMANGLE=1, make building against the libraries optional and enabled with BUILD_NONDISTRO=1. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 25 ++++++++++--------------- tools/perf/Makefile.perf | 2 ++ tools/perf/tests/make | 2 ++ 3 files changed, 14 insertions(+), 15 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index f882ce2e25b3..c4ae70c643b9 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -890,7 +890,7 @@ ifneq ($(NO_JEVENTS),1) endif endif -ifndef NO_LIBBFD +ifdef BUILD_NONDISTRO ifeq ($(feature-libbfd), 1) EXTLIBS += -lbfd -lopcodes else @@ -913,6 +913,7 @@ ifndef NO_LIBBFD $(call feature_check,disassembler-init-styled) endif + CFLAGS += -DHAVE_LIBBFD_SUPPORT ifeq ($(feature-libbfd-buildid), 1) CFLAGS += -DHAVE_LIBBFD_BUILDID_SUPPORT else @@ -923,32 +924,26 @@ endif ifdef NO_DEMANGLE CFLAGS += -DNO_DEMANGLE else - ifdef HAVE_CPLUS_DEMANGLE_SUPPORT - EXTLIBS += -liberty - else + ifdef BUILD_NONDISTRO ifeq ($(filter -liberty,$(EXTLIBS)),) - $(call feature_check,cplus-demangle) - - # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT - # or any of 'bfd iberty z' trinity - ifeq ($(feature-cplus-demangle), 1) + ifdef HAVE_CPLUS_DEMANGLE_SUPPORT EXTLIBS += -liberty else - msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling) - CFLAGS += -DNO_DEMANGLE + $(call feature_check,cplus-demangle) + ifeq ($(feature-cplus-demangle), 1) + EXTLIBS += -liberty + endif endif endif endif ifneq ($(filter -liberty,$(EXTLIBS)),) CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT + else + CFLAGS += -DNO_DEMANGLE endif endif -ifneq ($(filter -lbfd,$(EXTLIBS)),) - CFLAGS += -DHAVE_LIBBFD_SUPPORT -endif - ifndef NO_ZLIB ifeq ($(feature-zlib), 1) CFLAGS += -DHAVE_ZLIB_SUPPORT diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 283ee4f56234..a35bc995d5d8 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -128,6 +128,8 @@ include ../scripts/utilities.mak # # Define NO_BPF_SKEL to disable BPF skeletons # +# Define BUILD_NONDISTRO to enable building an linking against libbfd and +# libiberty distribution license incompatible libraries. # As per kernel Makefile, avoid funny character set dependencies unexport LC_ALL diff --git a/tools/perf/tests/make b/tools/perf/tests/make index f9f826c0df47..52b9b6895da5 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -68,6 +68,7 @@ python_perf_so := $(shell $(MAKE) python_perf_target|grep "Target is:"|awk '{pri make_clean_all := clean all make_python_perf_so := $(python_perf_so) make_debug := DEBUG=1 +make_nondistro := BUILD_NONDISTRO=1 make_no_libperl := NO_LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 @@ -134,6 +135,7 @@ MAKE_F := $(MAKE) -f $(MK) endif run += make_python_perf_so run += make_debug +run += make_nondistro run += make_no_libperl run += make_no_libpython run += make_no_scripts -- cgit v1.2.3 From d7c4f89af1611530562554a237069deb2b03b312 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:50 -0800 Subject: perf build: Switch libpfm4 to opt-out rather than opt-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If libpfm4 passes the feature test, it would be nice to have it enabled rather than also requiring the LIBPFM4=1 build flag. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 3 +-- tools/perf/Makefile.perf | 2 +- tools/perf/tests/make | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index ac8a206acf87..2caee19e3e9a 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1138,7 +1138,7 @@ ifdef LIBCLANGLLVM endif endif -ifdef LIBPFM4 +ifndef NO_LIBPFM4 $(call feature_check,libpfm4) ifeq ($(feature-libpfm4), 1) CFLAGS += -DHAVE_LIBPFM @@ -1147,7 +1147,6 @@ ifdef LIBPFM4 $(call detected,CONFIG_LIBPFM4) else msg := $(warning libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev); - NO_LIBPFM4 := 1 endif endif diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index a35bc995d5d8..3e06915f6bd0 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -122,7 +122,7 @@ include ../scripts/utilities.mak # generated from the kernel .tbl or unistd.h files and use, if available, libaudit # for doing the conversions to/from strings/id. # -# Define LIBPFM4 to enable libpfm4 events extension. +# Define NO_LIBPFM4 to disable libpfm4 events extension. # # Define NO_LIBDEBUGINFOD if you do not want support debuginfod # diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 52b9b6895da5..ba09a8b4ffb4 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -94,7 +94,7 @@ make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 make_no_syscall_tbl := NO_SYSCALL_TABLE=1 make_with_clangllvm := LIBCLANGLLVM=1 -make_with_libpfm4 := LIBPFM4=1 +make_no_libpfm4 := NO_LIBPFM4=1 make_with_gtk2 := GTK2=1 make_tags := tags make_cscope := cscope @@ -160,7 +160,7 @@ run += make_no_syscall_tbl run += make_with_babeltrace run += make_with_coresight run += make_with_clangllvm -run += make_with_libpfm4 +run += make_no_libpfm4 run += make_help run += make_doc run += make_perf_o -- cgit v1.2.3 From 6898e60f709b0047206110d3ec9f4612210e3ff7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:51 -0800 Subject: perf build: If libtraceevent isn't present error the build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If libtraceevent isn't present, the build will warn and continue. This disables a number of features and so isn't desirable. This change makes the build error for this case. The build can still be made to happen by adding NO_LIBTRACEEVENT=1. Committer notes: Add NO_LIBTRACEEVENT=1 to the 'make_static' target in tools/perf/tests/make so that 'make -C tools/perf build-test' works. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 2 +- tools/perf/tests/make | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 2caee19e3e9a..da0b13e819ee 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1164,7 +1164,7 @@ ifneq ($(NO_LIBTRACEEVENT),1) CFLAGS += -DLIBTRACEEVENT_VERSION=$(LIBTRACEEVENT_VERSION_CPP) $(call detected,CONFIG_LIBTRACEEVENT) else - dummy := $(warning Warning: libtraceevent is missing limiting functionality, please install libtraceevent-dev/libtraceevent-devel) + dummy := $(error ERROR: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel or build with NO_LIBTRACEEVENT=1) endif $(call feature_check,libtracefs) diff --git a/tools/perf/tests/make b/tools/perf/tests/make index ba09a8b4ffb4..55d0ef3a0cae 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -112,7 +112,7 @@ make_install_info := install-info make_install_pdf := install-pdf make_install_prefix := install prefix=/tmp/krava make_install_prefix_slash := install prefix=/tmp/krava/ -make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 +make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 # all the NO_* variable combined make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 -- cgit v1.2.3 From f1925bd588cfc3ea2e8624404027958955d39121 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:53 -0800 Subject: perf build: Remove redundant NO_NEWT build option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The option controlled nothing and no code depends, conditional or otherwise, on libnewt. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 4 ---- tools/perf/Makefile.perf | 2 -- tools/perf/tests/make | 6 ++---- 3 files changed, 2 insertions(+), 10 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index da0b13e819ee..0959714a89ed 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -760,10 +760,6 @@ ifndef NO_LIBCRYPTO endif endif -ifdef NO_NEWT - NO_SLANG=1 -endif - ifndef NO_SLANG ifneq ($(feature-libslang), 1) ifneq ($(feature-libslang-include-subdir), 1) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 3e06915f6bd0..dc9dda09b076 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -44,8 +44,6 @@ include ../scripts/utilities.mak # # Define WERROR=0 to disable treating any warnings as errors. # -# Define NO_NEWT if you do not want TUI support. (deprecated) -# # Define NO_SLANG if you do not want TUI support. # # Define GTK2 if you want GTK+ GUI support. diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 55d0ef3a0cae..0b92fa1863f6 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -72,10 +72,9 @@ make_nondistro := BUILD_NONDISTRO=1 make_no_libperl := NO_LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 -make_no_newt := NO_NEWT=1 make_no_slang := NO_SLANG=1 make_no_gtk2 := NO_GTK2=1 -make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1 +make_no_ui := NO_SLANG=1 NO_GTK2=1 make_no_demangle := NO_DEMANGLE=1 make_no_libelf := NO_LIBELF=1 make_no_libunwind := NO_LIBUNWIND=1 @@ -115,7 +114,7 @@ make_install_prefix_slash := install prefix=/tmp/krava/ make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 # all the NO_* variable combined -make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 +make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 @@ -139,7 +138,6 @@ run += make_nondistro run += make_no_libperl run += make_no_libpython run += make_no_scripts -run += make_no_newt run += make_no_slang run += make_no_gtk2 run += make_no_ui -- cgit v1.2.3 From 8d98ca5c02df13c1f750953bca2e308a41df08a9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 10 Mar 2023 22:57:44 -0800 Subject: perf build: Error if no libelf and NO_LIBELF isn't set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building without libelf support is going disable a lot of functionality. Require that the NO_LIBELF=1 build option is passed if this is intentional. Committer notes: Add NO_LIBELF=1 to the 'make_static' target in tools/perf/tests/make so that 'make -C tools/perf build-test' works. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andres Freund Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Martin LiÅ¡ka Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Pavithra Gurushankar Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Roberto Sassu Cc: Stephane Eranian Cc: Tiezhu Yang Cc: Tom Rix Cc: Yang Jihong Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230311065753.3012826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 10 +--------- tools/perf/tests/make | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 0959714a89ed..3066d0c318c3 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -426,15 +426,7 @@ else LIBC_SUPPORT := 1 endif ifeq ($(LIBC_SUPPORT),1) - msg := $(warning No libelf found. Disables 'probe' tool, jvmti and BPF support in 'perf record'. Please install libelf-dev, libelf-devel or elfutils-libelf-devel); - - NO_LIBELF := 1 - NO_DWARF := 1 - NO_DEMANGLE := 1 - NO_LIBUNWIND := 1 - NO_LIBDW_DWARF_UNWIND := 1 - NO_LIBBPF := 1 - NO_JVMTI := 1 + msg := $(error ERROR: No libelf found. Disables 'probe' tool, jvmti and BPF support. Please install libelf-dev, libelf-devel, elfutils-libelf-devel or build with NO_LIBELF=1.) else ifneq ($(filter s% -fsanitize=address%,$(EXTRA_CFLAGS),),) ifneq ($(shell ldconfig -p | grep libasan >/dev/null 2>&1; echo $$?), 0) diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 0b92fa1863f6..96896d498641 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -111,7 +111,7 @@ make_install_info := install-info make_install_pdf := install-pdf make_install_prefix := install prefix=/tmp/krava make_install_prefix_slash := install prefix=/tmp/krava/ -make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 +make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 NO_LIBELF=1 # all the NO_* variable combined make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 -- cgit v1.2.3 From ebf39d29b985b0c0f75c2e752781a9a80daadc0e Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 15 Mar 2023 22:51:05 +0800 Subject: perf hist: Add 'kvm_info' field in histograms entry __hists__add_entry() creates a temporary entry and compare it with existed histograms entries, if any existed entry equals to the temporary entry it skips to allocation to avoid duplication. The problem for support KVM event in histograms is it doesn't contain any info to identify KVM event and can be used for comparison entries. This patch adds 'kvm_info' field in the histograms entry which contains the KVM event's key, this identifier will be used for comparison histograms entries in later change. Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230315145112.186603-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-c2c.c | 4 ++-- tools/perf/builtin-diff.c | 4 ++-- tools/perf/tests/hists_link.c | 4 ++-- tools/perf/util/hist.c | 19 ++++++++++++------- tools/perf/util/hist.h | 3 +++ tools/perf/util/kvm-stat.h | 4 ++++ tools/perf/util/sort.h | 1 + 8 files changed, 27 insertions(+), 14 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 90458ca6933f..4750fac7bf93 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -252,7 +252,7 @@ static int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample, if (ann->has_br_stack && has_annotation(ann)) return process_branch_callback(evsel, sample, al, ann, machine); - he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); + he = hists__add_entry(hists, al, NULL, NULL, NULL, NULL, sample, true); if (he == NULL) return -ENOMEM; diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 56974eae0638..d3181fee4d3d 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -315,7 +315,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, c2c_decode_stats(&stats, mi); he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, - &al, NULL, NULL, mi, + &al, NULL, NULL, mi, NULL, sample, true); if (he == NULL) goto free_mi; @@ -349,7 +349,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, goto free_mi; he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, - &al, NULL, NULL, mi, + &al, NULL, NULL, mi, NULL, sample, true); if (he == NULL) goto free_mi; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index ed07cc6cca56..22b526766e14 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -423,7 +423,7 @@ static int diff__process_sample_event(struct perf_tool *tool, switch (compute) { case COMPUTE_CYCLES: if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL, - NULL, NULL, sample, true)) { + NULL, NULL, NULL, sample, true)) { pr_warning("problem incrementing symbol period, " "skipping event\n"); goto out_put; @@ -442,7 +442,7 @@ static int diff__process_sample_event(struct perf_tool *tool, break; default: - if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, + if (!hists__add_entry(hists, &al, NULL, NULL, NULL, NULL, sample, true)) { pr_warning("problem incrementing symbol period, " "skipping event\n"); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 14b2ff808b5e..e7e4ee57ce04 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -87,7 +87,7 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine) goto out; he = hists__add_entry(hists, &al, NULL, - NULL, NULL, &sample, true); + NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); goto out; @@ -106,7 +106,7 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine) goto out; he = hists__add_entry(hists, &al, NULL, - NULL, NULL, &sample, true); + NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); goto out; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b6e4b4edde43..3670136a0074 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -4,6 +4,7 @@ #include "dso.h" #include "build-id.h" #include "hist.h" +#include "kvm-stat.h" #include "map.h" #include "map_symbol.h" #include "branch.h" @@ -698,6 +699,7 @@ __hists__add_entry(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, + struct kvm_info *ki, struct block_info *block_info, struct perf_sample *sample, bool sample_self, @@ -733,6 +735,7 @@ __hists__add_entry(struct hists *hists, .hists = hists, .branch_info = bi, .mem_info = mi, + .kvm_info = ki, .block_info = block_info, .transaction = sample->transaction, .raw_data = sample->raw_data, @@ -756,10 +759,11 @@ struct hist_entry *hists__add_entry(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, + struct kvm_info *ki, struct perf_sample *sample, bool sample_self) { - return __hists__add_entry(hists, al, sym_parent, bi, mi, NULL, + return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL, sample, sample_self, NULL); } @@ -769,10 +773,11 @@ struct hist_entry *hists__add_entry_ops(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, + struct kvm_info *ki, struct perf_sample *sample, bool sample_self) { - return __hists__add_entry(hists, al, sym_parent, bi, mi, NULL, + return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL, sample, sample_self, ops); } @@ -846,7 +851,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al */ sample->period = cost; - he = hists__add_entry(hists, al, iter->parent, NULL, mi, + he = hists__add_entry(hists, al, iter->parent, NULL, mi, NULL, sample, true); if (!he) return -ENOMEM; @@ -949,7 +954,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a sample->period = 1; sample->weight = bi->flags.cycles ? bi->flags.cycles : 1; - he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, + he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, NULL, sample, true); if (he == NULL) return -ENOMEM; @@ -987,7 +992,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location struct hist_entry *he; he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample, true); + NULL, sample, true); if (he == NULL) return -ENOMEM; @@ -1047,7 +1052,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, struct hist_entry *he; int err = 0; - he = hists__add_entry(hists, al, iter->parent, NULL, NULL, + he = hists__add_entry(hists, al, iter->parent, NULL, NULL, NULL, sample, true); if (he == NULL) return -ENOMEM; @@ -1148,7 +1153,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, } he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample, false); + NULL, sample, false); if (he == NULL) return -ENOMEM; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index d93a4e510dc7..86a677954279 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -14,6 +14,7 @@ struct hist_entry_ops; struct addr_location; struct map_symbol; struct mem_info; +struct kvm_info; struct branch_info; struct branch_stack; struct block_info; @@ -150,6 +151,7 @@ struct hist_entry *hists__add_entry(struct hists *hists, struct symbol *parent, struct branch_info *bi, struct mem_info *mi, + struct kvm_info *ki, struct perf_sample *sample, bool sample_self); @@ -159,6 +161,7 @@ struct hist_entry *hists__add_entry_ops(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, + struct kvm_info *ki, struct perf_sample *sample, bool sample_self); diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 3b2eab91a9be..0cf704333c4c 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -23,6 +23,10 @@ struct event_key { struct exit_reasons_table *exit_reasons; }; +struct kvm_info { + char name[KVM_EVENT_NAME_LEN]; +}; + struct kvm_event_stats { u64 time; struct stats stats; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index d79a100e5999..22f437c3476f 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -144,6 +144,7 @@ struct hist_entry { struct hists *hists; struct mem_info *mem_info; struct block_info *block_info; + struct kvm_info *kvm_info; void *raw_data; u32 raw_size; int num_res; -- cgit v1.2.3 From 9bb5e1f682d8391b7e9918b12d22af9492b74dad Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Mar 2023 20:37:51 -0700 Subject: perf tests: Add common error route for code-reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A later change will enforce that the map is put on this path regardless of success or error. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: André Almeida Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320033810.980165-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index cb8cd09938d5..fb67fd5ebd9f 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -236,18 +236,19 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, const char *objdump_name; char decomp_name[KMOD_DECOMP_LEN]; bool decomp = false; - int ret; + int ret, err = 0; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) { if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { pr_debug("Hypervisor address can not be resolved - skipping\n"); - return 0; + goto out; } pr_debug("thread__find_map failed\n"); - return -1; + err = -1; + goto out; } pr_debug("File is: %s\n", al.map->dso->long_name); @@ -255,7 +256,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(al.map->dso)) { pr_debug("Unexpected kernel address - skipping\n"); - return 0; + goto out; } pr_debug("On file address is: %#"PRIx64"\n", al.addr); @@ -272,15 +273,18 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, al.addr, buf1, len); if (ret_len != len) { pr_debug("dso__data_read_offset failed\n"); - return -1; + err = -1; + goto out; } /* * Converting addresses for use by objdump requires more information. * map__load() does that. See map__rip_2objdump() for details. */ - if (map__load(al.map)) - return -1; + if (map__load(al.map)) { + err = -1; + goto out; + } /* objdump struggles with kcore - try each map only once */ if (dso__is_kcore(al.map->dso)) { @@ -290,12 +294,12 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, if (state->done[d] == al.map->start) { pr_debug("kcore map tested already"); pr_debug(" - skipping\n"); - return 0; + goto out; } } if (state->done_cnt >= ARRAY_SIZE(state->done)) { pr_debug("Too many kcore maps - skipping\n"); - return 0; + goto out; } state->done[state->done_cnt++] = al.map->start; } @@ -306,7 +310,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, decomp_name, sizeof(decomp_name)) < 0) { pr_debug("decompression failed\n"); - return -1; + err = -1; + goto out; } decomp = true; @@ -337,15 +342,16 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, */ pr_debug("objdump failed for kcore"); pr_debug(" - skipping\n"); - return 0; } else { - return -1; + err = -1; } + goto out; } } if (ret < 0) { pr_debug("read_via_objdump failed\n"); - return -1; + err = -1; + goto out; } /* The results should be identical */ @@ -355,11 +361,12 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, dump_buf(buf1, len); pr_debug("buf2 (objdump):\n"); dump_buf(buf2, len); - return -1; + err = -1; + goto out; } pr_debug("Bytes read match those read by objdump\n"); - - return 0; +out: + return err; } static int process_sample_event(struct machine *machine, -- cgit v1.2.3 From 82c6d83bc1779cc306f78083fc79dc7ec7d9b18d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 19 Mar 2023 20:37:52 -0700 Subject: perf test: Fix memory leak in symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit machine__delete() doesn't delete threads. Add call to delete threads ahead of deleting the machine. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: André Almeida Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320033810.980165-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/symbols.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c index 057b16df6416..0793f8f419e2 100644 --- a/tools/perf/tests/symbols.c +++ b/tools/perf/tests/symbols.c @@ -38,6 +38,7 @@ static int init_test_info(struct test_info *ti) static void exit_test_info(struct test_info *ti) { thread__put(ti->thread); + machine__delete_threads(ti->machine); machine__delete(ti->machine); } -- cgit v1.2.3 From 204e7c499f5fa7732144ef9765c195982be72f31 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 17 Feb 2023 16:32:11 -0600 Subject: perf tools: Add support for perf_event_attr::config3 perf_event_attr has gained a new field, config3, so add support for it extending the existing configN support. Signed-off-by: Rob Herring Cc: Alexander Shishkin Cc: James Clark Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20220914-arm-perf-tool-spe1-2-v2-v5-2-2cf5210b2f77@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 13 ++++++++++++- tools/perf/util/parse-events.c | 6 ++++++ tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.l | 1 + tools/perf/util/pmu.c | 3 +++ tools/perf/util/pmu.h | 1 + 6 files changed, 24 insertions(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b1c2f0a20306..6eb1400443ad 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -449,6 +449,7 @@ static int test__checkevent_pmu(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); /* * The period value gets configured within evlist__config, * while this test executes only parse events method. @@ -470,6 +471,7 @@ static int test__checkevent_list(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong config1", 0 == evsel->core.attr.config1); TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -632,6 +634,15 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong val", term->val.num == 3); TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config2")); + /* config3=4 */ + term = list_entry(term->list.next, struct parse_events_term, list); + TEST_ASSERT_VAL("wrong type term", + term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG3); + TEST_ASSERT_VAL("wrong type val", + term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); + TEST_ASSERT_VAL("wrong val", term->val.num == 4); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config3")); + /* umask=1*/ term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", @@ -2004,7 +2015,7 @@ struct terms_test { static const struct terms_test test__terms[] = { [0] = { - .str = "config=10,config1,config2=3,umask=1,read,r0xead", + .str = "config=10,config1,config2=3,config3=4,umask=1,read,r0xead", .check = test__checkterms_simple, }, }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6c5cf5244486..cc8e8766ca30 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -949,6 +949,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_CONFIG] = "config", [PARSE_EVENTS__TERM_TYPE_CONFIG1] = "config1", [PARSE_EVENTS__TERM_TYPE_CONFIG2] = "config2", + [PARSE_EVENTS__TERM_TYPE_CONFIG3] = "config3", [PARSE_EVENTS__TERM_TYPE_NAME] = "name", [PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD] = "period", [PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ] = "freq", @@ -988,6 +989,7 @@ config_term_avail(int term_type, struct parse_events_error *err) case PARSE_EVENTS__TERM_TYPE_CONFIG: case PARSE_EVENTS__TERM_TYPE_CONFIG1: case PARSE_EVENTS__TERM_TYPE_CONFIG2: + case PARSE_EVENTS__TERM_TYPE_CONFIG3: case PARSE_EVENTS__TERM_TYPE_NAME: case PARSE_EVENTS__TERM_TYPE_METRIC_ID: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: @@ -1033,6 +1035,10 @@ do { \ CHECK_TYPE_VAL(NUM); attr->config2 = term->val.num; break; + case PARSE_EVENTS__TERM_TYPE_CONFIG3: + CHECK_TYPE_VAL(NUM); + attr->config3 = term->val.num; + break; case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: CHECK_TYPE_VAL(NUM); break; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 46204c1a7916..86ad4438a2aa 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -59,6 +59,7 @@ enum { PARSE_EVENTS__TERM_TYPE_CONFIG, PARSE_EVENTS__TERM_TYPE_CONFIG1, PARSE_EVENTS__TERM_TYPE_CONFIG2, + PARSE_EVENTS__TERM_TYPE_CONFIG3, PARSE_EVENTS__TERM_TYPE_NAME, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 3a9ce96c8bce..51fe0a9fb3de 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -285,6 +285,7 @@ modifier_bp [rwx]{1,3} config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } +config3 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG3); } name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 45d9b8e28e16..e3aae731bd6f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1209,6 +1209,9 @@ static int pmu_config_term(const char *pmu_name, case PERF_PMU_FORMAT_VALUE_CONFIG2: vp = &attr->config2; break; + case PERF_PMU_FORMAT_VALUE_CONFIG3: + vp = &attr->config3; + break; default: return -EINVAL; } diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 6b770f17eb86..24cf69ab32cd 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -19,6 +19,7 @@ enum { PERF_PMU_FORMAT_VALUE_CONFIG, PERF_PMU_FORMAT_VALUE_CONFIG1, PERF_PMU_FORMAT_VALUE_CONFIG2, + PERF_PMU_FORMAT_VALUE_CONFIG3, PERF_PMU_FORMAT_VALUE_CONFIG_END, }; -- cgit v1.2.3 From 30df88a80f32ccca5c5cdcf2710d1fb2de5e314d Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 22 Mar 2023 10:47:31 +0100 Subject: perf test: Fix wrong size expectation for 'Setup struct perf_event_attr' The test case "perf test 'Setup struct perf_event_attr'" is failing. On s390 this output is observed: # ./perf test -Fvvvv 17 17: Setup struct perf_event_attr : --- start --- running './tests/attr/test-stat-C0' Using CPUID IBM,8561,703,T01,3.6,002f ..... Event event:base-stat fd = 1 group_fd = -1 flags = 0|8 cpu = * type = 0 size = 128 <<<--- wrong, specified in file base-stat config = 0 sample_period = 0 sample_type = 65536 ... 'PERF_TEST_ATTR=/tmp/tmpgw574wvg ./perf stat -o \ /tmp/tmpgw574wvg/perf.data -e cycles -C 0 kill >/dev/null \ 2>&1 ret '1', expected '1' loading result events Event event-0-0-4 fd = 4 group_fd = -1 cpu = 0 pid = -1 flags = 8 type = 0 size = 136 <<<--- actual size used in system call ..... compare matching [event-0-0-4] to [event:base-stat] [cpu] 0 * [flags] 8 0|8 [type] 0 0 [size] 136 128 ->FAIL match: [event-0-0-4] matches [] expected size=136, got 128 FAILED './tests/attr/test-stat-C0' - match failure This mismatch is caused by commit 09519ec3b19e ("perf: Add perf_event_attr::config3") which enlarges the structure perf_event_attr by 8 bytes. Fix this by adjusting the expected value of size. Output after: # ./perf test -Fvvvv 17 17: Setup struct perf_event_attr : --- start --- running './tests/attr/test-stat-C0' Using CPUID IBM,8561,703,T01,3.6,002f ... matched compare matching [event-0-0-4] to [event:base-stat] [cpu] 0 * [flags] 8 0|8 [type] 0 0 [size] 136 136 .... ->OK match: [event-0-0-4] matches ['event:base-stat'] matched Fixes: 09519ec3b19e4144 ("perf: Add perf_event_attr::config3") Signed-off-by: Thomas Richter Acked-by: Namhyung Kim Cc: Heiko Carstens Cc: Rob Herring Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Vasily Gorbik Cc: Will Deacon Link: https://lore.kernel.org/r/20230322094731.1768281-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/attr/base-stat | 2 +- tools/perf/tests/attr/system-wide-dummy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index 3ef07a12aa14..27c21271a16c 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record @@ -5,7 +5,7 @@ group_fd=-1 flags=0|8 cpu=* type=0|1 -size=128 +size=136 config=0 sample_period=* sample_type=263 diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat index 408164456530..a21fb65bc012 100644 --- a/tools/perf/tests/attr/base-stat +++ b/tools/perf/tests/attr/base-stat @@ -5,7 +5,7 @@ group_fd=-1 flags=0|8 cpu=* type=0 -size=128 +size=136 config=0 sample_period=0 sample_type=65536 diff --git a/tools/perf/tests/attr/system-wide-dummy b/tools/perf/tests/attr/system-wide-dummy index 8fec06eda5f9..2f3e3eb728eb 100644 --- a/tools/perf/tests/attr/system-wide-dummy +++ b/tools/perf/tests/attr/system-wide-dummy @@ -7,7 +7,7 @@ cpu=* pid=-1 flags=8 type=1 -size=128 +size=136 config=9 sample_period=4000 sample_type=455 -- cgit v1.2.3 From 9835b742ac3ee16dee361e7ccda8022f99d1cd94 Mon Sep 17 00:00:00 2001 From: Patrice Duroux Date: Fri, 3 Mar 2023 20:30:58 +0100 Subject: perf tests record_offcpu.sh: Fix redirection of stderr to stdin It's not 2&>1, the correct is 2>&1 Fixes: ade1d0307b2fb3d9 ("perf offcpu: Update offcpu test for child process") Signed-off-by: Patrice Duroux Acked-by: Ian Rogers Cc: Namhyung Kim Link: https://lore.kernel.org/r/20230303193058.21274-1-patrice.duroux@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record_offcpu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 24f81ff85793..155d4856551a 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -65,7 +65,7 @@ test_offcpu_child() { # perf bench sched messaging creates 400 processes if ! perf record --off-cpu -e dummy -o ${perfdata} -- \ - perf bench sched messaging -g 10 > /dev/null 2&>1 + perf bench sched messaging -g 10 > /dev/null 2>&1 then echo "Child task off-cpu test [Failed record]" err=1 -- cgit v1.2.3 From e293a5e816c03b57f07078db60497933f3400b2a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 31 Mar 2023 13:29:45 -0700 Subject: perf pmu: Use relative path for sysfs scan The PMU information is in the kernel sysfs so it needs to scan the directory to get the whole information like event aliases, formats and so on. During the traversal, it opens a lot of files and directories like below: dir = opendir("/sys/bus/event_source/devices"); while (dentry = readdir(dir)) { char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/%s", "/sys/bus/event_source/devices", dentry->d_name); fd = open(buf, O_RDONLY); ... } But this is not good since it needs to copy the string to build the absolute pathname, and it makes redundant pathname walk (from the /sys) unnecessarily. We can use openat(2) to open the file in the given directory. While it's not a problem ususally, it can be a problem when the kernel has contentions on the sysfs. Add a couple of new helper to return the file descriptor of PMU directory so that it can use it with relative paths. * perf_pmu__event_source_devices_fd() - returns a fd for the PMU root ("/sys/bus/event_source/devices") * perf_pmu__pathname_fd() - returns a fd for "/" under the PMU root Now the above code can be converted something like below: dirfd = perf_pmu__event_source_devices_fd(); dir = fdopendir(dirfd); while (dentry = readdir(dir)) { fd = openat(dirfd, dentry->d_name, O_RDONLY); ... } Signed-off-by: Namhyung Kim Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu.c | 9 ++- tools/perf/util/pmu.c | 161 ++++++++++++++++++++++++++++++------------------- tools/perf/util/pmu.h | 4 +- 3 files changed, 111 insertions(+), 63 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index 8507bd615e97..3cf25f883df7 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -3,6 +3,7 @@ #include "pmu.h" #include "tests.h" #include +#include #include #include #include @@ -149,10 +150,16 @@ static int test__pmu(struct test_suite *test __maybe_unused, int subtest __maybe do { struct perf_event_attr attr; + int fd; memset(&attr, 0, sizeof(attr)); - ret = perf_pmu__format_parse(format, &formats); + fd = open(format, O_DIRECTORY); + if (fd < 0) { + ret = fd; + break; + } + ret = perf_pmu__format_parse(fd, &formats); if (ret) break; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index b112606f36ec..9fc6b8b5732b 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -62,38 +62,38 @@ extern FILE *perf_pmu_in; static bool hybrid_scanned; +static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name); + /* * Parse & process all the sysfs attributes located under * the directory specified in 'dir' parameter. */ -int perf_pmu__format_parse(char *dir, struct list_head *head) +int perf_pmu__format_parse(int dirfd, struct list_head *head) { struct dirent *evt_ent; DIR *format_dir; int ret = 0; - format_dir = opendir(dir); + format_dir = fdopendir(dirfd); if (!format_dir) return -EINVAL; while (!ret && (evt_ent = readdir(format_dir))) { - char path[PATH_MAX]; char *name = evt_ent->d_name; - FILE *file; + int fd; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; - snprintf(path, PATH_MAX, "%s/%s", dir, name); ret = -EINVAL; - file = fopen(path, "r"); - if (!file) + fd = openat(dirfd, name, O_RDONLY); + if (fd < 0) break; - perf_pmu_in = file; + perf_pmu_in = fdopen(fd, "r"); ret = perf_pmu_parse(head, name); - fclose(file); + fclose(perf_pmu_in); } closedir(format_dir); @@ -105,17 +105,16 @@ int perf_pmu__format_parse(char *dir, struct list_head *head) * located at: * /sys/bus/event_source/devices//format as sysfs group attributes. */ -static int pmu_format(const char *name, struct list_head *format) +static int pmu_format(int dirfd, const char *name, struct list_head *format) { - char path[PATH_MAX]; - - if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "format")) - return -1; + int fd; - if (!file_available(path)) + fd = perf_pmu__pathname_fd(dirfd, name, "format", O_DIRECTORY); + if (fd < 0) return 0; - if (perf_pmu__format_parse(path, format)) + /* it'll close the fd */ + if (perf_pmu__format_parse(fd, format)) return -1; return 0; @@ -158,7 +157,7 @@ out: return ret; } -static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) +static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, int dirfd, char *name) { struct stat st; ssize_t sret; @@ -166,9 +165,9 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * int fd, ret = -1; char path[PATH_MAX]; - scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); + scnprintf(path, PATH_MAX, "%s.scale", name); - fd = open(path, O_RDONLY); + fd = openat(dirfd, path, O_RDONLY); if (fd == -1) return -1; @@ -190,15 +189,15 @@ error: return ret; } -static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) +static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, int dirfd, char *name) { char path[PATH_MAX]; ssize_t sret; int fd; - scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); + scnprintf(path, PATH_MAX, "%s.unit", name); - fd = open(path, O_RDONLY); + fd = openat(dirfd, path, O_RDONLY); if (fd == -1) return -1; @@ -221,14 +220,14 @@ error: } static int -perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) +perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, int dirfd, char *name) { char path[PATH_MAX]; int fd; - scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); + scnprintf(path, PATH_MAX, "%s.per-pkg", name); - fd = open(path, O_RDONLY); + fd = openat(dirfd, path, O_RDONLY); if (fd == -1) return -1; @@ -239,14 +238,14 @@ perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) } static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, - char *dir, char *name) + int dirfd, char *name) { char path[PATH_MAX]; int fd; - scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); + scnprintf(path, PATH_MAX, "%s.snapshot", name); - fd = open(path, O_RDONLY); + fd = openat(dirfd, path, O_RDONLY); if (fd == -1) return -1; @@ -332,7 +331,7 @@ static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, return false; } -static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, +static int __perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, char *desc, char *val, const struct pmu_event *pe) { struct parse_events_term *term; @@ -391,14 +390,14 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, } alias->name = strdup(name); - if (dir) { + if (dirfd >= 0) { /* * load unit name and scale if available */ - perf_pmu__parse_unit(alias, dir, name); - perf_pmu__parse_scale(alias, dir, name); - perf_pmu__parse_per_pkg(alias, dir, name); - perf_pmu__parse_snapshot(alias, dir, name); + perf_pmu__parse_unit(alias, dirfd, name); + perf_pmu__parse_scale(alias, dirfd, name); + perf_pmu__parse_per_pkg(alias, dirfd, name); + perf_pmu__parse_snapshot(alias, dirfd, name); } alias->desc = desc ? strdup(desc) : NULL; @@ -419,7 +418,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, return 0; } -static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) +static int perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, FILE *file) { char buf[256]; int ret; @@ -433,7 +432,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI /* Remove trailing newline from sysfs file */ strim(buf); - return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL); + return __perf_pmu__new_alias(list, dirfd, name, NULL, buf, NULL); } static inline bool pmu_alias_info_file(char *name) @@ -457,17 +456,17 @@ static inline bool pmu_alias_info_file(char *name) * Process all the sysfs attributes located under the directory * specified in 'dir' parameter. */ -static int pmu_aliases_parse(char *dir, struct list_head *head) +static int pmu_aliases_parse(int dirfd, struct list_head *head) { struct dirent *evt_ent; DIR *event_dir; + int fd; - event_dir = opendir(dir); + event_dir = fdopendir(dirfd); if (!event_dir) return -EINVAL; while ((evt_ent = readdir(event_dir))) { - char path[PATH_MAX]; char *name = evt_ent->d_name; FILE *file; @@ -480,15 +479,14 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) if (pmu_alias_info_file(name)) continue; - scnprintf(path, PATH_MAX, "%s/%s", dir, name); - - file = fopen(path, "r"); + fd = openat(dirfd, name, O_RDONLY); + file = fdopen(fd, "r"); if (!file) { - pr_debug("Cannot open %s\n", path); + pr_debug("Cannot open %s\n", name); continue; } - if (perf_pmu__new_alias(head, dir, name, file) < 0) + if (perf_pmu__new_alias(head, dirfd, name, file) < 0) pr_debug("Cannot set up %s\n", name); fclose(file); } @@ -501,17 +499,16 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) * Reading the pmu event aliases definition, which should be located at: * /sys/bus/event_source/devices//events as sysfs group attributes. */ -static int pmu_aliases(const char *name, struct list_head *head) +static int pmu_aliases(int dirfd, const char *name, struct list_head *head) { - char path[PATH_MAX]; - - if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "events")) - return -1; + int fd; - if (!file_available(path)) + fd = perf_pmu__pathname_fd(dirfd, name, "events", O_DIRECTORY); + if (fd < 0) return 0; - if (pmu_aliases_parse(path, head)) + /* it'll close the fd */ + if (pmu_aliases_parse(fd, head)) return -1; return 0; @@ -544,14 +541,15 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias, /* Add all pmus in sysfs to pmu list: */ static void pmu_read_sysfs(void) { - char path[PATH_MAX]; + int fd; DIR *dir; struct dirent *dent; - if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) + fd = perf_pmu__event_source_devices_fd(); + if (fd < 0) return; - dir = opendir(path); + dir = fdopendir(fd); if (!dir) return; @@ -559,7 +557,7 @@ static void pmu_read_sysfs(void) if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; /* add to static LIST_HEAD(pmus): */ - perf_pmu__find(dent->d_name); + perf_pmu__find2(fd, dent->d_name); } closedir(dir); @@ -763,7 +761,7 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, new_alias: /* need type casts to override 'const' */ - __perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc, + __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc, (char *)pe->event, pe); return 0; } @@ -814,7 +812,7 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, if (!strcmp(pmu->id, pe->compat) && pmu_uncore_alias_match(pe->pmu, pmu->name)) { - __perf_pmu__new_alias(idata->head, NULL, + __perf_pmu__new_alias(idata->head, -1, (char *)pe->name, (char *)pe->desc, (char *)pe->event, @@ -863,7 +861,7 @@ static int pmu_max_precise(struct perf_pmu *pmu) return max_precise; } -static struct perf_pmu *pmu_lookup(const char *lookup_name) +static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name) { struct perf_pmu *pmu; LIST_HEAD(format); @@ -884,13 +882,13 @@ static struct perf_pmu *pmu_lookup(const char *lookup_name) * type value and format definitions. Load both right * now. */ - if (pmu_format(name, &format)) + if (pmu_format(dirfd, name, &format)) return NULL; /* * Check the aliases first to avoid unnecessary work. */ - if (pmu_aliases(name, &aliases)) + if (pmu_aliases(dirfd, name, &aliases)) return NULL; pmu = zalloc(sizeof(*pmu)); @@ -1024,6 +1022,27 @@ bool evsel__is_aux_event(const struct evsel *evsel) } struct perf_pmu *perf_pmu__find(const char *name) +{ + struct perf_pmu *pmu; + int dirfd; + + /* + * Once PMU is loaded it stays in the list, + * so we keep us from multiple reading/parsing + * the pmu format definitions. + */ + pmu = pmu_find(name); + if (pmu) + return pmu; + + dirfd = perf_pmu__event_source_devices_fd(); + pmu = pmu_lookup(dirfd, name); + close(dirfd); + + return pmu; +} + +static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name) { struct perf_pmu *pmu; @@ -1036,7 +1055,7 @@ struct perf_pmu *perf_pmu__find(const char *name) if (pmu) return pmu; - return pmu_lookup(name); + return pmu_lookup(dirfd, name); } static struct perf_pmu_format * @@ -1938,6 +1957,18 @@ int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); } +int perf_pmu__event_source_devices_fd(void) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + scnprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs); + return open(path, O_DIRECTORY); +} + /* * Fill 'buf' with the path to a file or folder in 'pmu_name' in * sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format" @@ -1957,6 +1988,14 @@ int perf_pmu__pathname_scnprintf(char *buf, size_t size, return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); } +int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags) +{ + char path[PATH_MAX]; + + scnprintf(path, sizeof(path), "%s/%s", pmu_name, filename); + return openat(dirfd, path, flags); +} + static void perf_pmu__delete(struct perf_pmu *pmu) { perf_pmu__del_formats(&pmu->format); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 72fd5de334c0..751c7016e7b6 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -211,7 +211,7 @@ void perf_pmu_error(struct list_head *list, char *name, char const *msg); int perf_pmu__new_format(struct list_head *list, char *name, int config, unsigned long *bits); void perf_pmu__set_format(unsigned long *bits, long from, long to); -int perf_pmu__format_parse(char *dir, struct list_head *head); +int perf_pmu__format_parse(int dirfd, struct list_head *head); void perf_pmu__del_formats(struct list_head *formats); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); @@ -257,6 +257,8 @@ double perf_pmu__cpu_slots_per_cycle(void); int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size); int perf_pmu__pathname_scnprintf(char *buf, size_t size, const char *pmu_name, const char *filename); +int perf_pmu__event_source_devices_fd(void); +int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags); FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name); void perf_pmu__destroy(void); -- cgit v1.2.3 From c9dc580c43b8d83de0c14158e826f79e41098822 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 3 Apr 2023 11:40:30 -0700 Subject: tools api: Add io__getline Reads a line to allocated memory up to a newline following the getline API. Committer notes: It also adds this new function to the 'api io' 'perf test' entry: $ perf test "api io" 64: Test api io : Ok $ Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Tom Rix Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230403184033.1836023-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/io.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/tests/api-io.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'tools/perf/tests') diff --git a/tools/lib/api/io.h b/tools/lib/api/io.h index 777c20f6b604..d5e8cf0dada0 100644 --- a/tools/lib/api/io.h +++ b/tools/lib/api/io.h @@ -7,7 +7,9 @@ #ifndef __API_IO__ #define __API_IO__ +#include #include +#include #include struct io { @@ -112,4 +114,47 @@ static inline int io__get_dec(struct io *io, __u64 *dec) } } +/* Read up to and including the first newline following the pattern of getline. */ +static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out) +{ + char buf[128]; + int buf_pos = 0; + char *line = NULL, *temp; + size_t line_len = 0; + int ch = 0; + + /* TODO: reuse previously allocated memory. */ + free(*line_out); + while (ch != '\n') { + ch = io__get_char(io); + + if (ch < 0) + break; + + if (buf_pos == sizeof(buf)) { + temp = realloc(line, line_len + sizeof(buf)); + if (!temp) + goto err_out; + line = temp; + memcpy(&line[line_len], buf, sizeof(buf)); + line_len += sizeof(buf); + buf_pos = 0; + } + buf[buf_pos++] = (char)ch; + } + temp = realloc(line, line_len + buf_pos + 1); + if (!temp) + goto err_out; + line = temp; + memcpy(&line[line_len], buf, buf_pos); + line[line_len + buf_pos] = '\0'; + line_len += buf_pos; + *line_out = line; + *line_len_out = line_len; + return line_len; +err_out: + free(line); + return -ENOMEM; +} + #endif /* __API_IO__ */ diff --git a/tools/perf/tests/api-io.c b/tools/perf/tests/api-io.c index e91cf2c127f1..6aea84ca6673 100644 --- a/tools/perf/tests/api-io.c +++ b/tools/perf/tests/api-io.c @@ -289,6 +289,40 @@ static int test_get_dec(void) return ret; } +static int test_get_line(void) +{ + char path[PATH_MAX]; + struct io io; + char test_string[1024]; + char *line = NULL; + size_t i, line_len = 0; + size_t buf_size = 128; + int ret = 0; + + for (i = 0; i < 512; i++) + test_string[i] = 'a'; + test_string[512] = '\n'; + for (i = 513; i < 1023; i++) + test_string[i] = 'b'; + test_string[1023] = '\0'; + + if (setup_test(path, test_string, buf_size, &io)) + return -1; + + EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 513); + EXPECT_EQUAL((int)strlen(line), 513); + for (i = 0; i < 512; i++) + EXPECT_EQUAL(line[i], 'a'); + EXPECT_EQUAL(line[512], '\n'); + EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 510); + for (i = 0; i < 510; i++) + EXPECT_EQUAL(line[i], 'b'); + + free(line); + cleanup_test(path, &io); + return ret; +} + static int test__api_io(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { @@ -300,6 +334,8 @@ static int test__api_io(struct test_suite *test __maybe_unused, ret = TEST_FAIL; if (test_get_dec()) ret = TEST_FAIL; + if (test_get_line()) + ret = TEST_FAIL; return ret; } -- cgit v1.2.3 From ff583dc43dc8b62c9ec639604adae641ba38a91d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 20 Mar 2023 14:22:33 -0700 Subject: perf maps: Remove rb_node from struct map struct map is reference counted, having it also be a node in an red-black tree complicates the reference counting. Switch to having a map_rb_node which is a red-block tree node but points at the reference counted struct map. This reference is responsible for a single reference count. Committer notes: Fixed up tools/perf/util/unwind-libunwind-local.c to use map_rb_node as well. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320212248.1175731-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/event.c | 13 +-- tools/perf/builtin-report.c | 6 +- tools/perf/tests/maps.c | 8 +- tools/perf/tests/vmlinux-kallsyms.c | 17 +-- tools/perf/util/bpf_lock_contention.c | 2 +- tools/perf/util/machine.c | 68 +++++++----- tools/perf/util/map.c | 16 --- tools/perf/util/map.h | 1 - tools/perf/util/maps.c | 180 ++++++++++++++++++++----------- tools/perf/util/maps.h | 17 ++- tools/perf/util/probe-event.c | 18 ++-- tools/perf/util/symbol-elf.c | 9 +- tools/perf/util/symbol.c | 77 ++++++++----- tools/perf/util/synthetic-events.c | 26 ++--- tools/perf/util/thread.c | 10 +- tools/perf/util/unwind-libunwind-local.c | 6 +- tools/perf/util/vdso.c | 7 +- 17 files changed, 295 insertions(+), 186 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/x86/util/event.c b/tools/perf/arch/x86/util/event.c index e4288d09f3a0..17bf60babfbd 100644 --- a/tools/perf/arch/x86/util/event.c +++ b/tools/perf/arch/x86/util/event.c @@ -19,7 +19,7 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, struct machine *machine) { int rc = 0; - struct map *pos; + struct map_rb_node *pos; struct maps *kmaps = machine__kernel_maps(machine); union perf_event *event = zalloc(sizeof(event->mmap) + machine->id_hdr_size); @@ -33,11 +33,12 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, maps__for_each_entry(kmaps, pos) { struct kmap *kmap; size_t size; + struct map *map = pos->map; - if (!__map__is_extra_kernel_map(pos)) + if (!__map__is_extra_kernel_map(map)) continue; - kmap = map__kmap(pos); + kmap = map__kmap(map); size = sizeof(event->mmap) - sizeof(event->mmap.filename) + PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) + @@ -58,9 +59,9 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, event->mmap.header.size = size; - event->mmap.start = pos->start; - event->mmap.len = pos->end - pos->start; - event->mmap.pgoff = pos->pgoff; + event->mmap.start = map->start; + event->mmap.len = map->end - map->start; + event->mmap.pgoff = map->pgoff; event->mmap.pid = machine->pid; strlcpy(event->mmap.filename, kmap->name, PATH_MAX); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4011abc03d0d..c7e3863e8f44 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -844,9 +844,11 @@ static struct task *tasks_list(struct task *task, struct machine *machine) static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) { size_t printed = 0; - struct map *map; + struct map_rb_node *rb_node; + + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; - maps__for_each_entry(maps, map) { printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", indent, "", map->start, map->end, map->prot & PROT_READ ? 'r' : '-', diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index a69988a89d26..8246d37e4b7a 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -15,10 +15,12 @@ struct map_def { static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps) { - struct map *map; + struct map_rb_node *rb_node; unsigned int i = 0; - maps__for_each_entry(maps, map) { + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + if (i > 0) TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size)); @@ -74,7 +76,7 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest map->start = bpf_progs[i].start; map->end = bpf_progs[i].end; - maps__insert(maps, map); + TEST_ASSERT_VAL("failed to insert map", maps__insert(maps, map) == 0); map__put(map); } diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 8ab035b55875..c8abb3ca8347 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -118,7 +118,8 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused int err = TEST_FAIL; struct rb_node *nd; struct symbol *sym; - struct map *kallsyms_map, *vmlinux_map, *map; + struct map *kallsyms_map, *vmlinux_map; + struct map_rb_node *rb_node; struct machine kallsyms, vmlinux; struct maps *maps; u64 mem_start, mem_end; @@ -290,15 +291,15 @@ next_pair: header_printed = false; - maps__for_each_entry(maps, map) { - struct map * + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; /* * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while * the kernel will have the path for the vmlinux file being used, * so use the short name, less descriptive but the same ("[kernel]" in * both cases. */ - pair = maps__find_by_name(kallsyms.kmaps, (map->dso->kernel ? + struct map *pair = maps__find_by_name(kallsyms.kmaps, (map->dso->kernel ? map->dso->short_name : map->dso->name)); if (pair) { @@ -314,8 +315,8 @@ next_pair: header_printed = false; - maps__for_each_entry(maps, map) { - struct map *pair; + maps__for_each_entry(maps, rb_node) { + struct map *pair, *map = rb_node->map; mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start); mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end); @@ -344,7 +345,9 @@ next_pair: maps = machine__kernel_maps(&kallsyms); - maps__for_each_entry(maps, map) { + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + if (!map->priv) { if (!header_printed) { pr_info("WARN: Maps only in kallsyms:\n"); diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index b3e8aa9cd011..8a5d0eb44189 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -284,7 +284,7 @@ int lock_contention_read(struct lock_contention *con) } /* make sure it loads the kernel map */ - map__load(maps__first(machine->kmaps)); + map__load(maps__first(machine->kmaps)->map); prev_key = NULL; while (!bpf_map_get_next_key(fd, prev_key, &key)) { diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 3182815c73c6..2058623726d2 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -883,6 +883,7 @@ static int machine__process_ksymbol_register(struct machine *machine, if (!map) { struct dso *dso = dso__new(event->ksymbol.name); + int err; if (dso) { dso->kernel = DSO_SPACE__KERNEL; @@ -902,8 +903,11 @@ static int machine__process_ksymbol_register(struct machine *machine, map->start = event->ksymbol.addr; map->end = map->start + event->ksymbol.len; - maps__insert(machine__kernel_maps(machine), map); + err = maps__insert(machine__kernel_maps(machine), map); map__put(map); + if (err) + return err; + dso__set_loaded(dso); if (is_bpf_image(event->ksymbol.name)) { @@ -1003,6 +1007,7 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start struct map *map = NULL; struct kmod_path m; struct dso *dso; + int err; if (kmod_path__parse_name(&m, filename)) return NULL; @@ -1015,10 +1020,14 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start if (map == NULL) goto out; - maps__insert(machine__kernel_maps(machine), map); + err = maps__insert(machine__kernel_maps(machine), map); /* Put the map here because maps__insert already got it */ map__put(map); + + /* If maps__insert failed, return NULL. */ + if (err) + map = NULL; out: /* put the dso here, corresponding to machine__findnew_module_dso */ dso__put(dso); @@ -1185,10 +1194,11 @@ int machine__create_extra_kernel_map(struct machine *machine, { struct kmap *kmap; struct map *map; + int err; map = map__new2(xm->start, kernel); if (!map) - return -1; + return -ENOMEM; map->end = xm->end; map->pgoff = xm->pgoff; @@ -1197,14 +1207,16 @@ int machine__create_extra_kernel_map(struct machine *machine, strlcpy(kmap->name, xm->name, KMAP_NAME_LEN); - maps__insert(machine__kernel_maps(machine), map); + err = maps__insert(machine__kernel_maps(machine), map); - pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n", - kmap->name, map->start, map->end); + if (!err) { + pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n", + kmap->name, map->start, map->end); + } map__put(map); - return 0; + return err; } static u64 find_entry_trampoline(struct dso *dso) @@ -1245,16 +1257,16 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, struct maps *kmaps = machine__kernel_maps(machine); int nr_cpus_avail, cpu; bool found = false; - struct map *map; + struct map_rb_node *rb_node; u64 pgoff; /* * In the vmlinux case, pgoff is a virtual address which must now be * mapped to a vmlinux offset. */ - maps__for_each_entry(kmaps, map) { + maps__for_each_entry(kmaps, rb_node) { + struct map *dest_map, *map = rb_node->map; struct kmap *kmap = __map__kmap(map); - struct map *dest_map; if (!kmap || !is_entry_trampoline(kmap->name)) continue; @@ -1309,11 +1321,10 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) machine->vmlinux_map = map__new2(0, kernel); if (machine->vmlinux_map == NULL) - return -1; + return -ENOMEM; machine->vmlinux_map->map_ip = machine->vmlinux_map->unmap_ip = identity__map_ip; - maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); - return 0; + return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); } void machine__destroy_kernel_maps(struct machine *machine) @@ -1635,25 +1646,26 @@ static void machine__set_kernel_mmap(struct machine *machine, machine->vmlinux_map->end = ~0ULL; } -static void machine__update_kernel_mmap(struct machine *machine, +static int machine__update_kernel_mmap(struct machine *machine, u64 start, u64 end) { struct map *map = machine__kernel_map(machine); + int err; map__get(map); maps__remove(machine__kernel_maps(machine), map); machine__set_kernel_mmap(machine, start, end); - maps__insert(machine__kernel_maps(machine), map); + err = maps__insert(machine__kernel_maps(machine), map); map__put(map); + return err; } int machine__create_kernel_maps(struct machine *machine) { struct dso *kernel = machine__get_kernel(machine); const char *name = NULL; - struct map *map; u64 start = 0, end = ~0ULL; int ret; @@ -1685,7 +1697,9 @@ int machine__create_kernel_maps(struct machine *machine) * we have a real start address now, so re-order the kmaps * assume it's the last in the kmaps */ - machine__update_kernel_mmap(machine, start, end); + ret = machine__update_kernel_mmap(machine, start, end); + if (ret < 0) + goto out_put; } if (machine__create_extra_kernel_maps(machine, kernel)) @@ -1693,9 +1707,12 @@ int machine__create_kernel_maps(struct machine *machine) if (end == ~0ULL) { /* update end address of the kernel map using adjacent module address */ - map = map__next(machine__kernel_map(machine)); - if (map) - machine__set_kernel_mmap(machine, start, map->start); + struct map_rb_node *rb_node = maps__find_node(machine__kernel_maps(machine), + machine__kernel_map(machine)); + struct map_rb_node *next = map_rb_node__next(rb_node); + + if (next) + machine__set_kernel_mmap(machine, start, next->map->start); } out_put: @@ -1828,7 +1845,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine, if (strstr(kernel->long_name, "vmlinux")) dso__set_short_name(kernel, "[kernel.vmlinux]", false); - machine__update_kernel_mmap(machine, xm->start, xm->end); + if (machine__update_kernel_mmap(machine, xm->start, xm->end) < 0) { + dso__put(kernel); + goto out_problem; + } if (build_id__is_defined(bid)) dso__set_build_id(kernel, bid); @@ -3330,11 +3350,11 @@ int machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv) { struct maps *maps = machine__kernel_maps(machine); - struct map *map; + struct map_rb_node *pos; int err = 0; - for (map = maps__first(maps); map != NULL; map = map__next(map)) { - err = fn(map, priv); + maps__for_each_entry(maps, pos) { + err = fn(pos->map, priv); if (err != 0) { break; } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index f3a3d9b3a40d..7620cfa114d4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -111,7 +111,6 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) map->dso = dso__get(dso); map->map_ip = map__map_ip; map->unmap_ip = map__unmap_ip; - RB_CLEAR_NODE(&map->rb_node); map->erange_warned = false; refcount_set(&map->refcnt, 1); } @@ -397,7 +396,6 @@ struct map *map__clone(struct map *from) map = memdup(from, size); if (map != NULL) { refcount_set(&map->refcnt, 1); - RB_CLEAR_NODE(&map->rb_node); dso__get(map->dso); } @@ -537,20 +535,6 @@ bool map__contains_symbol(const struct map *map, const struct symbol *sym) return ip >= map->start && ip < map->end; } -static struct map *__map__next(struct map *map) -{ - struct rb_node *next = rb_next(&map->rb_node); - - if (next) - return rb_entry(next, struct map, rb_node); - return NULL; -} - -struct map *map__next(struct map *map) -{ - return map ? __map__next(map) : NULL; -} - struct kmap *__map__kmap(struct map *map) { if (!map->dso || !map->dso->kernel) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 2879cae05ee0..d1a6f85fd31d 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -16,7 +16,6 @@ struct maps; struct machine; struct map { - struct rb_node rb_node; u64 start; u64 end; bool erange_warned:1; diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 37bd5b40000d..83ec126bcbe5 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -10,8 +10,6 @@ #include "ui/ui.h" #include "unwind.h" -static void __maps__insert(struct maps *maps, struct map *map); - static void maps__init(struct maps *maps, struct machine *machine) { maps->entries = RB_ROOT; @@ -32,10 +30,44 @@ static void __maps__free_maps_by_name(struct maps *maps) maps->nr_maps_allocated = 0; } -void maps__insert(struct maps *maps, struct map *map) +static int __maps__insert(struct maps *maps, struct map *map) { + struct rb_node **p = &maps->entries.rb_node; + struct rb_node *parent = NULL; + const u64 ip = map->start; + struct map_rb_node *m, *new_rb_node; + + new_rb_node = malloc(sizeof(*new_rb_node)); + if (!new_rb_node) + return -ENOMEM; + + RB_CLEAR_NODE(&new_rb_node->rb_node); + new_rb_node->map = map; + + while (*p != NULL) { + parent = *p; + m = rb_entry(parent, struct map_rb_node, rb_node); + if (ip < m->map->start) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&new_rb_node->rb_node, parent, p); + rb_insert_color(&new_rb_node->rb_node, &maps->entries); + map__get(map); + return 0; +} + +int maps__insert(struct maps *maps, struct map *map) +{ + int err; + down_write(&maps->lock); - __maps__insert(maps, map); + err = __maps__insert(maps, map); + if (err) + goto out; + ++maps->nr_maps; if (map->dso && map->dso->kernel) { @@ -59,32 +91,39 @@ void maps__insert(struct maps *maps, struct map *map) if (maps_by_name == NULL) { __maps__free_maps_by_name(maps); - up_write(&maps->lock); - return; + err = -ENOMEM; + goto out; } maps->maps_by_name = maps_by_name; maps->nr_maps_allocated = nr_allocate; - } +} maps->maps_by_name[maps->nr_maps - 1] = map; __maps__sort_by_name(maps); } + out: up_write(&maps->lock); + return err; } -static void __maps__remove(struct maps *maps, struct map *map) +static void __maps__remove(struct maps *maps, struct map_rb_node *rb_node) { - rb_erase_init(&map->rb_node, &maps->entries); - map__put(map); + rb_erase_init(&rb_node->rb_node, &maps->entries); + map__put(rb_node->map); + free(rb_node); } void maps__remove(struct maps *maps, struct map *map) { + struct map_rb_node *rb_node; + down_write(&maps->lock); if (maps->last_search_by_name == map) maps->last_search_by_name = NULL; - __maps__remove(maps, map); + rb_node = maps__find_node(maps, map); + assert(rb_node->map == map); + __maps__remove(maps, rb_node); --maps->nr_maps; if (maps->maps_by_name) __maps__free_maps_by_name(maps); @@ -93,11 +132,12 @@ void maps__remove(struct maps *maps, struct map *map) static void __maps__purge(struct maps *maps) { - struct map *pos, *next; + struct map_rb_node *pos, *next; maps__for_each_entry_safe(maps, pos, next) { rb_erase_init(&pos->rb_node, &maps->entries); - map__put(pos); + map__put(pos->map); + free(pos); } } @@ -153,21 +193,21 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) { struct symbol *sym; - struct map *pos; + struct map_rb_node *pos; down_read(&maps->lock); maps__for_each_entry(maps, pos) { - sym = map__find_symbol_by_name(pos, name); + sym = map__find_symbol_by_name(pos->map, name); if (sym == NULL) continue; - if (!map__contains_symbol(pos, sym)) { + if (!map__contains_symbol(pos->map, sym)) { sym = NULL; continue; } if (mapp != NULL) - *mapp = pos; + *mapp = pos->map; goto out; } @@ -196,15 +236,15 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) size_t maps__fprintf(struct maps *maps, FILE *fp) { size_t printed = 0; - struct map *pos; + struct map_rb_node *pos; down_read(&maps->lock); maps__for_each_entry(maps, pos) { printed += fprintf(fp, "Map:"); - printed += map__fprintf(pos, fp); + printed += map__fprintf(pos->map, fp); if (verbose > 2) { - printed += dso__fprintf(pos->dso, fp); + printed += dso__fprintf(pos->map->dso, fp); printed += fprintf(fp, "--\n"); } } @@ -231,11 +271,11 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) next = root->rb_node; first = NULL; while (next) { - struct map *pos = rb_entry(next, struct map, rb_node); + struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); - if (pos->end > map->start) { + if (pos->map->end > map->start) { first = next; - if (pos->start <= map->start) + if (pos->map->start <= map->start) break; next = next->rb_left; } else @@ -244,14 +284,14 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) next = first; while (next) { - struct map *pos = rb_entry(next, struct map, rb_node); + struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); next = rb_next(&pos->rb_node); /* * Stop if current map starts after map->end. * Maps are ordered by start: next will not overlap for sure. */ - if (pos->start >= map->end) + if (pos->map->start >= map->end) break; if (verbose >= 2) { @@ -262,7 +302,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) } else { fputs("overlapping maps:\n", fp); map__fprintf(map, fp); - map__fprintf(pos, fp); + map__fprintf(pos->map, fp); } } @@ -271,8 +311,8 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) * Now check if we need to create new maps for areas not * overlapped by the new map: */ - if (map->start > pos->start) { - struct map *before = map__clone(pos); + if (map->start > pos->map->start) { + struct map *before = map__clone(pos->map); if (before == NULL) { err = -ENOMEM; @@ -280,14 +320,17 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) } before->end = map->start; - __maps__insert(maps, before); + err = __maps__insert(maps, before); + if (err) + goto put_map; + if (verbose >= 2 && !use_browser) map__fprintf(before, fp); map__put(before); } - if (map->end < pos->end) { - struct map *after = map__clone(pos); + if (map->end < pos->map->end) { + struct map *after = map__clone(pos->map); if (after == NULL) { err = -ENOMEM; @@ -295,15 +338,19 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) } after->start = map->end; - after->pgoff += map->end - pos->start; - assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); - __maps__insert(maps, after); + after->pgoff += map->end - pos->map->start; + assert(pos->map->map_ip(pos->map, map->end) == + after->map_ip(after, map->end)); + err = __maps__insert(maps, after); + if (err) + goto put_map; + if (verbose >= 2 && !use_browser) map__fprintf(after, fp); map__put(after); } put_map: - map__put(pos); + map__put(pos->map); if (err) goto out; @@ -322,12 +369,12 @@ int maps__clone(struct thread *thread, struct maps *parent) { struct maps *maps = thread->maps; int err; - struct map *map; + struct map_rb_node *rb_node; down_read(&parent->lock); - maps__for_each_entry(parent, map) { - struct map *new = map__clone(map); + maps__for_each_entry(parent, rb_node) { + struct map *new = map__clone(rb_node->map); if (new == NULL) { err = -ENOMEM; @@ -338,7 +385,10 @@ int maps__clone(struct thread *thread, struct maps *parent) if (err) goto out_unlock; - maps__insert(maps, new); + err = maps__insert(maps, new); + if (err) + goto out_unlock; + map__put(new); } @@ -348,40 +398,31 @@ out_unlock: return err; } -static void __maps__insert(struct maps *maps, struct map *map) +struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) { - struct rb_node **p = &maps->entries.rb_node; - struct rb_node *parent = NULL; - const u64 ip = map->start; - struct map *m; + struct map_rb_node *rb_node; - while (*p != NULL) { - parent = *p; - m = rb_entry(parent, struct map, rb_node); - if (ip < m->start) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; + maps__for_each_entry(maps, rb_node) { + if (rb_node->map == map) + return rb_node; } - - rb_link_node(&map->rb_node, parent, p); - rb_insert_color(&map->rb_node, &maps->entries); - map__get(map); + return NULL; } struct map *maps__find(struct maps *maps, u64 ip) { struct rb_node *p; - struct map *m; + struct map_rb_node *m; + down_read(&maps->lock); p = maps->entries.rb_node; while (p != NULL) { - m = rb_entry(p, struct map, rb_node); - if (ip < m->start) + m = rb_entry(p, struct map_rb_node, rb_node); + if (ip < m->map->start) p = p->rb_left; - else if (ip >= m->end) + else if (ip >= m->map->end) p = p->rb_right; else goto out; @@ -390,14 +431,29 @@ struct map *maps__find(struct maps *maps, u64 ip) m = NULL; out: up_read(&maps->lock); - return m; + return m ? m->map : NULL; } -struct map *maps__first(struct maps *maps) +struct map_rb_node *maps__first(struct maps *maps) { struct rb_node *first = rb_first(&maps->entries); if (first) - return rb_entry(first, struct map, rb_node); + return rb_entry(first, struct map_rb_node, rb_node); return NULL; } + +struct map_rb_node *map_rb_node__next(struct map_rb_node *node) +{ + struct rb_node *next; + + if (!node) + return NULL; + + next = rb_next(&node->rb_node); + + if (!next) + return NULL; + + return rb_entry(next, struct map_rb_node, rb_node); +} diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 7e729ff42749..512746ec0f9a 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -15,15 +15,22 @@ struct map; struct maps; struct thread; +struct map_rb_node { + struct rb_node rb_node; + struct map *map; +}; + +struct map_rb_node *maps__first(struct maps *maps); +struct map_rb_node *map_rb_node__next(struct map_rb_node *node); +struct map_rb_node *maps__find_node(struct maps *maps, struct map *map); struct map *maps__find(struct maps *maps, u64 addr); -struct map *maps__first(struct maps *maps); -struct map *map__next(struct map *map); #define maps__for_each_entry(maps, map) \ - for (map = maps__first(maps); map; map = map__next(map)) + for (map = maps__first(maps); map; map = map_rb_node__next(map)) #define maps__for_each_entry_safe(maps, map, next) \ - for (map = maps__first(maps), next = map__next(map); map; map = next, next = map__next(map)) + for (map = maps__first(maps), next = map_rb_node__next(map); map; \ + map = next, next = map_rb_node__next(map)) struct maps { struct rb_root entries; @@ -63,7 +70,7 @@ void maps__put(struct maps *maps); int maps__clone(struct thread *thread, struct maps *parent); size_t maps__fprintf(struct maps *maps, FILE *fp); -void maps__insert(struct maps *maps, struct map *map); +int maps__insert(struct maps *maps, struct map *map); void maps__remove(struct maps *maps, struct map *map); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 881d94f65a6b..cdf5d655d84c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -151,23 +151,27 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, static struct map *kernel_get_module_map(const char *module) { struct maps *maps = machine__kernel_maps(host_machine); - struct map *pos; + struct map_rb_node *pos; /* A file path -- this is an offline module */ if (module && strchr(module, '/')) return dso__new_map(module); if (!module) { - pos = machine__kernel_map(host_machine); - return map__get(pos); + struct map *map = machine__kernel_map(host_machine); + + return map__get(map); } maps__for_each_entry(maps, pos) { /* short_name is "[module]" */ - if (strncmp(pos->dso->short_name + 1, module, - pos->dso->short_name_len - 2) == 0 && - module[pos->dso->short_name_len - 2] == '\0') { - return map__get(pos); + const char *short_name = pos->map->dso->short_name; + u16 short_name_len = pos->map->dso->short_name_len; + + if (strncmp(short_name + 1, module, + short_name_len - 2) == 0 && + module[short_name_len - 2] == '\0') { + return map__get(pos->map); } } return NULL; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index ae810d4cf3cd..33e1f587baa9 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1361,10 +1361,14 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, map->unmap_ip = map__unmap_ip; /* Ensure maps are correctly ordered */ if (kmaps) { + int err; + map__get(map); maps__remove(kmaps, map); - maps__insert(kmaps, map); + err = maps__insert(kmaps, map); map__put(map); + if (err) + return err; } } @@ -1417,7 +1421,8 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; } curr_dso->symtab_type = dso->symtab_type; - maps__insert(kmaps, curr_map); + if (maps__insert(kmaps, curr_map)) + return -1; /* * Add it before we drop the reference to curr_map, i.e. while * we still are sure to have a reference to this DSO via diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8719074b7f21..e7a8ae290c57 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -273,13 +273,13 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) void maps__fixup_end(struct maps *maps) { - struct map *prev = NULL, *curr; + struct map_rb_node *prev = NULL, *curr; down_write(&maps->lock); maps__for_each_entry(maps, curr) { - if (prev != NULL && !prev->end) - prev->end = curr->start; + if (prev != NULL && !prev->map->end) + prev->map->end = curr->map->start; prev = curr; } @@ -288,8 +288,8 @@ void maps__fixup_end(struct maps *maps) * We still haven't the actual symbols, so guess the * last map final address. */ - if (curr && !curr->end) - curr->end = ~0ULL; + if (curr && !curr->map->end) + curr->map->end = ~0ULL; up_write(&maps->lock); } @@ -942,7 +942,10 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, } curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; - maps__insert(kmaps, curr_map); + if (maps__insert(kmaps, curr_map)) { + dso__put(ndso); + return -1; + } ++kernel_range; } else if (delta) { /* Kernel was relocated at boot time */ @@ -1130,14 +1133,15 @@ out_delete_from: static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) { struct rb_root modules = RB_ROOT; - struct map *old_map; + struct map_rb_node *old_node; int err; err = read_proc_modules(filename, &modules); if (err) return err; - maps__for_each_entry(kmaps, old_map) { + maps__for_each_entry(kmaps, old_node) { + struct map *old_map = old_node->map; struct module_info *mi; if (!__map__is_kmodule(old_map)) { @@ -1254,10 +1258,13 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) */ int maps__merge_in(struct maps *kmaps, struct map *new_map) { - struct map *old_map; + struct map_rb_node *rb_node; LIST_HEAD(merged); + int err = 0; + + maps__for_each_entry(kmaps, rb_node) { + struct map *old_map = rb_node->map; - maps__for_each_entry(kmaps, old_map) { /* no overload with this one */ if (new_map->end < old_map->start || new_map->start >= old_map->end) @@ -1281,13 +1288,16 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) */ struct map_list_node *m = map_list_node__new(); - if (!m) - return -ENOMEM; + if (!m) { + err = -ENOMEM; + goto out; + } m->map = map__clone(new_map); if (!m->map) { free(m); - return -ENOMEM; + err = -ENOMEM; + goto out; } m->map->end = old_map->start; @@ -1319,21 +1329,24 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) } } +out: while (!list_empty(&merged)) { struct map_list_node *old_node; old_node = list_entry(merged.next, struct map_list_node, node); list_del_init(&old_node->node); - maps__insert(kmaps, old_node->map); + if (!err) + err = maps__insert(kmaps, old_node->map); map__put(old_node->map); free(old_node); } if (new_map) { - maps__insert(kmaps, new_map); + if (!err) + err = maps__insert(kmaps, new_map); map__put(new_map); } - return 0; + return err; } static int dso__load_kcore(struct dso *dso, struct map *map, @@ -1341,7 +1354,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, { struct maps *kmaps = map__kmaps(map); struct kcore_mapfn_data md; - struct map *old_map, *replacement_map = NULL, *next; + struct map *replacement_map = NULL; + struct map_rb_node *old_node, *next; struct machine *machine; bool is_64_bit; int err, fd; @@ -1388,7 +1402,9 @@ static int dso__load_kcore(struct dso *dso, struct map *map, } /* Remove old maps */ - maps__for_each_entry_safe(kmaps, old_map, next) { + maps__for_each_entry_safe(kmaps, old_node, next) { + struct map *old_map = old_node->map; + /* * We need to preserve eBPF maps even if they are * covered by kcore, because we need to access @@ -1443,17 +1459,21 @@ static int dso__load_kcore(struct dso *dso, struct map *map, /* Ensure maps are correctly ordered */ map__get(map); maps__remove(kmaps, map); - maps__insert(kmaps, map); + err = maps__insert(kmaps, map); map__put(map); map__put(new_map); + if (err) + goto out_err; } else { /* * Merge kcore map into existing maps, * and ensure that current maps (eBPF) * stay intact. */ - if (maps__merge_in(kmaps, new_map)) + if (maps__merge_in(kmaps, new_map)) { + err = -EINVAL; goto out_err; + } } free(new_node); } @@ -1500,7 +1520,7 @@ out_err: free(list_node); } close(fd); - return -EINVAL; + return err; } /* @@ -2044,8 +2064,9 @@ void __maps__sort_by_name(struct maps *maps) static int map__groups__sort_by_name_from_rbtree(struct maps *maps) { - struct map *map; - struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map)); + struct map_rb_node *rb_node; + struct map **maps_by_name = realloc(maps->maps_by_name, + maps->nr_maps * sizeof(struct map *)); int i = 0; if (maps_by_name == NULL) @@ -2057,8 +2078,8 @@ static int map__groups__sort_by_name_from_rbtree(struct maps *maps) maps->maps_by_name = maps_by_name; maps->nr_maps_allocated = maps->nr_maps; - maps__for_each_entry(maps, map) - maps_by_name[i++] = map; + maps__for_each_entry(maps, rb_node) + maps_by_name[i++] = rb_node->map; __maps__sort_by_name(maps); @@ -2084,6 +2105,7 @@ static struct map *__maps__find_by_name(struct maps *maps, const char *name) struct map *maps__find_by_name(struct maps *maps, const char *name) { + struct map_rb_node *rb_node; struct map *map; down_read(&maps->lock); @@ -2102,12 +2124,13 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) goto out_unlock; /* Fallback to traversing the rbtree... */ - maps__for_each_entry(maps, map) + maps__for_each_entry(maps, rb_node) { + map = rb_node->map; if (strcmp(map->dso->short_name, name) == 0) { maps->last_search_by_name = map; goto out_unlock; } - + } map = NULL; out_unlock: diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index 6def01036eb5..57b95c1d7e39 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -669,7 +669,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t struct machine *machine) { int rc = 0; - struct map *pos; + struct map_rb_node *pos; struct maps *maps = machine__kernel_maps(machine); union perf_event *event; size_t size = symbol_conf.buildid_mmap2 ? @@ -692,37 +692,39 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; maps__for_each_entry(maps, pos) { - if (!__map__is_kmodule(pos)) + struct map *map = pos->map; + + if (!__map__is_kmodule(map)) continue; if (symbol_conf.buildid_mmap2) { - size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); + size = PERF_ALIGN(map->dso->long_name_len + 1, sizeof(u64)); event->mmap2.header.type = PERF_RECORD_MMAP2; event->mmap2.header.size = (sizeof(event->mmap2) - (sizeof(event->mmap2.filename) - size)); memset(event->mmap2.filename + size, 0, machine->id_hdr_size); event->mmap2.header.size += machine->id_hdr_size; - event->mmap2.start = pos->start; - event->mmap2.len = pos->end - pos->start; + event->mmap2.start = map->start; + event->mmap2.len = map->end - map->start; event->mmap2.pid = machine->pid; - memcpy(event->mmap2.filename, pos->dso->long_name, - pos->dso->long_name_len + 1); + memcpy(event->mmap2.filename, map->dso->long_name, + map->dso->long_name_len + 1); perf_record_mmap2__read_build_id(&event->mmap2, machine, false); } else { - size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); + size = PERF_ALIGN(map->dso->long_name_len + 1, sizeof(u64)); event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); memset(event->mmap.filename + size, 0, machine->id_hdr_size); event->mmap.header.size += machine->id_hdr_size; - event->mmap.start = pos->start; - event->mmap.len = pos->end - pos->start; + event->mmap.start = map->start; + event->mmap.len = map->end - map->start; event->mmap.pid = machine->pid; - memcpy(event->mmap.filename, pos->dso->long_name, - pos->dso->long_name_len + 1); + memcpy(event->mmap.filename, map->dso->long_name, + map->dso->long_name_len + 1); } if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index a2490a20eb56..24e53bd55f7d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -352,9 +352,7 @@ int thread__insert_map(struct thread *thread, struct map *map) return ret; maps__fixup_overlappings(thread->maps, map, stderr); - maps__insert(thread->maps, map); - - return 0; + return maps__insert(thread->maps, map); } static int __thread__prepare_access(struct thread *thread) @@ -362,12 +360,12 @@ static int __thread__prepare_access(struct thread *thread) bool initialized = false; int err = 0; struct maps *maps = thread->maps; - struct map *map; + struct map_rb_node *rb_node; down_read(&maps->lock); - maps__for_each_entry(maps, map) { - err = unwind__prepare_access(thread->maps, map, &initialized); + maps__for_each_entry(maps, rb_node) { + err = unwind__prepare_access(thread->maps, rb_node->map, &initialized); if (err || initialized) break; } diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 81b6bd6e1536..dea70a477b91 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -306,7 +306,7 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, u64 *table_data, u64 *segbase, u64 *fde_count) { - struct map *map; + struct map_rb_node *map_node; u64 base_addr = UINT64_MAX; int ret, fd; @@ -325,7 +325,9 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, return -EINVAL; } - maps__for_each_entry(ui->thread->maps, map) { + maps__for_each_entry(ui->thread->maps, map_node) { + struct map *map = map_node->map; + if (map->dso == dso && map->start < base_addr) base_addr = map->start; } diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 43beb169631d..835c39efb80d 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -144,10 +144,11 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { enum dso_type dso_type = DSO__TYPE_UNKNOWN; - struct map *map; + struct map_rb_node *rb_node; + + maps__for_each_entry(thread->maps, rb_node) { + struct dso *dso = rb_node->map->dso; - maps__for_each_entry(thread->maps, map) { - struct dso *dso = map->dso; if (!dso || dso->long_name[0] != '/') continue; dso_type = dso__type(dso, machine); -- cgit v1.2.3 From 5ab6d715c32f6249415bcd1972bae7e6c03636f0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 20 Mar 2023 14:22:34 -0700 Subject: perf maps: Add functions to access maps Introduce functions to access struct maps. These functions reduce the number of places reference counting is necessary. While tidying APIs do some small const-ification, in particlar to unwind_libunwind_ops. Committer notes: Fixed up tools/perf/util/unwind-libunwind.c: - return ops->get_entries(cb, arg, thread, data, max_stack); + return ops->get_entries(cb, arg, thread, data, max_stack, best_effort); Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320212248.1175731-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 7 ++- tools/perf/tests/code-reading.c | 2 +- tools/perf/ui/browsers/hists.c | 3 +- tools/perf/util/callchain.c | 9 +-- tools/perf/util/db-export.c | 12 ++-- tools/perf/util/dlfilter.c | 8 ++- tools/perf/util/event.c | 4 +- tools/perf/util/hist.c | 2 +- tools/perf/util/machine.c | 2 +- tools/perf/util/map.c | 14 +++-- tools/perf/util/maps.c | 71 ++++++++++++---------- tools/perf/util/maps.h | 47 +++++++++++--- .../util/scripting-engines/trace-event-python.c | 2 +- tools/perf/util/sort.c | 2 +- tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.c | 44 +++++++------- tools/perf/util/thread-stack.c | 4 +- tools/perf/util/thread.c | 4 +- tools/perf/util/unwind-libunwind-local.c | 16 ++--- tools/perf/util/unwind-libunwind.c | 31 ++++++---- 20 files changed, 175 insertions(+), 111 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index b0d449f41650..feedd02b3b3d 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -100,10 +100,11 @@ static PyObject *perf_sample_insn(PyObject *obj, PyObject *args) if (!c) return NULL; - if (c->sample->ip && !c->sample->insn_len && - c->al->thread->maps && c->al->thread->maps->machine) - script_fetch_insn(c->sample, c->al->thread, c->al->thread->maps->machine); + if (c->sample->ip && !c->sample->insn_len && c->al->thread->maps) { + struct machine *machine = maps__machine(c->al->thread->maps); + script_fetch_insn(c->sample, c->al->thread, machine); + } if (!c->sample->insn_len) Py_RETURN_NONE; /* N.B. This is a return statement */ diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index fb67fd5ebd9f..8d2036f2f944 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -269,7 +269,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len = al.map->end - addr; /* Read the object code using perf */ - ret_len = dso__data_read_offset(al.map->dso, thread->maps->machine, + ret_len = dso__data_read_offset(al.map->dso, maps__machine(thread->maps), al.addr, buf1, len); if (ret_len != len) { pr_debug("dso__data_read_offset failed\n"); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index b72ee6822222..572ff38ceb0f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3139,7 +3139,8 @@ do_hotkey: // key came straight from options ui__popup_menu() continue; case 'k': if (browser->selection != NULL) - hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map); + hists_browser__zoom_map(browser, + maps__machine(browser->selection->maps)->vmlinux_map); continue; case 'V': verbose = (verbose + 1) % 4; diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index a093a15f048f..0aa979f64565 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -1112,6 +1112,8 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, bool hide_unresolved) { + struct machine *machine = maps__machine(node->ms.maps); + al->maps = node->ms.maps; al->map = node->ms.map; al->sym = node->ms.sym; @@ -1124,9 +1126,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * if (al->map == NULL) goto out; } - - if (al->maps == machine__kernel_maps(al->maps->machine)) { - if (machine__is_host(al->maps->machine)) { + if (al->maps == machine__kernel_maps(machine)) { + if (machine__is_host(machine)) { al->cpumode = PERF_RECORD_MISC_KERNEL; al->level = 'k'; } else { @@ -1134,7 +1135,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * al->level = 'g'; } } else { - if (machine__is_host(al->maps->machine)) { + if (machine__is_host(machine)) { al->cpumode = PERF_RECORD_MISC_USER; al->level = '.'; } else if (perf_guest) { diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index e0d4f08839fb..1cfcfdd3cf52 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -181,7 +181,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, if (al->map) { struct dso *dso = al->map->dso; - err = db_export__dso(dbe, dso, al->maps->machine); + err = db_export__dso(dbe, dso, maps__machine(al->maps)); if (err) return err; *dso_db_id = dso->db_id; @@ -354,19 +354,21 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, }; struct thread *main_thread; struct comm *comm = NULL; + struct machine *machine; int err; err = db_export__evsel(dbe, evsel); if (err) return err; - err = db_export__machine(dbe, al->maps->machine); + machine = maps__machine(al->maps); + err = db_export__machine(dbe, machine); if (err) return err; - main_thread = thread__main_thread(al->maps->machine, thread); + main_thread = thread__main_thread(machine, thread); - err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm); + err = db_export__threads(dbe, thread, main_thread, machine, &comm); if (err) goto out_put; @@ -380,7 +382,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, goto out_put; if (dbe->cpr) { - struct call_path *cp = call_path_from_sample(dbe, al->maps->machine, + struct call_path *cp = call_path_from_sample(dbe, machine, thread, sample, evsel); if (cp) { diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 37beb7530288..fe2a0752a0f6 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -197,8 +197,12 @@ static const __u8 *dlfilter__insn(void *ctx, __u32 *len) if (!al->thread && machine__resolve(d->machine, al, d->sample) < 0) return NULL; - if (al->thread->maps && al->thread->maps->machine) - script_fetch_insn(d->sample, al->thread, al->thread->maps->machine); + if (al->thread->maps) { + struct machine *machine = maps__machine(al->thread->maps); + + if (machine) + script_fetch_insn(d->sample, al->thread, machine); + } } if (!d->sample->insn_len) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1fa14598b916..f40cdd6ac126 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -572,7 +572,7 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, struct addr_location *al) { struct maps *maps = thread->maps; - struct machine *machine = maps->machine; + struct machine *machine = maps__machine(maps); bool load_map = false; al->maps = maps; @@ -637,7 +637,7 @@ struct map *thread__find_map_fb(struct thread *thread, u8 cpumode, u64 addr, struct addr_location *al) { struct map *map = thread__find_map(thread, cpumode, addr, al); - struct machine *machine = thread->maps->machine; + struct machine *machine = maps__machine(thread->maps); u8 addr_cpumode = machine__addr_cpumode(machine, cpumode, addr); if (map || addr_cpumode == cpumode) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b339ff863fe2..5f9f38ed5da1 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -241,7 +241,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) if (h->cgroup) { const char *cgrp_name = "unknown"; - struct cgroup *cgrp = cgroup__find(h->ms.maps->machine->env, + struct cgroup *cgrp = cgroup__find(maps__machine(h->ms.maps)->env, h->cgroup); if (cgrp != NULL) cgrp_name = cgrp->name; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 2058623726d2..d6da4b5e1333 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2847,7 +2847,7 @@ static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, static u64 get_leaf_frame_caller(struct perf_sample *sample, struct thread *thread, int usr_idx) { - if (machine__normalized_is(thread->maps->machine, "arm64")) + if (machine__normalized_is(maps__machine(thread->maps), "arm64")) return get_leaf_frame_caller_aarch64(sample, thread, usr_idx); else return 0; diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 7620cfa114d4..a99dbde656a2 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -234,7 +234,7 @@ bool __map__is_kernel(const struct map *map) { if (!map->dso->kernel) return false; - return machine__kernel_map(map__kmaps((struct map *)map)->machine) == map; + return machine__kernel_map(maps__machine(map__kmaps((struct map *)map))) == map; } bool __map__is_extra_kernel_map(const struct map *map) @@ -475,11 +475,15 @@ u64 map__rip_2objdump(struct map *map, u64 rip) * kcore may not either. However the trampoline object code is on the * main kernel map, so just use that instead. */ - if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) { - struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine); + if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps) { + struct machine *machine = maps__machine(kmap->kmaps); - if (kernel_map) - map = kernel_map; + if (machine) { + struct map *kernel_map = machine__kernel_map(machine); + + if (kernel_map) + map = kernel_map; + } } if (!map->dso->adjust_symbols) diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 83ec126bcbe5..91bb015caede 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -13,7 +13,7 @@ static void maps__init(struct maps *maps, struct machine *machine) { maps->entries = RB_ROOT; - init_rwsem(&maps->lock); + init_rwsem(maps__lock(maps)); maps->machine = machine; maps->last_search_by_name = NULL; maps->nr_maps = 0; @@ -32,7 +32,7 @@ static void __maps__free_maps_by_name(struct maps *maps) static int __maps__insert(struct maps *maps, struct map *map) { - struct rb_node **p = &maps->entries.rb_node; + struct rb_node **p = &maps__entries(maps)->rb_node; struct rb_node *parent = NULL; const u64 ip = map->start; struct map_rb_node *m, *new_rb_node; @@ -54,7 +54,7 @@ static int __maps__insert(struct maps *maps, struct map *map) } rb_link_node(&new_rb_node->rb_node, parent, p); - rb_insert_color(&new_rb_node->rb_node, &maps->entries); + rb_insert_color(&new_rb_node->rb_node, maps__entries(maps)); map__get(map); return 0; } @@ -63,7 +63,7 @@ int maps__insert(struct maps *maps, struct map *map) { int err; - down_write(&maps->lock); + down_write(maps__lock(maps)); err = __maps__insert(maps, map); if (err) goto out; @@ -84,10 +84,11 @@ int maps__insert(struct maps *maps, struct map *map) * If we already performed some search by name, then we need to add the just * inserted map and resort. */ - if (maps->maps_by_name) { - if (maps->nr_maps > maps->nr_maps_allocated) { - int nr_allocate = maps->nr_maps * 2; - struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map)); + if (maps__maps_by_name(maps)) { + if (maps__nr_maps(maps) > maps->nr_maps_allocated) { + int nr_allocate = maps__nr_maps(maps) * 2; + struct map **maps_by_name = realloc(maps__maps_by_name(maps), + nr_allocate * sizeof(map)); if (maps_by_name == NULL) { __maps__free_maps_by_name(maps); @@ -97,18 +98,18 @@ int maps__insert(struct maps *maps, struct map *map) maps->maps_by_name = maps_by_name; maps->nr_maps_allocated = nr_allocate; -} - maps->maps_by_name[maps->nr_maps - 1] = map; + } + maps__maps_by_name(maps)[maps__nr_maps(maps) - 1] = map; __maps__sort_by_name(maps); } out: - up_write(&maps->lock); + up_write(maps__lock(maps)); return err; } static void __maps__remove(struct maps *maps, struct map_rb_node *rb_node) { - rb_erase_init(&rb_node->rb_node, &maps->entries); + rb_erase_init(&rb_node->rb_node, maps__entries(maps)); map__put(rb_node->map); free(rb_node); } @@ -117,7 +118,7 @@ void maps__remove(struct maps *maps, struct map *map) { struct map_rb_node *rb_node; - down_write(&maps->lock); + down_write(maps__lock(maps)); if (maps->last_search_by_name == map) maps->last_search_by_name = NULL; @@ -125,9 +126,9 @@ void maps__remove(struct maps *maps, struct map *map) assert(rb_node->map == map); __maps__remove(maps, rb_node); --maps->nr_maps; - if (maps->maps_by_name) + if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); - up_write(&maps->lock); + up_write(maps__lock(maps)); } static void __maps__purge(struct maps *maps) @@ -135,7 +136,7 @@ static void __maps__purge(struct maps *maps) struct map_rb_node *pos, *next; maps__for_each_entry_safe(maps, pos, next) { - rb_erase_init(&pos->rb_node, &maps->entries); + rb_erase_init(&pos->rb_node, maps__entries(maps)); map__put(pos->map); free(pos); } @@ -143,9 +144,9 @@ static void __maps__purge(struct maps *maps) static void maps__exit(struct maps *maps) { - down_write(&maps->lock); + down_write(maps__lock(maps)); __maps__purge(maps); - up_write(&maps->lock); + up_write(maps__lock(maps)); } bool maps__empty(struct maps *maps) @@ -170,6 +171,14 @@ void maps__delete(struct maps *maps) free(maps); } +struct maps *maps__get(struct maps *maps) +{ + if (maps) + refcount_inc(&maps->refcnt); + + return maps; +} + void maps__put(struct maps *maps) { if (maps && refcount_dec_and_test(&maps->refcnt)) @@ -195,7 +204,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, st struct symbol *sym; struct map_rb_node *pos; - down_read(&maps->lock); + down_read(maps__lock(maps)); maps__for_each_entry(maps, pos) { sym = map__find_symbol_by_name(pos->map, name); @@ -213,7 +222,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, st sym = NULL; out: - up_read(&maps->lock); + up_read(maps__lock(maps)); return sym; } @@ -238,7 +247,7 @@ size_t maps__fprintf(struct maps *maps, FILE *fp) size_t printed = 0; struct map_rb_node *pos; - down_read(&maps->lock); + down_read(maps__lock(maps)); maps__for_each_entry(maps, pos) { printed += fprintf(fp, "Map:"); @@ -249,7 +258,7 @@ size_t maps__fprintf(struct maps *maps, FILE *fp) } } - up_read(&maps->lock); + up_read(maps__lock(maps)); return printed; } @@ -260,9 +269,9 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) struct rb_node *next, *first; int err = 0; - down_write(&maps->lock); + down_write(maps__lock(maps)); - root = &maps->entries; + root = maps__entries(maps); /* * Find first map where end > map->start. @@ -358,7 +367,7 @@ put_map: err = 0; out: - up_write(&maps->lock); + up_write(maps__lock(maps)); return err; } @@ -371,7 +380,7 @@ int maps__clone(struct thread *thread, struct maps *parent) int err; struct map_rb_node *rb_node; - down_read(&parent->lock); + down_read(maps__lock(parent)); maps__for_each_entry(parent, rb_node) { struct map *new = map__clone(rb_node->map); @@ -394,7 +403,7 @@ int maps__clone(struct thread *thread, struct maps *parent) err = 0; out_unlock: - up_read(&parent->lock); + up_read(maps__lock(parent)); return err; } @@ -415,9 +424,9 @@ struct map *maps__find(struct maps *maps, u64 ip) struct map_rb_node *m; - down_read(&maps->lock); + down_read(maps__lock(maps)); - p = maps->entries.rb_node; + p = maps__entries(maps)->rb_node; while (p != NULL) { m = rb_entry(p, struct map_rb_node, rb_node); if (ip < m->map->start) @@ -430,13 +439,13 @@ struct map *maps__find(struct maps *maps, u64 ip) m = NULL; out: - up_read(&maps->lock); + up_read(maps__lock(maps)); return m ? m->map : NULL; } struct map_rb_node *maps__first(struct maps *maps) { - struct rb_node *first = rb_first(&maps->entries); + struct rb_node *first = rb_first(maps__entries(maps)); if (first) return rb_entry(first, struct map_rb_node, rb_node); diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 512746ec0f9a..bde3390c7096 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -43,7 +43,7 @@ struct maps { unsigned int nr_maps_allocated; #ifdef HAVE_LIBUNWIND_SUPPORT void *addr_space; - struct unwind_libunwind_ops *unwind_libunwind_ops; + const struct unwind_libunwind_ops *unwind_libunwind_ops; #endif }; @@ -58,20 +58,51 @@ struct kmap { struct maps *maps__new(struct machine *machine); void maps__delete(struct maps *maps); bool maps__empty(struct maps *maps); +int maps__clone(struct thread *thread, struct maps *parent); + +struct maps *maps__get(struct maps *maps); +void maps__put(struct maps *maps); -static inline struct maps *maps__get(struct maps *maps) +static inline struct rb_root *maps__entries(struct maps *maps) { - if (maps) - refcount_inc(&maps->refcnt); - return maps; + return &maps->entries; } -void maps__put(struct maps *maps); -int maps__clone(struct thread *thread, struct maps *parent); +static inline struct machine *maps__machine(struct maps *maps) +{ + return maps->machine; +} + +static inline struct rw_semaphore *maps__lock(struct maps *maps) +{ + return &maps->lock; +} + +static inline struct map **maps__maps_by_name(struct maps *maps) +{ + return maps->maps_by_name; +} + +static inline unsigned int maps__nr_maps(const struct maps *maps) +{ + return maps->nr_maps; +} + +#ifdef HAVE_LIBUNWIND_SUPPORT +static inline void *maps__addr_space(struct maps *maps) +{ + return maps->addr_space; +} + +static inline const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct maps *maps) +{ + return maps->unwind_libunwind_ops; +} +#endif + size_t maps__fprintf(struct maps *maps, FILE *fp); int maps__insert(struct maps *maps, struct map *map); - void maps__remove(struct maps *maps, struct map *map); struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 0f4ef61f2ffa..e5cc18f6fcda 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1288,7 +1288,7 @@ static void python_export_sample_table(struct db_export *dbe, tuple_set_d64(t, 0, es->db_id); tuple_set_d64(t, 1, es->evsel->db_id); - tuple_set_d64(t, 2, es->al->maps->machine->db_id); + tuple_set_d64(t, 2, maps__machine(es->al->maps)->db_id); tuple_set_d64(t, 3, es->al->thread->db_id); tuple_set_d64(t, 4, es->comm_db_id); tuple_set_d64(t, 5, es->dso_db_id); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 2b5cc8e4aa6e..430f67e7cc82 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -803,7 +803,7 @@ static int hist_entry__cgroup_snprintf(struct hist_entry *he, const char *cgrp_name = "N/A"; if (he->cgroup) { - struct cgroup *cgrp = cgroup__find(he->ms.maps->machine->env, + struct cgroup *cgrp = cgroup__find(maps__machine(he->ms.maps)->env, he->cgroup); if (cgrp != NULL) cgrp_name = cgrp->name; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 33e1f587baa9..3084e556d3eb 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1428,7 +1428,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, * we still are sure to have a reference to this DSO via * *curr_map->dso. */ - dsos__add(&kmaps->machine->dsos, curr_dso); + dsos__add(&maps__machine(kmaps)->dsos, curr_dso); /* kmaps already got it */ map__put(curr_map); dso__set_loaded(curr_dso); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7a8ae290c57..316b63fb5691 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -275,7 +275,7 @@ void maps__fixup_end(struct maps *maps) { struct map_rb_node *prev = NULL, *curr; - down_write(&maps->lock); + down_write(maps__lock(maps)); maps__for_each_entry(maps, curr) { if (prev != NULL && !prev->map->end) @@ -291,7 +291,7 @@ void maps__fixup_end(struct maps *maps) if (curr && !curr->map->end) curr->map->end = ~0ULL; - up_write(&maps->lock); + up_write(maps__lock(maps)); } struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) @@ -844,7 +844,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, if (!kmaps) return -1; - machine = kmaps->machine; + machine = maps__machine(kmaps); x86_64 = machine__is(machine, "x86_64"); @@ -968,7 +968,7 @@ discard_symbol: if (curr_map != initial_map && dso->kernel == DSO_SPACE__KERNEL_GUEST && - machine__is_default_guest(kmaps->machine)) { + machine__is_default_guest(maps__machine(kmaps))) { dso__set_loaded(curr_map->dso); } @@ -1365,7 +1365,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, if (!kmaps) return -EINVAL; - machine = kmaps->machine; + machine = maps__machine(kmaps); /* This function requires that the map is the kernel map */ if (!__map__is_kernel(map)) @@ -1894,7 +1894,7 @@ int dso__load(struct dso *dso, struct map *map) else if (dso->kernel == DSO_SPACE__KERNEL_GUEST) ret = dso__load_guest_kernel_sym(dso, map); - machine = map__kmaps(map)->machine; + machine = maps__machine(map__kmaps(map)); if (machine__is(machine, "x86_64")) machine__map_x86_64_entry_trampolines(machine, dso); goto out; @@ -2059,32 +2059,32 @@ static int map__strcmp_name(const void *name, const void *b) void __maps__sort_by_name(struct maps *maps) { - qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp); + qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); } static int map__groups__sort_by_name_from_rbtree(struct maps *maps) { struct map_rb_node *rb_node; - struct map **maps_by_name = realloc(maps->maps_by_name, - maps->nr_maps * sizeof(struct map *)); + struct map **maps_by_name = realloc(maps__maps_by_name(maps), + maps__nr_maps(maps) * sizeof(struct map *)); int i = 0; if (maps_by_name == NULL) return -1; - up_read(&maps->lock); - down_write(&maps->lock); + up_read(maps__lock(maps)); + down_write(maps__lock(maps)); maps->maps_by_name = maps_by_name; - maps->nr_maps_allocated = maps->nr_maps; + maps->nr_maps_allocated = maps__nr_maps(maps); maps__for_each_entry(maps, rb_node) maps_by_name[i++] = rb_node->map; __maps__sort_by_name(maps); - up_write(&maps->lock); - down_read(&maps->lock); + up_write(maps__lock(maps)); + down_read(maps__lock(maps)); return 0; } @@ -2093,11 +2093,12 @@ static struct map *__maps__find_by_name(struct maps *maps, const char *name) { struct map **mapp; - if (maps->maps_by_name == NULL && + if (maps__maps_by_name(maps) == NULL && map__groups__sort_by_name_from_rbtree(maps)) return NULL; - mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name); + mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), + sizeof(*mapp), map__strcmp_name); if (mapp) return *mapp; return NULL; @@ -2108,9 +2109,10 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) struct map_rb_node *rb_node; struct map *map; - down_read(&maps->lock); + down_read(maps__lock(maps)); - if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { + if (maps->last_search_by_name && + strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { map = maps->last_search_by_name; goto out_unlock; } @@ -2120,7 +2122,7 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) * made. */ map = __maps__find_by_name(maps, name); - if (map || maps->maps_by_name != NULL) + if (map || maps__maps_by_name(maps) != NULL) goto out_unlock; /* Fallback to traversing the rbtree... */ @@ -2134,7 +2136,7 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) map = NULL; out_unlock: - up_read(&maps->lock); + up_read(maps__lock(maps)); return map; } @@ -2386,7 +2388,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) { int err; const char *kallsyms_filename; - struct machine *machine = map__kmaps(map)->machine; + struct machine *machine = maps__machine(map__kmaps(map)); char path[PATH_MAX]; if (machine->kallsyms_filename) { diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 1b992bbba4e8..4b85c1728012 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -155,8 +155,8 @@ static int thread_stack__init(struct thread_stack *ts, struct thread *thread, ts->br_stack_sz = br_stack_sz; } - if (thread->maps && thread->maps->machine) { - struct machine *machine = thread->maps->machine; + if (thread->maps && maps__machine(thread->maps)) { + struct machine *machine = maps__machine(thread->maps); const char *arch = perf_env__arch(machine->env); ts->kernel_start = machine__kernel_start(machine); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 24e53bd55f7d..292585a52281 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -362,7 +362,7 @@ static int __thread__prepare_access(struct thread *thread) struct maps *maps = thread->maps; struct map_rb_node *rb_node; - down_read(&maps->lock); + down_read(maps__lock(maps)); maps__for_each_entry(maps, rb_node) { err = unwind__prepare_access(thread->maps, rb_node->map, &initialized); @@ -370,7 +370,7 @@ static int __thread__prepare_access(struct thread *thread) break; } - up_read(&maps->lock); + up_read(maps__lock(maps)); return err; } diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index dea70a477b91..c487a249b33c 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -667,24 +667,26 @@ static unw_accessors_t accessors = { static int _unwind__prepare_access(struct maps *maps) { - maps->addr_space = unw_create_addr_space(&accessors, 0); - if (!maps->addr_space) { + void *addr_space = unw_create_addr_space(&accessors, 0); + + maps->addr_space = addr_space; + if (!addr_space) { pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; } - unw_set_caching_policy(maps->addr_space, UNW_CACHE_GLOBAL); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); return 0; } static void _unwind__flush_access(struct maps *maps) { - unw_flush_cache(maps->addr_space, 0, 0); + unw_flush_cache(maps__addr_space(maps), 0, 0); } static void _unwind__finish_access(struct maps *maps) { - unw_destroy_addr_space(maps->addr_space); + unw_destroy_addr_space(maps__addr_space(maps)); } static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, @@ -709,7 +711,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, */ if (max_stack - 1 > 0) { WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space = ui->thread->maps->addr_space; + addr_space = maps__addr_space(ui->thread->maps); if (addr_space == NULL) return -1; @@ -759,7 +761,7 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct unwind_info ui = { .sample = data, .thread = thread, - .machine = thread->maps->machine, + .machine = maps__machine(thread->maps), .best_effort = best_effort }; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 509c287ee762..42528ade513e 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -22,12 +22,13 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized const char *arch; enum dso_type dso_type; struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; + struct machine *machine; int err; if (!dwarf_callchain_users) return 0; - if (maps->addr_space) { + if (maps__addr_space(maps)) { pr_debug("unwind: thread map already set, dso=%s\n", map->dso->name); if (initialized) @@ -35,15 +36,16 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized return 0; } + machine = maps__machine(maps); /* env->arch is NULL for live-mode (i.e. perf top) */ - if (!maps->machine->env || !maps->machine->env->arch) + if (!machine->env || !machine->env->arch) goto out_register; - dso_type = dso__type(map->dso, maps->machine); + dso_type = dso__type(map->dso, machine); if (dso_type == DSO__TYPE_UNKNOWN) return 0; - arch = perf_env__arch(maps->machine->env); + arch = perf_env__arch(machine->env); if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) @@ -60,7 +62,7 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized out_register: unwind__register_ops(maps, ops); - err = maps->unwind_libunwind_ops->prepare_access(maps); + err = maps__unwind_libunwind_ops(maps)->prepare_access(maps); if (initialized) *initialized = err ? false : true; return err; @@ -68,14 +70,18 @@ out_register: void unwind__flush_access(struct maps *maps) { - if (maps->unwind_libunwind_ops) - maps->unwind_libunwind_ops->flush_access(maps); + const struct unwind_libunwind_ops *ops = maps__unwind_libunwind_ops(maps); + + if (ops) + ops->flush_access(maps); } void unwind__finish_access(struct maps *maps) { - if (maps->unwind_libunwind_ops) - maps->unwind_libunwind_ops->finish_access(maps); + const struct unwind_libunwind_ops *ops = maps__unwind_libunwind_ops(maps); + + if (ops) + ops->finish_access(maps); } int unwind__get_entries(unwind_entry_cb_t cb, void *arg, @@ -83,8 +89,9 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct perf_sample *data, int max_stack, bool best_effort) { - if (thread->maps->unwind_libunwind_ops) - return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data, - max_stack, best_effort); + const struct unwind_libunwind_ops *ops = maps__unwind_libunwind_ops(thread->maps); + + if (ops) + return ops->get_entries(cb, arg, thread, data, max_stack, best_effort); return 0; } -- cgit v1.2.3 From 63df0e4bc368adbd12ed70ed4789d8d52d65661d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 20 Mar 2023 14:22:35 -0700 Subject: perf map: Add accessor for dso Later changes will add reference count checking for struct map, with dso being the most frequently accessed variable. Add an accessor so that the reference count check is only necessary in one place. Additional changes: - add a dso variable to avoid repeated map__dso calls. - in builtin-mem.c dump_raw_samples, code only partially tested for dso == NULL. Make the possibility of NULL consistent. - in thread.c thread__memcpy fix use of spaces and use tabs. Committer notes: Did missing conversions on these files: tools/perf/arch/powerpc/util/skip-callchain-idx.c tools/perf/arch/powerpc/util/sym-handling.c tools/perf/ui/browsers/hists.c tools/perf/ui/gtk/annotate.c tools/perf/util/cs-etm.c tools/perf/util/thread.c tools/perf/util/unwind-libunwind-local.c tools/perf/util/unwind-libunwind.c Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320212248.1175731-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 2 +- tools/perf/arch/powerpc/util/sym-handling.c | 2 +- tools/perf/builtin-annotate.c | 11 +-- tools/perf/builtin-buildid-list.c | 2 +- tools/perf/builtin-inject.c | 8 +- tools/perf/builtin-kallsyms.c | 4 +- tools/perf/builtin-mem.c | 10 ++- tools/perf/builtin-report.c | 7 +- tools/perf/builtin-script.c | 19 +++-- tools/perf/builtin-top.c | 11 ++- tools/perf/builtin-trace.c | 2 +- .../perf/scripts/python/Perf-Trace-Util/Context.c | 6 +- tools/perf/tests/code-reading.c | 28 ++++--- tools/perf/tests/hists_common.c | 8 +- tools/perf/tests/hists_cumulate.c | 4 +- tools/perf/tests/hists_filter.c | 4 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/maps.c | 2 +- tools/perf/tests/symbols.c | 6 +- tools/perf/tests/vmlinux-kallsyms.c | 13 +-- tools/perf/ui/browsers/annotate.c | 9 +- tools/perf/ui/browsers/hists.c | 17 ++-- tools/perf/ui/browsers/map.c | 4 +- tools/perf/ui/gtk/annotate.c | 5 +- tools/perf/util/annotate.c | 16 ++-- tools/perf/util/auxtrace.c | 2 +- tools/perf/util/block-info.c | 4 +- tools/perf/util/bpf-event.c | 10 ++- tools/perf/util/build-id.c | 2 +- tools/perf/util/callchain.c | 6 +- tools/perf/util/cs-etm.c | 17 ++-- tools/perf/util/data-convert-json.c | 10 ++- tools/perf/util/db-export.c | 4 +- tools/perf/util/dlfilter.c | 10 ++- tools/perf/util/event.c | 9 +- tools/perf/util/evsel_fprintf.c | 2 +- tools/perf/util/hist.c | 10 +-- tools/perf/util/intel-pt.c | 45 +++++----- tools/perf/util/machine.c | 70 +++++++++------- tools/perf/util/map.c | 96 ++++++++++++++-------- tools/perf/util/map.h | 7 +- tools/perf/util/maps.c | 7 +- tools/perf/util/probe-event.c | 30 ++++--- .../perf/util/scripting-engines/trace-event-perl.c | 10 ++- .../util/scripting-engines/trace-event-python.c | 16 ++-- tools/perf/util/sort.c | 49 +++++------ tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.c | 55 ++++++++----- tools/perf/util/synthetic-events.c | 12 +-- tools/perf/util/thread.c | 30 ++++--- tools/perf/util/unwind-libdw.c | 10 +-- tools/perf/util/unwind-libunwind-local.c | 31 ++++--- tools/perf/util/unwind-libunwind.c | 6 +- tools/perf/util/vdso.c | 2 +- 54 files changed, 447 insertions(+), 319 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index 20cd6244863b..fe0e4530673c 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -255,7 +255,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); if (al.map) - dso = al.map->dso; + dso = map__dso(al.map); if (!dso) { pr_debug("%" PRIx64 " dso is NULL\n", ip); diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 0856b32f9e08..9f99fc88dbff 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -104,7 +104,7 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev, lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); - if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) + if (map__dso(map)->symtab_type == DSO_BINARY_TYPE__KALLSYMS) tev->point.offset += PPC64LE_LEP_OFFSET; else if (lep_offset) { if (pev->uprobes) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 655987afef58..63fd2080b803 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -205,7 +205,7 @@ static int process_branch_callback(struct evsel *evsel, return 0; if (a.map != NULL) - a.map->dso->hit = 1; + map__dso(a.map)->hit = 1; hist__account_cycles(sample->branch_stack, al, sample, false, NULL); @@ -235,10 +235,11 @@ static int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample, * the DSO? */ if (al->sym != NULL) { - rb_erase_cached(&al->sym->rb_node, - &al->map->dso->symbols); + struct dso *dso = map__dso(al->map); + + rb_erase_cached(&al->sym->rb_node, &dso->symbols); symbol__delete(al->sym); - dso__reset_find_symbol_cache(al->map->dso); + dso__reset_find_symbol_cache(dso); } return 0; } @@ -320,7 +321,7 @@ static void hists__find_annotations(struct hists *hists, struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct annotation *notes; - if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) + if (he->ms.sym == NULL || map__dso(he->ms.map)->annotate_warned) goto find_next; if (ann->sym_hist_filter && diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 00bfe89f0b5d..cad9ed44ce7c 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -24,7 +24,7 @@ static int buildid__map_cb(struct map *map, void *arg __maybe_unused) { - const struct dso *dso = map->dso; + const struct dso *dso = map__dso(map); char bid_buf[SBUILD_ID_SIZE]; memset(bid_buf, 0, sizeof(bid_buf)); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 10bb1d494258..8f6909dd8a54 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -753,9 +753,11 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, } if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) { - if (!al.map->dso->hit) { - al.map->dso->hit = 1; - dso__inject_build_id(al.map->dso, tool, machine, + struct dso *dso = map__dso(al.map); + + if (!dso->hit) { + dso->hit = 1; + dso__inject_build_id(dso, tool, machine, sample->cpumode, al.map->flags); } } diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c index c08ee81529e8..5638ca4dbd8e 100644 --- a/tools/perf/builtin-kallsyms.c +++ b/tools/perf/builtin-kallsyms.c @@ -28,6 +28,7 @@ static int __cmd_kallsyms(int argc, const char **argv) for (i = 0; i < argc; ++i) { struct map *map; + const struct dso *dso; struct symbol *symbol = machine__find_kernel_symbol_by_name(machine, argv[i], &map); if (symbol == NULL) { @@ -35,8 +36,9 @@ static int __cmd_kallsyms(int argc, const char **argv) continue; } + dso = map__dso(map); printf("%s: %s %s %#" PRIx64 "-%#" PRIx64 " (%#" PRIx64 "-%#" PRIx64")\n", - symbol->name, map->dso->short_name, map->dso->long_name, + symbol->name, dso->short_name, dso->long_name, map->unmap_ip(map, symbol->start), map->unmap_ip(map, symbol->end), symbol->start, symbol->end); } diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index dedd612eae5e..1e27188b0de1 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -200,6 +200,7 @@ dump_raw_samples(struct perf_tool *tool, struct addr_location al; const char *fmt, *field_sep; char str[PAGE_SIZE_NAME_LEN]; + struct dso *dso = NULL; if (machine__resolve(machine, &al, sample) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", @@ -210,8 +211,11 @@ dump_raw_samples(struct perf_tool *tool, if (al.filtered || (mem->hide_unresolved && al.sym == NULL)) goto out_put; - if (al.map != NULL) - al.map->dso->hit = 1; + if (al.map != NULL) { + dso = map__dso(al.map); + if (dso) + dso->hit = 1; + } field_sep = symbol_conf.field_sep; if (field_sep) { @@ -252,7 +256,7 @@ dump_raw_samples(struct perf_tool *tool, symbol_conf.field_sep, sample->data_src, symbol_conf.field_sep, - al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", + dso ? dso->long_name : "???", al.sym ? al.sym->name : "???"); out_put: addr_location__put(&al); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c7e3863e8f44..ff239b89e4d0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -319,7 +319,7 @@ static int process_sample_event(struct perf_tool *tool, } if (al.map != NULL) - al.map->dso->hit = 1; + map__dso(al.map)->hit = 1; if (ui__has_annotation() || rep->symbol_ipc || rep->total_cycles_mode) { hist__account_cycles(sample->branch_stack, &al, sample, @@ -608,7 +608,7 @@ static void report__warn_kptr_restrict(const struct report *rep) return; if (kernel_map == NULL || - (kernel_map->dso->hit && + (map__dso(kernel_map)->hit && (kernel_kmap->ref_reloc_sym == NULL || kernel_kmap->ref_reloc_sym->addr == 0))) { const char *desc = @@ -848,6 +848,7 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) maps__for_each_entry(maps, rb_node) { struct map *map = rb_node->map; + const struct dso *dso = map__dso(map); printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", indent, "", map->start, map->end, @@ -856,7 +857,7 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) map->prot & PROT_EXEC ? 'x' : '-', map->flags & MAP_SHARED ? 's' : 'p', map->pgoff, - map->dso->id.ino, map->dso->name); + dso->id.ino, dso->name); } return printed; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c9296d8b33c0..27fd9c203600 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1011,11 +1011,11 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample, to = entries[i].to; if (thread__find_map_fb(thread, sample->cpumode, from, &alf) && - !alf.map->dso->adjust_symbols) + !map__dso(alf.map)->adjust_symbols) from = map__map_ip(alf.map, from); if (thread__find_map_fb(thread, sample->cpumode, to, &alt) && - !alt.map->dso->adjust_symbols) + !map__dso(alt.map)->adjust_symbols) to = map__map_ip(alt.map, to); printed += fprintf(fp, " 0x%"PRIx64, from); @@ -1044,6 +1044,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, long offset, len; struct addr_location al; bool kernel; + struct dso *dso; if (!start || !end) return 0; @@ -1074,11 +1075,12 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, return 0; } - if (!thread__find_map(thread, *cpumode, start, &al) || !al.map->dso) { + dso = map__dso(al.map); + if (!thread__find_map(thread, *cpumode, start, &al) || !dso) { pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); return 0; } - if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) { + if (dso->data.status == DSO_DATA_STATUS_ERROR) { pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); return 0; } @@ -1087,10 +1089,10 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, map__load(al.map); offset = al.map->map_ip(al.map, start); - len = dso__data_read_offset(al.map->dso, machine, offset, (u8 *)buffer, + len = dso__data_read_offset(dso, machine, offset, (u8 *)buffer, end - start + MAXINSN); - *is64bit = al.map->dso->is_64_bit; + *is64bit = dso->is_64_bit; if (len <= 0) pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n", start, end); @@ -1104,10 +1106,11 @@ static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srcc unsigned line; int len; char *srccode; + struct dso *dso = map__dso(map); - if (!map || !map->dso) + if (!map || !dso) return 0; - srcfile = get_srcline_split(map->dso, + srcfile = get_srcline_split(dso, map__rip_2objdump(map, addr), &line); if (!srcfile) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2c985cfea517..babfc163efe2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -114,6 +114,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) struct symbol *sym; struct annotation *notes; struct map *map; + struct dso *dso; int err = -1; if (!he || !he->ms.sym) @@ -123,12 +124,12 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) sym = he->ms.sym; map = he->ms.map; + dso = map__dso(map); /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && - !dso__is_kcore(map->dso)) { + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) { pr_err("Can't annotate %s: No vmlinux file was found in the " "path\n", sym->name); sleep(1); @@ -169,6 +170,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) { struct utsname uts; int err = uname(&uts); + struct dso *dso = map__dso(map); ui__warning("Out of bounds address found:\n\n" "Addr: %" PRIx64 "\n" @@ -180,7 +182,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) "Tools: %s\n\n" "Not all samples will be on the annotation output.\n\n" "Please report to linux-kernel@vger.kernel.org\n", - ip, map->dso->long_name, dso__symtab_origin(map->dso), + ip, dso->long_name, dso__symtab_origin(dso), map->start, map->end, sym->start, sym->end, sym->binding == STB_GLOBAL ? 'g' : sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, @@ -810,7 +812,8 @@ static void perf_event__process_sample(struct perf_tool *tool, __map__is_kernel(al.map) && map__has_symbols(al.map)) { if (symbol_conf.vmlinux_name) { char serr[256]; - dso__strerror_load(al.map->dso, serr, sizeof(serr)); + + dso__strerror_load(map__dso(al.map), serr, sizeof(serr)); ui__warning("The %s file can't be used: %s\n%s", symbol_conf.vmlinux_name, serr, msg); } else { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b363c609818b..72ef0bebb06b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2863,7 +2863,7 @@ static void print_location(FILE *f, struct perf_sample *sample, { if ((verbose > 0 || print_dso) && al->map) - fprintf(f, "%s@", al->map->dso->long_name); + fprintf(f, "%s@", map__dso(al->map)->long_name); if ((verbose > 0 || print_sym) && al->sym) fprintf(f, "%s+0x%" PRIx64, al->sym->name, diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index feedd02b3b3d..53b1587db403 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -145,6 +145,7 @@ static PyObject *perf_sample_src(PyObject *obj, PyObject *args, bool get_srccode char *srccode = NULL; PyObject *result; struct map *map; + struct dso *dso; int len = 0; u64 addr; @@ -153,9 +154,10 @@ static PyObject *perf_sample_src(PyObject *obj, PyObject *args, bool get_srccode map = c->al->map; addr = c->al->addr; + dso = map ? map__dso(map) : NULL; - if (map && map->dso) - srcfile = get_srcline_split(map->dso, map__rip_2objdump(map, addr), &line); + if (dso) + srcfile = get_srcline_split(dso, map__rip_2objdump(map, addr), &line); if (get_srccode) { if (srcfile) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 8d2036f2f944..936c61546e64 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -237,10 +237,11 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, char decomp_name[KMOD_DECOMP_LEN]; bool decomp = false; int ret, err = 0; + struct dso *dso; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); - if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) { + if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) { if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { pr_debug("Hypervisor address can not be resolved - skipping\n"); goto out; @@ -250,11 +251,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, err = -1; goto out; } + dso = map__dso(al.map); + pr_debug("File is: %s\n", dso->long_name); - pr_debug("File is: %s\n", al.map->dso->long_name); - - if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && - !dso__is_kcore(al.map->dso)) { + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) { pr_debug("Unexpected kernel address - skipping\n"); goto out; } @@ -269,7 +269,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len = al.map->end - addr; /* Read the object code using perf */ - ret_len = dso__data_read_offset(al.map->dso, maps__machine(thread->maps), + ret_len = dso__data_read_offset(dso, maps__machine(thread->maps), al.addr, buf1, len); if (ret_len != len) { pr_debug("dso__data_read_offset failed\n"); @@ -287,7 +287,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, } /* objdump struggles with kcore - try each map only once */ - if (dso__is_kcore(al.map->dso)) { + if (dso__is_kcore(dso)) { size_t d; for (d = 0; d < state->done_cnt; d++) { @@ -304,9 +304,9 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, state->done[state->done_cnt++] = al.map->start; } - objdump_name = al.map->dso->long_name; - if (dso__needs_decompress(al.map->dso)) { - if (dso__decompress_kmodule_path(al.map->dso, objdump_name, + objdump_name = dso->long_name; + if (dso__needs_decompress(dso)) { + if (dso__decompress_kmodule_path(dso, objdump_name, decomp_name, sizeof(decomp_name)) < 0) { pr_debug("decompression failed\n"); @@ -335,7 +335,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len -= ret; if (len) { pr_debug("Reducing len to %zu\n", len); - } else if (dso__is_kcore(al.map->dso)) { + } else if (dso__is_kcore(dso)) { /* * objdump cannot handle very large segments * that may be found in kcore. @@ -572,6 +572,7 @@ static int do_test_code_reading(bool try_kcore) pid_t pid; struct map *map; bool have_vmlinux, have_kcore, excl_kernel = false; + struct dso *dso; pid = getpid(); @@ -595,8 +596,9 @@ static int do_test_code_reading(bool try_kcore) pr_debug("map__load failed\n"); goto out_err; } - have_vmlinux = dso__is_vmlinux(map->dso); - have_kcore = dso__is_kcore(map->dso); + dso = map__dso(map); + have_vmlinux = dso__is_vmlinux(dso); + have_kcore = dso__is_kcore(dso); /* 2nd time through we just try kcore */ if (try_kcore && !have_kcore) diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index 6f34d08b84e5..745ab18d17db 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c @@ -179,9 +179,11 @@ void print_hists_in(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node_in); if (!he->filtered) { + struct dso *dso = map__dso(he->ms.map); + pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", i, thread__comm_str(he->thread), - he->ms.map->dso->short_name, + dso->short_name, he->ms.sym->name, he->stat.period); } @@ -206,9 +208,11 @@ void print_hists_out(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node); if (!he->filtered) { + struct dso *dso = map__dso(he->ms.map); + pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n", i, thread__comm_str(he->thread), he->thread->tid, - he->ms.map->dso->short_name, + dso->short_name, he->ms.sym->name, he->stat.period, he->stat_acc ? he->stat_acc->period : 0); } diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index b42d37ff2399..f00ec9abdbcd 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -150,12 +150,12 @@ static void del_hist_entries(struct hists *hists) typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) -#define DSO(he) (he->ms.map->dso->short_name) +#define DSO(he) (map__dso(he->ms.map)->short_name) #define SYM(he) (he->ms.sym->name) #define CPU(he) (he->cpu) #define PID(he) (he->thread->tid) #define DEPTH(he) (he->callchain->max_depth) -#define CDSO(cl) (cl->ms.map->dso->short_name) +#define CDSO(cl) (map__dso(cl->ms.map)->short_name) #define CSYM(cl) (cl->ms.sym->name) struct result { diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 8e1ceeb9b7b6..7c552549f4a4 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -194,7 +194,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes hists__filter_by_thread(hists); /* now applying dso filter for 'kernel' */ - hists->dso_filter = fake_samples[0].map->dso; + hists->dso_filter = map__dso(fake_samples[0].map); hists__filter_by_dso(hists); if (verbose > 2) { @@ -288,7 +288,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes /* now applying all filters at once. */ hists->thread_filter = fake_samples[1].thread; - hists->dso_filter = fake_samples[1].map->dso; + hists->dso_filter = map__dso(fake_samples[1].map); hists__filter_by_thread(hists); hists__filter_by_dso(hists); diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 62b0093253e3..428d11a938f2 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -116,7 +116,7 @@ static void del_hist_entries(struct hists *hists) typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) -#define DSO(he) (he->ms.map->dso->short_name) +#define DSO(he) (map__dso(he->ms.map)->short_name) #define SYM(he) (he->ms.sym->name) #define CPU(he) (he->cpu) #define PID(he) (he->thread->tid) diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index 8246d37e4b7a..ae7028fbf79e 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -26,7 +26,7 @@ static int check_maps(struct map_def *merged, unsigned int size, struct maps *ma TEST_ASSERT_VAL("wrong map start", map->start == merged[i].start); TEST_ASSERT_VAL("wrong map end", map->end == merged[i].end); - TEST_ASSERT_VAL("wrong map name", !strcmp(map->dso->name, merged[i].name)); + TEST_ASSERT_VAL("wrong map name", !strcmp(map__dso(map)->name, merged[i].name)); TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1); i++; diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c index 0793f8f419e2..2d1aa42d36a9 100644 --- a/tools/perf/tests/symbols.c +++ b/tools/perf/tests/symbols.c @@ -102,6 +102,7 @@ static int test_file(struct test_info *ti, char *filename) { struct map *map = NULL; int ret, nr; + struct dso *dso; pr_debug("Testing %s\n", filename); @@ -109,7 +110,8 @@ static int test_file(struct test_info *ti, char *filename) if (ret != TEST_OK) return ret; - nr = dso__load(map->dso, map); + dso = map__dso(map); + nr = dso__load(dso, map); if (nr < 0) { pr_debug("dso__load() failed!\n"); ret = TEST_FAIL; @@ -122,7 +124,7 @@ static int test_file(struct test_info *ti, char *filename) goto out_put; } - ret = test_dso(map->dso); + ret = test_dso(dso); out_put: map__put(map); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index c8abb3ca8347..c614c2db7e89 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -293,15 +293,16 @@ next_pair: maps__for_each_entry(maps, rb_node) { struct map *map = rb_node->map; + struct dso *dso = map__dso(map); /* * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while * the kernel will have the path for the vmlinux file being used, * so use the short name, less descriptive but the same ("[kernel]" in * both cases. */ - struct map *pair = maps__find_by_name(kallsyms.kmaps, (map->dso->kernel ? - map->dso->short_name : - map->dso->name)); + struct map *pair = maps__find_by_name(kallsyms.kmaps, (dso->kernel ? + dso->short_name : + dso->name)); if (pair) { pair->priv = 1; } else { @@ -326,17 +327,19 @@ next_pair: continue; if (pair->start == mem_start) { + struct dso *dso = map__dso(map); + if (!header_printed) { pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); header_printed = true; } pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", - map->start, map->end, map->pgoff, map->dso->name); + map->start, map->end, map->pgoff, dso->name); if (mem_end != pair->end) pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, pair->start, pair->end, pair->pgoff); - pr_info(" %s\n", pair->dso->name); + pr_info(" %s\n", dso->name); pair->priv = 1; } } diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c03fa76c02ff..12c3ce530e42 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -441,7 +441,8 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) static int sym_title(struct symbol *sym, struct map *map, char *title, size_t sz, int percent_type) { - return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name, + return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, + map__dso(map)->long_name, percent_type_str(percent_type)); } @@ -964,20 +965,22 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, }, .opts = opts, }; + struct dso *dso; int ret = -1, err; int not_annotated = list_empty(¬es->src->source); if (sym == NULL) return -1; - if (ms->map->dso->annotate_warned) + dso = map__dso(ms->map); + if (dso->annotate_warned) return -1; if (not_annotated) { err = symbol__annotate2(ms, evsel, opts, &browser.arch); if (err) { char msg[BUFSIZ]; - ms->map->dso->annotate_warned = true; + dso->annotate_warned = true; symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); ui__error("Couldn't annotate %s:\n%s", sym->name, msg); goto out_free_offsets; diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 572ff38ceb0f..9f9f622325ae 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2487,7 +2487,7 @@ static struct symbol *symbol__new_unresolved(u64 addr, struct map *map) return NULL; } - dso__insert_symbol(map->dso, sym); + dso__insert_symbol(map__dso(map), sym); } return sym; @@ -2499,7 +2499,9 @@ add_annotate_opt(struct hist_browser *browser __maybe_unused, struct map_symbol *ms, u64 addr) { - if (!ms->map || !ms->map->dso || ms->map->dso->annotate_warned) + struct dso *dso = map__dso(ms->map); + + if (!ms->map || !dso || dso->annotate_warned) return 0; if (!ms->sym) @@ -2589,9 +2591,10 @@ static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map browser->hists->dso_filter = NULL; ui_helpline__pop(); } else { + struct dso *dso = map__dso(map); ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", - __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); - browser->hists->dso_filter = map->dso; + __map__is_kernel(map) ? "the Kernel" : dso->short_name); + browser->hists->dso_filter = dso; perf_hpp__set_elide(HISTC_DSO, true); pstack__push(browser->pstack, &browser->hists->dso_filter); } @@ -2616,7 +2619,7 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)", browser->hists->dso_filter ? "out of" : "into", - __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) + __map__is_kernel(map) ? "the Kernel" : map__dso(map)->short_name) < 0) return 0; act->ms.map = map; @@ -3091,8 +3094,8 @@ do_hotkey: // key came straight from options ui__popup_menu() if (!browser->selection || !browser->selection->map || - !browser->selection->map->dso || - browser->selection->map->dso->annotate_warned) { + !map__dso(browser->selection->map) || + map__dso(browser->selection->map)->annotate_warned) { continue; } diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 3d49b916c9e4..3d1b958d8832 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -76,7 +76,7 @@ static int map_browser__run(struct map_browser *browser) { int key; - if (ui_browser__show(&browser->b, browser->map->dso->long_name, + if (ui_browser__show(&browser->b, map__dso(browser->map)->long_name, "Press ESC to exit, %s / to search", verbose > 0 ? "" : "restart with -v to use") < 0) return -1; @@ -106,7 +106,7 @@ int map__browse(struct map *map) { struct map_browser mb = { .b = { - .entries = &map->dso->symbols, + .entries = &map__dso(map)->symbols, .refresh = ui_browser__rb_tree_refresh, .seek = ui_browser__rb_tree_seek, .write = map_browser__write, diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index a1c021a6d3c1..2effac77ca8c 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -165,6 +165,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *options, struct hist_browser_timer *hbt) { + struct dso *dso = map__dso(ms->map); struct symbol *sym = ms->sym; GtkWidget *window; GtkWidget *notebook; @@ -172,13 +173,13 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, GtkWidget *tab_label; int err; - if (ms->map->dso->annotate_warned) + if (dso->annotate_warned) return -1; err = symbol__annotate(ms, evsel, options, NULL); if (err) { char msg[BUFSIZ]; - ms->map->dso->annotate_warned = true; + dso->annotate_warned = true; symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); ui__error("Couldn't annotate %s: %s\n", sym->name, msg); return -1; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f47b5dde66bc..84100ca5f306 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1585,7 +1585,7 @@ static void delete_last_nop(struct symbol *sym) int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen) { - struct dso *dso = ms->map->dso; + struct dso *dso = map__dso(ms->map); BUG_ON(buflen == 0); @@ -1727,7 +1727,7 @@ static int symbol__disassemble_bpf(struct symbol *sym, struct map *map = args->ms.map; struct perf_bpil *info_linear; struct disassemble_info info; - struct dso *dso = map->dso; + struct dso *dso = map__dso(map); int pc = 0, count, sub_id; struct btf *btf = NULL; char tpath[PATH_MAX]; @@ -1950,7 +1950,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { struct annotation_options *opts = args->options; struct map *map = args->ms.map; - struct dso *dso = map->dso; + struct dso *dso = map__dso(map); char *command; FILE *file; char symfs_filename[PATH_MAX]; @@ -2395,7 +2395,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, { struct map *map = ms->map; struct symbol *sym = ms->sym; - struct dso *dso = map->dso; + struct dso *dso = map__dso(map); char *filename; const char *d_filename; const char *evsel_name = evsel__name(evsel); @@ -2578,7 +2578,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, } fprintf(fp, "%s() %s\nEvent: %s\n\n", - ms->sym->name, ms->map->dso->long_name, ev_name); + ms->sym->name, map__dso(ms->map)->long_name, ev_name); symbol__annotate_fprintf2(ms->sym, fp, opts); fclose(fp); @@ -2804,7 +2804,7 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, if (percent_max <= 0.5) continue; - al->path = get_srcline(map->dso, notes->start + al->offset, NULL, + al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL, false, true, notes->start + al->offset); insert_source_line(&tmp_root, al, opts); } @@ -2823,7 +2823,7 @@ static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root, int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts) { - struct dso *dso = ms->map->dso; + struct dso *dso = map__dso(ms->map); struct symbol *sym = ms->sym; struct rb_root source_line = RB_ROOT; struct hists *hists = evsel__hists(evsel); @@ -2859,7 +2859,7 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts) { - struct dso *dso = ms->map->dso; + struct dso *dso = map__dso(ms->map); struct symbol *sym = ms->sym; struct rb_root source_line = RB_ROOT; int err; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index b2a5e5397bad..a0368202a746 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -2560,7 +2560,7 @@ static struct dso *load_dso(const char *name) if (map__load(map) < 0) pr_err("File '%s' not found or has no symbols.\n", name); - dso = dso__get(map->dso); + dso = dso__get(map__dso(map)); map__put(map); diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c index 5ecd4f401f32..16a7b4adcf18 100644 --- a/tools/perf/util/block-info.c +++ b/tools/perf/util/block-info.c @@ -317,9 +317,9 @@ static int block_dso_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt); struct map *map = he->ms.map; - if (map && map->dso) { + if (map && map__dso(map)) { return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, - map->dso->short_name); + map__dso(map)->short_name); } return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 025f331b3867..38fcf3ba5749 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -57,10 +57,12 @@ static int machine__process_bpf_event_load(struct machine *machine, struct map *map = maps__find(machine__kernel_maps(machine), addr); if (map) { - map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO; - map->dso->bpf_prog.id = id; - map->dso->bpf_prog.sub_id = i; - map->dso->bpf_prog.env = env; + struct dso *dso = map__dso(map); + + dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO; + dso->bpf_prog.id = id; + dso->bpf_prog.sub_id = i; + dso->bpf_prog.env = env; } } return 0; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index ea9c083ab1e3..06a8cd88cbef 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -59,7 +59,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, } if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) - al.map->dso->hit = 1; + map__dso(al.map)->hit = 1; thread__put(thread); return 0; diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 0aa979f64565..9e9c39dd9d2b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -701,8 +701,8 @@ static enum match_result match_chain_strings(const char *left, static enum match_result match_chain_dso_addresses(struct map *left_map, u64 left_ip, struct map *right_map, u64 right_ip) { - struct dso *left_dso = left_map ? left_map->dso : NULL; - struct dso *right_dso = right_map ? right_map->dso : NULL; + struct dso *left_dso = left_map ? map__dso(left_map) : NULL; + struct dso *right_dso = right_map ? map__dso(right_map) : NULL; if (left_dso != right_dso) return left_dso < right_dso ? MATCH_LT : MATCH_GT; @@ -1174,7 +1174,7 @@ char *callchain_list__sym_name(struct callchain_list *cl, if (show_dso) scnprintf(bf + printed, bfsize - printed, " %s", cl->ms.map ? - cl->ms.map->dso->short_name : + map__dso(cl->ms.map)->short_name : "unknown"); return bf; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 94e2d02009eb..528a7fb066cf 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -865,6 +865,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, struct thread *thread; struct machine *machine; struct addr_location al; + struct dso *dso; struct cs_etm_traceid_queue *tidq; if (!etmq) @@ -883,27 +884,29 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, thread = etmq->etm->unknown_thread; } - if (!thread__find_map(thread, cpumode, address, &al) || !al.map->dso) + dso = map__dso(al.map); + + if (!thread__find_map(thread, cpumode, address, &al) || !dso) return 0; - if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR && - dso__data_status_seen(al.map->dso, DSO_DATA_STATUS_SEEN_ITRACE)) + if (dso->data.status == DSO_DATA_STATUS_ERROR && + dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) return 0; offset = al.map->map_ip(al.map, address); map__load(al.map); - len = dso__data_read_offset(al.map->dso, machine, offset, buffer, size); + len = dso__data_read_offset(dso, machine, offset, buffer, size); if (len <= 0) { ui__warning_once("CS ETM Trace: Missing DSO. Use 'perf archive' or debuginfod to export data from the traced system.\n" " Enable CONFIG_PROC_KCORE or use option '-k /path/to/vmlinux' for kernel symbols.\n"); - if (!al.map->dso->auxtrace_warned) { + if (!dso->auxtrace_warned) { pr_err("CS ETM Trace: Debug data not found for address %#"PRIx64" in %s\n", address, - al.map->dso->long_name ? al.map->dso->long_name : "Unknown"); - al.map->dso->auxtrace_warned = true; + dso->long_name ? dso->long_name : "Unknown"); + dso->auxtrace_warned = true; } return 0; } diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c index ba9d93ce9463..653709ab867a 100644 --- a/tools/perf/util/data-convert-json.c +++ b/tools/perf/util/data-convert-json.c @@ -128,15 +128,17 @@ static void output_sample_callchain_entry(struct perf_tool *tool, output_json_key_format(out, false, 5, "ip", "\"0x%" PRIx64 "\"", ip); if (al && al->sym && al->sym->namelen) { + struct dso *dso = al->map ? map__dso(al->map) : NULL; + fputc(',', out); output_json_key_string(out, false, 5, "symbol", al->sym->name); - if (al->map && al->map->dso) { - const char *dso = al->map->dso->short_name; + if (dso) { + const char *dso_name = dso->short_name; - if (dso && strlen(dso) > 0) { + if (dso_name && strlen(dso_name) > 0) { fputc(',', out); - output_json_key_string(out, false, 5, "dso", dso); + output_json_key_string(out, false, 5, "dso", dso_name); } } } diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index 1cfcfdd3cf52..84c970c11794 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -179,7 +179,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, int err; if (al->map) { - struct dso *dso = al->map->dso; + struct dso *dso = map__dso(al->map); err = db_export__dso(dbe, dso, maps__machine(al->maps)); if (err) @@ -255,7 +255,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, al.addr = node->ip; if (al.map && !al.sym) - al.sym = dso__find_symbol(al.map->dso, al.addr); + al.sym = dso__find_symbol(map__dso(al.map), al.addr); db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset); diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index fe2a0752a0f6..8a7ffe0d805a 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -29,7 +29,7 @@ static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al) d_al->size = sizeof(*d_al); if (al->map) { - struct dso *dso = al->map->dso; + struct dso *dso = map__dso(al->map); if (symbol_conf.show_kernel_path && dso->long_name) d_al->dso = dso->long_name; @@ -220,6 +220,7 @@ static const char *dlfilter__srcline(void *ctx, __u32 *line_no) unsigned int line = 0; char *srcfile = NULL; struct map *map; + struct dso *dso; u64 addr; if (!d->ctx_valid || !line_no) @@ -231,9 +232,10 @@ static const char *dlfilter__srcline(void *ctx, __u32 *line_no) map = al->map; addr = al->addr; + dso = map ? map__dso(map) : NULL; - if (map && map->dso) - srcfile = get_srcline_split(map->dso, map__rip_2objdump(map, addr), &line); + if (dso) + srcfile = get_srcline_split(dso, map__rip_2objdump(map, addr), &line); *line_no = line; return srcfile; @@ -279,7 +281,7 @@ have_map: offset = map->map_ip(map, ip); if (ip + len >= map->end) len = map->end - ip; - return dso__data_read_offset(map->dso, d->machine, offset, buf, len); + return dso__data_read_offset(map__dso(map), d->machine, offset, buf, len); } static const struct perf_dlfilter_fns perf_dlfilter_fns = { diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index f40cdd6ac126..2ddc75dee019 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -685,6 +685,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al, struct perf_sample *sample) { struct thread *thread; + struct dso *dso; if (symbol_conf.guest_code && !machine__is_host(machine)) thread = machine__findnew_guest_code(machine, sample->pid); @@ -695,9 +696,11 @@ int machine__resolve(struct machine *machine, struct addr_location *al, dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); thread__find_map(thread, sample->cpumode, sample->ip, al); + dso = al->map ? map__dso(al->map) : NULL; dump_printf(" ...... dso: %s\n", - al->map ? al->map->dso->long_name : - al->level == 'H' ? "[hypervisor]" : ""); + dso + ? dso->long_name + : (al->level == 'H' ? "[hypervisor]" : "")); if (thread__is_filtered(thread)) al->filtered |= (1 << HIST_FILTER__THREAD); @@ -715,8 +718,6 @@ int machine__resolve(struct machine *machine, struct addr_location *al, } if (al->map) { - struct dso *dso = al->map->dso; - if (symbol_conf.dso_list && (!dso || !(strlist__has_entry(symbol_conf.dso_list, dso->short_name) || diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index bd22c4932d10..dff5d8c4b06d 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -155,7 +155,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, if (print_ip) { /* Show binary offset for userspace addr */ - if (map && !map->dso->kernel) + if (map && !map__dso(map)->kernel) printed += fprintf(fp, "%c%16" PRIx64, s, addr); else printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 5f9f38ed5da1..e494425cad06 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -106,7 +106,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__set_col_len(hists, HISTC_THREAD, len + 8); if (h->ms.map) { - len = dso__name_len(h->ms.map->dso); + len = dso__name_len(map__dso(h->ms.map)); hists__new_col_len(hists, HISTC_DSO, len); } @@ -120,7 +120,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) symlen += BITS_PER_LONG / 4 + 2 + 3; hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); - symlen = dso__name_len(h->branch_info->from.ms.map->dso); + symlen = dso__name_len(map__dso(h->branch_info->from.ms.map)); hists__new_col_len(hists, HISTC_DSO_FROM, symlen); } else { symlen = unresolved_col_width + 4 + 2; @@ -135,7 +135,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) symlen += BITS_PER_LONG / 4 + 2 + 3; hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); - symlen = dso__name_len(h->branch_info->to.ms.map->dso); + symlen = dso__name_len(map__dso(h->branch_info->to.ms.map)); hists__new_col_len(hists, HISTC_DSO_TO, symlen); } else { symlen = unresolved_col_width + 4 + 2; @@ -180,7 +180,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) } if (h->mem_info->daddr.ms.map) { - symlen = dso__name_len(h->mem_info->daddr.ms.map->dso); + symlen = dso__name_len(map__dso(h->mem_info->daddr.ms.map)); hists__new_col_len(hists, HISTC_MEM_DADDR_DSO, symlen); } else { @@ -2110,7 +2110,7 @@ static bool hists__filter_entry_by_dso(struct hists *hists, struct hist_entry *he) { if (hists->dso_filter != NULL && - (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) { + (he->ms.map == NULL || map__dso(he->ms.map) != hists->dso_filter)) { he->filtered |= (1 << HIST_FILTER__DSO); return true; } diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 955c1b9dc6a4..8cec88e09792 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -801,17 +801,19 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, } while (1) { - if (!thread__find_map(thread, cpumode, *ip, &al) || !al.map->dso) { + struct dso *dso; + + if (!thread__find_map(thread, cpumode, *ip, &al) || !map__dso(al.map)) { if (al.map) intel_pt_log("ERROR: thread has no dso for %#" PRIx64 "\n", *ip); else intel_pt_log("ERROR: thread has no map for %#" PRIx64 "\n", *ip); return -EINVAL; } + dso = map__dso(al.map); - if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR && - dso__data_status_seen(al.map->dso, - DSO_DATA_STATUS_SEEN_ITRACE)) + if (dso->data.status == DSO_DATA_STATUS_ERROR && + dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) return -ENOENT; offset = al.map->map_ip(al.map, *ip); @@ -819,7 +821,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, if (!to_ip && one_map) { struct intel_pt_cache_entry *e; - e = intel_pt_cache_lookup(al.map->dso, machine, offset); + e = intel_pt_cache_lookup(dso, machine, offset); if (e && (!max_insn_cnt || e->insn_cnt <= max_insn_cnt)) { *insn_cnt_ptr = e->insn_cnt; @@ -829,8 +831,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, intel_pt_insn->emulated_ptwrite = e->emulated_ptwrite; intel_pt_insn->length = e->length; intel_pt_insn->rel = e->rel; - memcpy(intel_pt_insn->buf, e->insn, - INTEL_PT_INSN_BUF_SZ); + memcpy(intel_pt_insn->buf, e->insn, INTEL_PT_INSN_BUF_SZ); intel_pt_log_insn_no_data(intel_pt_insn, *ip); return 0; } @@ -842,17 +843,17 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, /* Load maps to ensure dso->is_64_bit has been updated */ map__load(al.map); - x86_64 = al.map->dso->is_64_bit; + x86_64 = dso->is_64_bit; while (1) { - len = dso__data_read_offset(al.map->dso, machine, + len = dso__data_read_offset(dso, machine, offset, buf, INTEL_PT_INSN_BUF_SZ); if (len <= 0) { intel_pt_log("ERROR: failed to read at offset %#" PRIx64 " ", offset); if (intel_pt_enable_logging) - dso__fprintf(al.map->dso, intel_pt_log_fp()); + dso__fprintf(dso, intel_pt_log_fp()); return -EINVAL; } @@ -871,7 +872,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, goto out; /* Check for emulated ptwrite */ offs = offset + intel_pt_insn->length; - eptw = intel_pt_emulated_ptwrite(al.map->dso, machine, offs); + eptw = intel_pt_emulated_ptwrite(dso, machine, offs); intel_pt_insn->emulated_ptwrite = eptw; goto out; } @@ -906,13 +907,13 @@ out: if (to_ip) { struct intel_pt_cache_entry *e; - e = intel_pt_cache_lookup(al.map->dso, machine, start_offset); + e = intel_pt_cache_lookup(map__dso(al.map), machine, start_offset); if (e) return 0; } /* Ignore cache errors */ - intel_pt_cache_add(al.map->dso, machine, start_offset, insn_cnt, + intel_pt_cache_add(map__dso(al.map), machine, start_offset, insn_cnt, *ip - start_ip, intel_pt_insn); return 0; @@ -983,13 +984,12 @@ static int __intel_pt_pgd_ip(uint64_t ip, void *data) if (!thread) return -EINVAL; - if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso) + if (!thread__find_map(thread, cpumode, ip, &al) || !map__dso(al.map)) return -EINVAL; offset = al.map->map_ip(al.map, ip); - return intel_pt_match_pgd_ip(ptq->pt, ip, offset, - al.map->dso->long_name); + return intel_pt_match_pgd_ip(ptq->pt, ip, offset, map__dso(al.map)->long_name); } static bool intel_pt_pgd_ip(uint64_t ip, void *data) @@ -2744,7 +2744,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (map__load(map)) return 0; - start = dso__first_symbol(map->dso); + start = dso__first_symbol(map__dso(map)); for (sym = start; sym; sym = dso__next_symbol(sym)) { if (sym->binding == STB_GLOBAL && @@ -3381,18 +3381,21 @@ static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event) return 0; for (; cnt; cnt--, addr--) { + struct dso *dso; + if (intel_pt_find_map(thread, cpumode, addr, &al)) { if (addr < event->text_poke.addr) return 0; continue; } - if (!al.map->dso || !al.map->dso->auxtrace_cache) + dso = map__dso(al.map); + if (!dso || !dso->auxtrace_cache) continue; offset = al.map->map_ip(al.map, addr); - e = intel_pt_cache_lookup(al.map->dso, machine, offset); + e = intel_pt_cache_lookup(dso, machine, offset); if (!e) continue; @@ -3405,9 +3408,9 @@ static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event) if (e->branch != INTEL_PT_BR_NO_BRANCH) return 0; } else { - intel_pt_cache_invalidate(al.map->dso, machine, offset); + intel_pt_cache_invalidate(dso, machine, offset); intel_pt_log("Invalidated instruction cache for %s at %#"PRIx64"\n", - al.map->dso->long_name, addr); + dso->long_name, addr); } } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index d6da4b5e1333..8bae38c96788 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -48,7 +48,7 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms static struct dso *machine__kernel_dso(struct machine *machine) { - return machine->vmlinux_map->dso; + return map__dso(machine->vmlinux_map); } static void dsos__init(struct dsos *dsos) @@ -879,12 +879,13 @@ static int machine__process_ksymbol_register(struct machine *machine, struct perf_sample *sample __maybe_unused) { struct symbol *sym; + struct dso *dso; struct map *map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr); if (!map) { - struct dso *dso = dso__new(event->ksymbol.name); int err; + dso = dso__new(event->ksymbol.name); if (dso) { dso->kernel = DSO_SPACE__KERNEL; map = map__new2(0, dso); @@ -896,9 +897,9 @@ static int machine__process_ksymbol_register(struct machine *machine, } if (event->ksymbol.ksym_type == PERF_RECORD_KSYMBOL_TYPE_OOL) { - map->dso->binary_type = DSO_BINARY_TYPE__OOL; - map->dso->data.file_size = event->ksymbol.len; - dso__set_loaded(map->dso); + dso->binary_type = DSO_BINARY_TYPE__OOL; + dso->data.file_size = event->ksymbol.len; + dso__set_loaded(dso); } map->start = event->ksymbol.addr; @@ -914,6 +915,8 @@ static int machine__process_ksymbol_register(struct machine *machine, dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE; dso__set_long_name(dso, "", false); } + } else { + dso = map__dso(map); } sym = symbol__new(map->map_ip(map, map->start), @@ -921,7 +924,7 @@ static int machine__process_ksymbol_register(struct machine *machine, 0, 0, event->ksymbol.name); if (!sym) return -ENOMEM; - dso__insert_symbol(map->dso, sym); + dso__insert_symbol(dso, sym); return 0; } @@ -939,9 +942,11 @@ static int machine__process_ksymbol_unregister(struct machine *machine, if (map != machine->vmlinux_map) maps__remove(machine__kernel_maps(machine), map); else { - sym = dso__find_symbol(map->dso, map->map_ip(map, map->start)); + struct dso *dso = map__dso(map); + + sym = dso__find_symbol(dso, map->map_ip(map, map->start)); if (sym) - dso__delete_symbol(map->dso, sym); + dso__delete_symbol(dso, sym); } return 0; @@ -965,6 +970,7 @@ int machine__process_text_poke(struct machine *machine, union perf_event *event, { struct map *map = maps__find(machine__kernel_maps(machine), event->text_poke.addr); u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct dso *dso = map ? map__dso(map) : NULL; if (dump_trace) perf_event__fprintf_text_poke(event, machine, stdout); @@ -977,7 +983,7 @@ int machine__process_text_poke(struct machine *machine, union perf_event *event, return 0; } - if (map && map->dso) { + if (dso) { u8 *new_bytes = event->text_poke.bytes + event->text_poke.old_len; int ret; @@ -986,7 +992,7 @@ int machine__process_text_poke(struct machine *machine, union perf_event *event, * must be done prior to using kernel maps. */ map__load(map); - ret = dso__data_write_cache_addr(map->dso, map, machine, + ret = dso__data_write_cache_addr(dso, map, machine, event->text_poke.addr, new_bytes, event->text_poke.new_len); @@ -1422,10 +1428,11 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) int machine__load_kallsyms(struct machine *machine, const char *filename) { struct map *map = machine__kernel_map(machine); - int ret = __dso__load_kallsyms(map->dso, filename, map, true); + struct dso *dso = map__dso(map); + int ret = __dso__load_kallsyms(dso, filename, map, true); if (ret > 0) { - dso__set_loaded(map->dso); + dso__set_loaded(dso); /* * Since /proc/kallsyms will have multiple sessions for the * kernel, with modules between them, fixup the end of all @@ -1440,10 +1447,11 @@ int machine__load_kallsyms(struct machine *machine, const char *filename) int machine__load_vmlinux_path(struct machine *machine) { struct map *map = machine__kernel_map(machine); - int ret = dso__load_vmlinux_path(map->dso, map); + struct dso *dso = map__dso(map); + int ret = dso__load_vmlinux_path(dso, map); if (ret > 0) - dso__set_loaded(map->dso); + dso__set_loaded(dso); return ret; } @@ -1485,6 +1493,7 @@ static bool is_kmod_dso(struct dso *dso) static int maps__set_module_path(struct maps *maps, const char *path, struct kmod_path *m) { char *long_name; + struct dso *dso; struct map *map = maps__find_by_name(maps, m->name); if (map == NULL) @@ -1494,16 +1503,17 @@ static int maps__set_module_path(struct maps *maps, const char *path, struct kmo if (long_name == NULL) return -ENOMEM; - dso__set_long_name(map->dso, long_name, true); - dso__kernel_module_get_build_id(map->dso, ""); + dso = map__dso(map); + dso__set_long_name(dso, long_name, true); + dso__kernel_module_get_build_id(dso, ""); /* * Full name could reveal us kmod compression, so * we need to update the symtab_type if needed. */ - if (m->comp && is_kmod_dso(map->dso)) { - map->dso->symtab_type++; - map->dso->comp = m->comp; + if (m->comp && is_kmod_dso(dso)) { + dso->symtab_type++; + dso->comp = m->comp; } return 0; @@ -1602,7 +1612,7 @@ static int machine__create_module(void *arg, const char *name, u64 start, return -1; map->end = start + size; - dso__kernel_module_get_build_id(map->dso, machine->root_dir); + dso__kernel_module_get_build_id(map__dso(map), machine->root_dir); return 0; } @@ -1788,7 +1798,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, map->end = map->start + xm->end - xm->start; if (build_id__is_defined(bid)) - dso__set_build_id(map->dso, bid); + dso__set_build_id(map__dso(map), bid); } else if (is_kernel_mmap) { const char *symbol_name = xm->name + strlen(mmap_name); @@ -2248,18 +2258,20 @@ static char *callchain_srcline(struct map_symbol *ms, u64 ip) { struct map *map = ms->map; char *srcline = NULL; + struct dso *dso; if (!map || callchain_param.key == CCKEY_FUNCTION) return srcline; - srcline = srcline__tree_find(&map->dso->srclines, ip); + dso = map__dso(map); + srcline = srcline__tree_find(&dso->srclines, ip); if (!srcline) { bool show_sym = false; bool show_addr = callchain_param.key == CCKEY_ADDRESS; - srcline = get_srcline(map->dso, map__rip_2objdump(map, ip), + srcline = get_srcline(dso, map__rip_2objdump(map, ip), ms->sym, show_sym, show_addr, ip); - srcline__tree_insert(&map->dso->srclines, ip, srcline); + srcline__tree_insert(&dso->srclines, ip, srcline); } return srcline; @@ -3039,6 +3051,7 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms struct map *map = ms->map; struct inline_node *inline_node; struct inline_list *ilist; + struct dso *dso; u64 addr; int ret = 1; @@ -3047,13 +3060,14 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms addr = map__map_ip(map, ip); addr = map__rip_2objdump(map, addr); + dso = map__dso(map); - inline_node = inlines__tree_find(&map->dso->inlined_nodes, addr); + inline_node = inlines__tree_find(&dso->inlined_nodes, addr); if (!inline_node) { - inline_node = dso__parse_addr_inlines(map->dso, addr, sym); + inline_node = dso__parse_addr_inlines(dso, addr, sym); if (!inline_node) return ret; - inlines__tree_insert(&map->dso->inlined_nodes, inline_node); + inlines__tree_insert(&dso->inlined_nodes, inline_node); } list_for_each_entry(ilist, &inline_node->val, list) { @@ -3330,7 +3344,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch if (sym == NULL) return NULL; - *modp = __map__is_kmodule(map) ? (char *)map->dso->short_name : NULL; + *modp = __map__is_kmodule(map) ? (char *)map__dso(map)->short_name : NULL; *addrp = map->unmap_ip(map, sym->start); return sym->name; } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index a99dbde656a2..90062af6675a 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -232,7 +232,7 @@ struct map *map__new2(u64 start, struct dso *dso) bool __map__is_kernel(const struct map *map) { - if (!map->dso->kernel) + if (!map__dso(map)->kernel) return false; return machine__kernel_map(maps__machine(map__kmaps((struct map *)map))) == map; } @@ -247,8 +247,9 @@ bool __map__is_extra_kernel_map(const struct map *map) bool __map__is_bpf_prog(const struct map *map) { const char *name; + struct dso *dso = map__dso(map); - if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) return true; /* @@ -256,15 +257,16 @@ bool __map__is_bpf_prog(const struct map *map) * type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can * guess the type based on name. */ - name = map->dso->short_name; + name = dso->short_name; return name && (strstr(name, "bpf_prog_") == name); } bool __map__is_bpf_image(const struct map *map) { const char *name; + struct dso *dso = map__dso(map); - if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) + if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) return true; /* @@ -272,18 +274,20 @@ bool __map__is_bpf_image(const struct map *map) * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can * guess the type based on name. */ - name = map->dso->short_name; + name = dso->short_name; return name && is_bpf_image(name); } bool __map__is_ool(const struct map *map) { - return map->dso && map->dso->binary_type == DSO_BINARY_TYPE__OOL; + const struct dso *dso = map__dso(map); + + return dso && dso->binary_type == DSO_BINARY_TYPE__OOL; } bool map__has_symbols(const struct map *map) { - return dso__has_symbols(map->dso); + return dso__has_symbols(map__dso(map)); } static void map__exit(struct map *map) @@ -306,18 +310,23 @@ void map__put(struct map *map) void map__fixup_start(struct map *map) { - struct rb_root_cached *symbols = &map->dso->symbols; + struct dso *dso = map__dso(map); + struct rb_root_cached *symbols = &dso->symbols; struct rb_node *nd = rb_first_cached(symbols); + if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); + map->start = sym->start; } } void map__fixup_end(struct map *map) { - struct rb_root_cached *symbols = &map->dso->symbols; + struct dso *dso = map__dso(map); + struct rb_root_cached *symbols = &dso->symbols; struct rb_node *nd = rb_last(&symbols->rb_root); + if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); map->end = sym->end; @@ -328,18 +337,19 @@ void map__fixup_end(struct map *map) int map__load(struct map *map) { - const char *name = map->dso->long_name; + struct dso *dso = map__dso(map); + const char *name = dso->long_name; int nr; - if (dso__loaded(map->dso)) + if (dso__loaded(dso)) return 0; - nr = dso__load(map->dso, map); + nr = dso__load(dso, map); if (nr < 0) { - if (map->dso->has_build_id) { + if (dso->has_build_id) { char sbuild_id[SBUILD_ID_SIZE]; - build_id__sprintf(&map->dso->bid, sbuild_id); + build_id__sprintf(&dso->bid, sbuild_id); pr_debug("%s with build id %s not found", name, sbuild_id); } else pr_debug("Failed to open %s", name); @@ -371,32 +381,36 @@ struct symbol *map__find_symbol(struct map *map, u64 addr) if (map__load(map) < 0) return NULL; - return dso__find_symbol(map->dso, addr); + return dso__find_symbol(map__dso(map), addr); } struct symbol *map__find_symbol_by_name(struct map *map, const char *name) { + struct dso *dso; + if (map__load(map) < 0) return NULL; - if (!dso__sorted_by_name(map->dso)) - dso__sort_by_name(map->dso); + dso = map__dso(map); + if (!dso__sorted_by_name(dso)) + dso__sort_by_name(dso); - return dso__find_symbol_by_name(map->dso, name); + return dso__find_symbol_by_name(dso, name); } struct map *map__clone(struct map *from) { size_t size = sizeof(struct map); struct map *map; + struct dso *dso = map__dso(from); - if (from->dso && from->dso->kernel) + if (dso && dso->kernel) size += sizeof(struct kmap); map = memdup(from, size); if (map != NULL) { refcount_set(&map->refcnt, 1); - dso__get(map->dso); + dso__get(dso); } return map; @@ -404,20 +418,23 @@ struct map *map__clone(struct map *from) size_t map__fprintf(struct map *map, FILE *fp) { + const struct dso *dso = map__dso(map); + return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", - map->start, map->end, map->pgoff, map->dso->name); + map->start, map->end, map->pgoff, dso->name); } size_t map__fprintf_dsoname(struct map *map, FILE *fp) { char buf[symbol_conf.pad_output_len_dso + 1]; const char *dsoname = "[unknown]"; + const struct dso *dso = map ? map__dso(map) : NULL; - if (map && map->dso) { - if (symbol_conf.show_kernel_path && map->dso->long_name) - dsoname = map->dso->long_name; + if (dso) { + if (symbol_conf.show_kernel_path && dso->long_name) + dsoname = dso->long_name; else - dsoname = map->dso->name; + dsoname = dso->name; } if (symbol_conf.pad_output_len_dso) { @@ -432,15 +449,17 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym) { if (map == NULL) return SRCLINE_UNKNOWN; - return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr); + + return get_srcline(map__dso(map), map__rip_2objdump(map, addr), sym, true, true, addr); } int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, FILE *fp) { + const struct dso *dso = map ? map__dso(map) : NULL; int ret = 0; - if (map && map->dso) { + if (dso) { char *srcline = map__srcline(map, addr, NULL); if (strncmp(srcline, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) ret = fprintf(fp, "%s%s", prefix, srcline); @@ -469,6 +488,7 @@ void srccode_state_free(struct srccode_state *state) u64 map__rip_2objdump(struct map *map, u64 rip) { struct kmap *kmap = __map__kmap(map); + const struct dso *dso = map__dso(map); /* * vmlinux does not have program headers for PTI entry trampolines and @@ -486,18 +506,18 @@ u64 map__rip_2objdump(struct map *map, u64 rip) } } - if (!map->dso->adjust_symbols) + if (!dso->adjust_symbols) return rip; - if (map->dso->rel) + if (dso->rel) return rip - map->pgoff; /* * kernel modules also have DSO_TYPE_USER in dso->kernel, * but all kernel modules are ET_REL, so won't get here. */ - if (map->dso->kernel == DSO_SPACE__USER) - return rip + map->dso->text_offset; + if (dso->kernel == DSO_SPACE__USER) + return rip + dso->text_offset; return map->unmap_ip(map, rip) - map->reloc; } @@ -516,18 +536,20 @@ u64 map__rip_2objdump(struct map *map, u64 rip) */ u64 map__objdump_2mem(struct map *map, u64 ip) { - if (!map->dso->adjust_symbols) + const struct dso *dso = map__dso(map); + + if (!dso->adjust_symbols) return map->unmap_ip(map, ip); - if (map->dso->rel) + if (dso->rel) return map->unmap_ip(map, ip + map->pgoff); /* * kernel modules also have DSO_TYPE_USER in dso->kernel, * but all kernel modules are ET_REL, so won't get here. */ - if (map->dso->kernel == DSO_SPACE__USER) - return map->unmap_ip(map, ip - map->dso->text_offset); + if (dso->kernel == DSO_SPACE__USER) + return map->unmap_ip(map, ip - dso->text_offset); return ip + map->reloc; } @@ -541,7 +563,9 @@ bool map__contains_symbol(const struct map *map, const struct symbol *sym) struct kmap *__map__kmap(struct map *map) { - if (!map->dso || !map->dso->kernel) + const struct dso *dso = map__dso(map); + + if (!dso || !dso->kernel) return NULL; return (struct kmap *)(map + 1); } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index d1a6f85fd31d..36c5add0144d 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -47,6 +47,11 @@ u64 map__unmap_ip(const struct map *map, u64 ip); /* Returns ip */ u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip); +static inline struct dso *map__dso(const struct map *map) +{ + return map->dso; +} + static inline size_t map__size(const struct map *map) { return map->end - map->start; @@ -69,7 +74,7 @@ struct thread; * Note: caller must ensure map->dso is not NULL (map is loaded). */ #define map__for_each_symbol(map, pos, n) \ - dso__for_each_symbol(map->dso, pos, n) + dso__for_each_symbol(map__dso(map), pos, n) /* map__for_each_symbol_with_name - iterate over the symbols in the given map * that have the given name diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 91bb015caede..09ec6bbafcbc 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -62,6 +62,7 @@ static int __maps__insert(struct maps *maps, struct map *map) int maps__insert(struct maps *maps, struct map *map) { int err; + const struct dso *dso = map__dso(map); down_write(maps__lock(maps)); err = __maps__insert(maps, map); @@ -70,7 +71,7 @@ int maps__insert(struct maps *maps, struct map *map) ++maps->nr_maps; - if (map->dso && map->dso->kernel) { + if (dso && dso->kernel) { struct kmap *kmap = map__kmap(map); if (kmap) @@ -253,7 +254,7 @@ size_t maps__fprintf(struct maps *maps, FILE *fp) printed += fprintf(fp, "Map:"); printed += map__fprintf(pos->map, fp); if (verbose > 2) { - printed += dso__fprintf(pos->map->dso, fp); + printed += dso__fprintf(map__dso(pos->map), fp); printed += fprintf(fp, "--\n"); } } @@ -307,7 +308,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) if (use_browser) { pr_debug("overlapping maps in %s (disable tui for more info)\n", - map->dso->name); + map__dso(map)->name); } else { fputs("overlapping maps:\n", fp); map__fprintf(map, fp); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cdf5d655d84c..b26670a26005 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -165,8 +165,9 @@ static struct map *kernel_get_module_map(const char *module) maps__for_each_entry(maps, pos) { /* short_name is "[module]" */ - const char *short_name = pos->map->dso->short_name; - u16 short_name_len = pos->map->dso->short_name_len; + struct dso *dso = map__dso(pos->map); + const char *short_name = dso->short_name; + u16 short_name_len = dso->short_name_len; if (strncmp(short_name + 1, module, short_name_len - 2) == 0 && @@ -182,13 +183,15 @@ struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user) /* Init maps of given executable or kernel */ if (user) { struct map *map; + struct dso *dso; map = dso__new_map(target); - if (map && map->dso) { - mutex_lock(&map->dso->lock); - nsinfo__put(map->dso->nsinfo); - map->dso->nsinfo = nsinfo__get(nsi); - mutex_unlock(&map->dso->lock); + dso = map ? map__dso(map) : NULL; + if (dso) { + mutex_lock(&dso->lock); + nsinfo__put(dso->nsinfo); + dso->nsinfo = nsinfo__get(nsi); + mutex_unlock(&dso->lock); } return map; } else { @@ -341,7 +344,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) snprintf(module_name, sizeof(module_name), "[%s]", module); map = maps__find_by_name(machine__kernel_maps(host_machine), module_name); if (map) { - dso = map->dso; + dso = map__dso(map); goto found; } pr_debug("Failed to find module %s.\n", module); @@ -349,7 +352,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) } map = machine__kernel_map(host_machine); - dso = map->dso; + dso = map__dso(map); if (!dso->has_build_id) dso__read_running_kernel_build_id(dso, host_machine); @@ -3737,6 +3740,7 @@ int show_available_funcs(const char *target, struct nsinfo *nsi, { struct rb_node *nd; struct map *map; + struct dso *dso; int ret; ret = init_probe_symbol_maps(user); @@ -3762,14 +3766,14 @@ int show_available_funcs(const char *target, struct nsinfo *nsi, (target) ? : "kernel"); goto end; } - if (!dso__sorted_by_name(map->dso)) - dso__sort_by_name(map->dso); + dso = map__dso(map); + if (!dso__sorted_by_name(dso)) + dso__sort_by_name(dso); /* Show all (filtered) symbols */ setup_pager(); - for (nd = rb_first_cached(&map->dso->symbol_names); nd; - nd = rb_next(nd)) { + for (nd = rb_first_cached(&dso->symbol_names); nd; nd = rb_next(nd)) { struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); if (strfilter__compare(_filter, pos->sym.name)) diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 83fd2fd0ba16..039d0365ad41 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -315,12 +315,14 @@ static SV *perl_process_callchain(struct perf_sample *sample, if (node->ms.map) { struct map *map = node->ms.map; + struct dso *dso = map ? map__dso(map) : NULL; const char *dsoname = "[unknown]"; - if (map && map->dso) { - if (symbol_conf.show_kernel_path && map->dso->long_name) - dsoname = map->dso->long_name; + + if (dso) { + if (symbol_conf.show_kernel_path && dso->long_name) + dsoname = dso->long_name; else - dsoname = map->dso->name; + dsoname = dso->name; } if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { hv_undef(elem); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index e5cc18f6fcda..b8e5c6f61d80 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -390,12 +390,13 @@ static PyObject *get_field_numeric_entry(struct tep_event *event, static const char *get_dsoname(struct map *map) { const char *dsoname = "[unknown]"; + struct dso *dso = map ? map__dso(map) : NULL; - if (map && map->dso) { - if (symbol_conf.show_kernel_path && map->dso->long_name) - dsoname = map->dso->long_name; + if (dso) { + if (symbol_conf.show_kernel_path && dso->long_name) + dsoname = dso->long_name; else - dsoname = map->dso->name; + dsoname = dso->name; } return dsoname; @@ -780,9 +781,10 @@ static void set_sym_in_dict(PyObject *dict, struct addr_location *al, char sbuild_id[SBUILD_ID_SIZE]; if (al->map) { - pydict_set_item_string_decref(dict, dso_field, - _PyUnicode_FromString(al->map->dso->name)); - build_id__sprintf(&al->map->dso->bid, sbuild_id); + struct dso *dso = map__dso(al->map); + + pydict_set_item_string_decref(dict, dso_field, _PyUnicode_FromString(dso->name)); + build_id__sprintf(&dso->bid, sbuild_id); pydict_set_item_string_decref(dict, dso_bid_field, _PyUnicode_FromString(sbuild_id)); pydict_set_item_string_decref(dict, dso_map_start, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 430f67e7cc82..f161589aefda 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -230,8 +230,8 @@ struct sort_entry sort_comm = { static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) { - struct dso *dso_l = map_l ? map_l->dso : NULL; - struct dso *dso_r = map_r ? map_r->dso : NULL; + struct dso *dso_l = map_l ? map__dso(map_l) : NULL; + struct dso *dso_r = map_r ? map__dso(map_r) : NULL; const char *dso_name_l, *dso_name_r; if (!dso_l || !dso_r) @@ -257,13 +257,13 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) static int _hist_entry__dso_snprintf(struct map *map, char *bf, size_t size, unsigned int width) { - if (map && map->dso) { - const char *dso_name = verbose > 0 ? map->dso->long_name : - map->dso->short_name; - return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); - } + const struct dso *dso = map ? map__dso(map) : NULL; + const char *dso_name = "[unknown]"; + + if (dso) + dso_name = verbose > 0 ? dso->long_name : dso->short_name; - return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); + return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); } static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, @@ -279,7 +279,7 @@ static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *a if (type != HIST_FILTER__DSO) return -1; - return dso && (!he->ms.map || he->ms.map->dso != dso); + return dso && (!he->ms.map || map__dso(he->ms.map) != dso); } struct sort_entry sort_dso = { @@ -359,11 +359,11 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms, size_t ret = 0; if (verbose > 0) { - char o = map ? dso__symtab_origin(map->dso) : '!'; + struct dso *dso = map ? map__dso(map) : NULL; + char o = dso ? dso__symtab_origin(dso) : '!'; u64 rip = ip; - if (map && map->dso && map->dso->kernel - && map->dso->adjust_symbols) + if (dso && dso->kernel && dso->adjust_symbols) rip = map->unmap_ip(map, ip); ret += repsep_snprintf(bf, size, "%-#*llx %c ", @@ -641,7 +641,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e) if (!map) return no_srcfile; - sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), + sf = __get_srcline(map__dso(map), map__rip_2objdump(map, e->ip), e->ms.sym, false, true, true, e->ip); if (!strcmp(sf, SRCLINE_UNKNOWN)) return no_srcfile; @@ -982,7 +982,7 @@ static int hist_entry__dso_from_filter(struct hist_entry *he, int type, return -1; return dso && (!he->branch_info || !he->branch_info->from.ms.map || - he->branch_info->from.ms.map->dso != dso); + map__dso(he->branch_info->from.ms.map) != dso); } static int64_t @@ -1014,7 +1014,7 @@ static int hist_entry__dso_to_filter(struct hist_entry *he, int type, return -1; return dso && (!he->branch_info || !he->branch_info->to.ms.map || - he->branch_info->to.ms.map->dso != dso); + map__dso(he->branch_info->to.ms.map) != dso); } static int64_t @@ -1506,6 +1506,7 @@ sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) { u64 l, r; struct map *l_map, *r_map; + struct dso *l_dso, *r_dso; int rc; if (!left->mem_info) return -1; @@ -1525,7 +1526,9 @@ sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) if (!l_map) return -1; if (!r_map) return 1; - rc = dso__cmp_id(l_map->dso, r_map->dso); + l_dso = map__dso(l_map); + r_dso = map__dso(r_map); + rc = dso__cmp_id(l_dso, r_dso); if (rc) return rc; /* @@ -1537,9 +1540,8 @@ sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) */ if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && - (!(l_map->flags & MAP_SHARED)) && - !l_map->dso->id.maj && !l_map->dso->id.min && - !l_map->dso->id.ino && !l_map->dso->id.ino_generation) { + (!(l_map->flags & MAP_SHARED)) && !l_dso->id.maj && !l_dso->id.min && + !l_dso->id.ino && !l_dso->id.ino_generation) { /* userspace anonymous */ if (left->thread->pid_ > right->thread->pid_) return -1; @@ -1567,6 +1569,7 @@ static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, if (he->mem_info) { struct map *map = he->mem_info->daddr.ms.map; + struct dso *dso = map__dso(map); addr = cl_address(he->mem_info->daddr.al_addr, chk_double_cl); ms = &he->mem_info->daddr.ms; @@ -1575,8 +1578,7 @@ static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && map && !(map->prot & PROT_EXEC) && (map->flags & MAP_SHARED) && - (map->dso->id.maj || map->dso->id.min || - map->dso->id.ino || map->dso->id.ino_generation)) + (dso->id.maj || dso->id.min || dso->id.ino || dso->id.ino_generation)) level = 's'; else if (!map) level = 'X'; @@ -2072,9 +2074,8 @@ sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right) static int _hist_entry__dso_size_snprintf(struct map *map, char *bf, size_t bf_size, unsigned int width) { - if (map && map->dso) - return repsep_snprintf(bf, bf_size, "%*d", width, - map__size(map)); + if (map && map__dso(map)) + return repsep_snprintf(bf, bf_size, "%*d", width, map__size(map)); return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); } diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 3084e556d3eb..561372869792 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1435,7 +1435,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, *curr_mapp = curr_map; *curr_dsop = curr_dso; } else - *curr_dsop = curr_map->dso; + *curr_dsop = map__dso(curr_map); return 0; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 316b63fb5691..a1c85c22676f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -791,6 +791,7 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) *root = RB_ROOT_CACHED; while (next) { + struct dso *curr_map_dso; char *module; pos = rb_entry(next, struct symbol, rb_node); @@ -808,13 +809,13 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) symbol__delete(pos); continue; } - + curr_map_dso = map__dso(curr_map); pos->start -= curr_map->start - curr_map->pgoff; if (pos->end > curr_map->end) pos->end = curr_map->end; if (pos->end) pos->end -= curr_map->start - curr_map->pgoff; - symbols__insert(&curr_map->dso->symbols, pos); + symbols__insert(&curr_map_dso->symbols, pos); ++count; } @@ -856,12 +857,14 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, module = strchr(pos->name, '\t'); if (module) { + struct dso *curr_map_dso; + if (!symbol_conf.use_modules) goto discard_symbol; *module++ = '\0'; - - if (strcmp(curr_map->dso->short_name, module)) { + curr_map_dso = map__dso(curr_map); + if (strcmp(curr_map_dso->short_name, module)) { if (curr_map != initial_map && dso->kernel == DSO_SPACE__KERNEL_GUEST && machine__is_default_guest(machine)) { @@ -872,7 +875,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, * symbols are in its kmap. Mark it as * loaded. */ - dso__set_loaded(curr_map->dso); + dso__set_loaded(curr_map_dso); } curr_map = maps__find_by_name(kmaps, module); @@ -884,8 +887,8 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, curr_map = initial_map; goto discard_symbol; } - - if (curr_map->dso->loaded && + curr_map_dso = map__dso(curr_map); + if (curr_map_dso->loaded && !machine__is_default_guest(machine)) goto discard_symbol; } @@ -954,8 +957,10 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, } add_symbol: if (curr_map != initial_map) { + struct dso *curr_map_dso = map__dso(curr_map); + rb_erase_cached(&pos->rb_node, root); - symbols__insert(&curr_map->dso->symbols, pos); + symbols__insert(&curr_map_dso->symbols, pos); ++moved; } else ++count; @@ -969,7 +974,7 @@ discard_symbol: if (curr_map != initial_map && dso->kernel == DSO_SPACE__KERNEL_GUEST && machine__is_default_guest(maps__machine(kmaps))) { - dso__set_loaded(curr_map->dso); + dso__set_loaded(map__dso(curr_map)); } return count + moved; @@ -1143,13 +1148,14 @@ static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) maps__for_each_entry(kmaps, old_node) { struct map *old_map = old_node->map; struct module_info *mi; + struct dso *dso; if (!__map__is_kmodule(old_map)) { continue; } - + dso = map__dso(old_map); /* Module must be in memory at the same address */ - mi = find_module(old_map->dso->short_name, &modules); + mi = find_module(dso->short_name, &modules); if (!mi || mi->start != old_map->start) { err = -EINVAL; goto out; @@ -2047,14 +2053,17 @@ out: static int map__strcmp(const void *a, const void *b) { - const struct map *ma = *(const struct map **)a, *mb = *(const struct map **)b; - return strcmp(ma->dso->short_name, mb->dso->short_name); + const struct dso *dso_a = map__dso(*(const struct map **)a); + const struct dso *dso_b = map__dso(*(const struct map **)b); + + return strcmp(dso_a->short_name, dso_b->short_name); } static int map__strcmp_name(const void *name, const void *b) { - const struct map *map = *(const struct map **)b; - return strcmp(name, map->dso->short_name); + const struct dso *dso = map__dso(*(const struct map **)b); + + return strcmp(name, dso->short_name); } void __maps__sort_by_name(struct maps *maps) @@ -2111,10 +2120,13 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) down_read(maps__lock(maps)); - if (maps->last_search_by_name && - strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { - map = maps->last_search_by_name; - goto out_unlock; + if (maps->last_search_by_name) { + const struct dso *dso = map__dso(maps->last_search_by_name); + + if (strcmp(dso->short_name, name) == 0) { + map = maps->last_search_by_name; + goto out_unlock; + } } /* * If we have maps->maps_by_name, then the name isn't in the rbtree, @@ -2127,8 +2139,11 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) /* Fallback to traversing the rbtree... */ maps__for_each_entry(maps, rb_node) { + struct dso *dso; + map = rb_node->map; - if (strcmp(map->dso->short_name, name) == 0) { + dso = map__dso(map); + if (strcmp(dso->short_name, name) == 0) { maps->last_search_by_name = map; goto out_unlock; } diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index 57b95c1d7e39..fbd1a882b013 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -693,12 +693,14 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t maps__for_each_entry(maps, pos) { struct map *map = pos->map; + struct dso *dso; if (!__map__is_kmodule(map)) continue; + dso = map__dso(map); if (symbol_conf.buildid_mmap2) { - size = PERF_ALIGN(map->dso->long_name_len + 1, sizeof(u64)); + size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); event->mmap2.header.type = PERF_RECORD_MMAP2; event->mmap2.header.size = (sizeof(event->mmap2) - (sizeof(event->mmap2.filename) - size)); @@ -708,12 +710,11 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t event->mmap2.len = map->end - map->start; event->mmap2.pid = machine->pid; - memcpy(event->mmap2.filename, map->dso->long_name, - map->dso->long_name_len + 1); + memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1); perf_record_mmap2__read_build_id(&event->mmap2, machine, false); } else { - size = PERF_ALIGN(map->dso->long_name_len + 1, sizeof(u64)); + size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); @@ -723,8 +724,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t event->mmap.len = map->end - map->start; event->mmap.pid = machine->pid; - memcpy(event->mmap.filename, map->dso->long_name, - map->dso->long_name_len + 1); + memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1); } if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 292585a52281..bb7a2ce82d46 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -448,23 +448,27 @@ struct thread *thread__main_thread(struct machine *machine, struct thread *threa int thread__memcpy(struct thread *thread, struct machine *machine, void *buf, u64 ip, int len, bool *is64bit) { - u8 cpumode = PERF_RECORD_MISC_USER; - struct addr_location al; - long offset; + u8 cpumode = PERF_RECORD_MISC_USER; + struct addr_location al; + struct dso *dso; + long offset; - if (machine__kernel_ip(machine, ip)) - cpumode = PERF_RECORD_MISC_KERNEL; + if (machine__kernel_ip(machine, ip)) + cpumode = PERF_RECORD_MISC_KERNEL; - if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso || - al.map->dso->data.status == DSO_DATA_STATUS_ERROR || - map__load(al.map) < 0) - return -1; + if (!thread__find_map(thread, cpumode, ip, &al)) + return -1; - offset = al.map->map_ip(al.map, ip); - if (is64bit) - *is64bit = al.map->dso->is_64_bit; + dso = map__dso(al.map); - return dso__data_read_offset(al.map->dso, machine, offset, buf, len); + if( !dso || dso->data.status == DSO_DATA_STATUS_ERROR || map__load(al.map) < 0) + return -1; + + offset = al.map->map_ip(al.map, ip); + if (is64bit) + *is64bit = dso->is_64_bit; + + return dso__data_read_offset(dso, machine, offset, buf, len); } void thread__free_stitch_list(struct thread *thread) diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 94aa40f6e348..c8cba9d4bfd9 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -52,7 +52,7 @@ static int __report_module(struct addr_location *al, u64 ip, thread__find_symbol(ui->thread, PERF_RECORD_MISC_USER, ip, al); if (al->map) - dso = al->map->dso; + dso = map__dso(al->map); if (!dso) return 0; @@ -134,17 +134,17 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr, { struct addr_location al; ssize_t size; + struct dso *dso; if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) { pr_debug("unwind: no map for %lx\n", (unsigned long)addr); return -1; } - - if (!al.map->dso) + dso = map__dso(al.map); + if (!dso) return -1; - size = dso__data_read_addr(al.map->dso, al.map, ui->machine, - addr, (u8 *) data, sizeof(*data)); + size = dso__data_read_addr(dso, al.map, ui->machine, addr, (u8 *) data, sizeof(*data)); return !(size == sizeof(*data)); } diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index c487a249b33c..108f7b1697a7 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -328,7 +328,7 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, maps__for_each_entry(ui->thread->maps, map_node) { struct map *map = map_node->map; - if (map->dso == dso && map->start < base_addr) + if (map__dso(map) == dso && map->start < base_addr) base_addr = map->start; } base_addr -= dso->data.elf_base_addr; @@ -424,19 +424,23 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, { struct unwind_info *ui = arg; struct map *map; + struct dso *dso; unw_dyn_info_t di; u64 table_data, segbase, fde_count; int ret = -EINVAL; map = find_map(ip, ui); - if (!map || !map->dso) + if (!map) return -EINVAL; - pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); + dso = map__dso(map); + if (!dso) + return -EINVAL; + + pr_debug("unwind: find_proc_info dso %s\n", dso->name); /* Check the .eh_frame section for unwinding info */ - if (!read_unwind_spec_eh_frame(map->dso, ui, - &table_data, &segbase, &fde_count)) { + if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count)) { memset(&di, 0, sizeof(di)); di.format = UNW_INFO_FORMAT_REMOTE_TABLE; di.start_ip = map->start; @@ -452,16 +456,16 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, #ifndef NO_LIBUNWIND_DEBUG_FRAME /* Check the .debug_frame section for unwinding info */ if (ret < 0 && - !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { - int fd = dso__data_get_fd(map->dso, ui->machine); - int is_exec = elf_is_exec(fd, map->dso->name); + !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) { + int fd = dso__data_get_fd(dso, ui->machine); + int is_exec = elf_is_exec(fd, dso->name); unw_word_t base = is_exec ? 0 : map->start; const char *symfile; if (fd >= 0) - dso__data_put_fd(map->dso); + dso__data_put_fd(dso); - symfile = map->dso->symsrc_filename ?: map->dso->name; + symfile = dso->symsrc_filename ?: dso->name; memset(&di, 0, sizeof(di)); if (dwarf_find_debug_frame(0, &di, ip, base, symfile, @@ -513,6 +517,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, unw_word_t *data) { struct map *map; + struct dso *dso; ssize_t size; map = find_map(addr, ui); @@ -521,10 +526,12 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, return -1; } - if (!map->dso) + dso = map__dso(map); + + if (!dso) return -1; - size = dso__data_read_addr(map->dso, map, ui->machine, + size = dso__data_read_addr(dso, map, ui->machine, addr, (u8 *) data, sizeof(*data)); return !(size == sizeof(*data)); diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 42528ade513e..4378daaafcd3 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -22,6 +22,7 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized const char *arch; enum dso_type dso_type; struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; + struct dso *dso = map__dso(map); struct machine *machine; int err; @@ -29,8 +30,7 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized return 0; if (maps__addr_space(maps)) { - pr_debug("unwind: thread map already set, dso=%s\n", - map->dso->name); + pr_debug("unwind: thread map already set, dso=%s\n", dso->name); if (initialized) *initialized = true; return 0; @@ -41,7 +41,7 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized if (!machine->env || !machine->env->arch) goto out_register; - dso_type = dso__type(map->dso, machine); + dso_type = dso__type(dso, machine); if (dso_type == DSO__TYPE_UNKNOWN) return 0; diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 835c39efb80d..ec777ee11493 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -147,7 +147,7 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, struct map_rb_node *rb_node; maps__for_each_entry(thread->maps, rb_node) { - struct dso *dso = rb_node->map->dso; + struct dso *dso = map__dso(rb_node->map); if (!dso || dso->long_name[0] != '/') continue; -- cgit v1.2.3 From e5116f46d44b72ede59a6923829f68a8b8f84e76 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 20 Mar 2023 14:22:36 -0700 Subject: perf map: Add accessor for start and end Later changes will add reference count checking for struct map, start and end are frequently accessed variables. Add an accessor so that the reference count check is only necessary in one place. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230320212248.1175731-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/tests/dwarf-unwind.c | 2 +- tools/perf/arch/arm64/tests/dwarf-unwind.c | 2 +- tools/perf/arch/powerpc/tests/dwarf-unwind.c | 2 +- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 2 +- tools/perf/arch/x86/tests/dwarf-unwind.c | 2 +- tools/perf/arch/x86/util/event.c | 4 +- tools/perf/builtin-buildid-list.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/tests/code-reading.c | 8 ++-- tools/perf/tests/maps.c | 4 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 14 +++---- tools/perf/util/annotate.c | 4 +- tools/perf/util/dlfilter.c | 8 ++-- tools/perf/util/intel-pt.c | 8 ++-- tools/perf/util/machine.c | 14 +++---- tools/perf/util/map.c | 8 ++-- tools/perf/util/map.h | 12 +++++- tools/perf/util/maps.c | 30 +++++++------- tools/perf/util/probe-event.c | 4 +- .../util/scripting-engines/trace-event-python.c | 6 +-- tools/perf/util/symbol-elf.c | 8 ++-- tools/perf/util/symbol.c | 48 +++++++++++----------- tools/perf/util/symbol_fprintf.c | 2 +- tools/perf/util/synthetic-events.c | 16 ++++---- tools/perf/util/unwind-libdw.c | 6 +-- tools/perf/util/unwind-libunwind-local.c | 15 +++---- 29 files changed, 125 insertions(+), 114 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/arm/tests/dwarf-unwind.c b/tools/perf/arch/arm/tests/dwarf-unwind.c index ccfa87055c4a..566fb6c0eae7 100644 --- a/tools/perf/arch/arm/tests/dwarf-unwind.c +++ b/tools/perf/arch/arm/tests/dwarf-unwind.c @@ -33,7 +33,7 @@ static int sample_ustack(struct perf_sample *sample, return -1; } - stack_size = map->end - sp; + stack_size = map__end(map) - sp; stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size; memcpy(buf, (void *) sp, stack_size); diff --git a/tools/perf/arch/arm64/tests/dwarf-unwind.c b/tools/perf/arch/arm64/tests/dwarf-unwind.c index 46147a483049..90a7ef293ce7 100644 --- a/tools/perf/arch/arm64/tests/dwarf-unwind.c +++ b/tools/perf/arch/arm64/tests/dwarf-unwind.c @@ -33,7 +33,7 @@ static int sample_ustack(struct perf_sample *sample, return -1; } - stack_size = map->end - sp; + stack_size = map__end(map) - sp; stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size; memcpy(buf, (void *) sp, stack_size); diff --git a/tools/perf/arch/powerpc/tests/dwarf-unwind.c b/tools/perf/arch/powerpc/tests/dwarf-unwind.c index c9cb4b059392..32fffb593fbf 100644 --- a/tools/perf/arch/powerpc/tests/dwarf-unwind.c +++ b/tools/perf/arch/powerpc/tests/dwarf-unwind.c @@ -33,7 +33,7 @@ static int sample_ustack(struct perf_sample *sample, return -1; } - stack_size = map->end - sp; + stack_size = map__end(map) - sp; stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size; memcpy(buf, (void *) sp, stack_size); diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index fe0e4530673c..b7223feec770 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -262,7 +262,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) return skip_slot; } - rc = check_return_addr(dso, al.map->start, ip); + rc = check_return_addr(dso, map__start(al.map), ip); pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n", dso->long_name, al.sym->name, ip, rc); diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c index a54dea7c112f..497593be80f2 100644 --- a/tools/perf/arch/x86/tests/dwarf-unwind.c +++ b/tools/perf/arch/x86/tests/dwarf-unwind.c @@ -33,7 +33,7 @@ static int sample_ustack(struct perf_sample *sample, return -1; } - stack_size = map->end - sp; + stack_size = map__end(map) - sp; stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size; memcpy(buf, (void *) sp, stack_size); diff --git a/tools/perf/arch/x86/util/event.c b/tools/perf/arch/x86/util/event.c index 17bf60babfbd..3b2475707756 100644 --- a/tools/perf/arch/x86/util/event.c +++ b/tools/perf/arch/x86/util/event.c @@ -59,8 +59,8 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, event->mmap.header.size = size; - event->mmap.start = map->start; - event->mmap.len = map->end - map->start; + event->mmap.start = map__start(map); + event->mmap.len = map__size(map); event->mmap.pgoff = map->pgoff; event->mmap.pid = machine->pid; diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index cad9ed44ce7c..eea28cbcc0b7 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -30,7 +30,7 @@ static int buildid__map_cb(struct map *map, void *arg __maybe_unused) memset(bid_buf, 0, sizeof(bid_buf)); if (dso->has_build_id) build_id__sprintf(&dso->bid, bid_buf); - printf("%s %16" PRIx64 " %16" PRIx64, bid_buf, map->start, map->end); + printf("%s %16" PRIx64 " %16" PRIx64, bid_buf, map__start(map), map__end(map)); if (dso->long_name != NULL) { printf(" %s", dso->long_name); } else if (dso->short_name != NULL) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ff239b89e4d0..2a6e2cee5e0d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -851,7 +851,7 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) const struct dso *dso = map__dso(map); printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", - indent, "", map->start, map->end, + indent, "", map__start(map), map__end(map), map->prot & PROT_READ ? 'r' : '-', map->prot & PROT_WRITE ? 'w' : '-', map->prot & PROT_EXEC ? 'x' : '-', diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 27fd9c203600..1d078106abc4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1209,7 +1209,7 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread, if (al.addr < al.sym->end) off = al.addr - al.sym->start; else - off = al.addr - al.map->start - al.sym->start; + off = al.addr - map__start(al.map) - al.sym->start; printed += fprintf(fp, "\t%s", al.sym->name); if (off) printed += fprintf(fp, "%+d", off); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index babfc163efe2..b803af4329d1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -183,7 +183,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) "Not all samples will be on the annotation output.\n\n" "Please report to linux-kernel@vger.kernel.org\n", ip, dso->long_name, dso__symtab_origin(dso), - map->start, map->end, sym->start, sym->end, + map__start(map), map__end(map), sym->start, sym->end, sym->binding == STB_GLOBAL ? 'g' : sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, err ? "[unknown]" : uts.machine, diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 936c61546e64..1545fcaa95c6 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -265,8 +265,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len = BUFSZ; /* Do not go off the map */ - if (addr + len > al.map->end) - len = al.map->end - addr; + if (addr + len > map__end(al.map)) + len = map__end(al.map) - addr; /* Read the object code using perf */ ret_len = dso__data_read_offset(dso, maps__machine(thread->maps), @@ -291,7 +291,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, size_t d; for (d = 0; d < state->done_cnt; d++) { - if (state->done[d] == al.map->start) { + if (state->done[d] == map__start(al.map)) { pr_debug("kcore map tested already"); pr_debug(" - skipping\n"); goto out; @@ -301,7 +301,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, pr_debug("Too many kcore maps - skipping\n"); goto out; } - state->done[state->done_cnt++] = al.map->start; + state->done[state->done_cnt++] = map__start(al.map); } objdump_name = dso->long_name; diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index ae7028fbf79e..fd0c464fcf95 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -24,8 +24,8 @@ static int check_maps(struct map_def *merged, unsigned int size, struct maps *ma if (i > 0) TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size)); - TEST_ASSERT_VAL("wrong map start", map->start == merged[i].start); - TEST_ASSERT_VAL("wrong map end", map->end == merged[i].end); + TEST_ASSERT_VAL("wrong map start", map__start(map) == merged[i].start); + TEST_ASSERT_VAL("wrong map end", map__end(map) == merged[i].end); TEST_ASSERT_VAL("wrong map name", !strcmp(map__dso(map)->name, merged[i].name)); TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1); diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index a4301fc7b770..5cc4644e353d 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -202,7 +202,7 @@ static int mmap_events(synth_cb synth) break; } - pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start); + pr_debug("map %p, addr %" PRIx64 "\n", al.map, map__start(al.map)); } machine__delete_threads(machine); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index c614c2db7e89..0a75623172c2 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -267,7 +267,7 @@ next_pair: continue; } - } else if (mem_start == kallsyms.vmlinux_map->end) { + } else if (mem_start == map__end(kallsyms.vmlinux_map)) { /* * Ignore aliases to _etext, i.e. to the end of the kernel text area, * such as __indirect_thunk_end. @@ -319,14 +319,14 @@ next_pair: maps__for_each_entry(maps, rb_node) { struct map *pair, *map = rb_node->map; - mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start); - mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end); + mem_start = vmlinux_map->unmap_ip(vmlinux_map, map__start(map)); + mem_end = vmlinux_map->unmap_ip(vmlinux_map, map__end(map)); pair = maps__find(kallsyms.kmaps, mem_start); if (pair == NULL || pair->priv) continue; - if (pair->start == mem_start) { + if (map__start(pair) == mem_start) { struct dso *dso = map__dso(map); if (!header_printed) { @@ -335,10 +335,10 @@ next_pair: } pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", - map->start, map->end, map->pgoff, dso->name); - if (mem_end != pair->end) + map__start(map), map__end(map), map->pgoff, dso->name); + if (mem_end != map__end(pair)) pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, - pair->start, pair->end, pair->pgoff); + map__start(pair), map__end(pair), pair->pgoff); pr_info(" %s\n", dso->name); pair->priv = 1; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 84100ca5f306..b9cff782d7df 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1008,13 +1008,13 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, if (start && (start->ms.sym == ams->ms.sym || (ams->ms.sym && - start->addr == ams->ms.sym->start + ams->ms.map->start))) + start->addr == ams->ms.sym->start + map__start(ams->ms.map)))) saddr = start->al_addr; if (saddr == 0) pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n", ams->addr, start ? start->addr : 0, - ams->ms.sym ? ams->ms.sym->start + ams->ms.map->start : 0, + ams->ms.sym ? ams->ms.sym->start + map__start(ams->ms.map) : 0, saddr); err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles); if (err) diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 8a7ffe0d805a..fe401fa4be02 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -51,7 +51,7 @@ static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al) if (al->addr < sym->end) d_al->symoff = al->addr - sym->start; else - d_al->symoff = al->addr - al->map->start - sym->start; + d_al->symoff = al->addr - map__start(al->map) - sym->start; d_al->sym_binding = sym->binding; } else { d_al->sym = NULL; @@ -268,7 +268,7 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len) map = al->map; - if (map && ip >= map->start && ip < map->end && + if (map && ip >= map__start(map) && ip < map__end(map) && machine__kernel_ip(d->machine, ip) == machine__kernel_ip(d->machine, d->sample->ip)) goto have_map; @@ -279,8 +279,8 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len) map = a.map; have_map: offset = map->map_ip(map, ip); - if (ip + len >= map->end) - len = map->end - ip; + if (ip + len >= map__end(map)) + len = map__end(map) - ip; return dso__data_read_offset(map__dso(map), d->machine, offset, buf, len); } diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 8cec88e09792..a2e62daa708e 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -887,7 +887,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, goto out_no_cache; } - if (*ip >= al.map->end) + if (*ip >= map__end(al.map)) break; offset += intel_pt_insn->length; @@ -2750,7 +2750,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (sym->binding == STB_GLOBAL && !strcmp(sym->name, "__switch_to")) { ip = map->unmap_ip(map, sym->start); - if (ip >= map->start && ip < map->end) { + if (ip >= map__start(map) && ip < map__end(map)) { switch_ip = ip; break; } @@ -2768,7 +2768,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) for (sym = start; sym; sym = dso__next_symbol(sym)) { if (!strcmp(sym->name, ptss)) { ip = map->unmap_ip(map, sym->start); - if (ip >= map->start && ip < map->end) { + if (ip >= map__start(map) && ip < map__end(map)) { *ptss_ip = ip; break; } @@ -3356,7 +3356,7 @@ static int intel_pt_process_aux_output_hw_id(struct intel_pt *pt, static int intel_pt_find_map(struct thread *thread, u8 cpumode, u64 addr, struct addr_location *al) { - if (!al->map || addr < al->map->start || addr >= al->map->end) { + if (!al->map || addr < map__start(al->map) || addr >= map__end(al->map)) { if (!thread__find_map(thread, cpumode, addr, al)) return -1; } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 8bae38c96788..7852b97da10a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -903,7 +903,7 @@ static int machine__process_ksymbol_register(struct machine *machine, } map->start = event->ksymbol.addr; - map->end = map->start + event->ksymbol.len; + map->end = map__start(map) + event->ksymbol.len; err = maps__insert(machine__kernel_maps(machine), map); map__put(map); if (err) @@ -919,7 +919,7 @@ static int machine__process_ksymbol_register(struct machine *machine, dso = map__dso(map); } - sym = symbol__new(map->map_ip(map, map->start), + sym = symbol__new(map->map_ip(map, map__start(map)), event->ksymbol.len, 0, 0, event->ksymbol.name); if (!sym) @@ -944,7 +944,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, else { struct dso *dso = map__dso(map); - sym = dso__find_symbol(dso, map->map_ip(map, map->start)); + sym = dso__find_symbol(dso, map->map_ip(map, map__start(map))); if (sym) dso__delete_symbol(dso, sym); } @@ -1217,7 +1217,7 @@ int machine__create_extra_kernel_map(struct machine *machine, if (!err) { pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n", - kmap->name, map->start, map->end); + kmap->name, map__start(map), map__end(map)); } map__put(map); @@ -1722,7 +1722,7 @@ int machine__create_kernel_maps(struct machine *machine) struct map_rb_node *next = map_rb_node__next(rb_node); if (next) - machine__set_kernel_mmap(machine, start, next->map->start); + machine__set_kernel_mmap(machine, start, map__start(next->map)); } out_put: @@ -1795,7 +1795,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, if (map == NULL) goto out_problem; - map->end = map->start + xm->end - xm->start; + map->end = map__start(map) + xm->end - xm->start; if (build_id__is_defined(bid)) dso__set_build_id(map__dso(map), bid); @@ -3293,7 +3293,7 @@ int machine__get_kernel_start(struct machine *machine) * kernel_start = 1ULL << 63 for x86_64. */ if (!err && !machine__is(machine, "x86_64")) - machine->kernel_start = map->start; + machine->kernel_start = map__start(map); } return err; } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 90062af6675a..416fc449bde8 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -421,7 +421,7 @@ size_t map__fprintf(struct map *map, FILE *fp) const struct dso *dso = map__dso(map); return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", - map->start, map->end, map->pgoff, dso->name); + map__start(map), map__end(map), map->pgoff, dso->name); } size_t map__fprintf_dsoname(struct map *map, FILE *fp) @@ -558,7 +558,7 @@ bool map__contains_symbol(const struct map *map, const struct symbol *sym) { u64 ip = map->unmap_ip(map, sym->start); - return ip >= map->start && ip < map->end; + return ip >= map__start(map) && ip < map__end(map); } struct kmap *__map__kmap(struct map *map) @@ -592,12 +592,12 @@ struct maps *map__kmaps(struct map *map) u64 map__map_ip(const struct map *map, u64 ip) { - return ip - map->start + map->pgoff; + return ip - map__start(map) + map->pgoff; } u64 map__unmap_ip(const struct map *map, u64 ip) { - return ip + map->start - map->pgoff; + return ip + map__start(map) - map->pgoff; } u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 36c5add0144d..16646b94fa3a 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -52,9 +52,19 @@ static inline struct dso *map__dso(const struct map *map) return map->dso; } +static inline u64 map__start(const struct map *map) +{ + return map->start; +} + +static inline u64 map__end(const struct map *map) +{ + return map->end; +} + static inline size_t map__size(const struct map *map) { - return map->end - map->start; + return map__end(map) - map__start(map); } /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 09ec6bbafcbc..21010a2b8e16 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -34,7 +34,7 @@ static int __maps__insert(struct maps *maps, struct map *map) { struct rb_node **p = &maps__entries(maps)->rb_node; struct rb_node *parent = NULL; - const u64 ip = map->start; + const u64 ip = map__start(map); struct map_rb_node *m, *new_rb_node; new_rb_node = malloc(sizeof(*new_rb_node)); @@ -47,7 +47,7 @@ static int __maps__insert(struct maps *maps, struct map *map) while (*p != NULL) { parent = *p; m = rb_entry(parent, struct map_rb_node, rb_node); - if (ip < m->map->start) + if (ip < map__start(m->map)) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -229,7 +229,7 @@ out: int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) { - if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) { + if (ams->addr < map__start(ams->ms.map) || ams->addr >= map__end(ams->ms.map)) { if (maps == NULL) return -1; ams->ms.map = maps__find(maps, ams->addr); @@ -283,9 +283,9 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) while (next) { struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); - if (pos->map->end > map->start) { + if (map__end(pos->map) > map__start(map)) { first = next; - if (pos->map->start <= map->start) + if (map__start(pos->map) <= map__start(map)) break; next = next->rb_left; } else @@ -301,7 +301,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) * Stop if current map starts after map->end. * Maps are ordered by start: next will not overlap for sure. */ - if (pos->map->start >= map->end) + if (map__start(pos->map) >= map__end(map)) break; if (verbose >= 2) { @@ -321,7 +321,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) * Now check if we need to create new maps for areas not * overlapped by the new map: */ - if (map->start > pos->map->start) { + if (map__start(map) > map__start(pos->map)) { struct map *before = map__clone(pos->map); if (before == NULL) { @@ -329,7 +329,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - before->end = map->start; + before->end = map__start(map); err = __maps__insert(maps, before); if (err) goto put_map; @@ -339,7 +339,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) map__put(before); } - if (map->end < pos->map->end) { + if (map__end(map) < map__end(pos->map)) { struct map *after = map__clone(pos->map); if (after == NULL) { @@ -347,10 +347,10 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - after->start = map->end; - after->pgoff += map->end - pos->map->start; - assert(pos->map->map_ip(pos->map, map->end) == - after->map_ip(after, map->end)); + after->start = map__end(map); + after->pgoff += map__end(map) - map__start(pos->map); + assert(pos->map->map_ip(pos->map, map__end(map)) == + after->map_ip(after, map__end(map))); err = __maps__insert(maps, after); if (err) goto put_map; @@ -430,9 +430,9 @@ struct map *maps__find(struct maps *maps, u64 ip) p = maps__entries(maps)->rb_node; while (p != NULL) { m = rb_entry(p, struct map_rb_node, rb_node); - if (ip < m->map->start) + if (ip < map__start(m->map)) p = p->rb_left; - else if (ip >= m->map->end) + else if (ip >= map__end(m->map)) p = p->rb_right; else goto out; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b26670a26005..4d9dbeeb6014 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -143,7 +143,7 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, return -ENOENT; *addr = map->unmap_ip(map, sym->start) - ((reloc) ? 0 : map->reloc) - - ((reladdr) ? map->start : 0); + ((reladdr) ? map__start(map) : 0); } return 0; } @@ -257,7 +257,7 @@ static bool kprobe_warn_out_range(const char *symbol, u64 address) map = kernel_get_module_map(NULL); if (map) { - ret = address <= map->start || map->end < address; + ret = address <= map__start(map) || map__end(map) < address; if (ret) pr_warning("%s is out of .text, skip it.\n", symbol); map__put(map); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index b8e5c6f61d80..cbf09eaf3734 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -409,7 +409,7 @@ static unsigned long get_offset(struct symbol *sym, struct addr_location *al) if (al->addr < sym->end) offset = al->addr - sym->start; else - offset = al->addr - al->map->start - sym->start; + offset = al->addr - map__start(al->map) - sym->start; return offset; } @@ -788,9 +788,9 @@ static void set_sym_in_dict(PyObject *dict, struct addr_location *al, pydict_set_item_string_decref(dict, dso_bid_field, _PyUnicode_FromString(sbuild_id)); pydict_set_item_string_decref(dict, dso_map_start, - PyLong_FromUnsignedLong(al->map->start)); + PyLong_FromUnsignedLong(map__start(al->map))); pydict_set_item_string_decref(dict, dso_map_end, - PyLong_FromUnsignedLong(al->map->end)); + PyLong_FromUnsignedLong(map__end(al->map))); } if (al->sym) { pydict_set_item_string_decref(dict, sym_field, diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 561372869792..e715869eab8a 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1355,7 +1355,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, if (*remap_kernel && dso->kernel && !kmodule) { *remap_kernel = false; map->start = shdr->sh_addr + ref_reloc(kmap); - map->end = map->start + shdr->sh_size; + map->end = map__start(map) + shdr->sh_size; map->pgoff = shdr->sh_offset; map->map_ip = map__map_ip; map->unmap_ip = map__unmap_ip; @@ -1397,7 +1397,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, u64 start = sym->st_value; if (kmodule) - start += map->start + shdr->sh_offset; + start += map__start(map) + shdr->sh_offset; curr_dso = dso__new(dso_name); if (curr_dso == NULL) @@ -1415,7 +1415,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, if (adjust_kernel_syms) { curr_map->start = shdr->sh_addr + ref_reloc(kmap); - curr_map->end = curr_map->start + shdr->sh_size; + curr_map->end = map__start(curr_map) + shdr->sh_size; curr_map->pgoff = shdr->sh_offset; } else { curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; @@ -1536,7 +1536,7 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, * attempted to prelink vdso to its virtual address. */ if (dso__is_vdso(dso)) - map->reloc = map->start - dso->text_offset; + map->reloc = map__start(map) - dso->text_offset; dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap); /* diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a1c85c22676f..b91deb177091 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -278,8 +278,8 @@ void maps__fixup_end(struct maps *maps) down_write(maps__lock(maps)); maps__for_each_entry(maps, curr) { - if (prev != NULL && !prev->map->end) - prev->map->end = curr->map->start; + if (prev != NULL && !map__end(prev->map)) + prev->map->end = map__start(curr->map); prev = curr; } @@ -288,7 +288,7 @@ void maps__fixup_end(struct maps *maps) * We still haven't the actual symbols, so guess the * last map final address. */ - if (curr && !curr->map->end) + if (curr && !map__end(curr->map)) curr->map->end = ~0ULL; up_write(maps__lock(maps)); @@ -810,11 +810,11 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) continue; } curr_map_dso = map__dso(curr_map); - pos->start -= curr_map->start - curr_map->pgoff; - if (pos->end > curr_map->end) - pos->end = curr_map->end; + pos->start -= map__start(curr_map) - curr_map->pgoff; + if (pos->end > map__end(curr_map)) + pos->end = map__end(curr_map); if (pos->end) - pos->end -= curr_map->start - curr_map->pgoff; + pos->end -= map__start(curr_map) - curr_map->pgoff; symbols__insert(&curr_map_dso->symbols, pos); ++count; } @@ -1156,7 +1156,7 @@ static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) dso = map__dso(old_map); /* Module must be in memory at the same address */ mi = find_module(dso->short_name, &modules); - if (!mi || mi->start != old_map->start) { + if (!mi || mi->start != map__start(old_map)) { err = -EINVAL; goto out; } @@ -1250,7 +1250,7 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) return -ENOMEM; } - list_node->map->end = list_node->map->start + len; + list_node->map->end = map__start(list_node->map) + len; list_node->map->pgoff = pgoff; list_add(&list_node->node, &md->maps); @@ -1272,21 +1272,21 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) struct map *old_map = rb_node->map; /* no overload with this one */ - if (new_map->end < old_map->start || - new_map->start >= old_map->end) + if (map__end(new_map) < map__start(old_map) || + map__start(new_map) >= map__end(old_map)) continue; - if (new_map->start < old_map->start) { + if (map__start(new_map) < map__start(old_map)) { /* * |new...... * |old.... */ - if (new_map->end < old_map->end) { + if (map__end(new_map) < map__end(old_map)) { /* * |new......| -> |new..| * |old....| -> |old....| */ - new_map->end = old_map->start; + new_map->end = map__start(old_map); } else { /* * |new.............| -> |new..| |new..| @@ -1306,17 +1306,17 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) goto out; } - m->map->end = old_map->start; + m->map->end = map__start(old_map); list_add_tail(&m->node, &merged); - new_map->pgoff += old_map->end - new_map->start; - new_map->start = old_map->end; + new_map->pgoff += map__end(old_map) - map__start(new_map); + new_map->start = map__end(old_map); } } else { /* * |new...... * |old.... */ - if (new_map->end < old_map->end) { + if (map__end(new_map) < map__end(old_map)) { /* * |new..| -> x * |old.........| -> |old.........| @@ -1329,8 +1329,8 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) * |new......| -> |new...| * |old....| -> |old....| */ - new_map->pgoff += old_map->end - new_map->start; - new_map->start = old_map->end; + new_map->pgoff += map__end(old_map) - map__start(new_map); + new_map->start = map__end(old_map); } } } @@ -1428,9 +1428,9 @@ static int dso__load_kcore(struct dso *dso, struct map *map, list_for_each_entry(new_node, &md.maps, node) { struct map *new_map = new_node->map; - u64 new_size = new_map->end - new_map->start; + u64 new_size = map__size(new_map); - if (!(stext >= new_map->start && stext < new_map->end)) + if (!(stext >= map__start(new_map) && stext < map__end(new_map))) continue; /* @@ -1457,8 +1457,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, list_del_init(&new_node->node); if (new_map == replacement_map) { - map->start = new_map->start; - map->end = new_map->end; + map->start = map__start(new_map); + map->end = map__end(new_map); map->pgoff = new_map->pgoff; map->map_ip = new_map->map_ip; map->unmap_ip = new_map->unmap_ip; diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c index 2664fb65e47a..d9e5ad040b6a 100644 --- a/tools/perf/util/symbol_fprintf.c +++ b/tools/perf/util/symbol_fprintf.c @@ -30,7 +30,7 @@ size_t __symbol__fprintf_symname_offs(const struct symbol *sym, if (al->addr < sym->end) offset = al->addr - sym->start; else - offset = al->addr - al->map->start - sym->start; + offset = al->addr - map__start(al->map) - sym->start; length += fprintf(fp, "+0x%lx", offset); } return length; diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index fbd1a882b013..b2e4afa5efa1 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -706,8 +706,8 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t (sizeof(event->mmap2.filename) - size)); memset(event->mmap2.filename + size, 0, machine->id_hdr_size); event->mmap2.header.size += machine->id_hdr_size; - event->mmap2.start = map->start; - event->mmap2.len = map->end - map->start; + event->mmap2.start = map__start(map); + event->mmap2.len = map__size(map); event->mmap2.pid = machine->pid; memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1); @@ -720,8 +720,8 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t (sizeof(event->mmap.filename) - size)); memset(event->mmap.filename + size, 0, machine->id_hdr_size); event->mmap.header.size += machine->id_hdr_size; - event->mmap.start = map->start; - event->mmap.len = map->end - map->start; + event->mmap.start = map__start(map); + event->mmap.len = map__size(map); event->mmap.pid = machine->pid; memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1); @@ -1143,8 +1143,8 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, event->mmap2.header.size = (sizeof(event->mmap2) - (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size); event->mmap2.pgoff = kmap->ref_reloc_sym->addr; - event->mmap2.start = map->start; - event->mmap2.len = map->end - event->mmap.start; + event->mmap2.start = map__start(map); + event->mmap2.len = map__end(map) - event->mmap.start; event->mmap2.pid = machine->pid; perf_record_mmap2__read_build_id(&event->mmap2, machine, true); @@ -1156,8 +1156,8 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); event->mmap.pgoff = kmap->ref_reloc_sym->addr; - event->mmap.start = map->start; - event->mmap.len = map->end - event->mmap.start; + event->mmap.start = map__start(map); + event->mmap.len = map__end(map) - event->mmap.start; event->mmap.pid = machine->pid; } diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index c8cba9d4bfd9..b79f57e5648f 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -62,19 +62,19 @@ static int __report_module(struct addr_location *al, u64 ip, Dwarf_Addr s; dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); - if (s != al->map->start - al->map->pgoff) + if (s != map__start(al->map) - al->map->pgoff) mod = 0; } if (!mod) mod = dwfl_report_elf(ui->dwfl, dso->short_name, dso->long_name, -1, - al->map->start - al->map->pgoff, false); + map__start(al->map) - al->map->pgoff, false); if (!mod) { char filename[PATH_MAX]; if (dso__build_id_filename(dso, filename, sizeof(filename), false)) mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1, - al->map->start - al->map->pgoff, false); + map__start(al->map) - al->map->pgoff, false); } if (mod) { diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 108f7b1697a7..1c13f43e7d22 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -327,9 +327,10 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, maps__for_each_entry(ui->thread->maps, map_node) { struct map *map = map_node->map; + u64 start = map__start(map); - if (map__dso(map) == dso && map->start < base_addr) - base_addr = map->start; + if (map__dso(map) == dso && start < base_addr) + base_addr = start; } base_addr -= dso->data.elf_base_addr; /* Address of .eh_frame_hdr */ @@ -443,8 +444,8 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count)) { memset(&di, 0, sizeof(di)); di.format = UNW_INFO_FORMAT_REMOTE_TABLE; - di.start_ip = map->start; - di.end_ip = map->end; + di.start_ip = map__start(map); + di.end_ip = map__end(map); di.u.rti.segbase = segbase; di.u.rti.table_data = table_data; di.u.rti.table_len = fde_count * sizeof(struct table_entry) @@ -459,7 +460,8 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) { int fd = dso__data_get_fd(dso, ui->machine); int is_exec = elf_is_exec(fd, dso->name); - unw_word_t base = is_exec ? 0 : map->start; + u64 start = map__start(map); + unw_word_t base = is_exec ? 0 : start; const char *symfile; if (fd >= 0) @@ -468,8 +470,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, symfile = dso->symsrc_filename ?: dso->name; memset(&di, 0, sizeof(di)); - if (dwarf_find_debug_frame(0, &di, ip, base, symfile, - map->start, map->end)) + if (dwarf_find_debug_frame(0, &di, ip, base, symfile, start, map__end(map))) return dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg); } -- cgit v1.2.3 From 78a1f7cd9000d5d633268a2acb2d9b62d41a2f2c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 Apr 2023 13:59:44 -0700 Subject: perf map: Add helper for ->map_ip() and ->unmap_ip() Later changes will add reference count checking for struct map, add a helper function to invoke the map_ip and unmap_ip function pointers. The helper allows the reference count check to be in fewer places. Committer notes: Add missing conversions to: tools/perf/util/map.c tools/perf/util/cs-etm.c tools/perf/util/annotate.c tools/perf/arch/powerpc/util/sym-handling.c tools/perf/arch/s390/annotate/instructions.c Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230404205954.2245628-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/sym-handling.c | 2 +- tools/perf/arch/s390/annotate/instructions.c | 2 +- tools/perf/builtin-kallsyms.c | 2 +- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-lock.c | 4 ++-- tools/perf/builtin-script.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 10 +++++----- tools/perf/util/annotate.c | 14 +++++++------- tools/perf/util/bpf_lock_contention.c | 4 ++-- tools/perf/util/cs-etm.c | 2 +- tools/perf/util/dlfilter.c | 2 +- tools/perf/util/dso.c | 6 ++++-- tools/perf/util/event.c | 8 ++++---- tools/perf/util/evsel_fprintf.c | 2 +- tools/perf/util/intel-pt.c | 10 +++++----- tools/perf/util/machine.c | 16 ++++++++-------- tools/perf/util/map.c | 12 ++++++------ tools/perf/util/map.h | 10 ++++++++++ tools/perf/util/maps.c | 8 ++++---- tools/perf/util/probe-event.c | 8 ++++---- tools/perf/util/scripting-engines/trace-event-python.c | 2 +- tools/perf/util/sort.c | 12 ++++++------ tools/perf/util/symbol.c | 4 ++-- tools/perf/util/thread.c | 2 +- tools/perf/util/unwind-libdw.c | 2 +- tools/perf/util/unwind-libunwind-local.c | 2 +- 26 files changed, 81 insertions(+), 69 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 9f99fc88dbff..947bfad7aa59 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -131,7 +131,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, for (i = 0; i < ntevs; i++) { tev = &pev->tevs[i]; map__for_each_symbol(map, sym, tmp) { - if (map->unmap_ip(map, sym->start) == tev->point.address) { + if (map__unmap_ip(map, sym->start) == tev->point.address) { arch__fix_tev_from_maps(pev, tev, map, sym); break; } diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index 0e136630659e..de925b0e35ce 100644 --- a/tools/perf/arch/s390/annotate/instructions.c +++ b/tools/perf/arch/s390/annotate/instructions.c @@ -39,7 +39,7 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops, target.addr = map__objdump_2mem(map, ops->target.addr); if (maps__find_ams(ms->maps, &target) == 0 && - map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; return 0; diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c index 5638ca4dbd8e..3751df744577 100644 --- a/tools/perf/builtin-kallsyms.c +++ b/tools/perf/builtin-kallsyms.c @@ -39,7 +39,7 @@ static int __cmd_kallsyms(int argc, const char **argv) dso = map__dso(map); printf("%s: %s %s %#" PRIx64 "-%#" PRIx64 " (%#" PRIx64 "-%#" PRIx64")\n", symbol->name, dso->short_name, dso->long_name, - map->unmap_ip(map, symbol->start), map->unmap_ip(map, symbol->end), + map__unmap_ip(map, symbol->start), map__unmap_ip(map, symbol->end), symbol->start, symbol->end); } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 4d4b770a401c..fcd2ef3bd3f5 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -1024,7 +1024,7 @@ static void __print_slab_result(struct rb_root *root, if (sym != NULL) snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name, - addr - map->unmap_ip(map, sym->start)); + addr - map__unmap_ip(map, sym->start)); else snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr); printf(" %-34s |", buf); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 4e24351b18bd..ecb1fac8ba3c 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -900,7 +900,7 @@ static int get_symbol_name_offset(struct map *map, struct symbol *sym, u64 ip, return 0; } - offset = map->map_ip(map, ip) - sym->start; + offset = map__map_ip(map, ip) - sym->start; if (offset) return scnprintf(buf, size, "%s+%#lx", sym->name, offset); @@ -1070,7 +1070,7 @@ static int report_lock_contention_begin_event(struct evsel *evsel, return -ENOMEM; } - addrs[filters.nr_addrs++] = kmap->unmap_ip(kmap, sym->start); + addrs[filters.nr_addrs++] = map__unmap_ip(kmap, sym->start); filters.addrs = addrs; } } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index af0a69c7f41f..8fba247b798c 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1088,7 +1088,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, /* Load maps to ensure dso->is_64_bit has been updated */ map__load(al.map); - offset = al.map->map_ip(al.map, start); + offset = map__map_ip(al.map, start); len = dso__data_read_offset(dso, machine, offset, (u8 *)buffer, end - start + MAXINSN); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 0a75623172c2..05a322ea3f9f 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -13,7 +13,7 @@ #include "debug.h" #include "machine.h" -#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) +#define UM(x) map__unmap_ip(kallsyms_map, (x)) static bool is_ignored_symbol(const char *name, char type) { @@ -221,8 +221,8 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused if (sym->start == sym->end) continue; - mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start); - mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end); + mem_start = map__unmap_ip(vmlinux_map, sym->start); + mem_end = map__unmap_ip(vmlinux_map, sym->end); first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL); pair = first_pair; @@ -319,8 +319,8 @@ next_pair: maps__for_each_entry(maps, rb_node) { struct map *pair, *map = rb_node->map; - mem_start = vmlinux_map->unmap_ip(vmlinux_map, map__start(map)); - mem_end = vmlinux_map->unmap_ip(vmlinux_map, map__end(map)); + mem_start = map__unmap_ip(vmlinux_map, map__start(map)); + mem_end = map__unmap_ip(vmlinux_map, map__end(map)); pair = maps__find(kallsyms.kmaps, mem_start); if (pair == NULL || pair->priv) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b9cff782d7df..55f2e3a7577e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -272,7 +272,7 @@ find_target: target.addr = map__objdump_2mem(map, ops->target.addr); if (maps__find_ams(ms->maps, &target) == 0 && - map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; return 0; @@ -376,8 +376,8 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s } target.addr = map__objdump_2mem(map, ops->target.addr); - start = map->unmap_ip(map, sym->start), - end = map->unmap_ip(map, sym->end); + start = map__unmap_ip(map, sym->start); + end = map__unmap_ip(map, sym->end); ops->target.outside = target.addr < start || target.addr > end; @@ -400,7 +400,7 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s * the symbol searching and disassembly should be done. */ if (maps__find_ams(ms->maps, &target) == 0 && - map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; if (!ops->target.outside) { @@ -881,7 +881,7 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms, unsigned offset; struct sym_hist *h; - pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, ms->map->unmap_ip(ms->map, addr)); + pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr)); if ((addr < sym->start || addr >= sym->end) && (addr != sym->end || sym->start != sym->end)) { @@ -1977,8 +1977,8 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) return err; pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, - symfs_filename, sym->name, map->unmap_ip(map, sym->start), - map->unmap_ip(map, sym->end)); + symfs_filename, sym->name, map__unmap_ip(map, sym->start), + map__unmap_ip(map, sym->end)); pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso->long_name, sym, sym->name); diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index 9e20fa8ade09..e7dddf0127bc 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -74,7 +74,7 @@ int lock_contention_prepare(struct lock_contention *con) continue; } - addrs[con->filters->nr_addrs++] = kmap->unmap_ip(kmap, sym->start); + addrs[con->filters->nr_addrs++] = map__unmap_ip(kmap, sym->start); con->filters->addrs = addrs; } naddrs = con->filters->nr_addrs; @@ -233,7 +233,7 @@ static const char *lock_contention_get_name(struct lock_contention *con, if (sym) { unsigned long offset; - offset = kmap->map_ip(kmap, addr) - sym->start; + offset = map__map_ip(kmap, addr) - sym->start; if (offset == 0) return sym->name; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 528a7fb066cf..944835e16430 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -893,7 +893,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) return 0; - offset = al.map->map_ip(al.map, address); + offset = map__map_ip(al.map, address); map__load(al.map); diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index fe401fa4be02..16238f823a5e 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -278,7 +278,7 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len) map = a.map; have_map: - offset = map->map_ip(map, ip); + offset = map__map_ip(map, ip); if (ip + len >= map__end(map)) len = map__end(map) - ip; return dso__data_read_offset(map__dso(map), d->machine, offset, buf, len); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index f1a14c0ad26d..e36b418df2c6 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1122,7 +1122,8 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map, struct machine *machine, u64 addr, u8 *data, ssize_t size) { - u64 offset = map->map_ip(map, addr); + u64 offset = map__map_ip(map, addr); + return dso__data_read_offset(dso, machine, offset, data, size); } @@ -1162,7 +1163,8 @@ ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map, struct machine *machine, u64 addr, const u8 *data, ssize_t size) { - u64 offset = map->map_ip(map, addr); + u64 offset = map__map_ip(map, addr); + return dso__data_write_cache_offs(dso, machine, offset, data, size); } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2ddc75dee019..2712d1a8264e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -487,7 +487,7 @@ size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *ma al.map = maps__find(machine__kernel_maps(machine), tp->addr); if (al.map && map__load(al.map) >= 0) { - al.addr = al.map->map_ip(al.map, tp->addr); + al.addr = map__map_ip(al.map, tp->addr); al.sym = map__find_symbol(al.map, al.addr); if (al.sym) ret += symbol__fprintf_symname_offs(al.sym, &al, fp); @@ -622,7 +622,7 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, */ if (load_map) map__load(al->map); - al->addr = al->map->map_ip(al->map, al->addr); + al->addr = map__map_ip(al->map, al->addr); } return al->map; @@ -743,12 +743,12 @@ int machine__resolve(struct machine *machine, struct addr_location *al, } if (!ret && al->sym) { snprintf(al_addr_str, sz, "0x%"PRIx64, - al->map->unmap_ip(al->map, al->sym->start)); + map__unmap_ip(al->map, al->sym->start)); ret = strlist__has_entry(symbol_conf.sym_list, al_addr_str); } if (!ret && symbol_conf.addr_list && al->map) { - unsigned long addr = al->map->unmap_ip(al->map, al->addr); + unsigned long addr = map__unmap_ip(al->map, al->addr); ret = intlist__has_entry(symbol_conf.addr_list, addr); if (!ret && symbol_conf.addr_range) { diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index dff5d8c4b06d..a09ac00810b7 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -151,7 +151,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, printed += fprintf(fp, " <-"); if (map) - addr = map->map_ip(map, node->ip); + addr = map__map_ip(map, node->ip); if (print_ip) { /* Show binary offset for userspace addr */ diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index a2e62daa708e..fe893c9bab3f 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -816,7 +816,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) return -ENOENT; - offset = al.map->map_ip(al.map, *ip); + offset = map__map_ip(al.map, *ip); if (!to_ip && one_map) { struct intel_pt_cache_entry *e; @@ -987,7 +987,7 @@ static int __intel_pt_pgd_ip(uint64_t ip, void *data) if (!thread__find_map(thread, cpumode, ip, &al) || !map__dso(al.map)) return -EINVAL; - offset = al.map->map_ip(al.map, ip); + offset = map__map_ip(al.map, ip); return intel_pt_match_pgd_ip(ptq->pt, ip, offset, map__dso(al.map)->long_name); } @@ -2749,7 +2749,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) for (sym = start; sym; sym = dso__next_symbol(sym)) { if (sym->binding == STB_GLOBAL && !strcmp(sym->name, "__switch_to")) { - ip = map->unmap_ip(map, sym->start); + ip = map__unmap_ip(map, sym->start); if (ip >= map__start(map) && ip < map__end(map)) { switch_ip = ip; break; @@ -2767,7 +2767,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) for (sym = start; sym; sym = dso__next_symbol(sym)) { if (!strcmp(sym->name, ptss)) { - ip = map->unmap_ip(map, sym->start); + ip = map__unmap_ip(map, sym->start); if (ip >= map__start(map) && ip < map__end(map)) { *ptss_ip = ip; break; @@ -3393,7 +3393,7 @@ static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event) if (!dso || !dso->auxtrace_cache) continue; - offset = al.map->map_ip(al.map, addr); + offset = map__map_ip(al.map, addr); e = intel_pt_cache_lookup(dso, machine, offset); if (!e) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 9d24980a0a93..d29ec4a04488 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -919,7 +919,7 @@ static int machine__process_ksymbol_register(struct machine *machine, dso = map__dso(map); } - sym = symbol__new(map->map_ip(map, map__start(map)), + sym = symbol__new(map__map_ip(map, map__start(map)), event->ksymbol.len, 0, 0, event->ksymbol.name); if (!sym) @@ -944,7 +944,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, else { struct dso *dso = map__dso(map); - sym = dso__find_symbol(dso, map->map_ip(map, map__start(map))); + sym = dso__find_symbol(dso, map__map_ip(map, map__start(map))); if (sym) dso__delete_symbol(dso, sym); } @@ -1279,7 +1279,7 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, dest_map = maps__find(kmaps, map->pgoff); if (dest_map != map) - map->pgoff = dest_map->map_ip(dest_map, map->pgoff); + map->pgoff = map__map_ip(dest_map, map->pgoff); found = true; } if (found || machine->trampolines_mapped) @@ -3345,7 +3345,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch return NULL; *modp = __map__is_kmodule(map) ? (char *)map__dso(map)->short_name : NULL; - *addrp = map->unmap_ip(map, sym->start); + *addrp = map__unmap_ip(map, sym->start); return sym->name; } @@ -3388,17 +3388,17 @@ bool machine__is_lock_function(struct machine *machine, u64 addr) return false; } - machine->sched.text_start = kmap->unmap_ip(kmap, sym->start); + machine->sched.text_start = map__unmap_ip(kmap, sym->start); /* should not fail from here */ sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap); - machine->sched.text_end = kmap->unmap_ip(kmap, sym->start); + machine->sched.text_end = map__unmap_ip(kmap, sym->start); sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap); - machine->lock.text_start = kmap->unmap_ip(kmap, sym->start); + machine->lock.text_start = map__unmap_ip(kmap, sym->start); sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap); - machine->lock.text_end = kmap->unmap_ip(kmap, sym->start); + machine->lock.text_end = map__unmap_ip(kmap, sym->start); } /* failed to get kernel symbols */ diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index d97a6d20626f..a55aef4b1310 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -519,7 +519,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) if (dso->kernel == DSO_SPACE__USER) return rip + dso->text_offset; - return map->unmap_ip(map, rip) - map->reloc; + return map__unmap_ip(map, rip) - map->reloc; } /** @@ -530,7 +530,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) * Closely related to map__rip_2objdump(), this function takes an address from * objdump and converts it to a memory address. Note this assumes that @map * contains the address. To be sure the result is valid, check it forwards - * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip + * e.g. map__rip_2objdump(map__map_ip(map, map__objdump_2mem(map, ip))) == ip * * Return: Memory address. */ @@ -539,24 +539,24 @@ u64 map__objdump_2mem(struct map *map, u64 ip) const struct dso *dso = map__dso(map); if (!dso->adjust_symbols) - return map->unmap_ip(map, ip); + return map__unmap_ip(map, ip); if (dso->rel) - return map->unmap_ip(map, ip + map->pgoff); + return map__unmap_ip(map, ip + map->pgoff); /* * kernel modules also have DSO_TYPE_USER in dso->kernel, * but all kernel modules are ET_REL, so won't get here. */ if (dso->kernel == DSO_SPACE__USER) - return map->unmap_ip(map, ip - dso->text_offset); + return map__unmap_ip(map, ip - dso->text_offset); return ip + map->reloc; } bool map__contains_symbol(const struct map *map, const struct symbol *sym) { - u64 ip = map->unmap_ip(map, sym->start); + u64 ip = map__unmap_ip(map, sym->start); return ip >= map__start(map) && ip < map__end(map); } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 9b0a84e46e48..9118eba71032 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -52,6 +52,16 @@ static inline struct dso *map__dso(const struct map *map) return map->dso; } +static inline u64 map__map_ip(const struct map *map, u64 ip) +{ + return map->map_ip(map, ip); +} + +static inline u64 map__unmap_ip(const struct map *map, u64 ip) +{ + return map->unmap_ip(map, ip); +} + static inline u64 map__start(const struct map *map) { return map->start; diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 21010a2b8e16..0eee27e24c33 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -194,7 +194,7 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) if (map != NULL && map__load(map) >= 0) { if (mapp != NULL) *mapp = map; - return map__find_symbol(map, map->map_ip(map, addr)); + return map__find_symbol(map, map__map_ip(map, addr)); } return NULL; @@ -237,7 +237,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) return -1; } - ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr); + ams->al_addr = map__map_ip(ams->ms.map, ams->addr); ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr); return ams->ms.sym ? 0 : -1; @@ -349,8 +349,8 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) after->start = map__end(map); after->pgoff += map__end(map) - map__start(pos->map); - assert(pos->map->map_ip(pos->map, map__end(map)) == - after->map_ip(after, map__end(map))); + assert(map__map_ip(pos->map, map__end(map)) == + map__map_ip(after, map__end(map))); err = __maps__insert(maps, after); if (err) goto put_map; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4d9dbeeb6014..bb44a3798df8 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -141,7 +141,7 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, sym = machine__find_kernel_symbol_by_name(host_machine, name, &map); if (!sym) return -ENOENT; - *addr = map->unmap_ip(map, sym->start) - + *addr = map__unmap_ip(map, sym->start) - ((reloc) ? 0 : map->reloc) - ((reladdr) ? map__start(map) : 0); } @@ -400,7 +400,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, "Consider identifying the final function used at run time and set the probe directly on that.\n", pp->function); } else - address = map->unmap_ip(map, sym->start) - map->reloc; + address = map__unmap_ip(map, sym->start) - map->reloc; break; } if (!address) { @@ -2249,7 +2249,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, goto out; pp->retprobe = tp->retprobe; - pp->offset = addr - map->unmap_ip(map, sym->start); + pp->offset = addr - map__unmap_ip(map, sym->start); pp->function = strdup(sym->name); ret = pp->function ? 0 : -ENOMEM; @@ -3123,7 +3123,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, goto err_out; } /* Add one probe point */ - tp->address = map->unmap_ip(map, sym->start) + pp->offset; + tp->address = map__unmap_ip(map, sym->start) + pp->offset; /* Check the kprobe (not in module) is within .text */ if (!pev->uprobes && !pev->target && diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cbf09eaf3734..41d4f9e6a8b7 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -471,7 +471,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample, struct addr_location node_al; unsigned long offset; - node_al.addr = map->map_ip(map, node->ip); + node_al.addr = map__map_ip(map, node->ip); node_al.map = map; offset = get_offset(node->ms.sym, &node_al); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index f161589aefda..87a3ba584af5 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -364,7 +364,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms, u64 rip = ip; if (dso && dso->kernel && dso->adjust_symbols) - rip = map->unmap_ip(map, ip); + rip = map__unmap_ip(map, ip); ret += repsep_snprintf(bf, size, "%-#*llx %c ", BITS_PER_LONG / 4 + 2, rip, o); @@ -375,7 +375,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms, if (sym->type == STT_OBJECT) { ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", - ip - map->unmap_ip(map, sym->start)); + ip - map__unmap_ip(map, sym->start)); } else { ret += repsep_snprintf(bf + ret, size - ret, "%.*s", width - ret, @@ -1147,7 +1147,7 @@ static int _hist_entry__addr_snprintf(struct map_symbol *ms, if (sym->type == STT_OBJECT) { ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", - ip - map->unmap_ip(map, sym->start)); + ip - map__unmap_ip(map, sym->start)); } else { ret += repsep_snprintf(bf + ret, size - ret, "%.*s", width - ret, @@ -2104,9 +2104,9 @@ sort__addr_cmp(struct hist_entry *left, struct hist_entry *right) struct map *right_map = right->ms.map; if (left_map) - left_ip = left_map->unmap_ip(left_map, left_ip); + left_ip = map__unmap_ip(left_map, left_ip); if (right_map) - right_ip = right_map->unmap_ip(right_map, right_ip); + right_ip = map__unmap_ip(right_map, right_ip); return _sort__addr_cmp(left_ip, right_ip); } @@ -2118,7 +2118,7 @@ static int hist_entry__addr_snprintf(struct hist_entry *he, char *bf, struct map *map = he->ms.map; if (map) - ip = map->unmap_ip(map, ip); + ip = map__unmap_ip(map, ip); return repsep_snprintf(bf, size, "%-#*llx", width, ip); } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b91deb177091..9ba49c1ef6ef 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -896,8 +896,8 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, * So that we look just like we get from .ko files, * i.e. not prelinked, relative to initial_map->start. */ - pos->start = curr_map->map_ip(curr_map, pos->start); - pos->end = curr_map->map_ip(curr_map, pos->end); + pos->start = map__map_ip(curr_map, pos->start); + pos->end = map__map_ip(curr_map, pos->end); } else if (x86_64 && is_entry_trampoline(pos->name)) { /* * These symbols are not needed anymore since the diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index bb7a2ce82d46..4b5bdc277baa 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -464,7 +464,7 @@ int thread__memcpy(struct thread *thread, struct machine *machine, if( !dso || dso->data.status == DSO_DATA_STATUS_ERROR || map__load(al.map) < 0) return -1; - offset = al.map->map_ip(al.map, ip); + offset = map__map_ip(al.map, ip); if (is64bit) *is64bit = dso->is_64_bit; diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index b79f57e5648f..538320e4260c 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -115,7 +115,7 @@ static int entry(u64 ip, struct unwind_info *ui) pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", al.sym ? al.sym->name : "''", ip, - al.map ? al.map->map_ip(al.map, ip) : (u64) 0); + al.map ? map__map_ip(al.map, ip) : (u64) 0); return 0; } diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 1c13f43e7d22..f9a52af48de4 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -640,7 +640,7 @@ static int entry(u64 ip, struct thread *thread, pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", al.sym ? al.sym->name : "''", ip, - al.map ? al.map->map_ip(al.map, ip) : (u64) 0); + al.map ? map__map_ip(al.map, ip) : (u64) 0); return cb(&e, arg); } -- cgit v1.2.3 From ddee3f2bddc11f850f7f6fcfc04bc26ceeab23ce Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 Apr 2023 13:59:45 -0700 Subject: perf map: Add accessors for ->prot, ->priv and ->flags Later changes will add reference count checking for 'struct map'. Add an accessor so that the reference count check is only necessary in one place. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230404205954.2245628-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-report.c | 9 +++++---- tools/perf/tests/vmlinux-kallsyms.c | 4 ++-- tools/perf/util/map.h | 15 +++++++++++++++ tools/perf/util/sort.c | 6 +++--- tools/perf/util/symbol.c | 4 ++-- 6 files changed, 28 insertions(+), 12 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8f6909dd8a54..fd2b38458a5d 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -758,7 +758,7 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, if (!dso->hit) { dso->hit = 1; dso__inject_build_id(dso, tool, machine, - sample->cpumode, al.map->flags); + sample->cpumode, map__flags(al.map)); } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2a6e2cee5e0d..c066452219c8 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -849,13 +849,14 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) maps__for_each_entry(maps, rb_node) { struct map *map = rb_node->map; const struct dso *dso = map__dso(map); + u32 prot = map__prot(map); printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", indent, "", map__start(map), map__end(map), - map->prot & PROT_READ ? 'r' : '-', - map->prot & PROT_WRITE ? 'w' : '-', - map->prot & PROT_EXEC ? 'x' : '-', - map->flags & MAP_SHARED ? 's' : 'p', + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-', + map__flags(map) ? 's' : 'p', map->pgoff, dso->id.ino, dso->name); } diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 05a322ea3f9f..7db102868bc2 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -323,7 +323,7 @@ next_pair: mem_end = map__unmap_ip(vmlinux_map, map__end(map)); pair = maps__find(kallsyms.kmaps, mem_start); - if (pair == NULL || pair->priv) + if (pair == NULL || map__priv(pair)) continue; if (map__start(pair) == mem_start) { @@ -351,7 +351,7 @@ next_pair: maps__for_each_entry(maps, rb_node) { struct map *map = rb_node->map; - if (!map->priv) { + if (!map__priv(map)) { if (!header_printed) { pr_info("WARN: Maps only in kallsyms:\n"); header_printed = true; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 9118eba71032..fd440c9c279e 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -72,6 +72,21 @@ static inline u64 map__end(const struct map *map) return map->end; } +static inline u32 map__flags(const struct map *map) +{ + return map->flags; +} + +static inline u32 map__prot(const struct map *map) +{ + return map->prot; +} + +static inline bool map__priv(const struct map *map) +{ + return map->priv; +} + static inline size_t map__size(const struct map *map) { return map__end(map) - map__start(map); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 87a3ba584af5..80c9960c37e5 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1540,7 +1540,7 @@ sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) */ if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && - (!(l_map->flags & MAP_SHARED)) && !l_dso->id.maj && !l_dso->id.min && + (!(map__flags(l_map) & MAP_SHARED)) && !l_dso->id.maj && !l_dso->id.min && !l_dso->id.ino && !l_dso->id.ino_generation) { /* userspace anonymous */ @@ -1576,8 +1576,8 @@ static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, /* print [s] for shared data mmaps */ if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && - map && !(map->prot & PROT_EXEC) && - (map->flags & MAP_SHARED) && + map && !(map__prot(map) & PROT_EXEC) && + (map__flags(map) & MAP_SHARED) && (dso->id.maj || dso->id.min || dso->id.ino || dso->id.ino_generation)) level = 's'; else if (!map) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 9ba49c1ef6ef..5c075d77a792 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1396,7 +1396,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, } /* Read new maps into temporary lists */ - err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md, + err = file__read_maps(fd, map__prot(map) & PROT_EXEC, kcore_mapfn, &md, &is_64_bit); if (err) goto out_err; @@ -1509,7 +1509,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, close(fd); - if (map->prot & PROT_EXEC) + if (map__prot(map) & PROT_EXEC) pr_debug("Using %s for kernel object code\n", kcore_filename); else pr_debug("Using %s for kernel data\n", kcore_filename); -- cgit v1.2.3 From 2a6e5e8a2ab68c9048f80d174d1698427fbd9c8c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 Apr 2023 13:59:46 -0700 Subject: perf map: Add accessors for ->pgoff and ->reloc Later changes will add reference count checking for 'struct map'. Add accessors so that the reference count check is only necessary in one place. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230404205954.2245628-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/event.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 4 ++-- tools/perf/util/machine.c | 4 ++-- tools/perf/util/map.c | 14 +++++++------- tools/perf/util/map.h | 10 ++++++++++ tools/perf/util/probe-event.c | 8 ++++---- tools/perf/util/symbol.c | 6 +++--- tools/perf/util/unwind-libdw.c | 6 +++--- 9 files changed, 33 insertions(+), 23 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/x86/util/event.c b/tools/perf/arch/x86/util/event.c index 3b2475707756..5741ffe47312 100644 --- a/tools/perf/arch/x86/util/event.c +++ b/tools/perf/arch/x86/util/event.c @@ -61,7 +61,7 @@ int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, event->mmap.start = map__start(map); event->mmap.len = map__size(map); - event->mmap.pgoff = map->pgoff; + event->mmap.pgoff = map__pgoff(map); event->mmap.pid = machine->pid; strlcpy(event->mmap.filename, kmap->name, PATH_MAX); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c066452219c8..92c6797e7cba 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -857,7 +857,7 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-', map__flags(map) ? 's' : 'p', - map->pgoff, + map__pgoff(map), dso->id.ino, dso->name); } diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 7db102868bc2..af511233c764 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -335,10 +335,10 @@ next_pair: } pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", - map__start(map), map__end(map), map->pgoff, dso->name); + map__start(map), map__end(map), map__pgoff(map), dso->name); if (mem_end != map__end(pair)) pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, - map__start(pair), map__end(pair), pair->pgoff); + map__start(pair), map__end(pair), map__pgoff(pair)); pr_info(" %s\n", dso->name); pair->priv = 1; } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index d29ec4a04488..1ea6f6c06bbb 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1277,9 +1277,9 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, if (!kmap || !is_entry_trampoline(kmap->name)) continue; - dest_map = maps__find(kmaps, map->pgoff); + dest_map = maps__find(kmaps, map__pgoff(map)); if (dest_map != map) - map->pgoff = map__map_ip(dest_map, map->pgoff); + map->pgoff = map__map_ip(dest_map, map__pgoff(map)); found = true; } if (found || machine->trampolines_mapped) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index a55aef4b1310..6426af6882c2 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -421,7 +421,7 @@ size_t map__fprintf(struct map *map, FILE *fp) const struct dso *dso = map__dso(map); return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", - map__start(map), map__end(map), map->pgoff, dso->name); + map__start(map), map__end(map), map__pgoff(map), dso->name); } size_t map__fprintf_dsoname(struct map *map, FILE *fp) @@ -510,7 +510,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) return rip; if (dso->rel) - return rip - map->pgoff; + return rip - map__pgoff(map); /* * kernel modules also have DSO_TYPE_USER in dso->kernel, @@ -519,7 +519,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) if (dso->kernel == DSO_SPACE__USER) return rip + dso->text_offset; - return map__unmap_ip(map, rip) - map->reloc; + return map__unmap_ip(map, rip) - map__reloc(map); } /** @@ -542,7 +542,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) return map__unmap_ip(map, ip); if (dso->rel) - return map__unmap_ip(map, ip + map->pgoff); + return map__unmap_ip(map, ip + map__pgoff(map)); /* * kernel modules also have DSO_TYPE_USER in dso->kernel, @@ -551,7 +551,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) if (dso->kernel == DSO_SPACE__USER) return map__unmap_ip(map, ip - dso->text_offset); - return ip + map->reloc; + return ip + map__reloc(map); } bool map__contains_symbol(const struct map *map, const struct symbol *sym) @@ -592,12 +592,12 @@ struct maps *map__kmaps(struct map *map) u64 map__dso_map_ip(const struct map *map, u64 ip) { - return ip - map__start(map) + map->pgoff; + return ip - map__start(map) + map__pgoff(map); } u64 map__dso_unmap_ip(const struct map *map, u64 ip) { - return ip + map__start(map) - map->pgoff; + return ip + map__start(map) - map__pgoff(map); } u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index fd440c9c279e..102485699aa8 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -72,6 +72,16 @@ static inline u64 map__end(const struct map *map) return map->end; } +static inline u64 map__pgoff(const struct map *map) +{ + return map->pgoff; +} + +static inline u64 map__reloc(const struct map *map) +{ + return map->reloc; +} + static inline u32 map__flags(const struct map *map) { return map->flags; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index bb44a3798df8..6e2110d605fb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -135,14 +135,14 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, /* ref_reloc_sym is just a label. Need a special fix*/ reloc_sym = kernel_get_ref_reloc_sym(&map); if (reloc_sym && strcmp(name, reloc_sym->name) == 0) - *addr = (!map->reloc || reloc) ? reloc_sym->addr : + *addr = (!map__reloc(map) || reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; else { sym = machine__find_kernel_symbol_by_name(host_machine, name, &map); if (!sym) return -ENOENT; *addr = map__unmap_ip(map, sym->start) - - ((reloc) ? 0 : map->reloc) - + ((reloc) ? 0 : map__reloc(map)) - ((reladdr) ? map__start(map) : 0); } return 0; @@ -400,7 +400,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, "Consider identifying the final function used at run time and set the probe directly on that.\n", pp->function); } else - address = map__unmap_ip(map, sym->start) - map->reloc; + address = map__unmap_ip(map, sym->start) - map__reloc(map); break; } if (!address) { @@ -866,7 +866,7 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs, free(tevs[i].point.symbol); tevs[i].point.symbol = tmp; tevs[i].point.offset = tevs[i].point.address - - (map->reloc ? reloc_sym->unrelocated_addr : + (map__reloc(map) ? reloc_sym->unrelocated_addr : reloc_sym->addr); } return skipped; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 5c075d77a792..7282119c2990 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -810,11 +810,11 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) continue; } curr_map_dso = map__dso(curr_map); - pos->start -= map__start(curr_map) - curr_map->pgoff; + pos->start -= map__start(curr_map) - map__pgoff(curr_map); if (pos->end > map__end(curr_map)) pos->end = map__end(curr_map); if (pos->end) - pos->end -= map__start(curr_map) - curr_map->pgoff; + pos->end -= map__start(curr_map) - map__pgoff(curr_map); symbols__insert(&curr_map_dso->symbols, pos); ++count; } @@ -1459,7 +1459,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, if (new_map == replacement_map) { map->start = map__start(new_map); map->end = map__end(new_map); - map->pgoff = new_map->pgoff; + map->pgoff = map__pgoff(new_map); map->map_ip = new_map->map_ip; map->unmap_ip = new_map->unmap_ip; /* Ensure maps are correctly ordered */ diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 538320e4260c..9565f9906e5d 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -62,19 +62,19 @@ static int __report_module(struct addr_location *al, u64 ip, Dwarf_Addr s; dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); - if (s != map__start(al->map) - al->map->pgoff) + if (s != map__start(al->map) - map__pgoff(al->map)) mod = 0; } if (!mod) mod = dwfl_report_elf(ui->dwfl, dso->short_name, dso->long_name, -1, - map__start(al->map) - al->map->pgoff, false); + map__start(al->map) - map__pgoff(al->map), false); if (!mod) { char filename[PATH_MAX]; if (dso__build_id_filename(dso, filename, sizeof(filename), false)) mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1, - map__start(al->map) - al->map->pgoff, false); + map__start(al->map) - map__pgoff(al->map), false); } if (mod) { -- cgit v1.2.3 From 93c9f1c287d00ab396f76955a79beac46efca2d5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 Apr 2023 13:59:47 -0700 Subject: perf test: Add extra diagnostics to maps test Dump the resultant and comparison maps on failure. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230404205954.2245628-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/maps.c | 51 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index fd0c464fcf95..1c7293476aca 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include "tests.h" @@ -17,22 +18,42 @@ static int check_maps(struct map_def *merged, unsigned int size, struct maps *ma { struct map_rb_node *rb_node; unsigned int i = 0; - - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; - - if (i > 0) - TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size)); - - TEST_ASSERT_VAL("wrong map start", map__start(map) == merged[i].start); - TEST_ASSERT_VAL("wrong map end", map__end(map) == merged[i].end); - TEST_ASSERT_VAL("wrong map name", !strcmp(map__dso(map)->name, merged[i].name)); - TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1); - - i++; + bool failed = false; + + if (maps__nr_maps(maps) != size) { + pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps)); + failed = true; + } else { + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + + if (map__start(map) != merged[i].start || + map__end(map) != merged[i].end || + strcmp(map__dso(map)->name, merged[i].name) || + refcount_read(&map->refcnt) != 1) { + failed = true; + } + i++; + } } - - return TEST_OK; + if (failed) { + pr_debug("Expected:\n"); + for (i = 0; i < size; i++) { + pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n", + merged[i].start, merged[i].end, merged[i].name); + } + pr_debug("Got:\n"); + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + + pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n", + map__start(map), + map__end(map), + map__dso(map)->name, + refcount_read(&map->refcnt)); + } + } + return failed ? TEST_FAIL : TEST_OK; } static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest __maybe_unused) -- cgit v1.2.3 From ec417ad4c691b5d90ab13cf26789e8719468ae39 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 Apr 2023 13:59:49 -0700 Subject: perf map: Changes to reference counting When a pointer to a map exists do a get, when that pointer is overwritten or freed, put the map. This avoids issues with gets and puts being inconsistently used causing, use after puts, etc. For example, the map in struct addr_location is changed to hold a reference count. Reference count checking and address sanitizer were used to identify issues. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexey Bayduraev Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Shevchenko Cc: Darren Hart Cc: Davidlohr Bueso Cc: Dmitriy Vyukov Cc: Eric Dumazet Cc: German Gomez Cc: Hao Luo Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Miaoqian Lin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Song Liu Cc: Stephane Eranian Cc: Stephen Brennan Cc: Steven Rostedt (VMware) Cc: Thomas Gleixner Cc: Thomas Richter Cc: Yury Norov Link: https://lore.kernel.org/r/20230404205954.2245628-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 1 + tools/perf/tests/hists_cumulate.c | 10 +++++ tools/perf/tests/hists_filter.c | 10 +++++ tools/perf/tests/hists_link.c | 18 +++++++- tools/perf/tests/hists_output.c | 10 +++++ tools/perf/tests/mmap-thread-lookup.c | 1 + tools/perf/util/callchain.c | 9 ++-- tools/perf/util/event.c | 6 ++- tools/perf/util/hist.c | 10 ++--- tools/perf/util/machine.c | 79 +++++++++++++++++++++-------------- tools/perf/util/map.c | 2 +- 11 files changed, 112 insertions(+), 44 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 1545fcaa95c6..efe026a35010 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -366,6 +366,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, } pr_debug("Bytes read match those read by objdump\n"); out: + map__put(al.map); return err; } diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index f00ec9abdbcd..8c0e3f334747 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -112,6 +112,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -147,6 +148,14 @@ static void del_hist_entries(struct hists *hists) } } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) @@ -733,6 +742,7 @@ out: /* tear down everything */ evlist__delete(evlist); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 7c552549f4a4..98eff5935a1c 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -89,6 +89,7 @@ static int add_hist_entries(struct evlist *evlist, } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -101,6 +102,14 @@ out: return TEST_FAIL; } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + static int test__hists_filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int err = TEST_FAIL; @@ -322,6 +331,7 @@ out: evlist__delete(evlist); reset_output_field(); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index e7e4ee57ce04..64ce8097889c 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -6,6 +6,7 @@ #include "evsel.h" #include "evlist.h" #include "machine.h" +#include "map.h" #include "parse-events.h" #include "hists_common.h" #include "util/mmap.h" @@ -94,6 +95,7 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine) } fake_common_samples[k].thread = al.thread; + map__put(fake_common_samples[k].map); fake_common_samples[k].map = al.map; fake_common_samples[k].sym = al.sym; } @@ -126,11 +128,24 @@ out: return -1; } +static void put_fake_samples(void) +{ + size_t i, j; + + for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++) + map__put(fake_common_samples[i].map); + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { + for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++) + map__put(fake_samples[i][j].map); + } +} + static int find_sample(struct sample *samples, size_t nr_samples, struct thread *t, struct map *m, struct symbol *s) { while (nr_samples--) { - if (samples->thread == t && samples->map == m && + if (samples->thread == t && + samples->map == m && samples->sym == s) return 1; samples++; @@ -336,6 +351,7 @@ out: evlist__delete(evlist); reset_output_field(); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 428d11a938f2..cebd5226bb12 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -78,6 +78,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -113,6 +114,14 @@ static void del_hist_entries(struct hists *hists) } } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) @@ -620,6 +629,7 @@ out: /* tear down everything */ evlist__delete(evlist); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 5cc4644e353d..898eda55b7a8 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -203,6 +203,7 @@ static int mmap_events(synth_cb synth) } pr_debug("map %p, addr %" PRIx64 "\n", al.map, map__start(al.map)); + map__put(al.map); } machine__delete_threads(machine); diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 8e7c29836765..b0dafc758173 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -589,7 +589,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) } call->ip = cursor_node->ip; call->ms = cursor_node->ms; - map__get(call->ms.map); + call->ms.map = map__get(call->ms.map); call->srcline = cursor_node->srcline; if (cursor_node->branch) { @@ -1067,7 +1067,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, node->ip = ip; map__zput(node->ms.map); node->ms = *ms; - map__get(node->ms.map); + node->ms.map = map__get(node->ms.map); node->branch = branch; node->nr_loop_iter = nr_loop_iter; node->iter_cycles = iter_cycles; @@ -1115,7 +1115,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * struct machine *machine = maps__machine(node->ms.maps); al->maps = node->ms.maps; - al->map = node->ms.map; + map__put(al->map); + al->map = map__get(node->ms.map); al->sym = node->ms.sym; al->srcline = node->srcline; al->addr = node->ip; @@ -1528,7 +1529,7 @@ int callchain_node__make_parent_list(struct callchain_node *node) goto out; *new = *chain; new->has_children = false; - map__get(new->ms.map); + new->ms.map = map__get(new->ms.map); list_add_tail(&new->list, &head); } parent = parent->parent; diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2712d1a8264e..13f7f85e92e1 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -485,13 +485,14 @@ size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *ma if (machine) { struct addr_location al; - al.map = maps__find(machine__kernel_maps(machine), tp->addr); + al.map = map__get(maps__find(machine__kernel_maps(machine), tp->addr)); if (al.map && map__load(al.map) >= 0) { al.addr = map__map_ip(al.map, tp->addr); al.sym = map__find_symbol(al.map, al.addr); if (al.sym) ret += symbol__fprintf_symname_offs(al.sym, &al, fp); } + map__put(al.map); } ret += fprintf(fp, " old len %u new len %u\n", tp->old_len, tp->new_len); old = true; @@ -614,7 +615,7 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, return NULL; } - al->map = maps__find(maps, al->addr); + al->map = map__get(maps__find(maps, al->addr)); if (al->map != NULL) { /* * Kernel maps might be changed when loading symbols so loading @@ -773,6 +774,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al, */ void addr_location__put(struct addr_location *al) { + map__zput(al->map); thread__zput(al->thread); } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e494425cad06..51020da15ffc 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -450,7 +450,7 @@ static int hist_entry__init(struct hist_entry *he, memset(&he->stat, 0, sizeof(he->stat)); } - map__get(he->ms.map); + he->ms.map = map__get(he->ms.map); if (he->branch_info) { /* @@ -465,13 +465,13 @@ static int hist_entry__init(struct hist_entry *he, memcpy(he->branch_info, template->branch_info, sizeof(*he->branch_info)); - map__get(he->branch_info->from.ms.map); - map__get(he->branch_info->to.ms.map); + he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map); + he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map); } if (he->mem_info) { - map__get(he->mem_info->iaddr.ms.map); - map__get(he->mem_info->daddr.ms.map); + he->mem_info->iaddr.ms.map = map__get(he->mem_info->iaddr.ms.map); + he->mem_info->daddr.ms.map = map__get(he->mem_info->daddr.ms.map); } if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1ea6f6c06bbb..25738775834e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -881,21 +881,29 @@ static int machine__process_ksymbol_register(struct machine *machine, struct symbol *sym; struct dso *dso; struct map *map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr); + bool put_map = false; + int err = 0; if (!map) { - int err; - dso = dso__new(event->ksymbol.name); - if (dso) { - dso->kernel = DSO_SPACE__KERNEL; - map = map__new2(0, dso); - dso__put(dso); - } - if (!dso || !map) { - return -ENOMEM; + if (!dso) { + err = -ENOMEM; + goto out; } - + dso->kernel = DSO_SPACE__KERNEL; + map = map__new2(0, dso); + dso__put(dso); + if (!map) { + err = -ENOMEM; + goto out; + } + /* + * The inserted map has a get on it, we need to put to release + * the reference count here, but do it after all accesses are + * done. + */ + put_map = true; if (event->ksymbol.ksym_type == PERF_RECORD_KSYMBOL_TYPE_OOL) { dso->binary_type = DSO_BINARY_TYPE__OOL; dso->data.file_size = event->ksymbol.len; @@ -905,9 +913,10 @@ static int machine__process_ksymbol_register(struct machine *machine, map->start = event->ksymbol.addr; map->end = map__start(map) + event->ksymbol.len; err = maps__insert(machine__kernel_maps(machine), map); - map__put(map); - if (err) - return err; + if (err) { + err = -ENOMEM; + goto out; + } dso__set_loaded(dso); @@ -922,10 +931,15 @@ static int machine__process_ksymbol_register(struct machine *machine, sym = symbol__new(map__map_ip(map, map__start(map)), event->ksymbol.len, 0, 0, event->ksymbol.name); - if (!sym) - return -ENOMEM; + if (!sym) { + err = -ENOMEM; + goto out; + } dso__insert_symbol(dso, sym); - return 0; +out: + if (put_map) + map__put(map); + return err; } static int machine__process_ksymbol_unregister(struct machine *machine, @@ -1027,13 +1041,11 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start goto out; err = maps__insert(machine__kernel_maps(machine), map); - - /* Put the map here because maps__insert already got it */ - map__put(map); - /* If maps__insert failed, return NULL. */ - if (err) + if (err) { + map__put(map); map = NULL; + } out: /* put the dso here, corresponding to machine__findnew_module_dso */ dso__put(dso); @@ -1325,6 +1337,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) /* In case of renewal the kernel map, destroy previous one */ machine__destroy_kernel_maps(machine); + map__put(machine->vmlinux_map); machine->vmlinux_map = map__new2(0, kernel); if (machine->vmlinux_map == NULL) return -ENOMEM; @@ -1613,7 +1626,7 @@ static int machine__create_module(void *arg, const char *name, u64 start, map->end = start + size; dso__kernel_module_get_build_id(map__dso(map), machine->root_dir); - + map__put(map); return 0; } @@ -1659,16 +1672,18 @@ static void machine__set_kernel_mmap(struct machine *machine, static int machine__update_kernel_mmap(struct machine *machine, u64 start, u64 end) { - struct map *map = machine__kernel_map(machine); + struct map *orig, *updated; int err; - map__get(map); - maps__remove(machine__kernel_maps(machine), map); + orig = machine->vmlinux_map; + updated = map__get(orig); + machine->vmlinux_map = updated; machine__set_kernel_mmap(machine, start, end); + maps__remove(machine__kernel_maps(machine), orig); + err = maps__insert(machine__kernel_maps(machine), updated); + map__put(orig); - err = maps__insert(machine__kernel_maps(machine), map); - map__put(map); return err; } @@ -2295,7 +2310,7 @@ static int add_callchain_ip(struct thread *thread, { struct map_symbol ms; struct addr_location al; - int nr_loop_iter = 0; + int nr_loop_iter = 0, err; u64 iter_cycles = 0; const char *srcline = NULL; @@ -2360,9 +2375,11 @@ static int add_callchain_ip(struct thread *thread, return 0; srcline = callchain_srcline(&ms, al.addr); - return callchain_cursor_append(cursor, ip, &ms, - branch, flags, nr_loop_iter, - iter_cycles, branch_from, srcline); + err = callchain_cursor_append(cursor, ip, &ms, + branch, flags, nr_loop_iter, + iter_cycles, branch_from, srcline); + map__put(al.map); + return err; } struct branch_info *sample__resolve_bstack(struct perf_sample *sample, diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 6426af6882c2..d81b6ca18ee9 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -410,7 +410,7 @@ struct map *map__clone(struct map *from) map = memdup(from, size); if (map != NULL) { refcount_set(&map->refcnt, 1); - dso__get(dso); + map->dso = dso__get(dso); } return map; -- cgit v1.2.3 From 220368293a010d39fe41f130b99b666394034b08 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 7 Apr 2023 22:44:54 -0700 Subject: perf test stat+csv_output: Write CSV output to a file Write the CSV output to a file, then sanity check this output. This avoids problems with debug/warning/error output corrupting the file format. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Sumanth Korikkar Cc: Thomas Richter Link: https://lore.kernel.org/r/20230408054456.3001367-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat+csv_output.sh | 58 ++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index 324fc9e6edd7..fb78b6251a4e 100755 --- a/tools/perf/tests/shell/stat+csv_output.sh +++ b/tools/perf/tests/shell/stat+csv_output.sh @@ -9,6 +9,20 @@ set -e skip_test=0 csv_sep=@ +stat_output=$(mktemp /tmp/__perf_test.stat_output.csv.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + function commachecker() { local -i cnt=0 @@ -30,9 +44,11 @@ function commachecker() while read line do - # Check for lines beginning with Failed - x=${line:0:6} - [ "$x" = "Failed" ] && continue + # Ignore initial "started on" comment. + x=${line:0:1} + [ "$x" = "#" ] && continue + # Ignore initial blank line. + [ "$line" = "" ] && continue # Count the number of commas x=$(echo $line | tr -d -c $csv_sep) @@ -42,7 +58,7 @@ function commachecker() echo "wrong number of fields. expected $exp in $line" 1>&2 exit 1; } - done + done < "${stat_output}" return 0 } @@ -55,7 +71,8 @@ function ParanoidAndNotRoot() check_no_args() { echo -n "Checking CSV output: no args " - perf stat -x$csv_sep true 2>&1 | commachecker --no-args + perf stat -x$csv_sep -o "${stat_output}" true + commachecker --no-args echo "[Success]" } @@ -67,27 +84,29 @@ check_system_wide() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep -a true 2>&1 | commachecker --system-wide + perf stat -x$csv_sep -a -o "${stat_output}" true + commachecker --system-wide echo "[Success]" } check_system_wide_no_aggr() { - echo -n "Checking CSV output: system wide " + echo -n "Checking CSV output: system wide no aggregation " if ParanoidAndNotRoot 0 then echo "[Skip] paranoid and not root" return fi - echo -n "Checking CSV output: system wide no aggregation " - perf stat -x$csv_sep -A -a --no-merge true 2>&1 | commachecker --system-wide-no-aggr + perf stat -x$csv_sep -A -a --no-merge -o "${stat_output}" true + commachecker --system-wide-no-aggr echo "[Success]" } check_interval() { echo -n "Checking CSV output: interval " - perf stat -x$csv_sep -I 1000 true 2>&1 | commachecker --interval + perf stat -x$csv_sep -I 1000 -o "${stat_output}" true + commachecker --interval echo "[Success]" } @@ -95,7 +114,8 @@ check_interval() check_event() { echo -n "Checking CSV output: event " - perf stat -x$csv_sep -e cpu-clock true 2>&1 | commachecker --event + perf stat -x$csv_sep -e cpu-clock -o "${stat_output}" true + commachecker --event echo "[Success]" } @@ -107,7 +127,8 @@ check_per_core() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-core -a true 2>&1 | commachecker --per-core + perf stat -x$csv_sep --per-core -a -o "${stat_output}" true + commachecker --per-core echo "[Success]" } @@ -119,7 +140,8 @@ check_per_thread() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-thread -a true 2>&1 | commachecker --per-thread + perf stat -x$csv_sep --per-thread -a -o "${stat_output}" true + commachecker --per-thread echo "[Success]" } @@ -131,7 +153,8 @@ check_per_die() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-die -a true 2>&1 | commachecker --per-die + perf stat -x$csv_sep --per-die -a -o "${stat_output}" true + commachecker --per-die echo "[Success]" } @@ -143,7 +166,8 @@ check_per_node() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-node -a true 2>&1 | commachecker --per-node + perf stat -x$csv_sep --per-node -a -o "${stat_output}" true + commachecker --per-node echo "[Success]" } @@ -155,7 +179,8 @@ check_per_socket() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-socket -a true 2>&1 | commachecker --per-socket + perf stat -x$csv_sep --per-socket -a -o "${stat_output}" true + commachecker --per-socket echo "[Success]" } @@ -202,4 +227,5 @@ then else echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid" fi +cleanup exit 0 -- cgit v1.2.3 From 760eafb2a3dd568a8eec519bf21c9a24582930f3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 7 Apr 2023 22:44:56 -0700 Subject: perf test stat+json_output: Write JSON output to a file Write the JSON output to a file, then sanity check this output. This avoids problems with debug/warning/error output corrupting the file format. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Sumanth Korikkar Cc: Thomas Richter Link: https://lore.kernel.org/r/20230408054456.3001367-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/tests/shell/lib/perf_json_output_lint.py | 3 +- tools/perf/tests/shell/stat+json_output.sh | 48 ++++++++++++++++------ 2 files changed, 38 insertions(+), 13 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/perf/tests/shell/lib/perf_json_output_lint.py index 97598d14e532..61f3059ca54b 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -17,9 +17,10 @@ ap.add_argument('--per-thread', action='store_true') ap.add_argument('--per-die', action='store_true') ap.add_argument('--per-node', action='store_true') ap.add_argument('--per-socket', action='store_true') +ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin) args = ap.parse_args() -Lines = sys.stdin.readlines() +Lines = args.file.readlines() def isfloat(num): try: diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 2c4212c641ed..f3e4967cc72e 100755 --- a/tools/perf/tests/shell/stat+json_output.sh +++ b/tools/perf/tests/shell/stat+json_output.sh @@ -23,6 +23,20 @@ then fi fi +stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + # Return true if perf_event_paranoid is > $1 and not running as root. function ParanoidAndNotRoot() { @@ -32,7 +46,8 @@ function ParanoidAndNotRoot() check_no_args() { echo -n "Checking json output: no args " - perf stat -j true 2>&1 | $PYTHON $pythonchecker --no-args + perf stat -j -o "${stat_output}" true + $PYTHON $pythonchecker --no-args --file "${stat_output}" echo "[Success]" } @@ -44,27 +59,29 @@ check_system_wide() echo "[Skip] paranoia and not root" return fi - perf stat -j -a true 2>&1 | $PYTHON $pythonchecker --system-wide + perf stat -j -a -o "${stat_output}" true + $PYTHON $pythonchecker --system-wide --file "${stat_output}" echo "[Success]" } check_system_wide_no_aggr() { - echo -n "Checking json output: system wide " + echo -n "Checking json output: system wide no aggregation " if ParanoidAndNotRoot 0 then echo "[Skip] paranoia and not root" return fi - echo -n "Checking json output: system wide no aggregation " - perf stat -j -A -a --no-merge true 2>&1 | $PYTHON $pythonchecker --system-wide-no-aggr + perf stat -j -A -a --no-merge -o "${stat_output}" true + $PYTHON $pythonchecker --system-wide-no-aggr --file "${stat_output}" echo "[Success]" } check_interval() { echo -n "Checking json output: interval " - perf stat -j -I 1000 true 2>&1 | $PYTHON $pythonchecker --interval + perf stat -j -I 1000 -o "${stat_output}" true + $PYTHON $pythonchecker --interval --file "${stat_output}" echo "[Success]" } @@ -72,7 +89,8 @@ check_interval() check_event() { echo -n "Checking json output: event " - perf stat -j -e cpu-clock true 2>&1 | $PYTHON $pythonchecker --event + perf stat -j -e cpu-clock -o "${stat_output}" true + $PYTHON $pythonchecker --event --file "${stat_output}" echo "[Success]" } @@ -84,7 +102,8 @@ check_per_core() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-core -a true 2>&1 | $PYTHON $pythonchecker --per-core + perf stat -j --per-core -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-core --file "${stat_output}" echo "[Success]" } @@ -96,7 +115,8 @@ check_per_thread() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-thread -a true 2>&1 | $PYTHON $pythonchecker --per-thread + perf stat -j --per-thread -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-thread --file "${stat_output}" echo "[Success]" } @@ -108,7 +128,8 @@ check_per_die() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-die -a true 2>&1 | $PYTHON $pythonchecker --per-die + perf stat -j --per-die -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-die --file "${stat_output}" echo "[Success]" } @@ -120,7 +141,8 @@ check_per_node() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-node -a true 2>&1 | $PYTHON $pythonchecker --per-node + perf stat -j --per-node -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-node --file "${stat_output}" echo "[Success]" } @@ -132,7 +154,8 @@ check_per_socket() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-socket -a true 2>&1 | $PYTHON $pythonchecker --per-socket + perf stat -j --per-socket -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-socket --file "${stat_output}" echo "[Success]" } @@ -179,4 +202,5 @@ then else echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid" fi +cleanup exit 0 -- cgit v1.2.3 From 9ccbc21166ce149c5f7429cad22f9073d3fab0b1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Apr 2023 09:50:08 -0300 Subject: perf tests api-io: Use zfree() to reduce chances of use after free Do defensive programming by using zfree() to initialize freed pointers to NULL, so that eventual use after free result in a NULL pointer deref instead of more subtle behaviour. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/api-io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/api-io.c b/tools/perf/tests/api-io.c index 6aea84ca6673..0ba3d5ccebcf 100644 --- a/tools/perf/tests/api-io.c +++ b/tools/perf/tests/api-io.c @@ -12,6 +12,7 @@ #include "tests.h" #include #include +#include #define TEMPL "/tmp/perf-test-XXXXXX" @@ -79,7 +80,7 @@ static int setup_test(char path[PATH_MAX], const char *contents, static void cleanup_test(char path[PATH_MAX], struct io *io) { - free(io->buf); + zfree(&io->buf); close(io->fd); unlink(path); } -- cgit v1.2.3 From 4e8db2d7520f780f86055465c680e20327008a34 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Apr 2023 12:36:58 -0300 Subject: perf map: Add map__refcnt() accessor to use in the maps test To remove one more direct access to 'struct map' so that we can intecept accesses to its instantiations and refcount check it to catch use after free, etc. Cc: Adrian Hunter Cc: Alexey Bayduraev Cc: Dmitriy Vyukov Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Cc: Riccardo Mancini Cc: Stephane Eranian Cc: Stephen Brennan Link: https://lore.kernel.org/lkml/ZDbRIJknafLnDwtO@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/maps.c | 4 ++-- tools/perf/util/map.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index 1c7293476aca..a6278f9c8b71 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -30,7 +30,7 @@ static int check_maps(struct map_def *merged, unsigned int size, struct maps *ma if (map__start(map) != merged[i].start || map__end(map) != merged[i].end || strcmp(map__dso(map)->name, merged[i].name) || - refcount_read(&map->refcnt) != 1) { + refcount_read(map__refcnt(map)) != 1) { failed = true; } i++; @@ -50,7 +50,7 @@ static int check_maps(struct map_def *merged, unsigned int size, struct maps *ma map__start(map), map__end(map), map__dso(map)->name, - refcount_read(&map->refcnt)); + refcount_read(map__refcnt(map))); } } return failed ? TEST_FAIL : TEST_OK; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 102485699aa8..f89ab7c2d327 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -97,6 +97,11 @@ static inline bool map__priv(const struct map *map) return map->priv; } +static inline refcount_t *map__refcnt(struct map *map) +{ + return &map->refcnt; +} + static inline size_t map__size(const struct map *map) { return map__end(map) - map__start(map); -- cgit v1.2.3 From 17354d1528f902b3a4f66023cd24012e7999c4dc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Apr 2023 11:26:42 -0300 Subject: perf test: Simplify for_each_test() to avoid tripping on -Werror=array-bounds When cross building on debian to the mips 32-bit arch we get these warnings: In function '__cmd_test', inlined from 'cmd_test' at tests/builtin-test.c:561:9: tests/builtin-test.c:260:66: error: array subscript 1 is outside array bounds of 'struct test_suite *[1]' [-Werror=array-bounds] 260 | for (k = 0, t = tests[j][k]; tests[j][k]; k++, t = tests[j][k]) | ^ tests/builtin-test.c:369:9: note: in expansion of macro 'for_each_test' 369 | for_each_test(j, k, t) { | ^~~~~~~~~~~~~ tests/builtin-test.c: In function 'cmd_test': tests/builtin-test.c:36:27: note: at offset 4 into object 'arch_tests' of size 4 36 | struct test_suite *__weak arch_tests[] = { | ^~~~~~~~~~ cc1: all warnings being treated as errors Switch to using a while(!sentinel) for the second level of the 'tests' array to avoid that compiler complaint. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 35cc3807cc9e..b89d69afcef0 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -256,8 +256,8 @@ static int run_test(struct test_suite *test, int subtest) } #define for_each_test(j, k, t) \ - for (j = 0; j < ARRAY_SIZE(tests); j++) \ - for (k = 0, t = tests[j][k]; tests[j][k]; k++, t = tests[j][k]) + for (j = 0, k = 0; j < ARRAY_SIZE(tests); j++, k = 0) \ + while ((t = tests[j][k++]) != NULL) static int test_and_print(struct test_suite *t, int subtest) { -- cgit v1.2.3 From 4121234a32887a49d5da06e4c219f67abb6e744f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 17 Apr 2023 12:47:49 -0300 Subject: libperf: Add perf_cpu_map__refcnt() interanl accessor to use in the maps test To remove one more direct access to 'struct perf_cpu_map' so that we can intercept accesses to its instantiations and refcount check it to catch use after free, etc. Cc: Adrian Hunter Cc: Alexey Bayduraev Cc: Dmitriy Vyukov Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Cc: Riccardo Mancini Cc: Stephane Eranian Cc: Stephen Brennan Link: https://lore.kernel.org/lkml/ZD1qdYjG+DL6KOfP@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/cpumap.c | 6 +++--- tools/lib/perf/include/internal/cpumap.h | 4 ++++ tools/perf/tests/cpumap.c | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 6bbcbb83eb14..27c3e73c6db2 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -40,7 +40,7 @@ struct perf_cpu_map *perf_cpu_map__dummy_new(void) static void cpu_map__delete(struct perf_cpu_map *map) { if (map) { - WARN_ONCE(refcount_read(&map->refcnt) != 0, + WARN_ONCE(refcount_read(perf_cpu_map__refcnt(map)) != 0, "cpu_map refcnt unbalanced\n"); free(map); } @@ -49,13 +49,13 @@ static void cpu_map__delete(struct perf_cpu_map *map) struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map) { if (map) - refcount_inc(&map->refcnt); + refcount_inc(perf_cpu_map__refcnt(map)); return map; } void perf_cpu_map__put(struct perf_cpu_map *map) { - if (map && refcount_dec_and_test(&map->refcnt)) + if (map && refcount_dec_and_test(perf_cpu_map__refcnt(map))) cpu_map__delete(map); } diff --git a/tools/lib/perf/include/internal/cpumap.h b/tools/lib/perf/include/internal/cpumap.h index b82fd6607a00..1e840dd53a11 100644 --- a/tools/lib/perf/include/internal/cpumap.h +++ b/tools/lib/perf/include/internal/cpumap.h @@ -30,4 +30,8 @@ bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct perf_cpu void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus); +static inline refcount_t *perf_cpu_map__refcnt(struct perf_cpu_map *map) +{ + return &map->refcnt; +} #endif /* __LIBPERF_INTERNAL_CPUMAP_H */ diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 3150fc1fed6f..b1a924314e09 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -68,7 +68,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) == 2); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu == 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 1).cpu == 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(perf_cpu_map__refcnt(map)) == 1); perf_cpu_map__put(map); return 0; } @@ -94,7 +94,7 @@ static int process_event_range_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) == 256); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu == 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__max(map).cpu == 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(perf_cpu_map__refcnt(map)) == 1); perf_cpu_map__put(map); return 0; } -- cgit v1.2.3 From fe693d951e3c303b4fb6c712f8affecbe9e8b001 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Apr 2023 17:33:48 -0300 Subject: perf maps: Add maps__refcnt() accessor to allow checking maps pointer To remove one more direct access to 'struct maps' so that we can intercept accesses to its instantiations and refcount check it to catch use after free, etc. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/thread-maps-share.c | 12 ++++++------ tools/perf/util/maps.c | 6 +++--- tools/perf/util/maps.h | 5 +++++ 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c index 84edd82c519e..caf8fbe7c440 100644 --- a/tools/perf/tests/thread-maps-share.c +++ b/tools/perf/tests/thread-maps-share.c @@ -43,7 +43,7 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s leader && t1 && t2 && t3 && other); maps = leader->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 4); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 4); /* test the maps pointer is shared */ TEST_ASSERT_VAL("maps don't match", maps == t1->maps); @@ -71,25 +71,25 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s machine__remove_thread(machine, other_leader); other_maps = other->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 2); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(other_maps)), 2); TEST_ASSERT_VAL("maps don't match", other_maps == other_leader->maps); /* release thread group */ thread__put(leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 3); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 3); thread__put(t1); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 2); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 2); thread__put(t2); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 1); thread__put(t3); /* release other group */ thread__put(other_leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(other_maps)), 1); thread__put(other); diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 5afed53ea0b4..953dc20d55d7 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -12,13 +12,13 @@ static void maps__init(struct maps *maps, struct machine *machine) { + refcount_set(maps__refcnt(maps), 1); maps->entries = RB_ROOT; init_rwsem(maps__lock(maps)); maps->machine = machine; maps->last_search_by_name = NULL; maps->nr_maps = 0; maps->maps_by_name = NULL; - refcount_set(&maps->refcnt, 1); } static void __maps__free_maps_by_name(struct maps *maps) @@ -180,14 +180,14 @@ void maps__delete(struct maps *maps) struct maps *maps__get(struct maps *maps) { if (maps) - refcount_inc(&maps->refcnt); + refcount_inc(maps__refcnt(maps)); return maps; } void maps__put(struct maps *maps) { - if (maps && refcount_dec_and_test(&maps->refcnt)) + if (maps && refcount_dec_and_test(maps__refcnt(maps))) maps__delete(maps); } diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index bde3390c7096..cfb1b79d1671 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -88,6 +88,11 @@ static inline unsigned int maps__nr_maps(const struct maps *maps) return maps->nr_maps; } +static inline refcount_t *maps__refcnt(struct maps *maps) +{ + return &maps->refcnt; +} + #ifdef HAVE_LIBUNWIND_SUPPORT static inline void *maps__addr_space(struct maps *maps) { -- cgit v1.2.3 From 8f12692b7e61e5fb5d3e4f6692d6675f62eeebdc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 19 Apr 2023 10:48:37 -0300 Subject: perf maps: Add reference count checking Add reference count checking to make sure of good use of get and put. Add and use accessors to reduce RC_CHK clutter. The only significant issue was in tests/thread-maps-share.c where reference counts were released in the reverse order to acquisition, leading to a use after put. This was fixed by reversing the put order. Committer notes: Extracted from a larger patch removing bits that were covered by the use of pre-existing maps__ accessors (e.g. maps__nr_maps()) and new ones added (maps__refcnt()) to reduce RC_CHK_ACCESS(maps)-> source code pollution. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexey Bayduraev Cc: Dmitriy Vyukov Cc: Jiri Olsa Cc: Namhyung Kim Cc: Riccardo Mancini Cc: Stephane Eranian Cc: Stephen Brennan Link: https://lore.kernel.org/lkml/20230407230405.2931830-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/thread-maps-share.c | 8 +++--- tools/perf/util/maps.c | 47 ++++++++++++++++++-------------- tools/perf/util/maps.h | 19 +++++++------ tools/perf/util/symbol.c | 13 +++++---- tools/perf/util/unwind-libdw.c | 2 +- tools/perf/util/unwind-libunwind-local.c | 2 +- tools/perf/util/unwind-libunwind.c | 2 +- 7 files changed, 50 insertions(+), 43 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c index caf8fbe7c440..75ce8aedfc78 100644 --- a/tools/perf/tests/thread-maps-share.c +++ b/tools/perf/tests/thread-maps-share.c @@ -46,9 +46,9 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 4); /* test the maps pointer is shared */ - TEST_ASSERT_VAL("maps don't match", maps == t1->maps); - TEST_ASSERT_VAL("maps don't match", maps == t2->maps); - TEST_ASSERT_VAL("maps don't match", maps == t3->maps); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t1->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t2->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t3->maps)); /* * Verify the other leader was created by previous call. @@ -73,7 +73,7 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s other_maps = other->maps; TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(other_maps)), 2); - TEST_ASSERT_VAL("maps don't match", other_maps == other_leader->maps); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(other_maps) == RC_CHK_ACCESS(other_leader->maps)); /* release thread group */ thread__put(leader); diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 953dc20d55d7..8a13396acd1a 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -13,12 +13,12 @@ static void maps__init(struct maps *maps, struct machine *machine) { refcount_set(maps__refcnt(maps), 1); - maps->entries = RB_ROOT; init_rwsem(maps__lock(maps)); - maps->machine = machine; - maps->last_search_by_name = NULL; - maps->nr_maps = 0; - maps->maps_by_name = NULL; + RC_CHK_ACCESS(maps)->entries = RB_ROOT; + RC_CHK_ACCESS(maps)->machine = machine; + RC_CHK_ACCESS(maps)->last_search_by_name = NULL; + RC_CHK_ACCESS(maps)->nr_maps = 0; + RC_CHK_ACCESS(maps)->maps_by_name = NULL; } static void __maps__free_maps_by_name(struct maps *maps) @@ -29,8 +29,8 @@ static void __maps__free_maps_by_name(struct maps *maps) for (unsigned int i = 0; i < maps__nr_maps(maps); i++) map__put(maps__maps_by_name(maps)[i]); - zfree(&maps->maps_by_name); - maps->nr_maps_allocated = 0; + zfree(&RC_CHK_ACCESS(maps)->maps_by_name); + RC_CHK_ACCESS(maps)->nr_maps_allocated = 0; } static int __maps__insert(struct maps *maps, struct map *map) @@ -71,7 +71,7 @@ int maps__insert(struct maps *maps, struct map *map) if (err) goto out; - ++maps->nr_maps; + ++RC_CHK_ACCESS(maps)->nr_maps; if (dso && dso->kernel) { struct kmap *kmap = map__kmap(map); @@ -88,7 +88,7 @@ int maps__insert(struct maps *maps, struct map *map) * inserted map and resort. */ if (maps__maps_by_name(maps)) { - if (maps__nr_maps(maps) > maps->nr_maps_allocated) { + if (maps__nr_maps(maps) > RC_CHK_ACCESS(maps)->nr_maps_allocated) { int nr_allocate = maps__nr_maps(maps) * 2; struct map **maps_by_name = realloc(maps__maps_by_name(maps), nr_allocate * sizeof(map)); @@ -99,8 +99,8 @@ int maps__insert(struct maps *maps, struct map *map) goto out; } - maps->maps_by_name = maps_by_name; - maps->nr_maps_allocated = nr_allocate; + RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated = nr_allocate; } maps__maps_by_name(maps)[maps__nr_maps(maps) - 1] = map__get(map); __maps__sort_by_name(maps); @@ -122,15 +122,15 @@ void maps__remove(struct maps *maps, struct map *map) struct map_rb_node *rb_node; down_write(maps__lock(maps)); - if (maps->last_search_by_name == map) - maps->last_search_by_name = NULL; + if (RC_CHK_ACCESS(maps)->last_search_by_name == map) + RC_CHK_ACCESS(maps)->last_search_by_name = NULL; rb_node = maps__find_node(maps, map); assert(rb_node->map == map); __maps__remove(maps, rb_node); if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); - --maps->nr_maps; + --RC_CHK_ACCESS(maps)->nr_maps; up_write(maps__lock(maps)); } @@ -162,33 +162,38 @@ bool maps__empty(struct maps *maps) struct maps *maps__new(struct machine *machine) { - struct maps *maps = zalloc(sizeof(*maps)); + struct maps *result; + RC_STRUCT(maps) *maps = zalloc(sizeof(*maps)); - if (maps != NULL) - maps__init(maps, machine); + if (ADD_RC_CHK(result, maps)) + maps__init(result, machine); - return maps; + return result; } void maps__delete(struct maps *maps) { maps__exit(maps); unwind__finish_access(maps); - free(maps); + RC_CHK_FREE(maps); } struct maps *maps__get(struct maps *maps) { - if (maps) + struct maps *result; + + if (RC_CHK_GET(result, maps)) refcount_inc(maps__refcnt(maps)); - return maps; + return result; } void maps__put(struct maps *maps) { if (maps && refcount_dec_and_test(maps__refcnt(maps))) maps__delete(maps); + else + RC_CHK_PUT(maps); } struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index cfb1b79d1671..d2963456cfbe 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -8,6 +8,7 @@ #include #include #include "rwsem.h" +#include struct ref_reloc_sym; struct machine; @@ -32,7 +33,7 @@ struct map *maps__find(struct maps *maps, u64 addr); for (map = maps__first(maps), next = map_rb_node__next(map); map; \ map = next, next = map_rb_node__next(map)) -struct maps { +DECLARE_RC_STRUCT(maps) { struct rb_root entries; struct rw_semaphore lock; struct machine *machine; @@ -65,43 +66,43 @@ void maps__put(struct maps *maps); static inline struct rb_root *maps__entries(struct maps *maps) { - return &maps->entries; + return &RC_CHK_ACCESS(maps)->entries; } static inline struct machine *maps__machine(struct maps *maps) { - return maps->machine; + return RC_CHK_ACCESS(maps)->machine; } static inline struct rw_semaphore *maps__lock(struct maps *maps) { - return &maps->lock; + return &RC_CHK_ACCESS(maps)->lock; } static inline struct map **maps__maps_by_name(struct maps *maps) { - return maps->maps_by_name; + return RC_CHK_ACCESS(maps)->maps_by_name; } static inline unsigned int maps__nr_maps(const struct maps *maps) { - return maps->nr_maps; + return RC_CHK_ACCESS(maps)->nr_maps; } static inline refcount_t *maps__refcnt(struct maps *maps) { - return &maps->refcnt; + return &RC_CHK_ACCESS(maps)->refcnt; } #ifdef HAVE_LIBUNWIND_SUPPORT static inline void *maps__addr_space(struct maps *maps) { - return maps->addr_space; + return RC_CHK_ACCESS(maps)->addr_space; } static inline const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct maps *maps) { - return maps->unwind_libunwind_ops; + return RC_CHK_ACCESS(maps)->unwind_libunwind_ops; } #endif diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7f63670688e..01fa5560a0bb 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2096,8 +2096,8 @@ static int map__groups__sort_by_name_from_rbtree(struct maps *maps) up_read(maps__lock(maps)); down_write(maps__lock(maps)); - maps->maps_by_name = maps_by_name; - maps->nr_maps_allocated = maps__nr_maps(maps); + RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); maps__for_each_entry(maps, rb_node) maps_by_name[i++] = map__get(rb_node->map); @@ -2132,11 +2132,12 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) down_read(maps__lock(maps)); - if (maps->last_search_by_name) { - const struct dso *dso = map__dso(maps->last_search_by_name); + + if (RC_CHK_ACCESS(maps)->last_search_by_name) { + const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); if (strcmp(dso->short_name, name) == 0) { - map = maps->last_search_by_name; + map = RC_CHK_ACCESS(maps)->last_search_by_name; goto out_unlock; } } @@ -2156,7 +2157,7 @@ struct map *maps__find_by_name(struct maps *maps, const char *name) map = rb_node->map; dso = map__dso(map); if (strcmp(dso->short_name, name) == 0) { - maps->last_search_by_name = map; + RC_CHK_ACCESS(maps)->last_search_by_name = map; goto out_unlock; } } diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 9565f9906e5d..bdccfc511b7e 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -230,7 +230,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct unwind_info *ui, ui_buf = { .sample = data, .thread = thread, - .machine = thread->maps->machine, + .machine = RC_CHK_ACCESS(thread->maps)->machine, .cb = cb, .arg = arg, .max_stack = max_stack, diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index f9a52af48de4..83dd79dcd597 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -677,7 +677,7 @@ static int _unwind__prepare_access(struct maps *maps) { void *addr_space = unw_create_addr_space(&accessors, 0); - maps->addr_space = addr_space; + RC_CHK_ACCESS(maps)->addr_space = addr_space; if (!addr_space) { pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 4378daaafcd3..b54968e6a4e4 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -14,7 +14,7 @@ struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; static void unwind__register_ops(struct maps *maps, struct unwind_libunwind_ops *ops) { - maps->unwind_libunwind_ops = ops; + RC_CHK_ACCESS(maps)->unwind_libunwind_ops = ops; } int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized) -- cgit v1.2.3 From e6a9efcee55f084a5450e4853ecbbaa0b086dcd0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Apr 2023 12:24:12 -0300 Subject: perf map: Add set_ methods for map->{start,end,pgoff,pgoff,reloc,erange_warned,dso,map_ip,unmap_ip,priv} To have a way to intercept usage of the reference counted struct map. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +-- tools/perf/tests/maps.c | 16 ++++----- tools/perf/tests/vmlinux-kallsyms.c | 4 +-- tools/perf/util/machine.c | 23 ++++++------- tools/perf/util/map.c | 20 ++++++------ tools/perf/util/map.h | 65 +++++++++++++++++++++++++++++++++++++ tools/perf/util/maps.c | 6 ++-- tools/perf/util/symbol-elf.c | 26 +++++++-------- tools/perf/util/symbol.c | 33 ++++++++++--------- 9 files changed, 132 insertions(+), 65 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5d448c36ed22..eb5740154bc0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -191,7 +191,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) if (use_browser <= 0) sleep(5); - map->erange_warned = true; + map__set_erange_warned(map, true); } static void perf_top__record_precise_ip(struct perf_top *top, @@ -225,7 +225,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, */ mutex_unlock(&he->hists->lock); - if (err == -ERANGE && !he->ms.map->erange_warned) + if (err == -ERANGE && !map__erange_warned(he->ms.map)) ui__warn_map_erange(he->ms.map, sym, ip); else if (err == -ENOMEM) { pr_err("Not enough memory for annotating '%s' symbol!\n", diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index a6278f9c8b71..8c0eb5cf8bb5 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -95,8 +95,8 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest map = dso__new_map(bpf_progs[i].name); TEST_ASSERT_VAL("failed to create map", map); - map->start = bpf_progs[i].start; - map->end = bpf_progs[i].end; + map__set_start(map, bpf_progs[i].start); + map__set_end(map, bpf_progs[i].end); TEST_ASSERT_VAL("failed to insert map", maps__insert(maps, map) == 0); map__put(map); } @@ -111,16 +111,16 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest TEST_ASSERT_VAL("failed to create map", map_kcore3); /* kcore1 map overlaps over all bpf maps */ - map_kcore1->start = 100; - map_kcore1->end = 1000; + map__set_start(map_kcore1, 100); + map__set_end(map_kcore1, 1000); /* kcore2 map hides behind bpf_prog_2 */ - map_kcore2->start = 550; - map_kcore2->end = 570; + map__set_start(map_kcore2, 550); + map__set_end(map_kcore2, 570); /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */ - map_kcore3->start = 880; - map_kcore3->end = 1100; + map__set_start(map_kcore3, 880); + map__set_end(map_kcore3, 1100); ret = maps__merge_in(maps, map_kcore1); TEST_ASSERT_VAL("failed to merge map", !ret); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index af511233c764..1078a93b01aa 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -304,7 +304,7 @@ next_pair: dso->short_name : dso->name)); if (pair) { - pair->priv = 1; + map__set_priv(pair, 1); } else { if (!header_printed) { pr_info("WARN: Maps only in vmlinux:\n"); @@ -340,7 +340,7 @@ next_pair: pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, map__start(pair), map__end(pair), map__pgoff(pair)); pr_info(" %s\n", dso->name); - pair->priv = 1; + map__set_priv(pair, 1); } } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 85787672d335..8ccbe48e23bd 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -910,8 +910,8 @@ static int machine__process_ksymbol_register(struct machine *machine, dso__set_loaded(dso); } - map->start = event->ksymbol.addr; - map->end = map__start(map) + event->ksymbol.len; + map__set_start(map, event->ksymbol.addr); + map__set_end(map, map__start(map) + event->ksymbol.len); err = maps__insert(machine__kernel_maps(machine), map); if (err) { err = -ENOMEM; @@ -1218,8 +1218,8 @@ int machine__create_extra_kernel_map(struct machine *machine, if (!map) return -ENOMEM; - map->end = xm->end; - map->pgoff = xm->pgoff; + map__set_end(map, xm->end); + map__set_pgoff(map, xm->pgoff); kmap = map__kmap(map); @@ -1291,7 +1291,7 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, dest_map = maps__find(kmaps, map__pgoff(map)); if (dest_map != map) - map->pgoff = map__map_ip(dest_map, map__pgoff(map)); + map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map))); found = true; } if (found || machine->trampolines_mapped) @@ -1342,7 +1342,8 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) if (machine->vmlinux_map == NULL) return -ENOMEM; - machine->vmlinux_map->map_ip = machine->vmlinux_map->unmap_ip = identity__map_ip; + map__set_map_ip(machine->vmlinux_map, identity__map_ip); + map__set_unmap_ip(machine->vmlinux_map, identity__map_ip); return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); } @@ -1623,7 +1624,7 @@ static int machine__create_module(void *arg, const char *name, u64 start, map = machine__addnew_module_map(machine, start, name); if (map == NULL) return -1; - map->end = start + size; + map__set_end(map, start + size); dso__kernel_module_get_build_id(map__dso(map), machine->root_dir); map__put(map); @@ -1659,14 +1660,14 @@ static int machine__create_modules(struct machine *machine) static void machine__set_kernel_mmap(struct machine *machine, u64 start, u64 end) { - machine->vmlinux_map->start = start; - machine->vmlinux_map->end = end; + map__set_start(machine->vmlinux_map, start); + map__set_end(machine->vmlinux_map, end); /* * Be a bit paranoid here, some perf.data file came with * a zero sized synthesized MMAP event for the kernel. */ if (start == 0 && end == 0) - machine->vmlinux_map->end = ~0ULL; + map__set_end(machine->vmlinux_map, ~0ULL); } static int machine__update_kernel_mmap(struct machine *machine, @@ -1810,7 +1811,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, if (map == NULL) goto out_problem; - map->end = map__start(map) + xm->end - xm->start; + map__set_end(map, map__start(map) + xm->end - xm->start); if (build_id__is_defined(bid)) dso__set_build_id(map__dso(map), bid); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b6a8935026eb..bdd2742fa35b 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -104,14 +104,14 @@ static inline bool replace_android_lib(const char *filename, char *newfilename) void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) { - map->start = start; - map->end = end; - map->pgoff = pgoff; - map->reloc = 0; - map->dso = dso__get(dso); - map->map_ip = map__dso_map_ip; - map->unmap_ip = map__dso_unmap_ip; - map->erange_warned = false; + map__set_start(map, start); + map__set_end(map, end); + map__set_pgoff(map, pgoff); + map__set_reloc(map, 0); + map__set_dso(map, dso__get(dso)); + map__set_map_ip(map, map__dso_map_ip); + map__set_unmap_ip(map, map__dso_unmap_ip); + map__set_erange_warned(map, false); refcount_set(map__refcnt(map), 1); } @@ -317,7 +317,7 @@ void map__fixup_start(struct map *map) if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); - map->start = sym->start; + map__set_start(map, sym->start); } } @@ -329,7 +329,7 @@ void map__fixup_end(struct map *map) if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); - map->end = sym->end; + map__set_end(map, sym->end); } } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 4f7d9505f7ff..0760c671314d 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -62,6 +62,16 @@ static inline u64 map__unmap_ip(const struct map *map, u64 ip) return map->unmap_ip(map, ip); } +static inline void *map__map_ip_ptr(struct map *map) +{ + return map->map_ip; +} + +static inline void* map__unmap_ip_ptr(struct map *map) +{ + return map->unmap_ip; +} + static inline u64 map__start(const struct map *map) { return map->start; @@ -102,6 +112,11 @@ static inline refcount_t *map__refcnt(struct map *map) return &map->refcnt; } +static inline bool map__erange_warned(struct map *map) +{ + return map->erange_warned; +} + static inline size_t map__size(const struct map *map) { return map__end(map) - map__start(map); @@ -231,4 +246,54 @@ static inline int is_no_dso_memory(const char *filename) !strncmp(filename, "/SYSV", 5) || !strcmp(filename, "[heap]"); } + +static inline void map__set_start(struct map *map, u64 start) +{ + map->start = start; +} + +static inline void map__set_end(struct map *map, u64 end) +{ + map->end = end; +} + +static inline void map__set_pgoff(struct map *map, u64 pgoff) +{ + map->pgoff = pgoff; +} + +static inline void map__add_pgoff(struct map *map, u64 inc) +{ + map->pgoff += inc; +} + +static inline void map__set_reloc(struct map *map, u64 reloc) +{ + map->reloc = reloc; +} + +static inline void map__set_priv(struct map *map, int priv) +{ + map->priv = priv; +} + +static inline void map__set_erange_warned(struct map *map, bool erange_warned) +{ + map->erange_warned = erange_warned; +} + +static inline void map__set_dso(struct map *map, struct dso *dso) +{ + map->dso = dso; +} + +static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip)) +{ + map->map_ip = map_ip; +} + +static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip)) +{ + map->unmap_ip = unmap_ip; +} #endif /* __PERF_MAP_H */ diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 8a13396acd1a..df2fc8221f3c 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -339,7 +339,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - before->end = map__start(map); + map__set_end(before, map__start(map)); err = __maps__insert(maps, before); if (err) { map__put(before); @@ -359,8 +359,8 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - after->start = map__end(map); - after->pgoff += map__end(map) - map__start(pos->map); + map__set_start(after, map__end(map)); + map__add_pgoff(after, map__end(map) - map__start(pos->map)); assert(map__map_ip(pos->map, map__end(map)) == map__map_ip(after, map__end(map))); err = __maps__insert(maps, after); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 35724f6a84fa..2a165d83aac4 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1354,11 +1354,11 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, */ if (*remap_kernel && dso->kernel && !kmodule) { *remap_kernel = false; - map->start = shdr->sh_addr + ref_reloc(kmap); - map->end = map__start(map) + shdr->sh_size; - map->pgoff = shdr->sh_offset; - map->map_ip = map__dso_map_ip; - map->unmap_ip = map__dso_unmap_ip; + map__set_start(map, shdr->sh_addr + ref_reloc(kmap)); + map__set_end(map, map__start(map) + shdr->sh_size); + map__set_pgoff(map, shdr->sh_offset); + map__set_map_ip(map, map__dso_map_ip); + map__set_unmap_ip(map, map__dso_unmap_ip); /* Ensure maps are correctly ordered */ if (kmaps) { int err; @@ -1379,7 +1379,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, */ if (*remap_kernel && kmodule) { *remap_kernel = false; - map->pgoff = shdr->sh_offset; + map__set_pgoff(map, shdr->sh_offset); } *curr_mapp = map; @@ -1414,11 +1414,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, map__kmap(curr_map)->kmaps = kmaps; if (adjust_kernel_syms) { - curr_map->start = shdr->sh_addr + ref_reloc(kmap); - curr_map->end = map__start(curr_map) + shdr->sh_size; - curr_map->pgoff = shdr->sh_offset; + map__set_start(curr_map, shdr->sh_addr + ref_reloc(kmap)); + map__set_end(curr_map, map__start(curr_map) + shdr->sh_size); + map__set_pgoff(curr_map, shdr->sh_offset); } else { - curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; + map__set_map_ip(curr_map, identity__map_ip); + map__set_unmap_ip(curr_map, identity__map_ip); } curr_dso->symtab_type = dso->symtab_type; if (maps__insert(kmaps, curr_map)) @@ -1525,8 +1526,7 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, if (strcmp(elf_name, kmap->ref_reloc_sym->name)) continue; kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; - map->reloc = kmap->ref_reloc_sym->addr - - kmap->ref_reloc_sym->unrelocated_addr; + map__set_reloc(map, kmap->ref_reloc_sym->addr - kmap->ref_reloc_sym->unrelocated_addr); break; } } @@ -1536,7 +1536,7 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, * attempted to prelink vdso to its virtual address. */ if (dso__is_vdso(dso)) - map->reloc = map__start(map) - dso->text_offset; + map__set_reloc(map, map__start(map) - dso->text_offset); dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap); /* diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 01fa5560a0bb..35d860f95b18 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -279,7 +279,7 @@ void maps__fixup_end(struct maps *maps) maps__for_each_entry(maps, curr) { if (prev != NULL && !map__end(prev->map)) - prev->map->end = map__start(curr->map); + map__set_end(prev->map, map__start(curr->map)); prev = curr; } @@ -289,7 +289,7 @@ void maps__fixup_end(struct maps *maps) * last map final address. */ if (curr && !map__end(curr->map)) - curr->map->end = ~0ULL; + map__set_end(curr->map, ~0ULL); up_write(maps__lock(maps)); } @@ -944,7 +944,8 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, return -1; } - curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; + map__set_map_ip(curr_map, identity__map_ip); + map__set_unmap_ip(curr_map, identity__map_ip); if (maps__insert(kmaps, curr_map)) { dso__put(ndso); return -1; @@ -1250,8 +1251,8 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) return -ENOMEM; } - list_node->map->end = map__start(list_node->map) + len; - list_node->map->pgoff = pgoff; + map__set_end(list_node->map, map__start(list_node->map) + len); + map__set_pgoff(list_node->map, pgoff); list_add(&list_node->node, &md->maps); @@ -1286,7 +1287,7 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) * |new......| -> |new..| * |old....| -> |old....| */ - new_map->end = map__start(old_map); + map__set_end(new_map, map__start(old_map)); } else { /* * |new.............| -> |new..| |new..| @@ -1306,10 +1307,10 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) goto out; } - m->map->end = map__start(old_map); + map__set_end(m->map, map__start(old_map)); list_add_tail(&m->node, &merged); - new_map->pgoff += map__end(old_map) - map__start(new_map); - new_map->start = map__end(old_map); + map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); + map__set_start(new_map, map__end(old_map)); } } else { /* @@ -1329,8 +1330,8 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) * |new......| -> |new...| * |old....| -> |old....| */ - new_map->pgoff += map__end(old_map) - map__start(new_map); - new_map->start = map__end(old_map); + map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); + map__set_start(new_map, map__end(old_map)); } } } @@ -1457,11 +1458,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map, list_del_init(&new_node->node); if (new_map == replacement_map) { - map->start = map__start(new_map); - map->end = map__end(new_map); - map->pgoff = map__pgoff(new_map); - map->map_ip = new_map->map_ip; - map->unmap_ip = new_map->unmap_ip; + map__set_start(map, map__start(new_map)); + map__set_end(map, map__end(new_map)); + map__set_pgoff(map, map__pgoff(new_map)); + map__set_map_ip(map, map__map_ip_ptr(new_map)); + map__set_unmap_ip(map, map__unmap_ip_ptr(new_map)); /* Ensure maps are correctly ordered */ map__get(map); maps__remove(kmaps, map); -- cgit v1.2.3 From 2832ef81d4c75d4f0e3945bd2cb0b7012313cbb3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 19 Apr 2023 12:57:53 -0300 Subject: perf map: Add reference count checking There's no strict get/put policy with map that leads to leaks or use after free. Reference count checking identifies correct pairing of gets and puts. Committer notes: Extracted from a larger patch removing bits that were covered by the use of pre-existing map__ accessors (e.g. maps__nr_maps()) and new ones added (map__refcnt() and the maps__set_ ones) to reduce RC_CHK_ACCESS(maps)-> source code pollution. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexey Bayduraev Cc: Dmitriy Vyukov Cc: Jiri Olsa Cc: Namhyung Kim Cc: Riccardo Mancini Cc: Stephane Eranian Cc: Stephen Brennan Link: https://lore.kernel.org/lkml/20230407230405.2931830-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/hists_link.c | 2 +- tools/perf/util/machine.c | 2 +- tools/perf/util/map.c | 43 ++++++++++++++++++-------------- tools/perf/util/map.h | 58 +++++++++++++++++++++++-------------------- tools/perf/util/maps.c | 4 +-- tools/perf/util/symbol.c | 4 +-- 6 files changed, 62 insertions(+), 51 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 64ce8097889c..141e2972e34f 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -145,7 +145,7 @@ static int find_sample(struct sample *samples, size_t nr_samples, { while (nr_samples--) { if (samples->thread == t && - samples->map == m && + RC_CHK_ACCESS(samples->map) == RC_CHK_ACCESS(m) && samples->sym == s) return 1; samples++; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 8ccbe48e23bd..9e02e19c1b7a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -953,7 +953,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, if (!map) return 0; - if (map != machine->vmlinux_map) + if (RC_CHK_ACCESS(map) != RC_CHK_ACCESS(machine->vmlinux_map)) maps__remove(machine__kernel_maps(machine), map); else { struct dso *dso = map__dso(map); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index bdd2742fa35b..b7f890950909 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -120,11 +120,13 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, u32 prot, u32 flags, struct build_id *bid, char *filename, struct thread *thread) { - struct map *map = malloc(sizeof(*map)); + struct map *result; + RC_STRUCT(map) *map; struct nsinfo *nsi = NULL; struct nsinfo *nnsi; - if (map != NULL) { + map = malloc(sizeof(*map)); + if (ADD_RC_CHK(result, map)) { char newfilename[PATH_MAX]; struct dso *dso, *header_bid_dso; int anon, no_dso, vdso, android; @@ -167,7 +169,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, if (dso == NULL) goto out_delete; - map__init(map, start, start + len, pgoff, dso); + map__init(result, start, start + len, pgoff, dso); if (anon || no_dso) { map->map_ip = map->unmap_ip = identity__map_ip; @@ -204,10 +206,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, } dso__put(dso); } - return map; + return result; out_delete: nsinfo__put(nsi); - free(map); + RC_CHK_FREE(result); return NULL; } @@ -218,16 +220,18 @@ out_delete: */ struct map *map__new2(u64 start, struct dso *dso) { - struct map *map = calloc(1, (sizeof(*map) + - (dso->kernel ? sizeof(struct kmap) : 0))); - if (map != NULL) { + struct map *result; + RC_STRUCT(map) *map; + + map = calloc(1, sizeof(*map) + (dso->kernel ? sizeof(struct kmap) : 0)); + if (ADD_RC_CHK(result, map)) { /* * ->end will be filled after we load all the symbols */ - map__init(map, start, 0, 0, dso); + map__init(result, start, 0, 0, dso); } - return map; + return result; } bool __map__is_kernel(const struct map *map) @@ -293,19 +297,21 @@ bool map__has_symbols(const struct map *map) static void map__exit(struct map *map) { BUG_ON(refcount_read(map__refcnt(map)) != 0); - dso__zput(map->dso); + dso__zput(RC_CHK_ACCESS(map)->dso); } void map__delete(struct map *map) { map__exit(map); - free(map); + RC_CHK_FREE(map); } void map__put(struct map *map) { if (map && refcount_dec_and_test(map__refcnt(map))) map__delete(map); + else + RC_CHK_PUT(map); } void map__fixup_start(struct map *map) @@ -400,20 +406,21 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name) struct map *map__clone(struct map *from) { - size_t size = sizeof(struct map); - struct map *map; + struct map *result; + RC_STRUCT(map) *map; + size_t size = sizeof(RC_STRUCT(map)); struct dso *dso = map__dso(from); if (dso && dso->kernel) size += sizeof(struct kmap); - map = memdup(from, size); - if (map != NULL) { + map = memdup(RC_CHK_ACCESS(from), size); + if (ADD_RC_CHK(result, map)) { refcount_set(&map->refcnt, 1); map->dso = dso__get(dso); } - return map; + return result; } size_t map__fprintf(struct map *map, FILE *fp) @@ -567,7 +574,7 @@ struct kmap *__map__kmap(struct map *map) if (!dso || !dso->kernel) return NULL; - return (struct kmap *)(map + 1); + return (struct kmap *)(&RC_CHK_ACCESS(map)[1]); } struct kmap *map__kmap(struct map *map) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 0760c671314d..823ab7fc0acf 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -10,12 +10,13 @@ #include #include #include +#include struct dso; struct maps; struct machine; -struct map { +DECLARE_RC_STRUCT(map) { u64 start; u64 end; bool erange_warned:1; @@ -49,72 +50,72 @@ u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip); static inline struct dso *map__dso(const struct map *map) { - return map->dso; + return RC_CHK_ACCESS(map)->dso; } static inline u64 map__map_ip(const struct map *map, u64 ip) { - return map->map_ip(map, ip); + return RC_CHK_ACCESS(map)->map_ip(map, ip); } static inline u64 map__unmap_ip(const struct map *map, u64 ip) { - return map->unmap_ip(map, ip); + return RC_CHK_ACCESS(map)->unmap_ip(map, ip); } static inline void *map__map_ip_ptr(struct map *map) { - return map->map_ip; + return RC_CHK_ACCESS(map)->map_ip; } static inline void* map__unmap_ip_ptr(struct map *map) { - return map->unmap_ip; + return RC_CHK_ACCESS(map)->unmap_ip; } static inline u64 map__start(const struct map *map) { - return map->start; + return RC_CHK_ACCESS(map)->start; } static inline u64 map__end(const struct map *map) { - return map->end; + return RC_CHK_ACCESS(map)->end; } static inline u64 map__pgoff(const struct map *map) { - return map->pgoff; + return RC_CHK_ACCESS(map)->pgoff; } static inline u64 map__reloc(const struct map *map) { - return map->reloc; + return RC_CHK_ACCESS(map)->reloc; } static inline u32 map__flags(const struct map *map) { - return map->flags; + return RC_CHK_ACCESS(map)->flags; } static inline u32 map__prot(const struct map *map) { - return map->prot; + return RC_CHK_ACCESS(map)->prot; } static inline bool map__priv(const struct map *map) { - return map->priv; + return RC_CHK_ACCESS(map)->priv; } static inline refcount_t *map__refcnt(struct map *map) { - return &map->refcnt; + return &RC_CHK_ACCESS(map)->refcnt; } static inline bool map__erange_warned(struct map *map) { - return map->erange_warned; + return RC_CHK_ACCESS(map)->erange_warned; } static inline size_t map__size(const struct map *map) @@ -173,9 +174,12 @@ struct map *map__clone(struct map *map); static inline struct map *map__get(struct map *map) { - if (map) + struct map *result; + + if (RC_CHK_GET(result, map)) refcount_inc(map__refcnt(map)); - return map; + + return result; } void map__put(struct map *map); @@ -249,51 +253,51 @@ static inline int is_no_dso_memory(const char *filename) static inline void map__set_start(struct map *map, u64 start) { - map->start = start; + RC_CHK_ACCESS(map)->start = start; } static inline void map__set_end(struct map *map, u64 end) { - map->end = end; + RC_CHK_ACCESS(map)->end = end; } static inline void map__set_pgoff(struct map *map, u64 pgoff) { - map->pgoff = pgoff; + RC_CHK_ACCESS(map)->pgoff = pgoff; } static inline void map__add_pgoff(struct map *map, u64 inc) { - map->pgoff += inc; + RC_CHK_ACCESS(map)->pgoff += inc; } static inline void map__set_reloc(struct map *map, u64 reloc) { - map->reloc = reloc; + RC_CHK_ACCESS(map)->reloc = reloc; } static inline void map__set_priv(struct map *map, int priv) { - map->priv = priv; + RC_CHK_ACCESS(map)->priv = priv; } static inline void map__set_erange_warned(struct map *map, bool erange_warned) { - map->erange_warned = erange_warned; + RC_CHK_ACCESS(map)->erange_warned = erange_warned; } static inline void map__set_dso(struct map *map, struct dso *dso) { - map->dso = dso; + RC_CHK_ACCESS(map)->dso = dso; } static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip)) { - map->map_ip = map_ip; + RC_CHK_ACCESS(map)->map_ip = map_ip; } static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip)) { - map->unmap_ip = unmap_ip; + RC_CHK_ACCESS(map)->unmap_ip = unmap_ip; } #endif /* __PERF_MAP_H */ diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index df2fc8221f3c..1aeb1db58fe5 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -126,7 +126,7 @@ void maps__remove(struct maps *maps, struct map *map) RC_CHK_ACCESS(maps)->last_search_by_name = NULL; rb_node = maps__find_node(maps, map); - assert(rb_node->map == map); + assert(rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)); __maps__remove(maps, rb_node); if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); @@ -420,7 +420,7 @@ struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) struct map_rb_node *rb_node; maps__for_each_entry(maps, rb_node) { - if (rb_node->map == map) + if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)) return rb_node; } return NULL; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 35d860f95b18..6b9c55784b56 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -865,7 +865,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, *module++ = '\0'; curr_map_dso = map__dso(curr_map); if (strcmp(curr_map_dso->short_name, module)) { - if (curr_map != initial_map && + if (RC_CHK_ACCESS(curr_map) != RC_CHK_ACCESS(initial_map) && dso->kernel == DSO_SPACE__KERNEL_GUEST && machine__is_default_guest(machine)) { /* @@ -1457,7 +1457,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, list_del_init(&new_node->node); - if (new_map == replacement_map) { + if (RC_CHK_ACCESS(new_map) == RC_CHK_ACCESS(replacement_map)) { map__set_start(map, map__start(new_map)); map__set_end(map, map__end(new_map)); map__set_pgoff(map, map__pgoff(new_map)); -- cgit v1.2.3 From 686c511866b4634734be9d6e827e4e55b877d35e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Apr 2023 13:47:03 -0300 Subject: perf build: Test the refcnt check build Make sure we test build the currently added REFCNT_CHECKING infrastructure. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/make | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 96896d498641..d75876126631 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -95,6 +95,7 @@ make_no_syscall_tbl := NO_SYSCALL_TABLE=1 make_with_clangllvm := LIBCLANGLLVM=1 make_no_libpfm4 := NO_LIBPFM4=1 make_with_gtk2 := GTK2=1 +make_refcnt_check := EXTRA_CFLAGS="-DREFCNT_CHECKING=1" make_tags := tags make_cscope := cscope make_help := help @@ -159,6 +160,7 @@ run += make_with_babeltrace run += make_with_coresight run += make_with_clangllvm run += make_no_libpfm4 +run += make_refcnt_check run += make_help run += make_doc run += make_perf_o -- cgit v1.2.3 From edd4cab2d492daa5e45bd45e44084a2b9880f224 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 19 Apr 2023 20:04:30 -0700 Subject: perf test: Fix maps use after put Fix a use after put reference count issue. maps is copied from leader, but the leader is put on line 79 and then maps is used to read the reference count below - so a use after put, with the put of maps happening within thread__put. Fix by reversing the order of puts so that the leader is put last. To explain the reference count checker, I wrote this up as a little example here: https://perf.wiki.kernel.org/index.php/Reference_Count_Checking Note, the bug was introduced by the committer and wasn't present in the original reference count patch set. Committer notes: Yes, the bug predated your patch and is detected by the reference count checking you contributed. This was just part of splitting up your series into smaller chunks, in this case either we fix the problem detected while developing this reference counting infrastructure before the patch introducing REFCNT_CHECKING or fix it later after the merged infrastructure, when built with EXTRA_CFLAGS="-DREFCNT_CHECKING=1" detects it when running 'perf test', which is what this patch does. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20230420030430.489243-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/thread-maps-share.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c index 75ce8aedfc78..858e725318a9 100644 --- a/tools/perf/tests/thread-maps-share.c +++ b/tools/perf/tests/thread-maps-share.c @@ -76,16 +76,16 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(other_maps) == RC_CHK_ACCESS(other_leader->maps)); /* release thread group */ - thread__put(leader); + thread__put(t3); TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 3); - thread__put(t1); + thread__put(t2); TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 2); - thread__put(t2); + thread__put(t1); TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 1); - thread__put(t3); + thread__put(leader); /* release other group */ thread__put(other_leader); -- cgit v1.2.3 From ce1d3bc2733224573600e5564203345caea814eb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 Apr 2023 15:54:11 -0300 Subject: perf evsel: Introduce evsel__name_is() method to check if the evsel name is equal to a given string This makes the logic a bit clear by avoiding the !strcmp() pattern and also a way to intercept the pointer if we need to do extra validation on it or to do lazy setting of evsel->name via evsel__name(evsel). Reviewed-by: "Liang, Kan" Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZEGLM8VehJbS0gP2@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/kvm-stat.c | 4 ++-- tools/perf/arch/powerpc/util/kvm-stat.c | 4 ++-- tools/perf/arch/x86/util/kvm-stat.c | 8 ++++---- tools/perf/builtin-kvm.c | 6 +++--- tools/perf/builtin-stat.c | 2 +- tools/perf/tests/expand-cgroup.c | 2 +- tools/perf/tests/parse-events.c | 12 ++++++------ tools/perf/tests/parse-metric.c | 2 +- tools/perf/tests/pmu-events.c | 2 +- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 7 ++++++- tools/perf/util/evsel.h | 1 + tools/perf/util/sort.c | 2 +- 13 files changed, 31 insertions(+), 25 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/arch/arm64/util/kvm-stat.c b/tools/perf/arch/arm64/util/kvm-stat.c index 72ca9bb45804..6611aa21cba9 100644 --- a/tools/perf/arch/arm64/util/kvm-stat.c +++ b/tools/perf/arch/arm64/util/kvm-stat.c @@ -44,14 +44,14 @@ static bool event_begin(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { - return !strcmp(evsel->name, kvm_entry_trace); + return evsel__name_is(evsel, kvm_entry_trace); } static bool event_end(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { - if (!strcmp(evsel->name, kvm_exit_trace)) { + if (evsel__name_is(evsel, kvm_exit_trace)) { event_get_key(evsel, sample, key); return true; } diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c index d04a08c9fd19..ea1220d66b67 100644 --- a/tools/perf/arch/powerpc/util/kvm-stat.c +++ b/tools/perf/arch/powerpc/util/kvm-stat.c @@ -60,13 +60,13 @@ static bool hcall_event_end(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { - return (!strcmp(evsel->name, kvm_events_tp[3])); + return (evsel__name_is(evsel, kvm_events_tp[3])); } static bool hcall_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { - if (!strcmp(evsel->name, kvm_events_tp[2])) { + if (evsel__name_is(evsel, kvm_events_tp[2])) { hcall_event_get_key(evsel, sample, key); return true; } diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c index ef513def03ba..424716518b75 100644 --- a/tools/perf/arch/x86/util/kvm-stat.c +++ b/tools/perf/arch/x86/util/kvm-stat.c @@ -46,7 +46,7 @@ static bool mmio_event_begin(struct evsel *evsel, return true; /* MMIO write begin event in kernel. */ - if (!strcmp(evsel->name, "kvm:kvm_mmio") && + if (evsel__name_is(evsel, "kvm:kvm_mmio") && evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { mmio_event_get_key(evsel, sample, key); return true; @@ -63,7 +63,7 @@ static bool mmio_event_end(struct evsel *evsel, struct perf_sample *sample, return true; /* MMIO read end event in kernel.*/ - if (!strcmp(evsel->name, "kvm:kvm_mmio") && + if (evsel__name_is(evsel, "kvm:kvm_mmio") && evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { mmio_event_get_key(evsel, sample, key); return true; @@ -101,7 +101,7 @@ static bool ioport_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { - if (!strcmp(evsel->name, "kvm:kvm_pio")) { + if (evsel__name_is(evsel, "kvm:kvm_pio")) { ioport_event_get_key(evsel, sample, key); return true; } @@ -145,7 +145,7 @@ static bool msr_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { - if (!strcmp(evsel->name, "kvm:kvm_msr")) { + if (evsel__name_is(evsel, "kvm:kvm_msr")) { msr_event_get_key(evsel, sample, key); return true; } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 747d19336340..71165036e4ca 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -625,7 +625,7 @@ void exit_event_get_key(struct evsel *evsel, bool kvm_exit_event(struct evsel *evsel) { - return !strcmp(evsel->name, kvm_exit_trace); + return evsel__name_is(evsel, kvm_exit_trace); } bool exit_event_begin(struct evsel *evsel, @@ -641,7 +641,7 @@ bool exit_event_begin(struct evsel *evsel, bool kvm_entry_event(struct evsel *evsel) { - return !strcmp(evsel->name, kvm_entry_trace); + return evsel__name_is(evsel, kvm_entry_trace); } bool exit_event_end(struct evsel *evsel, @@ -878,7 +878,7 @@ static bool is_child_event(struct perf_kvm_stat *kvm, return false; for (; child_ops->name; child_ops++) { - if (!strcmp(evsel->name, child_ops->name)) { + if (evsel__name_is(evsel, child_ops->name)) { child_ops->get_key(evsel, sample, key); return true; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index d3cbee7460fc..efda63f6bf32 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2170,7 +2170,7 @@ static void setup_system_wide(int forks) evlist__for_each_entry(evsel_list, counter) { if (!counter->core.requires_cpu && - strcmp(counter->name, "duration_time")) { + !evsel__name_is(counter, "duration_time")) { return; } } diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index ec340880a848..9c1a1f18db75 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -61,7 +61,7 @@ static int test_expand_events(struct evlist *evlist, i = 0; evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel->name, ev_name[i % nr_events])) { + if (!evsel__name_is(evsel, ev_name[i % nr_events])) { pr_debug("event name doesn't match:\n"); pr_debug(" evsel[%d]: %s\n expected: %s\n", i, evsel->name, ev_name[i % nr_events]); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 6eb1400443ad..8068cfd89b84 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1401,7 +1401,7 @@ static int test__checkevent_config_symbol(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "insn")); return TEST_OK; } @@ -1409,7 +1409,7 @@ static int test__checkevent_config_raw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "rawpmu")); return TEST_OK; } @@ -1417,7 +1417,7 @@ static int test__checkevent_config_num(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "numpmu")); return TEST_OK; } @@ -1425,7 +1425,7 @@ static int test__checkevent_config_cache(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "cachepmu")); return TEST_OK; } @@ -1438,7 +1438,7 @@ static int test__intel_pt(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "intel_pt//u") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "intel_pt//u")); return TEST_OK; } @@ -1446,7 +1446,7 @@ static int test__checkevent_complex_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong complex name parsing", strcmp(evsel->name, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks") == 0); + TEST_ASSERT_VAL("wrong complex name parsing", evsel__name_is(evsel, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks")); return TEST_OK; } diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index c43b056f9fa3..1185b79e6274 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -39,7 +39,7 @@ static void load_runtime_stat(struct evlist *evlist, struct value *vals) evlist__for_each_entry(evlist, evsel) { count = find_value(evsel->name, vals); evsel->stats->aggr->counts.val = count; - if (!strcmp(evsel->name, "duration_time")) + if (evsel__name_is(evsel, "duration_time")) update_stats(&walltime_nsecs_stats, count); } } diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 7f8e86452527..1dff863b9711 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -866,7 +866,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { evsel->stats->aggr->counts.val = k; - if (!strcmp(evsel->name, "duration_time")) + if (evsel__name_is(evsel, "duration_time")) update_stats(&walltime_nsecs_stats, k); k++; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 2260e27adf44..a0504316b06f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -467,7 +467,7 @@ static int evsel__strcmp(struct evsel *pos, char *evsel_name) return 0; if (evsel__is_dummy_event(pos)) return 1; - return strcmp(pos->name, evsel_name); + return !evsel__name_is(pos, evsel_name); } static int evlist__is_enabled(struct evlist *evlist) @@ -1706,7 +1706,7 @@ struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str) evlist__for_each_entry(evlist, evsel) { if (!evsel->name) continue; - if (strcmp(str, evsel->name) == 0) + if (evsel__name_is(evsel, str)) return evsel; } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a85a987128aa..356c07f03be6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -821,6 +821,11 @@ out_unknown: return "unknown"; } +bool evsel__name_is(struct evsel *evsel, const char *name) +{ + return !strcmp(evsel__name(evsel), name); +} + const char *evsel__group_pmu_name(const struct evsel *evsel) { const struct evsel *leader; @@ -1146,7 +1151,7 @@ static void evsel__set_default_freq_period(struct record_opts *opts, static bool evsel__is_offcpu_event(struct evsel *evsel) { - return evsel__is_bpf_output(evsel) && !strcmp(evsel->name, OFFCPU_EVENT); + return evsel__is_bpf_output(evsel) && evsel__name_is(evsel, OFFCPU_EVENT); } /* diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 68072ec655ce..1e5d640e4a9b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -282,6 +282,7 @@ int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size); int __evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size); const char *evsel__name(struct evsel *evsel); +bool evsel__name_is(struct evsel *evsel, const char *name); const char *evsel__group_pmu_name(const struct evsel *evsel); const char *evsel__metric_id(const struct evsel *evsel); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 31b1cd0935e2..650cd8df4041 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2893,7 +2893,7 @@ static struct evsel *find_evsel(struct evlist *evlist, char *event_name) full_name = !!strchr(event_name, ':'); evlist__for_each_entry(evlist, pos) { /* case 2 */ - if (full_name && !strcmp(pos->name, event_name)) + if (full_name && evsel__name_is(pos, event_name)) return pos; /* case 3 */ if (!full_name && strstr(pos->name, event_name)) { -- cgit v1.2.3 From d1efa4a0a696e487f349f837f53a0db88f8f0d74 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 24 Apr 2023 14:47:47 +0100 Subject: perf cs-etm: Add separate decode paths for timeless and per-thread modes Timeless and per-thread are orthogonal concepts that are currently treated as if they are the same (per-thread == timeless). This breaks when you modify the command line or itrace options to something that the current logic doesn't expect. For example: # Force timeless with Z --itrace=Zi10i # Or inconsistent record options -e cs_etm/timestamp=1/ --per-thread Adding Z for decoding in per-cpu mode is particularly bad because in per-thread mode trace channel IDs are discarded and all assumed to be 0, which would mix trace from different CPUs in per-cpu mode. Although the results might not be perfect in all scenarios, if the user requests no timestamps, it should still be possible to decode in either mode. Especially if the relative times of samples in different processes aren't interesting, quite a bit of space can be saved by turning off timestamps in per-cpu mode. Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Denis Nikitin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Cc: Will Deacon Cc: Yang Shi Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230424134748.228137-8-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_arm_coresight.sh | 24 ++++ tools/perf/util/cs-etm.c | 162 ++++++++++++++++++++------- 2 files changed, 148 insertions(+), 38 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh index 565ce525c40b..482009e17bda 100755 --- a/tools/perf/tests/shell/test_arm_coresight.sh +++ b/tools/perf/tests/shell/test_arm_coresight.sh @@ -150,6 +150,8 @@ arm_cs_etm_system_wide_test() { echo "Recording trace with system wide mode" perf record -o ${perfdata} -e cs_etm// -a -- ls > /dev/null 2>&1 + # System-wide mode should include perf samples so test for that + # instead of ls perf_script_branch_samples perf && perf_report_branch_samples perf && perf_report_instruction_samples perf @@ -182,7 +184,29 @@ arm_cs_etm_snapshot_test() { arm_cs_report "CoreSight snapshot testing" $err } +arm_cs_etm_basic_test() { + echo "Recording trace with '$*'" + perf record -o ${perfdata} "$@" -- ls > /dev/null 2>&1 + + perf_script_branch_samples ls && + perf_report_branch_samples ls && + perf_report_instruction_samples ls + + err=$? + arm_cs_report "CoreSight basic testing with '$*'" $err +} + arm_cs_etm_traverse_path_test arm_cs_etm_system_wide_test arm_cs_etm_snapshot_test + +# Test all combinations of per-thread, system-wide and normal mode with +# and without timestamps +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ --per-thread +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ --per-thread +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ -a +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ -a +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ + exit $glb_err diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index e048949bf655..456994564d6e 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -50,7 +50,22 @@ struct cs_etm_auxtrace { struct thread *unknown_thread; struct perf_tsc_conversion tc; + /* + * Timeless has no timestamps in the trace so overlapping mmap lookups + * are less accurate but produces smaller trace data. We use context IDs + * in the trace instead of matching timestamps with fork records so + * they're not really needed in the general case. Overlapping mmaps + * happen in cases like between a fork and an exec. + */ bool timeless_decoding; + + /* + * Per-thread ignores the trace channel ID and instead assumes that + * everything in a buffer comes from the same process regardless of + * which CPU it ran on. It also implies no context IDs so the TID is + * taken from the auxtrace buffer. + */ + bool per_thread_decoding; bool snapshot_mode; bool data_queued; bool has_virtual_ts; /* Virtual/Kernel timestamps in the trace. */ @@ -98,7 +113,7 @@ struct cs_etm_queue { /* RB tree for quick conversion between traceID and metadata pointers */ static struct intlist *traceid_list; -static int cs_etm__process_queues(struct cs_etm_auxtrace *etm); +static int cs_etm__process_timestamped_queues(struct cs_etm_auxtrace *etm); static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, pid_t tid); static int cs_etm__get_data_block(struct cs_etm_queue *etmq); @@ -492,7 +507,7 @@ static struct cs_etm_traceid_queue struct cs_etm_traceid_queue *tidq, **traceid_queues; struct cs_etm_auxtrace *etm = etmq->etm; - if (etm->timeless_decoding) + if (etm->per_thread_decoding) trace_chan_id = CS_ETM_PER_THREAD_TRACEID; traceid_queues_list = etmq->traceid_queues_list; @@ -731,10 +746,15 @@ static int cs_etm__flush_events(struct perf_session *session, if (!tool->ordered_events) return -EINVAL; - if (etm->timeless_decoding) + if (etm->timeless_decoding) { + /* + * Pass tid = -1 to process all queues. But likely they will have + * already been processed on PERF_RECORD_EXIT anyway. + */ return cs_etm__process_timeless_queues(etm, -1); + } - return cs_etm__process_queues(etm); + return cs_etm__process_timestamped_queues(etm); } static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq) @@ -1066,7 +1086,7 @@ static int cs_etm__queue_first_cs_timestamp(struct cs_etm_auxtrace *etm, * chronological order. * * Note that packets decoded above are still in the traceID's packet - * queue and will be processed in cs_etm__process_queues(). + * queue and will be processed in cs_etm__process_timestamped_queues(). */ cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_chan_id); ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, cs_timestamp); @@ -1347,9 +1367,7 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq, struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_packet_queue *packet_queue = &tidq->packet_queue; - if (etm->timeless_decoding) - return 0; - else if (etm->has_virtual_ts) + if (!etm->timeless_decoding && etm->has_virtual_ts) return packet_queue->cs_timestamp; else return etm->latest_kernel_timestamp; @@ -2329,7 +2347,7 @@ static void cs_etm__clear_all_traceid_queues(struct cs_etm_queue *etmq) } } -static int cs_etm__run_decoder(struct cs_etm_queue *etmq) +static int cs_etm__run_per_thread_timeless_decoder(struct cs_etm_queue *etmq) { int err = 0; struct cs_etm_traceid_queue *tidq; @@ -2367,6 +2385,51 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq) return err; } +static int cs_etm__run_per_cpu_timeless_decoder(struct cs_etm_queue *etmq) +{ + int idx, err = 0; + struct cs_etm_traceid_queue *tidq; + struct int_node *inode; + + /* Go through each buffer in the queue and decode them one by one */ + while (1) { + err = cs_etm__get_data_block(etmq); + if (err <= 0) + return err; + + /* Run trace decoder until buffer consumed or end of trace */ + do { + err = cs_etm__decode_data_block(etmq); + if (err) + return err; + + /* + * cs_etm__run_per_thread_timeless_decoder() runs on a + * single traceID queue because each TID has a separate + * buffer. But here in per-cpu mode we need to iterate + * over each channel instead. + */ + intlist__for_each_entry(inode, + etmq->traceid_queues_list) { + idx = (int)(intptr_t)inode->priv; + tidq = etmq->traceid_queues[idx]; + cs_etm__process_traceid_queue(etmq, tidq); + } + } while (etmq->buf_len); + + intlist__for_each_entry(inode, etmq->traceid_queues_list) { + idx = (int)(intptr_t)inode->priv; + tidq = etmq->traceid_queues[idx]; + /* Flush any remaining branch stack entries */ + err = cs_etm__end_block(etmq, tidq); + if (err) + return err; + } + } + + return err; +} + static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, pid_t tid) { @@ -2381,22 +2444,30 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, if (!etmq) continue; - tidq = cs_etm__etmq_get_traceid_queue(etmq, - CS_ETM_PER_THREAD_TRACEID); + /* + * Per-cpu mode has contextIDs in the trace and the decoder + * calls cs_etm__set_pid_tid_cpu() automatically so no need + * to do this here + */ + if (etm->per_thread_decoding) { + tidq = cs_etm__etmq_get_traceid_queue( + etmq, CS_ETM_PER_THREAD_TRACEID); - if (!tidq) - continue; + if (!tidq) + continue; - if ((tid == -1) || (tidq->tid == tid)) { - cs_etm__set_pid_tid_cpu(etm, tidq); - cs_etm__run_decoder(etmq); - } + if ((tid == -1) || (tidq->tid == tid)) { + cs_etm__set_pid_tid_cpu(etm, tidq); + cs_etm__run_per_thread_timeless_decoder(etmq); + } + } else + cs_etm__run_per_cpu_timeless_decoder(etmq); } return 0; } -static int cs_etm__process_queues(struct cs_etm_auxtrace *etm) +static int cs_etm__process_timestamped_queues(struct cs_etm_auxtrace *etm) { int ret = 0; unsigned int cs_queue_nr, queue_nr, i; @@ -2573,7 +2644,6 @@ static int cs_etm__process_event(struct perf_session *session, struct perf_sample *sample, struct perf_tool *tool) { - u64 sample_kernel_timestamp; struct cs_etm_auxtrace *etm = container_of(session->auxtrace, struct cs_etm_auxtrace, auxtrace); @@ -2586,33 +2656,39 @@ static int cs_etm__process_event(struct perf_session *session, return -EINVAL; } - if (sample->time && (sample->time != (u64) -1)) - sample_kernel_timestamp = sample->time; - else - sample_kernel_timestamp = 0; - - /* - * Don't wait for cs_etm__flush_events() in per-thread/timeless mode to start the decode. We - * need the tid of the PERF_RECORD_EXIT event to assign to the synthesised samples because - * ETM_OPT_CTXTID is not enabled. - */ - if (etm->timeless_decoding && - event->header.type == PERF_RECORD_EXIT) - return cs_etm__process_timeless_queues(etm, - event->fork.tid); + switch (event->header.type) { + case PERF_RECORD_EXIT: + /* + * Don't need to wait for cs_etm__flush_events() in per-thread mode to + * start the decode because we know there will be no more trace from + * this thread. All this does is emit samples earlier than waiting for + * the flush in other modes, but with timestamps it makes sense to wait + * for flush so that events from different threads are interleaved + * properly. + */ + if (etm->per_thread_decoding && etm->timeless_decoding) + return cs_etm__process_timeless_queues(etm, + event->fork.tid); + break; - if (event->header.type == PERF_RECORD_ITRACE_START) + case PERF_RECORD_ITRACE_START: return cs_etm__process_itrace_start(etm, event); - else if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) + + case PERF_RECORD_SWITCH_CPU_WIDE: return cs_etm__process_switch_cpu_wide(etm, event); - if (!etm->timeless_decoding && event->header.type == PERF_RECORD_AUX) { + case PERF_RECORD_AUX: /* * Record the latest kernel timestamp available in the header * for samples so that synthesised samples occur from this point * onwards. */ - etm->latest_kernel_timestamp = sample_kernel_timestamp; + if (sample->time && (sample->time != (u64)-1)) + etm->latest_kernel_timestamp = sample->time; + break; + + default: + break; } return 0; @@ -2821,10 +2897,20 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o * Return 'not found' if mismatch. */ if (auxtrace_event->cpu == (__u32) -1) { + etm->per_thread_decoding = true; if (auxtrace_event->tid != sample->tid) return 1; - } else if (auxtrace_event->cpu != sample->cpu) + } else if (auxtrace_event->cpu != sample->cpu) { + if (etm->per_thread_decoding) { + /* + * Found a per-cpu buffer after a per-thread one was + * already found + */ + pr_err("CS ETM: Inconsistent per-thread/per-cpu mode.\n"); + return -EINVAL; + } return 1; + } if (aux_event->flags & PERF_AUX_FLAG_OVERWRITE) { /* -- cgit v1.2.3 From d199226143f0ef6919131120319766ece514314e Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 25 Apr 2023 11:44:13 +0100 Subject: perf build: Fix unescaped # in perf build-test With the following bash and make versions: $ make --version GNU Make 4.2.1 Built for aarch64-unknown-linux-gnu $ bash --version GNU bash, version 5.0.17(1)-release (aarch64-unknown-linux-gnu) This error is encountered when running the build-test target: $ make -C tools/perf build-test tests/make:181: *** unterminated call to function 'shell': missing ')'. Stop. make: *** [Makefile:103: build-test] Error 2 Fix it by escaping the # which was causing make to interpret the rest of the line as a comment leaving the unclosed opening bracket. Fixes: 56d5229471ee1634 ("tools build: Pass libbpf feature only if libbpf 1.0+") Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230425104414.1723571-1-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/make b/tools/perf/tests/make index d75876126631..8dd3f8090352 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -178,7 +178,7 @@ run += make_install_prefix_slash # run += make_install_pdf run += make_minimal -old_libbpf := $(shell echo "#include " | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") +old_libbpf := $(shell echo '\#include ' | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") ifneq ($(old_libbpf),) run += make_libbpf_dynamic -- cgit v1.2.3 From 311693ce81c9da3724d4294a4c3769a3b30b6a7f Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 3 May 2023 10:11:34 +0200 Subject: perf test record+probe_libc_inet_pton: Fix call chain match on s390 With Fedora 38 the perf test 86 probe libc's inet_pton fails on s390. The call chain of the ping command changed. The functions text_to_binary_address() and gaih_inet() do not show up in the call chain anymore. Output before: # ./perf test -v 86 86: probe libc's inet_pton & backtrace it with ping : --- start --- test child forked, pid 541050 fgrep: warning: fgrep is obsolescent; using grep -F fgrep: warning: fgrep is obsolescent; using grep -F BFD: DWARF error: could not find variable specification at offset 0x22011 ... ping 541078 [002] 348826.679581: probe_libc:inet_pton_1: (3ffad84b940) 14b940 __GI___inet_pton+0x0 (/usr/lib64/libc.so.6) 10e9c3 __GI_getaddrinfo+0xeb3 (inlined) 4397 main+0x737 (/usr/bin/ping) FAIL: expected backtrace entry "gaih_inet.*\+0x[[:xdigit:]]\ +[[:space:]]\(/usr/lib64/libc.so.6|inlined\)$" got "4397 main+0x737 (/usr/bin/ping)" test child finished with -1 ---- end ---- probe libc's inet_pton & backtrace it with ping: FAILED! # Output after: # ./perf test -v 86 86: probe libc's inet_pton & backtrace it with ping : --- start --- test child forked, pid 541098 fgrep: warning: fgrep is obsolescent; using grep -F fgrep: warning: fgrep is obsolescent; using grep -F BFD: DWARF error: could not find variable specification at offset 0x309d1 ... ping 541126 [006] 349309.099067: probe_libc:inet_pton_1: (3ffb7f4b940) 14b940 __GI___inet_pton+0x0 (/usr/lib64/libc.so.6) 10e9c3 __GI_getaddrinfo+0xeb3 (inlined) 4397 main+0x737 (/usr/bin/ping) test child finished with 0 ---- end ---- probe libc's inet_pton & backtrace it with ping: Ok # Signed-off-by: Thomas Richter Cc: Heiko Carstens Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Vasily Gorbik Link: https://lore.kernel.org/r/20230503081134.3372415-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record+probe_libc_inet_pton.sh | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index b4149b2db4c6..4c739056cb65 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -38,8 +38,6 @@ trace_libc_inet_pton_backtrace() { case "$(uname -m)" in s390x) eventattr='call-graph=dwarf,max-stack=4' - echo "text_to_binary_address.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected - echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; -- cgit v1.2.3 From 1f85d016768ff19f060f3cce014a43c761de8259 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 3 May 2023 10:12:55 +0200 Subject: perf test record+probe_libc_inet_pton: Fix call chain match on x86_64 The test case probe libc's inet_pton & backtrace it with ping fails with Fedora 38 on x86_64. Function getaddrinfo() does not show up in the call chain anymore: # ./perf script ping 1803 [000] 728.567146: probe_libc:inet_pton: (7f5275afc840) 133840 __GI___inet_pton+0x0 (/usr/lib64/libc.so.6) 27b4a __libc_start_call_main+0x7a (/usr/lib64/libc.so.6) 27c0b __libc_start_main@@GLIBC_2.34+0x8b (/usr/lib64/libc.so.6) ping 1803 [000] 728.567184: probe_libc:inet_pton: (7f5275afc840) 133840 __GI___inet_pton+0x0 (/usr/lib64/libc.so.6) 493e main+0xcde (/usr/bin/ping) 27b4a __libc_start_call_main+0x7a (/usr/lib64/libc.so.6) # which causes the test case to fail. Remove function getaddrinfo() from list of expected functions. Output before: # ./perf test 'libc' 91: probe libc's inet_pton & backtrace it with ping : FAILED! # Output after: # ./perf test 'libc' 91: probe libc's inet_pton & backtrace it with ping : Ok # Signed-off-by: Thomas Richter Tested-by: Arnaldo Carvalho de Melo Cc: Heiko Carstens Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Vasily Gorbik Link: https://lore.kernel.org/r/20230503081255.3372986-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record+probe_libc_inet_pton.sh | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index 4c739056cb65..bbb5b3d185fa 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -49,7 +49,6 @@ trace_libc_inet_pton_backtrace() { ;; *) eventattr='max-stack=3' - echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; esac -- cgit v1.2.3 From 9a2d5178b9d51e1c5f9e08989ff97fc8d4893f31 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 6 May 2023 18:07:37 -0300 Subject: Revert "perf build: Make BUILD_BPF_SKEL default, rename to NO_BPF_SKEL" This reverts commit a980755beb5aca9002e1c95ba519b83a44242b5b. We need to better polish building with BPF skels, so revert back to making it an experimental feature that has to be explicitely enabled using BUILD_BPF_SKEL=1. Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 19 +++++++------------ tools/perf/Makefile.perf | 8 ++++---- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-version.c | 1 - tools/perf/tests/shell/record_offcpu.sh | 2 +- 6 files changed, 14 insertions(+), 20 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 16bea51f0bcd..ee467af49b62 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -415,7 +415,6 @@ ifdef NO_LIBELF NO_LIBUNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1 NO_LIBBPF := 1 - NO_BPF_SKEL := 1 NO_JVMTI := 1 else ifeq ($(feature-libelf), 0) @@ -655,22 +654,18 @@ ifndef NO_LIBBPF msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.) NO_LIBBPF := 1 endif -else - NO_BPF_SKEL := 1 endif -ifndef NO_BPF_SKEL +ifdef BUILD_BPF_SKEL $(call feature_check,clang-bpf-co-re) ifeq ($(feature-clang-bpf-co-re), 0) - dummy := $(error: ERROR: BPF skeletons unsupported. clang too old/not installed or build with NO_BPF_SKEL=1.) - else - ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) - dummy := $(error: ERROR: BPF skeletons unsupported. BPF skeleton support requires libbpf or build with NO_BPF_SKEL=1.) - else - $(call detected,CONFIG_PERF_BPF_SKEL) - CFLAGS += -DHAVE_BPF_SKEL - endif + dummy := $(error Error: clang too old/not installed. Please install recent clang to build with BUILD_BPF_SKEL) + endif + ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) + dummy := $(error Error: BPF skeleton support requires libbpf) endif + $(call detected,CONFIG_PERF_BPF_SKEL) + CFLAGS += -DHAVE_BPF_SKEL endif dwarf-post-unwind := 1 diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 61c33d100b2b..a42a6a99c2bc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -124,7 +124,7 @@ include ../scripts/utilities.mak # # Define NO_LIBDEBUGINFOD if you do not want support debuginfod # -# Define NO_BPF_SKEL to disable BPF skeletons +# Define BUILD_BPF_SKEL to enable BPF skeletons # # Define BUILD_NONDISTRO to enable building an linking against libbfd and # libiberty distribution license incompatible libraries. @@ -1055,7 +1055,7 @@ SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): $(Q)$(MKDIR) -p $@ -ifndef NO_BPF_SKEL +ifdef BUILD_BPF_SKEL BPFTOOL := $(SKEL_TMP_OUT)/bootstrap/bpftool BPF_INCLUDE := -I$(SKEL_TMP_OUT)/.. -I$(LIBBPF_INCLUDE) @@ -1074,11 +1074,11 @@ bpf-skel: $(SKELETONS) .PRECIOUS: $(SKEL_TMP_OUT)/%.bpf.o -else # NO_BPF_SKEL +else # BUILD_BPF_SKEL bpf-skel: -endif # NO_BPF_SKEL +endif # BUILD_BPF_SKEL bpf-skel-clean: $(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index ecb1fac8ba3c..70b14ba5fdd5 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2387,7 +2387,7 @@ int cmd_lock(int argc, const char **argv) #ifndef HAVE_BPF_SKEL set_option_nobuild(contention_options, 'b', "use-bpf", - "NO_BPF_SKEL=1", false); + "no BUILD_BPF_SKEL=1", false); #endif if (argc) { argc = parse_options(argc, argv, contention_options, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7b7e74a56346..efa03e4ac2c9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -3981,7 +3981,7 @@ int cmd_record(int argc, const char **argv) #ifndef HAVE_BPF_SKEL # define set_nobuild(s, l, m, c) set_option_nobuild(record_options, s, l, m, c) - set_nobuild('\0', "off-cpu", "NO_BPF_SKEL=1", true); + set_nobuild('\0', "off-cpu", "no BUILD_BPF_SKEL=1", true); # undef set_nobuild #endif diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index 1872c90a6667..e5859c70e195 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c @@ -81,7 +81,6 @@ static void library_status(void) STATUS(HAVE_ZSTD_SUPPORT, zstd); STATUS(HAVE_LIBPFM, libpfm4); STATUS(HAVE_LIBTRACEEVENT, libtraceevent); - STATUS(HAVE_BPF_SKEL, BPF skeletons); } int cmd_version(int argc, const char **argv) diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 155d4856551a..f062ae9a95e1 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -28,7 +28,7 @@ test_offcpu_priv() { err=2 return fi - if perf version --build-options 2>&1 | grep HAVE_BPF_SKEL | grep -q OFF + if perf record --off-cpu -o /dev/null --quiet true 2>&1 | grep BUILD_BPF_SKEL then echo "off-cpu test [Skipped missing BPF support]" err=2 -- cgit v1.2.3