mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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;
|
||||||
|
|
||||||
|
if (tool_pmu__skip_event(str))
|
||||||
|
return TOOL_PMU__EVENT_NONE;
|
||||||
|
|
||||||
tool_pmu__for_each_event(i) {
|
tool_pmu__for_each_event(i) {
|
||||||
if (!strcasecmp(str, tool_pmu__event_names[i])) {
|
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;
|
|
||||||
#endif
|
|
||||||
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…
Add table
Reference in a new issue