18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "tests.h"
38c2ecf20Sopenharmony_ci#include "debug.h"
48c2ecf20Sopenharmony_ci#include "evlist.h"
58c2ecf20Sopenharmony_ci#include "cgroup.h"
68c2ecf20Sopenharmony_ci#include "rblist.h"
78c2ecf20Sopenharmony_ci#include "metricgroup.h"
88c2ecf20Sopenharmony_ci#include "parse-events.h"
98c2ecf20Sopenharmony_ci#include "pmu-events/pmu-events.h"
108c2ecf20Sopenharmony_ci#include "pfm.h"
118c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
128c2ecf20Sopenharmony_ci#include <stdio.h>
138c2ecf20Sopenharmony_ci#include <stdlib.h>
148c2ecf20Sopenharmony_ci#include <string.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int test_expand_events(struct evlist *evlist,
178c2ecf20Sopenharmony_ci			      struct rblist *metric_events)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	int i, ret = TEST_FAIL;
208c2ecf20Sopenharmony_ci	int nr_events;
218c2ecf20Sopenharmony_ci	bool was_group_event;
228c2ecf20Sopenharmony_ci	int nr_members;  /* for the first evsel only */
238c2ecf20Sopenharmony_ci	const char cgrp_str[] = "A,B,C";
248c2ecf20Sopenharmony_ci	const char *cgrp_name[] = { "A", "B", "C" };
258c2ecf20Sopenharmony_ci	int nr_cgrps = ARRAY_SIZE(cgrp_name);
268c2ecf20Sopenharmony_ci	char **ev_name;
278c2ecf20Sopenharmony_ci	struct evsel *evsel;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	TEST_ASSERT_VAL("evlist is empty", !perf_evlist__empty(evlist));
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	nr_events = evlist->core.nr_entries;
328c2ecf20Sopenharmony_ci	ev_name = calloc(nr_events, sizeof(*ev_name));
338c2ecf20Sopenharmony_ci	if (ev_name == NULL) {
348c2ecf20Sopenharmony_ci		pr_debug("memory allocation failure\n");
358c2ecf20Sopenharmony_ci		return TEST_FAIL;
368c2ecf20Sopenharmony_ci	}
378c2ecf20Sopenharmony_ci	i = 0;
388c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
398c2ecf20Sopenharmony_ci		ev_name[i] = strdup(evsel->name);
408c2ecf20Sopenharmony_ci		if (ev_name[i] == NULL) {
418c2ecf20Sopenharmony_ci			pr_debug("memory allocation failure\n");
428c2ecf20Sopenharmony_ci			goto out;
438c2ecf20Sopenharmony_ci		}
448c2ecf20Sopenharmony_ci		i++;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci	/* remember grouping info */
478c2ecf20Sopenharmony_ci	was_group_event = evsel__is_group_event(evlist__first(evlist));
488c2ecf20Sopenharmony_ci	nr_members = evlist__first(evlist)->core.nr_members;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	ret = evlist__expand_cgroup(evlist, cgrp_str, metric_events, false);
518c2ecf20Sopenharmony_ci	if (ret < 0) {
528c2ecf20Sopenharmony_ci		pr_debug("failed to expand events for cgroups\n");
538c2ecf20Sopenharmony_ci		goto out;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	ret = TEST_FAIL;
578c2ecf20Sopenharmony_ci	if (evlist->core.nr_entries != nr_events * nr_cgrps) {
588c2ecf20Sopenharmony_ci		pr_debug("event count doesn't match\n");
598c2ecf20Sopenharmony_ci		goto out;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	i = 0;
638c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
648c2ecf20Sopenharmony_ci		if (strcmp(evsel->name, ev_name[i % nr_events])) {
658c2ecf20Sopenharmony_ci			pr_debug("event name doesn't match:\n");
668c2ecf20Sopenharmony_ci			pr_debug("  evsel[%d]: %s\n  expected: %s\n",
678c2ecf20Sopenharmony_ci				 i, evsel->name, ev_name[i % nr_events]);
688c2ecf20Sopenharmony_ci			goto out;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci		if (strcmp(evsel->cgrp->name, cgrp_name[i / nr_events])) {
718c2ecf20Sopenharmony_ci			pr_debug("cgroup name doesn't match:\n");
728c2ecf20Sopenharmony_ci			pr_debug("  evsel[%d]: %s\n  expected: %s\n",
738c2ecf20Sopenharmony_ci				 i, evsel->cgrp->name, cgrp_name[i / nr_events]);
748c2ecf20Sopenharmony_ci			goto out;
758c2ecf20Sopenharmony_ci		}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		if ((i % nr_events) == 0) {
788c2ecf20Sopenharmony_ci			if (evsel__is_group_event(evsel) != was_group_event) {
798c2ecf20Sopenharmony_ci				pr_debug("event group doesn't match: got %s, expect %s\n",
808c2ecf20Sopenharmony_ci					 evsel__is_group_event(evsel) ? "true" : "false",
818c2ecf20Sopenharmony_ci					 was_group_event ? "true" : "false");
828c2ecf20Sopenharmony_ci				goto out;
838c2ecf20Sopenharmony_ci			}
848c2ecf20Sopenharmony_ci			if (evsel->core.nr_members != nr_members) {
858c2ecf20Sopenharmony_ci				pr_debug("event group member doesn't match: %d vs %d\n",
868c2ecf20Sopenharmony_ci					 evsel->core.nr_members, nr_members);
878c2ecf20Sopenharmony_ci				goto out;
888c2ecf20Sopenharmony_ci			}
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci		i++;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci	ret = TEST_OK;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciout:	for (i = 0; i < nr_events; i++)
958c2ecf20Sopenharmony_ci		free(ev_name[i]);
968c2ecf20Sopenharmony_ci	free(ev_name);
978c2ecf20Sopenharmony_ci	return ret;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int expand_default_events(void)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int ret;
1038c2ecf20Sopenharmony_ci	struct evlist *evlist;
1048c2ecf20Sopenharmony_ci	struct rblist metric_events;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	evlist = perf_evlist__new_default();
1078c2ecf20Sopenharmony_ci	TEST_ASSERT_VAL("failed to get evlist", evlist);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	rblist__init(&metric_events);
1108c2ecf20Sopenharmony_ci	ret = test_expand_events(evlist, &metric_events);
1118c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1128c2ecf20Sopenharmony_ci	return ret;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int expand_group_events(void)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	int ret;
1188c2ecf20Sopenharmony_ci	struct evlist *evlist;
1198c2ecf20Sopenharmony_ci	struct rblist metric_events;
1208c2ecf20Sopenharmony_ci	struct parse_events_error err;
1218c2ecf20Sopenharmony_ci	const char event_str[] = "{cycles,instructions}";
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	symbol_conf.event_group = true;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	evlist = evlist__new();
1268c2ecf20Sopenharmony_ci	TEST_ASSERT_VAL("failed to get evlist", evlist);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	ret = parse_events(evlist, event_str, &err);
1298c2ecf20Sopenharmony_ci	if (ret < 0) {
1308c2ecf20Sopenharmony_ci		pr_debug("failed to parse event '%s', err %d, str '%s'\n",
1318c2ecf20Sopenharmony_ci			 event_str, ret, err.str);
1328c2ecf20Sopenharmony_ci		parse_events_print_error(&err, event_str);
1338c2ecf20Sopenharmony_ci		goto out;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	rblist__init(&metric_events);
1378c2ecf20Sopenharmony_ci	ret = test_expand_events(evlist, &metric_events);
1388c2ecf20Sopenharmony_ciout:
1398c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int expand_libpfm_events(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	int ret;
1468c2ecf20Sopenharmony_ci	struct evlist *evlist;
1478c2ecf20Sopenharmony_ci	struct rblist metric_events;
1488c2ecf20Sopenharmony_ci	const char event_str[] = "CYCLES";
1498c2ecf20Sopenharmony_ci	struct option opt = {
1508c2ecf20Sopenharmony_ci		.value = &evlist,
1518c2ecf20Sopenharmony_ci	};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	symbol_conf.event_group = true;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	evlist = evlist__new();
1568c2ecf20Sopenharmony_ci	TEST_ASSERT_VAL("failed to get evlist", evlist);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	ret = parse_libpfm_events_option(&opt, event_str, 0);
1598c2ecf20Sopenharmony_ci	if (ret < 0) {
1608c2ecf20Sopenharmony_ci		pr_debug("failed to parse libpfm event '%s', err %d\n",
1618c2ecf20Sopenharmony_ci			 event_str, ret);
1628c2ecf20Sopenharmony_ci		goto out;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci	if (perf_evlist__empty(evlist)) {
1658c2ecf20Sopenharmony_ci		pr_debug("libpfm was not enabled\n");
1668c2ecf20Sopenharmony_ci		goto out;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	rblist__init(&metric_events);
1708c2ecf20Sopenharmony_ci	ret = test_expand_events(evlist, &metric_events);
1718c2ecf20Sopenharmony_ciout:
1728c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1738c2ecf20Sopenharmony_ci	return ret;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int expand_metric_events(void)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	int ret;
1798c2ecf20Sopenharmony_ci	struct evlist *evlist;
1808c2ecf20Sopenharmony_ci	struct rblist metric_events;
1818c2ecf20Sopenharmony_ci	const char metric_str[] = "CPI";
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	struct pmu_event pme_test[] = {
1848c2ecf20Sopenharmony_ci		{
1858c2ecf20Sopenharmony_ci			.metric_expr	= "instructions / cycles",
1868c2ecf20Sopenharmony_ci			.metric_name	= "IPC",
1878c2ecf20Sopenharmony_ci		},
1888c2ecf20Sopenharmony_ci		{
1898c2ecf20Sopenharmony_ci			.metric_expr	= "1 / IPC",
1908c2ecf20Sopenharmony_ci			.metric_name	= "CPI",
1918c2ecf20Sopenharmony_ci		},
1928c2ecf20Sopenharmony_ci		{
1938c2ecf20Sopenharmony_ci			.metric_expr	= NULL,
1948c2ecf20Sopenharmony_ci			.metric_name	= NULL,
1958c2ecf20Sopenharmony_ci		},
1968c2ecf20Sopenharmony_ci	};
1978c2ecf20Sopenharmony_ci	struct pmu_events_map ev_map = {
1988c2ecf20Sopenharmony_ci		.cpuid		= "test",
1998c2ecf20Sopenharmony_ci		.version	= "1",
2008c2ecf20Sopenharmony_ci		.type		= "core",
2018c2ecf20Sopenharmony_ci		.table		= pme_test,
2028c2ecf20Sopenharmony_ci	};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	evlist = evlist__new();
2058c2ecf20Sopenharmony_ci	TEST_ASSERT_VAL("failed to get evlist", evlist);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	rblist__init(&metric_events);
2088c2ecf20Sopenharmony_ci	ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
2098c2ecf20Sopenharmony_ci					     false, false, &metric_events);
2108c2ecf20Sopenharmony_ci	if (ret < 0) {
2118c2ecf20Sopenharmony_ci		pr_debug("failed to parse '%s' metric\n", metric_str);
2128c2ecf20Sopenharmony_ci		goto out;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ret = test_expand_events(evlist, &metric_events);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciout:
2188c2ecf20Sopenharmony_ci	metricgroup__rblist_exit(&metric_events);
2198c2ecf20Sopenharmony_ci	evlist__delete(evlist);
2208c2ecf20Sopenharmony_ci	return ret;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciint test__expand_cgroup_events(struct test *test __maybe_unused,
2248c2ecf20Sopenharmony_ci			       int subtest __maybe_unused)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	int ret;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ret = expand_default_events();
2298c2ecf20Sopenharmony_ci	TEST_ASSERT_EQUAL("failed to expand default events", ret, 0);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	ret = expand_group_events();
2328c2ecf20Sopenharmony_ci	TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	ret = expand_libpfm_events();
2358c2ecf20Sopenharmony_ci	TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	ret = expand_metric_events();
2388c2ecf20Sopenharmony_ci	TEST_ASSERT_EQUAL("failed to expand metric events", ret, 0);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return ret;
2418c2ecf20Sopenharmony_ci}
242