Arnaldo Carvalho de Meloperf evsel: Ditch evsel->handler.data field744a97113 years agoHistory
1661 lines · 42.8 KB · C
RawDownload
#include <linux/kernel.h>#include <traceevent/event-parse.h> #include <byteswap.h>#include <unistd.h>#include <sys/types.h>#include <sys/mman.h> #include "evlist.h"#include "evsel.h"#include "session.h"#include "tool.h"#include "sort.h"#include "util.h"#include "cpumap.h"#include "perf_regs.h"#include "vdso.h" 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)");		return -1;	} 	if (perf_data_file__is_pipe(file))		return 0; 	if (!perf_evlist__valid_sample_type(session->evlist)) {		pr_err("non matching sample_type");		return -1;	} 	if (!perf_evlist__valid_sample_id_all(session->evlist)) {		pr_err("non matching sample_id_all");		return -1;	} 	if (!perf_evlist__valid_read_format(session->evlist)) {		pr_err("non matching read_format");		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);} 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;	INIT_LIST_HEAD(&session->ordered_samples.samples);	INIT_LIST_HEAD(&session->ordered_samples.sample_cache);	INIT_LIST_HEAD(&session->ordered_samples.to_free);	machines__init(&session->machines); 	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; 			perf_session__set_id_hdr_size(session);		}	} 	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)			goto out_delete;	} 	if (tool && tool->ordering_requires_timestamps &&	    tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {		dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");		tool->ordered_samples = false;	} 	return session;  out_close:	perf_data_file__close(file); out_delete:	perf_session__delete(session); out:	return NULL;} static void perf_session__delete_dead_threads(struct perf_session *session){	machine__delete_dead_threads(&session->machines.host);} static void perf_session__delete_threads(struct perf_session *session){	machine__delete_threads(&session->machines.host);} static void perf_session_env__delete(struct perf_session_env *env){	free(env->hostname);	free(env->os_release);	free(env->version);	free(env->arch);	free(env->cpu_desc);	free(env->cpuid); 	free(env->cmdline);	free(env->sibling_cores);	free(env->sibling_threads);	free(env->numa_nodes);	free(env->pmu_mappings);} void perf_session__delete(struct perf_session *session){	perf_session__destroy_kernel_maps(session);	perf_session__delete_dead_threads(session);	perf_session__delete_threads(session);	perf_session_env__delete(&session->header.env);	machines__exit(&session->machines);	if (session->file)		perf_data_file__close(session->file);	free(session);	vdso__exit();} 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_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 perf_session *perf_session				       __maybe_unused){	dump_printf(": unhandled!\n");	return 0;} static int process_finished_round(struct perf_tool *tool,				  union perf_event *event,				  struct perf_session *session); 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->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->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			tool->finished_round = process_finished_round_stub;	}} void mem_bswap_32(void *src, int byte_size){	u32 *m = src;	while (byte_size > 0) {		*m = bswap_32(*m);		byte_size -= sizeof(u32);		++m;	}} void mem_bswap_64(void *src, int byte_size){	u64 *m = src; 	while (byte_size > 0) {		*m = bswap_64(*m);		byte_size -= sizeof(u64);		++m;	}} 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);	event->fork.tid	 = bswap_32(event->fork.tid);	event->fork.ppid = bswap_32(event->fork.ppid);	event->fork.ptid = bswap_32(event->fork.ptid);	event->fork.time = bswap_64(event->fork.time); 	if (sample_id_all)		swap_sample_id_all(event, &event->fork + 1);} static void perf_event__read_swap(union perf_event *event, bool sample_id_all){	event->read.pid		 = bswap_32(event->read.pid);	event->read.tid		 = bswap_32(event->read.tid);	event->read.value	 = bswap_64(event->read.value);	event->read.time_enabled = bswap_64(event->read.time_enabled);	event->read.time_running = bswap_64(event->read.time_running);	event->read.id		 = bswap_64(event->read.id); 	if (sample_id_all)		swap_sample_id_all(event, &event->read + 1);} static void perf_event__throttle_swap(union perf_event *event,				      bool sample_id_all){	event->throttle.time	  = bswap_64(event->throttle.time);	event->throttle.id	  = bswap_64(event->throttle.id);	event->throttle.stream_id = bswap_64(event->throttle.stream_id); 	if (sample_id_all)		swap_sample_id_all(event, &event->throttle + 1);} static u8 revbyte(u8 b){	int rev = (b >> 4) | ((b & 0xf) << 4);	rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);	rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);	return (u8) rev;} /* * XXX this is hack in attempt to carry flags bitfield * throught endian village. ABI says: * * Bit-fields are allocated from right to left (least to most significant) * on little-endian implementations and from left to right (most to least * significant) on big-endian implementations. * * The above seems to be byte specific, so we need to reverse each * byte of the bitfield. 'Internet' also says this might be implementation * specific and we probably need proper fix and carry perf_event_attr * bitfield flags in separate data file FEAT_ section. Thought this seems * to work for now. */static void swap_bitfield(u8 *p, unsigned len){	unsigned i; 	for (i = 0; i < len; i++) {		*p = revbyte(*p);		p++;	}} /* exported for swapping attributes in file header */void perf_event__attr_swap(struct perf_event_attr *attr){	attr->type		= bswap_32(attr->type);	attr->size		= bswap_32(attr->size);	attr->config		= bswap_64(attr->config);	attr->sample_period	= bswap_64(attr->sample_period);	attr->sample_type	= bswap_64(attr->sample_type);	attr->read_format	= bswap_64(attr->read_format);	attr->wakeup_events	= bswap_32(attr->wakeup_events);	attr->bp_type		= bswap_32(attr->bp_type);	attr->bp_addr		= bswap_64(attr->bp_addr);	attr->bp_len		= bswap_64(attr->bp_len);	attr->branch_sample_type = bswap_64(attr->branch_sample_type);	attr->sample_regs_user	 = bswap_64(attr->sample_regs_user);	attr->sample_stack_user  = bswap_32(attr->sample_stack_user); 	swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));} static void perf_event__hdr_attr_swap(union perf_event *event,				      bool sample_id_all __maybe_unused){	size_t size; 	perf_event__attr_swap(&event->attr.attr); 	size = event->header.size;	size -= (void *)&event->attr.id - (void *)event;	mem_bswap_64(event->attr.id, size);} static void perf_event__event_type_swap(union perf_event *event,					bool sample_id_all __maybe_unused){	event->event_type.event_type.event_id =		bswap_64(event->event_type.event_type.event_id);} static void perf_event__tracing_data_swap(union perf_event *event,					  bool sample_id_all __maybe_unused){	event->tracing_data.size = bswap_32(event->tracing_data.size);} typedef void (*perf_event__swap_op)(union perf_event *event,				    bool sample_id_all); static perf_event__swap_op perf_event__swap_ops[] = {	[PERF_RECORD_MMAP]		  = perf_event__mmap_swap,	[PERF_RECORD_MMAP2]		  = perf_event__mmap2_swap,	[PERF_RECORD_COMM]		  = perf_event__comm_swap,	[PERF_RECORD_FORK]		  = perf_event__task_swap,	[PERF_RECORD_EXIT]		  = perf_event__task_swap,	[PERF_RECORD_LOST]		  = perf_event__all64_swap,	[PERF_RECORD_READ]		  = perf_event__read_swap,	[PERF_RECORD_THROTTLE]		  = perf_event__throttle_swap,	[PERF_RECORD_UNTHROTTLE]	  = perf_event__throttle_swap,	[PERF_RECORD_SAMPLE]		  = perf_event__all64_swap,	[PERF_RECORD_HEADER_ATTR]	  = perf_event__hdr_attr_swap,	[PERF_RECORD_HEADER_EVENT_TYPE]	  = perf_event__event_type_swap,	[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,	[PERF_RECORD_HEADER_BUILD_ID]	  = NULL,	[PERF_RECORD_HEADER_MAX]	  = NULL,}; struct sample_queue {	u64			timestamp;	u64			file_offset;	union perf_event	*event;	struct list_head	list;}; static void perf_session_free_sample_buffers(struct perf_session *session){	struct ordered_samples *os = &session->ordered_samples; 	while (!list_empty(&os->to_free)) {		struct sample_queue *sq; 		sq = list_entry(os->to_free.next, struct sample_queue, list);		list_del(&sq->list);		free(sq);	}} 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 flush_sample_queue(struct perf_session *s,		       struct perf_tool *tool){	struct ordered_samples *os = &s->ordered_samples;	struct list_head *head = &os->samples;

Lines 1–500 of 1661.