From a6c925fd3aa2aba043a73b0ad57ffd296e1c42c9 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:16 +0800 Subject: perf test: Add pmu-events test The initial test will verify that the test tables in generated pmu-events.c match against known, expected values. For known events added in pmu-events/arch/test, we need to add an entry in test_cpu_aliases_events[] or test_uncore_events[]. A sample run is as follows for x86: john@linux-3c19:~/linux> tools/perf/perf test -vv 10 10: PMU event aliases : --- start --- test child forked, pid 5316 testing event table bp_l1_btb_correct: pass testing event table bp_l2_btb_correct: pass testing event table segment_reg_loads.any: pass testing event table dispatch_blocked.any: pass testing event table eist_trans: pass testing event table uncore_hisi_ddrc.flux_wcmd: pass testing event table unc_cbo_xsnp_response.miss_eviction: pass test child finished with 0 ---- end ---- PMU event aliases: Ok Signed-off-by: John Garry Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com [ Fixup test_cpu_events[] and test_uncore_events[] sentinels to initialize one of its members to NULL, fixing the build in older compilers ] Link: http://lore.kernel.org/lkml/1584442939-8911-5-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/pmu-events.c | 233 ++++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 4 files changed, 239 insertions(+) create mode 100644 tools/perf/tests/pmu-events.c (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 1692529639b0..b3d1bf13ca07 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -14,6 +14,7 @@ perf-y += evsel-roundtrip-name.o perf-y += evsel-tp-sched.o perf-y += fdarray.o perf-y += pmu.o +perf-y += pmu-events.o perf-y += hists_common.o perf-y += hists_link.o perf-y += hists_filter.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 54d9516c9839..b6322eb0f423 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -72,6 +72,10 @@ static struct test generic_tests[] = { .desc = "Parse perf pmu format", .func = test__pmu, }, + { + .desc = "PMU events", + .func = test__pmu_events, + }, { .desc = "DSO data read", .func = test__dso_data, diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c new file mode 100644 index 000000000000..12fc29746a09 --- /dev/null +++ b/tools/perf/tests/pmu-events.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "parse-events.h" +#include "pmu.h" +#include "tests.h" +#include +#include +#include + +#include "debug.h" +#include "../pmu-events/pmu-events.h" + +struct perf_pmu_test_event { + struct pmu_event event; +}; +static struct perf_pmu_test_event test_cpu_events[] = { + { + .event = { + .name = "bp_l1_btb_correct", + .event = "event=0x8a", + .desc = "L1 BTB Correction", + .topic = "branch", + }, + }, + { + .event = { + .name = "bp_l2_btb_correct", + .event = "event=0x8b", + .desc = "L2 BTB Correction", + .topic = "branch", + }, + }, + { + .event = { + .name = "segment_reg_loads.any", + .event = "umask=0x80,period=200000,event=0x6", + .desc = "Number of segment register loads", + .topic = "other", + }, + }, + { + .event = { + .name = "dispatch_blocked.any", + .event = "umask=0x20,period=200000,event=0x9", + .desc = "Memory cluster signals to block micro-op dispatch for any reason", + .topic = "other", + }, + }, + { + .event = { + .name = "eist_trans", + .event = "umask=0x0,period=200000,event=0x3a", + .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", + .topic = "other", + }, + }, + { /* sentinel */ + .event = { + .name = NULL, + }, + }, +}; + +static struct perf_pmu_test_event test_uncore_events[] = { + { + .event = { + .name = "uncore_hisi_ddrc.flux_wcmd", + .event = "event=0x2", + .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", + .topic = "uncore", + .long_desc = "DDRC write commands", + .pmu = "hisi_sccl,ddrc", + }, + }, + { + .event = { + .name = "unc_cbo_xsnp_response.miss_eviction", + .event = "umask=0x81,event=0x22", + .desc = "Unit: uncore_cbox A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .topic = "uncore", + .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .pmu = "uncore_cbox", + }, + }, + { /* sentinel */ + .event = { + .name = NULL, + }, + } +}; + +const int total_test_events_size = ARRAY_SIZE(test_uncore_events); + +static bool is_same(const char *reference, const char *test) +{ + if (!reference && !test) + return true; + + if (reference && !test) + return false; + + if (!reference && test) + return false; + + return !strcmp(reference, test); +} + +static struct pmu_events_map *__test_pmu_get_events_map(void) +{ + struct pmu_events_map *map; + + for (map = &pmu_events_map[0]; map->cpuid; map++) { + if (!strcmp(map->cpuid, "testcpu")) + return map; + } + + pr_err("could not find test events map\n"); + + return NULL; +} + +/* Verify generated events from pmu-events.c is as expected */ +static int __test_pmu_event_table(void) +{ + struct pmu_events_map *map = __test_pmu_get_events_map(); + struct pmu_event *table; + int map_events = 0, expected_events; + + /* ignore 2x sentinels */ + expected_events = ARRAY_SIZE(test_cpu_events) + + ARRAY_SIZE(test_uncore_events) - 2; + + if (!map) + return -1; + + for (table = map->table; table->name; table++) { + struct perf_pmu_test_event *test; + struct pmu_event *te; + bool found = false; + + if (table->pmu) + test = &test_uncore_events[0]; + else + test = &test_cpu_events[0]; + + te = &test->event; + + for (; te->name; test++, te = &test->event) { + if (strcmp(table->name, te->name)) + continue; + found = true; + map_events++; + + if (!is_same(table->desc, te->desc)) { + pr_debug2("testing event table %s: mismatched desc, %s vs %s\n", + table->name, table->desc, te->desc); + return -1; + } + + if (!is_same(table->topic, te->topic)) { + pr_debug2("testing event table %s: mismatched topic, %s vs %s\n", + table->name, table->topic, + te->topic); + return -1; + } + + if (!is_same(table->long_desc, te->long_desc)) { + pr_debug2("testing event table %s: mismatched long_desc, %s vs %s\n", + table->name, table->long_desc, + te->long_desc); + return -1; + } + + if (!is_same(table->unit, te->unit)) { + pr_debug2("testing event table %s: mismatched unit, %s vs %s\n", + table->name, table->unit, + te->unit); + return -1; + } + + if (!is_same(table->perpkg, te->perpkg)) { + pr_debug2("testing event table %s: mismatched perpkg, %s vs %s\n", + table->name, table->perpkg, + te->perpkg); + return -1; + } + + if (!is_same(table->metric_expr, te->metric_expr)) { + pr_debug2("testing event table %s: mismatched metric_expr, %s vs %s\n", + table->name, table->metric_expr, + te->metric_expr); + return -1; + } + + if (!is_same(table->metric_name, te->metric_name)) { + pr_debug2("testing event table %s: mismatched metric_name, %s vs %s\n", + table->name, table->metric_name, + te->metric_name); + return -1; + } + + if (!is_same(table->deprecated, te->deprecated)) { + pr_debug2("testing event table %s: mismatched deprecated, %s vs %s\n", + table->name, table->deprecated, + te->deprecated); + return -1; + } + + pr_debug("testing event table %s: pass\n", table->name); + } + + if (!found) { + pr_err("testing event table: could not find event %s\n", + table->name); + return -1; + } + } + + if (map_events != expected_events) { + pr_err("testing event table: found %d, but expected %d\n", + map_events, expected_events); + return -1; + } + + return 0; +} +int test__pmu_events(struct test *test __maybe_unused, + int subtest __maybe_unused) +{ + if (__test_pmu_event_table()) + return -1; + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 9a160fef47c9..61a1ab032080 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -49,6 +49,7 @@ int test__perf_evsel__roundtrip_name_test(struct test *test, int subtest); int test__perf_evsel__tp_sched_test(struct test *test, int subtest); int test__syscall_openat_tp_fields(struct test *test, int subtest); int test__pmu(struct test *test, int subtest); +int test__pmu_events(struct test *test, int subtest); int test__attr(struct test *test, int subtest); int test__dso_data(struct test *test, int subtest); int test__dso_data_cache(struct test *test, int subtest); -- cgit v1.2.3 From 956a78356c24c1ac3becf854135dc065b6b74265 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 17 Mar 2020 19:02:19 +0800 Subject: perf test: Test pmu-events aliases Add creating event aliases to the pmu-events test. So currently we verify that the generated pmu-events.c is as expected for some test events. Now test that we generate aliases as expected for those events during normal operation. For that, we cycle through each HW PMU in the system, and use the test events to create aliases, and verify those against known, expected values. For core PMUs, we should create an alias for every event in test_cpu_events[]. However, for uncore PMUs, they need to be matched by the pmu_event.pmu member, so use test_uncore_events[]; so check the match beforehand with pmu_uncore_alias_match(). A sample run is as follows for my x86 machine: john@linux-3c19:~/linux> tools/perf/perf test -vv 10 10: PMU events : --- start --- ... testing PMU uncore_arb aliases: no events to match testing PMU cstate_pkg aliases: no events to match skipping testing PMU breakpoint testing aliases PMU uncore_cbox_1: matched event unc_cbo_xsnp_response.miss_eviction testing PMU uncore_cbox_1 aliases: pass testing PMU power aliases: no events to match testing aliases PMU cpu: matched event bp_l1_btb_correct testing aliases PMU cpu: matched event bp_l2_btb_correct testing aliases PMU cpu: matched event segment_reg_loads.any testing aliases PMU cpu: matched event dispatch_blocked.any testing aliases PMU cpu: matched event eist_trans testing PMU cpu aliases: pass testing PMU intel_pt aliases: no events to match skipping testing PMU software skipping testing PMU intel_bts testing PMU uncore_imc aliases: no events to match testing aliases PMU uncore_cbox_0: matched event unc_cbo_xsnp_response.miss_eviction testing PMU uncore_cbox_0 aliases: pass testing PMU cstate_core aliases: no events to match skipping testing PMU tracepoint testing PMU msr aliases: no events to match test child finished with 0 Signed-off-by: John Garry Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: James Clark Cc: Joakim Zhang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linuxarm@huawei.com Link: http://lore.kernel.org/lkml/1584442939-8911-8-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu-events.c | 148 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 12fc29746a09..d64261da8bf7 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -5,13 +5,24 @@ #include #include #include - +#include #include "debug.h" #include "../pmu-events/pmu-events.h" struct perf_pmu_test_event { struct pmu_event event; + + /* extra events for aliases */ + const char *alias_str; + + /* + * Note: For when PublicDescription does not exist in the JSON, we + * will have no long_desc in pmu_event.long_desc, but long_desc may + * be set in the alias. + */ + const char *alias_long_desc; }; + static struct perf_pmu_test_event test_cpu_events[] = { { .event = { @@ -20,6 +31,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "L1 BTB Correction", .topic = "branch", }, + .alias_str = "event=0x8a", + .alias_long_desc = "L1 BTB Correction", }, { .event = { @@ -28,6 +41,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "L2 BTB Correction", .topic = "branch", }, + .alias_str = "event=0x8b", + .alias_long_desc = "L2 BTB Correction", }, { .event = { @@ -36,6 +51,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Number of segment register loads", .topic = "other", }, + .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", + .alias_long_desc = "Number of segment register loads", }, { .event = { @@ -44,6 +61,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Memory cluster signals to block micro-op dispatch for any reason", .topic = "other", }, + .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", + .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", }, { .event = { @@ -52,6 +71,8 @@ static struct perf_pmu_test_event test_cpu_events[] = { .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", .topic = "other", }, + .alias_str = "umask=0,(null)=0x30d40,event=0x3a", + .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", }, { /* sentinel */ .event = { @@ -70,6 +91,8 @@ static struct perf_pmu_test_event test_uncore_events[] = { .long_desc = "DDRC write commands", .pmu = "hisi_sccl,ddrc", }, + .alias_str = "event=0x2", + .alias_long_desc = "DDRC write commands", }, { .event = { @@ -80,6 +103,8 @@ static struct perf_pmu_test_event test_uncore_events[] = { .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", .pmu = "uncore_cbox", }, + .alias_str = "umask=0x81,event=0x22", + .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", }, { /* sentinel */ .event = { @@ -223,11 +248,132 @@ static int __test_pmu_event_table(void) return 0; } + +static struct perf_pmu_alias *find_alias(const char *test_event, struct list_head *aliases) +{ + struct perf_pmu_alias *alias; + + list_for_each_entry(alias, aliases, list) + if (!strcmp(test_event, alias->name)) + return alias; + + return NULL; +} + +/* Verify aliases are as expected */ +static int __test__pmu_event_aliases(char *pmu_name, int *count) +{ + struct perf_pmu_test_event *test; + struct pmu_event *te; + struct perf_pmu *pmu; + LIST_HEAD(aliases); + int res = 0; + bool use_uncore_table; + struct pmu_events_map *map = __test_pmu_get_events_map(); + + if (!map) + return -1; + + if (is_pmu_core(pmu_name)) { + test = &test_cpu_events[0]; + use_uncore_table = false; + } else { + test = &test_uncore_events[0]; + use_uncore_table = true; + } + + pmu = zalloc(sizeof(*pmu)); + if (!pmu) + return -1; + + pmu->name = pmu_name; + + pmu_add_cpu_aliases_map(&aliases, pmu, map); + + for (te = &test->event; te->name; test++, te = &test->event) { + struct perf_pmu_alias *alias = find_alias(te->name, &aliases); + + if (!alias) { + bool uncore_match = pmu_uncore_alias_match(pmu_name, + te->pmu); + + if (use_uncore_table && !uncore_match) { + pr_debug3("testing aliases PMU %s: skip matching alias %s\n", + pmu_name, te->name); + continue; + } + + pr_debug2("testing aliases PMU %s: no alias, alias_table->name=%s\n", + pmu_name, te->name); + res = -1; + break; + } + + if (!is_same(alias->desc, te->desc)) { + pr_debug2("testing aliases PMU %s: mismatched desc, %s vs %s\n", + pmu_name, alias->desc, te->desc); + res = -1; + break; + } + + if (!is_same(alias->long_desc, test->alias_long_desc)) { + pr_debug2("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", + pmu_name, alias->long_desc, + test->alias_long_desc); + res = -1; + break; + } + + if (!is_same(alias->str, test->alias_str)) { + pr_debug2("testing aliases PMU %s: mismatched str, %s vs %s\n", + pmu_name, alias->str, test->alias_str); + res = -1; + break; + } + + if (!is_same(alias->topic, te->topic)) { + pr_debug2("testing aliases PMU %s: mismatched topic, %s vs %s\n", + pmu_name, alias->topic, te->topic); + res = -1; + break; + } + + (*count)++; + pr_debug2("testing aliases PMU %s: matched event %s\n", + pmu_name, alias->name); + } + + free(pmu); + return res; +} + int test__pmu_events(struct test *test __maybe_unused, int subtest __maybe_unused) { + struct perf_pmu *pmu = NULL; + if (__test_pmu_event_table()) return -1; + while ((pmu = perf_pmu__scan(pmu)) != NULL) { + int count = 0; + + if (list_empty(&pmu->format)) { + pr_debug2("skipping testing PMU %s\n", pmu->name); + continue; + } + + if (__test__pmu_event_aliases(pmu->name, &count)) { + pr_debug("testing PMU %s aliases: failed\n", pmu->name); + return -1; + } + + if (count == 0) + pr_debug3("testing PMU %s aliases: no events to match\n", + pmu->name); + else + pr_debug("testing PMU %s aliases: pass\n", pmu->name); + } + return 0; } -- cgit v1.2.3 From ba78c1c5461c2fc2f57b777e971b3a9ec0df5666 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 25 Mar 2020 21:45:30 +0900 Subject: perf tools: Basic support for CGROUP event Implement basic functionality to support cgroup tracking. Each cgroup can be identified by inode number which can be read from userspace too. The actual cgroup processing will come in the later patch. Reported-by: kernel test robot Signed-off-by: Namhyung Kim Cc: Adrian Hunter [ fix perf test failure on sampling parsing ] Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200325124536.2800725-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/sample-parsing.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 14239e472187..61865699c3f4 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -151,6 +151,9 @@ static bool samples_same(const struct perf_sample *s1, if (type & PERF_SAMPLE_PHYS_ADDR) COMP(phys_addr); + if (type & PERF_SAMPLE_CGROUP) + COMP(cgroup); + if (type & PERF_SAMPLE_AUX) { COMP(aux_sample.size); if (memcmp(s1->aux_sample.data, s2->aux_sample.data, @@ -230,6 +233,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) .regs = regs, }, .phys_addr = 113, + .cgroup = 114, .aux_sample = { .size = sizeof(aux_data), .data = (void *)aux_data, @@ -336,7 +340,7 @@ int test__sample_parsing(struct test *test __maybe_unused, int subtest __maybe_u * were added. Please actually update the test rather than just change * the condition below. */ - if (PERF_SAMPLE_MAX > PERF_SAMPLE_AUX << 1) { + if (PERF_SAMPLE_MAX > PERF_SAMPLE_CGROUP << 1) { pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); return -1; } -- cgit v1.2.3 From 7b1642f2fc1e1f20948e806b7ce319f660633342 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 30 Mar 2020 09:32:41 -0300 Subject: perf build-test: Honour JOBS to override detection of number of cores When one does: $ make -C tools/perf build-test The makefile in tools/perf/tests/ will, just like the main one, detect how many cores are in the system and use it with -j. Sometimes we may need to override that, for instance, when using icecream or distcc to use multiple machines in the build process, then we need to, as with the main makefile, use: $ make JOBS=N -C tools/perf build-test Fix the tests makefile to honour that. Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Namhyung Kim Link: http://lore.kernel.org/lkml/20200330130301.GA31702@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/make | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/perf/tests') diff --git a/tools/perf/tests/make b/tools/perf/tests/make index c850d1664c56..5d0c3a9c47a1 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -28,9 +28,13 @@ endif PARALLEL_OPT= ifeq ($(SET_PARALLEL),1) - cores := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null) - ifeq ($(cores),0) - cores := 1 + ifeq ($(JOBS),) + cores := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null) + ifeq ($(cores),0) + cores := 1 + endif + else + cores=$(JOBS) endif PARALLEL_OPT="-j$(cores)" endif -- cgit v1.2.3