forked from mirrors/linux
		
	perf tool_pmu: Switch to standard pmu functions and json descriptions
Use the regular PMU approaches with tool json events to reduce the amount of special tool_pmu code - tool_pmu__config_terms and tool_pmu__for_each_event_cb are removed. Some functions remain, like tool_pmu__str_to_event, as conveniences to metricgroups. Add tool_pmu__skip_event/tool_pmu__num_skip_events to handle the case that tool json events shouldn't appear on certain architectures. This isn't done in jevents.py due to complexity in the empty-pmu-events.c and when all vendor json is built into the tool. Signed-off-by: Ian Rogers <irogers@google.com> Acked-by: Namhyung Kim <namhyung@kernel.org> Link: https://lore.kernel.org/r/20241002032016.333748-10-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
		
							parent
							
								
									c9b121b7fa
								
							
						
					
					
						commit
						609aa2667f
					
				
					 4 changed files with 47 additions and 106 deletions
				
			
		| 
						 | 
					@ -1549,9 +1549,6 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool zero = !!pmu->perf_event_attr_init_default;
 | 
						bool zero = !!pmu->perf_event_attr_init_default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu))
 | 
					 | 
				
			||||||
		return tool_pmu__config_terms(attr, head_terms, err);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Fake PMU doesn't have proper terms so nothing to configure in attr. */
 | 
						/* Fake PMU doesn't have proper terms so nothing to configure in attr. */
 | 
				
			||||||
	if (perf_pmu__is_fake(pmu))
 | 
						if (perf_pmu__is_fake(pmu))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					@ -1664,8 +1661,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
 | 
				
			||||||
	info->scale    = 0.0;
 | 
						info->scale    = 0.0;
 | 
				
			||||||
	info->snapshot = false;
 | 
						info->snapshot = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Tool/fake PMU doesn't rewrite terms. */
 | 
						/* Fake PMU doesn't rewrite terms. */
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu) || perf_pmu__is_fake(pmu))
 | 
						if (perf_pmu__is_fake(pmu))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_safe(term, h, &head_terms->terms, list) {
 | 
						list_for_each_entry_safe(term, h, &head_terms->terms, list) {
 | 
				
			||||||
| 
						 | 
					@ -1835,8 +1832,8 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!name)
 | 
						if (!name)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu))
 | 
						if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(name))
 | 
				
			||||||
		return tool_pmu__str_to_event(name) != TOOL_PMU__EVENT_NONE;
 | 
							return false;
 | 
				
			||||||
	if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
 | 
						if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	if (pmu->cpu_aliases_added || !pmu->events_table)
 | 
						if (pmu->cpu_aliases_added || !pmu->events_table)
 | 
				
			||||||
