Commit e5c6109f authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

perf list: Reorganize to use callbacks to allow honouring command line options

Rather than controlling the list output with passed flags, add
callbacks that are called when an event or metric are
encountered. State is passed to the callback so that command line
options can be respected, alternatively the callbacks can be changed.

Fix a few bugs:
 - wordwrap to columns metric descriptions and expressions;
 - remove unnecessary whitespace after PMU event names;
 - the metric filter is a glob but matched using strstr which will
   always fail, switch to using a proper globmatch,
 - the detail flag gives details for extra kernel PMU events like
   branch-instructions.

In metricgroup.c switch from struct mep being a rbtree of metricgroups
containing a list of metrics, to the tree directly containing all the
metrics. In general the alias for a name is passed to the print
routine rather than being contained in the name with OR.

Committer notes:

Check the asprint() return to address this on fedora 36:

  util/print-events.c: In function ‘print_sdt_events’:
  util/print-events.c:183:33: error: ignoring return value of ‘asprintf’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
    183 |                                 asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid);
        |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  cc1: all warnings being treated as errors

  $ gcc --version | head -1
  gcc (GCC) 12.2.1 20220819 (Red Hat 12.2.1-2)
  $

Fix ps.pmu_glob setting when dealing with *:* events, it was being left
with a freed pointer that then at the end of cmd_list() would be double
freed.

