* [PATCH 1/5] perf, tools: Add support for parsing uncore json files
2015-06-05 21:14 perf, tools: Add support for uncore events and updated Intel events Andi Kleen
@ 2015-06-05 21:14 ` Andi Kleen
2015-06-05 21:14 ` [PATCH 2/5] perf, tools: Support per pmu json aliases Andi Kleen
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Andi Kleen @ 2015-06-05 21:14 UTC (permalink / raw)
To: sukadev; +Cc: jolsa, acme, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Handle the Unit field, which is needed to find the right PMU for
an event.
Handle the ExtSel field.
Handle the Filter field.
Filter out zero fields, except for the event itself.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/pmu-events/jevents.c | 130 +++++++++++++++++++++++++++++++++++--
tools/perf/pmu-events/jevents.h | 2 +-
tools/perf/pmu-events/pmu-events.h | 1 +
3 files changed, 126 insertions(+), 7 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index 7347cca..63ade38 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -133,7 +133,6 @@ static struct field {
const char *field;
const char *kernel;
} fields[] = {
- { "EventCode", "event=" },
{ "UMask", "umask=" },
{ "CounterMask", "cmask=" },
{ "Invert", "inv=" },
@@ -162,6 +161,9 @@ static int match_field(char *map, jsmntok_t *field, int nz,
for (f = fields; f->field; f++)
if (json_streq(map, field, f->field) && nz) {
+ if (json_streq(map, val, "0x00") ||
+ json_streq(map, val, "0x0"))
+ return 1;
cut_comma(map, &newval);
addfield(map, event, ",", f->kernel, &newval);
return 1;
@@ -187,6 +189,62 @@ static struct msrmap *lookup_msr(char *map, jsmntok_t *val)
return NULL;
}
+static struct map {
+ const char *json;
+ const char *perf;
+} unit_to_perf[] = {
+ { "CBO", "cbox" },
+ { "QPI LL", "qpi" },
+ { "SBO", "sbox" },
+ {}
+};
+
+static struct map filter_to_perf[] = {
+#if 0
+ { "QPIMatch0[17:0]", "match0"},
+ { "QPIMask0[17:0]", "mask0"},
+ { "QPIMatch0[12:0]", "match0"},
+ { "QPIMask0[12:0]", "mask_mc, match_opc, match_vnw"},
+ { "QPIMatch0[12:0]", "match_mc, match_opc, match_vnw"},
+#endif
+ { "CBoFilter0[22:18]", "filter_state"},
+ { "CBoFilter1[17:10]", "filter_nid"},
+ { "CBoFilter[17:10]", "filter_nid"},
+ { "PCUFilter[7:0]", "filter_band0"},
+ { "PCUFilter[15:8]", "filter_band1"},
+ { "PCUFilter[23:16]", "filter_band2"},
+ { "PCUFilter[31:24]", "filter_band3"},
+ { "QPIMask0[17:0]", "mask0"},
+ { "QPIMask1[19:16]", "mask_rds"},
+ { "QPIMatch0[17:0]", "match_mc, match_opc, match_vnw, match_dnid"},
+ { "QPIMatch1[19:16]", "match_rds"},
+ { "CBoFilter[31:23]", "filter_opc"},
+ { "CBoFilter0[23:17]", "filter_state" },
+#if 0
+ /* Missing in uncore driver currently? */
+ CBoFilter1[15:0]
+ CBoFilter1[28:20]
+ HA_AddrMatch0[31:6]
+ HA_AddrMatch1[13:0]
+ HA_Opcod
+ HA_OpcodeMatch[5:0]
+ IRPFilter[4:0]
+ UBoxFilter[3:0]
+#endif
+ {}
+};
+
+static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val)
+{
+ int i;
+
+ for (i = 0; table[i].json; i++) {
+ if (json_streq(map, val, table[i].json))
+ return table[i].perf;
+ }
+ return NULL;
+}
+
#define EXPECT(e, t, m) do { if (!(e)) { \
jsmntok_t *loc = (t); \
if (!(t)->start && (t) > tokens) \
@@ -203,7 +261,8 @@ 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 *long_desc, char *topic)
+ char *desc, char *long_desc, char *topic,
+ char *unit)
{
FILE *outfp = data;
/*
@@ -219,7 +278,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
fprintf(outfp, "\t.long_desc = \"%s\",\n", long_desc);
if (topic)
fprintf(outfp, "\t.topic = \"%s\",\n", topic);
-
+ if (unit)
+ fprintf(outfp, "\t.unit = \"%s\",\n", unit);
fprintf(outfp, "},\n");
return 0;
@@ -240,7 +300,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,
- char *long_desc, char *topic),
+ char *long_desc, char *topic, char *unit),
void *data)
{
int err = -EIO;
@@ -248,6 +308,7 @@ int json_events(const char *fn,
jsmntok_t *tokens, *tok;
int i, j, len;
char *map;
+ char buf[128];
if (!fn)
return -ENOENT;
@@ -262,6 +323,9 @@ int json_events(const char *fn,
char *long_desc = NULL;
char *extra_desc = NULL;
char *topic = NULL;
+ char *unit = NULL;
+ char *filter = NULL;
+ unsigned long long eventcode = 0;
struct msrmap *msr = NULL;
jsmntok_t *msrval = NULL;
jsmntok_t *precise = NULL;
@@ -282,6 +346,16 @@ int json_events(const char *fn,
nz = !json_streq(map, val, "0");
if (match_field(map, field, nz, &event, val)) {
/* ok */
+ } else if (json_streq(map, field, "EventCode")) {
+ char *code = NULL;
+ addfield(map, &code, "", "", val);
+ eventcode |= strtoul(code, NULL, 0);
+ free(code);
+ } else if (json_streq(map, field, "ExtSel")) {
+ char *code = NULL;
+ addfield(map, &code, "", "", val);
+ eventcode |= strtoul(code, NULL, 0) << 21;
+ free(code);
} else if (json_streq(map, field, "EventName")) {
addfield(map, &name, "", "", val);
} else if (json_streq(map, field, "BriefDescription")) {
@@ -306,9 +380,46 @@ int json_events(const char *fn,
addfield(map, &extra_desc, ". ",
" Supports address when precise",
NULL);
+ } else if (json_streq(map, field, "Unit")) {
+ const char *punit;
+ char *s;
+
+ addfield(map, &topic, " ", "Uncore ", val);
+
+ punit = field_to_perf(unit_to_perf, map, val);
+ if (punit) {
+ unit = strdup(punit);
+ } else {
+ addfield(map, &unit, "", "", val);
+ for (s = unit; *s; s++)
+ *s = tolower(*s);
+ }
+ addfield(map, &desc, ". ", "Unit: ", NULL);
+ addfield(map, &desc, "", unit, NULL);
+ } else if (json_streq(map, field, "Filter")) {
+ jsmntok_t nt = *val;
+ const char *nf;
+
+ do {
+ cut_comma(map, &nt);
+ while (nt.start < val->end && isspace(map[nt.start]))
+ nt.start++;
+ nf = field_to_perf(filter_to_perf, map, &nt);
+ if (!nf) {
+ if (verbose > 1)
+ printf("no filter match %.*s\n",
+ json_len(&nt), map + nt.start);
+ addfield(map, &filter, " ", "", &nt);
+ } else
+ addfield(map, &filter, " ", nf, NULL);
+ nt.start = nt.end + 1;
+ nt.end = val->end;
+ } while (nt.start < val->end);
}
/* ignore unknown fields */
}
+ if (verbose > 1 && filter && strchr(filter, '['))
+ printf("%s\n", name);
if (precise && !strstr(desc, "(Precise Event)")) {
if (json_streq(map, precise, "2"))
addfield(map, &extra_desc, " ",
@@ -317,21 +428,28 @@ int json_events(const char *fn,
addfield(map, &extra_desc, " ",
"(Precise event)", NULL);
}
+ snprintf(buf, sizeof buf, "event=%#llx", eventcode);
+ addfield(map, &event, ",", buf, NULL);
if (desc && extra_desc)
addfield(map, &desc, " ", extra_desc, NULL);
if (long_desc && extra_desc)
addfield(map, &long_desc, " ", extra_desc, NULL);
+ if (filter) {
+ addfield(map, &desc, ". ", "Filter: ", NULL);
+ addfield(map, &desc, "", filter, NULL);
+ }
if (msr != NULL)
addfield(map, &event, ",", msr->pname, msrval);
fixname(name);
-
- err = func(data, name, event, desc, long_desc, topic);
+ err = func(data, name, event, desc, long_desc, topic, unit);
free(event);
free(desc);
free(name);
free(long_desc);
free(extra_desc);
free(topic);
+ free(unit);
+ free(filter);
if (err)
break;
tok += j;
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
index 9ffcb89..bf6cf79 100644
--- a/tools/perf/pmu-events/jevents.h
+++ b/tools/perf/pmu-events/jevents.h
@@ -3,7 +3,7 @@
int json_events(const char *fn,
int (*func)(void *data, char *name, char *event, char *desc,
- char *long_desc, char *topic),
+ char *long_desc, char *topic, char *unit),
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 6b69f4b..cafea50 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -10,6 +10,7 @@ struct pmu_event {
const char *desc;
const char *long_desc;
const char *topic;
+ const char *unit;
};
/*
--
2.4.2
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 4/5] perf, tools: Add debug support for outputing alias string
2015-06-05 21:14 perf, tools: Add support for uncore events and updated Intel events Andi Kleen
` (2 preceding siblings ...)
2015-06-05 21:14 ` [PATCH 3/5] perf, tools: Support event aliases for non cpu// pmus Andi Kleen
@ 2015-06-05 21:14 ` Andi Kleen
2015-06-05 21:14 ` [PATCH 5/5] perf, tools: Expand PMU events by prefetch match Andi Kleen
4 siblings, 0 replies; 6+ messages in thread
From: Andi Kleen @ 2015-06-05 21:14 UTC (permalink / raw)
To: sukadev; +Cc: jolsa, acme, linux-kernel, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
For debugging and testing it is useful to see the converted
alias string. Add support to perf stat/record and perf list to print
the alias conversion. The text string is saved in the alias structure.
For perf stat/record it is folded into the normal -v. For perf list
-v was taken, so we use --debug.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-list.c | 5 ++++-
tools/perf/util/parse-events.y | 3 +++
tools/perf/util/pmu.c | 7 +++++++
tools/perf/util/pmu.h | 1 +
4 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index d0f7a18..c3c4594 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -15,6 +15,7 @@
#include "util/cache.h"
#include "util/pmu.h"
#include "util/parse-options.h"
+#include "util/debug.h"
static bool desc_flag = true;
@@ -29,10 +30,12 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
"Print extra event descriptions. --no-desc to not print."),
OPT_BOOLEAN('d', "long-desc", &long_desc_flag,
"Print longer event descriptions."),
+ OPT_INCR(0, "debug", &verbose,
+ "Enable debugging output"),
OPT_END()
};
const char * const list_usage[] = {
- "perf list [--no-desc] [hw|sw|cache|tracepoint|pmu|event_glob]",
+ "perf list [--no-desc] [-v] [hw|sw|cache|tracepoint|pmu|event_glob]",
NULL
};
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 12745ce..2b90fb8 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include "util.h"
#include "pmu.h"
+#include "debug.h"
#include "parse-events.h"
#include "parse-events-bison.h"
@@ -246,6 +247,8 @@ PE_KERNEL_PMU_EVENT sep_dc
if (!strcasecmp(alias->name, $1)) {
if (!parse_events_add_pmu(data, list,
pmu->name, head)) {
+ pr_debug("%s -> %s/%s/\n", $1,
+ pmu->name, alias->str);
ok++;
}
}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index dac87bc..788bd9e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -247,6 +247,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
alias->long_desc = long_desc ? strdup(long_desc) :
desc ? strdup(desc) : NULL;
alias->topic = topic ? strdup(topic) : NULL;
+ alias->str = strdup(val);
list_add_tail(&alias->list, list);
@@ -1023,6 +1024,8 @@ struct sevent {
char *name;
char *desc;
char *topic;
+ char *str;
+ char *pmu;
};
static int cmp_sevent(const void *a, const void *b)
@@ -1116,6 +1119,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
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;
j++;
}
if (pmu->selectable) {
@@ -1149,6 +1154,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
printf("%*s", 8, "[");
wordwrap(aliases[j].desc, 8, columns, 0);
printf("]\n");
+ if (verbose)
+ printf("%*s%s/%s/\n", 8, "", aliases[j].pmu, aliases[j].str);
} else
printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
printed++;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index b3fe9b8..92d40c3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -41,6 +41,7 @@ struct perf_pmu_alias {
char *desc;
char *long_desc;
char *topic;
+ char *str;
struct list_head terms; /* HEAD struct parse_events_term -> list */
struct list_head list; /* ELEM */
char unit[UNIT_MAX_LEN+1];
--
2.4.2
^ permalink raw reply [flat|nested] 6+ messages in thread