summaryrefslogtreecommitdiff
path: root/tools/perf/builtin-list.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-list.c')
-rw-r--r--tools/perf/builtin-list.c545
1 files changed, 368 insertions, 177 deletions
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 137d73edb541..5cbca0bacd35 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -11,16 +11,19 @@
#include "builtin.h"
#include "util/print-events.h"
+#include "util/pmus.h"
#include "util/pmu.h"
-#include "util/pmu-hybrid.h"
#include "util/debug.h"
#include "util/metricgroup.h"
+#include "util/pfm.h"
#include "util/string2.h"
#include "util/strlist.h"
#include "util/strbuf.h"
+#include "util/tool_pmu.h"
#include <subcmd/pager.h>
#include <subcmd/parse-options.h>
#include <linux/zalloc.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
@@ -29,6 +32,8 @@
* functions.
*/
struct print_state {
+ /** @fp: File to write output to. */
+ FILE *fp;
/**
* @pmu_glob: Optionally restrict PMU and metric matching to PMU or
* debugfs subsystem name.
@@ -53,6 +58,8 @@ struct print_state {
bool metrics;
/** @metricgroups: Controls printing of metric and metric groups. */
bool metricgroups;
+ /** @exclude_abi: Exclude PMUs with types less than PERF_TYPE_MAX except PERF_TYPE_RAW. */
+ bool exclude_abi;
/** @last_topic: The last printed event topic. */
char *last_topic;
/** @last_metricgroups: The last printed metric group. */
@@ -65,50 +72,68 @@ static void default_print_start(void *ps)
{
struct print_state *print_state = ps;
- if (!print_state->name_only && pager_in_use())
- printf("\nList of pre-defined events (to be used in -e or -M):\n\n");
+ if (!print_state->name_only && pager_in_use()) {
+ fprintf(print_state->fp,
+ "\nList of pre-defined events (to be used in -e or -M):\n\n");
+ }
}
static void default_print_end(void *print_state __maybe_unused) {}
-static void wordwrap(const char *s, int start, int max, int corr)
+static const char *skip_spaces_or_commas(const char *str)
+{
+ while (isspace(*str) || *str == ',')
+ ++str;
+ return str;
+}
+
+static void wordwrap(FILE *fp, const char *s, int start, int max, int corr)
{
int column = start;
int n;
bool saw_newline = false;
+ bool comma = false;
while (*s) {
- int wlen = strcspn(s, " \t\n");
+ int wlen = strcspn(s, " ,\t\n");
+ const char *sep = comma ? "," : " ";
if ((column + wlen >= max && column > start) || saw_newline) {
- printf("\n%*s", start, "");
+ fprintf(fp, comma ? ",\n%*s" : "\n%*s", start, "");
column = start + corr;
}
- n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+ if (column <= start)
+ sep = "";
+ n = fprintf(fp, "%s%.*s", sep, wlen, s);
if (n <= 0)
break;
saw_newline = s[wlen] == '\n';
s += wlen;
+ comma = s[0] == ',';
column += n;
- s = skip_spaces(s);
+ s = skip_spaces_or_commas(s);
}
}
-static void default_print_event(void *ps, const char *pmu_name, const char *topic,
+static void default_print_event(void *ps, const char *topic,
+ const char *pmu_name, u32 pmu_type,
const char *event_name, const char *event_alias,
const char *scale_unit __maybe_unused,
bool deprecated, const char *event_type_desc,
const char *desc, const char *long_desc,
- const char *encoding_desc,
- const char *metric_name, const char *metric_expr)
+ const char *encoding_desc)
{
struct print_state *print_state = ps;
int pos;
+ FILE *fp = print_state->fp;
if (deprecated && !print_state->deprecated)
return;
- if (print_state->pmu_glob && pmu_name && !strglobmatch(pmu_name, print_state->pmu_glob))
+ if (print_state->pmu_glob && (!pmu_name || !strglobmatch(pmu_name, print_state->pmu_glob)))
+ return;
+
+ if (print_state->exclude_abi && pmu_type < PERF_TYPE_MAX && pmu_type != PERF_TYPE_RAW)
return;
if (print_state->event_glob &&
@@ -119,51 +144,55 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
if (print_state->name_only) {
if (event_alias && strlen(event_alias))
- printf("%s ", event_alias);
+ fprintf(fp, "%s ", event_alias);
else
- printf("%s ", event_name);
+ fprintf(fp, "%s ", event_name);
return;
}
if (strcmp(print_state->last_topic, topic ?: "")) {
if (topic)
- printf("\n%s:\n", topic);
- free(print_state->last_topic);
+ fprintf(fp, "\n%s:\n", topic);
+ zfree(&print_state->last_topic);
print_state->last_topic = strdup(topic ?: "");
}
if (event_alias && strlen(event_alias))
- pos = printf(" %s OR %s", event_name, event_alias);
+ pos = fprintf(fp, " %s OR %s", event_name, event_alias);
else
- pos = printf(" %s", event_name);
+ pos = fprintf(fp, " %s", event_name);
if (!topic && event_type_desc) {
for (; pos < 53; pos++)
- putchar(' ');
- printf("[%s]\n", event_type_desc);
+ fputc(' ', fp);
+ fprintf(fp, "[%s]\n", event_type_desc);
} else
- putchar('\n');
+ fputc('\n', fp);
- if (desc && print_state->desc) {
- printf("%*s", 8, "[");
- wordwrap(desc, 8, pager_get_columns(), 0);
- printf("]\n");
- }
- long_desc = long_desc ?: desc;
- if (long_desc && print_state->long_desc) {
- printf("%*s", 8, "[");
- wordwrap(long_desc, 8, pager_get_columns(), 0);
- printf("]\n");
+ if (long_desc && print_state->long_desc)
+ desc = long_desc;
+
+ if (desc && (print_state->desc || print_state->long_desc)) {
+ char *desc_with_unit = NULL;
+ int desc_len = -1;
+
+ if (pmu_name && strcmp(pmu_name, "default_core")) {
+ desc_len = strlen(desc);
+ desc_len = asprintf(&desc_with_unit,
+ desc_len > 0 && desc[desc_len - 1] != '.'
+ ? "%s. Unit: %s" : "%s Unit: %s",
+ desc, pmu_name);
+ }
+ fprintf(fp, "%*s", 8, "[");
+ wordwrap(fp, desc_len > 0 ? desc_with_unit : desc, 8, pager_get_columns(), 0);
+ fprintf(fp, "]\n");
+ free(desc_with_unit);
}
if (print_state->detailed && encoding_desc) {
- printf("%*s", 8, "");
- wordwrap(encoding_desc, 8, pager_get_columns(), 0);
- if (metric_name)
- printf(" MetricName: %s", metric_name);
- if (metric_expr)
- printf(" MetricExpr: %s", metric_expr);
- putchar('\n');
+ fprintf(fp, "%*s", 8, "");
+ wordwrap(fp, encoding_desc, 8, pager_get_columns(), 0);
+ fputc('\n', fp);
}
}
@@ -173,9 +202,12 @@ static void default_print_metric(void *ps,
const char *desc,
const char *long_desc,
const char *expr,
- const char *unit __maybe_unused)
+ const char *threshold,
+ const char *unit __maybe_unused,
+ const char *pmu_name __maybe_unused)
{
struct print_state *print_state = ps;
+ FILE *fp = print_state->fp;
if (print_state->event_glob &&
(!print_state->metrics || !name || !strglobmatch(name, print_state->event_glob)) &&
@@ -184,24 +216,36 @@ static void default_print_metric(void *ps,
if (!print_state->name_only && !print_state->last_metricgroups) {
if (print_state->metricgroups) {
- printf("\nMetric Groups:\n");
+ fprintf(fp, "\nMetric Groups:\n");
if (!print_state->metrics)
- putchar('\n');
+ fputc('\n', fp);
} else {
- printf("\nMetrics:\n\n");
+ fprintf(fp, "\nMetrics:\n\n");
}
}
if (!print_state->last_metricgroups ||
strcmp(print_state->last_metricgroups, group ?: "")) {
if (group && print_state->metricgroups) {
- if (print_state->name_only)
- printf("%s ", group);
- else if (print_state->metrics)
- printf("\n%s:\n", group);
- else
- printf("%s\n", group);
+ if (print_state->name_only) {
+ fprintf(fp, "%s ", group);
+ } else {
+ const char *gdesc = print_state->desc
+ ? describe_metricgroup(group)
+ : NULL;
+ const char *print_colon = "";
+
+ if (print_state->metrics) {
+ print_colon = ":";
+ fputc('\n', fp);
+ }
+
+ if (gdesc)
+ fprintf(fp, "%s%s [%s]\n", group, print_colon, gdesc);
+ else
+ fprintf(fp, "%s%s\n", group, print_colon);
+ }
}
- free(print_state->last_metricgroups);
+ zfree(&print_state->last_metricgroups);
print_state->last_metricgroups = strdup(group ?: "");
}
if (!print_state->metrics)
@@ -210,48 +254,58 @@ static void default_print_metric(void *ps,
if (print_state->name_only) {
if (print_state->metrics &&
!strlist__has_entry(print_state->visited_metrics, name)) {
- printf("%s ", name);
+ fprintf(fp, "%s ", name);
strlist__add(print_state->visited_metrics, name);
}
return;
}
- printf(" %s\n", name);
+ fprintf(fp, " %s\n", name);
- if (desc && print_state->desc) {
- printf("%*s", 8, "[");
- wordwrap(desc, 8, pager_get_columns(), 0);
- printf("]\n");
- }
if (long_desc && print_state->long_desc) {
- printf("%*s", 8, "[");
- wordwrap(long_desc, 8, pager_get_columns(), 0);
- printf("]\n");
+ fprintf(fp, "%*s", 8, "[");
+ wordwrap(fp, long_desc, 8, pager_get_columns(), 0);
+ fprintf(fp, "]\n");
+ } else if (desc && print_state->desc) {
+ fprintf(fp, "%*s", 8, "[");
+ wordwrap(fp, desc, 8, pager_get_columns(), 0);
+ fprintf(fp, "]\n");
}
if (expr && print_state->detailed) {
- printf("%*s", 8, "[");
- wordwrap(expr, 8, pager_get_columns(), 0);
- printf("]\n");
+ fprintf(fp, "%*s", 8, "[");
+ wordwrap(fp, expr, 8, pager_get_columns(), 0);
+ fprintf(fp, "]\n");
+ }
+ if (threshold && print_state->detailed) {
+ fprintf(fp, "%*s", 8, "[");
+ wordwrap(fp, threshold, 8, pager_get_columns(), 0);
+ fprintf(fp, "]\n");
}
}
struct json_print_state {
+ /** The shared print_state */
+ struct print_state common;
/** Should a separator be printed prior to the next item? */
bool need_sep;
};
-static void json_print_start(void *print_state __maybe_unused)
+static void json_print_start(void *ps)
{
- printf("[\n");
+ struct json_print_state *print_state = ps;
+ FILE *fp = print_state->common.fp;
+
+ fprintf(fp, "[\n");
}
static void json_print_end(void *ps)
{
struct json_print_state *print_state = ps;
+ FILE *fp = print_state->common.fp;
- printf("%s]\n", print_state->need_sep ? "\n" : "");
+ fprintf(fp, "%s]\n", print_state->need_sep ? "\n" : "");
}
-static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...)
+static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, ...)
{
va_list args;
@@ -276,11 +330,14 @@ static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...)
case '\n':
strbuf_addstr(buf, "\\n");
break;
+ case '\r':
+ strbuf_addstr(buf, "\\r");
+ break;
case '\\':
- __fallthrough;
+ fallthrough;
case '\"':
strbuf_addch(buf, '\\');
- __fallthrough;
+ fallthrough;
default:
strbuf_addch(buf, s[s_pos]);
break;
@@ -300,142 +357,210 @@ static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...)
}
}
va_end(args);
- fputs(buf->buf, stdout);
+ fputs(buf->buf, fp);
}
-static void json_print_event(void *ps, const char *pmu_name, const char *topic,
+static void json_print_event(void *ps, const char *topic,
+ const char *pmu_name, u32 pmu_type __maybe_unused,
const char *event_name, const char *event_alias,
const char *scale_unit,
bool deprecated, const char *event_type_desc,
const char *desc, const char *long_desc,
- const char *encoding_desc,
- const char *metric_name, const char *metric_expr)
+ const char *encoding_desc)
{
struct json_print_state *print_state = ps;
bool need_sep = false;
+ FILE *fp = print_state->common.fp;
struct strbuf buf;
+ if (deprecated && !print_state->common.deprecated)
+ return;
+
+ if (print_state->common.pmu_glob &&
+ (!pmu_name || !strglobmatch(pmu_name, print_state->common.pmu_glob)))
+ return;
+
+ if (print_state->common.exclude_abi && pmu_type < PERF_TYPE_MAX &&
+ pmu_type != PERF_TYPE_RAW)
+ return;
+
+ if (print_state->common.event_glob &&
+ (!event_name || !strglobmatch(event_name, print_state->common.event_glob)) &&
+ (!event_alias || !strglobmatch(event_alias, print_state->common.event_glob)) &&
+ (!topic || !strglobmatch_nocase(topic, print_state->common.event_glob)))
+ return;
+
strbuf_init(&buf, 0);
- printf("%s{\n", print_state->need_sep ? ",\n" : "");
+ fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : "");
print_state->need_sep = true;
if (pmu_name) {
- fix_escape_printf(&buf, "\t\"Unit\": \"%S\"", pmu_name);
+ fix_escape_fprintf(fp, &buf, "\t\"Unit\": \"%S\"", pmu_name);
need_sep = true;
}
if (topic) {
- fix_escape_printf(&buf, "%s\t\"Topic\": \"%S\"", need_sep ? ",\n" : "", topic);
+ fix_escape_fprintf(fp, &buf, "%s\t\"Topic\": \"%S\"",
+ need_sep ? ",\n" : "",
+ topic);
need_sep = true;
}
if (event_name) {
- fix_escape_printf(&buf, "%s\t\"EventName\": \"%S\"", need_sep ? ",\n" : "",
- event_name);
+ fix_escape_fprintf(fp, &buf, "%s\t\"EventName\": \"%S\"",
+ need_sep ? ",\n" : "",
+ event_name);
need_sep = true;
}
if (event_alias && strlen(event_alias)) {
- fix_escape_printf(&buf, "%s\t\"EventAlias\": \"%S\"", need_sep ? ",\n" : "",
- event_alias);
+ fix_escape_fprintf(fp, &buf, "%s\t\"EventAlias\": \"%S\"",
+ need_sep ? ",\n" : "",
+ event_alias);
need_sep = true;
}
if (scale_unit && strlen(scale_unit)) {
- fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "",
- scale_unit);
+ fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"",
+ need_sep ? ",\n" : "",
+ scale_unit);
need_sep = true;
}
if (event_type_desc) {
- fix_escape_printf(&buf, "%s\t\"EventType\": \"%S\"", need_sep ? ",\n" : "",
- event_type_desc);
+ fix_escape_fprintf(fp, &buf, "%s\t\"EventType\": \"%S\"",
+ need_sep ? ",\n" : "",
+ event_type_desc);
need_sep = true;
}
if (deprecated) {
- fix_escape_printf(&buf, "%s\t\"Deprecated\": \"%S\"", need_sep ? ",\n" : "",
- deprecated ? "1" : "0");
+ fix_escape_fprintf(fp, &buf, "%s\t\"Deprecated\": \"%S\"",
+ need_sep ? ",\n" : "",
+ deprecated ? "1" : "0");
need_sep = true;
}
if (desc) {
- fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "",
- desc);
+ fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"",
+ need_sep ? ",\n" : "",
+ desc);
need_sep = true;
}
if (long_desc) {
- fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "",
- long_desc);
+ fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"",
+ need_sep ? ",\n" : "",
+ long_desc);
need_sep = true;
}
if (encoding_desc) {
- fix_escape_printf(&buf, "%s\t\"Encoding\": \"%S\"", need_sep ? ",\n" : "",
- encoding_desc);
- need_sep = true;
- }
- if (metric_name) {
- fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "",
- metric_name);
- need_sep = true;
- }
- if (metric_expr) {
- fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "",
- metric_expr);
+ fix_escape_fprintf(fp, &buf, "%s\t\"Encoding\": \"%S\"",
+ need_sep ? ",\n" : "",
+ encoding_desc);
need_sep = true;
}
- printf("%s}", need_sep ? "\n" : "");
+ fprintf(fp, "%s}", need_sep ? "\n" : "");
strbuf_release(&buf);
}
static void json_print_metric(void *ps __maybe_unused, const char *group,
const char *name, const char *desc,
const char *long_desc, const char *expr,
- const char *unit)
+ const char *threshold, const char *unit,
+ const char *pmu_name)
{
struct json_print_state *print_state = ps;
bool need_sep = false;
+ FILE *fp = print_state->common.fp;
struct strbuf buf;
+ if (print_state->common.event_glob &&
+ (!print_state->common.metrics || !name ||
+ !strglobmatch(name, print_state->common.event_glob)) &&
+ (!print_state->common.metricgroups || !group ||
+ !strglobmatch(group, print_state->common.event_glob)))
+ return;
+
strbuf_init(&buf, 0);
- printf("%s{\n", print_state->need_sep ? ",\n" : "");
+ fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : "");
print_state->need_sep = true;
if (group) {
- fix_escape_printf(&buf, "\t\"MetricGroup\": \"%S\"", group);
+ fix_escape_fprintf(fp, &buf, "\t\"MetricGroup\": \"%S\"", group);
need_sep = true;
}
if (name) {
- fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "", name);
+ fix_escape_fprintf(fp, &buf, "%s\t\"MetricName\": \"%S\"",
+ need_sep ? ",\n" : "",
+ name);
need_sep = true;
}
if (expr) {
- fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "", expr);
+ fix_escape_fprintf(fp, &buf, "%s\t\"MetricExpr\": \"%S\"",
+ need_sep ? ",\n" : "",
+ expr);
+ need_sep = true;
+ }
+ if (threshold) {
+ fix_escape_fprintf(fp, &buf, "%s\t\"MetricThreshold\": \"%S\"",
+ need_sep ? ",\n" : "",
+ threshold);
need_sep = true;
}
if (unit) {
- fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "", unit);
+ fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"",
+ need_sep ? ",\n" : "",
+ unit);
need_sep = true;
}
if (desc) {
- fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "",
- desc);
+ fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"",
+ need_sep ? ",\n" : "",
+ desc);
need_sep = true;
}
if (long_desc) {
- fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "",
- long_desc);
+ fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"",
+ need_sep ? ",\n" : "",
+ long_desc);
need_sep = true;
}
- printf("%s}", need_sep ? "\n" : "");
+ if (pmu_name) {
+ fix_escape_fprintf(fp, &buf, "%s\t\"Unit\": \"%S\"",
+ need_sep ? ",\n" : "",
+ pmu_name);
+ need_sep = true;
+ }
+ fprintf(fp, "%s}", need_sep ? "\n" : "");
strbuf_release(&buf);
}
+static bool json_skip_duplicate_pmus(void *ps __maybe_unused)
+{
+ return false;
+}
+
+static bool default_skip_duplicate_pmus(void *ps)
+{
+ struct print_state *print_state = ps;
+
+ return !print_state->long_desc;
+}
+
int cmd_list(int argc, const char **argv)
{
int i, ret = 0;
- struct print_state default_ps = {};
- struct print_state json_ps = {};
- void *ps = &default_ps;
+ struct print_state default_ps = {
+ .fp = stdout,
+ .desc = true,
+ };
+ struct json_print_state json_ps = {
+ .common = {
+ .fp = stdout,
+ },
+ };
+ struct print_state *ps = &default_ps;
struct print_callbacks print_cb = {
.print_start = default_print_start,
.print_end = default_print_end,
.print_event = default_print_event,
.print_metric = default_print_metric,
+ .skip_duplicate_pmus = default_skip_duplicate_pmus,
};
- const char *hybrid_name = NULL;
+ const char *cputype = NULL;
const char *unit_name = NULL;
+ const char *output_path = NULL;
bool json = false;
struct option list_options[] = {
OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"),
@@ -443,13 +568,14 @@ int cmd_list(int argc, const char **argv)
OPT_BOOLEAN('d', "desc", &default_ps.desc,
"Print extra event descriptions. --no-desc to not print."),
OPT_BOOLEAN('v', "long-desc", &default_ps.long_desc,
- "Print longer event descriptions."),
+ "Print longer event descriptions and all similar PMUs with alphanumeric suffixes."),
OPT_BOOLEAN(0, "details", &default_ps.detailed,
"Print information on the perf event names and expressions used internally by events."),
+ OPT_STRING('o', "output", &output_path, "file", "output file name"),
OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated,
"Print deprecated events."),
- OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type",
- "Limit PMU or metric printing to the given hybrid PMU (e.g. core or atom)."),
+ OPT_STRING(0, "cputype", &cputype, "cpu type",
+ "Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
OPT_STRING(0, "unit", &unit_name, "PMU name",
"Limit PMU or metric printing to the specified PMU."),
OPT_INCR(0, "debug", &verbose,
@@ -457,7 +583,11 @@ int cmd_list(int argc, const char **argv)
OPT_END()
};
const char * const list_usage[] = {
+#ifdef HAVE_LIBPFM
+ "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]",
+#else
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
+#endif
NULL
};
@@ -468,6 +598,13 @@ int cmd_list(int argc, const char **argv)
argc = parse_options(argc, argv, list_options, list_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+ if (json)
+ ps = &json_ps.common;
+
+ if (output_path) {
+ ps->fp = fopen(output_path, "w");
+ }
+
setup_pager();
if (!default_ps.name_only)
@@ -479,27 +616,33 @@ int cmd_list(int argc, const char **argv)
.print_end = json_print_end,
.print_event = json_print_event,
.print_metric = json_print_metric,
+ .skip_duplicate_pmus = json_skip_duplicate_pmus,
};
- ps = &json_ps;
} else {
- default_ps.desc = !default_ps.long_desc;
- default_ps.last_topic = strdup("");
- assert(default_ps.last_topic);
- default_ps.visited_metrics = strlist__new(NULL, NULL);
- assert(default_ps.visited_metrics);
+ ps->last_topic = strdup("");
+ assert(ps->last_topic);
+ ps->visited_metrics = strlist__new(NULL, NULL);
+ assert(ps->visited_metrics);
if (unit_name)
- default_ps.pmu_glob = strdup(unit_name);
- else if (hybrid_name) {
- default_ps.pmu_glob = perf_pmu__hybrid_type_to_pmu(hybrid_name);
- if (!default_ps.pmu_glob)
- pr_warning("WARNING: hybrid cputype is not supported!\n");
+ ps->pmu_glob = strdup(unit_name);
+ else if (cputype) {
+ const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype);
+
+ if (!pmu) {
+ pr_err("ERROR: cputype is not supported!\n");
+ ret = -1;
+ goto out;
+ }
+ ps->pmu_glob = strdup(pmu->name);
}
}
print_cb.print_start(ps);
if (argc == 0) {
- default_ps.metrics = true;
- default_ps.metricgroups = true;
+ if (!unit_name) {
+ ps->metrics = true;
+ ps->metricgroups = true;
+ }
print_events(&print_cb, ps);
goto out;
}
@@ -507,66 +650,111 @@ int cmd_list(int argc, const char **argv)
for (i = 0; i < argc; ++i) {
char *sep, *s;
- if (strcmp(argv[i], "tracepoint") == 0)
- print_tracepoint_events(&print_cb, ps);
- else if (strcmp(argv[i], "hw") == 0 ||
- strcmp(argv[i], "hardware") == 0)
- print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
- event_symbols_hw, PERF_COUNT_HW_MAX);
- else if (strcmp(argv[i], "sw") == 0 ||
+ if (strcmp(argv[i], "tracepoint") == 0) {
+ char *old_pmu_glob = default_ps.pmu_glob;
+
+ default_ps.pmu_glob = strdup("tracepoint");
+ if (!default_ps.pmu_glob) {
+ ret = -1;
+ goto out;
+ }
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ zfree(&default_ps.pmu_glob);
+ default_ps.pmu_glob = old_pmu_glob;
+ } else if (strcmp(argv[i], "hw") == 0 ||
+ strcmp(argv[i], "hardware") == 0) {
+ char *old_event_glob = ps->event_glob;
+
+ ps->event_glob = strdup("legacy hardware");
+ if (!ps->event_glob) {
+ ret = -1;
+ goto out;
+ }
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ zfree(&ps->event_glob);
+ ps->event_glob = old_event_glob;
+ } else if (strcmp(argv[i], "sw") == 0 ||
strcmp(argv[i], "software") == 0) {
- print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
- event_symbols_sw, PERF_COUNT_SW_MAX);
- print_tool_events(&print_cb, ps);
+ char *old_pmu_glob = ps->pmu_glob;
+ static const char * const sw_globs[] = { "software", "tool" };
+
+ for (size_t j = 0; j < ARRAY_SIZE(sw_globs); j++) {
+ ps->pmu_glob = strdup(sw_globs[j]);
+ if (!ps->pmu_glob) {
+ ret = -1;
+ goto out;
+ }
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ zfree(&ps->pmu_glob);
+ }
+ ps->pmu_glob = old_pmu_glob;
} else if (strcmp(argv[i], "cache") == 0 ||
- strcmp(argv[i], "hwcache") == 0)
- print_hwcache_events(&print_cb, ps);
- else if (strcmp(argv[i], "pmu") == 0)
- print_pmu_events(&print_cb, ps);
- else if (strcmp(argv[i], "sdt") == 0)
+ strcmp(argv[i], "hwcache") == 0) {
+ char *old_event_glob = ps->event_glob;
+
+ ps->event_glob = strdup("legacy cache");
+ if (!ps->event_glob) {
+ ret = -1;
+ goto out;
+ }
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ zfree(&ps->event_glob);
+ ps->event_glob = old_event_glob;
+ } else if (strcmp(argv[i], "pmu") == 0) {
+ ps->exclude_abi = true;
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ ps->exclude_abi = false;
+ } else if (strcmp(argv[i], "sdt") == 0)
print_sdt_events(&print_cb, ps);
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
- default_ps.metricgroups = false;
- default_ps.metrics = true;
+ ps->metricgroups = false;
+ ps->metrics = true;
metricgroup__print(&print_cb, ps);
} else if (strcmp(argv[i], "metricgroup") == 0 ||
strcmp(argv[i], "metricgroups") == 0) {
- default_ps.metricgroups = true;
- default_ps.metrics = false;
+ ps->metricgroups = true;
+ ps->metrics = false;
metricgroup__print(&print_cb, ps);
- } else if ((sep = strchr(argv[i], ':')) != NULL) {
- char *old_pmu_glob = default_ps.pmu_glob;
-
- default_ps.event_glob = strdup(argv[i]);
- if (!default_ps.event_glob) {
+ }
+#ifdef HAVE_LIBPFM
+ else if (strcmp(argv[i], "pfm") == 0)
+ print_libpfm_events(&print_cb, ps);
+#endif
+ else if ((sep = strchr(argv[i], ':')) != NULL) {
+ char *old_pmu_glob = ps->pmu_glob;
+ char *old_event_glob = ps->event_glob;
+
+ ps->event_glob = strdup(argv[i]);
+ if (!ps->event_glob) {
ret = -1;
goto out;
}
- print_tracepoint_events(&print_cb, ps);
+ ps->pmu_glob = strdup("tracepoint");
+ if (!ps->pmu_glob) {
+ zfree(&ps->event_glob);
+ ret = -1;
+ goto out;
+ }
+ perf_pmus__print_pmu_events(&print_cb, ps);
+ zfree(&ps->pmu_glob);
+ ps->pmu_glob = old_pmu_glob;
print_sdt_events(&print_cb, ps);
- default_ps.metrics = true;
- default_ps.metricgroups = true;
+ ps->metrics = true;
+ ps->metricgroups = true;
metricgroup__print(&print_cb, ps);
- zfree(&default_ps.event_glob);
- default_ps.pmu_glob = old_pmu_glob;
+ zfree(&ps->event_glob);
+ ps->event_glob = old_event_glob;
} else {
if (asprintf(&s, "*%s*", argv[i]) < 0) {
printf("Critical: Not enough memory! Trying to continue...\n");
continue;
}
- default_ps.event_glob = s;
- print_symbol_events(&print_cb, ps, PERF_TYPE_HARDWARE,
- event_symbols_hw, PERF_COUNT_HW_MAX);
- print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE,
- event_symbols_sw, PERF_COUNT_SW_MAX);
- print_tool_events(&print_cb, ps);
- print_hwcache_events(&print_cb, ps);
- print_pmu_events(&print_cb, ps);
- print_tracepoint_events(&print_cb, ps);
+ ps->event_glob = s;
+ perf_pmus__print_pmu_events(&print_cb, ps);
print_sdt_events(&print_cb, ps);
- default_ps.metrics = true;
- default_ps.metricgroups = true;
+ ps->metrics = true;
+ ps->metricgroups = true;
metricgroup__print(&print_cb, ps);
free(s);
}
@@ -574,9 +762,12 @@ int cmd_list(int argc, const char **argv)
out:
print_cb.print_end(ps);
- free(default_ps.pmu_glob);
- free(default_ps.last_topic);
- free(default_ps.last_metricgroups);
- strlist__delete(default_ps.visited_metrics);
+ free(ps->pmu_glob);
+ free(ps->last_topic);
+ free(ps->last_metricgroups);
+ strlist__delete(ps->visited_metrics);
+ if (output_path)
+ fclose(ps->fp);
+
return ret;
}