This fixes some left over issues in my Haswell PMU patchkit yesterday:
Ideally applied on top, although there should be no direct dependencies.
- Now the kernel supplied sysfs aliases can be directly used for cpu.
This means I can use "tx-aborts" instead of "cpu/tx-aborts/
- List the kernel events
- Support using the same names as generic events for kernel events.
This allows to use cpu/instructions,intx=1/ which was not possible
before because instructions clashed with the generic name.
-Andi
From: Andi Kleen <[email protected]>
Extend the parser/lexer to allow generic event names like,
"instructions" as a sysfs supplied PMU event name too.
This resolves the problem that cpu/instructions/ gives a parse
error, even when the kernel supplies a "instructions" event
This is useful to add sysfs specified qualifiers to these
events, for example cpu/instructions,intx=1/ and needed
for the TSX events
Simply extend the grammar to handle this case. The lexer
needs minor changes to save the original string.
Signed-off-by: Andi Kleen <[email protected]>
---
tools/perf/util/parse-events.l | 3 ++-
tools/perf/util/parse-events.y | 27 +++++++++++++++++++++++----
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index c2e5142..dd3a901 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -55,7 +55,8 @@ static int sym(yyscan_t scanner, int type, int config)
{
YYSTYPE *yylval = parse_events_get_lval(scanner);
- yylval->num = (type << 16) + config;
+ yylval->namenum.num = (type << 16) + config;
+ yylval->namenum.name = strdup(parse_events_get_text(scanner));
return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index cd88209..5b26ad3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -34,8 +34,8 @@ do { \
%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
%token PE_ERROR
%type <num> PE_VALUE
-%type <num> PE_VALUE_SYM_HW
-%type <num> PE_VALUE_SYM_SW
+%type <namenum> PE_VALUE_SYM_HW
+%type <namenum> PE_VALUE_SYM_SW
%type <num> PE_RAW
%type <num> PE_TERM
%type <str> PE_NAME
@@ -65,6 +65,7 @@ do { \
%union
{
+ struct { char *name; u64 num; } namenum;
char *str;
u64 num;
struct list_head *head;
@@ -195,9 +196,9 @@ PE_NAME '/' event_config '/'
}
value_sym:
-PE_VALUE_SYM_HW
+PE_VALUE_SYM_HW { free($1.name); return $1.num; }
|
-PE_VALUE_SYM_SW
+PE_VALUE_SYM_SW { free($1.name); return $1.num; }
event_legacy_symbol:
value_sym '/' event_config '/'
@@ -361,6 +362,24 @@ PE_NAME
$$ = term;
}
|
+PE_VALUE_SYM_HW
+{
+ struct parse_events__term *term;
+
+ ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ $1.name, 1));
+ $$ = term;
+}
+|
+PE_VALUE_SYM_SW
+{
+ struct parse_events__term *term;
+
+ ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ $1.name, 1));
+ $$ = term;
+}
+|
PE_TERM '=' PE_NAME
{
struct parse_events__term *term;
--
1.7.7.6
From: Andi Kleen <[email protected]>
When an event fails to parse and it's not in a new style format,
try to parse it again as a cpu event.
This allows to use sysfs exported events directly without //, so I can use
perf record -e tx-aborts ...
instead of
perf record -e cpu/tx-aborts/
Signed-off-by: Andi Kleen <[email protected]>
---
tools/perf/util/parse-events.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index de1cb9e..4e7117f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -785,6 +785,16 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
parse_events__flush_buffer(buffer, scanner);
parse_events__delete_buffer(buffer, scanner);
parse_events_lex_destroy(scanner);
+
+ if (ret && !strchr(str, '/')) {
+ char *s = malloc(strlen(str) + strlen("cpu/") + 2);
+
+ if (!s)
+ return ret;
+ sprintf(s, "cpu/%s/", str);
+ str = s;
+ return parse_events__scanner(str, data, start_token);
+ }
return ret;
}
--
1.7.7.6
From: Andi Kleen <[email protected]>
List the kernel supplied pmu event aliases in perf list
It's better when the users can actually see them.
Signed-off-by: Andi Kleen <[email protected]>
---
tools/perf/Documentation/perf-list.txt | 4 +-
tools/perf/builtin-list.c | 3 +
tools/perf/util/parse-events.c | 5 ++-
tools/perf/util/pmu.c | 71 ++++++++++++++++++++++++++++++++
tools/perf/util/pmu.h | 3 +
5 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index d1e39dc..826f3d6 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
-'perf list' [hw|sw|cache|tracepoint|event_glob]
+'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
DESCRIPTION
-----------
@@ -104,6 +104,8 @@ To limit the list use:
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
block, etc.
+. 'pmu' to print the kernel supplied PMU events.
+
. If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match.
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 1948ece..e79f423 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
#include "util/parse-events.h"
#include "util/cache.h"
+#include "util/pmu.h"
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{
@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
else if (strcmp(argv[i], "cache") == 0 ||
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL, false);
+ else if (strcmp(argv[i], "pmu") == 0)
+ print_pmu_events(NULL, false);
else if (strcmp(argv[i], "--raw-dump") == 0)
print_events(NULL, true);
else {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4e7117f..0b1a4b1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1033,6 +1033,8 @@ int print_hwcache_events(const char *event_glob, bool name_only)
}
}
+ if (printed)
+ printf("\n");
return printed;
}
@@ -1087,11 +1089,12 @@ void print_events(const char *event_glob, bool name_only)
print_hwcache_events(event_glob, name_only);
+ print_pmu_events(event_glob, name_only);
+
if (event_glob != NULL)
return;
if (!name_only) {
- printf("\n");
printf(" %-50s [%s]\n",
"rNNN",
event_type_descriptors[PERF_TYPE_RAW]);
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8a2229d..c0d2fc9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -551,6 +551,77 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
set_bit(b, bits);
}
+static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
+ struct perf_pmu__alias *alias)
+{
+ snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
+ return buf;
+}
+
+static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
+ struct perf_pmu__alias *alias)
+{
+ snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
+ return buf;
+}
+
+static int cmp_string(const void *a, const void *b)
+{
+ const char * const *as = a;
+ const char * const *bs = b;
+ return strcmp(*as, *bs);
+}
+
+void print_pmu_events(const char *event_glob, bool name_only)
+{
+ struct perf_pmu *pmu;
+ struct perf_pmu__alias *alias;
+ char buf[1024];
+ int printed = 0;
+ int len, j;
+ char **aliases;
+
+ pmu = NULL;
+ len = 0;
+ while ((pmu = perf_pmu__scan(pmu)) != NULL)
+ list_for_each_entry (alias, &pmu->aliases, list)
+ len++;
+ aliases = malloc(sizeof(char *) * len);
+ if (!aliases)
+ return;
+ pmu = NULL;
+ j = 0;
+ while ((pmu = perf_pmu__scan(pmu)) != NULL)
+ list_for_each_entry (alias, &pmu->aliases, list) {
+ char *name = format_alias(buf, sizeof buf, pmu, alias);
+ bool is_cpu = !strcmp(pmu->name, "cpu");
+
+ if (event_glob != NULL &&
+ !(strglobmatch(name, event_glob) ||
+ (!is_cpu && strglobmatch(alias->name, event_glob))))
+ continue;
+ aliases[j] = name;
+ if (is_cpu && !name_only)
+ aliases[j] = format_alias_or(buf, sizeof buf,
+ pmu, alias);
+ aliases[j] = strdup(aliases[j]);
+ j++;
+ }
+ qsort(aliases, len, sizeof(char *), cmp_string);
+ for (j = 0; j < len; j++) {
+ if (name_only) {
+ printf("%s ", aliases[j]);
+ continue;
+ }
+ printf(" %-50s [Kernel PMU event]\n", aliases[j]);
+ free(aliases[j]);
+ printed++;
+ }
+ if (printed)
+ printf("\n");
+ free(aliases);
+}
+
/* Simulated format definitions. */
static struct test_format {
const char *name;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 53c7794..b4e0203 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include "../../../include/linux/perf_event.h"
+#include <stdbool.h>
enum {
PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -49,5 +50,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to);
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
+void print_pmu_events(const char *event_glob, bool name_only);
+
int perf_pmu__test(void);
#endif /* __PMU_H */
--
1.7.7.6
On 10/03/2012 11:22 PM, Andi Kleen wrote:
> This fixes some left over issues in my Haswell PMU patchkit yesterday:
> Ideally applied on top, although there should be no direct dependencies.
>
> - Now the kernel supplied sysfs aliases can be directly used for cpu.
> This means I can use "tx-aborts" instead of "cpu/tx-aborts/
> - List the kernel events
> - Support using the same names as generic events for kernel events.
> This allows to use cpu/instructions,intx=1/ which was not possible
> before because instructions clashed with the generic name.
I (i.e. me, moi) received only patches 2/3 and 3/3. Is there a patch 1/3?
On Sat, Oct 06, 2012 at 04:57:20PM +0200, Jan Ceuleers wrote:
> On 10/03/2012 11:22 PM, Andi Kleen wrote:
> > This fixes some left over issues in my Haswell PMU patchkit yesterday:
> > Ideally applied on top, although there should be no direct dependencies.
> >
> > - Now the kernel supplied sysfs aliases can be directly used for cpu.
> > This means I can use "tx-aborts" instead of "cpu/tx-aborts/
> > - List the kernel events
> > - Support using the same names as generic events for kernel events.
> > This allows to use cpu/instructions,intx=1/ which was not possible
> > before because instructions clashed with the generic name.
>
> I (i.e. me, moi) received only patches 2/3 and 3/3. Is there a patch 1/3?
Yes there was. Not sure what happened. But these three patches had some bugs,
I'll post an updated version folded into the original Haswell patchkit
after the merge window closes. Right now people seem to be too busy
to review it.
Let me know if you want to test something earlier.
-Andi
--
[email protected] -- Speaking for myself only.