| Author | Tokens | Token Proportion | Commits | Commit Proportion |
|---|---|---|---|---|
| Ian Rogers | 1092 | 96.64% | 5 | 45.45% |
| Dapeng Mi | 19 | 1.68% | 1 | 9.09% |
| Jiri Olsa | 8 | 0.71% | 1 | 9.09% |
| Kan Liang | 4 | 0.35% | 1 | 9.09% |
| Namhyung Kim | 3 | 0.27% | 1 | 9.09% |
| Ingo Molnar | 3 | 0.27% | 1 | 9.09% |
| Greg Kroah-Hartman | 1 | 0.09% | 1 | 9.09% |
| Total | 1130 | 11 |
// SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include "arch-tests.h" #include "../util/topdown.h" #include "debug.h" #include "evlist.h" #include "parse-events.h" #include "pmu.h" #include "pmus.h" static int event_cb(void *state, struct pmu_event_info *info) { char buf[256]; struct parse_events_error parse_err; int *ret = state, err; struct evlist *evlist = evlist__new(); struct evsel *evsel; if (!evlist) return -ENOMEM; parse_events_error__init(&parse_err); snprintf(buf, sizeof(buf), "%s/%s/", info->pmu->name, info->name); err = parse_events(evlist, buf, &parse_err); if (err) { parse_events_error__print(&parse_err, buf); *ret = TEST_FAIL; } parse_events_error__exit(&parse_err); evlist__for_each_entry(evlist, evsel) { bool fail = false; bool p_core_pmu = evsel->pmu->type == PERF_TYPE_RAW; const char *name = evsel__name(evsel); if (strcasestr(name, "uops_retired.slots") || strcasestr(name, "topdown.backend_bound_slots") || strcasestr(name, "topdown.br_mispredict_slots") || strcasestr(name, "topdown.memory_bound_slots") || strcasestr(name, "topdown.bad_spec_slots") || strcasestr(name, "topdown.slots_p")) { if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel)) fail = true; } else if (strcasestr(name, "slots")) { if (arch_is_topdown_slots(evsel) != p_core_pmu || arch_is_topdown_metrics(evsel)) fail = true; } else if (strcasestr(name, "topdown")) { if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel) != p_core_pmu) fail = true; } else if (arch_is_topdown_slots(evsel) || arch_is_topdown_metrics(evsel)) { fail = true; } if (fail) { pr_debug("Broken topdown information for '%s'\n", evsel__name(evsel)); *ret = TEST_FAIL; } } evlist__delete(evlist); return 0; } static int test__x86_topdown(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int ret = TEST_OK; struct perf_pmu *pmu = NULL; if (!topdown_sys_has_perf_metrics()) return TEST_OK; while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { if (perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/false, &ret, event_cb)) break; } return ret; } #define CHECK_COND(cond, text) \ do { \ if (!(cond)) { \ pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ ret = TEST_FAIL; \ goto out_err; \ } \ } while (0) #define CHECK_EQUAL(val, expected, text) \ do { \ if ((val) != (expected)) { \ pr_debug("FAILED %s:%d %s (%d != %d)\n", \ __FILE__, __LINE__, text, (val), (expected)); \ ret = TEST_FAIL; \ goto out_err; \ } \ } while (0) static int test_sort(const char *str, int expected_slots_group_size, int expected_instructions_group_size) { struct evlist *evlist = NULL; struct parse_events_error err; struct evsel *evsel; int ret = TEST_FAIL; bool slots_seen = false; parse_events_error__init(&err); evlist = evlist__new(); if (!evlist) goto out_err; if (parse_events(evlist, str, &err)) { pr_debug("parse_events failed for %s\n", str); goto out_err; } evlist__for_each_entry(evlist, evsel) { if (!evsel__is_group_leader(evsel)) continue; if (strstr(evsel__name(evsel), "slots")) { /* * Slots as a leader means the PMU is for a perf metric * group as the slots event isn't present when not. */ slots_seen = true; CHECK_EQUAL(evsel->core.nr_members, expected_slots_group_size, "slots group size"); if (expected_slots_group_size == 3) { struct evsel *next = evsel__next(evsel); struct evsel *next2 = evsel__next(next); CHECK_COND(strstr(evsel__name(next), "instructions") != NULL, "slots second event is instructions"); CHECK_COND(strstr(evsel__name(next2), "topdown-retiring") != NULL, "slots third event is topdown-retiring"); } else if (expected_slots_group_size == 2) { struct evsel *next = evsel__next(evsel); CHECK_COND(strstr(evsel__name(next), "topdown-retiring") != NULL, "slots second event is topdown-retiring"); } } else if (strstr(evsel__name(evsel), "instructions")) { CHECK_EQUAL(evsel->core.nr_members, expected_instructions_group_size, "instructions group size"); if (expected_instructions_group_size == 2) { /* * On Intel hybrid CPUs (e.g., Alder Lake/ * Raptor Lake), E-cores (cpu_atom) do not * support/enforce the slots event. When * parsing event groups containing slots * across all PMUs, slots is automatically * filtered out from cpu_atom, leaving * {cpu_atom/instructions/, * cpu_atom/topdown-retiring/}. On cpu_atom, * instructions correctly leads this group of * 2 without slots reordering. */ struct evsel *next = evsel__next(evsel); CHECK_COND(strstr(evsel__name(next), "topdown-retiring") != NULL, "instructions second event is topdown-retiring"); } } else if (strstr(evsel__name(evsel), "topdown-retiring")) { /* * A perf metric event where the PMU doesn't require * slots as a leader. */ CHECK_EQUAL(evsel->core.nr_members, 1, "topdown-retiring group size"); } else if (strstr(evsel__name(evsel), "cycles")) { CHECK_EQUAL(evsel->core.nr_members, 1, "cycles group size"); } } CHECK_COND(slots_seen, "slots seen"); ret = TEST_OK; out_err: evlist__delete(evlist); parse_events_error__exit(&err); return ret; } static int test__x86_topdown_sorting(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int ret; if (!topdown_sys_has_perf_metrics()) return TEST_OK; ret = test_sort("{instructions,topdown-retiring,slots}", 3, 2); TEST_ASSERT_EQUAL("all events in a group", ret, TEST_OK); ret = test_sort("instructions,topdown-retiring,slots", 2, 1); TEST_ASSERT_EQUAL("all events not in a group", ret, TEST_OK); ret = test_sort("{instructions,slots},topdown-retiring", 2, 1); TEST_ASSERT_EQUAL("slots event in a group but topdown metrics events outside the group", ret, TEST_OK); ret = test_sort("{instructions,slots},{topdown-retiring}", 2, 1); TEST_ASSERT_EQUAL("slots event and topdown metrics events in two groups", ret, TEST_OK); ret = test_sort("{instructions,slots},cycles,topdown-retiring", 2, 1); TEST_ASSERT_EQUAL("slots event and metrics event are not in a group and not adjacent", ret, TEST_OK); return TEST_OK; } static int test__x86_topdown_slots_injection(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int ret; if (!topdown_sys_has_perf_metrics()) return TEST_OK; ret = test_sort("{instructions,topdown-retiring}", 3, 2); TEST_ASSERT_EQUAL("all events in a group", ret, TEST_OK); ret = test_sort("instructions,topdown-retiring", 2, 1); TEST_ASSERT_EQUAL("all events not in a group", ret, TEST_OK); ret = test_sort("{instructions},topdown-retiring", 2, 1); TEST_ASSERT_EQUAL("event in a group but topdown metrics events outside the group", ret, TEST_OK); ret = test_sort("{instructions},{topdown-retiring}", 2, 1); TEST_ASSERT_EQUAL("event and topdown metrics events in two groups", ret, TEST_OK); ret = test_sort("{instructions},cycles,topdown-retiring", 2, 1); TEST_ASSERT_EQUAL("event and metrics event are not in a group and not adjacent", ret, TEST_OK); return TEST_OK; } static struct test_case x86_topdown_tests[] = { TEST_CASE("topdown events", x86_topdown), TEST_CASE("topdown sorting", x86_topdown_sorting), TEST_CASE("topdown slots injection", x86_topdown_slots_injection), { .name = NULL, } }; struct test_suite suite__x86_topdown = { .desc = "x86 topdown", .test_cases = x86_topdown_tests, };
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1