diff options
Diffstat (limited to 'tools/perf/util/session.c')
| -rw-r--r-- | tools/perf/util/session.c | 346 | 
1 files changed, 202 insertions, 144 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 85c1e6b76f0a..b5ca2558c7bb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -10,6 +10,7 @@  #include "evlist.h"  #include "evsel.h"  #include "session.h" +#include "tool.h"  #include "sort.h"  #include "util.h"  #include "cpumap.h" @@ -78,39 +79,13 @@ out_close:  	return -1;  } -static void perf_session__id_header_size(struct perf_session *session) -{ -       struct perf_sample *data; -       u64 sample_type = session->sample_type; -       u16 size = 0; - -	if (!session->sample_id_all) -		goto out; - -       if (sample_type & PERF_SAMPLE_TID) -               size += sizeof(data->tid) * 2; - -       if (sample_type & PERF_SAMPLE_TIME) -               size += sizeof(data->time); - -       if (sample_type & PERF_SAMPLE_ID) -               size += sizeof(data->id); - -       if (sample_type & PERF_SAMPLE_STREAM_ID) -               size += sizeof(data->stream_id); - -       if (sample_type & PERF_SAMPLE_CPU) -               size += sizeof(data->cpu) * 2; -out: -       session->id_hdr_size = size; -} -  void perf_session__update_sample_type(struct perf_session *self)  {  	self->sample_type = perf_evlist__sample_type(self->evlist);  	self->sample_size = __perf_evsel__sample_size(self->sample_type);  	self->sample_id_all = perf_evlist__sample_id_all(self->evlist); -	perf_session__id_header_size(self); +	self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); +	self->host_machine.id_hdr_size = self->id_hdr_size;  }  int perf_session__create_kernel_maps(struct perf_session *self) @@ -130,18 +105,26 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)  struct perf_session *perf_session__new(const char *filename, int mode,  				       bool force, bool repipe, -				       struct perf_event_ops *ops) +				       struct perf_tool *tool)  { -	size_t len = filename ? strlen(filename) + 1 : 0; -	struct perf_session *self = zalloc(sizeof(*self) + len); +	struct perf_session *self; +	struct stat st; +	size_t len; + +	if (!filename || !strlen(filename)) { +		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) +			filename = "-"; +		else +			filename = "perf.data"; +	} + +	len = strlen(filename); +	self = zalloc(sizeof(*self) + len);  	if (self == NULL)  		goto out;  	memcpy(self->filename, filename, len); -	self->threads = RB_ROOT; -	INIT_LIST_HEAD(&self->dead_threads); -	self->last_match = NULL;  	/*  	 * On 64bit we can mmap the data file in one go. No need for tiny mmap  	 * slices. On 32bit we use 32MB. @@ -171,10 +154,10 @@ struct perf_session *perf_session__new(const char *filename, int mode,  			goto out_delete;  	} -	if (ops && ops->ordering_requires_timestamps && -	    ops->ordered_samples && !self->sample_id_all) { +	if (tool && tool->ordering_requires_timestamps && +	    tool->ordered_samples && !self->sample_id_all) {  		dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); -		ops->ordered_samples = false; +		tool->ordered_samples = false;  	}  out: @@ -184,17 +167,22 @@ out_delete:  	return NULL;  } -static void perf_session__delete_dead_threads(struct perf_session *self) +static void machine__delete_dead_threads(struct machine *machine)  {  	struct thread *n, *t; -	list_for_each_entry_safe(t, n, &self->dead_threads, node) { +	list_for_each_entry_safe(t, n, &machine->dead_threads, node) {  		list_del(&t->node);  		thread__delete(t);  	}  } -static void perf_session__delete_threads(struct perf_session *self) +static void perf_session__delete_dead_threads(struct perf_session *session) +{ +	machine__delete_dead_threads(&session->host_machine); +} + +static void machine__delete_threads(struct machine *self)  {  	struct rb_node *nd = rb_first(&self->threads); @@ -207,6 +195,11 @@ static void perf_session__delete_threads(struct perf_session *self)  	}  } +static void perf_session__delete_threads(struct perf_session *session) +{ +	machine__delete_threads(&session->host_machine); +} +  void perf_session__delete(struct perf_session *self)  {  	perf_session__destroy_kernel_maps(self); @@ -217,7 +210,7 @@ void perf_session__delete(struct perf_session *self)  	free(self);  } -void perf_session__remove_thread(struct perf_session *self, struct thread *th) +void machine__remove_thread(struct machine *self, struct thread *th)  {  	self->last_match = NULL;  	rb_erase(&th->rb_node, &self->threads); @@ -236,16 +229,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)  	return 0;  } -int perf_session__resolve_callchain(struct perf_session *self, -				    struct thread *thread, -				    struct ip_callchain *chain, -				    struct symbol **parent) +int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, +			       struct thread *thread, +			       struct ip_callchain *chain, +			       struct symbol **parent)  {  	u8 cpumode = PERF_RECORD_MISC_USER;  	unsigned int i;  	int err; -	callchain_cursor_reset(&self->callchain_cursor); +	callchain_cursor_reset(&evsel->hists.callchain_cursor);  	for (i = 0; i < chain->nr; i++) {  		u64 ip; @@ -272,7 +265,7 @@ int perf_session__resolve_callchain(struct perf_session *self,  		al.filtered = false;  		thread__find_addr_location(thread, self, cpumode, -				MAP__FUNCTION, thread->pid, ip, &al, NULL); +					   MAP__FUNCTION, ip, &al, NULL);  		if (al.sym != NULL) {  			if (sort__has_parent && !*parent &&  			    symbol__match_parent_regex(al.sym)) @@ -281,7 +274,7 @@ int perf_session__resolve_callchain(struct perf_session *self,  				break;  		} -		err = callchain_cursor_append(&self->callchain_cursor, +		err = callchain_cursor_append(&evsel->hists.callchain_cursor,  					      ip, al.map, al.sym);  		if (err)  			return err; @@ -290,75 +283,91 @@ int perf_session__resolve_callchain(struct perf_session *self,  	return 0;  } -static int process_event_synth_stub(union perf_event *event __used, -				    struct perf_session *session __used) +static int process_event_synth_tracing_data_stub(union perf_event *event __used, +						 struct perf_session *session __used)  {  	dump_printf(": unhandled!\n");  	return 0;  } -static int process_event_sample_stub(union perf_event *event __used, +static int process_event_synth_attr_stub(union perf_event *event __used, +					 struct perf_evlist **pevlist __used) +{ +	dump_printf(": unhandled!\n"); +	return 0; +} + +static int process_event_sample_stub(struct perf_tool *tool __used, +				     union perf_event *event __used,  				     struct perf_sample *sample __used,  				     struct perf_evsel *evsel __used, -				     struct perf_session *session __used) +				     struct machine *machine __used)  {  	dump_printf(": unhandled!\n");  	return 0;  } -static int process_event_stub(union perf_event *event __used, +static int process_event_stub(struct perf_tool *tool __used, +			      union perf_event *event __used,  			      struct perf_sample *sample __used, -			      struct perf_session *session __used) +			      struct machine *machine __used) +{ +	dump_printf(": unhandled!\n"); +	return 0; +} + +static int process_finished_round_stub(struct perf_tool *tool __used, +				       union perf_event *event __used, +				       struct perf_session *perf_session __used)  {  	dump_printf(": unhandled!\n");  	return 0;  } -static int process_finished_round_stub(union perf_event *event __used, -				       struct perf_session *session __used, -				       struct perf_event_ops *ops __used) +static int process_event_type_stub(struct perf_tool *tool __used, +				   union perf_event *event __used)  {  	dump_printf(": unhandled!\n");  	return 0;  } -static int process_finished_round(union perf_event *event, -				  struct perf_session *session, -				  struct perf_event_ops *ops); +static int process_finished_round(struct perf_tool *tool, +				  union perf_event *event, +				  struct perf_session *session); -static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) +static void perf_tool__fill_defaults(struct perf_tool *tool)  { -	if (handler->sample == NULL) -		handler->sample = process_event_sample_stub; -	if (handler->mmap == NULL) -		handler->mmap = process_event_stub; -	if (handler->comm == NULL) -		handler->comm = process_event_stub; -	if (handler->fork == NULL) -		handler->fork = process_event_stub; -	if (handler->exit == NULL) -		handler->exit = process_event_stub; -	if (handler->lost == NULL) -		handler->lost = perf_event__process_lost; -	if (handler->read == NULL) -		handler->read = process_event_stub; -	if (handler->throttle == NULL) -		handler->throttle = process_event_stub; -	if (handler->unthrottle == NULL) -		handler->unthrottle = process_event_stub; -	if (handler->attr == NULL) -		handler->attr = process_event_synth_stub; -	if (handler->event_type == NULL) -		handler->event_type = process_event_synth_stub; -	if (handler->tracing_data == NULL) -		handler->tracing_data = process_event_synth_stub; -	if (handler->build_id == NULL) -		handler->build_id = process_event_synth_stub; -	if (handler->finished_round == NULL) { -		if (handler->ordered_samples) -			handler->finished_round = process_finished_round; +	if (tool->sample == NULL) +		tool->sample = process_event_sample_stub; +	if (tool->mmap == NULL) +		tool->mmap = process_event_stub; +	if (tool->comm == NULL) +		tool->comm = process_event_stub; +	if (tool->fork == NULL) +		tool->fork = process_event_stub; +	if (tool->exit == NULL) +		tool->exit = process_event_stub; +	if (tool->lost == NULL) +		tool->lost = perf_event__process_lost; +	if (tool->read == NULL) +		tool->read = process_event_sample_stub; +	if (tool->throttle == NULL) +		tool->throttle = process_event_stub; +	if (tool->unthrottle == NULL) +		tool->unthrottle = process_event_stub; +	if (tool->attr == NULL) +		tool->attr = process_event_synth_attr_stub; +	if (tool->event_type == NULL) +		tool->event_type = process_event_type_stub; +	if (tool->tracing_data == NULL) +		tool->tracing_data = process_event_synth_tracing_data_stub; +	if (tool->build_id == NULL) +		tool->build_id = process_finished_round_stub; +	if (tool->finished_round == NULL) { +		if (tool->ordered_samples) +			tool->finished_round = process_finished_round;  		else -			handler->finished_round = process_finished_round_stub; +			tool->finished_round = process_finished_round_stub;  	}  } @@ -490,11 +499,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)  static int perf_session_deliver_event(struct perf_session *session,  				      union perf_event *event,  				      struct perf_sample *sample, -				      struct perf_event_ops *ops, +				      struct perf_tool *tool,  				      u64 file_offset);  static void flush_sample_queue(struct perf_session *s, -			       struct perf_event_ops *ops) +			       struct perf_tool *tool)  {  	struct ordered_samples *os = &s->ordered_samples;  	struct list_head *head = &os->samples; @@ -505,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s,  	unsigned idx = 0, progress_next = os->nr_samples / 16;  	int ret; -	if (!ops->ordered_samples || !limit) +	if (!tool->ordered_samples || !limit)  		return;  	list_for_each_entry_safe(iter, tmp, head, list) { @@ -516,7 +525,7 @@ static void flush_sample_queue(struct perf_session *s,  		if (ret)  			pr_err("Can't parse sample, err = %d\n", ret);  		else -			perf_session_deliver_event(s, iter->event, &sample, ops, +			perf_session_deliver_event(s, iter->event, &sample, tool,  						   iter->file_offset);  		os->last_flush = iter->timestamp; @@ -578,11 +587,11 @@ static void flush_sample_queue(struct perf_session *s,   *      Flush every events below timestamp 7   *      etc...   */ -static int process_finished_round(union perf_event *event __used, -				  struct perf_session *session, -				  struct perf_event_ops *ops) +static int process_finished_round(struct perf_tool *tool, +				  union perf_event *event __used, +				  struct perf_session *session)  { -	flush_sample_queue(session, ops); +	flush_sample_queue(session, tool);  	session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;  	return 0; @@ -737,13 +746,26 @@ static void dump_sample(struct perf_session *session, union perf_event *event,  		callchain__printf(sample);  } +static struct machine * +	perf_session__find_machine_for_cpumode(struct perf_session *session, +					       union perf_event *event) +{ +	const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + +	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) +		return perf_session__find_machine(session, event->ip.pid); + +	return perf_session__find_host_machine(session); +} +  static int perf_session_deliver_event(struct perf_session *session,  				      union perf_event *event,  				      struct perf_sample *sample, -				      struct perf_event_ops *ops, +				      struct perf_tool *tool,  				      u64 file_offset)  {  	struct perf_evsel *evsel; +	struct machine *machine;  	dump_event(session, event, file_offset, sample); @@ -765,6 +787,8 @@ static int perf_session_deliver_event(struct perf_session *session,  		hists__inc_nr_events(&evsel->hists, event->header.type);  	} +	machine = perf_session__find_machine_for_cpumode(session, event); +  	switch (event->header.type) {  	case PERF_RECORD_SAMPLE:  		dump_sample(session, event, sample); @@ -772,23 +796,25 @@ static int perf_session_deliver_event(struct perf_session *session,  			++session->hists.stats.nr_unknown_id;  			return -1;  		} -		return ops->sample(event, sample, evsel, session); +		return tool->sample(tool, event, sample, evsel, machine);  	case PERF_RECORD_MMAP: -		return ops->mmap(event, sample, session); +		return tool->mmap(tool, event, sample, machine);  	case PERF_RECORD_COMM: -		return ops->comm(event, sample, session); +		return tool->comm(tool, event, sample, machine);  	case PERF_RECORD_FORK: -		return ops->fork(event, sample, session); +		return tool->fork(tool, event, sample, machine);  	case PERF_RECORD_EXIT: -		return ops->exit(event, sample, session); +		return tool->exit(tool, event, sample, machine);  	case PERF_RECORD_LOST: -		return ops->lost(event, sample, session); +		if (tool->lost == perf_event__process_lost) +			session->hists.stats.total_lost += event->lost.lost; +		return tool->lost(tool, event, sample, machine);  	case PERF_RECORD_READ: -		return ops->read(event, sample, session); +		return tool->read(tool, event, sample, evsel, machine);  	case PERF_RECORD_THROTTLE: -		return ops->throttle(event, sample, session); +		return tool->throttle(tool, event, sample, machine);  	case PERF_RECORD_UNTHROTTLE: -		return ops->unthrottle(event, sample, session); +		return tool->unthrottle(tool, event, sample, machine);  	default:  		++session->hists.stats.nr_unknown_events;  		return -1; @@ -812,24 +838,29 @@ static int perf_session__preprocess_sample(struct perf_session *session,  }  static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, -					    struct perf_event_ops *ops, u64 file_offset) +					    struct perf_tool *tool, u64 file_offset)  { +	int err; +  	dump_event(session, event, file_offset, NULL);  	/* These events are processed right away */  	switch (event->header.type) {  	case PERF_RECORD_HEADER_ATTR: -		return ops->attr(event, session); +		err = tool->attr(event, &session->evlist); +		if (err == 0) +			perf_session__update_sample_type(session); +		return err;  	case PERF_RECORD_HEADER_EVENT_TYPE: -		return ops->event_type(event, session); +		return tool->event_type(tool, event);  	case PERF_RECORD_HEADER_TRACING_DATA:  		/* setup for reading amidst mmap */  		lseek(session->fd, file_offset, SEEK_SET); -		return ops->tracing_data(event, session); +		return tool->tracing_data(event, session);  	case PERF_RECORD_HEADER_BUILD_ID: -		return ops->build_id(event, session); +		return tool->build_id(tool, event, session);  	case PERF_RECORD_FINISHED_ROUND: -		return ops->finished_round(event, session, ops); +		return tool->finished_round(tool, event, session);  	default:  		return -EINVAL;  	} @@ -837,7 +868,7 @@ static int perf_session__process_user_event(struct perf_session *session, union  static int perf_session__process_event(struct perf_session *session,  				       union perf_event *event, -				       struct perf_event_ops *ops, +				       struct perf_tool *tool,  				       u64 file_offset)  {  	struct perf_sample sample; @@ -853,7 +884,7 @@ static int perf_session__process_event(struct perf_session *session,  	hists__inc_nr_events(&session->hists, event->header.type);  	if (event->header.type >= PERF_RECORD_USER_TYPE_START) -		return perf_session__process_user_event(session, event, ops, file_offset); +		return perf_session__process_user_event(session, event, tool, file_offset);  	/*  	 * For all kernel events we get the sample data @@ -866,14 +897,14 @@ static int perf_session__process_event(struct perf_session *session,  	if (perf_session__preprocess_sample(session, event, &sample))  		return 0; -	if (ops->ordered_samples) { +	if (tool->ordered_samples) {  		ret = perf_session_queue_event(session, event, &sample,  					       file_offset);  		if (ret != -ETIME)  			return ret;  	} -	return perf_session_deliver_event(session, event, &sample, ops, +	return perf_session_deliver_event(session, event, &sample, tool,  					  file_offset);  } @@ -884,6 +915,11 @@ void perf_event_header__bswap(struct perf_event_header *self)  	self->size = bswap_16(self->size);  } +struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) +{ +	return machine__findnew_thread(&session->host_machine, pid); +} +  static struct thread *perf_session__register_idle_thread(struct perf_session *self)  {  	struct thread *thread = perf_session__findnew(self, 0); @@ -897,9 +933,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se  }  static void perf_session__warn_about_errors(const struct perf_session *session, -					    const struct perf_event_ops *ops) +					    const struct perf_tool *tool)  { -	if (ops->lost == perf_event__process_lost && +	if (tool->lost == perf_event__process_lost &&  	    session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {  		ui__warning("Processed %d events and lost %d chunks!\n\n"  			    "Check IO/CPU overload!\n\n", @@ -934,7 +970,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session,  volatile int session_done;  static int __perf_session__process_pipe_events(struct perf_session *self, -					       struct perf_event_ops *ops) +					       struct perf_tool *tool)  {  	union perf_event event;  	uint32_t size; @@ -943,7 +979,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,  	int err;  	void *p; -	perf_event_ops__fill_defaults(ops); +	perf_tool__fill_defaults(tool);  	head = 0;  more: @@ -979,8 +1015,7 @@ more:  		}  	} -	if (size == 0 || -	    (skip = perf_session__process_event(self, &event, ops, head)) < 0) { +	if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {  		dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",  			    head, event.header.size, event.header.type);  		/* @@ -1003,7 +1038,7 @@ more:  done:  	err = 0;  out_err: -	perf_session__warn_about_errors(self, ops); +	perf_session__warn_about_errors(self, tool);  	perf_session_free_sample_buffers(self);  	return err;  } @@ -1034,7 +1069,7 @@ fetch_mmaped_event(struct perf_session *session,  int __perf_session__process_events(struct perf_session *session,  				   u64 data_offset, u64 data_size, -				   u64 file_size, struct perf_event_ops *ops) +				   u64 file_size, struct perf_tool *tool)  {  	u64 head, page_offset, file_offset, file_pos, progress_next;  	int err, mmap_prot, mmap_flags, map_idx = 0; @@ -1043,7 +1078,7 @@ int __perf_session__process_events(struct perf_session *session,  	union perf_event *event;  	uint32_t size; -	perf_event_ops__fill_defaults(ops); +	perf_tool__fill_defaults(tool);  	page_size = sysconf(_SC_PAGESIZE); @@ -1098,7 +1133,7 @@ more:  	size = event->header.size;  	if (size == 0 || -	    perf_session__process_event(session, event, ops, file_pos) < 0) { +	    perf_session__process_event(session, event, tool, file_pos) < 0) {  		dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",  			    file_offset + head, event->header.size,  			    event->header.type); @@ -1127,15 +1162,15 @@ more:  	err = 0;  	/* do the final flush for ordered samples */  	session->ordered_samples.next_flush = ULLONG_MAX; -	flush_sample_queue(session, ops); +	flush_sample_queue(session, tool);  out_err: -	perf_session__warn_about_errors(session, ops); +	perf_session__warn_about_errors(session, tool);  	perf_session_free_sample_buffers(session);  	return err;  }  int perf_session__process_events(struct perf_session *self, -				 struct perf_event_ops *ops) +				 struct perf_tool *tool)  {  	int err; @@ -1146,9 +1181,9 @@ int perf_session__process_events(struct perf_session *self,  		err = __perf_session__process_events(self,  						     self->header.data_offset,  						     self->header.data_size, -						     self->size, ops); +						     self->size, tool);  	else -		err = __perf_session__process_pipe_events(self, ops); +		err = __perf_session__process_pipe_events(self, tool);  	return err;  } @@ -1163,9 +1198,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg)  	return true;  } -int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, -					     const char *symbol_name, -					     u64 addr) +int maps__set_kallsyms_ref_reloc_sym(struct map **maps, +				     const char *symbol_name, u64 addr)  {  	char *bracket;  	enum map_type i; @@ -1224,6 +1258,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)  	return ret;  } +size_t perf_session__fprintf(struct perf_session *session, FILE *fp) +{ +	/* +	 * FIXME: Here we have to actually print all the machines in this +	 * session, not just the host... +	 */ +	return machine__fprintf(&session->host_machine, fp); +} + +void perf_session__remove_thread(struct perf_session *session, +				 struct thread *th) +{ +	/* +	 * FIXME: This one makes no sense, we need to remove the thread from +	 * the machine it belongs to, perf_session can have many machines, so +	 * doing it always on ->host_machine is wrong.  Fix when auditing all +	 * the 'perf kvm' code. +	 */ +	machine__remove_thread(&session->host_machine, th); +} +  struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,  					      unsigned int type)  { @@ -1236,17 +1291,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,  	return NULL;  } -void perf_session__print_ip(union perf_event *event, -			    struct perf_sample *sample, -			    struct perf_session *session, -			    int print_sym, int print_dso) +void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, +			  struct machine *machine, struct perf_evsel *evsel, +			  int print_sym, int print_dso)  {  	struct addr_location al;  	const char *symname, *dsoname; -	struct callchain_cursor *cursor = &session->callchain_cursor; +	struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;  	struct callchain_cursor_node *node; -	if (perf_event__preprocess_sample(event, session, &al, sample, +	if (perf_event__preprocess_sample(event, machine, &al, sample,  					  NULL) < 0) {  		error("problem processing %d event, skipping it.\n",  			event->header.type); @@ -1255,7 +1309,7 @@ void perf_session__print_ip(union perf_event *event,  	if (symbol_conf.use_callchain && sample->callchain) { -		if (perf_session__resolve_callchain(session, al.thread, +		if (machine__resolve_callchain(machine, evsel, al.thread,  						sample->callchain, NULL) != 0) {  			if (verbose)  				error("Failed to resolve callchain. Skipping\n"); @@ -1333,6 +1387,10 @@ int perf_session__cpu_bitmap(struct perf_session *session,  	}  	map = cpu_map__new(cpu_list); +	if (map == NULL) { +		pr_err("Invalid cpu_list\n"); +		return -1; +	}  	for (i = 0; i < map->nr; i++) {  		int cpu = map->map[i];  |