diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
| -rw-r--r-- | tools/perf/builtin-record.c | 450 | 
1 files changed, 169 insertions, 281 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b2f729fdb317..6febcc168a8c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -18,11 +18,13 @@  #include "util/header.h"  #include "util/event.h" +#include "util/evlist.h"  #include "util/evsel.h"  #include "util/debug.h"  #include "util/session.h"  #include "util/symbol.h"  #include "util/cpumap.h" +#include "util/thread_map.h"  #include <unistd.h>  #include <sched.h> @@ -37,16 +39,14 @@ enum write_mode_t {  static u64			user_interval			= ULLONG_MAX;  static u64			default_interval		=      0; -static u64			sample_type; -static struct cpu_map		*cpus;  static unsigned int		page_size;  static unsigned int		mmap_pages			=    128;  static unsigned int		user_freq 			= UINT_MAX;  static int			freq				=   1000;  static int			output;  static int			pipe_output			=      0; -static const char		*output_name			= "perf.data"; +static const char		*output_name			= NULL;  static int			group				=      0;  static int			realtime_prio			=      0;  static bool			nodelay				=  false; @@ -55,7 +55,6 @@ 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 struct thread_map	*threads;  static pid_t			child_pid			=     -1;  static bool			no_inherit			=  false;  static enum write_mode_t	write_mode			= WRITE_FORCE; @@ -66,51 +65,17 @@ static bool			sample_address			=  false;  static bool			sample_time			=  false;  static bool			no_buildid			=  false;  static bool			no_buildid_cache		=  false; +static struct perf_evlist	*evsel_list;  static long			samples				=      0;  static u64			bytes_written			=      0; -static struct pollfd		*event_array; - -static int			nr_poll				=      0; -static int			nr_cpu				=      0; -  static int			file_new			=      1;  static off_t			post_processing_offset;  static struct perf_session	*session;  static const char		*cpu_list; -struct mmap_data { -	void			*base; -	unsigned int		mask; -	unsigned int		prev; -}; - -static struct mmap_data		mmap_array[MAX_NR_CPUS]; - -static unsigned long mmap_read_head(struct mmap_data *md) -{ -	struct perf_event_mmap_page *pc = md->base; -	long head; - -	head = pc->data_head; -	rmb(); - -	return head; -} - -static void mmap_write_tail(struct mmap_data *md, unsigned long tail) -{ -	struct perf_event_mmap_page *pc = md->base; - -	/* -	 * ensure all reads are done before we write the tail out. -	 */ -	/* mb(); */ -	pc->data_tail = tail; -} -  static void advance_output(size_t size)  {  	bytes_written += size; @@ -131,42 +96,26 @@ static void write_output(void *buf, size_t size)  	}  } -static int process_synthesized_event(event_t *event, -				     struct sample_data *sample __used, +static int process_synthesized_event(union perf_event *event, +				     struct perf_sample *sample __used,  				     struct perf_session *self __used)  {  	write_output(event, event->header.size);  	return 0;  } -static void mmap_read(struct mmap_data *md) +static void mmap_read(struct perf_mmap *md)  { -	unsigned int head = mmap_read_head(md); +	unsigned int head = perf_mmap__read_head(md);  	unsigned int old = md->prev;  	unsigned char *data = md->base + page_size;  	unsigned long size;  	void *buf; -	int diff; -	/* -	 * If we're further behind than half the buffer, there's a chance -	 * the writer will bite our tail and mess up the samples under us. -	 * -	 * If we somehow ended up ahead of the head, we got messed up. -	 * -	 * In either case, truncate and restart at head. -	 */ -	diff = head - old; -	if (diff < 0) { -		fprintf(stderr, "WARNING: failed to keep up with mmap data\n"); -		/* -		 * head points to a known good entry, start there. -		 */ -		old = head; -	} +	if (old == head) +		return; -	if (old != head) -		samples++; +	samples++;  	size = head - old; @@ -185,7 +134,7 @@ static void mmap_read(struct mmap_data *md)  	write_output(buf, size);  	md->prev = old; -	mmap_write_tail(md, old); +	perf_mmap__write_tail(md, old);  }  static volatile int done = 0; @@ -209,53 +158,10 @@ static void sig_atexit(void)  	kill(getpid(), signr);  } -static int group_fd; - -static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) -{ -	struct perf_header_attr *h_attr; - -	if (nr < session->header.attrs) { -		h_attr = session->header.attr[nr]; -	} else { -		h_attr = perf_header_attr__new(a); -		if (h_attr != NULL) -			if (perf_header__add_attr(&session->header, h_attr) < 0) { -				perf_header_attr__delete(h_attr); -				h_attr = NULL; -			} -	} - -	return h_attr; -} - -static void create_counter(struct perf_evsel *evsel, int cpu) +static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)  { -	char *filter = evsel->filter;  	struct perf_event_attr *attr = &evsel->attr; -	struct perf_header_attr *h_attr;  	int track = !evsel->idx; /* only the first counter needs these */ -	int thread_index; -	int ret; -	struct { -		u64 count; -		u64 time_enabled; -		u64 time_running; -		u64 id; -	} read_data; -	/* - 	 * 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;  	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |  				  PERF_FORMAT_TOTAL_TIME_RUNNING | @@ -263,7 +169,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu)  	attr->sample_type	|= PERF_SAMPLE_IP | PERF_SAMPLE_TID; -	if (nr_counters > 1) +	if (evlist->nr_entries > 1)  		attr->sample_type |= PERF_SAMPLE_ID;  	/* @@ -315,19 +221,58 @@ static void create_counter(struct perf_evsel *evsel, int cpu)  	attr->mmap		= track;  	attr->comm		= track; -	attr->inherit		= !no_inherit; +  	if (target_pid == -1 && target_tid == -1 && !system_wide) {  		attr->disabled = 1;  		attr->enable_on_exec = 1;  	} -retry_sample_id: -	attr->sample_id_all = sample_id_all_avail ? 1 : 0; +} -	for (thread_index = 0; thread_index < threads->nr; thread_index++) { -try_again: -		FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); +static bool perf_evlist__equal(struct perf_evlist *evlist, +			       struct perf_evlist *other) +{ +	struct perf_evsel *pos, *pair; + +	if (evlist->nr_entries != other->nr_entries) +		return false; + +	pair = list_entry(other->entries.next, struct perf_evsel, node); -		if (FD(evsel, nr_cpu, thread_index) < 0) { +	list_for_each_entry(pos, &evlist->entries, node) { +		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) +			return false; +		pair = list_entry(pair->node.next, struct perf_evsel, node); +	} + +	return true; +} + +static void open_counters(struct perf_evlist *evlist) +{ +	struct perf_evsel *pos; + +	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: +		attr->sample_id_all = sample_id_all_avail ? 1 : 0; +try_again: +		if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, +				     !no_inherit) < 0) {  			int err = errno;  			if (err == EPERM || err == EACCES) @@ -364,7 +309,7 @@ try_again:  			}  			printf("\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 (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) @@ -375,90 +320,28 @@ try_again:  #endif  			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 (perf_evlist__set_filters(evlist)) { +		error("failed to set filter with %d (%s)\n", errno, +			strerror(errno)); +		exit(-1); +	} -		if (!file_new) { -			if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { -				fprintf(stderr, "incompatible append\n"); -				exit(-1); -			} -		} +	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) +		die("failed to mmap with %d (%s)\n", errno, strerror(errno)); -		if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { -			perror("Unable to read perf file descriptor"); +	if (file_new) +		session->evlist = evlist; +	else { +		if (!perf_evlist__equal(session->evlist, evlist)) { +			fprintf(stderr, "incompatible append\n");  			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(evsel_list.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); -			} - -			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(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(int cpu) -{ -	struct perf_evsel *pos; - -	group_fd = -1; - -	list_for_each_entry(pos, &evsel_list, node) -		create_counter(pos, cpu); - -	nr_cpu++; +	perf_session__update_sample_type(session);  }  static int process_buildids(void) @@ -481,14 +364,14 @@ static void atexit_header(void)  		if (!no_buildid)  			process_buildids(); -		perf_header__write(&session->header, output, true); +		perf_session__write_header(session, evsel_list, output, true);  		perf_session__delete(session); -		perf_evsel_list__delete(); +		perf_evlist__delete(evsel_list);  		symbol__exit();  	}  } -static void event__synthesize_guest_os(struct machine *machine, void *data) +static void perf_event__synthesize_guest_os(struct machine *machine, void *data)  {  	int err;  	struct perf_session *psession = data; @@ -504,8 +387,8 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)  	 *method is used to avoid symbol missing when the first addr is  	 *in module instead of in guest kernel.  	 */ -	err = event__synthesize_modules(process_synthesized_event, -					psession, machine); +	err = perf_event__synthesize_modules(process_synthesized_event, +					     psession, machine);  	if (err < 0)  		pr_err("Couldn't record guest kernel [%d]'s reference"  		       " relocation symbol.\n", machine->pid); @@ -514,11 +397,12 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)  	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms  	 * have no _text sometimes.  	 */ -	err = event__synthesize_kernel_mmap(process_synthesized_event, -					    psession, machine, "_text"); +	err = perf_event__synthesize_kernel_mmap(process_synthesized_event, +						 psession, machine, "_text");  	if (err < 0) -		err = event__synthesize_kernel_mmap(process_synthesized_event, -						    psession, machine, "_stext"); +		err = perf_event__synthesize_kernel_mmap(process_synthesized_event, +							 psession, machine, +							 "_stext");  	if (err < 0)  		pr_err("Couldn't record guest kernel [%d]'s reference"  		       " relocation symbol.\n", machine->pid); @@ -533,9 +417,9 @@ static void mmap_read_all(void)  {  	int i; -	for (i = 0; i < nr_cpu; i++) { -		if (mmap_array[i].base) -			mmap_read(&mmap_array[i]); +	for (i = 0; i < evsel_list->cpus->nr; i++) { +		if (evsel_list->mmap[i].base) +			mmap_read(&evsel_list->mmap[i]);  	}  	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) @@ -566,18 +450,26 @@ static int __cmd_record(int argc, const char **argv)  		exit(-1);  	} -	if (!strcmp(output_name, "-")) -		pipe_output = 1; -	else if (!stat(output_name, &st) && st.st_size) { -		if (write_mode == WRITE_FORCE) { -			char oldname[PATH_MAX]; -			snprintf(oldname, sizeof(oldname), "%s.old", -				 output_name); -			unlink(oldname); -			rename(output_name, oldname); +	if (!output_name) { +		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) +			pipe_output = 1; +		else +			output_name = "perf.data"; +	} +	if (output_name) { +		if (!strcmp(output_name, "-")) +			pipe_output = 1; +		else if (!stat(output_name, &st) && st.st_size) { +			if (write_mode == WRITE_FORCE) { +				char oldname[PATH_MAX]; +				snprintf(oldname, sizeof(oldname), "%s.old", +					 output_name); +				unlink(oldname); +				rename(output_name, oldname); +			} +		} else if (write_mode == WRITE_APPEND) { +			write_mode = WRITE_FORCE;  		} -	} else if (write_mode == WRITE_APPEND) { -		write_mode = WRITE_FORCE;  	}  	flags = O_CREAT|O_RDWR; @@ -606,19 +498,14 @@ static int __cmd_record(int argc, const char **argv)  		perf_header__set_feat(&session->header, HEADER_BUILD_ID);  	if (!file_new) { -		err = perf_header__read(session, output); +		err = perf_session__read_header(session, output);  		if (err < 0)  			goto out_delete_session;  	} -	if (have_tracepoints(&evsel_list)) +	if (have_tracepoints(&evsel_list->entries))  		perf_header__set_feat(&session->header, HEADER_TRACE_INFO); -	/* - 	 * perf_session__delete(session) will be called at atexit_header() -	 */ -	atexit(atexit_header); -  	if (forks) {  		child_pid = fork();  		if (child_pid < 0) { @@ -659,7 +546,7 @@ static int __cmd_record(int argc, const char **argv)  		}  		if (!system_wide && target_tid == -1 && target_pid == -1) -			threads->map[0] = child_pid; +			evsel_list->threads->map[0] = child_pid;  		close(child_ready_pipe[1]);  		close(go_pipe[0]); @@ -673,46 +560,42 @@ static int __cmd_record(int argc, const char **argv)  		close(child_ready_pipe[0]);  	} -	if (!system_wide && no_inherit && !cpu_list) { -		open_counters(-1); -	} else { -		for (i = 0; i < cpus->nr; i++) -			open_counters(cpus->map[i]); -	} +	open_counters(evsel_list); -	perf_session__set_sample_type(session, sample_type); +	/* +	 * perf_session__delete(session) will be called at atexit_header() +	 */ +	atexit(atexit_header);  	if (pipe_output) {  		err = perf_header__write_pipe(output);  		if (err < 0)  			return err;  	} else if (file_new) { -		err = perf_header__write(&session->header, output, false); +		err = perf_session__write_header(session, evsel_list, +						 output, false);  		if (err < 0)  			return err;  	}  	post_processing_offset = lseek(output, 0, SEEK_CUR); -	perf_session__set_sample_id_all(session, sample_id_all_avail); -  	if (pipe_output) { -		err = event__synthesize_attrs(&session->header, -					      process_synthesized_event, -					      session); +		err = perf_session__synthesize_attrs(session, +						     process_synthesized_event);  		if (err < 0) {  			pr_err("Couldn't synthesize attrs.\n");  			return err;  		} -		err = event__synthesize_event_types(process_synthesized_event, -						    session); +		err = perf_event__synthesize_event_types(process_synthesized_event, +							 session);  		if (err < 0) {  			pr_err("Couldn't synthesize event_types.\n");  			return err;  		} -		if (have_tracepoints(&evsel_list)) { +		if (have_tracepoints(&evsel_list->entries)) {  			/*  			 * FIXME err <= 0 here actually means that  			 * there were no tracepoints so its not really @@ -721,9 +604,9 @@ 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, &evsel_list, -							     process_synthesized_event, -							     session); +			err = perf_event__synthesize_tracing_data(output, evsel_list, +								  process_synthesized_event, +								  session);  			if (err <= 0) {  				pr_err("Couldn't record tracing data.\n");  				return err; @@ -738,31 +621,34 @@ static int __cmd_record(int argc, const char **argv)  		return -1;  	} -	err = event__synthesize_kernel_mmap(process_synthesized_event, -					    session, machine, "_text"); +	err = perf_event__synthesize_kernel_mmap(process_synthesized_event, +						 session, machine, "_text");  	if (err < 0) -		err = event__synthesize_kernel_mmap(process_synthesized_event, -						    session, machine, "_stext"); +		err = perf_event__synthesize_kernel_mmap(process_synthesized_event, +							 session, machine, "_stext");  	if (err < 0)  		pr_err("Couldn't record kernel reference relocation symbol\n"  		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"  		       "Check /proc/kallsyms permission or run as root.\n"); -	err = event__synthesize_modules(process_synthesized_event, -					session, machine); +	err = perf_event__synthesize_modules(process_synthesized_event, +					     session, machine);  	if (err < 0)  		pr_err("Couldn't record kernel module information.\n"  		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"  		       "Check /proc/modules permission or run as root.\n");  	if (perf_guest) -		perf_session__process_machines(session, event__synthesize_guest_os); +		perf_session__process_machines(session, +					       perf_event__synthesize_guest_os);  	if (!system_wide) -		event__synthesize_thread(target_tid, process_synthesized_event, -					 session); +		perf_event__synthesize_thread_map(evsel_list->threads, +						  process_synthesized_event, +						  session);  	else -		event__synthesize_threads(process_synthesized_event, session); +		perf_event__synthesize_threads(process_synthesized_event, +					       session);  	if (realtime_prio) {  		struct sched_param param; @@ -789,17 +675,17 @@ static int __cmd_record(int argc, const char **argv)  		if (hits == samples) {  			if (done)  				break; -			err = poll(event_array, nr_poll, -1); +			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);  			waking++;  		}  		if (done) { -			for (i = 0; i < nr_cpu; i++) { +			for (i = 0; i < evsel_list->cpus->nr; i++) {  				struct perf_evsel *pos; -				list_for_each_entry(pos, &evsel_list, node) { +				list_for_each_entry(pos, &evsel_list->entries, node) {  					for (thread = 0; -						thread < threads->nr; +						thread < evsel_list->threads->nr;  						thread++)  						ioctl(FD(pos, i, thread),  							PERF_EVENT_IOC_DISABLE); @@ -838,10 +724,10 @@ static const char * const record_usage[] = {  static bool force, append_file;  const struct option record_options[] = { -	OPT_CALLBACK('e', "event", NULL, "event", +	OPT_CALLBACK('e', "event", &evsel_list, "event",  		     "event selector. use 'perf list' to list available events",  		     parse_events), -	OPT_CALLBACK(0, "filter", NULL, "filter", +	OPT_CALLBACK(0, "filter", &evsel_list, "filter",  		     "event filter", parse_filter),  	OPT_INTEGER('p', "pid", &target_pid,  		    "record events on existing process id"), @@ -884,6 +770,9 @@ const struct option record_options[] = {  		    "do not update the buildid cache"),  	OPT_BOOLEAN('B', "no-buildid", &no_buildid,  		    "do not collect buildids in perf.data"), +	OPT_CALLBACK('G', "cgroup", &evsel_list, "name", +		     "monitor event in cgroup name only", +		     parse_cgroups),  	OPT_END()  }; @@ -892,6 +781,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  	int err = -ENOMEM;  	struct perf_evsel *pos; +	evsel_list = perf_evlist__new(NULL, NULL); +	if (evsel_list == NULL) +		return -ENOMEM; +  	argc = parse_options(argc, argv, record_options, record_usage,  			    PARSE_OPT_STOP_AT_NON_OPTION);  	if (!argc && target_pid == -1 && target_tid == -1 && @@ -908,12 +801,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  		write_mode = WRITE_FORCE;  	} +	if (nr_cgroups && !system_wide) { +		fprintf(stderr, "cgroup monitoring only available in" +			" system-wide mode\n"); +		usage_with_options(record_usage, record_options); +	} +  	symbol__init();  	if (no_buildid_cache || no_buildid)  		disable_buildid_cache(); -	if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { +	if (evsel_list->nr_entries == 0 && +	    perf_evlist__add_default(evsel_list) < 0) {  		pr_err("Not enough memory for event selector list\n");  		goto out_symbol_exit;  	} @@ -921,27 +821,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  	if (target_pid != -1)  		target_tid = target_pid; -	threads = thread_map__new(target_pid, target_tid); -	if (threads == NULL) { -		pr_err("Problems finding threads of monitor\n"); +	if (perf_evlist__create_maps(evsel_list, target_pid, +				     target_tid, cpu_list) < 0)  		usage_with_options(record_usage, record_options); -	} -	cpus = cpu_map__new(cpu_list); -	if (cpus == NULL) { -		perror("failed to parse CPUs map"); -		return -1; -	} - -	list_for_each_entry(pos, &evsel_list, node) { -		if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) +	list_for_each_entry(pos, &evsel_list->entries, node) { +		if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, +					 evsel_list->threads->nr) < 0)  			goto out_free_fd;  		if (perf_header__push_event(pos->attr.config, event_name(pos)))  			goto out_free_fd;  	} -	event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * -			      MAX_COUNTERS * threads->nr)); -	if (!event_array) + +	if (perf_evlist__alloc_pollfd(evsel_list) < 0)  		goto out_free_fd;  	if (user_interval != ULLONG_MAX) @@ -959,16 +851,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  	} else {  		fprintf(stderr, "frequency and count are zero, aborting\n");  		err = -EINVAL; -		goto out_free_event_array; +		goto out_free_fd;  	}  	err = __cmd_record(argc, argv); - -out_free_event_array: -	free(event_array);  out_free_fd: -	thread_map__delete(threads); -	threads = NULL; +	perf_evlist__delete_maps(evsel_list);  out_symbol_exit:  	symbol__exit();  	return err;  | 