| 
						 | 
					@ -1848,9 +1845,6 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t nr;
 | 
						size_t nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu))
 | 
					 | 
				
			||||||
		return tool_pmu__num_events();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pmu_aliases_parse(pmu);
 | 
						pmu_aliases_parse(pmu);
 | 
				
			||||||
	nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
 | 
						nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1861,6 +1855,9 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		assert(pmu->cpu_json_aliases == 0);
 | 
							assert(pmu->cpu_json_aliases == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (perf_pmu__is_tool(pmu))
 | 
				
			||||||
 | 
							nr -= tool_pmu__num_skip_events();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pmu->selectable ? nr + 1 : nr;
 | 
						return pmu->selectable ? nr + 1 : nr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1911,15 +1908,15 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
	struct strbuf sb;
 | 
						struct strbuf sb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu))
 | 
					 | 
				
			||||||
		return tool_pmu__for_each_event_cb(pmu, state, cb);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strbuf_init(&sb, /*hint=*/ 0);
 | 
						strbuf_init(&sb, /*hint=*/ 0);
 | 
				
			||||||
	pmu_aliases_parse(pmu);
 | 
						pmu_aliases_parse(pmu);
 | 
				
			||||||
	pmu_add_cpu_aliases(pmu);
 | 
						pmu_add_cpu_aliases(pmu);
 | 
				
			||||||
	list_for_each_entry(event, &pmu->aliases, list) {
 | 
						list_for_each_entry(event, &pmu->aliases, list) {
 | 
				
			||||||
		size_t buf_used, pmu_name_len;
 | 
							size_t buf_used, pmu_name_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		info.pmu_name = event->pmu_name ?: pmu->name;
 | 
							info.pmu_name = event->pmu_name ?: pmu->name;
 | 
				
			||||||
		pmu_name_len = pmu_deduped_name_len(pmu, info.pmu_name,
 | 
							pmu_name_len = pmu_deduped_name_len(pmu, info.pmu_name,
 | 
				
			||||||
						    skip_duplicate_pmus);
 | 
											    skip_duplicate_pmus);
 | 
				
			||||||
| 
						 | 
					@ -2325,9 +2322,6 @@ const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
 | 
				
			||||||
	if (!pmu)
 | 
						if (!pmu)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (perf_pmu__is_tool(pmu))
 | 
					 | 
				
			||||||
		return tool_pmu__event_to_str(config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pmu_aliases_parse(pmu);
 | 
						pmu_aliases_parse(pmu);
 | 
				
			||||||
	pmu_add_cpu_aliases(pmu);
 | 
						pmu_add_cpu_aliases(pmu);
 | 
				
			||||||
	list_for_each_entry(event, &pmu->aliases, list) {
 | 
						list_for_each_entry(event, &pmu->aliases, list) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -440,6 +440,7 @@ static int perf_pmus__print_pmu_events__callback(void *vstate,
 | 
				
			||||||
		pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name);
 | 
							pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name);
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						assert(info->pmu != NULL || info->name != NULL);
 | 
				
			||||||
	s = &state->aliases[state->index];
 | 
						s = &state->aliases[state->index];
 | 
				
			||||||
	s->pmu = info->pmu;
 | 
						s->pmu = info->pmu;
 | 
				
			||||||
#define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL
 | 
					#define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL
 | 
				
			||||||
| 
						 | 
					@ -590,9 +591,6 @@ void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, voi
 | 
				
			||||||
		int len = pmu_name_len_no_suffix(pmu->name);
 | 
							int len = pmu_name_len_no_suffix(pmu->name);
 | 
				
			||||||
		const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
 | 
							const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (perf_pmu__is_tool(pmu))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!pmu->is_core)
 | 
							if (!pmu->is_core)
 | 
				
			||||||
			desc = NULL;
 | 
								desc = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,33 @@ static const char *const tool_pmu__event_names[TOOL_PMU__EVENT_MAX] = {
 | 
				
			||||||
	"system_tsc_freq",
 | 
						"system_tsc_freq",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool tool_pmu__skip_event(const char *name __maybe_unused)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if !defined(__aarch64__)
 | 
				
			||||||
 | 
						/* The slots event should only appear on arm64. */
 | 
				
			||||||
 | 
						if (strcasecmp(name, "slots") == 0)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(__i386__) && !defined(__x86_64__)
 | 
				
			||||||
 | 
						/* The system_tsc_freq event should only appear on x86. */
 | 
				
			||||||
 | 
						if (strcasecmp(name, "system_tsc_freq") == 0)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tool_pmu__num_skip_events(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int num = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(__aarch64__)
 | 
				
			||||||
 | 
						num++;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(__i386__) && !defined(__x86_64__)
 | 
				
			||||||
 | 
						num++;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *tool_pmu__event_to_str(enum tool_pmu_event ev)
 | 
					const char *tool_pmu__event_to_str(enum tool_pmu_event ev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -46,90 +73,16 @@ enum tool_pmu_event tool_pmu__str_to_event(const char *str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tool_pmu__for_each_event(i) {
 | 
						if (tool_pmu__skip_event(str))
 | 
				
			||||||
		if (!strcasecmp(str, tool_pmu__event_names[i])) {
 | 
					 | 
				
			||||||
#if !defined(__aarch64__)
 | 
					 | 
				
			||||||
			/* The slots event should only appear on arm64. */
 | 
					 | 
				
			||||||
			if (i == TOOL_PMU__EVENT_SLOTS)
 | 
					 | 
				
			||||||
		return TOOL_PMU__EVENT_NONE;
 | 
							return TOOL_PMU__EVENT_NONE;
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
 | 
						tool_pmu__for_each_event(i) {
 | 
				
			||||||
 | 
							if (!strcasecmp(str, tool_pmu__event_names[i]))
 | 
				
			||||||
			return i;
 | 
								return i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return TOOL_PMU__EVENT_NONE;
 | 
						return TOOL_PMU__EVENT_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tool_pmu__config_term(struct perf_event_attr *attr,
 | 
					 | 
				
			||||||
				 struct parse_events_term *term,
 | 
					 | 
				
			||||||
				 struct parse_events_error *err)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
 | 
					 | 
				
			||||||
		enum tool_pmu_event ev = tool_pmu__str_to_event(term->config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ev == TOOL_PMU__EVENT_NONE)
 | 
					 | 
				
			||||||
			goto err_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		attr->config = ev;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
err_out:
 | 
					 | 
				
			||||||
	if (err) {
 | 
					 | 
				
			||||||
		char *err_str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		parse_events_error__handle(err, term->err_val,
 | 
					 | 
				
			||||||
					asprintf(&err_str,
 | 
					 | 
				
			||||||
						"unexpected tool event term (%s) %s",
 | 
					 | 
				
			||||||
						parse_events__term_type_str(term->type_term),
 | 
					 | 
				
			||||||
						term->config) < 0
 | 
					 | 
				
			||||||
					? strdup("unexpected tool event term")
 | 
					 | 
				
			||||||
					: err_str,
 | 
					 | 
				
			||||||
					NULL);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tool_pmu__config_terms(struct perf_event_attr *attr,
 | 
					 | 
				
			||||||
			   struct parse_events_terms *terms,
 | 
					 | 
				
			||||||
			   struct parse_events_error *err)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct parse_events_term *term;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_for_each_entry(term, &terms->terms, list) {
 | 
					 | 
				
			||||||
		if (tool_pmu__config_term(attr, term, err))
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pmu_event_info info = {
 | 
					 | 
				
			||||||
		.pmu = pmu,
 | 
					 | 
				
			||||||
		.event_type_desc = "Tool event",
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tool_pmu__for_each_event(i) {
 | 
					 | 
				
			||||||
		int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		info.name = tool_pmu__event_to_str(i);
 | 
					 | 
				
			||||||
		info.alias = NULL;
 | 
					 | 
				
			||||||
		info.scale_unit = NULL;
 | 
					 | 
				
			||||||
		info.desc = NULL;
 | 
					 | 
				
			||||||
		info.long_desc = NULL;
 | 
					 | 
				
			||||||
		info.encoding_desc = NULL;
 | 
					 | 
				
			||||||
		info.topic = NULL;
 | 
					 | 
				
			||||||
		info.pmu_name = pmu->name;
 | 
					 | 
				
			||||||
		info.deprecated = false;
 | 
					 | 
				
			||||||
		ret = cb(state, &info);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool perf_pmu__is_tool(const struct perf_pmu *pmu)
 | 
					bool perf_pmu__is_tool(const struct perf_pmu *pmu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return pmu && pmu->type == PERF_PMU_TYPE_TOOL;
 | 
						return pmu && pmu->type == PERF_PMU_TYPE_TOOL;
 | 
				
			||||||
| 
						 | 
					@ -546,6 +499,8 @@ struct perf_pmu *perf_pmus__tool_pmu(void)
 | 
				
			||||||
		.caps = LIST_HEAD_INIT(tool.caps),
 | 
							.caps = LIST_HEAD_INIT(tool.caps),
 | 
				
			||||||
		.format = LIST_HEAD_INIT(tool.format),
 | 
							.format = LIST_HEAD_INIT(tool.format),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
						if (!tool.events_table)
 | 
				
			||||||
 | 
							tool.events_table = find_core_events_table("common", "common");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &tool;
 | 
						return &tool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,17 +29,11 @@ enum tool_pmu_event {
 | 
				
			||||||
#define tool_pmu__for_each_event(ev)					\
 | 
					#define tool_pmu__for_each_event(ev)					\
 | 
				
			||||||
	for ((ev) = TOOL_PMU__EVENT_DURATION_TIME; (ev) < TOOL_PMU__EVENT_MAX; ev++)
 | 
						for ((ev) = TOOL_PMU__EVENT_DURATION_TIME; (ev) < TOOL_PMU__EVENT_MAX; ev++)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline size_t tool_pmu__num_events(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return TOOL_PMU__EVENT_MAX - 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *tool_pmu__event_to_str(enum tool_pmu_event ev);
 | 
					const char *tool_pmu__event_to_str(enum tool_pmu_event ev);
 | 
				
			||||||
enum tool_pmu_event tool_pmu__str_to_event(const char *str);
 | 
					enum tool_pmu_event tool_pmu__str_to_event(const char *str);
 | 
				
			||||||
int tool_pmu__config_terms(struct perf_event_attr *attr,
 | 
					bool tool_pmu__skip_event(const char *name);
 | 
				
			||||||
			   struct parse_events_terms *terms,
 | 
					int tool_pmu__num_skip_events(void);
 | 
				
			||||||
			   struct parse_events_error *err);
 | 
					
 | 
				
			||||||
int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb);
 | 
					 | 
				
			||||||
bool tool_pmu__read_event(enum tool_pmu_event ev, u64 *result);
 | 
					bool tool_pmu__read_event(enum tool_pmu_event ev, u64 *result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u64 tool_pmu__cpu_slots_per_cycle(void);
 | 
					u64 tool_pmu__cpu_slots_per_cycle(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue