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

Commit 6a4bb04c authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Enable grouping logic for parsed events



This patch adds a functionality that allows to create event groups
based on the way they are specified on the command line. Adding
functionality to the '{}' group syntax introduced in earlier patch.

The current '--group/-g' option behaviour remains intact. If you
specify it for record/stat/top command, all the specified events
become members of a single group with the first event as a group
leader.

With the new '{}' group syntax you can create group like:
  # perf record -e '{cycles,faults}' ls

resulting in single event group containing 'cycles' and 'faults'
events, with cycles event as group leader.

All groups are created with regards to threads and cpus. Thus
recording an event group within a 2 threads on server with
4 CPUs will create 8 separate groups.

Examples (first event in brackets is group leader):

  # 1 group (cpu-clock,task-clock)
  perf record --group -e cpu-clock,task-clock ls
  perf record -e '{cpu-clock,task-clock}' ls

  # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
  perf record -e '{cpu-clock,task-clock},{minor-faults,major-faults}' ls

  # 1 group (cpu-clock,task-clock,minor-faults,major-faults)
  perf record --group -e cpu-clock,task-clock -e minor-faults,major-faults ls
  perf record -e '{cpu-clock,task-clock,minor-faults,major-faults}' ls

  # 2 groups (cpu-clock,task-clock) (minor-faults,major-faults)
  perf record -e '{cpu-clock,task-clock} -e '{minor-faults,major-faults}' \
   -e instructions ls

  # 1 group
  # (cpu-clock,task-clock,minor-faults,major-faults,instructions)
  perf record --group -e cpu-clock,task-clock \
   -e minor-faults,major-faults -e instructions ls perf record -e
'{cpu-clock,task-clock,minor-faults,major-faults,instructions}' ls

It's possible to use standard event modifier for a group, which spans
over all events in the group and updates each event modifier settings,
for example:

  # perf record -r '{faults:k,cache-references}:p'

resulting in ':kp' modifier being used for 'faults' and ':p' modifier
being used for 'cache-references' event.

Reviewed-by: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Acked-by: default avatarPeter Zijlstra <peterz@infradead.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ulrich Drepper <drepper@gmail.com>
Link: http://lkml.kernel.org/n/tip-ho42u0wcr8mn1otkalqi13qp@git.kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent f5b1135b
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -185,18 +185,18 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,

static void perf_record__open(struct perf_record *rec)
{
	struct perf_evsel *pos, *first;
	struct perf_evsel *pos;
	struct perf_evlist *evlist = rec->evlist;
	struct perf_session *session = rec->session;
	struct perf_record_opts *opts = &rec->opts;

	first = list_entry(evlist->entries.next, struct perf_evsel, node);

	perf_evlist__config_attrs(evlist, opts);

	if (opts->group)
		perf_evlist__group(evlist);

	list_for_each_entry(pos, &evlist->entries, node) {
		struct perf_event_attr *attr = &pos->attr;
		struct xyarray *group_fd = NULL;
		/*
		 * Check if parse_single_tracepoint_event has already asked for
		 * PERF_SAMPLE_TIME.
@@ -211,16 +211,13 @@ static void perf_record__open(struct perf_record *rec)
		 */
		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;

		if (opts->group && pos != first)
			group_fd = first->fd;
fallback_missing_features:
		if (opts->exclude_guest_missing)
			attr->exclude_guest = attr->exclude_host = 0;
retry_sample_id:
		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
try_again:
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
				     opts->group, group_fd) < 0) {
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
			int err = errno;

			if (err == EPERM || err == EACCES) {
+5 −8
Original line number Diff line number Diff line
@@ -281,13 +281,9 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
				    struct perf_evsel *first)
{
	struct perf_event_attr *attr = &evsel->attr;
	struct xyarray *group_fd = NULL;
	bool exclude_guest_missing = false;
	int ret;

	if (group && evsel != first)
		group_fd = first->fd;

	if (scale)
		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
				    PERF_FORMAT_TOTAL_TIME_RUNNING;
@@ -299,8 +295,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;

	if (perf_target__has_cpu(&target)) {
		ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
					       group, group_fd);
		ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus);
		if (ret)
			goto check_ret;
		return 0;
@@ -311,8 +306,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
		attr->enable_on_exec = 1;
	}

	ret = perf_evsel__open_per_thread(evsel, evsel_list->threads,
					  group, group_fd);
	ret = perf_evsel__open_per_thread(evsel, evsel_list->threads);
	if (!ret)
		return 0;
	/* fall through */
