diff options
| author | Ingo Molnar <mingo@elte.hu> | 2011-03-16 13:42:48 +0100 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2011-03-16 13:44:06 +0100 | 
| commit | 8b7cdd08fe304b41a2399eaaa5225159ac6db0d8 (patch) | |
| tree | 77aecdeaf0a9127717211d27c0fdff6e357846e4 /tools | |
| parent | d10902812c9cd5583130a4ebb9ad19c60b68149d (diff) | |
| parent | 43adec955edd116c3e98c6e2f85fbd63281f5221 (diff) | |
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/urgent
Diffstat (limited to 'tools')
24 files changed, 580 insertions, 200 deletions
| diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt new file mode 100644 index 000000000000..0cada9e053dc --- /dev/null +++ b/tools/perf/Documentation/perf-evlist.txt @@ -0,0 +1,26 @@ +perf-evlist(1) +============== + +NAME +---- +perf-evlist - List the event names in a perf.data file + +SYNOPSIS +-------- +[verse] +'perf evlist <options>' + +DESCRIPTION +----------- +This command displays the names of events sampled in a perf.data file. + +OPTIONS +------- +-i:: +--input=:: +        Input file name. (default: perf.data) + +SEE ALSO +-------- +linkperf:perf-record[1], linkperf:perf-list[1], +linkperf:perf-report[1] diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 29ad94293cd2..66f040b30729 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -112,6 +112,28 @@ OPTIONS  --debug-mode::          Do various checks like samples ordering and lost events. +-f:: +--fields +        Comma separated list of fields to print. Options are: +        comm, tid, pid, time, cpu, event, trace, sym. Field +        list must be prepended with the type, trace, sw or hw, +        to indicate to which event type the field list applies. +        e.g., -f sw:comm,tid,time,sym  and -f trace:time,cpu,trace + +-k:: +--vmlinux=<file>:: +        vmlinux pathname + +--kallsyms=<file>:: +        kallsyms pathname + +--symfs=<directory>:: +        Look for files with symbols relative to this directory. + +-G:: +--hide-call-graph:: +        When printing symbols do not display call chain. +  SEE ALSO  --------  linkperf:perf-record[1], linkperf:perf-script-perl[1], diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 9b8421805c5c..158c30e8210c 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -338,6 +338,7 @@ endif  BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o  BUILTIN_OBJS += $(OUTPUT)builtin-diff.o +BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o  BUILTIN_OBJS += $(OUTPUT)builtin-help.o  BUILTIN_OBJS += $(OUTPUT)builtin-sched.o  BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c new file mode 100644 index 000000000000..4c5e9e04a41f --- /dev/null +++ b/tools/perf/builtin-evlist.c @@ -0,0 +1,54 @@ +/* + * Builtin evlist command: Show the list of event selectors present + * in a perf.data file. + */ +#include "builtin.h" + +#include "util/util.h" + +#include <linux/list.h> + +#include "perf.h" +#include "util/evlist.h" +#include "util/evsel.h" +#include "util/parse-events.h" +#include "util/parse-options.h" +#include "util/session.h" + +static char const *input_name = "perf.data"; + +static int __cmd_evlist(void) +{ +	struct perf_session *session; +	struct perf_evsel *pos; + +	session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); +	if (session == NULL) +		return -ENOMEM; + +	list_for_each_entry(pos, &session->evlist->entries, node) +		printf("%s\n", event_name(pos)); + +	perf_session__delete(session); +	return 0; +} + +static const char * const evlist_usage[] = { +	"perf evlist [<options>]", +	NULL +}; + +static const struct option options[] = { +	OPT_STRING('i', "input", &input_name, "file", +		    "input file name"), +	OPT_END() +}; + +int cmd_evlist(int argc, const char **argv, const char *prefix __used) +{ +	argc = parse_options(argc, argv, options, evlist_usage, 0); +	if (argc) +		usage_with_options(evlist_usage, options); + +	return __cmd_evlist(); +} diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 5f40df635dcb..9f5fc5492141 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -12,6 +12,8 @@  #include "util/trace-event.h"  #include "util/parse-options.h"  #include "util/util.h" +#include "util/evlist.h" +#include "util/evsel.h"  static char const		*script_name;  static char const		*generate_script_lang; @@ -19,6 +21,183 @@ static bool			debug_mode;  static u64			last_timestamp;  static u64			nr_unordered;  extern const struct option	record_options[]; +static bool			no_callchain; + +enum perf_output_field { +	PERF_OUTPUT_COMM            = 1U << 0, +	PERF_OUTPUT_TID             = 1U << 1, +	PERF_OUTPUT_PID             = 1U << 2, +	PERF_OUTPUT_TIME            = 1U << 3, +	PERF_OUTPUT_CPU             = 1U << 4, +	PERF_OUTPUT_EVNAME          = 1U << 5, +	PERF_OUTPUT_TRACE           = 1U << 6, +	PERF_OUTPUT_SYM             = 1U << 7, +}; + +struct output_option { +	const char *str; +	enum perf_output_field field; +} all_output_options[] = { +	{.str = "comm",  .field = PERF_OUTPUT_COMM}, +	{.str = "tid",   .field = PERF_OUTPUT_TID}, +	{.str = "pid",   .field = PERF_OUTPUT_PID}, +	{.str = "time",  .field = PERF_OUTPUT_TIME}, +	{.str = "cpu",   .field = PERF_OUTPUT_CPU}, +	{.str = "event", .field = PERF_OUTPUT_EVNAME}, +	{.str = "trace", .field = PERF_OUTPUT_TRACE}, +	{.str = "sym",   .field = PERF_OUTPUT_SYM}, +}; + +/* default set to maintain compatibility with current format */ +static u64 output_fields[PERF_TYPE_MAX] = { +	[PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ +			       PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ +			       PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + +	[PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ +			       PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ +			       PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + +	[PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ +				 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ +				 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, +}; + +static bool output_set_by_user; + +#define PRINT_FIELD(x)  (output_fields[attr->type] & PERF_OUTPUT_##x) + +static int perf_session__check_attr(struct perf_session *session, +				    struct perf_event_attr *attr) +{ +	if (PRINT_FIELD(TRACE) && +		!perf_session__has_traces(session, "record -R")) +		return -EINVAL; + +	if (PRINT_FIELD(SYM)) { +		if (!(session->sample_type & PERF_SAMPLE_IP)) { +			pr_err("Samples do not contain IP data.\n"); +			return -EINVAL; +		} +		if (!no_callchain && +		    !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) +			symbol_conf.use_callchain = false; +	} + +	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && +		!(session->sample_type & PERF_SAMPLE_TID)) { +		pr_err("Samples do not contain TID/PID data.\n"); +		return -EINVAL; +	} + +	if (PRINT_FIELD(TIME) && +		!(session->sample_type & PERF_SAMPLE_TIME)) { +		pr_err("Samples do not contain timestamps.\n"); +		return -EINVAL; +	} + +	if (PRINT_FIELD(CPU) && +		!(session->sample_type & PERF_SAMPLE_CPU)) { +		pr_err("Samples do not contain cpu.\n"); +		return -EINVAL; +	} + +	return 0; +} + +static void print_sample_start(struct perf_sample *sample, +			       struct thread *thread, +			       struct perf_event_attr *attr) +{ +	int type; +	struct event *event; +	const char *evname = NULL; +	unsigned long secs; +	unsigned long usecs; +	unsigned long long nsecs; + +	if (PRINT_FIELD(COMM)) { +		if (latency_format) +			printf("%8.8s ", thread->comm); +		else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain) +			printf("%s ", thread->comm); +		else +			printf("%16s ", thread->comm); +	} + +	if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) +		printf("%5d/%-5d ", sample->pid, sample->tid); +	else if (PRINT_FIELD(PID)) +		printf("%5d ", sample->pid); +	else if (PRINT_FIELD(TID)) +		printf("%5d ", sample->tid); + +	if (PRINT_FIELD(CPU)) { +		if (latency_format) +			printf("%3d ", sample->cpu); +		else +			printf("[%03d] ", sample->cpu); +	} + +	if (PRINT_FIELD(TIME)) { +		nsecs = sample->time; +		secs = nsecs / NSECS_PER_SEC; +		nsecs -= secs * NSECS_PER_SEC; +		usecs = nsecs / NSECS_PER_USEC; +		printf("%5lu.%06lu: ", secs, usecs); +	} + +	if (PRINT_FIELD(EVNAME)) { +		if (attr->type == PERF_TYPE_TRACEPOINT) { +			type = trace_parse_common_type(sample->raw_data); +			event = trace_find_event(type); +			if (event) +				evname = event->name; +		} else +			evname = __event_name(attr->type, attr->config); + +		printf("%s: ", evname ? evname : "(unknown)"); +	} +} + +static void process_event(union perf_event *event __unused, +			  struct perf_sample *sample, +			  struct perf_session *session, +			  struct thread *thread) +{ +	struct perf_event_attr *attr; +	struct perf_evsel *evsel; + +	evsel = perf_evlist__id2evsel(session->evlist, sample->id); +	if (evsel == NULL) { +		pr_err("Invalid data. Contains samples with id not in " +		       "its header!\n"); +		return; +	} +	attr = &evsel->attr; + +	if (output_fields[attr->type] == 0) +		return; + +	if (perf_session__check_attr(session, attr) < 0) +		return; + +	print_sample_start(sample, thread, attr); + +	if (PRINT_FIELD(TRACE)) +		print_trace_event(sample->cpu, sample->raw_data, +				  sample->raw_size); + +	if (PRINT_FIELD(SYM)) { +		if (!symbol_conf.use_callchain) +			printf(" "); +		else +			printf("\n"); +		perf_session__print_symbols(event, sample, session); +	} + +	printf("\n"); +}  static int default_start_script(const char *script __unused,  				int argc __unused, @@ -40,7 +219,7 @@ static int default_generate_script(const char *outfile __unused)  static struct scripting_ops default_scripting_ops = {  	.start_script		= default_start_script,  	.stop_script		= default_stop_script, -	.process_event		= print_event, +	.process_event		= process_event,  	.generate_script	= default_generate_script,  }; @@ -75,26 +254,17 @@ static int process_sample_event(union perf_event *event,  		return -1;  	} -	if (session->sample_type & PERF_SAMPLE_RAW) { -		if (debug_mode) { -			if (sample->time < last_timestamp) { -				pr_err("Samples misordered, previous: %" PRIu64 -					" this: %" PRIu64 "\n", last_timestamp, -					sample->time); -				nr_unordered++; -			} -			last_timestamp = sample->time; -			return 0; +	if (debug_mode) { +		if (sample->time < last_timestamp) { +			pr_err("Samples misordered, previous: %" PRIu64 +				" this: %" PRIu64 "\n", last_timestamp, +				sample->time); +			nr_unordered++;  		} -		/* -		 * FIXME: better resolve from pid from the struct trace_entry -		 * field, although it should be the same than this perf -		 * event pid -		 */ -		scripting_ops->process_event(sample->cpu, sample->raw_data, -					     sample->raw_size, -					     sample->time, thread->comm); +		last_timestamp = sample->time; +		return 0;  	} +	scripting_ops->process_event(event, sample, session, thread);  	session->hists.stats.total_period += sample->period;  	return 0; @@ -102,7 +272,10 @@ static int process_sample_event(union perf_event *event,  static struct perf_event_ops event_ops = {  	.sample		 = process_sample_event, +	.mmap		 = perf_event__process_mmap,  	.comm		 = perf_event__process_comm, +	.exit		 = perf_event__process_task, +	.fork		 = perf_event__process_task,  	.attr		 = perf_event__process_attr,  	.event_type	 = perf_event__process_event_type,  	.tracing_data	 = perf_event__process_tracing_data, @@ -280,6 +453,68 @@ static int parse_scriptname(const struct option *opt __used,  	return 0;  } +static int parse_output_fields(const struct option *opt __used, +			    const char *arg, int unset __used) +{ +	char *tok; +	int i, imax = sizeof(all_output_options) / sizeof(struct output_option); +	int rc = 0; +	char *str = strdup(arg); +	int type = -1; + +	if (!str) +		return -ENOMEM; + +	tok = strtok(str, ":"); +	if (!tok) { +		fprintf(stderr, +			"Invalid field string - not prepended with type."); +		return -EINVAL; +	} + +	/* first word should state which event type user +	 * is specifying the fields +	 */ +	if (!strcmp(tok, "hw")) +		type = PERF_TYPE_HARDWARE; +	else if (!strcmp(tok, "sw")) +		type = PERF_TYPE_SOFTWARE; +	else if (!strcmp(tok, "trace")) +		type = PERF_TYPE_TRACEPOINT; +	else { +		fprintf(stderr, "Invalid event type in field string."); +		return -EINVAL; +	} + +	output_fields[type] = 0; +	while (1) { +		tok = strtok(NULL, ","); +		if (!tok) +			break; +		for (i = 0; i < imax; ++i) { +			if (strcmp(tok, all_output_options[i].str) == 0) { +				output_fields[type] |= all_output_options[i].field; +				break; +			} +		} +		if (i == imax) { +			fprintf(stderr, "Invalid field requested."); +			rc = -EINVAL; +			break; +		} +	} + +	if (output_fields[type] == 0) { +		pr_debug("No fields requested for %s type. " +			 "Events will not be displayed\n", event_type(type)); +	} + +	output_set_by_user = true; + +	free(str); +	return rc; +} +  /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */  static int is_directory(const char *base_path, const struct dirent *dent)  { @@ -592,6 +827,17 @@ static const struct option options[] = {  		    "input file name"),  	OPT_BOOLEAN('d', "debug-mode", &debug_mode,  		   "do various checks like samples ordering and lost events"), +	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, +		   "file", "vmlinux pathname"), +	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, +		   "file", "kallsyms pathname"), +	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, +		    "When printing symbols do not display call chain"), +	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", +		    "Look for files with symbols relative to this directory"), +	OPT_CALLBACK('f', "fields", NULL, "str", +		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym", +		     parse_output_fields),  	OPT_END()  }; @@ -772,14 +1018,22 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)  	if (session == NULL)  		return -ENOMEM; -	if (strcmp(input_name, "-") && -	    !perf_session__has_traces(session, "record -R")) -		return -EINVAL; +	if (!no_callchain) +		symbol_conf.use_callchain = true; +	else +		symbol_conf.use_callchain = false;  	if (generate_script_lang) {  		struct stat perf_stat; +		int input; + +		if (output_set_by_user) { +			fprintf(stderr, +				"custom fields not supported for generated scripts"); +			return -1; +		} -		int input = open(input_name, O_RDONLY); +		input = open(input_name, O_RDONLY);  		if (input < 0) {  			perror("failed to open file");  			exit(-1); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 21c025222496..e2109f9b43eb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -333,6 +333,12 @@ static int run_perf_stat(int argc __used, const char **argv)  		}  	} +	if (perf_evlist__set_filters(evsel_list)) { +		error("failed to set filter with %d (%s)\n", errno, +			strerror(errno)); +		return -1; +	} +  	/*  	 * Enable counters and exec the command:  	 */ @@ -634,6 +640,8 @@ static const struct option options[] = {  	OPT_CALLBACK('e', "event", &evsel_list, "event",  		     "event selector. use 'perf list' to list available events",  		     parse_events), +	OPT_CALLBACK(0, "filter", &evsel_list, "filter", +		     "event filter", parse_filter),  	OPT_BOOLEAN('i', "no-inherit", &no_inherit,  		    "child tasks do not inherit counters"),  	OPT_INTEGER('p', "pid", &target_pid, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 80c9e062bd5b..70f1075cc5b0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -152,7 +152,7 @@ static int parse_source(struct sym_entry *syme)  	/*  	 * We can't annotate with just /proc/kallsyms  	 */ -	if (map->dso->origin == DSO__ORIG_KERNEL) { +	if (map->dso->symtab_type == SYMTAB__KALLSYMS) {  		pr_err("Can't annotate %s: No vmlinux file was found in the "  		       "path\n", sym->name);  		sleep(1); @@ -515,24 +515,25 @@ static void handle_keypress(struct perf_session *session, int c)  			break;  		case 'E':  			if (top.evlist->nr_entries > 1) { +				int counter;  				fprintf(stderr, "\nAvailable events:");  				list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)  					fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); -				prompt_integer(&top.sym_counter, "Enter details event counter"); +				prompt_integer(&counter, "Enter details event counter"); -				if (top.sym_counter >= top.evlist->nr_entries) { +				if (counter >= top.evlist->nr_entries) {  					top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); -					top.sym_counter = 0;  					fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));  					sleep(1);  					break;  				}  				list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) -					if (top.sym_evsel->idx == top.sym_counter) +					if (top.sym_evsel->idx == counter)  						break; -			} else top.sym_counter = 0; +			} else +				top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);  			break;  		case 'f':  			prompt_integer(&top.count_filter, "Enter display event count filter"); @@ -675,7 +676,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)  	for (i = 0; skip_symbols[i]; i++) {  		if (!strcmp(skip_symbols[i], name)) { -			syme->skip = 1; +			sym->ignore = true;  			break;  		}  	} @@ -768,7 +769,7 @@ static void perf_event__process_sample(const union perf_event *event,  			struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);  			pr_err("Can't annotate %s", sym->name); -			if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { +			if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {  				pr_err(": No vmlinux file was found in the path:\n");  				machine__fprintf_vmlinux_path(machine, stderr);  			} else @@ -778,10 +779,9 @@ static void perf_event__process_sample(const union perf_event *event,  	}  	syme = symbol__priv(al.sym); -	if (!syme->skip) { +	if (!al.sym->ignore) {  		struct perf_evsel *evsel; -		syme->origin = origin;  		evsel = perf_evlist__id2evsel(top.evlist, sample->id);  		assert(evsel != NULL);  		syme->count[evsel->idx]++; diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index c7798c7f24ed..4702e2443a8e 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -19,6 +19,7 @@ extern int cmd_bench(int argc, const char **argv, const char *prefix);  extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);  extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);  extern int cmd_diff(int argc, const char **argv, const char *prefix); +extern int cmd_evlist(int argc, const char **argv, const char *prefix);  extern int cmd_help(int argc, const char **argv, const char *prefix);  extern int cmd_sched(int argc, const char **argv, const char *prefix);  extern int cmd_list(int argc, const char **argv, const char *prefix); diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 16b5088cf8f4..d695fe40fbff 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -8,6 +8,7 @@ perf-bench			mainporcelain common  perf-buildid-cache		mainporcelain common  perf-buildid-list		mainporcelain common  perf-diff			mainporcelain common +perf-evlist			mainporcelain common  perf-inject			mainporcelain common  perf-list			mainporcelain common  perf-sched			mainporcelain common diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 595d0f4a7103..ec635b7cc8ea 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -313,6 +313,7 @@ static void handle_internal_command(int argc, const char **argv)  		{ "buildid-cache", cmd_buildid_cache, 0 },  		{ "buildid-list", cmd_buildid_list, 0 },  		{ "diff",	cmd_diff,	0 }, +		{ "evlist",	cmd_evlist,	0 },  		{ "help",	cmd_help,	0 },  		{ "list",	cmd_list,	0 },  		{ "record",	cmd_record,	0 }, diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0d0830c98cd7..e01af2b1a469 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -294,7 +294,7 @@ fallback:  		free_filename = false;  	} -	if (dso->origin == DSO__ORIG_KERNEL) { +	if (dso->symtab_type == SYMTAB__KALLSYMS) {  		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";  		char *build_id_msg = NULL; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 54a7e2634d58..952b4ae3d954 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -263,6 +263,28 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)  	return name;  } +const char *event_type(int type) +{ +	switch (type) { +	case PERF_TYPE_HARDWARE: +		return "hardware"; + +	case PERF_TYPE_SOFTWARE: +		return "software"; + +	case PERF_TYPE_TRACEPOINT: +		return "tracepoint"; + +	case PERF_TYPE_HW_CACHE: +		return "hardware-cache"; + +	default: +		break; +	} + +	return "unknown"; +} +  const char *event_name(struct perf_evsel *evsel)  {  	u64 config = evsel->attr.config; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 212f88e07a9c..746d3fcbfc2a 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -20,6 +20,7 @@ struct tracepoint_path {  extern struct tracepoint_path *tracepoint_id_to_path(u64 config);  extern bool have_tracepoints(struct list_head *evlist); +const char *event_type(int type);  const char *event_name(struct perf_evsel *event);  extern const char *__event_name(int type, u64 config); diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 93680818e244..621427212e86 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -245,9 +245,10 @@ static inline struct event *find_cache_event(int type)  	return event;  } -static void perl_process_event(int cpu, void *data, -			       int size __unused, -			       unsigned long long nsecs, char *comm) +static void perl_process_event(union perf_event *pevent __unused, +			       struct perf_sample *sample, +			       struct perf_session *session __unused, +			       struct thread *thread)  {  	struct format_field *field;  	static char handler[256]; @@ -256,6 +257,10 @@ static void perl_process_event(int cpu, void *data,  	struct event *event;  	int type;  	int pid; +	int cpu = sample->cpu; +	void *data = sample->raw_data; +	unsigned long long nsecs = sample->time; +	char *comm = thread->comm;  	dSP; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 2040b8538527..1b85d6055159 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -204,9 +204,10 @@ static inline struct event *find_cache_event(int type)  	return event;  } -static void python_process_event(int cpu, void *data, -				 int size __unused, -				 unsigned long long nsecs, char *comm) +static void python_process_event(union perf_event *pevent __unused, +				 struct perf_sample *sample, +				 struct perf_session *session __unused, +				 struct thread *thread)  {  	PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;  	static char handler_name[256]; @@ -217,6 +218,10 @@ static void python_process_event(int cpu, void *data,  	unsigned n = 0;  	int type;  	int pid; +	int cpu = sample->cpu; +	void *data = sample->raw_data; +	unsigned long long nsecs = sample->time; +	char *comm = thread->comm;  	t = PyTuple_New(MAX_FIELDS);  	if (!t) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f26639fa0fb3..c68cf40764f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)  	return ret;  } + +void perf_session__print_symbols(union perf_event *event, +				struct perf_sample *sample, +				struct perf_session *session) +{ +	struct addr_location al; +	const char *symname, *dsoname; +	struct callchain_cursor *cursor = &session->callchain_cursor; +	struct callchain_cursor_node *node; + +	if (perf_event__preprocess_sample(event, session, &al, sample, +					  NULL) < 0) { +		error("problem processing %d event, skipping it.\n", +			event->header.type); +		return; +	} + +	if (symbol_conf.use_callchain && sample->callchain) { + +		if (perf_session__resolve_callchain(session, al.thread, +						sample->callchain, NULL) != 0) { +			if (verbose) +				error("Failed to resolve callchain. Skipping\n"); +			return; +		} +		callchain_cursor_commit(cursor); + +		while (1) { +			node = callchain_cursor_current(cursor); +			if (!node) +				break; + +			if (node->sym && node->sym->name) +				symname = node->sym->name; +			else +				symname = ""; + +			if (node->map && node->map->dso && node->map->dso->name) +				dsoname = node->map->dso->name; +			else +				dsoname = ""; + +			printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname); + +			callchain_cursor_advance(cursor); +		} + +	} else { +		if (al.sym && al.sym->name) +			symname = al.sym->name; +		else +			symname = ""; + +		if (al.map && al.map->dso && al.map->dso->name) +			dsoname = al.map->dso->name; +		else +			dsoname = ""; + +		printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname); +	} +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b5b148b0aaca..0b3c9afecaa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,  					session->sample_id_all, sample);  } +void perf_session__print_symbols(union perf_event *event, +				 struct perf_sample *sample, +				 struct perf_session *session); +  #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 00014e32c288..651dbfe7f4f3 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -207,7 +207,7 @@ struct dso *dso__new(const char *name)  		dso__set_short_name(self, self->name);  		for (i = 0; i < MAP__NR_TYPES; ++i)  			self->symbols[i] = self->symbol_names[i] = RB_ROOT; -		self->origin = DSO__ORIG_NOT_FOUND; +		self->symtab_type = SYMTAB__NOT_FOUND;  		self->loaded = 0;  		self->sorted_by_name = 0;  		self->has_build_id = 0; @@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename,  		return -1;  	if (self->kernel == DSO_TYPE_GUEST_KERNEL) -		self->origin = DSO__ORIG_GUEST_KERNEL; +		self->symtab_type = SYMTAB__GUEST_KALLSYMS;  	else -		self->origin = DSO__ORIG_KERNEL; +		self->symtab_type = SYMTAB__KALLSYMS;  	return dso__split_kallsyms(self, map, filter);  } @@ -1204,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,  				}  				curr_map->map_ip = identity__map_ip;  				curr_map->unmap_ip = identity__map_ip; -				curr_dso->origin = self->origin; +				curr_dso->symtab_type = self->symtab_type;  				map_groups__insert(kmap->kmaps, curr_map);  				dsos__add(&self->node, curr_dso);  				dso__set_loaded(curr_dso, map->type); @@ -1430,21 +1430,21 @@ out:  char dso__symtab_origin(const struct dso *self)  {  	static const char origin[] = { -		[DSO__ORIG_KERNEL] =   'k', -		[DSO__ORIG_JAVA_JIT] = 'j', -		[DSO__ORIG_BUILD_ID_CACHE] = 'B', -		[DSO__ORIG_FEDORA] =   'f', -		[DSO__ORIG_UBUNTU] =   'u', -		[DSO__ORIG_BUILDID] =  'b', -		[DSO__ORIG_DSO] =      'd', -		[DSO__ORIG_KMODULE] =  'K', -		[DSO__ORIG_GUEST_KERNEL] =  'g', -		[DSO__ORIG_GUEST_KMODULE] =  'G', +		[SYMTAB__KALLSYMS]	      = 'k', +		[SYMTAB__JAVA_JIT]	      = 'j', +		[SYMTAB__BUILD_ID_CACHE]      = 'B', +		[SYMTAB__FEDORA_DEBUGINFO]    = 'f', +		[SYMTAB__UBUNTU_DEBUGINFO]    = 'u', +		[SYMTAB__BUILDID_DEBUGINFO]   = 'b', +		[SYMTAB__SYSTEM_PATH_DSO]     = 'd', +		[SYMTAB__SYSTEM_PATH_KMODULE] = 'K', +		[SYMTAB__GUEST_KALLSYMS]      =  'g', +		[SYMTAB__GUEST_KMODULE]	      =  'G',  	}; -	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) +	if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)  		return '!'; -	return origin[self->origin]; +	return origin[self->symtab_type];  }  int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) @@ -1477,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)  	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {  		ret = dso__load_perf_map(self, map, filter); -		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : -					 DSO__ORIG_NOT_FOUND; +		self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : +					      SYMTAB__NOT_FOUND;  		return ret;  	} @@ -1486,26 +1486,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)  	 * On the first pass, only load images if they have a full symtab.  	 * Failing that, do a second pass where we accept .dynsym also  	 */ -	for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; -	     self->origin != DSO__ORIG_NOT_FOUND; -	     self->origin++) { -		switch (self->origin) { -		case DSO__ORIG_BUILD_ID_CACHE: +	for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; +	     self->symtab_type != SYMTAB__NOT_FOUND; +	     self->symtab_type++) { +		switch (self->symtab_type) { +		case SYMTAB__BUILD_ID_CACHE:  			/* skip the locally configured cache if a symfs is given */  			if (symbol_conf.symfs[0] ||  			    (dso__build_id_filename(self, name, size) == NULL)) {  				continue;  			}  			break; -		case DSO__ORIG_FEDORA: +		case SYMTAB__FEDORA_DEBUGINFO:  			snprintf(name, size, "%s/usr/lib/debug%s.debug",  				 symbol_conf.symfs, self->long_name);  			break; -		case DSO__ORIG_UBUNTU: +		case SYMTAB__UBUNTU_DEBUGINFO:  			snprintf(name, size, "%s/usr/lib/debug%s",  				 symbol_conf.symfs, self->long_name);  			break; -		case DSO__ORIG_BUILDID: { +		case SYMTAB__BUILDID_DEBUGINFO: {  			char build_id_hex[BUILD_ID_SIZE * 2 + 1];  			if (!self->has_build_id) @@ -1519,11 +1519,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)  				 symbol_conf.symfs, build_id_hex, build_id_hex + 2);  			}  			break; -		case DSO__ORIG_DSO: +		case SYMTAB__SYSTEM_PATH_DSO:  			snprintf(name, size, "%s%s",  			     symbol_conf.symfs, self->long_name);  			break; -		case DSO__ORIG_GUEST_KMODULE: +		case SYMTAB__GUEST_KMODULE:  			if (map->groups && machine)  				root_dir = machine->root_dir;  			else @@ -1532,7 +1532,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)  				 root_dir, self->long_name);  			break; -		case DSO__ORIG_KMODULE: +		case SYMTAB__SYSTEM_PATH_KMODULE:  			snprintf(name, size, "%s%s", symbol_conf.symfs,  				 self->long_name);  			break; @@ -1544,7 +1544,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)  			 */  			if (want_symtab) {  				want_symtab = 0; -				self->origin = DSO__ORIG_BUILD_ID_CACHE; +				self->symtab_type = SYMTAB__BUILD_ID_CACHE;  			} else  				continue;  		} @@ -1757,9 +1757,9 @@ struct map *machine__new_module(struct machine *self, u64 start,  		return NULL;  	if (machine__is_host(self)) -		dso->origin = DSO__ORIG_KMODULE; +		dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;  	else -		dso->origin = DSO__ORIG_GUEST_KMODULE; +		dso->symtab_type = SYMTAB__GUEST_KMODULE;  	map_groups__insert(&self->kmaps, map);  	return map;  } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 4d7ed09fe332..713b0b40cc4a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -48,12 +48,17 @@ char *strxfrchar(char *s, char from, char to);  #define BUILD_ID_SIZE 20 +/** struct symbol - symtab entry + * + * @ignore - resolvable but tools ignore it (e.g. idle routines) + */  struct symbol {  	struct rb_node	rb_node;  	u64		start;  	u64		end;  	u16		namelen;  	u8		binding; +	bool		ignore;  	char		name[0];  }; @@ -137,7 +142,7 @@ struct dso {  	u8		 annotate_warned:1;  	u8		 sname_alloc:1;  	u8		 lname_alloc:1; -	unsigned char	 origin; +	unsigned char	 symtab_type;  	u8		 sorted_by_name;  	u8		 loaded;  	u8		 build_id[BUILD_ID_SIZE]; @@ -188,18 +193,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);  size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp);  size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); -enum dso_origin { -	DSO__ORIG_KERNEL = 0, -	DSO__ORIG_GUEST_KERNEL, -	DSO__ORIG_JAVA_JIT, -	DSO__ORIG_BUILD_ID_CACHE, -	DSO__ORIG_FEDORA, -	DSO__ORIG_UBUNTU, -	DSO__ORIG_BUILDID, -	DSO__ORIG_DSO, -	DSO__ORIG_GUEST_KMODULE, -	DSO__ORIG_KMODULE, -	DSO__ORIG_NOT_FOUND, +enum symtab_type { +	SYMTAB__KALLSYMS = 0, +	SYMTAB__GUEST_KALLSYMS, +	SYMTAB__JAVA_JIT, +	SYMTAB__BUILD_ID_CACHE, +	SYMTAB__FEDORA_DEBUGINFO, +	SYMTAB__UBUNTU_DEBUGINFO, +	SYMTAB__BUILDID_DEBUGINFO, +	SYMTAB__SYSTEM_PATH_DSO, +	SYMTAB__GUEST_KMODULE, +	SYMTAB__SYSTEM_PATH_KMODULE, +	SYMTAB__NOT_FOUND,  };  char dso__symtab_origin(const struct dso *self); diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 75cfe4d45119..a11f60735a18 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -171,7 +171,7 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)  {  	struct sym_entry *syme, *n;  	float sum_ksamples = 0.0; -	int snap = !top->display_weighted ? top->sym_counter : 0, j; +	int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;  	/* Sort the active symbols */  	pthread_mutex_lock(&top->active_symbols_lock); @@ -184,9 +184,9 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)  		if (syme->snap_count != 0) {  			if ((top->hide_user_symbols && -			     syme->origin == PERF_RECORD_MISC_USER) || +			     syme->map->dso->kernel == DSO_TYPE_USER) ||  			    (top->hide_kernel_symbols && -			     syme->origin == PERF_RECORD_MISC_KERNEL)) { +			     syme->map->dso->kernel == DSO_TYPE_KERNEL)) {  				perf_top__remove_active_sym(top, syme);  				continue;  			} diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 96d1cb78af01..bfbf95bcc603 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -16,8 +16,6 @@ struct sym_entry {  	struct list_head	node;  	unsigned long		snap_count;  	double			weight; -	int			skip; -	u8			origin;  	struct map		*map;  	unsigned long		count[0];  }; @@ -41,7 +39,7 @@ struct perf_top {  	u64		   exact_samples;  	u64		   guest_us_samples, guest_kernel_samples;  	int		   print_entries, count_filter, delay_secs; -	int		   display_weighted, freq, rb_entries, sym_counter; +	int		   display_weighted, freq, rb_entries;  	pid_t		   target_pid, target_tid;  	bool		   hide_kernel_symbols, hide_user_symbols, zero;  	const char	   *cpu_list; diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index d8e622dd738a..0a7ed5b5e281 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2643,68 +2643,13 @@ static void print_lat_fmt(void *data, int size __unused)  		printf(".");  	if (lock_depth < 0) -		printf("."); +		printf(". ");  	else -		printf("%d", lock_depth); +		printf("%d ", lock_depth);  } -/* taken from Linux, written by Frederic Weisbecker */ -static void print_graph_cpu(int cpu) -{ -	int i; -	int log10_this = log10_cpu(cpu); -	int log10_all = log10_cpu(cpus); - - -	/* -	 * Start with a space character - to make it stand out -	 * to the right a bit when trace output is pasted into -	 * email: -	 */ -	printf(" "); - -	/* -	 * Tricky - we space the CPU field according to the max -	 * number of online CPUs. On a 2-cpu system it would take -	 * a maximum of 1 digit - on a 128 cpu system it would -	 * take up to 3 digits: -	 */ -	for (i = 0; i < log10_all - log10_this; i++) -		printf(" "); - -	printf("%d) ", cpu); -} - -#define TRACE_GRAPH_PROCINFO_LENGTH	14  #define TRACE_GRAPH_INDENT	2 -static void print_graph_proc(int pid, const char *comm) -{ -	/* sign + log10(MAX_INT) + '\0' */ -	char pid_str[11]; -	int spaces = 0; -	int len; -	int i; - -	sprintf(pid_str, "%d", pid); - -	/* 1 stands for the "-" character */ -	len = strlen(comm) + strlen(pid_str) + 1; - -	if (len < TRACE_GRAPH_PROCINFO_LENGTH) -		spaces = TRACE_GRAPH_PROCINFO_LENGTH - len; - -	/* First spaces to align center */ -	for (i = 0; i < spaces / 2; i++) -		printf(" "); - -	printf("%s-%s", comm, pid_str); - -	/* Last spaces to align center */ -	for (i = 0; i < spaces - (spaces / 2); i++) -		printf(" "); -} -  static struct record *  get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,  		    struct record *next) @@ -2876,21 +2821,13 @@ static void print_graph_nested(struct event *event, void *data)  static void  pretty_print_func_ent(void *data, int size, struct event *event, -		      int cpu, int pid, const char *comm, -		      unsigned long secs, unsigned long usecs) +		      int cpu, int pid)  {  	struct format_field *field;  	struct record *rec;  	void *copy_data;  	unsigned long val; -	printf("%5lu.%06lu |  ", secs, usecs); - -	print_graph_cpu(cpu); -	print_graph_proc(pid, comm); - -	printf(" | "); -  	if (latency_format) {  		print_lat_fmt(data, size);  		printf(" | "); @@ -2923,22 +2860,13 @@ out_free:  }  static void -pretty_print_func_ret(void *data, int size __unused, struct event *event, -		      int cpu, int pid, const char *comm, -		      unsigned long secs, unsigned long usecs) +pretty_print_func_ret(void *data, int size __unused, struct event *event)  {  	unsigned long long rettime, calltime;  	unsigned long long duration, depth;  	struct format_field *field;  	int i; -	printf("%5lu.%06lu |  ", secs, usecs); - -	print_graph_cpu(cpu); -	print_graph_proc(pid, comm); - -	printf(" | "); -  	if (latency_format) {  		print_lat_fmt(data, size);  		printf(" | "); @@ -2976,31 +2904,21 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,  static void  pretty_print_func_graph(void *data, int size, struct event *event, -			int cpu, int pid, const char *comm, -			unsigned long secs, unsigned long usecs) +			int cpu, int pid)  {  	if (event->flags & EVENT_FL_ISFUNCENT) -		pretty_print_func_ent(data, size, event, -				      cpu, pid, comm, secs, usecs); +		pretty_print_func_ent(data, size, event, cpu, pid);  	else if (event->flags & EVENT_FL_ISFUNCRET) -		pretty_print_func_ret(data, size, event, -				      cpu, pid, comm, secs, usecs); +		pretty_print_func_ret(data, size, event);  	printf("\n");  } -void print_event(int cpu, void *data, int size, unsigned long long nsecs, -		  char *comm) +void print_trace_event(int cpu, void *data, int size)  {  	struct event *event; -	unsigned long secs; -	unsigned long usecs;  	int type;  	int pid; -	secs = nsecs / NSECS_PER_SEC; -	nsecs -= secs * NSECS_PER_SEC; -	usecs = nsecs / NSECS_PER_USEC; -  	type = trace_parse_common_type(data);  	event = trace_find_event(type); @@ -3012,17 +2930,10 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,  	pid = trace_parse_common_pid(data);  	if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) -		return pretty_print_func_graph(data, size, event, cpu, -					       pid, comm, secs, usecs); +		return pretty_print_func_graph(data, size, event, cpu, pid); -	if (latency_format) { -		printf("%8.8s-%-5d %3d", -		       comm, pid, cpu); +	if (latency_format)  		print_lat_fmt(data, size); -	} else -		printf("%16s-%-5d [%03d]", comm, pid,  cpu); - -	printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);  	if (event->flags & EVENT_FL_FAILED) {  		printf("EVENT '%s' FAILED TO PARSE\n", @@ -3031,7 +2942,6 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,  	}  	pretty_print(data, size, event); -	printf("\n");  }  static void print_fields(struct print_flag_sym *field) diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index f7af2fca965d..66f4b78737ab 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -36,11 +36,10 @@ static int stop_script_unsupported(void)  	return 0;  } -static void process_event_unsupported(int cpu __unused, -				      void *data __unused, -				      int size __unused, -				      unsigned long long nsecs __unused, -				      char *comm __unused) +static void process_event_unsupported(union perf_event *event __unused, +				      struct perf_sample *sample __unused, +				      struct perf_session *session __unused, +				      struct thread *thread __unused)  {  } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b5f12ca24d99..b04da5722437 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -3,6 +3,7 @@  #include <stdbool.h>  #include "parse-events.h" +#include "session.h"  #define __unused __attribute__((unused)) @@ -176,8 +177,7 @@ void print_printk(void);  int parse_ftrace_file(char *buf, unsigned long size);  int parse_event_file(char *buf, unsigned long size, char *sys); -void print_event(int cpu, void *data, int size, unsigned long long nsecs, -		  char *comm); +void print_trace_event(int cpu, void *data, int size);  extern int file_bigendian;  extern int host_bigendian; @@ -278,8 +278,10 @@ struct scripting_ops {  	const char *name;  	int (*start_script) (const char *script, int argc, const char **argv);  	int (*stop_script) (void); -	void (*process_event) (int cpu, void *data, int size, -			       unsigned long long nsecs, char *comm); +	void (*process_event) (union perf_event *event, +			       struct perf_sample *sample, +			       struct perf_session *session, +			       struct thread *thread);  	int (*generate_script) (const char *outfile);  }; | 
