162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include "arch-tests.h" 362306a36Sopenharmony_ci#include "debug.h" 462306a36Sopenharmony_ci#include "evlist.h" 562306a36Sopenharmony_ci#include "evsel.h" 662306a36Sopenharmony_ci#include "pmu.h" 762306a36Sopenharmony_ci#include "pmus.h" 862306a36Sopenharmony_ci#include "tests/tests.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic bool test_config(const struct evsel *evsel, __u64 expected_config) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == expected_config; 1362306a36Sopenharmony_ci} 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_config) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config; 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic bool test_hybrid_type(const struct evsel *evsel, __u64 expected_config) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return (evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT) == expected_config; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int test__hybrid_hw_event_with_pmu(struct evlist *evlist) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct evsel *evsel = evlist__first(evlist); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 3062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 3162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 3262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 3362306a36Sopenharmony_ci return TEST_OK; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int test__hybrid_hw_group_event(struct evlist *evlist) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct evsel *evsel, *leader; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci evsel = leader = evlist__first(evlist); 4162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 4262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 4362306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 4462306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 4562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci evsel = evsel__next(evsel); 4862306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 4962306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 5062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); 5162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 5262306a36Sopenharmony_ci return TEST_OK; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int test__hybrid_sw_hw_group_event(struct evlist *evlist) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct evsel *evsel, *leader; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci evsel = leader = evlist__first(evlist); 6062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 6162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); 6262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci evsel = evsel__next(evsel); 6562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 6662306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 6762306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 6862306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 6962306a36Sopenharmony_ci return TEST_OK; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int test__hybrid_hw_sw_group_event(struct evlist *evlist) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct evsel *evsel, *leader; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci evsel = leader = evlist__first(evlist); 7762306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 7862306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 7962306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 8062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 8162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci evsel = evsel__next(evsel); 8462306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); 8562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 8662306a36Sopenharmony_ci return TEST_OK; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int test__hybrid_group_modifier1(struct evlist *evlist) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct evsel *evsel, *leader; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci evsel = leader = evlist__first(evlist); 9462306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 9562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 9662306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 9762306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 9862306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 9962306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); 10062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci evsel = evsel__next(evsel); 10362306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 10462306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 10562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); 10662306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 10762306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); 10862306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); 10962306a36Sopenharmony_ci return TEST_OK; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int test__hybrid_raw1(struct evlist *evlist) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct perf_evsel *evsel; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci perf_evlist__for_each_evsel(&evlist->core, evsel) { 11762306a36Sopenharmony_ci struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->attr.type); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci TEST_ASSERT_VAL("missing pmu", pmu); 12062306a36Sopenharmony_ci TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4)); 12162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a)); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return TEST_OK; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int test__hybrid_raw2(struct evlist *evlist) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct evsel *evsel = evlist__first(evlist); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 13162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); 13262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a)); 13362306a36Sopenharmony_ci return TEST_OK; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int test__hybrid_cache_event(struct evlist *evlist) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct evsel *evsel = evlist__first(evlist); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 14162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); 14262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff)); 14362306a36Sopenharmony_ci return TEST_OK; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int test__checkevent_pmu(struct evlist *evlist) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci struct evsel *evsel = evlist__first(evlist); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 15262306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); 15362306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); 15462306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); 15562306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); 15662306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * The period value gets configured within evlist__config, 15962306a36Sopenharmony_ci * while this test executes only parse events method. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return TEST_OK; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct evlist_test { 16762306a36Sopenharmony_ci const char *name; 16862306a36Sopenharmony_ci bool (*valid)(void); 16962306a36Sopenharmony_ci int (*check)(struct evlist *evlist); 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic const struct evlist_test test__hybrid_events[] = { 17362306a36Sopenharmony_ci { 17462306a36Sopenharmony_ci .name = "cpu_core/cpu-cycles/", 17562306a36Sopenharmony_ci .check = test__hybrid_hw_event_with_pmu, 17662306a36Sopenharmony_ci /* 0 */ 17762306a36Sopenharmony_ci }, 17862306a36Sopenharmony_ci { 17962306a36Sopenharmony_ci .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}", 18062306a36Sopenharmony_ci .check = test__hybrid_hw_group_event, 18162306a36Sopenharmony_ci /* 1 */ 18262306a36Sopenharmony_ci }, 18362306a36Sopenharmony_ci { 18462306a36Sopenharmony_ci .name = "{cpu-clock,cpu_core/cpu-cycles/}", 18562306a36Sopenharmony_ci .check = test__hybrid_sw_hw_group_event, 18662306a36Sopenharmony_ci /* 2 */ 18762306a36Sopenharmony_ci }, 18862306a36Sopenharmony_ci { 18962306a36Sopenharmony_ci .name = "{cpu_core/cpu-cycles/,cpu-clock}", 19062306a36Sopenharmony_ci .check = test__hybrid_hw_sw_group_event, 19162306a36Sopenharmony_ci /* 3 */ 19262306a36Sopenharmony_ci }, 19362306a36Sopenharmony_ci { 19462306a36Sopenharmony_ci .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}", 19562306a36Sopenharmony_ci .check = test__hybrid_group_modifier1, 19662306a36Sopenharmony_ci /* 4 */ 19762306a36Sopenharmony_ci }, 19862306a36Sopenharmony_ci { 19962306a36Sopenharmony_ci .name = "r1a", 20062306a36Sopenharmony_ci .check = test__hybrid_raw1, 20162306a36Sopenharmony_ci /* 5 */ 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .name = "cpu_core/r1a/", 20562306a36Sopenharmony_ci .check = test__hybrid_raw2, 20662306a36Sopenharmony_ci /* 6 */ 20762306a36Sopenharmony_ci }, 20862306a36Sopenharmony_ci { 20962306a36Sopenharmony_ci .name = "cpu_core/config=10,config1,config2=3,period=1000/u", 21062306a36Sopenharmony_ci .check = test__checkevent_pmu, 21162306a36Sopenharmony_ci /* 7 */ 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci { 21462306a36Sopenharmony_ci .name = "cpu_core/LLC-loads/", 21562306a36Sopenharmony_ci .check = test__hybrid_cache_event, 21662306a36Sopenharmony_ci /* 8 */ 21762306a36Sopenharmony_ci }, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int test_event(const struct evlist_test *e) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct parse_events_error err; 22362306a36Sopenharmony_ci struct evlist *evlist; 22462306a36Sopenharmony_ci int ret; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (e->valid && !e->valid()) { 22762306a36Sopenharmony_ci pr_debug("... SKIP\n"); 22862306a36Sopenharmony_ci return TEST_OK; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci evlist = evlist__new(); 23262306a36Sopenharmony_ci if (evlist == NULL) { 23362306a36Sopenharmony_ci pr_err("Failed allocation"); 23462306a36Sopenharmony_ci return TEST_FAIL; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci parse_events_error__init(&err); 23762306a36Sopenharmony_ci ret = parse_events(evlist, e->name, &err); 23862306a36Sopenharmony_ci if (ret) { 23962306a36Sopenharmony_ci pr_debug("failed to parse event '%s', err %d, str '%s'\n", 24062306a36Sopenharmony_ci e->name, ret, err.str); 24162306a36Sopenharmony_ci parse_events_error__print(&err, e->name); 24262306a36Sopenharmony_ci ret = TEST_FAIL; 24362306a36Sopenharmony_ci if (strstr(err.str, "can't access trace events")) 24462306a36Sopenharmony_ci ret = TEST_SKIP; 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci ret = e->check(evlist); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci parse_events_error__exit(&err); 24962306a36Sopenharmony_ci evlist__delete(evlist); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int combine_test_results(int existing, int latest) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci if (existing == TEST_FAIL) 25762306a36Sopenharmony_ci return TEST_FAIL; 25862306a36Sopenharmony_ci if (existing == TEST_SKIP) 25962306a36Sopenharmony_ci return latest == TEST_OK ? TEST_SKIP : latest; 26062306a36Sopenharmony_ci return latest; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int test_events(const struct evlist_test *events, int cnt) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int ret = TEST_OK; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (int i = 0; i < cnt; i++) { 26862306a36Sopenharmony_ci const struct evlist_test *e = &events[i]; 26962306a36Sopenharmony_ci int test_ret; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci pr_debug("running test %d '%s'\n", i, e->name); 27262306a36Sopenharmony_ci test_ret = test_event(e); 27362306a36Sopenharmony_ci if (test_ret != TEST_OK) { 27462306a36Sopenharmony_ci pr_debug("Event test failure: test %d '%s'", i, e->name); 27562306a36Sopenharmony_ci ret = combine_test_results(ret, test_ret); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return ret; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci if (perf_pmus__num_core_pmus() == 1) 28562306a36Sopenharmony_ci return TEST_SKIP; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events)); 28862306a36Sopenharmony_ci} 289