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

Commit 727ab04e authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo
Browse files

perf evlist: Fix grouping of multiple events



The __perf_evsel__open routing was grouping just the threads for that
specific events per cpu when we want to group all threads in all events
to the first fd opened on that cpu.

So pass the xyarray with the first event, where the other events will be
able to get that first per cpu fd.

At some point top and record will switch to using perf_evlist__open that
takes care of this detail and probably will also handle the fallback
from hw to soft counters, etc.

Reported-by: default avatarDeng-Cheng Zhu <dczhu@mips.com>
Tested-by: default avatarDeng-Cheng Zhu <dczhu@mips.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-ebm34rh098i9y9v4cytfdp0x@git.kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c752d040
Loading
Loading
Loading
Loading
+9 −2
Original line number Original line Diff line number Diff line
@@ -262,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,


static void open_counters(struct perf_evlist *evlist)
static void open_counters(struct perf_evlist *evlist)
{
{
	struct perf_evsel *pos;
	struct perf_evsel *pos, *first;


	if (evlist->cpus->map[0] < 0)
	if (evlist->cpus->map[0] < 0)
		no_inherit = true;
		no_inherit = true;


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

	list_for_each_entry(pos, &evlist->entries, node) {
	list_for_each_entry(pos, &evlist->entries, node) {
		struct perf_event_attr *attr = &pos->attr;
		struct perf_event_attr *attr = &pos->attr;
		struct xyarray *group_fd = NULL;
		/*
		/*
		 * Check if parse_single_tracepoint_event has already asked for
		 * Check if parse_single_tracepoint_event has already asked for
		 * PERF_SAMPLE_TIME.
		 * PERF_SAMPLE_TIME.
@@ -283,11 +286,15 @@ static void open_counters(struct perf_evlist *evlist)
		 */
		 */
		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;


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

		config_attr(pos, evlist);
		config_attr(pos, evlist);
retry_sample_id:
retry_sample_id:
		attr->sample_id_all = sample_id_all_avail ? 1 : 0;
		attr->sample_id_all = sample_id_all_avail ? 1 : 0;
try_again:
try_again:
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
				     group_fd) < 0) {
			int err = errno;
			int err = errno;


			if (err == EPERM || err == EACCES) {
			if (err == EPERM || err == EACCES) {
+14 −6
Original line number Original line Diff line number Diff line
@@ -278,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
struct stats			runtime_dtlb_cache_stats[MAX_NR_CPUS];
struct stats			runtime_dtlb_cache_stats[MAX_NR_CPUS];
struct stats			walltime_nsecs_stats;
struct stats			walltime_nsecs_stats;


static int create_perf_stat_counter(struct perf_evsel *evsel)
static int create_perf_stat_counter(struct perf_evsel *evsel,
				    struct perf_evsel *first)
{
{
	struct perf_event_attr *attr = &evsel->attr;
	struct perf_event_attr *attr = &evsel->attr;
	struct xyarray *group_fd = NULL;

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


	if (scale)
	if (scale)
		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -289,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
	attr->inherit = !no_inherit;
	attr->inherit = !no_inherit;


	if (system_wide)
	if (system_wide)
		return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
		return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,

						group, group_fd);
	if (target_pid == -1 && target_tid == -1) {
	if (target_pid == -1 && target_tid == -1) {
		attr->disabled = 1;
		attr->disabled = 1;
		attr->enable_on_exec = 1;
		attr->enable_on_exec = 1;
	}
	}


	return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
	return perf_evsel__open_per_thread(evsel, evsel_list->threads,
					   group, group_fd);
}
}


/*
/*
@@ -396,7 +402,7 @@ static int read_counter(struct perf_evsel *counter)
static int run_perf_stat(int argc __used, const char **argv)
static int run_perf_stat(int argc __used, const char **argv)
{
{
	unsigned long long t0, t1;
	unsigned long long t0, t1;
	struct perf_evsel *counter;
	struct perf_evsel *counter, *first;
	int status = 0;
	int status = 0;
	int child_ready_pipe[2], go_pipe[2];
	int child_ready_pipe[2], go_pipe[2];
	const bool forks = (argc > 0);
	const bool forks = (argc > 0);
@@ -453,8 +459,10 @@ static int run_perf_stat(int argc __used, const char **argv)
		close(child_ready_pipe[0]);
		close(child_ready_pipe[0]);
	}
	}


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

	list_for_each_entry(counter, &evsel_list->entries, node) {
	list_for_each_entry(counter, &evsel_list->entries, node) {
		if (create_perf_stat_counter(counter) < 0) {
		if (create_perf_stat_counter(counter, first) < 0) {
			if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
			if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
				if (verbose)
				if (verbose)
					ui__warning("%s event is not supported by the kernel.\n",
					ui__warning("%s event is not supported by the kernel.\n",
+3 −3
Original line number Original line Diff line number Diff line
@@ -291,7 +291,7 @@ static int test__open_syscall_event(void)
		goto out_thread_map_delete;
		goto out_thread_map_delete;
	}
	}


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


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


		perf_evlist__add(evlist, evsels[i]);
		perf_evlist__add(evlist, evsels[i]);


		if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
		if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
			pr_debug("failed to open counter: %s, "
			pr_debug("failed to open counter: %s, "
				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
				 strerror(errno));
				 strerror(errno));
+9 −2
Original line number Original line Diff line number Diff line
@@ -834,10 +834,16 @@ static void perf_session__mmap_read(struct perf_session *self)


static void start_counters(struct perf_evlist *evlist)
static void start_counters(struct perf_evlist *evlist)
{
{
	struct perf_evsel *counter;
	struct perf_evsel *counter, *first;

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


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

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


		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
		attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;


@@ -860,7 +866,8 @@ static void start_counters(struct perf_evlist *evlist)
		attr->inherit = inherit;
		attr->inherit = inherit;
try_again:
try_again:
		if (perf_evsel__open(counter, top.evlist->cpus,
		if (perf_evsel__open(counter, top.evlist->cpus,
				     top.evlist->threads, group) < 0) {
				     top.evlist->threads, group,
				     group_fd) < 0) {
			int err = errno;
			int err = errno;


			if (err == EPERM || err == EACCES) {
			if (err == EPERM || err == EACCES) {
+30 −0
Original line number Original line Diff line number Diff line
@@ -539,3 +539,33 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
{
{
	evlist->selected = evsel;
	evlist->selected = evsel;
}
}

int perf_evlist__open(struct perf_evlist *evlist, bool group)
{
	struct perf_evsel *evsel, *first;
	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);
		if (err < 0)
			goto out_err;
	}

	return 0;
out_err:
	ncpus = evlist->cpus ? evlist->cpus->nr : 1;
	nthreads = evlist->threads ? evlist->threads->nr : 1;

	list_for_each_entry_reverse(evsel, &evlist->entries, node)
		perf_evsel__close(evsel, ncpus, nthreads);

	return err;
}
Loading