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

Commit 92858553 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'perf/test' of...

Merge branch 'perf/test' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
parents cc222196 d854861c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -396,6 +396,7 @@ LIB_H += util/build-id.h
LIB_H += util/debug.h
LIB_H += util/debugfs.h
LIB_H += util/event.h
LIB_H += util/evsel.h
LIB_H += util/exec_cmd.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
@@ -404,6 +405,7 @@ LIB_H += util/parse-options.h
LIB_H += util/parse-events.h
LIB_H += util/quote.h
LIB_H += util/util.h
LIB_H += util/xyarray.h
LIB_H += util/header.h
LIB_H += util/help.h
LIB_H += util/session.h
@@ -433,6 +435,7 @@ LIB_OBJS += $(OUTPUT)util/ctype.o
LIB_OBJS += $(OUTPUT)util/debugfs.o
LIB_OBJS += $(OUTPUT)util/environment.o
LIB_OBJS += $(OUTPUT)util/event.o
LIB_OBJS += $(OUTPUT)util/evsel.o
LIB_OBJS += $(OUTPUT)util/exec_cmd.o
LIB_OBJS += $(OUTPUT)util/help.o
LIB_OBJS += $(OUTPUT)util/levenshtein.o
@@ -470,6 +473,7 @@ LIB_OBJS += $(OUTPUT)util/sort.o
LIB_OBJS += $(OUTPUT)util/hist.o
LIB_OBJS += $(OUTPUT)util/probe-event.o
LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o

BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
+68 −84
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "util/header.h"
#include "util/event.h"
#include "util/evsel.h"
#include "util/debug.h"
#include "util/session.h"
#include "util/symbol.h"
@@ -27,18 +28,18 @@
#include <sched.h>
#include <sys/mman.h>

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))

enum write_mode_t {
	WRITE_FORCE,
	WRITE_APPEND
};

static int			*fd[MAX_NR_CPUS][MAX_COUNTERS];

static u64			user_interval			= ULLONG_MAX;
static u64			default_interval		=      0;
static u64			sample_type;

static int			nr_cpus				=      0;
static struct cpu_map		*cpus;
static unsigned int		page_size;
static unsigned int		mmap_pages			=    128;
static unsigned int		user_freq 			= UINT_MAX;
@@ -53,8 +54,7 @@ static bool sample_id_all_avail = true;
static bool			system_wide			=  false;
static pid_t			target_pid			=     -1;
static pid_t			target_tid			=     -1;
static pid_t			*all_tids			=      NULL;
static int			thread_num			=      0;
static struct thread_map	*threads;
static pid_t			child_pid			=     -1;
static bool			no_inherit			=  false;
static enum write_mode_t	write_mode			= WRITE_FORCE;
@@ -81,7 +81,6 @@ static struct perf_session *session;
static const char		*cpu_list;

struct mmap_data {
	int			counter;
	void			*base;
	unsigned int		mask;
	unsigned int		prev;
@@ -229,12 +228,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
	return h_attr;
}

static void create_counter(int counter, int cpu)
static void create_counter(struct perf_evsel *evsel, int cpu)
{
	char *filter = filters[counter];
	struct perf_event_attr *attr = attrs + counter;
	char *filter = evsel->filter;
	struct perf_event_attr *attr = &evsel->attr;
	struct perf_header_attr *h_attr;
	int track = !counter; /* only the first counter needs these */
	int track = !evsel->idx; /* only the first counter needs these */
	int thread_index;
	int ret;
	struct {
@@ -318,12 +317,11 @@ static void create_counter(int counter, int cpu)
retry_sample_id:
	attr->sample_id_all = sample_id_all_avail ? 1 : 0;

	for (thread_index = 0; thread_index < thread_num; thread_index++) {
	for (thread_index = 0; thread_index < threads->nr; thread_index++) {
try_again:
		fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr,
				all_tids[thread_index], cpu, group_fd, 0);
		FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);

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

			if (err == EPERM || err == EACCES)
@@ -360,7 +358,7 @@ try_again:
			}
			printf("\n");
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
					fd[nr_cpu][counter][thread_index], strerror(err));
			      FD(evsel, nr_cpu, thread_index), strerror(err));

#if defined(__i386__) || defined(__x86_64__)
			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -374,7 +372,7 @@ try_again:
			exit(-1);
		}

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

@@ -385,7 +383,7 @@ try_again:
			}
		}

		if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
		if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
			perror("Unable to read perf file descriptor");
			exit(-1);
		}
@@ -395,42 +393,43 @@ try_again:
			exit(-1);
		}

		assert(fd[nr_cpu][counter][thread_index] >= 0);
		fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK);
		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[nr_cpu][counter][thread_index];
			group_fd = FD(evsel, nr_cpu, thread_index);

		if (counter || thread_index) {
			ret = ioctl(fd[nr_cpu][counter][thread_index],
		if (evsel->idx || thread_index) {
			struct perf_evsel *first;
			first = list_entry(evsel_list.next, struct perf_evsel, node);
			ret = ioctl(FD(evsel, nr_cpu, thread_index),
				    PERF_EVENT_IOC_SET_OUTPUT,
					fd[nr_cpu][0][0]);
				    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].counter = counter;
			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[nr_cpu][counter][thread_index], 0);
				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);
			}

			event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
			event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
			event_array[nr_poll].events = POLLIN;
			nr_poll++;
		}

		if (filter != NULL) {
			ret = ioctl(fd[nr_cpu][counter][thread_index],
			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,
@@ -446,11 +445,12 @@ try_again:

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

	group_fd = -1;
	for (counter = 0; counter < nr_counters; counter++)
		create_counter(counter, cpu);

	list_for_each_entry(pos, &evsel_list, node)
		create_counter(pos, cpu);

	nr_cpu++;
}
@@ -537,7 +537,7 @@ static void mmap_read_all(void)

static int __cmd_record(int argc, const char **argv)
{
	int i, counter;
	int i;
	struct stat st;
	int flags;
	int err;
@@ -604,7 +604,7 @@ static int __cmd_record(int argc, const char **argv)
			goto out_delete_session;
	}

	if (have_tracepoints(attrs, nr_counters))
	if (have_tracepoints(&evsel_list))
		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);

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

		if (!system_wide && target_tid == -1 && target_pid == -1)
			all_tids[0] = child_pid;
			threads->map[0] = child_pid;

		close(child_ready_pipe[1]);
		close(go_pipe[0]);
@@ -666,17 +666,11 @@ static int __cmd_record(int argc, const char **argv)
		close(child_ready_pipe[0]);
	}

	nr_cpus = read_cpu_map(cpu_list);
	if (nr_cpus < 1) {
		perror("failed to collect number of CPUs");
		return -1;
	}

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

	perf_session__set_sample_type(session, sample_type);
@@ -711,7 +705,7 @@ static int __cmd_record(int argc, const char **argv)
			return err;
		}

		if (have_tracepoints(attrs, nr_counters)) {
		if (have_tracepoints(&evsel_list)) {
			/*
			 * FIXME err <= 0 here actually means that
			 * there were no tracepoints so its not really
@@ -720,8 +714,7 @@ static int __cmd_record(int argc, const char **argv)
			 * return this more properly and also
			 * propagate errors that now are calling die()
			 */
			err = event__synthesize_tracing_data(output, attrs,
							     nr_counters,
			err = event__synthesize_tracing_data(output, &evsel_list,
							     process_synthesized_event,
							     session);
			if (err <= 0) {
@@ -795,13 +788,13 @@ static int __cmd_record(int argc, const char **argv)

		if (done) {
			for (i = 0; i < nr_cpu; i++) {
				for (counter = 0;
					counter < nr_counters;
					counter++) {
				struct perf_evsel *pos;

				list_for_each_entry(pos, &evsel_list, node) {
					for (thread = 0;
						thread < thread_num;
						thread < threads->nr;
						thread++)
						ioctl(fd[i][counter][thread],
						ioctl(FD(pos, i, thread),
							PERF_EVENT_IOC_DISABLE);
				}
			}
@@ -887,7 +880,8 @@ const struct option record_options[] = {

int cmd_record(int argc, const char **argv, const char *prefix __used)
{
	int i, j, err = -ENOMEM;
	int err = -ENOMEM;
	struct perf_evsel *pos;

	argc = parse_options(argc, argv, record_options, record_usage,
			    PARSE_OPT_STOP_AT_NON_OPTION);
@@ -910,38 +904,32 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
	if (no_buildid_cache || no_buildid)
		disable_buildid_cache();

	if (!nr_counters) {
		nr_counters	= 1;
		attrs[0].type	= PERF_TYPE_HARDWARE;
		attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
	if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
		pr_err("Not enough memory for event selector list\n");
		goto out_symbol_exit;
	}

	if (target_pid != -1) {
	if (target_pid != -1)
		target_tid = target_pid;
		thread_num = find_all_tid(target_pid, &all_tids);
		if (thread_num <= 0) {
			fprintf(stderr, "Can't find all threads of pid %d\n",
					target_pid);

	threads = thread_map__new(target_pid, target_tid);
	if (threads == NULL) {
		pr_err("Problems finding threads of monitor\n");
		usage_with_options(record_usage, record_options);
	}
	} else {
		all_tids=malloc(sizeof(pid_t));
		if (!all_tids)
			goto out_symbol_exit;

		all_tids[0] = target_tid;
		thread_num = 1;
	cpus = cpu_map__new(cpu_list);
	if (cpus == NULL) {
		perror("failed to parse CPUs map");
		return -1;
	}

	for (i = 0; i < MAX_NR_CPUS; i++) {
		for (j = 0; j < MAX_COUNTERS; j++) {
			fd[i][j] = malloc(sizeof(int)*thread_num);
			if (!fd[i][j])
	list_for_each_entry(pos, &evsel_list, node) {
		if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
			goto out_free_fd;
	}
	}
	event_array = malloc(
		sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
	event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
			      MAX_COUNTERS * threads->nr));
	if (!event_array)
		goto out_free_fd;

@@ -968,12 +956,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
out_free_event_array:
	free(event_array);
out_free_fd:
	for (i = 0; i < MAX_NR_CPUS; i++) {
		for (j = 0; j < MAX_COUNTERS; j++)
			free(fd[i][j]);
	}
	free(all_tids);
	all_tids = NULL;
	thread_map__delete(threads);
	threads = NULL;
out_symbol_exit:
	symbol__exit();
	return err;
+149 −219

File changed.

Preview size limit exceeded, changes collapsed.

+83 −0
Original line number Diff line number Diff line
@@ -234,6 +234,85 @@ out:
	return err;
}

#include "util/evsel.h"
#include <sys/types.h>

static int trace_event__id(const char *event_name)
{
	char *filename;
	int err = -1, fd;

	if (asprintf(&filename,
		     "/sys/kernel/debug/tracing/events/syscalls/%s/id",
		     event_name) < 0)
		return -1;

	fd = open(filename, O_RDONLY);
	if (fd >= 0) {
		char id[16];
		if (read(fd, id, sizeof(id)) > 0)
			err = atoi(id);
		close(fd);
	}

	free(filename);
	return err;
}

static int test__open_syscall_event(void)
{
	int err = -1, fd;
	struct thread_map *threads;
	struct perf_evsel *evsel;
	unsigned int nr_open_calls = 111, i;
	int id = trace_event__id("sys_enter_open");

	if (id < 0) {
		pr_debug("trace_event__id(\"sys_enter_open\") ");
		return -1;
	}

	threads = thread_map__new(-1, getpid());
	if (threads == NULL) {
		pr_debug("thread_map__new ");
		return -1;
	}

	evsel = perf_evsel__new(PERF_TYPE_TRACEPOINT, id, 0);
	if (evsel == NULL) {
		pr_debug("perf_evsel__new ");
		goto out_thread_map_delete;
	}

	if (perf_evsel__open_per_thread(evsel, threads) < 0) {
		pr_debug("perf_evsel__open_per_thread ");
		goto out_evsel_delete;
	}

	for (i = 0; i < nr_open_calls; ++i) {
		fd = open("/etc/passwd", O_RDONLY);
		close(fd);
	}

	if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
		pr_debug("perf_evsel__open_read_on_cpu ");
		goto out_close_fd;
	}

	if (evsel->counts->cpu[0].val != nr_open_calls)
		pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld ",
			 nr_open_calls, evsel->counts->cpu[0].val);
	
	err = 0;
out_close_fd:
	perf_evsel__close_fd(evsel, 1, threads->nr);
out_evsel_delete:
	perf_evsel__delete(evsel);
out_thread_map_delete:
	thread_map__delete(threads);
	return err;
}

static struct test {
	const char *desc;
	int (*func)(void);
@@ -242,6 +321,10 @@ static struct test {
		.desc = "vmlinux symtab matches kallsyms",
		.func = test__vmlinux_matches_kallsyms,
	},
	{
		.desc = "detect open syscall event",
		.func = test__open_syscall_event,
	},
	{
		.func = NULL,
	},
+121 −100
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "perf.h"

#include "util/color.h"
#include "util/evsel.h"
#include "util/session.h"
#include "util/symbol.h"
#include "util/thread.h"
@@ -29,6 +30,7 @@
#include "util/parse-options.h"
#include "util/parse-events.h"
#include "util/cpumap.h"
#include "util/xyarray.h"

#include "util/debug.h"

@@ -55,7 +57,7 @@
#include <linux/unistd.h>
#include <linux/types.h>

static int			*fd[MAX_NR_CPUS][MAX_COUNTERS];
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))

static bool			system_wide			=  false;

@@ -66,10 +68,9 @@ static int print_entries;

static int			target_pid			=     -1;
static int			target_tid			=     -1;
static pid_t			*all_tids			=      NULL;
static int			thread_num			=      0;
static struct thread_map	*threads;
static bool			inherit				=  false;
static int			nr_cpus				=      0;
static struct cpu_map		*cpus;
static int			realtime_prio			=      0;
static bool			group				=  false;
static unsigned int		page_size;
@@ -100,6 +101,7 @@ struct sym_entry *sym_filter_entry = NULL;
struct sym_entry		*sym_filter_entry_sched		=   NULL;
static int			sym_pcnt_filter			=      5;
static int			sym_counter			=      0;
static struct perf_evsel	*sym_evsel			=   NULL;
static int			display_weighted		=     -1;
static const char		*cpu_list;

@@ -353,7 +355,7 @@ static void show_details(struct sym_entry *syme)
		return;

	symbol = sym_entry__symbol(syme);
	printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
	printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name);
	printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);

	pthread_mutex_lock(&syme->src->lock);
@@ -460,7 +462,8 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
static void print_sym_table(void)
{
	int printed = 0, j;
	int counter, snap = !display_weighted ? sym_counter : 0;
	struct perf_evsel *counter;
	int snap = !display_weighted ? sym_counter : 0;
	float samples_per_sec = samples/delay_secs;
	float ksamples_per_sec = kernel_samples/delay_secs;
	float us_samples_per_sec = (us_samples)/delay_secs;
@@ -532,7 +535,9 @@ static void print_sym_table(void)
	}

	if (nr_counters == 1 || !display_weighted) {
		printf("%Ld", (u64)attrs[0].sample_period);
		struct perf_evsel *first;
		first = list_entry(evsel_list.next, struct perf_evsel, node);
		printf("%Ld", first->attr.sample_period);
		if (freq)
			printf("Hz ");
		else
@@ -540,9 +545,9 @@ static void print_sym_table(void)
	}

	if (!display_weighted)
		printf("%s", event_name(sym_counter));
	else for (counter = 0; counter < nr_counters; counter++) {
		if (counter)
		printf("%s", event_name(sym_evsel));
	else list_for_each_entry(counter, &evsel_list, node) {
		if (counter->idx)
			printf("/");

		printf("%s", event_name(counter));
@@ -558,12 +563,12 @@ static void print_sym_table(void)
		printf(" (all");

	if (cpu_list)
		printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list);
		printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
	else {
		if (target_tid != -1)
			printf(")\n");
		else
			printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : "");
			printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
	}

	printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
@@ -739,7 +744,7 @@ static void print_mapped_keys(void)
	fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", print_entries);

	if (nr_counters > 1)
		fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(sym_counter));
		fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(sym_evsel));

	fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);

@@ -826,19 +831,23 @@ static void handle_keypress(struct perf_session *session, int c)
			break;
		case 'E':
			if (nr_counters > 1) {
				int i;

				fprintf(stderr, "\nAvailable events:");
				for (i = 0; i < nr_counters; i++)
					fprintf(stderr, "\n\t%d %s", i, event_name(i));

				list_for_each_entry(sym_evsel, &evsel_list, node)
					fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));

				prompt_integer(&sym_counter, "Enter details event counter");

				if (sym_counter >= nr_counters) {
					fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
					sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
					sym_counter = 0;
					fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
					sleep(1);
					break;
				}
				list_for_each_entry(sym_evsel, &evsel_list, node)
					if (sym_evsel->idx == sym_counter)
						break;
			} else sym_counter = 0;
			break;
		case 'f':
@@ -978,7 +987,8 @@ static int symbol_filter(struct map *map, struct symbol *sym)

static void event__process_sample(const event_t *self,
				  struct sample_data *sample,
				  struct perf_session *session, int counter)
				  struct perf_session *session,
				  struct perf_evsel *evsel)
{
	u64 ip = self->ip.ip;
	struct sym_entry *syme;
@@ -1071,9 +1081,9 @@ static void event__process_sample(const event_t *self,

	syme = symbol__priv(al.sym);
	if (!syme->skip) {
		syme->count[counter]++;
		syme->count[evsel->idx]++;
		syme->origin = origin;
		record_precise_ip(syme, counter, ip);
		record_precise_ip(syme, evsel->idx, ip);
		pthread_mutex_lock(&active_symbols_lock);
		if (list_empty(&syme->node) || !syme->node.next)
			__list_insert_active_sym(syme);
@@ -1082,12 +1092,24 @@ static void event__process_sample(const event_t *self,
}

struct mmap_data {
	int			counter;
	void			*base;
	int			mask;
	unsigned int		prev;
};

static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
					     int ncpus, int nthreads)
{
	evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
	return evsel->priv != NULL ? 0 : -ENOMEM;
}

static void perf_evsel__free_mmap(struct perf_evsel *evsel)
{
	xyarray__delete(evsel->priv);
	evsel->priv = NULL;
}

static unsigned int mmap_read_head(struct mmap_data *md)
{
	struct perf_event_mmap_page *pc = md->base;
@@ -1100,8 +1122,11 @@ static unsigned int mmap_read_head(struct mmap_data *md)
}

static void perf_session__mmap_read_counter(struct perf_session *self,
					    struct mmap_data *md)
					    struct perf_evsel *evsel,
					    int cpu, int thread_idx)
{
	struct xyarray *mmap_array = evsel->priv;
	struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
	unsigned int head = mmap_read_head(md);
	unsigned int old = md->prev;
	unsigned char *data = md->base + page_size;
@@ -1155,7 +1180,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self,

		event__parse_sample(event, self, &sample);
		if (event->header.type == PERF_RECORD_SAMPLE)
			event__process_sample(event, &sample, self, md->counter);
			event__process_sample(event, &sample, self, evsel);
		else
			event__process(event, &sample, self);
		old += size;
@@ -1165,19 +1190,20 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
}

static struct pollfd *event_array;
static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];

static void perf_session__mmap_read(struct perf_session *self)
{
	int i, counter, thread_index;
	struct perf_evsel *counter;
	int i, thread_index;

	for (i = 0; i < nr_cpus; i++) {
		for (counter = 0; counter < nr_counters; counter++)
	for (i = 0; i < cpus->nr; i++) {
		list_for_each_entry(counter, &evsel_list, node) {
			for (thread_index = 0;
				thread_index < thread_num;
				thread_index < threads->nr;
				thread_index++) {
				perf_session__mmap_read_counter(self,
					&mmap_array[i][counter][thread_index]);
					counter, i, thread_index);
			}
		}
	}
}
@@ -1185,16 +1211,18 @@ static void perf_session__mmap_read(struct perf_session *self)
int nr_poll;
int group_fd;

static void start_counter(int i, int counter)
static void start_counter(int i, struct perf_evsel *evsel)
{
	struct xyarray *mmap_array = evsel->priv;
	struct mmap_data *mm;
	struct perf_event_attr *attr;
	int cpu = -1;
	int thread_index;

	if (target_tid == -1)
		cpu = cpumap[i];
		cpu = cpus->map[i];

	attr = attrs + counter;
	attr = &evsel->attr;

	attr->sample_type	= PERF_SAMPLE_IP | PERF_SAMPLE_TID;

@@ -1207,12 +1235,12 @@ static void start_counter(int i, int counter)
	attr->inherit		= (cpu < 0) && inherit;
	attr->mmap		= 1;

	for (thread_index = 0; thread_index < thread_num; thread_index++) {
	for (thread_index = 0; thread_index < threads->nr; thread_index++) {
try_again:
		fd[i][counter][thread_index] = sys_perf_event_open(attr,
				all_tids[thread_index], cpu, group_fd, 0);
		FD(evsel, i, thread_index) = sys_perf_event_open(attr,
				threads->map[thread_index], cpu, group_fd, 0);

		if (fd[i][counter][thread_index] < 0) {
		if (FD(evsel, i, thread_index) < 0) {
			int err = errno;

			if (err == EPERM || err == EACCES)
@@ -1236,29 +1264,29 @@ try_again:
			}
			printf("\n");
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
					fd[i][counter][thread_index], strerror(err));
					FD(evsel, i, thread_index), strerror(err));
			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
			exit(-1);
		}
		assert(fd[i][counter][thread_index] >= 0);
		fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
		assert(FD(evsel, i, thread_index) >= 0);
		fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);

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

		event_array[nr_poll].fd = fd[i][counter][thread_index];
		event_array[nr_poll].fd = FD(evsel, i, thread_index);
		event_array[nr_poll].events = POLLIN;
		nr_poll++;

		mmap_array[i][counter][thread_index].counter = counter;
		mmap_array[i][counter][thread_index].prev = 0;
		mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
		mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
				PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
		if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
		mm = xyarray__entry(mmap_array, i, thread_index);
		mm->prev = 0;
		mm->mask = mmap_pages*page_size - 1;
		mm->base = mmap(NULL, (mmap_pages+1)*page_size,
				PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
		if (mm->base == MAP_FAILED)
			die("failed to mmap with %d (%s)\n", errno, strerror(errno));
	}
}
@@ -1266,8 +1294,8 @@ try_again:
static int __cmd_top(void)
{
	pthread_t thread;
	int i, counter;
	int ret;
	struct perf_evsel *counter;
	int i, ret;
	/*
	 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
	 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1281,9 +1309,9 @@ static int __cmd_top(void)
	else
		event__synthesize_threads(event__process, session);

	for (i = 0; i < nr_cpus; i++) {
	for (i = 0; i < cpus->nr; i++) {
		group_fd = -1;
		for (counter = 0; counter < nr_counters; counter++)
		list_for_each_entry(counter, &evsel_list, node)
			start_counter(i, counter);
	}

@@ -1372,8 +1400,8 @@ static const struct option options[] = {

int cmd_top(int argc, const char **argv, const char *prefix __used)
{
	int counter;
	int i,j;
	struct perf_evsel *pos;
	int status = -ENOMEM;

	page_size = sysconf(_SC_PAGE_SIZE);

@@ -1381,34 +1409,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
	if (argc)
		usage_with_options(top_usage, options);

	if (target_pid != -1) {
	if (target_pid != -1)
		target_tid = target_pid;
		thread_num = find_all_tid(target_pid, &all_tids);
		if (thread_num <= 0) {
			fprintf(stderr, "Can't find all threads of pid %d\n",
				target_pid);
			usage_with_options(top_usage, options);
		}
	} else {
		all_tids=malloc(sizeof(pid_t));
		if (!all_tids)
			return -ENOMEM;

		all_tids[0] = target_tid;
		thread_num = 1;
	threads = thread_map__new(target_pid, target_tid);
	if (threads == NULL) {
		pr_err("Problems finding threads of monitor\n");
		usage_with_options(top_usage, options);
	}

	for (i = 0; i < MAX_NR_CPUS; i++) {
		for (j = 0; j < MAX_COUNTERS; j++) {
			fd[i][j] = malloc(sizeof(int)*thread_num);
			mmap_array[i][j] = zalloc(
				sizeof(struct mmap_data)*thread_num);
			if (!fd[i][j] || !mmap_array[i][j])
				return -ENOMEM;
		}
	}
	event_array = malloc(
		sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
	event_array = malloc((sizeof(struct pollfd) *
			      MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
	if (!event_array)
		return -ENOMEM;

@@ -1419,15 +1430,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
		cpu_list = NULL;
	}

	if (!nr_counters)
		nr_counters = 1;

	symbol_conf.priv_size = (sizeof(struct sym_entry) +
				 (nr_counters + 1) * sizeof(unsigned long));

	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
	if (symbol__init() < 0)
		return -1;
	if (!nr_counters && perf_evsel_list__create_default() < 0) {
		pr_err("Not enough memory for event selector list\n");
		return -ENOMEM;
	}

	if (delay_secs < 1)
		delay_secs = 1;
@@ -1444,23 +1450,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
		exit(EXIT_FAILURE);
	}

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

	if (cpus == NULL)
		usage_with_options(top_usage, options);

	list_for_each_entry(pos, &evsel_list, node) {
		if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
		    perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
			goto out_free_fd;
		/*
		 * Fill in the ones not specifically initialized via -c:
		 */
	for (counter = 0; counter < nr_counters; counter++) {
		if (attrs[counter].sample_period)
		if (pos->attr.sample_period)
			continue;

		attrs[counter].sample_period = default_interval;
		pos->attr.sample_period = default_interval;
	}

	if (target_tid != -1)
		nr_cpus = 1;
	else
		nr_cpus = read_cpu_map(cpu_list);
	symbol_conf.priv_size = (sizeof(struct sym_entry) +
				 (nr_counters + 1) * sizeof(unsigned long));

	if (nr_cpus < 1)
		usage_with_options(top_usage, options);
	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
	if (symbol__init() < 0)
		return -1;

	get_term_dimensions(&winsize);
	if (print_entries == 0) {
@@ -1468,5 +1484,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
		signal(SIGWINCH, sig_winch_handler);
	}

	return __cmd_top();
	status = __cmd_top();
out_free_fd:
	list_for_each_entry(pos, &evsel_list, node)
		perf_evsel__free_mmap(pos);

	return status;
}
Loading