mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +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;
|
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;
|
||||||
|
|
Loading…
Reference in a new issue