Check if pmu_name is NULL in default_print_event() before calling
strglobmatch(pmu_name, ...) to avoid a segfault.
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xin Gao <gaoxin@cdjrlc.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: http://lore.kernel.org/lkml/20221114210723.2749751-10-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent a3720e96
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "strbuf.h" #include "strbuf.h"
#include "pmu.h" #include "pmu.h"
#include "pmu-hybrid.h" #include "pmu-hybrid.h"
#include "print-events.h"
#include "expr.h" #include "expr.h"
#include "rblist.h" #include "rblist.h"
#include <string.h> #include <string.h>
...@@ -353,51 +354,65 @@ static bool match_pe_metric(const struct pmu_event *pe, const char *metric) ...@@ -353,51 +354,65 @@ static bool match_pe_metric(const struct pmu_event *pe, const char *metric)
match_metric(pe->metric_name, metric); match_metric(pe->metric_name, metric);
} }
/** struct mep - RB-tree node for building printing information. */
struct mep { struct mep {
/** nd - RB-tree element. */
struct rb_node nd; struct rb_node nd;
const char *name; /** @metric_group: Owned metric group name, separated others with ';'. */
struct strlist *metrics; char *metric_group;
const char *metric_name;
const char *metric_desc;
const char *metric_long_desc;
const char *metric_expr;
const char *metric_unit;
}; };
static int mep_cmp(struct rb_node *rb_node, const void *entry) static int mep_cmp(struct rb_node *rb_node, const void *entry)
{ {
struct mep *a = container_of(rb_node, struct mep, nd); struct mep *a = container_of(rb_node, struct mep, nd);
struct mep *b = (struct mep *)entry; struct mep *b = (struct mep *)entry;
int ret;
return strcmp(a->name, b->name); ret = strcmp(a->metric_group, b->metric_group);
if (ret)
return ret;
return strcmp(a->metric_name, b->metric_name);
} }
static struct rb_node *mep_new(struct rblist *rl __maybe_unused, static struct rb_node *mep_new(struct rblist *rl __maybe_unused, const void *entry)
const void *entry)
{ {
struct mep *me = malloc(sizeof(struct mep)); struct mep *me = malloc(sizeof(struct mep));
if (!me) if (!me)
return NULL; return NULL;
memcpy(me, entry, sizeof(struct mep)); memcpy(me, entry, sizeof(struct mep));
me->name = strdup(me->name);
if (!me->name)
goto out_me;
me->metrics = strlist__new(NULL, NULL);
if (!me->metrics)
goto out_name;
return &me->nd; return &me->nd;
out_name: }
zfree(&me->name);
out_me: static void mep_delete(struct rblist *rl __maybe_unused,
struct rb_node *nd)
{
struct mep *me = container_of(nd, struct mep, nd);
zfree(&me->metric_group);
free(me); free(me);
return NULL;
} }
static struct mep *mep_lookup(struct rblist *groups, const char *name) static struct mep *mep_lookup(struct rblist *groups, const char *metric_group,
const char *metric_name)
{ {
struct rb_node *nd; struct rb_node *nd;
struct mep me = { struct mep me = {
.name = name .metric_group = strdup(metric_group),
.metric_name = metric_name,
}; };
nd = rblist__find(groups, &me); nd = rblist__find(groups, &me);
if (nd) if (nd) {
free(me.metric_group);
return container_of(nd, struct mep, nd); return container_of(nd, struct mep, nd);
}
rblist__add_node(groups, &me); rblist__add_node(groups, &me);
nd = rblist__find(groups, &me); nd = rblist__find(groups, &me);
if (nd) if (nd)
...@@ -405,107 +420,37 @@ static struct mep *mep_lookup(struct rblist *groups, const char *name) ...@@ -405,107 +420,37 @@ static struct mep *mep_lookup(struct rblist *groups, const char *name)
return NULL; return NULL;
} }
static void mep_delete(struct rblist *rl __maybe_unused, static int metricgroup__add_to_mep_groups(const struct pmu_event *pe,
struct rb_node *nd) struct rblist *groups)
{
struct mep *me = container_of(nd, struct mep, nd);
strlist__delete(me->metrics);
zfree(&me->name);
free(me);
}
static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
{
struct str_node *sn;
int n = 0;
strlist__for_each_entry (sn, metrics) {
if (raw)
printf("%s%s", n > 0 ? " " : "", sn->s);
else
printf(" %s\n", sn->s);
n++;
}
if (raw)
putchar('\n');
}
static int metricgroup__print_pmu_event(const struct pmu_event *pe,
bool metricgroups, char *filter,
bool raw, bool details,
struct rblist *groups,
struct strlist *metriclist)
{ {
const char *g; const char *g;
char *omg, *mg; char *omg, *mg;
g = pe->metric_group; mg = strdup(pe->metric_group ?: "No_group");
if (!g && pe->metric_name) {
if (pe->name)
return 0;
g = "No_group";
}
if (!g)
return 0;
mg = strdup(g);
if (!mg) if (!mg)
return -ENOMEM; return -ENOMEM;
omg = mg; omg = mg;
while ((g = strsep(&mg, ";")) != NULL) { while ((g = strsep(&mg, ";")) != NULL) {
struct mep *me; struct mep *me;
char *s;
g = skip_spaces(g); g = skip_spaces(g);
if (*g == 0) if (strlen(g))
g = "No_group"; me = mep_lookup(groups, g, pe->metric_name);
if (filter && !strstr(g, filter)) else
continue; me = mep_lookup(groups, "No_group", pe->metric_name);
if (raw)
s = (char *)pe->metric_name;
else {
if (asprintf(&s, "%s\n%*s%s]",
pe->metric_name, 8, "[", pe->desc) < 0)
return -1;
if (details) {
if (asprintf(&s, "%s\n%*s%s]",
s, 8, "[", pe->metric_expr) < 0)
return -1;
}
}
if (!s)
continue;
if (!metricgroups) { if (me) {
strlist__add(metriclist, s); me->metric_desc = pe->desc;
} else { me->metric_long_desc = pe->long_desc;
me = mep_lookup(groups, g); me->metric_expr = pe->metric_expr;
if (!me) me->metric_unit = pe->unit;
continue;
strlist__add(me->metrics, s);
} }
if (!raw)
free(s);
} }
free(omg); free(omg);
return 0; return 0;
} }
struct metricgroup_print_sys_idata {
struct strlist *metriclist;
char *filter;
struct rblist *groups;
bool metricgroups;
bool raw;
bool details;
};
struct metricgroup_iter_data { struct metricgroup_iter_data {
pmu_event_iter_fn fn; pmu_event_iter_fn fn;
void *data; void *data;
...@@ -528,61 +473,26 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe, ...@@ -528,61 +473,26 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe,
return d->fn(pe, table, d->data); return d->fn(pe, table, d->data);
} }
return 0; return 0;
} }
static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, static int metricgroup__add_to_mep_groups_callback(const struct pmu_event *pe,
const struct pmu_events_table *table __maybe_unused, const struct pmu_events_table *table __maybe_unused,
void *data) void *vdata)
{
struct metricgroup_print_sys_idata *d = data;
return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw,
d->details, d->groups, d->metriclist);
}
struct metricgroup_print_data {
const char *pmu_name;
struct strlist *metriclist;
char *filter;
struct rblist *groups;
bool metricgroups;
bool raw;
bool details;
};
static int metricgroup__print_callback(const struct pmu_event *pe,
const struct pmu_events_table *table __maybe_unused,
void *vdata)
{ {
struct metricgroup_print_data *data = vdata; struct rblist *groups = vdata;
const char *pmu = pe->pmu ?: "cpu";
if (!pe->metric_expr) if (!pe->metric_name)
return 0;
if (data->pmu_name && strcmp(data->pmu_name, pmu))
return 0; return 0;
return metricgroup__print_pmu_event(pe, data->metricgroups, data->filter, return metricgroup__add_to_mep_groups(pe, groups);
data->raw, data->details, data->groups,
data->metriclist);
} }
void metricgroup__print(bool metrics, bool metricgroups, char *filter, void metricgroup__print(const struct print_callbacks *print_cb, void *print_state)
bool raw, bool details, const char *pmu_name)
{ {
struct rblist groups; struct rblist groups;
struct rb_node *node, *next;
struct strlist *metriclist = NULL;
const struct pmu_events_table *table; const struct pmu_events_table *table;
struct rb_node *node, *next;
if (!metricgroups) {
metriclist = strlist__new(NULL, NULL);
if (!metriclist)
return;
}
rblist__init(&groups); rblist__init(&groups);
groups.node_new = mep_new; groups.node_new = mep_new;
...@@ -590,56 +500,31 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter, ...@@ -590,56 +500,31 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
groups.node_delete = mep_delete; groups.node_delete = mep_delete;
table = pmu_events_table__find(); table = pmu_events_table__find();
if (table) { if (table) {
struct metricgroup_print_data data = {
.pmu_name = pmu_name,
.metriclist = metriclist,
.metricgroups = metricgroups,
.filter = filter,
.raw = raw,
.details = details,
.groups = &groups,
};
pmu_events_table_for_each_event(table, pmu_events_table_for_each_event(table,
metricgroup__print_callback, metricgroup__add_to_mep_groups_callback,
&data); &groups);
} }
{ {
struct metricgroup_iter_data data = { struct metricgroup_iter_data data = {
.fn = metricgroup__print_sys_event_iter, .fn = metricgroup__add_to_mep_groups_callback,
.data = (void *) &(struct metricgroup_print_sys_idata){ .data = &groups,
.metriclist = metriclist,
.metricgroups = metricgroups,
.filter = filter,
.raw = raw,
.details = details,
.groups = &groups,
},
}; };
pmu_for_each_sys_event(metricgroup__sys_event_iter, &data); pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
} }
if (!filter || !rblist__empty(&groups)) {
if (metricgroups && !raw)
printf("\nMetric Groups:\n\n");
else if (metrics && !raw)
printf("\nMetrics:\n\n");
}
for (node = rb_first_cached(&groups.entries); node; node = next) { for (node = rb_first_cached(&groups.entries); node; node = next) {
struct mep *me = container_of(node, struct mep, nd); struct mep *me = container_of(node, struct mep, nd);
if (metricgroups) print_cb->print_metric(print_state,
printf("%s%s%s", me->name, metrics && !raw ? ":" : "", raw ? " " : "\n"); me->metric_group,
if (metrics) me->metric_name,
metricgroup__print_strlist(me->metrics, raw); me->metric_desc,
me->metric_long_desc,
me->metric_expr,
me->metric_unit);
next = rb_next(node); next = rb_next(node);
rblist__remove_node(&groups, node); rblist__remove_node(&groups, node);
} }
if (!metricgroups)
metricgroup__print_strlist(metriclist, raw);
strlist__delete(metriclist);
} }
static const char *code_characters = ",-=@"; static const char *code_characters = ",-=@";
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
struct evlist; struct evlist;
struct evsel; struct evsel;
struct option; struct option;
struct print_callbacks;
struct rblist; struct rblist;
struct cgroup; struct cgroup;
...@@ -78,8 +79,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist, ...@@ -78,8 +79,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
bool metric_no_merge, bool metric_no_merge,
struct rblist *metric_events); struct rblist *metric_events);
void metricgroup__print(bool metrics, bool groups, char *filter, void metricgroup__print(const struct print_callbacks *print_cb, void *print_state);
bool raw, bool details, const char *pmu_name);
bool metricgroup__has_metric(const char *metric); bool metricgroup__has_metric(const char *metric);
int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused); int arch_get_runtimeparam(const struct pmu_event *pe __maybe_unused);
void metricgroup__rblist_exit(struct rblist *metric_events); void metricgroup__rblist_exit(struct rblist *metric_events);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "evsel.h" #include "evsel.h"
#include "pmu.h" #include "pmu.h"
#include "parse-events.h" #include "parse-events.h"
#include "print-events.h"
#include "header.h" #include "header.h"
#include "string2.h" #include "string2.h"
#include "strbuf.h" #include "strbuf.h"
...@@ -1579,13 +1580,6 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, ...@@ -1579,13 +1580,6 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
return buf; return buf;
} }
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 for ordering events as output in perf list. */
struct sevent { struct sevent {
/** PMU for event. */ /** PMU for event. */
...@@ -1629,7 +1623,7 @@ static int cmp_sevent(const void *a, const void *b) ...@@ -1629,7 +1623,7 @@ static int cmp_sevent(const void *a, const void *b)
/* Order CPU core events to be first */ /* Order CPU core events to be first */
if (as->is_cpu != bs->is_cpu) if (as->is_cpu != bs->is_cpu)
return bs->is_cpu - as->is_cpu; return as->is_cpu ? -1 : 1;
/* Order by PMU name. */ /* Order by PMU name. */
a_pmu_name = as->pmu->name ?: ""; a_pmu_name = as->pmu->name ?: "";
...@@ -1642,27 +1636,6 @@ static int cmp_sevent(const void *a, const void *b) ...@@ -1642,27 +1636,6 @@ static int cmp_sevent(const void *a, const void *b)
return strcmp(a_name, b_name); return strcmp(a_name, b_name);
} }
static void wordwrap(char *s, int start, int max, int corr)
{
int column = start;
int n;
while (*s) {
int wlen = strcspn(s, " \t");
if (column + wlen >= max && column > start) {
printf("\n%*s", start, "");
column = start + corr;
}
n = printf("%s%.*s", column > start ? " " : "", wlen, s);
if (n <= 0)
break;
s += wlen;
column += n;
s = skip_spaces(s);
}
}
bool is_pmu_core(const char *name) bool is_pmu_core(const char *name)
{ {
return !strcmp(name, "cpu") || is_arm_pmu_core(name); return !strcmp(name, "cpu") || is_arm_pmu_core(name);
...@@ -1685,24 +1658,19 @@ static bool pmu_alias_is_duplicate(struct sevent *alias_a, ...@@ -1685,24 +1658,19 @@ static bool pmu_alias_is_duplicate(struct sevent *alias_a,
return strcmp(a_pmu_name, b_pmu_name) == 0; return strcmp(a_pmu_name, b_pmu_name) == 0;
} }
void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
bool long_desc, bool details_flag, bool deprecated,
const char *pmu_name)
{ {
struct perf_pmu *pmu; struct perf_pmu *pmu;
struct perf_pmu_alias *alias; struct perf_pmu_alias *event;
char buf[1024]; char buf[1024];
int printed = 0; int printed = 0;
int len, j; int len, j;
struct sevent *aliases; struct sevent *aliases;
int numdesc = 0;
int columns = pager_get_columns();
char *topic = NULL;
pmu = NULL; pmu = NULL;
len = 0; len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL) { while ((pmu = perf_pmu__scan(pmu)) != NULL) {
list_for_each_entry(alias, &pmu->aliases, list) list_for_each_entry(event, &pmu->aliases, list)
len++; len++;
if (pmu->selectable) if (pmu->selectable)
len++; len++;
...@@ -1715,32 +1683,15 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, ...@@ -1715,32 +1683,15 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
pmu = NULL; pmu = NULL;
j = 0; j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL) { while ((pmu = perf_pmu__scan(pmu)) != NULL) {
bool is_cpu; bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name);
if (pmu_name && pmu->name && strcmp(pmu_name, pmu->name)) list_for_each_entry(event, &pmu->aliases, list) {
continue; aliases[j].event = event;
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(alias->name, event_glob) ||
(!is_cpu &&
strglobmatch_nocase(alias->name, event_glob)) ||
(alias->topic &&
strglobmatch_nocase(alias->topic, event_glob))))
continue;
aliases[j].event = alias;
aliases[j].pmu = pmu; aliases[j].pmu = pmu;
aliases[j].is_cpu = is_cpu; aliases[j].is_cpu = is_cpu;
j++; j++;
} }
if (pmu->selectable && if (pmu->selectable) {
(event_glob == NULL || strglobmatch(pmu->name, event_glob))) {
aliases[j].event = NULL; aliases[j].event = NULL;
aliases[j].pmu = pmu; aliases[j].pmu = pmu;
aliases[j].is_cpu = is_cpu; aliases[j].is_cpu = is_cpu;
...@@ -1750,7 +1701,12 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, ...@@ -1750,7 +1701,12 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
len = j; len = j;
qsort(aliases, len, sizeof(struct sevent), cmp_sevent); qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
char *name, *desc; const char *name, *alias = NULL, *scale_unit = NULL,
*desc = NULL, *long_desc = NULL,
*encoding_desc = NULL, *topic = NULL,
*metric_name = NULL, *metric_expr = NULL;
bool deprecated = false;
size_t buf_used;
/* Skip duplicates */ /* Skip duplicates */
if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
...@@ -1758,48 +1714,51 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, ...@@ -1758,48 +1714,51 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
if (!aliases[j].event) { if (!aliases[j].event) {
/* A selectable event. */ /* A selectable event. */
snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name); buf_used = snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) + 1;
name = buf; name = buf;
} else if (aliases[j].event->desc) {
name = aliases[j].event->name;
} else { } else {
if (!name_only && aliases[j].is_cpu) { if (aliases[j].event->desc) {
name = format_alias_or(buf, sizeof(buf), aliases[j].pmu, name = aliases[j].event->name;
aliases[j].event); buf_used = 0;
} else { } else {
name = format_alias(buf, sizeof(buf), aliases[j].pmu, name = format_alias(buf, sizeof(buf), aliases[j].pmu,
aliases[j].event); aliases[j].event);
if (aliases[j].is_cpu) {
alias = name;
name = aliases[j].event->name;
}
buf_used = strlen(buf) + 1;
} }
} if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) {
if (name_only) { scale_unit = buf + buf_used;
printf("%s ", name); buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
continue; "%G%s", aliases[j].event->scale,
} aliases[j].event->unit) + 1;
printed++; }
if (!aliases[j].event || !aliases[j].event->desc || quiet_flag) { desc = aliases[j].event->desc;
printf(" %-50s [Kernel PMU event]\n", name); long_desc = aliases[j].event->long_desc;
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; topic = aliases[j].event->topic;
encoding_desc = buf + buf_used;
buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
"%s/%s/", aliases[j].pmu->name,
aliases[j].event->str) + 1;
metric_name = aliases[j].event->metric_name;
metric_expr = aliases[j].event->metric_expr;
deprecated = aliases[j].event->deprecated;
} }
printf(" %-50s\n", name); print_cb->print_event(print_state,
printf("%*s", 8, "["); aliases[j].pmu->name,
desc = long_desc ? aliases[j].event->long_desc : aliases[j].event->desc; topic,
wordwrap(desc, 8, columns, 0); name,
printf("]\n"); alias,
if (details_flag) { scale_unit,
printf("%*s%s/%s/ ", 8, "", aliases[j].pmu->name, aliases[j].event->str); deprecated,
if (aliases[j].event->metric_name) "Kernel PMU event",
printf(" MetricName: %s", aliases[j].event->metric_name); desc,
if (aliases[j].event->metric_expr) long_desc,
printf(" MetricExpr: %s", aliases[j].event->metric_expr); encoding_desc,
putchar('\n'); metric_name,
} metric_expr);
} }
if (printed && pager_in_use()) if (printed && pager_in_use())
printf("\n"); printf("\n");
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
struct evsel_config_term; struct evsel_config_term;
struct perf_cpu_map; struct perf_cpu_map;
struct print_callbacks;
enum { enum {
PERF_PMU_FORMAT_VALUE_CONFIG, PERF_PMU_FORMAT_VALUE_CONFIG,
...@@ -225,9 +226,7 @@ void perf_pmu__del_formats(struct list_head *formats); ...@@ -225,9 +226,7 @@ void perf_pmu__del_formats(struct list_head *formats);
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
bool is_pmu_core(const char *name); bool is_pmu_core(const char *name);
void print_pmu_events(const char *event_glob, bool name_only, bool quiet, void print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
bool long_desc, bool details_flag,
bool deprecated, const char *pmu_name);
bool pmu_have_event(const char *pname, const char *name); bool pmu_have_event(const char *pname, const char *name);
int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4); int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);
......
This diff is collapsed.
...@@ -2,21 +2,39 @@ ...@@ -2,21 +2,39 @@
#ifndef __PERF_PRINT_EVENTS_H #ifndef __PERF_PRINT_EVENTS_H
#define __PERF_PRINT_EVENTS_H #define __PERF_PRINT_EVENTS_H
#include <linux/perf_event.h>
#include <stdbool.h> #include <stdbool.h>
struct event_symbol; struct event_symbol;
void print_events(const char *event_glob, bool name_only, bool quiet_flag, struct print_callbacks {
bool long_desc, bool details_flag, bool deprecated, void (*print_start)(void *print_state);
const char *pmu_name); void (*print_end)(void *print_state);
int print_hwcache_events(const char *event_glob, bool name_only); void (*print_event)(void *print_state, const char *topic,
void print_sdt_events(const char *subsys_glob, const char *event_glob, const char *pmu_name,
bool name_only); const char *event_name, const char *event_alias,
void print_symbol_events(const char *event_glob, unsigned int type, const char *scale_unit,
struct event_symbol *syms, unsigned int max, bool deprecated, const char *event_type_desc,
bool name_only); const char *desc, const char *long_desc,
void print_tool_events(const char *event_glob, bool name_only); const char *encoding_desc,
void print_tracepoint_events(const char *subsys_glob, const char *event_glob, const char *metric_name, const char *metric_expr);
bool name_only); void (*print_metric)(void *print_state,
const char *group,
const char *name,
const char *desc,
const char *long_desc,
const char *expr,
const char *unit);
};
/** Print all events, the default when no options are specified. */
void print_events(const struct print_callbacks *print_cb, void *print_state);
int print_hwcache_events(const struct print_callbacks *print_cb, void *print_state);
void print_sdt_events(const struct print_callbacks *print_cb, void *print_state);
void print_symbol_events(const struct print_callbacks *print_cb, void *print_state,
unsigned int type, const struct event_symbol *syms,
unsigned int max);
void print_tool_events(const struct print_callbacks *print_cb, void *print_state);
void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state);
#endif /* __PERF_PRINT_EVENTS_H */ #endif /* __PERF_PRINT_EVENTS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment