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

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

perf record: Use perf_evsel__open



Now its time to factor out the mmap handling bits into the perf_evsel
class.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 72cb7013
Loading
Loading
Loading
Loading
+113 −120
Original line number Original line Diff line number Diff line
@@ -72,8 +72,6 @@ static struct perf_evlist *evsel_list;
static long			samples				=      0;
static long			samples				=      0;
static u64			bytes_written			=      0;
static u64			bytes_written			=      0;


static int			nr_cpu				=      0;

static int			file_new			=      1;
static int			file_new			=      1;
static off_t			post_processing_offset;
static off_t			post_processing_offset;


@@ -208,8 +206,6 @@ static void sig_atexit(void)
	kill(getpid(), signr);
	kill(getpid(), signr);
}
}


static int group_fd;

static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
{
{
	struct perf_header_attr *h_attr;
	struct perf_header_attr *h_attr;
@@ -234,7 +230,6 @@ static void create_counter(struct perf_evlist *evlist,
	char *filter = evsel->filter;
	char *filter = evsel->filter;
	struct perf_event_attr *attr = &evsel->attr;
	struct perf_event_attr *attr = &evsel->attr;
	struct perf_header_attr *h_attr;
	struct perf_header_attr *h_attr;
	int track = !evsel->idx; /* only the first counter needs these */
	int thread_index;
	int thread_index;
	int ret;
	int ret;
	struct {
	struct {
@@ -243,19 +238,77 @@ static void create_counter(struct perf_evlist *evlist,
		u64 time_running;
		u64 time_running;
		u64 id;
		u64 id;
	} read_data;
	} read_data;
	/*

 	 * Check if parse_single_tracepoint_event has already asked for
	for (thread_index = 0; thread_index < threads->nr; thread_index++) {
 	 * PERF_SAMPLE_TIME.
		h_attr = get_header_attr(attr, evsel->idx);
 	 *
		if (h_attr == NULL)
	 * XXX this is kludgy but short term fix for problems introduced by
			die("nomem\n");
	 * eac23d1c that broke 'perf script' by having different sample_types

	 * when using multiple tracepoint events when we use a perf binary
		if (!file_new) {
	 * that tries to use sample_id_all on an older kernel.
			if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
 	 *
				fprintf(stderr, "incompatible append\n");
 	 * We need to move counter creation to perf_session, support
				exit(-1);
 	 * different sample_types, etc.
			}
 	 */
		}
	bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;

		if (read(FD(evsel, cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
			perror("Unable to read perf file descriptor");
			exit(-1);
		}

		if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
			pr_warning("Not enough memory to add id\n");
			exit(-1);
		}

		assert(FD(evsel, cpu, thread_index) >= 0);
		fcntl(FD(evsel, cpu, thread_index), F_SETFL, O_NONBLOCK);

		if (evsel->idx || thread_index) {
			struct perf_evsel *first;
			first = list_entry(evlist->entries.next, struct perf_evsel, node);
			ret = ioctl(FD(evsel, cpu, thread_index),
				    PERF_EVENT_IOC_SET_OUTPUT,
				    FD(first, cpu, 0));
			if (ret) {
				error("failed to set output: %d (%s)\n", errno,
						strerror(errno));
				exit(-1);
			}
		} else {
			mmap_array[cpu].prev = 0;
			mmap_array[cpu].mask = mmap_pages*page_size - 1;
			mmap_array[cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
				PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, cpu, thread_index), 0);
			if (mmap_array[cpu].base == MAP_FAILED) {
				error("failed to mmap with %d (%s)\n", errno, strerror(errno));
				exit(-1);
			}

			evlist->pollfd[evlist->nr_fds].fd = FD(evsel, cpu, thread_index);
			evlist->pollfd[evlist->nr_fds].events = POLLIN;
			evlist->nr_fds++;
		}

		if (filter != NULL) {
			ret = ioctl(FD(evsel, cpu, thread_index),
				    PERF_EVENT_IOC_SET_FILTER, filter);
			if (ret) {
				error("failed to set filter with %d (%s)\n", errno,
						strerror(errno));
				exit(-1);
			}
		}
	}

	if (!sample_type)
		sample_type = attr->sample_type;
}

static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
{
	struct perf_event_attr *attr = &evsel->attr;
	int track = !evsel->idx; /* only the first counter needs these */


	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |
	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |
				  PERF_FORMAT_TOTAL_TIME_RUNNING |
				  PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -315,19 +368,39 @@ static void create_counter(struct perf_evlist *evlist,


	attr->mmap		= track;
	attr->mmap		= track;
	attr->comm		= track;
	attr->comm		= track;
	attr->inherit		= !no_inherit;

	if (target_pid == -1 && target_tid == -1 && !system_wide) {
	if (target_pid == -1 && target_tid == -1 && !system_wide) {
		attr->disabled = 1;
		attr->disabled = 1;
		attr->enable_on_exec = 1;
		attr->enable_on_exec = 1;
	}
	}
}

static void open_counters(struct perf_evlist *evlist)
{
	struct perf_evsel *pos;
	int cpu;

	list_for_each_entry(pos, &evlist->entries, node) {
		struct perf_event_attr *attr = &pos->attr;
		/*
		 * Check if parse_single_tracepoint_event has already asked for
		 * PERF_SAMPLE_TIME.
		 *
		 * XXX this is kludgy but short term fix for problems introduced by
		 * eac23d1c that broke 'perf script' by having different sample_types
		 * when using multiple tracepoint events when we use a perf binary
		 * that tries to use sample_id_all on an older kernel.
		 *
		 * We need to move counter creation to perf_session, support
		 * different sample_types, etc.
		 */
		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;

		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;

	for (thread_index = 0; thread_index < threads->nr; thread_index++) {
try_again:
try_again:
		FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
		if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) {

		if (FD(evsel, nr_cpu, thread_index) < 0) {
			int err = errno;
			int err = errno;


			if (err == EPERM || err == EACCES)
			if (err == EPERM || err == EACCES)
@@ -364,7 +437,7 @@ static void create_counter(struct perf_evlist *evlist,
			}
			}
			printf("\n");
			printf("\n");
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
			      FD(evsel, nr_cpu, thread_index), strerror(err));
			      err, strerror(err));


#if defined(__i386__) || defined(__x86_64__)
#if defined(__i386__) || defined(__x86_64__)
			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +448,13 @@ static void create_counter(struct perf_evlist *evlist,
#endif
#endif


			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
			exit(-1);
		}

		h_attr = get_header_attr(attr, evsel->idx);
		if (h_attr == NULL)
			die("nomem\n");

		if (!file_new) {
			if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
				fprintf(stderr, "incompatible append\n");
				exit(-1);
		}
		}
	}
	}


		if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
	for (cpu = 0; cpu < cpus->nr; ++cpu) {
			perror("Unable to read perf file descriptor");
			exit(-1);
		}

		if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
			pr_warning("Not enough memory to add id\n");
			exit(-1);
		}

		assert(FD(evsel, nr_cpu, thread_index) >= 0);
		fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);

		/*
		 * First counter acts as the group leader:
		 */
		if (group && group_fd == -1)
			group_fd = FD(evsel, nr_cpu, thread_index);

		if (evsel->idx || thread_index) {
			struct perf_evsel *first;
			first = list_entry(evlist->entries.next, struct perf_evsel, node);
			ret = ioctl(FD(evsel, nr_cpu, thread_index),
				    PERF_EVENT_IOC_SET_OUTPUT,
				    FD(first, nr_cpu, 0));
			if (ret) {
				error("failed to set output: %d (%s)\n", errno,
						strerror(errno));
				exit(-1);
			}
		} else {
			mmap_array[nr_cpu].prev = 0;
			mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
			mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
				PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
			if (mmap_array[nr_cpu].base == MAP_FAILED) {
				error("failed to mmap with %d (%s)\n", errno, strerror(errno));
				exit(-1);
			}

			evlist->pollfd[evlist->nr_fds].fd = FD(evsel, nr_cpu, thread_index);
			evlist->pollfd[evlist->nr_fds].events = POLLIN;
			evlist->nr_fds++;
		}

		if (filter != NULL) {
			ret = ioctl(FD(evsel, nr_cpu, thread_index),
				    PERF_EVENT_IOC_SET_FILTER, filter);
			if (ret) {
				error("failed to set filter with %d (%s)\n", errno,
						strerror(errno));
				exit(-1);
			}
		}
	}

	if (!sample_type)
		sample_type = attr->sample_type;
}

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

	group_fd = -1;

		list_for_each_entry(pos, &evlist->entries, node)
		list_for_each_entry(pos, &evlist->entries, node)
			create_counter(evlist, pos, cpu);
			create_counter(evlist, pos, cpu);

	}
	nr_cpu++;
}
}


