162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <dirent.h>
362306a36Sopenharmony_ci#include <errno.h>
462306a36Sopenharmony_ci#include <stdio.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <string.h>
762306a36Sopenharmony_ci#include <fcntl.h>
862306a36Sopenharmony_ci#include <sys/param.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <api/fs/tracing_path.h>
1262306a36Sopenharmony_ci#include <linux/stddef.h>
1362306a36Sopenharmony_ci#include <linux/perf_event.h>
1462306a36Sopenharmony_ci#include <linux/zalloc.h>
1562306a36Sopenharmony_ci#include <subcmd/pager.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "build-id.h"
1862306a36Sopenharmony_ci#include "debug.h"
1962306a36Sopenharmony_ci#include "evsel.h"
2062306a36Sopenharmony_ci#include "metricgroup.h"
2162306a36Sopenharmony_ci#include "parse-events.h"
2262306a36Sopenharmony_ci#include "pmu.h"
2362306a36Sopenharmony_ci#include "pmus.h"
2462306a36Sopenharmony_ci#include "print-events.h"
2562306a36Sopenharmony_ci#include "probe-file.h"
2662306a36Sopenharmony_ci#include "string2.h"
2762306a36Sopenharmony_ci#include "strlist.h"
2862306a36Sopenharmony_ci#include "tracepoint.h"
2962306a36Sopenharmony_ci#include "pfm.h"
3062306a36Sopenharmony_ci#include "thread_map.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define MAX_NAME_LEN 100
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/** Strings corresponding to enum perf_type_id. */
3562306a36Sopenharmony_cistatic const char * const event_type_descriptors[] = {
3662306a36Sopenharmony_ci	"Hardware event",
3762306a36Sopenharmony_ci	"Software event",
3862306a36Sopenharmony_ci	"Tracepoint event",
3962306a36Sopenharmony_ci	"Hardware cache event",
4062306a36Sopenharmony_ci	"Raw hardware event descriptor",
4162306a36Sopenharmony_ci	"Hardware breakpoint",
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
4562306a36Sopenharmony_ci	[PERF_TOOL_DURATION_TIME] = {
4662306a36Sopenharmony_ci		.symbol = "duration_time",
4762306a36Sopenharmony_ci		.alias  = "",
4862306a36Sopenharmony_ci	},
4962306a36Sopenharmony_ci	[PERF_TOOL_USER_TIME] = {
5062306a36Sopenharmony_ci		.symbol = "user_time",
5162306a36Sopenharmony_ci		.alias  = "",
5262306a36Sopenharmony_ci	},
5362306a36Sopenharmony_ci	[PERF_TOOL_SYSTEM_TIME] = {
5462306a36Sopenharmony_ci		.symbol = "system_time",
5562306a36Sopenharmony_ci		.alias  = "",
5662306a36Sopenharmony_ci	},
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * Print the events from <debugfs_mount_point>/tracing/events
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_civoid print_tracepoint_events(const struct print_callbacks *print_cb __maybe_unused, void *print_state __maybe_unused)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	char *events_path = get_tracing_file("events");
6562306a36Sopenharmony_ci	int events_fd = open(events_path, O_PATH);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	put_tracing_file(events_path);
6862306a36Sopenharmony_ci	if (events_fd < 0) {
6962306a36Sopenharmony_ci		printf("Error: failed to open tracing events directory\n");
7062306a36Sopenharmony_ci		return;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#ifdef HAVE_SCANDIRAT_SUPPORT
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct dirent **sys_namelist = NULL;
7662306a36Sopenharmony_ci	int sys_items = tracing_events__scandir_alphasort(&sys_namelist);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	for (int i = 0; i < sys_items; i++) {
7962306a36Sopenharmony_ci		struct dirent *sys_dirent = sys_namelist[i];
8062306a36Sopenharmony_ci		struct dirent **evt_namelist = NULL;
8162306a36Sopenharmony_ci		int dir_fd;
8262306a36Sopenharmony_ci		int evt_items;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		if (sys_dirent->d_type != DT_DIR ||
8562306a36Sopenharmony_ci		    !strcmp(sys_dirent->d_name, ".") ||
8662306a36Sopenharmony_ci		    !strcmp(sys_dirent->d_name, ".."))
8762306a36Sopenharmony_ci			goto next_sys;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		dir_fd = openat(events_fd, sys_dirent->d_name, O_PATH);
9062306a36Sopenharmony_ci		if (dir_fd < 0)
9162306a36Sopenharmony_ci			goto next_sys;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		evt_items = scandirat(events_fd, sys_dirent->d_name, &evt_namelist, NULL, alphasort);
9462306a36Sopenharmony_ci		for (int j = 0; j < evt_items; j++) {
9562306a36Sopenharmony_ci			struct dirent *evt_dirent = evt_namelist[j];
9662306a36Sopenharmony_ci			char evt_path[MAXPATHLEN];
9762306a36Sopenharmony_ci			int evt_fd;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci			if (evt_dirent->d_type != DT_DIR ||
10062306a36Sopenharmony_ci			    !strcmp(evt_dirent->d_name, ".") ||
10162306a36Sopenharmony_ci			    !strcmp(evt_dirent->d_name, ".."))
10262306a36Sopenharmony_ci				goto next_evt;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci			snprintf(evt_path, sizeof(evt_path), "%s/id", evt_dirent->d_name);
10562306a36Sopenharmony_ci			evt_fd = openat(dir_fd, evt_path, O_RDONLY);
10662306a36Sopenharmony_ci			if (evt_fd < 0)
10762306a36Sopenharmony_ci				goto next_evt;
10862306a36Sopenharmony_ci			close(evt_fd);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci			snprintf(evt_path, MAXPATHLEN, "%s:%s",
11162306a36Sopenharmony_ci				 sys_dirent->d_name, evt_dirent->d_name);
11262306a36Sopenharmony_ci			print_cb->print_event(print_state,
11362306a36Sopenharmony_ci					/*topic=*/NULL,
11462306a36Sopenharmony_ci					/*pmu_name=*/NULL,
11562306a36Sopenharmony_ci					evt_path,
11662306a36Sopenharmony_ci					/*event_alias=*/NULL,
11762306a36Sopenharmony_ci					/*scale_unit=*/NULL,
11862306a36Sopenharmony_ci					/*deprecated=*/false,
11962306a36Sopenharmony_ci					"Tracepoint event",
12062306a36Sopenharmony_ci					/*desc=*/NULL,
12162306a36Sopenharmony_ci					/*long_desc=*/NULL,
12262306a36Sopenharmony_ci					/*encoding_desc=*/NULL);
12362306a36Sopenharmony_cinext_evt:
12462306a36Sopenharmony_ci			free(evt_namelist[j]);
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci		close(dir_fd);
12762306a36Sopenharmony_ci		free(evt_namelist);
12862306a36Sopenharmony_cinext_sys:
12962306a36Sopenharmony_ci		free(sys_namelist[i]);
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	free(sys_namelist);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci#else
13562306a36Sopenharmony_ci	printf("\nWARNING: Your libc doesn't have the scandirat function, please ask its maintainers to implement it.\n"
13662306a36Sopenharmony_ci	       "         As a rough fallback, please do 'ls %s' to see the available tracepoint events.\n", events_path);
13762306a36Sopenharmony_ci#endif
13862306a36Sopenharmony_ci	close(events_fd);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_civoid print_sdt_events(const struct print_callbacks *print_cb, void *print_state)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct strlist *bidlist, *sdtlist;
14462306a36Sopenharmony_ci	struct str_node *bid_nd, *sdt_name, *next_sdt_name;
14562306a36Sopenharmony_ci	const char *last_sdt_name = NULL;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * The implicitly sorted sdtlist will hold the tracepoint name followed
14962306a36Sopenharmony_ci	 * by @<buildid>. If the tracepoint name is unique (determined by
15062306a36Sopenharmony_ci	 * looking at the adjacent nodes) the @<buildid> is dropped otherwise
15162306a36Sopenharmony_ci	 * the executable path and buildid are added to the name.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	sdtlist = strlist__new(NULL, NULL);
15462306a36Sopenharmony_ci	if (!sdtlist) {
15562306a36Sopenharmony_ci		pr_debug("Failed to allocate new strlist for SDT\n");
15662306a36Sopenharmony_ci		return;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	bidlist = build_id_cache__list_all(true);
15962306a36Sopenharmony_ci	if (!bidlist) {
16062306a36Sopenharmony_ci		pr_debug("Failed to get buildids: %d\n", errno);
16162306a36Sopenharmony_ci		return;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	strlist__for_each_entry(bid_nd, bidlist) {
16462306a36Sopenharmony_ci		struct probe_cache *pcache;
16562306a36Sopenharmony_ci		struct probe_cache_entry *ent;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		pcache = probe_cache__new(bid_nd->s, NULL);
16862306a36Sopenharmony_ci		if (!pcache)
16962306a36Sopenharmony_ci			continue;
17062306a36Sopenharmony_ci		list_for_each_entry(ent, &pcache->entries, node) {
17162306a36Sopenharmony_ci			char buf[1024];
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci			snprintf(buf, sizeof(buf), "%s:%s@%s",
17462306a36Sopenharmony_ci				 ent->pev.group, ent->pev.event, bid_nd->s);
17562306a36Sopenharmony_ci			strlist__add(sdtlist, buf);
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci		probe_cache__delete(pcache);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	strlist__delete(bidlist);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	strlist__for_each_entry(sdt_name, sdtlist) {
18262306a36Sopenharmony_ci		bool show_detail = false;
18362306a36Sopenharmony_ci		char *bid = strchr(sdt_name->s, '@');
18462306a36Sopenharmony_ci		char *evt_name = NULL;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		if (bid)
18762306a36Sopenharmony_ci			*(bid++) = '\0';
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		if (last_sdt_name && !strcmp(last_sdt_name, sdt_name->s)) {
19062306a36Sopenharmony_ci			show_detail = true;
19162306a36Sopenharmony_ci		} else {
19262306a36Sopenharmony_ci			next_sdt_name = strlist__next(sdt_name);
19362306a36Sopenharmony_ci			if (next_sdt_name) {
19462306a36Sopenharmony_ci				char *bid2 = strchr(next_sdt_name->s, '@');
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci				if (bid2)
19762306a36Sopenharmony_ci					*bid2 = '\0';
19862306a36Sopenharmony_ci				if (strcmp(sdt_name->s, next_sdt_name->s) == 0)
19962306a36Sopenharmony_ci					show_detail = true;
20062306a36Sopenharmony_ci				if (bid2)
20162306a36Sopenharmony_ci					*bid2 = '@';
20262306a36Sopenharmony_ci			}
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci		last_sdt_name = sdt_name->s;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		if (show_detail) {
20762306a36Sopenharmony_ci			char *path = build_id_cache__origname(bid);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci			if (path) {
21062306a36Sopenharmony_ci				if (asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid) < 0)
21162306a36Sopenharmony_ci					evt_name = NULL;
21262306a36Sopenharmony_ci				free(path);
21362306a36Sopenharmony_ci			}
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci		print_cb->print_event(print_state,
21662306a36Sopenharmony_ci				/*topic=*/NULL,
21762306a36Sopenharmony_ci				/*pmu_name=*/NULL,
21862306a36Sopenharmony_ci				evt_name ?: sdt_name->s,
21962306a36Sopenharmony_ci				/*event_alias=*/NULL,
22062306a36Sopenharmony_ci				/*deprecated=*/false,
22162306a36Sopenharmony_ci				/*scale_unit=*/NULL,
22262306a36Sopenharmony_ci				"SDT event",
22362306a36Sopenharmony_ci				/*desc=*/NULL,
22462306a36Sopenharmony_ci				/*long_desc=*/NULL,
22562306a36Sopenharmony_ci				/*encoding_desc=*/NULL);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		free(evt_name);
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci	strlist__delete(sdtlist);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cibool is_event_supported(u8 type, u64 config)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	bool ret = true;
23562306a36Sopenharmony_ci	struct evsel *evsel;
23662306a36Sopenharmony_ci	struct perf_event_attr attr = {
23762306a36Sopenharmony_ci		.type = type,
23862306a36Sopenharmony_ci		.config = config,
23962306a36Sopenharmony_ci		.disabled = 1,
24062306a36Sopenharmony_ci	};
24162306a36Sopenharmony_ci	struct perf_thread_map *tmap = thread_map__new_by_tid(0);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (tmap == NULL)
24462306a36Sopenharmony_ci		return false;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	evsel = evsel__new(&attr);
24762306a36Sopenharmony_ci	if (evsel) {
24862306a36Sopenharmony_ci		ret = evsel__open(evsel, NULL, tmap) >= 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		if (!ret) {
25162306a36Sopenharmony_ci			/*
25262306a36Sopenharmony_ci			 * The event may fail to open if the paranoid value
25362306a36Sopenharmony_ci			 * /proc/sys/kernel/perf_event_paranoid is set to 2
25462306a36Sopenharmony_ci			 * Re-run with exclude_kernel set; we don't do that by
25562306a36Sopenharmony_ci			 * default as some ARM machines do not support it.
25662306a36Sopenharmony_ci			 */
25762306a36Sopenharmony_ci			evsel->core.attr.exclude_kernel = 1;
25862306a36Sopenharmony_ci			ret = evsel__open(evsel, NULL, tmap) >= 0;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (!ret) {
26262306a36Sopenharmony_ci			/*
26362306a36Sopenharmony_ci			 * The event may fail to open if the PMU requires
26462306a36Sopenharmony_ci			 * exclude_guest to be set (e.g. as the Apple M1 PMU
26562306a36Sopenharmony_ci			 * requires).
26662306a36Sopenharmony_ci			 * Re-run with exclude_guest set; we don't do that by
26762306a36Sopenharmony_ci			 * default as it's equally legitimate for another PMU
26862306a36Sopenharmony_ci			 * driver to require that exclude_guest is clear.
26962306a36Sopenharmony_ci			 */
27062306a36Sopenharmony_ci			evsel->core.attr.exclude_guest = 1;
27162306a36Sopenharmony_ci			ret = evsel__open(evsel, NULL, tmap) >= 0;
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		evsel__delete(evsel);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	perf_thread_map__put(tmap);
27862306a36Sopenharmony_ci	return ret;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ciint print_hwcache_events(const struct print_callbacks *print_cb, void *print_state)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct perf_pmu *pmu = NULL;
28462306a36Sopenharmony_ci	const char *event_type_descriptor = event_type_descriptors[PERF_TYPE_HW_CACHE];
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * Only print core PMUs, skipping uncore for performance and
28862306a36Sopenharmony_ci	 * PERF_TYPE_SOFTWARE that can succeed in opening legacy cache evenst.
28962306a36Sopenharmony_ci	 */
29062306a36Sopenharmony_ci	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
29162306a36Sopenharmony_ci		if (pmu->is_uncore || pmu->type == PERF_TYPE_SOFTWARE)
29262306a36Sopenharmony_ci			continue;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		for (int type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
29562306a36Sopenharmony_ci			for (int op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
29662306a36Sopenharmony_ci				/* skip invalid cache type */
29762306a36Sopenharmony_ci				if (!evsel__is_cache_op_valid(type, op))
29862306a36Sopenharmony_ci					continue;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci				for (int res = 0; res < PERF_COUNT_HW_CACHE_RESULT_MAX; res++) {
30162306a36Sopenharmony_ci					char name[64];
30262306a36Sopenharmony_ci					char alias_name[128];
30362306a36Sopenharmony_ci					__u64 config;
30462306a36Sopenharmony_ci					int ret;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci					__evsel__hw_cache_type_op_res_name(type, op, res,
30762306a36Sopenharmony_ci									name, sizeof(name));
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci					ret = parse_events__decode_legacy_cache(name, pmu->type,
31062306a36Sopenharmony_ci										&config);
31162306a36Sopenharmony_ci					if (ret || !is_event_supported(PERF_TYPE_HW_CACHE, config))
31262306a36Sopenharmony_ci						continue;
31362306a36Sopenharmony_ci					snprintf(alias_name, sizeof(alias_name), "%s/%s/",
31462306a36Sopenharmony_ci						 pmu->name, name);
31562306a36Sopenharmony_ci					print_cb->print_event(print_state,
31662306a36Sopenharmony_ci							"cache",
31762306a36Sopenharmony_ci							pmu->name,
31862306a36Sopenharmony_ci							name,
31962306a36Sopenharmony_ci							alias_name,
32062306a36Sopenharmony_ci							/*scale_unit=*/NULL,
32162306a36Sopenharmony_ci							/*deprecated=*/false,
32262306a36Sopenharmony_ci							event_type_descriptor,
32362306a36Sopenharmony_ci							/*desc=*/NULL,
32462306a36Sopenharmony_ci							/*long_desc=*/NULL,
32562306a36Sopenharmony_ci							/*encoding_desc=*/NULL);
32662306a36Sopenharmony_ci				}
32762306a36Sopenharmony_ci			}
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_civoid print_tool_events(const struct print_callbacks *print_cb, void *print_state)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	// Start at 1 because the first enum entry means no tool event.
33662306a36Sopenharmony_ci	for (int i = 1; i < PERF_TOOL_MAX; ++i) {
33762306a36Sopenharmony_ci		print_cb->print_event(print_state,
33862306a36Sopenharmony_ci				"tool",
33962306a36Sopenharmony_ci				/*pmu_name=*/NULL,
34062306a36Sopenharmony_ci				event_symbols_tool[i].symbol,
34162306a36Sopenharmony_ci				event_symbols_tool[i].alias,
34262306a36Sopenharmony_ci				/*scale_unit=*/NULL,
34362306a36Sopenharmony_ci				/*deprecated=*/false,
34462306a36Sopenharmony_ci				"Tool event",
34562306a36Sopenharmony_ci				/*desc=*/NULL,
34662306a36Sopenharmony_ci				/*long_desc=*/NULL,
34762306a36Sopenharmony_ci				/*encoding_desc=*/NULL);
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_civoid print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
35262306a36Sopenharmony_ci			 unsigned int type, const struct event_symbol *syms,
35362306a36Sopenharmony_ci			 unsigned int max)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct strlist *evt_name_list = strlist__new(NULL, NULL);
35662306a36Sopenharmony_ci	struct str_node *nd;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (!evt_name_list) {
35962306a36Sopenharmony_ci		pr_debug("Failed to allocate new strlist for symbol events\n");
36062306a36Sopenharmony_ci		return;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci	for (unsigned int i = 0; i < max; i++) {
36362306a36Sopenharmony_ci		/*
36462306a36Sopenharmony_ci		 * New attr.config still not supported here, the latest
36562306a36Sopenharmony_ci		 * example was PERF_COUNT_SW_CGROUP_SWITCHES
36662306a36Sopenharmony_ci		 */
36762306a36Sopenharmony_ci		if (syms[i].symbol == NULL)
36862306a36Sopenharmony_ci			continue;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (!is_event_supported(type, i))
37162306a36Sopenharmony_ci			continue;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		if (strlen(syms[i].alias)) {
37462306a36Sopenharmony_ci			char name[MAX_NAME_LEN];
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			snprintf(name, MAX_NAME_LEN, "%s OR %s", syms[i].symbol, syms[i].alias);
37762306a36Sopenharmony_ci			strlist__add(evt_name_list, name);
37862306a36Sopenharmony_ci		} else
37962306a36Sopenharmony_ci			strlist__add(evt_name_list, syms[i].symbol);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	strlist__for_each_entry(nd, evt_name_list) {
38362306a36Sopenharmony_ci		char *alias = strstr(nd->s, " OR ");
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		if (alias) {
38662306a36Sopenharmony_ci			*alias = '\0';
38762306a36Sopenharmony_ci			alias += 4;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci		print_cb->print_event(print_state,
39062306a36Sopenharmony_ci				/*topic=*/NULL,
39162306a36Sopenharmony_ci				/*pmu_name=*/NULL,
39262306a36Sopenharmony_ci				nd->s,
39362306a36Sopenharmony_ci				alias,
39462306a36Sopenharmony_ci				/*scale_unit=*/NULL,
39562306a36Sopenharmony_ci				/*deprecated=*/false,
39662306a36Sopenharmony_ci				event_type_descriptors[type],
39762306a36Sopenharmony_ci				/*desc=*/NULL,
39862306a36Sopenharmony_ci				/*long_desc=*/NULL,
39962306a36Sopenharmony_ci				/*encoding_desc=*/NULL);
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci	strlist__delete(evt_name_list);
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci/*
40562306a36Sopenharmony_ci * Print the help text for the event symbols:
40662306a36Sopenharmony_ci */
40762306a36Sopenharmony_civoid print_events(const struct print_callbacks *print_cb, void *print_state)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE,
41062306a36Sopenharmony_ci			event_symbols_hw, PERF_COUNT_HW_MAX);
41162306a36Sopenharmony_ci	print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE,
41262306a36Sopenharmony_ci			event_symbols_sw, PERF_COUNT_SW_MAX);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	print_tool_events(print_cb, print_state);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	print_hwcache_events(print_cb, print_state);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	perf_pmus__print_pmu_events(print_cb, print_state);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	print_cb->print_event(print_state,
42162306a36Sopenharmony_ci			/*topic=*/NULL,
42262306a36Sopenharmony_ci			/*pmu_name=*/NULL,
42362306a36Sopenharmony_ci			"rNNN",
42462306a36Sopenharmony_ci			/*event_alias=*/NULL,
42562306a36Sopenharmony_ci			/*scale_unit=*/NULL,
42662306a36Sopenharmony_ci			/*deprecated=*/false,
42762306a36Sopenharmony_ci			event_type_descriptors[PERF_TYPE_RAW],
42862306a36Sopenharmony_ci			/*desc=*/NULL,
42962306a36Sopenharmony_ci			/*long_desc=*/NULL,
43062306a36Sopenharmony_ci			/*encoding_desc=*/NULL);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	print_cb->print_event(print_state,
43362306a36Sopenharmony_ci			/*topic=*/NULL,
43462306a36Sopenharmony_ci			/*pmu_name=*/NULL,
43562306a36Sopenharmony_ci			"cpu/t1=v1[,t2=v2,t3 ...]/modifier",
43662306a36Sopenharmony_ci			/*event_alias=*/NULL,
43762306a36Sopenharmony_ci			/*scale_unit=*/NULL,
43862306a36Sopenharmony_ci			/*deprecated=*/false,
43962306a36Sopenharmony_ci			event_type_descriptors[PERF_TYPE_RAW],
44062306a36Sopenharmony_ci			"(see 'man perf-list' on how to encode it)",
44162306a36Sopenharmony_ci			/*long_desc=*/NULL,
44262306a36Sopenharmony_ci			/*encoding_desc=*/NULL);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	print_cb->print_event(print_state,
44562306a36Sopenharmony_ci			/*topic=*/NULL,
44662306a36Sopenharmony_ci			/*pmu_name=*/NULL,
44762306a36Sopenharmony_ci			"mem:<addr>[/len][:access]",
44862306a36Sopenharmony_ci			/*scale_unit=*/NULL,
44962306a36Sopenharmony_ci			/*event_alias=*/NULL,
45062306a36Sopenharmony_ci			/*deprecated=*/false,
45162306a36Sopenharmony_ci			event_type_descriptors[PERF_TYPE_BREAKPOINT],
45262306a36Sopenharmony_ci			/*desc=*/NULL,
45362306a36Sopenharmony_ci			/*long_desc=*/NULL,
45462306a36Sopenharmony_ci			/*encoding_desc=*/NULL);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	print_tracepoint_events(print_cb, print_state);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	print_sdt_events(print_cb, print_state);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	metricgroup__print(print_cb, print_state);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	print_libpfm_events(print_cb, print_state);
46362306a36Sopenharmony_ci}
464