[PATCH 2/3] perf, tools: Support long descriptions with perf list -v

From: Andi Kleen
Date: Sun May 31 2015 - 12:12:49 EST


From: Andi Kleen <ak@xxxxxxxxxxxxxxx>

Previously we were dropping the useful longer descriptions that some
events have in the event list completely. This patch makes them appear with
perf list.

Old perf list:

baclears:
baclears.all
[Counts the number of baclears]

vs new:

perf list -v:
...
baclears:
baclears.all
[The BACLEARS event counts the number of times the front end is resteered, mainly when
the Branch Prediction Unit cannot provide a correct prediction and this is corrected
by the Branch Address Calculator at the front end. The BACLEARS.ANY event counts the
number of baclears for any type of branch]

Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
---
tools/perf/builtin-list.c | 9 ++++++---
tools/perf/pmu-events/jevents.c | 29 ++++++++++++++++++++---------
tools/perf/pmu-events/jevents.h | 2 +-
tools/perf/pmu-events/pmu-events.h | 1 +
tools/perf/util/parse-events.c | 4 ++--
tools/perf/util/parse-events.h | 2 +-
tools/perf/util/pmu.c | 17 ++++++++++++-----
tools/perf/util/pmu.h | 4 +++-
8 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 3f058f7..c912368 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -22,10 +22,13 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{
int i;
bool raw_dump = false;
+ bool long_desc_flag = false;
struct option list_options[] = {
OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
OPT_BOOLEAN('d', "desc", &desc_flag,
"Print extra event descriptions. --no-desc to not print."),
+ OPT_BOOLEAN('v', "long-desc", &long_desc_flag,
+ "Print longer event descriptions."),
OPT_END()
};
const char * const list_usage[] = {
@@ -44,7 +47,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
printf("\nList of pre-defined events (to be used in -e):\n\n");

if (argc == 0) {
- print_events(NULL, raw_dump, !desc_flag);
+ print_events(NULL, raw_dump, !desc_flag, long_desc_flag);
return 0;
}

@@ -63,13 +66,13 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL, raw_dump);
else if (strcmp(argv[i], "pmu") == 0)
- print_pmu_events(NULL, raw_dump, !desc_flag);
+ print_pmu_events(NULL, raw_dump, !desc_flag, long_desc_flag);
else {
char *sep = strchr(argv[i], ':'), *s;
int sep_idx;

if (sep == NULL) {
- print_events(argv[i], raw_dump, !desc_flag);
+ print_events(argv[i], raw_dump, !desc_flag, long_desc_flag);
continue;
}
sep_idx = sep - argv[i];
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index 43651cc..da9408c 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -202,7 +202,7 @@ static void print_events_table_prefix(FILE *fp, const char *tblname)
}

static int print_events_table_entry(void *data, char *name, char *event,
- char *desc)
+ char *desc, char *long_desc)
{
FILE *outfp = data;
/*
@@ -214,7 +214,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
fprintf(outfp, "\t.name = \"%s\",\n", name);
fprintf(outfp, "\t.event = \"%s\",\n", event);
fprintf(outfp, "\t.desc = \"%s\",\n", desc);
-
+ if (long_desc && long_desc[0])
+ fprintf(outfp, "\t.long_desc = \"%s\"", long_desc);
fprintf(outfp, "},\n");

return 0;
@@ -234,7 +235,7 @@ static void print_events_table_suffix(FILE *outfp)

/* Call func with each event in the json file */
int json_events(const char *fn,
- int (*func)(void *data, char *name, char *event, char *desc),
+ int (*func)(void *data, char *name, char *event, char *desc, char *long_desc),
void *data)
{
int err = -EIO;
@@ -252,7 +253,8 @@ int json_events(const char *fn,
EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array");
tok = tokens + 1;
for (i = 0; i < tokens->size; i++) {
- char *event = NULL, *desc = NULL, *name = NULL;
+ char *event = NULL, *desc = NULL, *name = NULL, *long_desc = NULL;
+ char *extra_desc = NULL;
struct msrmap *msr = NULL;
jsmntok_t *msrval = NULL;
jsmntok_t *precise = NULL;
@@ -278,6 +280,9 @@ int json_events(const char *fn,
} else if (json_streq(map, field, "BriefDescription")) {
addfield(map, &desc, "", "", val);
fixdesc(desc);
+ } else if (json_streq(map, field, "PublicDescription")) {
+ addfield(map, &long_desc, "", "", val);
+ fixdesc(long_desc);
} else if (json_streq(map, field, "PEBS") && nz) {
precise = val;
} else if (json_streq(map, field, "MSRIndex") && nz) {
@@ -286,10 +291,10 @@ int json_events(const char *fn,
msrval = val;
} else if (json_streq(map, field, "Errata") &&
!json_streq(map, val, "null")) {
- addfield(map, &desc, ". ",
+ addfield(map, &extra_desc, ". ",
" Spec update: ", val);
} else if (json_streq(map, field, "Data_LA") && nz) {
- addfield(map, &desc, ". ",
+ addfield(map, &extra_desc, ". ",
" Supports address when precise",
NULL);
}
@@ -297,19 +302,25 @@ int json_events(const char *fn,
}
if (precise && !strstr(desc, "(Precise Event)")) {
if (json_streq(map, precise, "2"))
- addfield(map, &desc, " ", "(Must be precise)",
+ addfield(map, &extra_desc, " ", "(Must be precise)",
NULL);
else
- addfield(map, &desc, " ",
+ addfield(map, &extra_desc, " ",
"(Precise event)", NULL);
}
+ if (desc && extra_desc)
+ addfield(map, &desc, " ", extra_desc, NULL);
+ if (long_desc && extra_desc)
+ addfield(map, &long_desc, " ", extra_desc, NULL);
if (msr != NULL)
addfield(map, &event, ",", msr->pname, msrval);
fixname(name);
- err = func(data, name, event, desc);
+ err = func(data, name, event, desc, long_desc);
free(event);
free(desc);
free(name);
+ free(extra_desc);
+ free(long_desc);
if (err)
break;
tok += j;
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
index 996601f..2168ad4 100644
--- a/tools/perf/pmu-events/jevents.h
+++ b/tools/perf/pmu-events/jevents.h
@@ -2,7 +2,7 @@
#define JEVENTS_H 1

int json_events(const char *fn,
- int (*func)(void *data, char *name, char *event, char *desc),
+ int (*func)(void *data, char *name, char *event, char *desc, char *long_desc),
void *data);
char *get_cpu_str(void);

diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 39fec04..711f049 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -8,6 +8,7 @@ struct pmu_event {
const char *name;
const char *event;
const char *desc;
+ const char *long_desc;
};

/*
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c660061..a6bf781 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1419,7 +1419,7 @@ out_enomem:
/*
* Print the help text for the event symbols:
*/
-void print_events(const char *event_glob, bool name_only, bool quiet_flag)
+void print_events(const char *event_glob, bool name_only, bool quiet_flag, bool long_desc)
{
print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -1429,7 +1429,7 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag)

print_hwcache_events(event_glob, name_only);

- print_pmu_events(event_glob, name_only, quiet_flag);
+ print_pmu_events(event_glob, name_only, quiet_flag, long_desc);

if (event_glob != NULL)
return;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index cdb100e..698cf45 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -115,7 +115,7 @@ void parse_events_update_lists(struct list_head *list_event,
struct list_head *list_all);
void parse_events_error(void *data, void *scanner, char const *msg);

-void print_events(const char *event_glob, bool name_only, bool quiet);
+void print_events(const char *event_glob, bool name_only, bool quiet, bool long_desc);

struct event_symbol {
const char *symbol;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 5c30f89..a85eade 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -201,7 +201,8 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
return 0;
}

-static int __perf_pmu__new_alias(struct list_head *list, char *name, char *dir, char *desc __maybe_unused, char *val)
+static int __perf_pmu__new_alias(struct list_head *list, char *name, char *dir, char *desc __maybe_unused, char *val,
+ char *long_desc)
{
struct perf_pmu_alias *alias;
int ret;
@@ -234,6 +235,9 @@ static int __perf_pmu__new_alias(struct list_head *list, char *name, char *dir,
}

alias->desc = desc ? strdup(desc) : NULL;
+ alias->long_desc = long_desc ?
+ strdup(long_desc) :
+ desc ? strdup(desc) : NULL;

list_add_tail(&alias->list, list);

@@ -250,7 +254,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
return -EINVAL;
buf[ret] = 0;

- return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+ return __perf_pmu__new_alias(list, name, dir, NULL, buf, NULL);
}

static inline bool pmu_alias_info_file(char *name)
@@ -503,7 +507,8 @@ static int pmu_add_cpu_aliases(void *data)

/* need type casts to override 'const' */
__perf_pmu__new_alias(head, (char *)pe->name, NULL,
- (char *)pe->desc, (char *)pe->event);
+ (char *)pe->desc, (char *)pe->event,
+ (char *)pe->long_desc);
}

free(cpuid);
@@ -976,7 +981,8 @@ static void wordwrap(char *s, int start, int max, int corr)
}
}

-void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag)
+void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
+ bool long_desc)
{
struct perf_pmu *pmu;
struct perf_pmu_alias *alias;
@@ -1021,7 +1027,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag)
pmu, alias);
aliases[j].name = strdup(aliases[j].name);
/* failure harmless */
- aliases[j].desc = alias->desc;
+ aliases[j].desc = long_desc ? alias->long_desc :
+ alias->desc;
j++;
}
if (pmu->selectable) {
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 3ca632b..e0f7ed3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -38,6 +38,7 @@ struct perf_pmu_info {
struct perf_pmu_alias {
char *name;
char *desc;
+ char *long_desc;
struct list_head terms; /* HEAD struct parse_events_term -> list */
struct list_head list; /* ELEM */
char unit[UNIT_MAX_LEN+1];
@@ -67,7 +68,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);

struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);

-void print_pmu_events(const char *event_glob, bool name_only, bool quiet);
+void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
+ bool long_desc);
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,
--
2.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/