@@ -483,6 +477,9 @@ static int run_perf_stat(int argc __used, const char **argv)
		close(child_ready_pipe[0]);
	}

	if (group)
		perf_evlist__group(evsel_list);

	first = list_entry(evsel_list->entries.next, struct perf_evsel, node);

	list_for_each_entry(counter, &evsel_list->entries, node) {
+4 −4
Original line number Diff line number Diff line
@@ -294,7 +294,7 @@ static int test__open_syscall_event(void)
		goto out_thread_map_delete;
	}

	if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
	if (perf_evsel__open_per_thread(evsel, threads) < 0) {
		pr_debug("failed to open counter: %s, "
			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
			 strerror(errno));
@@ -369,7 +369,7 @@ static int test__open_syscall_event_on_all_cpus(void)
		goto out_thread_map_delete;
	}

	if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
	if (perf_evsel__open(evsel, cpus, threads) < 0) {
		pr_debug("failed to open counter: %s, "
			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
			 strerror(errno));
@@ -533,7 +533,7 @@ static int test__basic_mmap(void)

		perf_evlist__add(evlist, evsels[i]);

		if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
		if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
			pr_debug("failed to open counter: %s, "
				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
				 strerror(errno));
@@ -737,7 +737,7 @@ static int test__PERF_RECORD(void)
	 * Call sys_perf_event_open on all the fds on all the evsels,
	 * grouping them if asked to.
	 */
	err = perf_evlist__open(evlist, opts.group);
	err = perf_evlist__open(evlist);
	if (err < 0) {
		pr_debug("perf_evlist__open: %s\n", strerror(errno));
		goto out_delete_evlist;
+4 −8
Original line number Diff line number Diff line
@@ -886,17 +886,14 @@ static void perf_top__mmap_read(struct perf_top *top)

static void perf_top__start_counters(struct perf_top *top)
{
	struct perf_evsel *counter, *first;
	struct perf_evsel *counter;
	struct perf_evlist *evlist = top->evlist;

	first = list_entry(evlist->entries.next, struct perf_evsel, node);
	if (top->group)
		perf_evlist__group(evlist);

	list_for_each_entry(counter, &evlist->entries, node) {
		struct perf_event_attr *attr = &counter->attr;
		struct xyarray *group_fd = NULL;

		if (top->group && counter != first)
			group_fd = first->fd;

		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;

@@ -927,8 +924,7 @@ static void perf_top__start_counters(struct perf_top *top)
		attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
try_again:
		if (perf_evsel__open(counter, top->evlist->cpus,
				     top->evlist->threads, top->group,
				     group_fd) < 0) {
				     top->evlist->threads) < 0) {
			int err = errno;

			if (err == EPERM || err == EACCES) {
+9 −11
Original line number Diff line number Diff line
@@ -108,6 +108,12 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
	evlist->nr_entries += nr_entries;
}

void perf_evlist__group(struct perf_evlist *evlist)
{
	if (evlist->nr_entries)
		parse_events__set_leader(&evlist->entries);
}

int perf_evlist__add_default(struct perf_evlist *evlist)
{
	struct perf_event_attr attr = {
@@ -757,21 +763,13 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
	evlist->selected = evsel;
}

int perf_evlist__open(struct perf_evlist *evlist, bool group)
int perf_evlist__open(struct perf_evlist *evlist)
{
	struct perf_evsel *evsel, *first;
	struct perf_evsel *evsel;
	int err, ncpus, nthreads;

	first = list_entry(evlist->entries.next, struct perf_evsel, node);

	list_for_each_entry(evsel, &evlist->entries, node) {
		struct xyarray *group_fd = NULL;

		if (group && evsel != first)
			group_fd = first->fd;

		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
				       group, group_fd);
		err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
		if (err < 0)
			goto out_err;
	}
Loading