Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.9.4.
  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, char *name,
 42			       struct list_head *config_terms,
 43			       struct perf_pmu *pmu)
 44{
 45	struct evsel *evsel;
 46	__u32 type = attr->type;
 47	__u64 config = attr->config;
 48
 49	config_hybrid_attr(attr, config_type, pmu->type);
 50	evsel = parse_events__add_event_hybrid(list, idx, attr, name,
 51					       pmu, config_terms);
 52	if (evsel)
 53		evsel->pmu_name = strdup(pmu->name);
 54	else
 55		return -ENOMEM;
 56
 57	attr->type = type;
 58	attr->config = config;
 59	return 0;
 60}
 61
 62static int pmu_cmp(struct parse_events_state *parse_state,
 63		   struct perf_pmu *pmu)
 64{
 65	if (!parse_state->hybrid_pmu_name)
 66		return 0;
 67
 68	return strcmp(parse_state->hybrid_pmu_name, pmu->name);
 69}
 70
 71static int add_hw_hybrid(struct parse_events_state *parse_state,
 72			 struct list_head *list, struct perf_event_attr *attr,
 73			 char *name, struct list_head *config_terms)
 74{
 75	struct perf_pmu *pmu;
 76	int ret;
 77
 78	perf_pmu__for_each_hybrid_pmu(pmu) {
 79		if (pmu_cmp(parse_state, pmu))
 80			continue;
 81
 82		ret = create_event_hybrid(PERF_TYPE_HARDWARE,
 83					  &parse_state->idx, list, attr, name,
 84					  config_terms, pmu);
 85		if (ret)
 86			return ret;
 87	}
 88
 89	return 0;
 90}
 91
 92static int create_raw_event_hybrid(int *idx, struct list_head *list,
 93				   struct perf_event_attr *attr, char *name,
 94				   struct list_head *config_terms,
 95				   struct perf_pmu *pmu)
 96{
 97	struct evsel *evsel;
 98
 99	attr->type = pmu->type;
100	evsel = parse_events__add_event_hybrid(list, idx, attr, name,
101					       pmu, config_terms);
102	if (evsel)
103		evsel->pmu_name = strdup(pmu->name);
104	else
105		return -ENOMEM;
106
107	return 0;
108}
109
110static int add_raw_hybrid(struct parse_events_state *parse_state,
111			  struct list_head *list, struct perf_event_attr *attr,
112			  char *name, struct list_head *config_terms)
113{
114	struct perf_pmu *pmu;
115	int ret;
116
117	perf_pmu__for_each_hybrid_pmu(pmu) {
118		if (pmu_cmp(parse_state, pmu))
119			continue;
120
121		ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
122					      name, config_terms, pmu);
123		if (ret)
124			return ret;
125	}
126
127	return 0;
128}
129
130int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
131				     struct list_head *list,
132				     struct perf_event_attr *attr,
133				     char *name, struct list_head *config_terms,
134				     bool *hybrid)
135{
136	*hybrid = false;
137	if (attr->type == PERF_TYPE_SOFTWARE)
138		return 0;
139
140	if (!perf_pmu__has_hybrid())
141		return 0;
142
143	*hybrid = true;
144	if (attr->type != PERF_TYPE_RAW) {
145		return add_hw_hybrid(parse_state, list, attr, name,
146				     config_terms);
147	}
148
149	return add_raw_hybrid(parse_state, list, attr, name,
150			      config_terms);
151}
152
153int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
154				   struct perf_event_attr *attr, char *name,
155				   struct list_head *config_terms,
156				   bool *hybrid,
157				   struct parse_events_state *parse_state)
158{
159	struct perf_pmu *pmu;
160	int ret;
161
162	*hybrid = false;
163	if (!perf_pmu__has_hybrid())
164		return 0;
165
166	*hybrid = true;
167	perf_pmu__for_each_hybrid_pmu(pmu) {
168		if (pmu_cmp(parse_state, pmu))
169			continue;
170
171		ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
172					  attr, name, config_terms, pmu);
173		if (ret)
174			return ret;
175	}
176
177	return 0;
178}