static int process_buildids(void)
static int process_buildids(void)
@@ -533,7 +529,7 @@ static void mmap_read_all(void)
{
{
	int i;
	int i;


	for (i = 0; i < nr_cpu; i++) {
	for (i = 0; i < cpus->nr; i++) {
		if (mmap_array[i].base)
		if (mmap_array[i].base)
			mmap_read(&mmap_array[i]);
			mmap_read(&mmap_array[i]);
	}
	}
@@ -673,12 +669,7 @@ static int __cmd_record(int argc, const char **argv)
		close(child_ready_pipe[0]);
		close(child_ready_pipe[0]);
	}
	}


	if (!system_wide && no_inherit && !cpu_list) {
	open_counters(evsel_list);
		open_counters(evsel_list, -1);
	} else {
		for (i = 0; i < cpus->nr; i++)
			open_counters(evsel_list, cpus->map[i]);
	}


	perf_session__set_sample_type(session, sample_type);
	perf_session__set_sample_type(session, sample_type);


@@ -795,7 +786,7 @@ static int __cmd_record(int argc, const char **argv)
		}
		}


		if (done) {
		if (done) {
			for (i = 0; i < nr_cpu; i++) {
			for (i = 0; i < cpus->nr; i++) {
				struct perf_evsel *pos;
				struct perf_evsel *pos;


				list_for_each_entry(pos, &evsel_list->entries, node) {
				list_for_each_entry(pos, &evsel_list->entries, node) {
@@ -933,11 +924,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
		usage_with_options(record_usage, record_options);
		usage_with_options(record_usage, record_options);
	}
	}


	if (target_tid != -1)
		cpus = cpu_map__dummy_new();
	else
		cpus = cpu_map__new(cpu_list);
		cpus = cpu_map__new(cpu_list);
	if (cpus == NULL) {

		perror("failed to parse CPUs map");
	if (cpus == NULL)
		return -1;
		usage_with_options(record_usage, record_options);
	}


	list_for_each_entry(pos, &evsel_list->entries, node) {
	list_for_each_entry(pos, &evsel_list->entries, node) {
		if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
		if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)