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

parse-events-hybrid.c (5133B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/err.h>
      3#include <linux/zalloc.h>
      4#include <errno.h>
      5#include <sys/types.h>
      6#include <sys/stat.h>
      7#include <fcntl.h>
      8#include <sys/param.h>
      9#include "evlist.h"
     10#include "evsel.h"
     11#include "parse-events.h"
     12#include "parse-events-hybrid.h"
     13#include "debug.h"
     14#include "pmu.h"
     15#include "pmu-hybrid.h"
     16#include "perf.h"
     17
     18static void config_hybrid_attr(struct perf_event_attr *attr,
     19			       int type, int pmu_type)
     20{
     21	/*
     22	 * attr.config layout for type PERF_TYPE_HARDWARE and
     23	 * PERF_TYPE_HW_CACHE
     24	 *
     25	 * PERF_TYPE_HARDWARE:                 0xEEEEEEEE000000AA
     26	 *                                     AA: hardware event ID
     27	 *                                     EEEEEEEE: PMU type ID
     28	 * PERF_TYPE_HW_CACHE:                 0xEEEEEEEE00DDCCBB
     29	 *                                     BB: hardware cache ID
     30	 *                                     CC: hardware cache op ID
     31	 *                                     DD: hardware cache op result ID
     32	 *                                     EEEEEEEE: PMU type ID
     33	 * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
     34	 */
     35	attr->type = type;
     36	attr->config = attr->config | ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
     37}
     38
     39static int create_event_hybrid(__u32 config_type, int *idx,
     40			       struct list_head *list,
     41			       struct perf_event_attr *attr, const char *name,
     42			       const char *metric_id,
     43			       struct list_head *config_terms,
     44			       struct perf_pmu *pmu)
     45{
     46	struct evsel *evsel;
     47	__u32 type = attr->type;
     48	__u64 config = attr->config;
     49
     50	config_hybrid_attr(attr, config_type, pmu->type);
     51	evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
     52					       pmu, config_terms);
     53	if (evsel)
     54		evsel->pmu_name = strdup(pmu->name);
     55	else
     56		return -ENOMEM;
     57
     58	attr->type = type;
     59	attr->config = config;
     60	return 0;
     61}
     62
     63static int pmu_cmp(struct parse_events_state *parse_state,
     64		   struct perf_pmu *pmu)
     65{
     66	if (parse_state->evlist && parse_state->evlist->hybrid_pmu_name)
     67		return strcmp(parse_state->evlist->hybrid_pmu_name, pmu->name);
     68
     69	if (parse_state->hybrid_pmu_name)
     70		return strcmp(parse_state->hybrid_pmu_name, pmu->name);
     71
     72	return 0;
     73}
     74
     75static int add_hw_hybrid(struct parse_events_state *parse_state,
     76			 struct list_head *list, struct perf_event_attr *attr,
     77			 const char *name, const char *metric_id,
     78			 struct list_head *config_terms)
     79{
     80	struct perf_pmu *pmu;
     81	int ret;
     82
     83	perf_pmu__for_each_hybrid_pmu(pmu) {
     84		LIST_HEAD(terms);
     85
     86		if (pmu_cmp(parse_state, pmu))
     87			continue;
     88
     89		copy_config_terms(&terms, config_terms);
     90		ret = create_event_hybrid(PERF_TYPE_HARDWARE,
     91					  &parse_state->idx, list, attr, name,
     92					  metric_id, &terms, pmu);
     93		free_config_terms(&terms);
     94		if (ret)
     95			return ret;
     96	}
     97
     98	return 0;
     99}
    100
    101static int create_raw_event_hybrid(int *idx, struct list_head *list,
    102				   struct perf_event_attr *attr,
    103				   const char *name,
    104				   const char *metric_id,
    105				   struct list_head *config_terms,
    106				   struct perf_pmu *pmu)
    107{
    108	struct evsel *evsel;
    109
    110	attr->type = pmu->type;
    111	evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
    112					       pmu, config_terms);
    113	if (evsel)
    114		evsel->pmu_name = strdup(pmu->name);
    115	else
    116		return -ENOMEM;
    117
    118	return 0;
    119}
    120
    121static int add_raw_hybrid(struct parse_events_state *parse_state,
    122			  struct list_head *list, struct perf_event_attr *attr,
    123			  const char *name, const char *metric_id,
    124			  struct list_head *config_terms)
    125{
    126	struct perf_pmu *pmu;
    127	int ret;
    128
    129	perf_pmu__for_each_hybrid_pmu(pmu) {
    130		LIST_HEAD(terms);
    131
    132		if (pmu_cmp(parse_state, pmu))
    133			continue;
    134
    135		copy_config_terms(&terms, config_terms);
    136		ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
    137					      name, metric_id, &terms, pmu);
    138		free_config_terms(&terms);
    139		if (ret)
    140			return ret;
    141	}
    142
    143	return 0;
    144}
    145
    146int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
    147				     struct list_head *list,
    148				     struct perf_event_attr *attr,
    149				     const char *name, const char *metric_id,
    150				     struct list_head *config_terms,
    151				     bool *hybrid)
    152{
    153	*hybrid = false;
    154	if (attr->type == PERF_TYPE_SOFTWARE)
    155		return 0;
    156
    157	if (!perf_pmu__has_hybrid())
    158		return 0;
    159
    160	*hybrid = true;
    161	if (attr->type != PERF_TYPE_RAW) {
    162		return add_hw_hybrid(parse_state, list, attr, name, metric_id,
    163				     config_terms);
    164	}
    165
    166	return add_raw_hybrid(parse_state, list, attr, name, metric_id,
    167			      config_terms);
    168}
    169
    170int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
    171				   struct perf_event_attr *attr,
    172				   const char *name,
    173				   const char *metric_id,
    174				   struct list_head *config_terms,
    175				   bool *hybrid,
    176				   struct parse_events_state *parse_state)
    177{
    178	struct perf_pmu *pmu;
    179	int ret;
    180
    181	*hybrid = false;
    182	if (!perf_pmu__has_hybrid())
    183		return 0;
    184
    185	*hybrid = true;
    186	perf_pmu__for_each_hybrid_pmu(pmu) {
    187		LIST_HEAD(terms);
    188
    189		if (pmu_cmp(parse_state, pmu))
    190			continue;
    191
    192		copy_config_terms(&terms, config_terms);
    193		ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
    194					  attr, name, metric_id, &terms, pmu);
    195		free_config_terms(&terms);
    196		if (ret)
    197			return ret;
    198	}
    199
    200	return 0;
    201}