perf tools: Allow the specification of all tracepoints at once

Currently, when one wants to activate every tracepoint
counters of a subsystem from perf record, the current sequence
is needed:

  perf record -e subsys:ev1 -e subsys:ev2 -e subsys:ev3

This may annoy the most patient of us.

Now we can just do:

  perf record -e subsys:*

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Frederic Weisbecker 2009-09-11 23:19:45 +02:00 committed by Ingo Molnar
parent ad236fd23b
commit bcd3279f46

View file

@ -18,6 +18,12 @@ struct event_symbol {
const char *alias; const char *alias;
}; };
enum event_result {
EVT_FAILED,
EVT_HANDLED,
EVT_HANDLED_ALL
};
char debugfs_path[MAXPATHLEN]; char debugfs_path[MAXPATHLEN];
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
@ -344,7 +350,7 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
return -1; return -1;
} }
static int static enum event_result
parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
{ {
const char *s = *str; const char *s = *str;
@ -356,7 +362,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
* then bail out: * then bail out:
*/ */
if (cache_type == -1) if (cache_type == -1)
return 0; return EVT_FAILED;
while ((cache_op == -1 || cache_result == -1) && *s == '-') { while ((cache_op == -1 || cache_result == -1) && *s == '-') {
++s; ++s;
@ -402,27 +408,112 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
attr->type = PERF_TYPE_HW_CACHE; attr->type = PERF_TYPE_HW_CACHE;
*str = s; *str = s;
return 1; return EVT_HANDLED;
} }
static int parse_tracepoint_event(const char **strp, static enum event_result
parse_single_tracepoint_event(char *sys_name,
const char *evt_name,
unsigned int evt_length,
char *flags,
struct perf_counter_attr *attr,
const char **strp)
{
char evt_path[MAXPATHLEN];
char id_buf[4];
u64 id;
int fd;
if (flags) {
if (!strncmp(flags, "record", strlen(flags)))
attr->sample_type |= PERF_SAMPLE_RAW;
}
snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
sys_name, evt_name);
fd = open(evt_path, O_RDONLY);
if (fd < 0)
return EVT_FAILED;
if (read(fd, id_buf, sizeof(id_buf)) < 0) {
close(fd);
return EVT_FAILED;
}
close(fd);
id = atoll(id_buf);
attr->config = id;
attr->type = PERF_TYPE_TRACEPOINT;
*strp = evt_name + evt_length;
return EVT_HANDLED;
}
/* sys + ':' + event + ':' + flags*/
#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
static enum event_result
parse_subsystem_tracepoint_event(char *sys_name, char *flags)
{
char evt_path[MAXPATHLEN];
struct dirent *evt_ent;
DIR *evt_dir;
snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
evt_dir = opendir(evt_path);
if (!evt_dir) {
perror("Can't open event dir");
return EVT_FAILED;
}
while ((evt_ent = readdir(evt_dir))) {
char event_opt[MAX_EVOPT_LEN + 1];
int len;
unsigned int rem = MAX_EVOPT_LEN;
if (!strcmp(evt_ent->d_name, ".")
|| !strcmp(evt_ent->d_name, "..")
|| !strcmp(evt_ent->d_name, "enable")
|| !strcmp(evt_ent->d_name, "filter"))
continue;
len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name,
evt_ent->d_name);
if (len < 0)
return EVT_FAILED;
rem -= len;
if (flags) {
if (rem < strlen(flags) + 1)
return EVT_FAILED;
strcat(event_opt, ":");
strcat(event_opt, flags);
}
if (parse_events(NULL, event_opt, 0))
return EVT_FAILED;
}
return EVT_HANDLED_ALL;
}
static enum event_result parse_tracepoint_event(const char **strp,
struct perf_counter_attr *attr) struct perf_counter_attr *attr)
{ {
const char *evt_name; const char *evt_name;
char *flags; char *flags;
char sys_name[MAX_EVENT_LENGTH]; char sys_name[MAX_EVENT_LENGTH];
char id_buf[4];
int fd;
unsigned int sys_length, evt_length; unsigned int sys_length, evt_length;
u64 id;
char evt_path[MAXPATHLEN];
if (valid_debugfs_mount(debugfs_path)) if (valid_debugfs_mount(debugfs_path))
return 0; return 0;
evt_name = strchr(*strp, ':'); evt_name = strchr(*strp, ':');
if (!evt_name) if (!evt_name)
return 0; return EVT_FAILED;
sys_length = evt_name - *strp; sys_length = evt_name - *strp;
if (sys_length >= MAX_EVENT_LENGTH) if (sys_length >= MAX_EVENT_LENGTH)
@ -436,30 +527,19 @@ static int parse_tracepoint_event(const char **strp,
if (flags) { if (flags) {
*flags = '\0'; *flags = '\0';
flags++; flags++;
if (!strncmp(flags, "record", strlen(flags)))
attr->sample_type |= PERF_SAMPLE_RAW;
} }
evt_length = strlen(evt_name); evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH) if (evt_length >= MAX_EVENT_LENGTH)
return 0; return EVT_FAILED;
snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, if (!strcmp(evt_name, "*")) {
sys_name, evt_name); *strp = evt_name + evt_length;
fd = open(evt_path, O_RDONLY); return parse_subsystem_tracepoint_event(sys_name, flags);
if (fd < 0) } else
return 0; return parse_single_tracepoint_event(sys_name, evt_name,
evt_length, flags,
if (read(fd, id_buf, sizeof(id_buf)) < 0) { attr, strp);
close(fd);
return 0;
}
close(fd);
id = atoll(id_buf);
attr->config = id;
attr->type = PERF_TYPE_TRACEPOINT;
*strp = evt_name + evt_length;
return 1;
} }
static int check_events(const char *str, unsigned int i) static int check_events(const char *str, unsigned int i)
@ -477,7 +557,7 @@ static int check_events(const char *str, unsigned int i)
return 0; return 0;
} }
static int static enum event_result
parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
{ {
const char *str = *strp; const char *str = *strp;
@ -490,31 +570,32 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
attr->type = event_symbols[i].type; attr->type = event_symbols[i].type;
attr->config = event_symbols[i].config; attr->config = event_symbols[i].config;
*strp = str + n; *strp = str + n;
return 1; return EVT_HANDLED;
} }
} }
return 0; return EVT_FAILED;
} }
static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) static enum event_result
parse_raw_event(const char **strp, struct perf_counter_attr *attr)
{ {
const char *str = *strp; const char *str = *strp;
u64 config; u64 config;
int n; int n;
if (*str != 'r') if (*str != 'r')
return 0; return EVT_FAILED;
n = hex2u64(str + 1, &config); n = hex2u64(str + 1, &config);
if (n > 0) { if (n > 0) {
*strp = str + n + 1; *strp = str + n + 1;
attr->type = PERF_TYPE_RAW; attr->type = PERF_TYPE_RAW;
attr->config = config; attr->config = config;
return 1; return EVT_HANDLED;
} }
return 0; return EVT_FAILED;
} }
static int static enum event_result
parse_numeric_event(const char **strp, struct perf_counter_attr *attr) parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
{ {
const char *str = *strp; const char *str = *strp;
@ -530,13 +611,13 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
attr->type = type; attr->type = type;
attr->config = config; attr->config = config;
*strp = endp; *strp = endp;
return 1; return EVT_HANDLED;
} }
} }
return 0; return EVT_FAILED;
} }
static int static enum event_result
parse_event_modifier(const char **strp, struct perf_counter_attr *attr) parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
{ {
const char *str = *strp; const char *str = *strp;
@ -569,37 +650,60 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
* Each event can have multiple symbolic names. * Each event can have multiple symbolic names.
* Symbolic names are (almost) exactly matched. * Symbolic names are (almost) exactly matched.
*/ */
static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) static enum event_result
parse_event_symbols(const char **str, struct perf_counter_attr *attr)
{ {
if (!(parse_tracepoint_event(str, attr) || enum event_result ret;
parse_raw_event(str, attr) ||
parse_numeric_event(str, attr) ||
parse_symbolic_event(str, attr) ||
parse_generic_hw_event(str, attr)))
return 0;
ret = parse_tracepoint_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
ret = parse_raw_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
ret = parse_numeric_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
ret = parse_symbolic_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
ret = parse_generic_hw_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
return EVT_FAILED;
modifier:
parse_event_modifier(str, attr); parse_event_modifier(str, attr);
return 1; return ret;
} }
int parse_events(const struct option *opt __used, const char *str, int unset __used) int parse_events(const struct option *opt __used, const char *str, int unset __used)
{ {
struct perf_counter_attr attr; struct perf_counter_attr attr;
enum event_result ret;
for (;;) { for (;;) {
if (nr_counters == MAX_COUNTERS) if (nr_counters == MAX_COUNTERS)
return -1; return -1;
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
if (!parse_event_symbols(&str, &attr)) ret = parse_event_symbols(&str, &attr);
if (ret == EVT_FAILED)
return -1; return -1;
if (!(*str == 0 || *str == ',' || isspace(*str))) if (!(*str == 0 || *str == ',' || isspace(*str)))
return -1; return -1;
attrs[nr_counters] = attr; if (ret != EVT_HANDLED_ALL) {
nr_counters++; attrs[nr_counters] = attr;
nr_counters++;
}
if (*str == 0) if (*str == 0)
break; break;