cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pfm.c (6028B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Support for libpfm4 event encoding.
      4 *
      5 * Copyright 2020 Google LLC.
      6 */
      7#include "util/cpumap.h"
      8#include "util/debug.h"
      9#include "util/event.h"
     10#include "util/evlist.h"
     11#include "util/evsel.h"
     12#include "util/parse-events.h"
     13#include "util/pmu.h"
     14#include "util/pfm.h"
     15
     16#include <string.h>
     17#include <linux/kernel.h>
     18#include <perfmon/pfmlib_perf_event.h>
     19
     20static void libpfm_initialize(void)
     21{
     22	int ret;
     23
     24	ret = pfm_initialize();
     25	if (ret != PFM_SUCCESS) {
     26		ui__warning("libpfm failed to initialize: %s\n",
     27			pfm_strerror(ret));
     28	}
     29}
     30
     31int parse_libpfm_events_option(const struct option *opt, const char *str,
     32			int unset __maybe_unused)
     33{
     34	struct evlist *evlist = *(struct evlist **)opt->value;
     35	struct perf_event_attr attr;
     36	struct perf_pmu *pmu;
     37	struct evsel *evsel, *grp_leader = NULL;
     38	char *p, *q, *p_orig;
     39	const char *sep;
     40	int grp_evt = -1;
     41	int ret;
     42
     43	libpfm_initialize();
     44
     45	p_orig = p = strdup(str);
     46	if (!p)
     47		return -1;
     48	/*
     49	 * force loading of the PMU list
     50	 */
     51	perf_pmu__scan(NULL);
     52
     53	for (q = p; strsep(&p, ",{}"); q = p) {
     54		sep = p ? str + (p - p_orig - 1) : "";
     55		if (*sep == '{') {
     56			if (grp_evt > -1) {
     57				ui__error(
     58					"nested event groups not supported\n");
     59				goto error;
     60			}
     61			grp_evt++;
     62		}
     63
     64		/* no event */
     65		if (*q == '\0') {
     66			if (*sep == '}') {
     67				if (grp_evt < 0) {
     68					ui__error("cannot close a non-existing event group\n");
     69					goto error;
     70				}
     71				grp_evt--;
     72			}
     73			continue;
     74		}
     75
     76		memset(&attr, 0, sizeof(attr));
     77		event_attr_init(&attr);
     78
     79		ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3,
     80						&attr, NULL, NULL);
     81
     82		if (ret != PFM_SUCCESS) {
     83			ui__error("failed to parse event %s : %s\n", str,
     84				  pfm_strerror(ret));
     85			goto error;
     86		}
     87
     88		pmu = perf_pmu__find_by_type((unsigned int)attr.type);
     89		evsel = parse_events__add_event(evlist->core.nr_entries,
     90						&attr, q, /*metric_id=*/NULL,
     91						pmu);
     92		if (evsel == NULL)
     93			goto error;
     94
     95		evsel->is_libpfm_event = true;
     96
     97		evlist__add(evlist, evsel);
     98
     99		if (grp_evt == 0)
    100			grp_leader = evsel;
    101
    102		if (grp_evt > -1) {
    103			evsel__set_leader(evsel, grp_leader);
    104			grp_leader->core.nr_members++;
    105			grp_evt++;
    106		}
    107
    108		if (*sep == '}') {
    109			if (grp_evt < 0) {
    110				ui__error(
    111				   "cannot close a non-existing event group\n");
    112				goto error;
    113			}
    114			evlist->core.nr_groups++;
    115			grp_leader = NULL;
    116			grp_evt = -1;
    117		}
    118	}
    119	free(p_orig);
    120	return 0;
    121error:
    122	free(p_orig);
    123	return -1;
    124}
    125
    126static const char *srcs[PFM_ATTR_CTRL_MAX] = {
    127	[PFM_ATTR_CTRL_UNKNOWN] = "???",
    128	[PFM_ATTR_CTRL_PMU] = "PMU",
    129	[PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
    130};
    131
    132static void
    133print_attr_flags(pfm_event_attr_info_t *info)
    134{
    135	int n = 0;
    136
    137	if (info->is_dfl) {
    138		printf("[default] ");
    139		n++;
    140	}
    141
    142	if (info->is_precise) {
    143		printf("[precise] ");
    144		n++;
    145	}
    146
    147	if (!n)
    148		printf("- ");
    149}
    150
    151static void
    152print_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc)
    153{
    154	pfm_event_attr_info_t ainfo;
    155	const char *src;
    156	int j, ret;
    157
    158	ainfo.size = sizeof(ainfo);
    159
    160	printf("  %s\n", info->name);
    161	printf("    [%s]\n", info->desc);
    162	if (long_desc) {
    163		if (info->equiv)
    164			printf("      Equiv: %s\n", info->equiv);
    165
    166		printf("      Code  : 0x%"PRIx64"\n", info->code);
    167	}
    168	pfm_for_each_event_attr(j, info) {
    169		ret = pfm_get_event_attr_info(info->idx, j,
    170					      PFM_OS_PERF_EVENT_EXT, &ainfo);
    171		if (ret != PFM_SUCCESS)
    172			continue;
    173
    174		if (ainfo.type == PFM_ATTR_UMASK) {
    175			printf("      %s:%s\n", info->name, ainfo.name);
    176			printf("        [%s]\n", ainfo.desc);
    177		}
    178
    179		if (!long_desc)
    180			continue;
    181
    182		if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
    183			ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
    184
    185		src = srcs[ainfo.ctrl];
    186		switch (ainfo.type) {
    187		case PFM_ATTR_UMASK:
    188			printf("        Umask : 0x%02"PRIx64" : %s: ",
    189				ainfo.code, src);
    190			print_attr_flags(&ainfo);
    191			putchar('\n');
    192			break;
    193		case PFM_ATTR_MOD_BOOL:
    194			printf("      Modif : %s: [%s] : %s (boolean)\n", src,
    195				ainfo.name, ainfo.desc);
    196			break;
    197		case PFM_ATTR_MOD_INTEGER:
    198			printf("      Modif : %s: [%s] : %s (integer)\n", src,
    199				ainfo.name, ainfo.desc);
    200			break;
    201		case PFM_ATTR_NONE:
    202		case PFM_ATTR_RAW_UMASK:
    203		case PFM_ATTR_MAX:
    204		default:
    205			printf("      Attr  : %s: [%s] : %s\n", src,
    206				ainfo.name, ainfo.desc);
    207		}
    208	}
    209}
    210
    211/*
    212 * list all pmu::event:umask, pmu::event
    213 * printed events may not be all valid combinations of umask for an event
    214 */
    215static void
    216print_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
    217{
    218	pfm_event_attr_info_t ainfo;
    219	int j, ret;
    220	bool has_umask = false;
    221
    222	ainfo.size = sizeof(ainfo);
    223
    224	pfm_for_each_event_attr(j, info) {
    225		ret = pfm_get_event_attr_info(info->idx, j,
    226					      PFM_OS_PERF_EVENT_EXT, &ainfo);
    227		if (ret != PFM_SUCCESS)
    228			continue;
    229
    230		if (ainfo.type != PFM_ATTR_UMASK)
    231			continue;
    232
    233		printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
    234		has_umask = true;
    235	}
    236	if (!has_umask)
    237		printf("%s::%s\n", pinfo->name, info->name);
    238}
    239
    240void print_libpfm_events(bool name_only, bool long_desc)
    241{
    242	pfm_event_info_t info;
    243	pfm_pmu_info_t pinfo;
    244	int i, p, ret;
    245
    246	libpfm_initialize();
    247
    248	/* initialize to zero to indicate ABI version */
    249	info.size  = sizeof(info);
    250	pinfo.size = sizeof(pinfo);
    251
    252	if (!name_only)
    253		puts("\nList of pre-defined events (to be used in --pfm-events):\n");
    254
    255	pfm_for_all_pmus(p) {
    256		bool printed_pmu = false;
    257
    258		ret = pfm_get_pmu_info(p, &pinfo);
    259		if (ret != PFM_SUCCESS)
    260			continue;
    261
    262		/* only print events that are supported by host HW */
    263		if (!pinfo.is_present)
    264			continue;
    265
    266		/* handled by perf directly */
    267		if (pinfo.pmu == PFM_PMU_PERF_EVENT)
    268			continue;
    269
    270		for (i = pinfo.first_event; i != -1;
    271		     i = pfm_get_event_next(i)) {
    272
    273			ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT,
    274						&info);
    275			if (ret != PFM_SUCCESS)
    276				continue;
    277
    278			if (!name_only && !printed_pmu) {
    279				printf("%s:\n", pinfo.name);
    280				printed_pmu = true;
    281			}
    282
    283			if (!name_only)
    284				print_libpfm_events_detailed(&info, long_desc);
    285			else
    286				print_libpfm_events_raw(&pinfo, &info);
    287		}
    288		if (!name_only && printed_pmu)
    289			putchar('\n');
    290	}
    291}