Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf test: Add event group test for events in multiple PMUs

Multiple events in a group can belong to one or more PMUs, however
there are some limitations.

One of the limitations is that perf doesn't allow creating a group of
events from different hw PMUs.

Write a simple test to create various combinations of hw, sw and uncore
PMU events and verify group creation succeeds or fails as expected.

Signed-off-by: Ravi Bangoria <ravi.bangoria@amd.com>
Acked-by: Ian Rogers <irogers@google.com>
Acked-by: Kan Liang <kan.liang@linux.intel.com>
Acked-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ananth Narayan <ananth.narayan@amd.com>
Cc: Athira Jajeev <atrajeev@linux.vnet.ibm.com>
Cc: Carsten Haitzler <carsten.haitzler@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Santosh Shukla <santosh.shukla@amd.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Link: https://lore.kernel.org/r/20221206043237.12159-3-ravi.bangoria@amd.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ravi Bangoria and committed by
Arnaldo Carvalho de Melo
9d9b22be 336b92da

+130
+1
tools/perf/tests/Build
··· 67 67 perf-y += perf-time-to-tsc.o 68 68 perf-y += dlfilter-test.o 69 69 perf-y += sigtrap.o 70 + perf-y += event_groups.o 70 71 71 72 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build 72 73 $(call rule_mkdir)
+1
tools/perf/tests/builtin-test.c
··· 110 110 &suite__perf_time_to_tsc, 111 111 &suite__dlfilter, 112 112 &suite__sigtrap, 113 + &suite__event_groups, 113 114 NULL, 114 115 }; 115 116
+127
tools/perf/tests/event_groups.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <string.h> 3 + #include <unistd.h> 4 + #include <stdio.h> 5 + #include "linux/perf_event.h" 6 + #include "tests.h" 7 + #include "debug.h" 8 + #include "pmu.h" 9 + #include "pmus.h" 10 + #include "header.h" 11 + #include "../perf-sys.h" 12 + 13 + /* hw: cycles, sw: context-switch, uncore: [arch dependent] */ 14 + static int types[] = {0, 1, -1}; 15 + static unsigned long configs[] = {0, 3, 0}; 16 + 17 + #define NR_UNCORE_PMUS 5 18 + 19 + /* Uncore pmus that support more than 3 counters */ 20 + static struct uncore_pmus { 21 + const char *name; 22 + __u64 config; 23 + } uncore_pmus[NR_UNCORE_PMUS] = { 24 + { "amd_l3", 0x0 }, 25 + { "amd_df", 0x0 }, 26 + { "uncore_imc_0", 0x1 }, /* Intel */ 27 + { "core_imc", 0x318 }, /* PowerPC: core_imc/CPM_STCX_FIN/ */ 28 + { "hv_24x7", 0x22000000003 }, /* PowerPC: hv_24x7/CPM_STCX_FIN/ */ 29 + }; 30 + 31 + static int event_open(int type, unsigned long config, int group_fd) 32 + { 33 + struct perf_event_attr attr; 34 + 35 + memset(&attr, 0, sizeof(struct perf_event_attr)); 36 + attr.type = type; 37 + attr.size = sizeof(struct perf_event_attr); 38 + attr.config = config; 39 + /* 40 + * When creating an event group, typically the group leader is 41 + * initialized with disabled set to 1 and any child events are 42 + * initialized with disabled set to 0. Despite disabled being 0, 43 + * the child events will not start until the group leader is 44 + * enabled. 45 + */ 46 + attr.disabled = group_fd == -1 ? 1 : 0; 47 + 48 + return sys_perf_event_open(&attr, -1, 0, group_fd, 0); 49 + } 50 + 51 + static int setup_uncore_event(void) 52 + { 53 + struct perf_pmu *pmu; 54 + int i; 55 + 56 + if (list_empty(&pmus)) 57 + perf_pmu__scan(NULL); 58 + 59 + perf_pmus__for_each_pmu(pmu) { 60 + for (i = 0; i < NR_UNCORE_PMUS; i++) { 61 + if (!strcmp(uncore_pmus[i].name, pmu->name)) { 62 + pr_debug("Using %s for uncore pmu event\n", pmu->name); 63 + types[2] = pmu->type; 64 + configs[2] = uncore_pmus[i].config; 65 + return 0; 66 + } 67 + } 68 + } 69 + return -1; 70 + } 71 + 72 + static int run_test(int i, int j, int k) 73 + { 74 + int erroneous = ((((1 << i) | (1 << j) | (1 << k)) & 5) == 5); 75 + int group_fd, sibling_fd1, sibling_fd2; 76 + 77 + group_fd = event_open(types[i], configs[i], -1); 78 + if (group_fd == -1) 79 + return -1; 80 + 81 + sibling_fd1 = event_open(types[j], configs[j], group_fd); 82 + if (sibling_fd1 == -1) { 83 + close(group_fd); 84 + return erroneous ? 0 : -1; 85 + } 86 + 87 + sibling_fd2 = event_open(types[k], configs[k], group_fd); 88 + if (sibling_fd2 == -1) { 89 + close(sibling_fd1); 90 + close(group_fd); 91 + return erroneous ? 0 : -1; 92 + } 93 + 94 + close(sibling_fd2); 95 + close(sibling_fd1); 96 + close(group_fd); 97 + return erroneous ? -1 : 0; 98 + } 99 + 100 + static int test__event_groups(struct test_suite *text __maybe_unused, int subtest __maybe_unused) 101 + { 102 + int i, j, k; 103 + int ret; 104 + int r; 105 + 106 + ret = setup_uncore_event(); 107 + if (ret || types[2] == -1) 108 + return TEST_SKIP; 109 + 110 + ret = TEST_OK; 111 + for (i = 0; i < 3; i++) { 112 + for (j = 0; j < 3; j++) { 113 + for (k = 0; k < 3; k++) { 114 + r = run_test(i, j, k); 115 + if (r) 116 + ret = TEST_FAIL; 117 + 118 + pr_debug("0x%x 0x%lx, 0x%x 0x%lx, 0x%x 0x%lx: %s\n", 119 + types[i], configs[i], types[j], configs[j], 120 + types[k], configs[k], r ? "Fail" : "Pass"); 121 + } 122 + } 123 + } 124 + return ret; 125 + } 126 + 127 + DEFINE_SUITE("Event groups", event_groups);
+1
tools/perf/tests/tests.h
··· 147 147 DECLARE_SUITE(perf_time_to_tsc); 148 148 DECLARE_SUITE(dlfilter); 149 149 DECLARE_SUITE(sigtrap); 150 + DECLARE_SUITE(event_groups); 150 151 151 152 /* 152 153 * PowerPC and S390 do not support creation of instruction breakpoints using the