|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * Test support for libpfm4 event encodings. | 
|  | * | 
|  | * Copyright 2020 Google LLC. | 
|  | */ | 
|  | #include "tests.h" | 
|  | #include "util/debug.h" | 
|  | #include "util/evlist.h" | 
|  | #include "util/pfm.h" | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  |  | 
|  | #ifdef HAVE_LIBPFM | 
|  | static int count_pfm_events(struct perf_evlist *evlist) | 
|  | { | 
|  | struct perf_evsel *evsel; | 
|  | int count = 0; | 
|  |  | 
|  | perf_evlist__for_each_entry(evlist, evsel) { | 
|  | count++; | 
|  | } | 
|  | return count; | 
|  | } | 
|  |  | 
|  | static int test__pfm_events(struct test_suite *test __maybe_unused, | 
|  | int subtest __maybe_unused) | 
|  | { | 
|  | struct evlist *evlist; | 
|  | struct option opt; | 
|  | size_t i; | 
|  | const struct { | 
|  | const char *events; | 
|  | int nr_events; | 
|  | } table[] = { | 
|  | { | 
|  | .events = "", | 
|  | .nr_events = 0, | 
|  | }, | 
|  | { | 
|  | .events = "instructions", | 
|  | .nr_events = 1, | 
|  | }, | 
|  | { | 
|  | .events = "instructions,cycles", | 
|  | .nr_events = 2, | 
|  | }, | 
|  | { | 
|  | .events = "stereolab", | 
|  | .nr_events = 0, | 
|  | }, | 
|  | { | 
|  | .events = "instructions,instructions", | 
|  | .nr_events = 2, | 
|  | }, | 
|  | { | 
|  | .events = "stereolab,instructions", | 
|  | .nr_events = 0, | 
|  | }, | 
|  | { | 
|  | .events = "instructions,stereolab", | 
|  | .nr_events = 1, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(table); i++) { | 
|  | evlist = evlist__new(); | 
|  | if (evlist == NULL) | 
|  | return -ENOMEM; | 
|  |  | 
|  | opt.value = evlist; | 
|  | parse_libpfm_events_option(&opt, | 
|  | table[i].events, | 
|  | 0); | 
|  | TEST_ASSERT_EQUAL(table[i].events, | 
|  | count_pfm_events(&evlist->core), | 
|  | table[i].nr_events); | 
|  | TEST_ASSERT_EQUAL(table[i].events, | 
|  | evlist->core.nr_groups, | 
|  | 0); | 
|  |  | 
|  | evlist__delete(evlist); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int test__pfm_group(struct test_suite *test __maybe_unused, | 
|  | int subtest __maybe_unused) | 
|  | { | 
|  | struct evlist *evlist; | 
|  | struct option opt; | 
|  | size_t i; | 
|  | const struct { | 
|  | const char *events; | 
|  | int nr_events; | 
|  | int nr_groups; | 
|  | } table[] = { | 
|  | { | 
|  | .events = "{},", | 
|  | .nr_events = 0, | 
|  | .nr_groups = 0, | 
|  | }, | 
|  | { | 
|  | .events = "{instructions}", | 
|  | .nr_events = 1, | 
|  | .nr_groups = 1, | 
|  | }, | 
|  | { | 
|  | .events = "{instructions},{}", | 
|  | .nr_events = 1, | 
|  | .nr_groups = 1, | 
|  | }, | 
|  | { | 
|  | .events = "{},{instructions}", | 
|  | .nr_events = 1, | 
|  | .nr_groups = 1, | 
|  | }, | 
|  | { | 
|  | .events = "{instructions},{instructions}", | 
|  | .nr_events = 2, | 
|  | .nr_groups = 2, | 
|  | }, | 
|  | { | 
|  | .events = "{instructions,cycles},{instructions,cycles}", | 
|  | .nr_events = 4, | 
|  | .nr_groups = 2, | 
|  | }, | 
|  | { | 
|  | .events = "{stereolab}", | 
|  | .nr_events = 0, | 
|  | .nr_groups = 0, | 
|  | }, | 
|  | { | 
|  | .events = | 
|  | "{instructions,cycles},{instructions,stereolab}", | 
|  | .nr_events = 3, | 
|  | .nr_groups = 1, | 
|  | }, | 
|  | { | 
|  | .events = "instructions}", | 
|  | .nr_events = 1, | 
|  | .nr_groups = 0, | 
|  | }, | 
|  | { | 
|  | .events = "{{instructions}}", | 
|  | .nr_events = 0, | 
|  | .nr_groups = 0, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(table); i++) { | 
|  | evlist = evlist__new(); | 
|  | if (evlist == NULL) | 
|  | return -ENOMEM; | 
|  |  | 
|  | opt.value = evlist; | 
|  | parse_libpfm_events_option(&opt, | 
|  | table[i].events, | 
|  | 0); | 
|  | TEST_ASSERT_EQUAL(table[i].events, | 
|  | count_pfm_events(&evlist->core), | 
|  | table[i].nr_events); | 
|  | TEST_ASSERT_EQUAL(table[i].events, | 
|  | evlist->core.nr_groups, | 
|  | table[i].nr_groups); | 
|  |  | 
|  | evlist__delete(evlist); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | #else | 
|  | static int test__pfm_events(struct test_suite *test __maybe_unused, | 
|  | int subtest __maybe_unused) | 
|  | { | 
|  | return TEST_SKIP; | 
|  | } | 
|  |  | 
|  | static int test__pfm_group(struct test_suite *test __maybe_unused, | 
|  | int subtest __maybe_unused) | 
|  | { | 
|  | return TEST_SKIP; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static struct test_case pfm_tests[] = { | 
|  | TEST_CASE_REASON("test of individual --pfm-events", pfm_events, "not compiled in"), | 
|  | TEST_CASE_REASON("test groups of --pfm-events", pfm_group, "not compiled in"), | 
|  | { .name = NULL, } | 
|  | }; | 
|  |  | 
|  | struct test_suite suite__pfm = { | 
|  | .desc = "Test libpfm4 support", | 
|  | .test_cases = pfm_tests, | 
|  | }; |