@@ -1553,8 +1553,8 @@ static int sub_non_neg(int a, int b)
return a - b;
}
-static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
- struct perf_pmu_alias *alias)
+static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
+ const struct perf_pmu_alias *alias)
{
struct parse_events_term *term;
int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
@@ -1579,51 +1579,67 @@ static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
return buf;
}
-static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
- struct perf_pmu_alias *alias)
+static char *format_alias_or(char *buf, int len, const struct perf_pmu *pmu,
+ const struct perf_pmu_alias *alias)
{
snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
return buf;
}
+/** Struct for ordering events as output in perf list. */
struct sevent {
- char *name;
- char *desc;
- char *topic;
- char *str;
- char *pmu;
- char *metric_expr;
- char *metric_name;
- int is_cpu;
+ /** PMU for event. */
+ const struct perf_pmu *pmu;
+ /**
+ * Optional event for name, desc, etc. If not present then this is a
+ * selectable PMU and the event name is shown as "//".
+ */
+ const struct perf_pmu_alias *event;
+ /** Is the PMU for the CPU? */
+ bool is_cpu;
};
static int cmp_sevent(const void *a, const void *b)
{
const struct sevent *as = a;
const struct sevent *bs = b;
+ const char *a_pmu_name, *b_pmu_name;
+ const char *a_name = "//", *a_desc = NULL, *a_topic = "";
+ const char *b_name = "//", *b_desc = NULL, *b_topic = "";
int ret;
- /* Put extra events last */
- if (!!as->desc != !!bs->desc)
- return !!as->desc - !!bs->desc;
- if (as->topic && bs->topic) {
- int n = strcmp(as->topic, bs->topic);
-
- if (n)
- return n;
+ if (as->event) {
+ a_name = as->event->name;
+ a_desc = as->event->desc;
+ a_topic = as->event->topic ?: "";
}
+ if (bs->event) {
+ b_name = bs->event->name;
+ b_desc = bs->event->desc;
+ b_topic = bs->event->topic ?: "";
+ }
+ /* Put extra events last. */
+ if (!!a_desc != !!b_desc)
+ return !!a_desc - !!b_desc;
+
+ /* Order by topics. */
+ ret = strcmp(a_topic, b_topic);
+ if (ret)
+ return ret;
/* Order CPU core events to be first */
if (as->is_cpu != bs->is_cpu)
return bs->is_cpu - as->is_cpu;
- ret = strcmp(as->name, bs->name);
- if (!ret) {
- if (as->pmu && bs->pmu)
- return strcmp(as->pmu, bs->pmu);
- }
+ /* Order by PMU name. */
+ a_pmu_name = as->pmu->name ?: "";
+ b_pmu_name = bs->pmu->name ?: "";
+ ret = strcmp(a_pmu_name, b_pmu_name);
+ if (ret)
+ return ret;
- return ret;
+ /* Order by event name. */
+ return strcmp(a_name, b_name);
}
static void wordwrap(char *s, int start, int max, int corr)
@@ -1655,16 +1671,18 @@ bool is_pmu_core(const char *name)
static bool pmu_alias_is_duplicate(struct sevent *alias_a,
struct sevent *alias_b)
{
- /* Different names -> never duplicates */
- if (strcmp(alias_a->name, alias_b->name))
- return false;
+ const char *a_pmu_name, *b_pmu_name;
+ const char *a_name = alias_a->event ? alias_a->event->name : "//";
+ const char *b_name = alias_b->event ? alias_b->event->name : "//";
- /* Don't remove duplicates for hybrid PMUs */
- if (perf_pmu__is_hybrid(alias_a->pmu) &&
- perf_pmu__is_hybrid(alias_b->pmu))
+ /* Different names -> never duplicates */
+ if (strcmp(a_name, b_name))
return false;
- return true;
+ /* Don't remove duplicates for different PMUs */
+ a_pmu_name = alias_a->pmu->name ?: "";
+ b_pmu_name = alias_b->pmu->name ?: "";
+ return strcmp(a_pmu_name, b_pmu_name) == 0;
}
void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
@@ -1690,110 +1708,104 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
len++;
}
aliases = zalloc(sizeof(struct sevent) * len);
- if (!aliases)
- goto out_enomem;
+ if (!aliases) {
+ pr_err("FATAL: not enough memory to print PMU events\n");
+ return;
+ }
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ bool is_cpu;
+
if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name))
continue;
- list_for_each_entry(alias, &pmu->aliases, list) {
- char *name = alias->desc ? alias->name :
- format_alias(buf, sizeof(buf), pmu, alias);
- bool is_cpu = is_pmu_core(pmu->name) ||
- perf_pmu__is_hybrid(pmu->name);
+ is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name);
+ list_for_each_entry(alias, &pmu->aliases, list) {
if (alias->deprecated && !deprecated)
continue;
if (event_glob != NULL &&
- !(strglobmatch_nocase(name, event_glob) ||
- (!is_cpu && strglobmatch_nocase(alias->name,
- event_glob)) ||
+ !(strglobmatch_nocase(alias->name, event_glob) ||
+ (!is_cpu &&
+ strglobmatch_nocase(alias->name, event_glob)) ||
(alias->topic &&
strglobmatch_nocase(alias->topic, event_glob))))
continue;
- if (is_cpu && !name_only && !alias->desc)
- name = format_alias_or(buf, sizeof(buf), pmu, alias);
-
- aliases[j].name = name;
- if (is_cpu && !name_only && !alias->desc)
- aliases[j].name = format_alias_or(buf,
- sizeof(buf),
- pmu, alias);
- aliases[j].name = strdup(aliases[j].name);
- if (!aliases[j].name)
- goto out_enomem;
-
- aliases[j].desc = long_desc ? alias->long_desc :
- alias->desc;
- aliases[j].topic = alias->topic;
- aliases[j].str = alias->str;
- aliases[j].pmu = pmu->name;
- aliases[j].metric_expr = alias->metric_expr;
- aliases[j].metric_name = alias->metric_name;
+ aliases[j].event = alias;
+ aliases[j].pmu = pmu;
aliases[j].is_cpu = is_cpu;
j++;
}
if (pmu->selectable &&
(event_glob == NULL || strglobmatch(pmu->name, event_glob))) {
- char *s;
- if (asprintf(&s, "%s//", pmu->name) < 0)
- goto out_enomem;
- aliases[j].name = s;
+ aliases[j].event = NULL;
+ aliases[j].pmu = pmu;
+ aliases[j].is_cpu = is_cpu;
j++;
}
}
len = j;
qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
for (j = 0; j < len; j++) {
+ char *name, *desc;
+
/* Skip duplicates */
if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
continue;
+ if (!aliases[j].event) {
+ /* A selectable event. */
+ snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name);
+ name = buf;
+ } else if (aliases[j].event->desc) {
+ name = aliases[j].event->name;
+ } else {
+ if (!name_only && aliases[j].is_cpu) {
+ name = format_alias_or(buf, sizeof(buf), aliases[j].pmu,
+ aliases[j].event);
+ } else {
+ name = format_alias(buf, sizeof(buf), aliases[j].pmu,
+ aliases[j].event);
+ }
+ }
if (name_only) {
- printf("%s ", aliases[j].name);
+ printf("%s ", name);
continue;
}
- if (aliases[j].desc && !quiet_flag) {
- if (numdesc++ == 0)
- printf("\n");
- if (aliases[j].topic && (!topic ||
- strcmp(topic, aliases[j].topic))) {
- printf("%s%s:\n", topic ? "\n" : "",
- aliases[j].topic);
- topic = aliases[j].topic;
- }
- printf(" %-50s\n", aliases[j].name);
- printf("%*s", 8, "[");
- wordwrap(aliases[j].desc, 8, columns, 0);
- printf("]\n");
- if (details_flag) {
- printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str);
- if (aliases[j].metric_name)
- printf(" MetricName: %s", aliases[j].metric_name);
- if (aliases[j].metric_expr)
- printf(" MetricExpr: %s", aliases[j].metric_expr);
- putchar('\n');
- }
- } else
- printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
printed++;
+ if (!aliases[j].event || !aliases[j].event->desc || quiet_flag) {
+ printf(" %-50s [Kernel PMU event]\n", name);
+ continue;
+ }
+ if (numdesc++ == 0)
+ printf("\n");
+ if (aliases[j].event->topic && (!topic ||
+ strcmp(topic, aliases[j].event->topic))) {
+ printf("%s%s:\n", topic ? "\n" : "", aliases[j].event->topic);
+ topic = aliases[j].event->topic;
+ }
+ printf(" %-50s\n", name);
+ printf("%*s", 8, "[");
+ desc = long_desc ? aliases[j].event->long_desc : aliases[j].event->desc;
+ wordwrap(desc, 8, columns, 0);
+ printf("]\n");
+ if (details_flag) {
+ printf("%*s%s/%s/ ", 8, "", aliases[j].pmu->name, aliases[j].event->str);
+ if (aliases[j].event->metric_name)
+ printf(" MetricName: %s", aliases[j].event->metric_name);
+ if (aliases[j].event->metric_expr)
+ printf(" MetricExpr: %s", aliases[j].event->metric_expr);
+ putchar('\n');
+ }
}
if (printed && pager_in_use())
printf("\n");
-out_free:
- for (j = 0; j < len; j++)
- zfree(&aliases[j].name);
+
zfree(&aliases);
return;
-
-out_enomem:
- printf("FATAL: not enough memory to print PMU events\n");
- if (aliases)
- goto out_free;
}
bool pmu_have_event(const char *pname, const char *name)