On Tue, Sep 22, 2020 at 7:00 PM Namhyung Kim <namhy...@kernel.org> wrote: > > It'll expand given events for cgroups A, B and C. > > $ ./perf test -v expansion > 69: Event expansion for cgroups : > --- start --- > test child forked, pid 983140 > metric expr 1 / IPC for CPI > metric expr instructions / cycles for IPC > found event instructions > found event cycles > adding {instructions,cycles}:W > copying metric event for cgroup 'A': instructions (idx=0) > copying metric event for cgroup 'B': instructions (idx=0) > copying metric event for cgroup 'C': instructions (idx=0) > test child finished with 0 > ---- end ---- > Event expansion for cgroups: Ok > > Cc: John Garry <john.ga...@huawei.com> > Signed-off-by: Namhyung Kim <namhy...@kernel.org> > --- > tools/perf/tests/Build | 1 + > tools/perf/tests/builtin-test.c | 4 + > tools/perf/tests/expand-cgroup.c | 241 +++++++++++++++++++++++++++++++ > tools/perf/tests/tests.h | 1 + > 4 files changed, 247 insertions(+) > create mode 100644 tools/perf/tests/expand-cgroup.c > > diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build > index 69bea7996f18..4d15bf6041fb 100644 > --- a/tools/perf/tests/Build > +++ b/tools/perf/tests/Build > @@ -61,6 +61,7 @@ perf-y += demangle-java-test.o > perf-y += pfm.o > perf-y += parse-metric.o > perf-y += pe-file-parsing.o > +perf-y += expand-cgroup.o > > $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build > $(call rule_mkdir) > diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c > index 651b8ea3354a..132bdb3e6c31 100644 > --- a/tools/perf/tests/builtin-test.c > +++ b/tools/perf/tests/builtin-test.c > @@ -345,6 +345,10 @@ static struct test generic_tests[] = { > .desc = "PE file support", > .func = test__pe_file_parsing, > }, > + { > + .desc = "Event expansion for cgroups", > + .func = test__expand_cgroup_events, > + }, > { > .func = NULL, > }, > diff --git a/tools/perf/tests/expand-cgroup.c > b/tools/perf/tests/expand-cgroup.c > new file mode 100644 > index 000000000000..d5771e4d094f > --- /dev/null > +++ b/tools/perf/tests/expand-cgroup.c > @@ -0,0 +1,241 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include "tests.h" > +#include "debug.h" > +#include "evlist.h" > +#include "cgroup.h" > +#include "rblist.h" > +#include "metricgroup.h" > +#include "parse-events.h" > +#include "pmu-events/pmu-events.h" > +#include "pfm.h" > +#include <subcmd/parse-options.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > + > +static int test_expand_events(struct evlist *evlist, > + struct rblist *metric_events) > +{ > + int i, ret = TEST_FAIL; > + int nr_events; > + bool was_group_event; > + int nr_members; /* for the first evsel only */ > + const char cgrp_str[] = "A,B,C"; > + const char *cgrp_name[] = { "A", "B", "C" }; > + int nr_cgrps = ARRAY_SIZE(cgrp_name); > + char **ev_name; > + struct evsel *evsel; > + > + TEST_ASSERT_VAL("evlist is empty", !perf_evlist__empty(evlist)); > + > + nr_events = evlist->core.nr_entries; > + ev_name = calloc(nr_events, sizeof(*ev_name)); > + if (ev_name == NULL) { > + pr_debug("memory allocation failure\n"); > + return TEST_FAIL; > + } > + i = 0; > + evlist__for_each_entry(evlist, evsel) { > + ev_name[i] = strdup(evsel->name); > + if (ev_name[i] == NULL) { > + pr_debug("memory allocation failure\n"); > + goto out; > + } > + i++; > + } > + /* remember grouping info */ > + was_group_event = evsel__is_group_event(evlist__first(evlist)); > + nr_members = evlist__first(evlist)->core.nr_members; > + > + ret = evlist__expand_cgroup(evlist, cgrp_str, metric_events, false); > + if (ret < 0) { > + pr_debug("failed to expand events for cgroups\n"); > + goto out; > + } > + > + ret = TEST_FAIL; > + if (evlist->core.nr_entries != nr_events * nr_cgrps) { > + pr_debug("event count doesn't match\n"); > + goto out; > + } > + > + i = 0; > + evlist__for_each_entry(evlist, evsel) { > + if (strcmp(evsel->name, 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]); > + goto out; > + } > + if (strcmp(evsel->cgrp->name, cgrp_name[i / nr_events])) { > + pr_debug("cgroup name doesn't match:\n"); > + pr_debug(" evsel[%d]: %s\n expected: %s\n", > + i, evsel->cgrp->name, cgrp_name[i / > nr_events]); > + goto out; > + } > + > + if ((i % nr_events) == 0) { > + if (evsel__is_group_event(evsel) != was_group_event) { > + pr_debug("event group doesn't match: got %s, > expect %s\n", > + evsel__is_group_event(evsel) ? > "true" : "false", > + was_group_event ? "true" : "false"); > + goto out; > + } > + if (evsel->core.nr_members != nr_members) { > + pr_debug("event group member doesn't match: > %d vs %d\n", > + evsel->core.nr_members, nr_members); > + goto out; > + } > + } > + i++; > + } > + ret = TEST_OK; > + > +out: for (i = 0; i < nr_events; i++) > + free(ev_name[i]); > + free(ev_name); > + return ret; > +} > + > +static int expand_default_events(void) > +{ > + int ret; > + struct evlist *evlist; > + struct rblist metric_events; > + > + evlist = perf_evlist__new_default(); > + TEST_ASSERT_VAL("failed to get evlist", evlist); > + > + rblist__init(&metric_events); > + ret = test_expand_events(evlist, &metric_events); > + evlist__delete(evlist); > + return ret; > +} > + > +static int expand_group_events(void) > +{ > + int ret; > + struct evlist *evlist; > + struct rblist metric_events; > + struct parse_events_error err; > + const char event_str[] = "{cycles,instructions}"; > + > + symbol_conf.event_group = true; > + > + evlist = evlist__new(); > + TEST_ASSERT_VAL("failed to get evlist", evlist); > + > + ret = parse_events(evlist, event_str, &err); > + if (ret < 0) { > + pr_debug("failed to parse event '%s', err %d, str '%s'\n", > + event_str, ret, err.str); > + parse_events_print_error(&err, event_str); > + goto out; > + } > + > + rblist__init(&metric_events); > + ret = test_expand_events(evlist, &metric_events); > +out: > + evlist__delete(evlist); > + return ret; > +} > +
Should this be #ifdef HAVE_LIBPFM ? Thanks, Ian > +static int expand_libpfm_events(void) > +{ > + int ret; > + struct evlist *evlist; > + struct rblist metric_events; > + const char event_str[] = "UNHALTED_CORE_CYCLES"; > + struct option opt = { > + .value = &evlist, > + }; > + > + symbol_conf.event_group = true; > + > + evlist = evlist__new(); > + TEST_ASSERT_VAL("failed to get evlist", evlist); > + > + ret = parse_libpfm_events_option(&opt, event_str, 0); > + if (ret < 0) { > + pr_debug("failed to parse libpfm event '%s', err %d\n", > + event_str, ret); > + goto out; > + } > + if (perf_evlist__empty(evlist)) { > + pr_debug("libpfm was not enabled\n"); > + goto out; > + } > + > + rblist__init(&metric_events); > + ret = test_expand_events(evlist, &metric_events); > +out: > + evlist__delete(evlist); > + return ret; > +} > + > +static int expand_metric_events(void) > +{ > + int ret; > + struct evlist *evlist; > + struct rblist metric_events; > + const char metric_str[] = "CPI"; > + > + struct pmu_event pme_test[] = { > + { > + .metric_expr = "instructions / cycles", > + .metric_name = "IPC", > + }, > + { > + .metric_expr = "1 / IPC", > + .metric_name = "CPI", > + }, > + { > + .metric_expr = NULL, > + .metric_name = NULL, > + }, > + }; > + struct pmu_events_map ev_map = { > + .cpuid = "test", > + .version = "1", > + .type = "core", > + .table = pme_test, > + }; > + > + evlist = evlist__new(); > + TEST_ASSERT_VAL("failed to get evlist", evlist); > + > + rblist__init(&metric_events); > + ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str, > + false, false, &metric_events); > + if (ret < 0) { > + pr_debug("failed to parse '%s' metric\n", metric_str); > + goto out; > + } > + > + ret = test_expand_events(evlist, &metric_events); > + > +out: > + metricgroup__rblist_exit(&metric_events); > + evlist__delete(evlist); > + return ret; > +} > + > +int test__expand_cgroup_events(struct test *test __maybe_unused, > + int subtest __maybe_unused) > +{ > + int ret; > + > + ret = expand_default_events(); > + TEST_ASSERT_EQUAL("failed to expand default events", ret, 0); > + > + ret = expand_group_events(); > + TEST_ASSERT_EQUAL("failed to expand event group", ret, 0); > + > + ret = expand_libpfm_events(); > + TEST_ASSERT_EQUAL("failed to expand event group", ret, 0); > + > + ret = expand_metric_events(); > + TEST_ASSERT_EQUAL("failed to expand metric events", ret, 0); > + > + return ret; > +} > diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h > index ef0f33c6ba23..c85a2c08e407 100644 > --- a/tools/perf/tests/tests.h > +++ b/tools/perf/tests/tests.h > @@ -123,6 +123,7 @@ const char *test__pfm_subtest_get_desc(int subtest); > int test__pfm_subtest_get_nr(void); > int test__parse_metric(struct test *test, int subtest); > int test__pe_file_parsing(struct test *test, int subtest); > +int test__expand_cgroup_events(struct test *test, int subtest); > > bool test__bp_signal_is_supported(void); > bool test__bp_account_is_supported(void); > -- > 2.28.0.681.g6f77f65b4e-goog >