2214 lines · 59.2 KB · C
RawDownload
#include <errno.h>#include <inttypes.h>#include <linux/kernel.h>#include <traceevent/event-parse.h>#include <api/fs/fs.h> #include <byteswap.h>#include <unistd.h>#include <sys/types.h>#include <sys/mman.h> #include "evlist.h"#include "evsel.h"#include "memswap.h"#include "session.h"#include "tool.h"#include "sort.h"#include "util.h"#include "cpumap.h"#include "perf_regs.h"#include "asm/bug.h"#include "auxtrace.h"#include "thread.h"#include "thread-stack.h"#include "stat.h" static int perf_session__deliver_event(struct perf_session *session,				       union perf_event *event,				       struct perf_sample *sample,				       struct perf_tool *tool,				       u64 file_offset); static int perf_session__open(struct perf_session *session){	struct perf_data_file *file = session->file; 	if (perf_session__read_header(session) < 0) {		pr_err("incompatible file format (rerun with -v to learn more)\n");		return -1;	} 	if (perf_data_file__is_pipe(file))		return 0; 	if (perf_header__has_feat(&session->header, HEADER_STAT))		return 0; 	if (!perf_evlist__valid_sample_type(session->evlist)) {		pr_err("non matching sample_type\n");		return -1;	} 	if (!perf_evlist__valid_sample_id_all(session->evlist)) {		pr_err("non matching sample_id_all\n");		return -1;	} 	if (!perf_evlist__valid_read_format(session->evlist)) {		pr_err("non matching read_format\n");		return -1;	} 	return 0;} void perf_session__set_id_hdr_size(struct perf_session *session){	u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 	machines__set_id_hdr_size(&session->machines, id_hdr_size);} int perf_session__create_kernel_maps(struct perf_session *session){	int ret = machine__create_kernel_maps(&session->machines.host); 	if (ret >= 0)		ret = machines__create_guest_kernel_maps(&session->machines);	return ret;} static void perf_session__destroy_kernel_maps(struct perf_session *session){	machines__destroy_kernel_maps(&session->machines);} static bool perf_session__has_comm_exec(struct perf_session *session){	struct perf_evsel *evsel; 	evlist__for_each_entry(session->evlist, evsel) {		if (evsel->attr.comm_exec)			return true;	} 	return false;} static void perf_session__set_comm_exec(struct perf_session *session){	bool comm_exec = perf_session__has_comm_exec(session); 	machines__set_comm_exec(&session->machines, comm_exec);} static int ordered_events__deliver_event(struct ordered_events *oe,					 struct ordered_event *event){	struct perf_sample sample;	struct perf_session *session = container_of(oe, struct perf_session,						    ordered_events);	int ret = perf_evlist__parse_sample(session->evlist, event->event, &sample); 	if (ret) {		pr_err("Can't parse sample, err = %d\n", ret);		return ret;	} 	return perf_session__deliver_event(session, event->event, &sample,					   session->tool, event->file_offset);} struct perf_session *perf_session__new(struct perf_data_file *file,				       bool repipe, struct perf_tool *tool){	struct perf_session *session = zalloc(sizeof(*session)); 	if (!session)		goto out; 	session->repipe = repipe;	session->tool   = tool;	INIT_LIST_HEAD(&session->auxtrace_index);	machines__init(&session->machines);	ordered_events__init(&session->ordered_events, ordered_events__deliver_event); 	if (file) {		if (perf_data_file__open(file))			goto out_delete; 		session->file = file; 		if (perf_data_file__is_read(file)) {			if (perf_session__open(session) < 0)				goto out_close; 			/*			 * set session attributes that are present in perf.data			 * but not in pipe-mode.			 */			if (!file->is_pipe) {				perf_session__set_id_hdr_size(session);				perf_session__set_comm_exec(session);			}		}	} else  {		session->machines.host.env = &perf_env;	} 	if (!file || perf_data_file__is_write(file)) {		/*		 * In O_RDONLY mode this will be performed when reading the		 * kernel MMAP event, in perf_event__process_mmap().		 */		if (perf_session__create_kernel_maps(session) < 0)			pr_warning("Cannot read kernel map\n");	} 	/*	 * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is	 * processed, so perf_evlist__sample_id_all is not meaningful here.	 */	if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps &&	    tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {		dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");		tool->ordered_events = false;	} 	return session;  out_close:	perf_data_file__close(file); out_delete:	perf_session__delete(session); out:	return NULL;} static void perf_session__delete_threads(struct perf_session *session){	machine__delete_threads(&session->machines.host);} void perf_session__delete(struct perf_session *session){	if (session == NULL)		return;	auxtrace__free(session);	auxtrace_index__free(&session->auxtrace_index);	perf_session__destroy_kernel_maps(session);	perf_session__delete_threads(session);	perf_env__exit(&session->header.env);	machines__exit(&session->machines);	if (session->file)		perf_data_file__close(session->file);	free(session);} static int process_event_synth_tracing_data_stub(struct perf_tool *tool						 __maybe_unused,						 union perf_event *event						 __maybe_unused,						 struct perf_session *session						__maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,					 union perf_event *event __maybe_unused,					 struct perf_evlist **pevlist					 __maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused,						 union perf_event *event __maybe_unused,						 struct perf_evlist **pevlist						 __maybe_unused){	if (dump_trace)		perf_event__fprintf_event_update(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,				     union perf_event *event __maybe_unused,				     struct perf_sample *sample __maybe_unused,				     struct perf_evsel *evsel __maybe_unused,				     struct machine *machine __maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_event_stub(struct perf_tool *tool __maybe_unused,			      union perf_event *event __maybe_unused,			      struct perf_sample *sample __maybe_unused,			      struct machine *machine __maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,				       union perf_event *event __maybe_unused,				       struct ordered_events *oe __maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_finished_round(struct perf_tool *tool,				  union perf_event *event,				  struct ordered_events *oe); static int skipn(int fd, off_t n){	char buf[4096];	ssize_t ret; 	while (n > 0) {		ret = read(fd, buf, min(n, (off_t)sizeof(buf)));		if (ret <= 0)			return ret;		n -= ret;	} 	return 0;} static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,				       union perf_event *event,				       struct perf_session *session				       __maybe_unused){	dump_printf(": unhandled!\n");	if (perf_data_file__is_pipe(session->file))		skipn(perf_data_file__fd(session->file), event->auxtrace.size);	return event->auxtrace.size;} static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,				  union perf_event *event __maybe_unused,				  struct perf_session *session __maybe_unused){	dump_printf(": unhandled!\n");	return 0;}  staticint process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,				  union perf_event *event __maybe_unused,				  struct perf_session *session __maybe_unused){	if (dump_trace)		perf_event__fprintf_thread_map(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} staticint process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,			       union perf_event *event __maybe_unused,			       struct perf_session *session __maybe_unused){	if (dump_trace)		perf_event__fprintf_cpu_map(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} staticint process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,				   union perf_event *event __maybe_unused,				   struct perf_session *session __maybe_unused){	if (dump_trace)		perf_event__fprintf_stat_config(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} static int process_stat_stub(struct perf_tool *tool __maybe_unused,			     union perf_event *event __maybe_unused,			     struct perf_session *perf_session			     __maybe_unused){	if (dump_trace)		perf_event__fprintf_stat(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,				   union perf_event *event __maybe_unused,				   struct perf_session *perf_session				   __maybe_unused){	if (dump_trace)		perf_event__fprintf_stat_round(event, stdout); 	dump_printf(": unhandled!\n");	return 0;} void perf_tool__fill_defaults(struct perf_tool *tool){	if (tool->sample == NULL)		tool->sample = process_event_sample_stub;	if (tool->mmap == NULL)		tool->mmap = process_event_stub;	if (tool->mmap2 == NULL)		tool->mmap2 = 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->lost_samples == NULL)		tool->lost_samples = perf_event__process_lost_samples;	if (tool->aux == NULL)		tool->aux = perf_event__process_aux;	if (tool->itrace_start == NULL)		tool->itrace_start = perf_event__process_itrace_start;	if (tool->context_switch == NULL)		tool->context_switch = perf_event__process_switch;	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_update == NULL)		tool->event_update = process_event_synth_event_update_stub;	if (tool->tracing_data == NULL)		tool->tracing_data = process_event_synth_tracing_data_stub;	if (tool->build_id == NULL)		tool->build_id = process_event_op2_stub;	if (tool->finished_round == NULL) {		if (tool->ordered_events)			tool->finished_round = process_finished_round;		else			tool->finished_round = process_finished_round_stub;	}	if (tool->id_index == NULL)		tool->id_index = process_event_op2_stub;	if (tool->auxtrace_info == NULL)		tool->auxtrace_info = process_event_op2_stub;	if (tool->auxtrace == NULL)		tool->auxtrace = process_event_auxtrace_stub;	if (tool->auxtrace_error == NULL)		tool->auxtrace_error = process_event_op2_stub;	if (tool->thread_map == NULL)		tool->thread_map = process_event_thread_map_stub;	if (tool->cpu_map == NULL)		tool->cpu_map = process_event_cpu_map_stub;	if (tool->stat_config == NULL)		tool->stat_config = process_event_stat_config_stub;	if (tool->stat == NULL)		tool->stat = process_stat_stub;	if (tool->stat_round == NULL)		tool->stat_round = process_stat_round_stub;	if (tool->time_conv == NULL)		tool->time_conv = process_event_op2_stub;} static void swap_sample_id_all(union perf_event *event, void *data){	void *end = (void *) event + event->header.size;	int size = end - data; 	BUG_ON(size % sizeof(u64));	mem_bswap_64(data, size);} static void perf_event__all64_swap(union perf_event *event,				   bool sample_id_all __maybe_unused){	struct perf_event_header *hdr = &event->header;	mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));} static void perf_event__comm_swap(union perf_event *event, bool sample_id_all){	event->comm.pid = bswap_32(event->comm.pid);	event->comm.tid = bswap_32(event->comm.tid); 	if (sample_id_all) {		void *data = &event->comm.comm; 		data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));		swap_sample_id_all(event, data);	}} static void perf_event__mmap_swap(union perf_event *event,				  bool sample_id_all){	event->mmap.pid	  = bswap_32(event->mmap.pid);	event->mmap.tid	  = bswap_32(event->mmap.tid);	event->mmap.start = bswap_64(event->mmap.start);	event->mmap.len	  = bswap_64(event->mmap.len);	event->mmap.pgoff = bswap_64(event->mmap.pgoff); 	if (sample_id_all) {		void *data = &event->mmap.filename; 		data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));		swap_sample_id_all(event, data);	}} static void perf_event__mmap2_swap(union perf_event *event,				  bool sample_id_all){	event->mmap2.pid   = bswap_32(event->mmap2.pid);	event->mmap2.tid   = bswap_32(event->mmap2.tid);	event->mmap2.start = bswap_64(event->mmap2.start);	event->mmap2.len   = bswap_64(event->mmap2.len);	event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);	event->mmap2.maj   = bswap_32(event->mmap2.maj);	event->mmap2.min   = bswap_32(event->mmap2.min);	event->mmap2.ino   = bswap_64(event->mmap2.ino); 	if (sample_id_all) {		void *data = &event->mmap2.filename; 		data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));		swap_sample_id_all(event, data);	}}static void perf_event__task_swap(union perf_event *event, bool sample_id_all){	event->fork.pid	 = bswap_32(event->fork.pid);

Lines 1–500 of 2214.