mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
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:
parent
ad236fd23b
commit
bcd3279f46
1 changed files with 154 additions and 50 deletions
|
@ -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 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)
|
||||
{
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue