Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+154 −50
Original line number Diff line number Diff line
@@ -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;
	}

static int parse_tracepoint_event(const char **strp,
	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;
	if (!strcmp(evt_name, "*")) {
		*strp = evt_name + evt_length;
	return 1;
		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;

		if (ret != EVT_HANDLED_ALL) {
			attrs[nr_counters] = attr;
			nr_counters++;
		}

		if (*str == 0)
			break;