Commit bcd3279f authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar

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: default avatarFrederic 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: default avatarIngo Molnar <mingo@elte.hu>
parent ad236fd2
......@@ -18,6 +18,12 @@ struct event_symbol {
const char *alias;
};
enum event_result {
EVT_FAILED,
EVT_HANDLED,
EVT_HANDLED_ALL
};
char debugfs_path[MAXPATHLEN];
#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;
}
static int
static enum event_result
parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
{
const char *s = *str;
......@@ -356,7 +362,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
* then bail out:
*/
if (cache_type == -1)
return 0;
return EVT_FAILED;
while ((cache_op == -1 || cache_result == -1) && *s == '-') {
++s;
......@@ -402,27 +408,112 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
attr->type = PERF_TYPE_HW_CACHE;
*str = s;
return 1;
return EVT_HANDLED;
}
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;
}
static int parse_tracepoint_event(const char **strp,
/* 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)
{
const char *evt_name;
char *flags;
char sys_name[MAX_EVENT_LENGTH];
char id_buf[4];
int fd;
unsigned int sys_length, evt_length;
u64 id;
char evt_path[MAXPATHLEN];
if (valid_debugfs_mount(debugfs_path))
return 0;
evt_name = strchr(*strp, ':');
if (!evt_name)
return 0;
return EVT_FAILED;
sys_length = evt_name - *strp;
if (sys_length >= MAX_EVENT_LENGTH)
......@@ -436,30 +527,19 @@ static int parse_tracepoint_event(const char **strp,
if (flags) {
*flags = '\0';
flags++;
if (!strncmp(flags, "record", strlen(flags)))
attr->sample_type |= PERF_SAMPLE_RAW;
}
evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH)
return 0;
return EVT_FAILED;
snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
sys_name, evt_name);
fd = open(evt_path, O_RDONLY);
if (fd < 0)
return 0;
if (read(fd, id_buf, sizeof(id_buf)) < 0) {
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;
if (!strcmp(evt_name, "*")) {
*strp = evt_name + evt_length;
return parse_subsystem_tracepoint_event(sys_name, flags);
} else
return parse_single_tracepoint_event(sys_name, evt_name,
evt_length, flags,
attr, strp);
}
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;
}
static int
static enum event_result
parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
{
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->config = event_symbols[i].config;
*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;
u64 config;
int n;
if (*str != 'r')
return 0;
return EVT_FAILED;
n = hex2u64(str + 1, &config);
if (n > 0) {
*strp = str + n + 1;
attr->type = PERF_TYPE_RAW;
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)
{
const char *str = *strp;
......@@ -530,13 +611,13 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
attr->type = type;
attr->config = config;
*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)
{
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.
* 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) ||
parse_raw_event(str, attr) ||
parse_numeric_event(str, attr) ||
parse_symbolic_event(str, attr) ||
parse_generic_hw_event(str, attr)))
return 0;
enum event_result ret;
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);
return 1;
return ret;
}
int parse_events(const struct option *opt __used, const char *str, int unset __used)
{
struct perf_counter_attr attr;
enum event_result ret;
for (;;) {
if (nr_counters == MAX_COUNTERS)
return -1;
memset(&attr, 0, sizeof(attr));
if (!parse_event_symbols(&str, &attr))
ret = parse_event_symbols(&str, &attr);
if (ret == EVT_FAILED)
return -1;
if (!(*str == 0 || *str == ',' || isspace(*str)))
return -1;
attrs[nr_counters] = attr;
nr_counters++;
if (ret != EVT_HANDLED_ALL) {
attrs[nr_counters] = attr;
nr_counters++;
}
if (*str == 0)
break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment