mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
perf tests: Add test for uncore event sorting
Add a test for uncore event sorting matching multiple PMUs.
Uncore PMUs may have a common prefix, like the PMUs
uncore_imc_free_running_0 and uncore_imc_free_running_1 have a prefix of
uncore_imc_free_running.
Parsing an event group like "{data_read,data_write}" for those PMUs
should result with two groups:
"{uncore_imc_free_running_0/data_read/,uncore_imc_free_running_0/data_write/},
{uncore_imc_free_running_1/data_read/,uncore_imc_free_running_1/data_write/}"
which means the evsels need resorting as when initially parsed the
evsels are ordered with mixed PMUs:
"{uncore_imc_free_running_0/data_read/,uncore_imc_free_running_1/data_read/,
uncore_imc_free_running_0/data_write/,uncore_imc_free_running_1/data_write/}".
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Zide Chen <zide.chen@intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Collin Funk <collin.funk1@gmail.com>
Cc: Dmitrii Dolgov <9erthalion6@gmail.com>
Cc: German Gomez <german.gomez@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
98e68cb778
commit
9f116f4b81
@@ -3,6 +3,7 @@
|
||||
perf-test-y += builtin-test.o
|
||||
perf-test-y += tests-scripts.o
|
||||
perf-test-y += parse-events.o
|
||||
perf-test-y += uncore-event-sorting.o
|
||||
perf-test-y += dso-data.o
|
||||
perf-test-y += vmlinux-kallsyms.o
|
||||
perf-test-y += openat-syscall.o
|
||||
|
||||
@@ -71,6 +71,7 @@ static struct test_suite *generic_tests[] = {
|
||||
&suite__basic_mmap,
|
||||
&suite__mem,
|
||||
&suite__parse_events,
|
||||
&suite__uncore_event_sorting,
|
||||
&suite__expr,
|
||||
&suite__PERF_RECORD,
|
||||
&suite__pmu,
|
||||
|
||||
@@ -177,6 +177,7 @@ DECLARE_SUITE(sigtrap);
|
||||
DECLARE_SUITE(event_groups);
|
||||
DECLARE_SUITE(symbols);
|
||||
DECLARE_SUITE(util);
|
||||
DECLARE_SUITE(uncore_event_sorting);
|
||||
DECLARE_SUITE(subcmd_help);
|
||||
DECLARE_SUITE(kallsyms_split);
|
||||
|
||||
|
||||
176
tools/perf/tests/uncore-event-sorting.c
Normal file
176
tools/perf/tests/uncore-event-sorting.c
Normal file
@@ -0,0 +1,176 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "evlist.h"
|
||||
#include "parse-events.h"
|
||||
#include "pmu.h"
|
||||
#include "pmus.h"
|
||||
#include "tests.h"
|
||||
|
||||
struct match_state {
|
||||
char *event1;
|
||||
char *event2;
|
||||
};
|
||||
|
||||
static char *clean_event_name(struct pmu_event_info *info)
|
||||
{
|
||||
const char *name = info->name;
|
||||
const char *pmu_name = info->pmu->name;
|
||||
size_t pmu_len = strlen(pmu_name);
|
||||
char *res;
|
||||
size_t len;
|
||||
|
||||
if (!strncmp(name, pmu_name, pmu_len) && name[pmu_len] == '/')
|
||||
name += pmu_len + 1;
|
||||
|
||||
res = strdup(name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
len = strlen(res);
|
||||
if (len > 0 && res[len - 1] == '/')
|
||||
res[len - 1] = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int event_cb(void *state, struct pmu_event_info *info)
|
||||
{
|
||||
struct match_state *m = state;
|
||||
char *clean_name;
|
||||
|
||||
if (m->event1 && m->event2)
|
||||
return 1;
|
||||
|
||||
clean_name = clean_event_name(info);
|
||||
if (!clean_name)
|
||||
return 0;
|
||||
|
||||
if (!m->event1) {
|
||||
m->event1 = clean_name;
|
||||
} else {
|
||||
if (strcmp(m->event1, clean_name)) {
|
||||
m->event2 = clean_name;
|
||||
return 1;
|
||||
}
|
||||
free(clean_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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__uncore_event_sorting(struct test_suite *test __maybe_unused,
|
||||
int subtest __maybe_unused)
|
||||
{
|
||||
struct evlist *evlist = NULL;
|
||||
struct parse_events_error err;
|
||||
struct evsel *evsel;
|
||||
struct perf_pmu *pmu = NULL;
|
||||
char *pmu_prefix = NULL;
|
||||
struct match_state m = { NULL, NULL };
|
||||
char buf[1024];
|
||||
int ret;
|
||||
|
||||
parse_events_error__init(&err);
|
||||
|
||||
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||
size_t len;
|
||||
struct perf_pmu *sibling;
|
||||
|
||||
if (pmu->is_core)
|
||||
continue;
|
||||
|
||||
len = pmu_name_len_no_suffix(pmu->name);
|
||||
if (len == strlen(pmu->name))
|
||||
continue;
|
||||
|
||||
sibling = pmu;
|
||||
while ((sibling = perf_pmus__scan(sibling)) != NULL) {
|
||||
if (sibling->is_core)
|
||||
continue;
|
||||
if (pmu_name_len_no_suffix(sibling->name) == len &&
|
||||
!strncmp(pmu->name, sibling->name, len))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sibling)
|
||||
continue;
|
||||
|
||||
m.event1 = m.event2 = NULL;
|
||||
perf_pmu__for_each_event(pmu, false, &m, event_cb);
|
||||
|
||||
if (m.event1 && m.event2) {
|
||||
pmu_prefix = strndup(pmu->name, len);
|
||||
break;
|
||||
}
|
||||
zfree(&m.event1);
|
||||
}
|
||||
|
||||
if (!pmu_prefix) {
|
||||
pr_debug("No suitable uncore PMU found\n");
|
||||
ret = TEST_SKIP;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
evlist = evlist__new();
|
||||
if (!evlist) {
|
||||
ret = TEST_FAIL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "{%s/%s/,%s/%s/}", pmu_prefix, m.event1, pmu_prefix, m.event2);
|
||||
pr_debug("Parsing: %s\n", buf);
|
||||
|
||||
ret = parse_events(evlist, buf, &err);
|
||||
if (ret) {
|
||||
pr_debug("parse_events failed\n");
|
||||
ret = TEST_FAIL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
CHECK_COND(evlist->core.nr_entries >= 4, "Number of events is >= 4");
|
||||
CHECK_EQUAL(evlist->core.nr_entries % 2, 0, "Number of events is a multiple of 2");
|
||||
|
||||
evlist__for_each_entry(evlist, evsel) {
|
||||
struct evsel *next;
|
||||
|
||||
if (!evsel__is_group_leader(evsel))
|
||||
continue;
|
||||
|
||||
next = evsel__next(evsel);
|
||||
CHECK_EQUAL(evsel->core.nr_members, 2, "Group size is 2");
|
||||
CHECK_COND(evsel->pmu == next->pmu, "PMU match");
|
||||
CHECK_COND(strstr(evsel__name(evsel), m.event1) != NULL, "First event name");
|
||||
CHECK_COND(strstr(evsel__name(next), m.event2) != NULL, "Second event name");
|
||||
}
|
||||
ret = TEST_OK;
|
||||
|
||||
out_err:
|
||||
evlist__delete(evlist);
|
||||
parse_events_error__exit(&err);
|
||||
zfree(&pmu_prefix);
|
||||
zfree(&m.event1);
|
||||
zfree(&m.event2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_SUITE("Uncore event sorting", uncore_event_sorting);
|
||||
Reference in New Issue
Block a user