diff options
Diffstat (limited to 'tools/perf')
74 files changed, 3556 insertions, 4835 deletions
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 0507ec7bad7..15217345c2f 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt @@ -20,6 +20,14 @@ OPTIONS  --input=::          Input file name. (default: perf.data unless stdin is a fifo) +-F:: +--freq=:: +	Show just the sample frequency used for each event. + +-v:: +--verbose=:: +	Show all fields. +  SEE ALSO  --------  linkperf:perf-record[1], linkperf:perf-list[1], diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a1386b2fff0..b38a1f9ad46 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -168,7 +168,7 @@ following filters are defined:          - any:  any type of branches          - any_call: any function call or system call          - any_ret: any function return or system call return -        - any_ind: any indirect branch +        - ind_call: any indirect branch          - u:  only when the branch target is at the user level          - k: only when the branch target is in the kernel          - hv: only when the target is at the hypervisor level diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example index d1448668f4d..42c6fd2ae85 100644 --- a/tools/perf/Documentation/perfconfig.example +++ b/tools/perf/Documentation/perfconfig.example @@ -6,6 +6,7 @@  	normal = black, lightgray  	selected = lightgray, magenta  	code = blue, lightgray +	addr = magenta, lightgray  [tui] diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 92271d32bc3..1d3d513beb9 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -1,18 +1,10 @@ -ifeq ("$(origin O)", "command line") -	OUTPUT := $(O)/ -endif +include ../scripts/Makefile.include  # The default target of this Makefile is...  all:  include config/utilities.mak -ifneq ($(OUTPUT),) -# check that the output directory actually exists -OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) -$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) -endif -  # Define V to have a more verbose compile.  #  # Define O to save output files in a separate directory. @@ -84,31 +76,6 @@ ifneq ($(WERROR),0)  	CFLAGS_WERROR := -Werror  endif -# -# Include saner warnings here, which can catch bugs: -# - -EXTRA_WARNINGS := -Wformat -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes -EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement -  ifeq ("$(origin DEBUG)", "command line")    PERF_DEBUG = $(DEBUG)  endif @@ -116,7 +83,13 @@ ifndef PERF_DEBUG    CFLAGS_OPTIMIZE = -O6  endif -CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) +ifdef PARSER_DEBUG +	PARSER_DEBUG_BISON  := -t +	PARSER_DEBUG_FLEX   := -d +	PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG +endif + +CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)  EXTLIBS = -lpthread -lrt -lelf -lm  ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE  ALL_LDFLAGS = $(LDFLAGS) @@ -182,7 +155,7 @@ endif  ### --- END CONFIGURATION SECTION --- -BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE  BASIC_LDFLAGS =  # Guard against environment variables @@ -211,6 +184,17 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) +TRACE_EVENT_DIR = ../lib/traceevent/ + +ifeq ("$(origin O)", "command line") +	TE_PATH=$(OUTPUT)/ +else +	TE_PATH=$(TRACE_EVENT_DIR)/ +endif + +LIBTRACEEVENT = $(TE_PATH)libtraceevent.a +TE_LIB := -L$(TE_PATH) -ltraceevent +  #  # Single 'perf' binary right now:  # @@ -238,10 +222,10 @@ FLEX = flex  BISON= bison  $(OUTPUT)util/parse-events-flex.c: util/parse-events.l -	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c +	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c  $(OUTPUT)util/parse-events-bison.c: util/parse-events.y -	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c +	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c  $(OUTPUT)util/pmu-flex.c: util/pmu.l  	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c @@ -333,6 +317,8 @@ LIB_H += util/cpumap.h  LIB_H += util/top.h  LIB_H += $(ARCH_INCLUDE)  LIB_H += util/cgroup.h +LIB_H += $(TRACE_EVENT_DIR)event-parse.h +LIB_H += util/target.h  LIB_OBJS += $(OUTPUT)util/abspath.o  LIB_OBJS += $(OUTPUT)util/alias.o @@ -352,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/help.o  LIB_OBJS += $(OUTPUT)util/levenshtein.o  LIB_OBJS += $(OUTPUT)util/parse-options.o  LIB_OBJS += $(OUTPUT)util/parse-events.o +LIB_OBJS += $(OUTPUT)util/parse-events-test.o  LIB_OBJS += $(OUTPUT)util/path.o  LIB_OBJS += $(OUTPUT)util/rbtree.o  LIB_OBJS += $(OUTPUT)util/bitmap.o @@ -394,6 +381,7 @@ LIB_OBJS += $(OUTPUT)util/util.o  LIB_OBJS += $(OUTPUT)util/xyarray.o  LIB_OBJS += $(OUTPUT)util/cpumap.o  LIB_OBJS += $(OUTPUT)util/cgroup.o +LIB_OBJS += $(OUTPUT)util/target.o  BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o @@ -429,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o  BUILTIN_OBJS += $(OUTPUT)builtin-test.o  BUILTIN_OBJS += $(OUTPUT)builtin-inject.o -PERFLIBS = $(LIB_FILE) +PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)  # Files needed for the python binding, perf.so  # pyrf is just an internal name needed for all those wrappers. @@ -506,22 +494,23 @@ else  		# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h  		BASIC_CFLAGS += -I/usr/include/slang  		EXTLIBS += -lnewt -lslang -		LIB_OBJS += $(OUTPUT)util/ui/setup.o -		LIB_OBJS += $(OUTPUT)util/ui/browser.o -		LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o -		LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o -		LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o -		LIB_OBJS += $(OUTPUT)util/ui/helpline.o -		LIB_OBJS += $(OUTPUT)util/ui/progress.o -		LIB_OBJS += $(OUTPUT)util/ui/util.o -		LIB_H += util/ui/browser.h -		LIB_H += util/ui/browsers/map.h -		LIB_H += util/ui/helpline.h -		LIB_H += util/ui/keysyms.h -		LIB_H += util/ui/libslang.h -		LIB_H += util/ui/progress.h -		LIB_H += util/ui/util.h -		LIB_H += util/ui/ui.h +		LIB_OBJS += $(OUTPUT)ui/setup.o +		LIB_OBJS += $(OUTPUT)ui/browser.o +		LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o +		LIB_OBJS += $(OUTPUT)ui/browsers/hists.o +		LIB_OBJS += $(OUTPUT)ui/browsers/map.o +		LIB_OBJS += $(OUTPUT)ui/helpline.o +		LIB_OBJS += $(OUTPUT)ui/progress.o +		LIB_OBJS += $(OUTPUT)ui/util.o +		LIB_OBJS += $(OUTPUT)ui/tui/setup.o +		LIB_H += ui/browser.h +		LIB_H += ui/browsers/map.h +		LIB_H += ui/helpline.h +		LIB_H += ui/keysyms.h +		LIB_H += ui/libslang.h +		LIB_H += ui/progress.h +		LIB_H += ui/util.h +		LIB_H += ui/ui.h  	endif  endif @@ -535,7 +524,12 @@ else  	else  		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)  		EXTLIBS += $(shell pkg-config --libs gtk+-2.0) -		LIB_OBJS += $(OUTPUT)util/gtk/browser.o +		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o +		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o +		# Make sure that it'd be included only once. +		ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) +			LIB_OBJS += $(OUTPUT)ui/setup.o +		endif  	endif  endif @@ -678,18 +672,6 @@ else  	endif  endif -ifneq ($(findstring $(MAKEFLAGS),s),s) -ifndef V -	QUIET_CC       = @echo '   ' CC $@; -	QUIET_AR       = @echo '   ' AR $@; -	QUIET_LINK     = @echo '   ' LINK $@; -	QUIET_MKDIR    = @echo '   ' MKDIR $@; -	QUIET_GEN      = @echo '   ' GEN $@; -	QUIET_FLEX     = @echo '   ' FLEX $@; -	QUIET_BISON    = @echo '   ' BISON $@; -endif -endif -  ifdef ASCIIDOC8  	export ASCIIDOC8  endif @@ -800,16 +782,16 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS  $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< -$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS +$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< -$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS +$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< -$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS +$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< -$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS +$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<  $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS @@ -844,6 +826,10 @@ $(sort $(dir $(DIRECTORY_DEPS))):  $(LIB_FILE): $(LIB_OBJS)  	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) +# libtraceevent.a +$(LIBTRACEEVENT): +	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a +  help:  	@echo 'Perf make targets:'  	@echo '  doc		- make *all* documentation (see below)' @@ -990,6 +976,6 @@ clean:  	$(RM) $(OUTPUT)util/*-{bison,flex}*  	$(python-clean) -.PHONY: all install clean strip +.PHONY: all install clean strip $(LIBTRACEEVENT)  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell  .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 52480467e9f..6b2bcfbde15 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void)  	if (filename__fprintf_build_id(session->filename, stdout))  		goto out; -	if (with_hits) +	/* +	 * in pipe-mode, the only way to get the buildids is to parse +	 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID +	 */ +	if (with_hits || session->fd_pipe)  		perf_session__process_events(session, &build_id__mark_dso_hit_ops);  	perf_session__fprintf_dsos_buildid(session, stdout, with_hits); diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 26760322c4f..e52d77ec708 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -15,9 +15,40 @@  #include "util/parse-options.h"  #include "util/session.h" -static const char *input_name; +struct perf_attr_details { +	bool freq; +	bool verbose; +}; + +static int comma_printf(bool *first, const char *fmt, ...) +{ +	va_list args; +	int ret = 0; + +	if (!*first) { +		ret += printf(","); +	} else { +		ret += printf(":"); +		*first = false; +	} + +	va_start(args, fmt); +	ret += vprintf(fmt, args); +	va_end(args); +	return ret; +} + +static int __if_print(bool *first, const char *field, u64 value) +{ +	if (value == 0) +		return 0; + +	return comma_printf(first, " %s: %" PRIu64, field, value); +} + +#define if_print(field) __if_print(&first, #field, pos->attr.field) -static int __cmd_evlist(void) +static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)  {  	struct perf_session *session;  	struct perf_evsel *pos; @@ -26,8 +57,52 @@ static int __cmd_evlist(void)  	if (session == NULL)  		return -ENOMEM; -	list_for_each_entry(pos, &session->evlist->entries, node) -		printf("%s\n", event_name(pos)); +	list_for_each_entry(pos, &session->evlist->entries, node) { +		bool first = true; + +		printf("%s", event_name(pos)); + +		if (details->verbose || details->freq) { +			comma_printf(&first, " sample_freq=%" PRIu64, +				     (u64)pos->attr.sample_freq); +		} + +		if (details->verbose) { +			if_print(type); +			if_print(config); +			if_print(config1); +			if_print(config2); +			if_print(size); +			if_print(sample_type); +			if_print(read_format); +			if_print(disabled); +			if_print(inherit); +			if_print(pinned); +			if_print(exclusive); +			if_print(exclude_user); +			if_print(exclude_kernel); +			if_print(exclude_hv); +			if_print(exclude_idle); +			if_print(mmap); +			if_print(comm); +			if_print(freq); +			if_print(inherit_stat); +			if_print(enable_on_exec); +			if_print(task); +			if_print(watermark); +			if_print(precise_ip); +			if_print(mmap_data); +			if_print(sample_id_all); +			if_print(exclude_host); +			if_print(exclude_guest); +			if_print(__reserved_1); +			if_print(wakeup_events); +			if_print(bp_type); +			if_print(branch_sample_type); +		} + +		putchar('\n'); +	}  	perf_session__delete(session);  	return 0; @@ -38,17 +113,23 @@ static const char * const evlist_usage[] = {  	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)  { +	struct perf_attr_details details = { .verbose = false, }; +	const char *input_name; +	const struct option options[] = { +		OPT_STRING('i', "input", &input_name, "file", +			    "Input file name"), +		OPT_BOOLEAN('F', "freq", &details.freq, +			    "Show the sample frequency"), +		OPT_BOOLEAN('v', "verbose", &details.verbose, +			    "Show all event attr details"), +		OPT_END() +	}; +  	argc = parse_options(argc, argv, options, evlist_usage, 0);  	if (argc)  		usage_with_options(evlist_usage, options); -	return __cmd_evlist(); +	return __cmd_evlist(input_name, &details);  } diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 09c106193e6..3beab489afc 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event,  static int perf_event__repipe_attr(union perf_event *event,  				   struct perf_evlist **pevlist __used)  { +	int ret; +	ret = perf_event__process_attr(event, pevlist); +	if (ret) +		return ret; +  	return perf_event__repipe_synth(NULL, event, NULL);  } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 39104c0beea..547af48deb4 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -192,7 +192,7 @@ static void insert_caller_stat(unsigned long call_site,  }  static void process_alloc_event(void *data, -				struct event *event, +				struct event_format *event,  				int cpu,  				u64 timestamp __used,  				struct thread *thread __used, @@ -253,7 +253,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,  }  static void process_free_event(void *data, -			       struct event *event, +			       struct event_format *event,  			       int cpu,  			       u64 timestamp __used,  			       struct thread *thread __used) @@ -281,7 +281,7 @@ static void process_free_event(void *data,  static void process_raw_event(union perf_event *raw_event __used, void *data,  			      int cpu, u64 timestamp, struct thread *thread)  { -	struct event *event; +	struct event_format *event;  	int type;  	type = trace_parse_common_type(data); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 12c81483899..fd53319de20 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -356,25 +356,25 @@ struct trace_release_event {  struct trace_lock_handler {  	void (*acquire_event)(struct trace_acquire_event *, -			      struct event *, +			      struct event_format *,  			      int cpu,  			      u64 timestamp,  			      struct thread *thread);  	void (*acquired_event)(struct trace_acquired_event *, -			       struct event *, +			       struct event_format *,  			       int cpu,  			       u64 timestamp,  			       struct thread *thread);  	void (*contended_event)(struct trace_contended_event *, -				struct event *, +				struct event_format *,  				int cpu,  				u64 timestamp,  				struct thread *thread);  	void (*release_event)(struct trace_release_event *, -			      struct event *, +			      struct event_format *,  			      int cpu,  			      u64 timestamp,  			      struct thread *thread); @@ -416,7 +416,7 @@ enum acquire_flags {  static void  report_lock_acquire_event(struct trace_acquire_event *acquire_event, -			struct event *__event __used, +			struct event_format *__event __used,  			int cpu __used,  			u64 timestamp __used,  			struct thread *thread __used) @@ -480,7 +480,7 @@ end:  static void  report_lock_acquired_event(struct trace_acquired_event *acquired_event, -			 struct event *__event __used, +			 struct event_format *__event __used,  			 int cpu __used,  			 u64 timestamp __used,  			 struct thread *thread __used) @@ -536,7 +536,7 @@ end:  static void  report_lock_contended_event(struct trace_contended_event *contended_event, -			  struct event *__event __used, +			  struct event_format *__event __used,  			  int cpu __used,  			  u64 timestamp __used,  			  struct thread *thread __used) @@ -583,7 +583,7 @@ end:  static void  report_lock_release_event(struct trace_release_event *release_event, -			struct event *__event __used, +			struct event_format *__event __used,  			int cpu __used,  			u64 timestamp __used,  			struct thread *thread __used) @@ -647,7 +647,7 @@ static struct trace_lock_handler *trace_handler;  static void  process_lock_acquire_event(void *data, -			   struct event *event __used, +			   struct event_format *event __used,  			   int cpu __used,  			   u64 timestamp __used,  			   struct thread *thread __used) @@ -666,7 +666,7 @@ process_lock_acquire_event(void *data,  static void  process_lock_acquired_event(void *data, -			    struct event *event __used, +			    struct event_format *event __used,  			    int cpu __used,  			    u64 timestamp __used,  			    struct thread *thread __used) @@ -684,7 +684,7 @@ process_lock_acquired_event(void *data,  static void  process_lock_contended_event(void *data, -			     struct event *event __used, +			     struct event_format *event __used,  			     int cpu __used,  			     u64 timestamp __used,  			     struct thread *thread __used) @@ -702,7 +702,7 @@ process_lock_contended_event(void *data,  static void  process_lock_release_event(void *data, -			   struct event *event __used, +			   struct event_format *event __used,  			   int cpu __used,  			   u64 timestamp __used,  			   struct thread *thread __used) @@ -721,7 +721,7 @@ process_lock_release_event(void *data,  static void  process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)  { -	struct event *event; +	struct event_format *event;  	int type;  	type = trace_parse_common_type(data); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index be4e1eee782..e5cb08427e1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -44,7 +44,6 @@ struct perf_record {  	struct perf_evlist	*evlist;  	struct perf_session	*session;  	const char		*progname; -	const char		*uid_str;  	int			output;  	unsigned int		page_size;  	int			realtime_prio; @@ -218,7 +217,7 @@ try_again:  			if (err == EPERM || err == EACCES) {  				ui__error_paranoid();  				exit(EXIT_FAILURE); -			} else if (err ==  ENODEV && opts->cpu_list) { +			} else if (err ==  ENODEV && opts->target.cpu_list) {  				die("No such device - did you specify"  					" an out-of-range profile CPU?\n");  			} else if (err == EINVAL) { @@ -243,9 +242,13 @@ try_again:  			/*  			 * If it's cycles then fall back to hrtimer  			 * based cpu-clock-tick sw counter, which -			 * is always available even if no PMU support: +			 * is always available even if no PMU support. +			 * +			 * PPC returns ENXIO until 2.6.37 (behavior changed +			 * with commit b0a873e).  			 */ -			if (attr->type == PERF_TYPE_HARDWARE +			if ((err == ENOENT || err == ENXIO) +					&& attr->type == PERF_TYPE_HARDWARE  					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {  				if (verbose) @@ -253,6 +256,10 @@ try_again:  						    "trying to fall back to cpu-clock-ticks\n");  				attr->type = PERF_TYPE_SOFTWARE;  				attr->config = PERF_COUNT_SW_CPU_CLOCK; +				if (pos->name) { +					free(pos->name); +					pos->name = NULL; +				}  				goto try_again;  			} @@ -389,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec)  			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);  	} -	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) +	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))  		write_output(rec, &finished_round_event, sizeof(finished_round_event));  } @@ -471,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)  		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);  	if (!have_tracepoints(&evsel_list->entries)) -		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO); +		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);  	if (!rec->opts.branch_stack)  		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); @@ -578,7 +585,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)  		perf_session__process_machines(session, tool,  					       perf_event__synthesize_guest_os); -	if (!opts->system_wide) +	if (!opts->target.system_wide)  		perf_event__synthesize_thread_map(tool, evsel_list->threads,  						  process_synthesized_event,  						  machine); @@ -746,7 +753,10 @@ static struct perf_record record = {  		.mmap_pages	     = UINT_MAX,  		.user_freq	     = UINT_MAX,  		.user_interval	     = ULLONG_MAX, -		.freq		     = 1000, +		.freq		     = 4000, +		.target		     = { +			.uses_mmap   = true, +		},  	},  	.write_mode = WRITE_FORCE,  	.file_new   = true, @@ -765,9 +775,9 @@ const struct option record_options[] = {  		     parse_events_option),  	OPT_CALLBACK(0, "filter", &record.evlist, "filter",  		     "event filter", parse_filter), -	OPT_STRING('p', "pid", &record.opts.target_pid, "pid", +	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",  		    "record events on existing process id"), -	OPT_STRING('t', "tid", &record.opts.target_tid, "tid", +	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",  		    "record events on existing thread id"),  	OPT_INTEGER('r', "realtime", &record.realtime_prio,  		    "collect data with this RT SCHED_FIFO priority"), @@ -775,11 +785,11 @@ const struct option record_options[] = {  		    "collect data without buffering"),  	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,  		    "collect raw sample records from all opened counters"), -	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, +	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,  			    "system-wide collection from all CPUs"),  	OPT_BOOLEAN('A', "append", &record.append_file,  			    "append to the output file to do incremental profiling"), -	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", +	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",  		    "list of cpus to monitor"),  	OPT_BOOLEAN('f', "force", &record.force,  			"overwrite existing data file (deprecated)"), @@ -813,7 +823,8 @@ const struct option record_options[] = {  	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",  		     "monitor event in cgroup name only",  		     parse_cgroups), -	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), +	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", +		   "user to profile"),  	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,  		     "branch any", "sample any taken branches", @@ -831,6 +842,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  	struct perf_evsel *pos;  	struct perf_evlist *evsel_list;  	struct perf_record *rec = &record; +	char errbuf[BUFSIZ];  	perf_header__set_cmdline(argc, argv); @@ -842,8 +854,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  	argc = parse_options(argc, argv, record_options, record_usage,  			    PARSE_OPT_STOP_AT_NON_OPTION); -	if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && -		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) +	if (!argc && perf_target__none(&rec->opts.target))  		usage_with_options(record_usage, record_options);  	if (rec->force && rec->append_file) { @@ -856,7 +867,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  		rec->write_mode = WRITE_FORCE;  	} -	if (nr_cgroups && !rec->opts.system_wide) { +	if (nr_cgroups && !rec->opts.target.system_wide) {  		fprintf(stderr, "cgroup monitoring only available in"  			" system-wide mode\n");  		usage_with_options(record_usage, record_options); @@ -883,17 +894,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)  		goto out_symbol_exit;  	} -	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid, -					 rec->opts.target_pid); -	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) -		goto out_free_fd; +	err = perf_target__validate(&rec->opts.target); +	if (err) { +		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); +		ui__warning("%s", errbuf); +	} + +	err = perf_target__parse_uid(&rec->opts.target); +	if (err) { +		int saved_errno = errno; -	if (rec->opts.target_pid) -		rec->opts.target_tid = rec->opts.target_pid; +		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); +		ui__warning("%s", errbuf); + +		err = -saved_errno; +		goto out_free_fd; +	} -	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, -				     rec->opts.target_tid, rec->opts.uid, -				     rec->opts.cpu_list) < 0) +	err = -ENOMEM; +	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)  		usage_with_options(record_usage, record_options);  	list_for_each_entry(pos, &evsel_list->entries, node) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cdae9b2db1c..d58e41445d0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -296,12 +296,15 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,  {  	size_t ret;  	char unit; -	unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; +	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; +	u64 nr_events = self->stats.total_period; -	nr_events = convert_unit(nr_events, &unit); -	ret = fprintf(fp, "# Events: %lu%c", nr_events, unit); +	nr_samples = convert_unit(nr_samples, &unit); +	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);  	if (evname != NULL) -		ret += fprintf(fp, " %s", evname); +		ret += fprintf(fp, " of event '%s'", evname); + +	ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);  	return ret + fprintf(fp, "\n#\n");  } @@ -680,14 +683,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)  	} -	if (strcmp(report.input_name, "-") != 0) { -		if (report.use_gtk) -			perf_gtk_setup_browser(argc, argv, true); -		else -			setup_browser(true); -	} else { +	if (strcmp(report.input_name, "-") != 0) +		setup_browser(true); +	else  		use_browser = 0; -	}  	/*  	 * Only in the newt browser we are doing integrated annotation, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 1cad3af4bf4..b125e07eb39 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -728,34 +728,34 @@ struct trace_migrate_task_event {  struct trace_sched_handler {  	void (*switch_event)(struct trace_switch_event *,  			     struct machine *, -			     struct event *, +			     struct event_format *,  			     int cpu,  			     u64 timestamp,  			     struct thread *thread);  	void (*runtime_event)(struct trace_runtime_event *,  			      struct machine *, -			      struct event *, +			      struct event_format *,  			      int cpu,  			      u64 timestamp,  			      struct thread *thread);  	void (*wakeup_event)(struct trace_wakeup_event *,  			     struct machine *, -			     struct event *, +			     struct event_format *,  			     int cpu,  			     u64 timestamp,  			     struct thread *thread);  	void (*fork_event)(struct trace_fork_event *, -			   struct event *, +			   struct event_format *,  			   int cpu,  			   u64 timestamp,  			   struct thread *thread);  	void (*migrate_task_event)(struct trace_migrate_task_event *,  			   struct machine *machine, -			   struct event *, +			   struct event_format *,  			   int cpu,  			   u64 timestamp,  			   struct thread *thread); @@ -765,7 +765,7 @@ struct trace_sched_handler {  static void  replay_wakeup_event(struct trace_wakeup_event *wakeup_event,  		    struct machine *machine __used, -		    struct event *event, +		    struct event_format *event,  		    int cpu __used,  		    u64 timestamp __used,  		    struct thread *thread __used) @@ -792,7 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];  static void  replay_switch_event(struct trace_switch_event *switch_event,  		    struct machine *machine __used, -		    struct event *event, +		    struct event_format *event,  		    int cpu,  		    u64 timestamp,  		    struct thread *thread __used) @@ -835,7 +835,7 @@ replay_switch_event(struct trace_switch_event *switch_event,  static void  replay_fork_event(struct trace_fork_event *fork_event, -		  struct event *event, +		  struct event_format *event,  		  int cpu __used,  		  u64 timestamp __used,  		  struct thread *thread __used) @@ -944,7 +944,7 @@ static void thread_atoms_insert(struct thread *thread)  static void  latency_fork_event(struct trace_fork_event *fork_event __used, -		   struct event *event __used, +		   struct event_format *event __used,  		   int cpu __used,  		   u64 timestamp __used,  		   struct thread *thread __used) @@ -1026,7 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)  static void  latency_switch_event(struct trace_switch_event *switch_event,  		     struct machine *machine, -		     struct event *event __used, +		     struct event_format *event __used,  		     int cpu,  		     u64 timestamp,  		     struct thread *thread __used) @@ -1079,7 +1079,7 @@ latency_switch_event(struct trace_switch_event *switch_event,  static void  latency_runtime_event(struct trace_runtime_event *runtime_event,  		     struct machine *machine, -		     struct event *event __used, +		     struct event_format *event __used,  		     int cpu,  		     u64 timestamp,  		     struct thread *this_thread __used) @@ -1102,7 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,  static void  latency_wakeup_event(struct trace_wakeup_event *wakeup_event,  		     struct machine *machine, -		     struct event *__event __used, +		     struct event_format *__event __used,  		     int cpu __used,  		     u64 timestamp,  		     struct thread *thread __used) @@ -1150,7 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,  static void  latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,  		     struct machine *machine, -		     struct event *__event __used, +		     struct event_format *__event __used,  		     int cpu __used,  		     u64 timestamp,  		     struct thread *thread __used) @@ -1361,7 +1361,7 @@ static struct trace_sched_handler *trace_handler;  static void  process_sched_wakeup_event(struct perf_tool *tool __used, -			   struct event *event, +			   struct event_format *event,  			   struct perf_sample *sample,  			   struct machine *machine,  			   struct thread *thread) @@ -1398,7 +1398,7 @@ static char next_shortname2 = '0';  static void  map_switch_event(struct trace_switch_event *switch_event,  		 struct machine *machine, -		 struct event *event __used, +		 struct event_format *event __used,  		 int this_cpu,  		 u64 timestamp,  		 struct thread *thread __used) @@ -1476,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,  static void  process_sched_switch_event(struct perf_tool *tool __used, -			   struct event *event, +			   struct event_format *event,  			   struct perf_sample *sample,  			   struct machine *machine,  			   struct thread *thread) @@ -1512,7 +1512,7 @@ process_sched_switch_event(struct perf_tool *tool __used,  static void  process_sched_runtime_event(struct perf_tool *tool __used, -			    struct event *event, +			    struct event_format *event,  			    struct perf_sample *sample,  			    struct machine *machine,  			    struct thread *thread) @@ -1532,7 +1532,7 @@ process_sched_runtime_event(struct perf_tool *tool __used,  static void  process_sched_fork_event(struct perf_tool *tool __used, -			 struct event *event, +			 struct event_format *event,  			 struct perf_sample *sample,  			 struct machine *machine __used,  			 struct thread *thread) @@ -1554,7 +1554,7 @@ process_sched_fork_event(struct perf_tool *tool __used,  static void  process_sched_exit_event(struct perf_tool *tool __used, -			 struct event *event, +			 struct event_format *event,  			 struct perf_sample *sample __used,  			 struct machine *machine __used,  			 struct thread *thread __used) @@ -1565,7 +1565,7 @@ process_sched_exit_event(struct perf_tool *tool __used,  static void  process_sched_migrate_task_event(struct perf_tool *tool __used, -				 struct event *event, +				 struct event_format *event,  				 struct perf_sample *sample,  				 struct machine *machine,  				 struct thread *thread) @@ -1586,7 +1586,7 @@ process_sched_migrate_task_event(struct perf_tool *tool __used,  						  sample->time, thread);  } -typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, +typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,  				   struct perf_sample *sample,  				   struct machine *machine,  				   struct thread *thread); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d4ce733b9eb..8e395a538eb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -261,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,  			       struct perf_event_attr *attr)  {  	int type; -	struct event *event; +	struct event_format *event;  	const char *evname = NULL;  	unsigned long secs;  	unsigned long usecs; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1e5e9b270f5..62ae30d34fa 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -173,24 +173,23 @@ static struct perf_event_attr very_very_detailed_attrs[] = { -struct perf_evlist		*evsel_list; +static struct perf_evlist	*evsel_list; -static bool			system_wide			=  false; -static int			run_idx				=  0; +static struct perf_target	target = { +	.uid	= UINT_MAX, +}; +static int			run_idx				=  0;  static int			run_count			=  1;  static bool			no_inherit			= false;  static bool			scale				=  true;  static bool			no_aggr				= false; -static const char		*target_pid; -static const char		*target_tid;  static pid_t			child_pid			= -1;  static bool			null_run			=  false;  static int			detailed_run			=  0;  static bool			sync_run			=  false;  static bool			big_num				=  true;  static int			big_num_opt			=  -1; -static const char		*cpu_list;  static const char		*csv_sep			= NULL;  static bool			csv_output			= false;  static bool			group				= false; @@ -265,18 +264,18 @@ static double stddev_stats(struct stats *stats)  	return sqrt(variance_mean);  } -struct stats			runtime_nsecs_stats[MAX_NR_CPUS]; -struct stats			runtime_cycles_stats[MAX_NR_CPUS]; -struct stats			runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; -struct stats			runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; -struct stats			runtime_branches_stats[MAX_NR_CPUS]; -struct stats			runtime_cacherefs_stats[MAX_NR_CPUS]; -struct stats			runtime_l1_dcache_stats[MAX_NR_CPUS]; -struct stats			runtime_l1_icache_stats[MAX_NR_CPUS]; -struct stats			runtime_ll_cache_stats[MAX_NR_CPUS]; -struct stats			runtime_itlb_cache_stats[MAX_NR_CPUS]; -struct stats			runtime_dtlb_cache_stats[MAX_NR_CPUS]; -struct stats			walltime_nsecs_stats; +static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; +static struct stats runtime_cycles_stats[MAX_NR_CPUS]; +static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; +static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; +static struct stats runtime_branches_stats[MAX_NR_CPUS]; +static struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; +static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; +static struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; +static struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; +static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; +static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; +static struct stats walltime_nsecs_stats;  static int create_perf_stat_counter(struct perf_evsel *evsel,  				    struct perf_evsel *first) @@ -299,15 +298,15 @@ retry:  	if (exclude_guest_missing)  		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; -	if (system_wide) { +	if (perf_target__has_cpu(&target)) {  		ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus, -						group, group_fd); +					       group, group_fd);  		if (ret)  			goto check_ret;  		return 0;  	} -	if (!target_pid && !target_tid && (!group || evsel == first)) { +	if (!perf_target__has_task(&target) && (!group || evsel == first)) {  		attr->disabled = 1;  		attr->enable_on_exec = 1;  	} @@ -471,7 +470,7 @@ static int run_perf_stat(int argc __used, const char **argv)  			exit(-1);  		} -		if (!target_tid && !target_pid && !system_wide) +		if (perf_target__none(&target))  			evsel_list->threads->map[0] = child_pid;  		/* @@ -506,7 +505,7 @@ static int run_perf_stat(int argc __used, const char **argv)  				error("You may not have permission to collect %sstats.\n"  				      "\t Consider tweaking"  				      " /proc/sys/kernel/perf_event_paranoid or running as root.", -				      system_wide ? "system-wide " : ""); +				      target.system_wide ? "system-wide " : "");  			} else {  				error("open_counter returned with %d (%s). "  				      "/bin/dmesg may provide additional information.\n", @@ -998,14 +997,14 @@ static void print_stat(int argc, const char **argv)  	if (!csv_output) {  		fprintf(output, "\n");  		fprintf(output, " Performance counter stats for "); -		if (!target_pid && !target_tid) { +		if (!perf_target__has_task(&target)) {  			fprintf(output, "\'%s", argv[0]);  			for (i = 1; i < argc; i++)  				fprintf(output, " %s", argv[i]); -		} else if (target_pid) -			fprintf(output, "process id \'%s", target_pid); +		} else if (target.pid) +			fprintf(output, "process id \'%s", target.pid);  		else -			fprintf(output, "thread id \'%s", target_tid); +			fprintf(output, "thread id \'%s", target.tid);  		fprintf(output, "\'");  		if (run_count > 1) @@ -1079,11 +1078,11 @@ static const struct option options[] = {  		     "event filter", parse_filter),  	OPT_BOOLEAN('i', "no-inherit", &no_inherit,  		    "child tasks do not inherit counters"), -	OPT_STRING('p', "pid", &target_pid, "pid", +	OPT_STRING('p', "pid", &target.pid, "pid",  		   "stat events on existing process id"), -	OPT_STRING('t', "tid", &target_tid, "tid", +	OPT_STRING('t', "tid", &target.tid, "tid",  		   "stat events on existing thread id"), -	OPT_BOOLEAN('a', "all-cpus", &system_wide, +	OPT_BOOLEAN('a', "all-cpus", &target.system_wide,  		    "system-wide collection from all CPUs"),  	OPT_BOOLEAN('g', "group", &group,  		    "put the counters into a counter group"), @@ -1102,7 +1101,7 @@ static const struct option options[] = {  	OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,   			   "print large numbers with thousands\' separators",  			   stat__set_big_num), -	OPT_STRING('C', "cpu", &cpu_list, "cpu", +	OPT_STRING('C', "cpu", &target.cpu_list, "cpu",  		    "list of cpus to monitor in system-wide"),  	OPT_BOOLEAN('A', "no-aggr", &no_aggr,  		    "disable CPU count aggregation"), @@ -1220,13 +1219,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)  	} else if (big_num_opt == 0) /* User passed --no-big-num */  		big_num = false; -	if (!argc && !target_pid && !target_tid) +	if (!argc && !perf_target__has_task(&target))  		usage_with_options(stat_usage, options);  	if (run_count <= 0)  		usage_with_options(stat_usage, options);  	/* no_aggr, cgroup are for system-wide only */ -	if ((no_aggr || nr_cgroups) && !system_wide) { +	if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {  		fprintf(stderr, "both cgroup and no-aggregation "  			"modes only available in system-wide mode\n"); @@ -1236,23 +1235,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)  	if (add_default_attributes())  		goto out; -	if (target_pid) -		target_tid = target_pid; +	perf_target__validate(&target); -	evsel_list->threads = thread_map__new_str(target_pid, -						  target_tid, UINT_MAX); -	if (evsel_list->threads == NULL) { -		pr_err("Problems finding threads of monitor\n"); -		usage_with_options(stat_usage, options); -	} - -	if (system_wide) -		evsel_list->cpus = cpu_map__new(cpu_list); -	else -		evsel_list->cpus = cpu_map__dummy_new(); +	if (perf_evlist__create_maps(evsel_list, &target) < 0) { +		if (perf_target__has_task(&target)) +			pr_err("Problems finding threads of monitor\n"); +		if (perf_target__has_cpu(&target)) +			perror("failed to parse CPUs map"); -	if (evsel_list->cpus == NULL) { -		perror("failed to parse CPUs map");  		usage_with_options(stat_usage, options);  		return -1;  	} diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 223ffdcc0fd..5a8727c0875 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -604,556 +604,6 @@ out_free_threads:  #undef nsyscalls  } -#define TEST_ASSERT_VAL(text, cond) \ -do { \ -	if (!(cond)) { \ -		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ -		return -1; \ -	} \ -} while (0) - -static int test__checkevent_tracepoint(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong sample_type", -		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == -		evsel->attr.sample_type); -	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); -	return 0; -} - -static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel; - -	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); - -	list_for_each_entry(evsel, &evlist->entries, node) { -		TEST_ASSERT_VAL("wrong type", -			PERF_TYPE_TRACEPOINT == evsel->attr.type); -		TEST_ASSERT_VAL("wrong sample_type", -			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) -			== evsel->attr.sample_type); -		TEST_ASSERT_VAL("wrong sample_period", -			1 == evsel->attr.sample_period); -	} -	return 0; -} - -static int test__checkevent_raw(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config); -	return 0; -} - -static int test__checkevent_numeric(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); -	return 0; -} - -static int test__checkevent_symbolic_name(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", -			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); -	return 0; -} - -static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", -			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); -	TEST_ASSERT_VAL("wrong period", -			100000 == evsel->attr.sample_period); -	TEST_ASSERT_VAL("wrong config1", -			0 == evsel->attr.config1); -	TEST_ASSERT_VAL("wrong config2", -			1 == evsel->attr.config2); -	return 0; -} - -static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", -			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); -	return 0; -} - -static int test__checkevent_genhw(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config); -	return 0; -} - -static int test__checkevent_breakpoint(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == -					 evsel->attr.bp_type); -	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 == -					evsel->attr.bp_len); -	return 0; -} - -static int test__checkevent_breakpoint_x(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong bp_type", -			HW_BREAKPOINT_X == evsel->attr.bp_type); -	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len); -	return 0; -} - -static int test__checkevent_breakpoint_r(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", -			PERF_TYPE_BREAKPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong bp_type", -			HW_BREAKPOINT_R == evsel->attr.bp_type); -	TEST_ASSERT_VAL("wrong bp_len", -			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); -	return 0; -} - -static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", -			PERF_TYPE_BREAKPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong bp_type", -			HW_BREAKPOINT_W == evsel->attr.bp_type); -	TEST_ASSERT_VAL("wrong bp_len", -			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); -	return 0; -} - -static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	return test__checkevent_tracepoint(evlist); -} - -static int -test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel; - -	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); - -	list_for_each_entry(evsel, &evlist->entries, node) { -		TEST_ASSERT_VAL("wrong exclude_user", -				!evsel->attr.exclude_user); -		TEST_ASSERT_VAL("wrong exclude_kernel", -				evsel->attr.exclude_kernel); -		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); -	} - -	return test__checkevent_tracepoint_multi(evlist); -} - -static int test__checkevent_raw_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return test__checkevent_raw(evlist); -} - -static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return test__checkevent_numeric(evlist); -} - -static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); -	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - -	return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); -	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - -	return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	return test__checkevent_symbolic_alias(evlist); -} - -static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return test__checkevent_genhw(evlist); -} - -static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	return test__checkevent_breakpoint(evlist); -} - -static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	return test__checkevent_breakpoint_x(evlist); -} - -static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return test__checkevent_breakpoint_r(evlist); -} - -static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return test__checkevent_breakpoint_w(evlist); -} - -static int test__checkevent_pmu(struct perf_evlist *evlist) -{ - -	struct perf_evsel *evsel = list_entry(evlist->entries.next, -					      struct perf_evsel, node); - -	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1); -	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2); -	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period); - -	return 0; -} - -static int test__checkevent_list(struct perf_evlist *evlist) -{ -	struct perf_evsel *evsel; - -	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); - -	/* r1 */ -	evsel = list_entry(evlist->entries.next, struct perf_evsel, node); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); -	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); -	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	/* syscalls:sys_enter_open:k */ -	evsel = list_entry(evsel->node.next, struct perf_evsel, node); -	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); -	TEST_ASSERT_VAL("wrong sample_type", -		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == -		evsel->attr.sample_type); -	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - -	/* 1:1:hp */ -	evsel = list_entry(evsel->node.next, struct perf_evsel, node); -	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); -	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); -	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); -	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); -	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); -	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - -	return 0; -} - -static struct test__event_st { -	const char *name; -	__u32 type; -	int (*check)(struct perf_evlist *evlist); -} test__events[] = { -	{ -		.name  = "syscalls:sys_enter_open", -		.check = test__checkevent_tracepoint, -	}, -	{ -		.name  = "syscalls:*", -		.check = test__checkevent_tracepoint_multi, -	}, -	{ -		.name  = "r1a", -		.check = test__checkevent_raw, -	}, -	{ -		.name  = "1:1", -		.check = test__checkevent_numeric, -	}, -	{ -		.name  = "instructions", -		.check = test__checkevent_symbolic_name, -	}, -	{ -		.name  = "cycles/period=100000,config2/", -		.check = test__checkevent_symbolic_name_config, -	}, -	{ -		.name  = "faults", -		.check = test__checkevent_symbolic_alias, -	}, -	{ -		.name  = "L1-dcache-load-miss", -		.check = test__checkevent_genhw, -	}, -	{ -		.name  = "mem:0", -		.check = test__checkevent_breakpoint, -	}, -	{ -		.name  = "mem:0:x", -		.check = test__checkevent_breakpoint_x, -	}, -	{ -		.name  = "mem:0:r", -		.check = test__checkevent_breakpoint_r, -	}, -	{ -		.name  = "mem:0:w", -		.check = test__checkevent_breakpoint_w, -	}, -	{ -		.name  = "syscalls:sys_enter_open:k", -		.check = test__checkevent_tracepoint_modifier, -	}, -	{ -		.name  = "syscalls:*:u", -		.check = test__checkevent_tracepoint_multi_modifier, -	}, -	{ -		.name  = "r1a:kp", -		.check = test__checkevent_raw_modifier, -	}, -	{ -		.name  = "1:1:hp", -		.check = test__checkevent_numeric_modifier, -	}, -	{ -		.name  = "instructions:h", -		.check = test__checkevent_symbolic_name_modifier, -	}, -	{ -		.name  = "faults:u", -		.check = test__checkevent_symbolic_alias_modifier, -	}, -	{ -		.name  = "L1-dcache-load-miss:kp", -		.check = test__checkevent_genhw_modifier, -	}, -	{ -		.name  = "mem:0:u", -		.check = test__checkevent_breakpoint_modifier, -	}, -	{ -		.name  = "mem:0:x:k", -		.check = test__checkevent_breakpoint_x_modifier, -	}, -	{ -		.name  = "mem:0:r:hp", -		.check = test__checkevent_breakpoint_r_modifier, -	}, -	{ -		.name  = "mem:0:w:up", -		.check = test__checkevent_breakpoint_w_modifier, -	}, -	{ -		.name  = "cpu/config=10,config1,config2=3,period=1000/u", -		.check = test__checkevent_pmu, -	}, -	{ -		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp", -		.check = test__checkevent_list, -	}, -	{ -		.name  = "instructions:G", -		.check = test__checkevent_exclude_host_modifier, -	}, -	{ -		.name  = "instructions:H", -		.check = test__checkevent_exclude_guest_modifier, -	}, -}; - -#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) - -static int test__parse_events(void) -{ -	struct perf_evlist *evlist; -	u_int i; -	int ret = 0; - -	for (i = 0; i < TEST__EVENTS_CNT; i++) { -		struct test__event_st *e = &test__events[i]; - -		evlist = perf_evlist__new(NULL, NULL); -		if (evlist == NULL) -			break; - -		ret = parse_events(evlist, e->name, 0); -		if (ret) { -			pr_debug("failed to parse event '%s', err %d\n", -				 e->name, ret); -			break; -		} - -		ret = e->check(evlist); -		perf_evlist__delete(evlist); -		if (ret) -			break; -	} - -	return ret; -} -  static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,  					 size_t *sizep)  { @@ -1195,6 +645,10 @@ realloc:  static int test__PERF_RECORD(void)  {  	struct perf_record_opts opts = { +		.target = { +			.uid = UINT_MAX, +			.uses_mmap = true, +		},  		.no_delay   = true,  		.freq	    = 10,  		.mmap_pages = 256, @@ -1237,8 +691,7 @@ static int test__PERF_RECORD(void)  	 * perf_evlist__prepare_workload we'll fill in the only thread  	 * we're monitoring, the one forked there.  	 */ -	err = perf_evlist__create_maps(evlist, opts.target_pid, -				       opts.target_tid, UINT_MAX, opts.cpu_list); +	err = perf_evlist__create_maps(evlist, &opts.target);  	if (err < 0) {  		pr_debug("Not enough memory to create thread/cpu maps\n");  		goto out_delete_evlist; @@ -1579,8 +1032,6 @@ static int __test__rdpmc(void)  	sa.sa_sigaction = segfault_handler;  	sigaction(SIGSEGV, &sa, NULL); -	fprintf(stderr, "\n\n"); -  	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);  	if (fd < 0) {  		die("Error: sys_perf_event_open() syscall returned " @@ -1605,7 +1056,7 @@ static int __test__rdpmc(void)  		loops *= 10;  		delta = now - stamp; -		fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); +		pr_debug("%14d: %14Lu\n", n, (long long)delta);  		delta_sum += delta;  	} @@ -1613,7 +1064,7 @@ static int __test__rdpmc(void)  	munmap(addr, page_size);  	close(fd); -	fprintf(stderr, "   "); +	pr_debug("   ");  	if (!delta_sum)  		return -1; @@ -1674,7 +1125,7 @@ static struct test {  	},  	{  		.desc = "parse events tests", -		.func = test__parse_events, +		.func = parse_events__test,  	},  #if defined(__x86_64__) || defined(__i386__)  	{ diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8ef59f8262b..6031dce0429 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)  	 * via --uid.  	 */  	list_for_each_entry(pos, &top->evlist->entries, node) -		pos->hists.uid_filter_str = top->uid_str; +		pos->hists.uid_filter_str = top->target.uid_str;  	perf_evlist__tui_browse_hists(top->evlist, help,  				      perf_top__sort_new_samples, @@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top)  			attr->read_format |= PERF_FORMAT_ID;  		} +		if (perf_target__has_cpu(&top->target)) +			attr->sample_type |= PERF_SAMPLE_CPU; +  		if (symbol_conf.use_callchain)  			attr->sample_type |= PERF_SAMPLE_CALLCHAIN; @@ -948,6 +951,10 @@ try_again:  				attr->type = PERF_TYPE_SOFTWARE;  				attr->config = PERF_COUNT_SW_CPU_CLOCK; +				if (counter->name) { +					free(counter->name); +					counter->name = strdup(event_name(counter)); +				}  				goto try_again;  			} @@ -1016,7 +1023,7 @@ static int __cmd_top(struct perf_top *top)  	if (ret)  		goto out_delete; -	if (top->target_tid || top->uid != UINT_MAX) +	if (perf_target__has_task(&top->target))  		perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,  						  perf_event__process,  						  &top->session->host_machine); @@ -1150,14 +1157,17 @@ static const char * const top_usage[] = {  int cmd_top(int argc, const char **argv, const char *prefix __used)  {  	struct perf_evsel *pos; -	int status = -ENOMEM; +	int status; +	char errbuf[BUFSIZ];  	struct perf_top top = {  		.count_filter	     = 5,  		.delay_secs	     = 2, -		.uid		     = UINT_MAX, -		.freq		     = 1000, /* 1 KHz */ +		.freq		     = 4000, /* 4 KHz */  		.mmap_pages	     = 128,  		.sym_pcnt_filter     = 5, +		.target		     = { +			.uses_mmap   = true, +		},  	};  	char callchain_default_opt[] = "fractal,0.5,callee";  	const struct option options[] = { @@ -1166,13 +1176,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)  		     parse_events_option),  	OPT_INTEGER('c', "count", &top.default_interval,  		    "event period to sample"), -	OPT_STRING('p', "pid", &top.target_pid, "pid", +	OPT_STRING('p', "pid", &top.target.pid, "pid",  		    "profile events on existing process id"), -	OPT_STRING('t', "tid", &top.target_tid, "tid", +	OPT_STRING('t', "tid", &top.target.tid, "tid",  		    "profile events on existing thread id"), -	OPT_BOOLEAN('a', "all-cpus", &top.system_wide, +	OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,  			    "system-wide collection from all CPUs"), -	OPT_STRING('C', "cpu", &top.cpu_list, "cpu", +	OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",  		    "list of cpus to monitor"),  	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,  		   "file", "vmlinux pathname"), @@ -1227,7 +1237,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)  		    "Display raw encoding of assembly instructions (default)"),  	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",  		   "Specify disassembler style (e.g. -M intel for intel syntax)"), -	OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"), +	OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),  	OPT_END()  	}; @@ -1253,22 +1263,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)  	setup_browser(false); -	top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid); -	if (top.uid_str != NULL && top.uid == UINT_MAX - 1) -		goto out_delete_evlist; +	status = perf_target__validate(&top.target); +	if (status) { +		perf_target__strerror(&top.target, status, errbuf, BUFSIZ); +		ui__warning("%s", errbuf); +	} -	/* CPU and PID are mutually exclusive */ -	if (top.target_tid && top.cpu_list) { -		printf("WARNING: PID switch overriding CPU\n"); -		sleep(1); -		top.cpu_list = NULL; +	status = perf_target__parse_uid(&top.target); +	if (status) { +		int saved_errno = errno; + +		perf_target__strerror(&top.target, status, errbuf, BUFSIZ); +		ui__warning("%s", errbuf); + +		status = -saved_errno; +		goto out_delete_evlist;  	} -	if (top.target_pid) -		top.target_tid = top.target_pid; +	if (perf_target__none(&top.target)) +		top.target.system_wide = true; -	if (perf_evlist__create_maps(top.evlist, top.target_pid, -				     top.target_tid, top.uid, top.cpu_list) < 0) +	if (perf_evlist__create_maps(top.evlist, &top.target) < 0)  		usage_with_options(top_usage, options);  	if (!top.evlist->nr_entries && diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 89e3355ab17..14f1034f14f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -207,10 +207,10 @@ extern const char perf_version_string[];  void pthread__unblock_sigwinch(void); +#include "util/target.h" +  struct perf_record_opts { -	const char   *target_pid; -	const char   *target_tid; -	uid_t	     uid; +	struct perf_target target;  	bool	     call_graph;  	bool	     group;  	bool	     inherit_stat; @@ -223,7 +223,6 @@ struct perf_record_opts {  	bool	     sample_time;  	bool	     sample_id_all_missing;  	bool	     exclude_guest_missing; -	bool	     system_wide;  	bool	     period;  	unsigned int freq;  	unsigned int mmap_pages; @@ -231,7 +230,6 @@ struct perf_record_opts {  	int	     branch_stack;  	u64	     default_interval;  	u64	     user_interval; -	const char   *cpu_list;  };  #endif diff --git a/tools/perf/util/ui/browser.c b/tools/perf/ui/browser.c index 556829124b0..cde4d0f0ddb 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -27,9 +27,12 @@ static int ui_browser__percent_color(struct ui_browser *browser,  	return HE_COLORSET_NORMAL;  } -void ui_browser__set_color(struct ui_browser *self __used, int color) +int ui_browser__set_color(struct ui_browser *browser, int color)  { +	int ret = browser->current_color; +	browser->current_color = color;  	SLsmg_set_color(color); +	return ret;  }  void ui_browser__set_percent_color(struct ui_browser *self, @@ -503,6 +506,12 @@ static struct ui_browser__colorset {  		.bg	  = "default",  	},  	{ +		.colorset = HE_COLORSET_ADDR, +		.name	  = "addr", +		.fg	  = "magenta", +		.bg	  = "default", +	}, +	{  		.name = NULL,  	}  }; @@ -584,6 +593,111 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)  	return row;  } +void __ui_browser__vline(struct ui_browser *browser, unsigned int column, +			 u16 start, u16 end) +{ +	SLsmg_set_char_set(1); +	ui_browser__gotorc(browser, start, column); +	SLsmg_draw_vline(end - start + 1); +	SLsmg_set_char_set(0); +} + +void ui_browser__write_graph(struct ui_browser *browser __used, int graph) +{ +	SLsmg_set_char_set(1); +	SLsmg_write_char(graph); +	SLsmg_set_char_set(0); +} + +static void __ui_browser__line_arrow_up(struct ui_browser *browser, +					unsigned int column, +					u64 start, u64 end) +{ +	unsigned int row, end_row; + +	SLsmg_set_char_set(1); + +	if (start < browser->top_idx + browser->height) { +		row = start - browser->top_idx; +		ui_browser__gotorc(browser, row, column); +		SLsmg_write_char(SLSMG_LLCORN_CHAR); +		ui_browser__gotorc(browser, row, column + 1); +		SLsmg_draw_hline(2); + +		if (row-- == 0) +			goto out; +	} else +		row = browser->height - 1; + +	if (end > browser->top_idx) +		end_row = end - browser->top_idx; +	else +		end_row = 0; + +	ui_browser__gotorc(browser, end_row, column); +	SLsmg_draw_vline(row - end_row + 1); + +	ui_browser__gotorc(browser, end_row, column); +	if (end >= browser->top_idx) { +		SLsmg_write_char(SLSMG_ULCORN_CHAR); +		ui_browser__gotorc(browser, end_row, column + 1); +		SLsmg_write_char(SLSMG_HLINE_CHAR); +		ui_browser__gotorc(browser, end_row, column + 2); +		SLsmg_write_char(SLSMG_RARROW_CHAR); +	} +out: +	SLsmg_set_char_set(0); +} + +static void __ui_browser__line_arrow_down(struct ui_browser *browser, +					  unsigned int column, +					  u64 start, u64 end) +{ +	unsigned int row, end_row; + +	SLsmg_set_char_set(1); + +	if (start >= browser->top_idx) { +		row = start - browser->top_idx; +		ui_browser__gotorc(browser, row, column); +		SLsmg_write_char(SLSMG_ULCORN_CHAR); +		ui_browser__gotorc(browser, row, column + 1); +		SLsmg_draw_hline(2); + +		if (row++ == 0) +			goto out; +	} else +		row = 0; + +	if (end >= browser->top_idx + browser->height) +		end_row = browser->height - 1; +	else +		end_row = end - browser->top_idx;; + +	ui_browser__gotorc(browser, row, column); +	SLsmg_draw_vline(end_row - row + 1); + +	ui_browser__gotorc(browser, end_row, column); +	if (end < browser->top_idx + browser->height) { +		SLsmg_write_char(SLSMG_LLCORN_CHAR); +		ui_browser__gotorc(browser, end_row, column + 1); +		SLsmg_write_char(SLSMG_HLINE_CHAR); +		ui_browser__gotorc(browser, end_row, column + 2); +		SLsmg_write_char(SLSMG_RARROW_CHAR); +	} +out: +	SLsmg_set_char_set(0); +} + +void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column, +			      u64 start, u64 end) +{ +	if (start > end) +		__ui_browser__line_arrow_up(browser, column, start, end); +	else +		__ui_browser__line_arrow_down(browser, column, start, end); +} +  void ui_browser__init(void)  {  	int i = 0; diff --git a/tools/perf/util/ui/browser.h b/tools/perf/ui/browser.h index 6ee82f60fea..dd96d822990 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -10,11 +10,13 @@  #define HE_COLORSET_NORMAL	52  #define HE_COLORSET_SELECTED	53  #define HE_COLORSET_CODE	54 +#define HE_COLORSET_ADDR	55  struct ui_browser {  	u64	      index, top_idx;  	void	      *top, *entries;  	u16	      y, x, width, height; +	int	      current_color;  	void	      *priv;  	const char    *title;  	char	      *helpline; @@ -27,7 +29,7 @@ struct ui_browser {  	bool	      use_navkeypressed;  }; -void ui_browser__set_color(struct ui_browser *self, int color); +int  ui_browser__set_color(struct ui_browser *browser, int color);  void ui_browser__set_percent_color(struct ui_browser *self,  				   double percent, bool current);  bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); @@ -35,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);  void ui_browser__reset_index(struct ui_browser *self);  void ui_browser__gotorc(struct ui_browser *self, int y, int x); +void ui_browser__write_graph(struct ui_browser *browser, int graph); +void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column, +			      u64 start, u64 end);  void __ui_browser__show_title(struct ui_browser *browser, const char *title);  void ui_browser__show_title(struct ui_browser *browser, const char *title);  int ui_browser__show(struct ui_browser *self, const char *title, @@ -44,6 +49,8 @@ int ui_browser__refresh(struct ui_browser *self);  int ui_browser__run(struct ui_browser *browser, int delay_secs);  void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);  void ui_browser__handle_resize(struct ui_browser *browser); +void __ui_browser__vline(struct ui_browser *browser, unsigned int column, +			 u16 start, u16 end);  int ui_browser__warning(struct ui_browser *browser, int timeout,  			const char *format, ...); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c new file mode 100644 index 00000000000..6e0ef79be16 --- /dev/null +++ b/tools/perf/ui/browsers/annotate.c @@ -0,0 +1,867 @@ +#include "../../util/util.h" +#include "../browser.h" +#include "../helpline.h" +#include "../libslang.h" +#include "../ui.h" +#include "../util.h" +#include "../../util/annotate.h" +#include "../../util/hist.h" +#include "../../util/sort.h" +#include "../../util/symbol.h" +#include <pthread.h> +#include <newt.h> + +struct browser_disasm_line { +	struct rb_node	rb_node; +	double		percent; +	u32		idx; +	int		idx_asm; +	int		jump_sources; +}; + +struct annotate_browser { +	struct ui_browser b; +	struct rb_root	  entries; +	struct rb_node	  *curr_hot; +	struct disasm_line	  *selection; +	struct disasm_line  **offsets; +	u64		    start; +	int		    nr_asm_entries; +	int		    nr_entries; +	int		    max_jump_sources; +	int		    nr_jumps; +	bool		    hide_src_code; +	bool		    use_offset; +	bool		    jump_arrows; +	bool		    show_nr_jumps; +	bool		    searching_backwards; +	u8		    addr_width; +	u8		    jumps_width; +	u8		    target_width; +	u8		    min_addr_width; +	u8		    max_addr_width; +	char		    search_bf[128]; +}; + +static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) +{ +	return (struct browser_disasm_line *)(dl + 1); +} + +static bool disasm_line__filter(struct ui_browser *browser, void *entry) +{ +	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); + +	if (ab->hide_src_code) { +		struct disasm_line *dl = list_entry(entry, struct disasm_line, node); +		return dl->offset == -1; +	} + +	return false; +} + +static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, +						 int nr, bool current) +{ +	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) +		return HE_COLORSET_SELECTED; +	if (nr == browser->max_jump_sources) +		return HE_COLORSET_TOP; +	if (nr > 1) +		return HE_COLORSET_MEDIUM; +	return HE_COLORSET_NORMAL; +} + +static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, +						     int nr, bool current) +{ +	 int color = annotate_browser__jumps_percent_color(browser, nr, current); +	 return ui_browser__set_color(&browser->b, color); +} + +static void annotate_browser__write(struct ui_browser *self, void *entry, int row) +{ +	struct annotate_browser *ab = container_of(self, struct annotate_browser, b); +	struct disasm_line *dl = list_entry(entry, struct disasm_line, node); +	struct browser_disasm_line *bdl = disasm_line__browser(dl); +	bool current_entry = ui_browser__is_current_entry(self, row); +	bool change_color = (!ab->hide_src_code && +			     (!current_entry || (self->use_navkeypressed && +					         !self->navkeypressed))); +	int width = self->width, printed; +	char bf[256]; + +	if (dl->offset != -1 && bdl->percent != 0.0) { +		ui_browser__set_percent_color(self, bdl->percent, current_entry); +		slsmg_printf("%6.2f ", bdl->percent); +	} else { +		ui_browser__set_percent_color(self, 0, current_entry); +		slsmg_write_nstring(" ", 7); +	} + +	SLsmg_write_char(' '); + +	/* The scroll bar isn't being used */ +	if (!self->navkeypressed) +		width += 1; + +	if (!*dl->line) +		slsmg_write_nstring(" ", width - 7); +	else if (dl->offset == -1) { +		printed = scnprintf(bf, sizeof(bf), "%*s  ", +				    ab->addr_width, " "); +		slsmg_write_nstring(bf, printed); +		slsmg_write_nstring(dl->line, width - printed - 6); +	} else { +		u64 addr = dl->offset; +		int color = -1; + +		if (!ab->use_offset) +			addr += ab->start; + +		if (!ab->use_offset) { +			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); +		} else { +			if (bdl->jump_sources) { +				if (ab->show_nr_jumps) { +					int prev; +					printed = scnprintf(bf, sizeof(bf), "%*d ", +							    ab->jumps_width, +							    bdl->jump_sources); +					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources, +											 current_entry); +					slsmg_write_nstring(bf, printed); +					ui_browser__set_color(self, prev); +				} + +				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", +						    ab->target_width, addr); +			} else { +				printed = scnprintf(bf, sizeof(bf), "%*s  ", +						    ab->addr_width, " "); +			} +		} + +		if (change_color) +			color = ui_browser__set_color(self, HE_COLORSET_ADDR); +		slsmg_write_nstring(bf, printed); +		if (change_color) +			ui_browser__set_color(self, color); +		if (dl->ins && dl->ins->ops->scnprintf) { +			if (ins__is_jump(dl->ins)) { +				bool fwd = dl->ops.target.offset > (u64)dl->offset; + +				ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR : +								    SLSMG_UARROW_CHAR); +				SLsmg_write_char(' '); +			} else if (ins__is_call(dl->ins)) { +				ui_browser__write_graph(self, SLSMG_RARROW_CHAR); +				SLsmg_write_char(' '); +			} else { +				slsmg_write_nstring(" ", 2); +			} +		} else { +			if (strcmp(dl->name, "retq")) { +				slsmg_write_nstring(" ", 2); +			} else { +				ui_browser__write_graph(self, SLSMG_LARROW_CHAR); +				SLsmg_write_char(' '); +			} +		} + +		disasm_line__scnprintf(dl, bf, sizeof(bf), !ab->use_offset); +		slsmg_write_nstring(bf, width - 10 - printed); +	} + +	if (current_entry) +		ab->selection = dl; +} + +static void annotate_browser__draw_current_jump(struct ui_browser *browser) +{ +	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); +	struct disasm_line *cursor = ab->selection, *target; +	struct browser_disasm_line *btarget, *bcursor; +	unsigned int from, to; + +	if (!cursor->ins || !ins__is_jump(cursor->ins) || +	    !disasm_line__has_offset(cursor)) +		return; + +	target = ab->offsets[cursor->ops.target.offset]; +	if (!target) +		return; + +	bcursor = disasm_line__browser(cursor); +	btarget = disasm_line__browser(target); + +	if (ab->hide_src_code) { +		from = bcursor->idx_asm; +		to = btarget->idx_asm; +	} else { +		from = (u64)bcursor->idx; +		to = (u64)btarget->idx; +	} + +	ui_browser__set_color(browser, HE_COLORSET_CODE); +	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); +} + +static unsigned int annotate_browser__refresh(struct ui_browser *browser) +{ +	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); +	int ret = ui_browser__list_head_refresh(browser); + +	if (ab->jump_arrows) +		annotate_browser__draw_current_jump(browser); + +	ui_browser__set_color(browser, HE_COLORSET_NORMAL); +	__ui_browser__vline(browser, 7, 0, browser->height - 1); +	return ret; +} + +static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) +{ +	double percent = 0.0; + +	if (dl->offset != -1) { +		int len = sym->end - sym->start; +		unsigned int hits = 0; +		struct annotation *notes = symbol__annotation(sym); +		struct source_line *src_line = notes->src->lines; +		struct sym_hist *h = annotation__histogram(notes, evidx); +		s64 offset = dl->offset; +		struct disasm_line *next; + +		next = disasm__get_next_ip_line(¬es->src->source, dl); +		while (offset < (s64)len && +		       (next == NULL || offset < next->offset)) { +			if (src_line) { +				percent += src_line[offset].percent; +			} else +				hits += h->addr[offset]; + +			++offset; +		} +		/* + 		 * If the percentage wasn't already calculated in + 		 * symbol__get_source_line, do it now: + 		 */ +		if (src_line == NULL && h->sum) +			percent = 100.0 * hits / h->sum; +	} + +	return percent; +} + +static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) +{ +	struct rb_node **p = &root->rb_node; +	struct rb_node *parent = NULL; +	struct browser_disasm_line *l; + +	while (*p != NULL) { +		parent = *p; +		l = rb_entry(parent, struct browser_disasm_line, rb_node); +		if (bdl->percent < l->percent) +			p = &(*p)->rb_left; +		else +			p = &(*p)->rb_right; +	} +	rb_link_node(&bdl->rb_node, parent, p); +	rb_insert_color(&bdl->rb_node, root); +} + +static void annotate_browser__set_top(struct annotate_browser *self, +				      struct disasm_line *pos, u32 idx) +{ +	unsigned back; + +	ui_browser__refresh_dimensions(&self->b); +	back = self->b.height / 2; +	self->b.top_idx = self->b.index = idx; + +	while (self->b.top_idx != 0 && back != 0) { +		pos = list_entry(pos->node.prev, struct disasm_line, node); + +		if (disasm_line__filter(&self->b, &pos->node)) +			continue; + +		--self->b.top_idx; +		--back; +	} + +	self->b.top = pos; +	self->b.navkeypressed = true; +} + +static void annotate_browser__set_rb_top(struct annotate_browser *browser, +					 struct rb_node *nd) +{ +	struct browser_disasm_line *bpos; +	struct disasm_line *pos; + +	bpos = rb_entry(nd, struct browser_disasm_line, rb_node); +	pos = ((struct disasm_line *)bpos) - 1; +	annotate_browser__set_top(browser, pos, bpos->idx); +	browser->curr_hot = nd; +} + +static void annotate_browser__calc_percent(struct annotate_browser *browser, +					   int evidx) +{ +	struct map_symbol *ms = browser->b.priv; +	struct symbol *sym = ms->sym; +	struct annotation *notes = symbol__annotation(sym); +	struct disasm_line *pos; + +	browser->entries = RB_ROOT; + +	pthread_mutex_lock(¬es->lock); + +	list_for_each_entry(pos, ¬es->src->source, node) { +		struct browser_disasm_line *bpos = disasm_line__browser(pos); +		bpos->percent = disasm_line__calc_percent(pos, sym, evidx); +		if (bpos->percent < 0.01) { +			RB_CLEAR_NODE(&bpos->rb_node); +			continue; +		} +		disasm_rb_tree__insert(&browser->entries, bpos); +	} +	pthread_mutex_unlock(¬es->lock); + +	browser->curr_hot = rb_last(&browser->entries); +} + +static bool annotate_browser__toggle_source(struct annotate_browser *browser) +{ +	struct disasm_line *dl; +	struct browser_disasm_line *bdl; +	off_t offset = browser->b.index - browser->b.top_idx; + +	browser->b.seek(&browser->b, offset, SEEK_CUR); +	dl = list_entry(browser->b.top, struct disasm_line, node); +	bdl = disasm_line__browser(dl); + +	if (browser->hide_src_code) { +		if (bdl->idx_asm < offset) +			offset = bdl->idx; + +		browser->b.nr_entries = browser->nr_entries; +		browser->hide_src_code = false; +		browser->b.seek(&browser->b, -offset, SEEK_CUR); +		browser->b.top_idx = bdl->idx - offset; +		browser->b.index = bdl->idx; +	} else { +		if (bdl->idx_asm < 0) { +			ui_helpline__puts("Only available for assembly lines."); +			browser->b.seek(&browser->b, -offset, SEEK_CUR); +			return false; +		} + +		if (bdl->idx_asm < offset) +			offset = bdl->idx_asm; + +		browser->b.nr_entries = browser->nr_asm_entries; +		browser->hide_src_code = true; +		browser->b.seek(&browser->b, -offset, SEEK_CUR); +		browser->b.top_idx = bdl->idx_asm - offset; +		browser->b.index = bdl->idx_asm; +	} + +	return true; +} + +static bool annotate_browser__callq(struct annotate_browser *browser, +				    int evidx, void (*timer)(void *arg), +				    void *arg, int delay_secs) +{ +	struct map_symbol *ms = browser->b.priv; +	struct disasm_line *dl = browser->selection; +	struct symbol *sym = ms->sym; +	struct annotation *notes; +	struct symbol *target; +	u64 ip; + +	if (!ins__is_call(dl->ins)) +		return false; + +	ip = ms->map->map_ip(ms->map, dl->ops.target.addr); +	target = map__find_symbol(ms->map, ip, NULL); +	if (target == NULL) { +		ui_helpline__puts("The called function was not found."); +		return true; +	} + +	notes = symbol__annotation(target); +	pthread_mutex_lock(¬es->lock); + +	if (notes->src == NULL && symbol__alloc_hist(target) < 0) { +		pthread_mutex_unlock(¬es->lock); +		ui__warning("Not enough memory for annotating '%s' symbol!\n", +			    target->name); +		return true; +	} + +	pthread_mutex_unlock(¬es->lock); +	symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs); +	ui_browser__show_title(&browser->b, sym->name); +	return true; +} + +static +struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, +					  s64 offset, s64 *idx) +{ +	struct map_symbol *ms = browser->b.priv; +	struct symbol *sym = ms->sym; +	struct annotation *notes = symbol__annotation(sym); +	struct disasm_line *pos; + +	*idx = 0; +	list_for_each_entry(pos, ¬es->src->source, node) { +		if (pos->offset == offset) +			return pos; +		if (!disasm_line__filter(&browser->b, &pos->node)) +			++*idx; +	} + +	return NULL; +} + +static bool annotate_browser__jump(struct annotate_browser *browser) +{ +	struct disasm_line *dl = browser->selection; +	s64 idx; + +	if (!ins__is_jump(dl->ins)) +		return false; + +	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); +	if (dl == NULL) { +		ui_helpline__puts("Invallid jump offset"); +		return true; +	} + +	annotate_browser__set_top(browser, dl, idx); +	 +	return true; +} + +static +struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser, +					  char *s, s64 *idx) +{ +	struct map_symbol *ms = browser->b.priv; +	struct symbol *sym = ms->sym; +	struct annotation *notes = symbol__annotation(sym); +	struct disasm_line *pos = browser->selection; + +	*idx = browser->b.index; +	list_for_each_entry_continue(pos, ¬es->src->source, node) { +		if (disasm_line__filter(&browser->b, &pos->node)) +			continue; + +		++*idx; + +		if (pos->line && strstr(pos->line, s) != NULL) +			return pos; +	} + +	return NULL; +} + +static bool __annotate_browser__search(struct annotate_browser *browser) +{ +	struct disasm_line *dl; +	s64 idx; + +	dl = annotate_browser__find_string(browser, browser->search_bf, &idx); +	if (dl == NULL) { +		ui_helpline__puts("String not found!"); +		return false; +	} + +	annotate_browser__set_top(browser, dl, idx); +	browser->searching_backwards = false; +	return true; +} + +static +struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, +						  char *s, s64 *idx) +{ +	struct map_symbol *ms = browser->b.priv; +	struct symbol *sym = ms->sym; +	struct annotation *notes = symbol__annotation(sym); +	struct disasm_line *pos = browser->selection; + +	*idx = browser->b.index; +	list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { +		if (disasm_line__filter(&browser->b, &pos->node)) +			continue; + +		--*idx; + +		if (pos->line && strstr(pos->line, s) != NULL) +			return pos; +	} + +	return NULL; +} + +static bool __annotate_browser__search_reverse(struct annotate_browser *browser) +{ +	struct disasm_line *dl; +	s64 idx; + +	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); +	if (dl == NULL) { +		ui_helpline__puts("String not found!"); +		return false; +	} + +	annotate_browser__set_top(browser, dl, idx); +	browser->searching_backwards = true; +	return true; +} + +static bool annotate_browser__search_window(struct annotate_browser *browser, +					    int delay_secs) +{ +	if (ui_browser__input_window("Search", "String: ", browser->search_bf, +				     "ENTER: OK, ESC: Cancel", +				     delay_secs * 2) != K_ENTER || +	    !*browser->search_bf) +		return false; + +	return true; +} + +static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) +{ +	if (annotate_browser__search_window(browser, delay_secs)) +		return __annotate_browser__search(browser); + +	return false; +} + +static bool annotate_browser__continue_search(struct annotate_browser *browser, +					      int delay_secs) +{ +	if (!*browser->search_bf) +		return annotate_browser__search(browser, delay_secs); + +	return __annotate_browser__search(browser); +} + +static bool annotate_browser__search_reverse(struct annotate_browser *browser, +					   int delay_secs) +{ +	if (annotate_browser__search_window(browser, delay_secs)) +		return __annotate_browser__search_reverse(browser); + +	return false; +} + +static +bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, +					       int delay_secs) +{ +	if (!*browser->search_bf) +		return annotate_browser__search_reverse(browser, delay_secs); + +	return __annotate_browser__search_reverse(browser); +} + +static int annotate_browser__run(struct annotate_browser *self, int evidx, +				 void(*timer)(void *arg), +				 void *arg, int delay_secs) +{ +	struct rb_node *nd = NULL; +	struct map_symbol *ms = self->b.priv; +	struct symbol *sym = ms->sym; +	const char *help = "Press 'h' for help on key bindings"; +	int key; + +	if (ui_browser__show(&self->b, sym->name, help) < 0) +		return -1; + +	annotate_browser__calc_percent(self, evidx); + +	if (self->curr_hot) { +		annotate_browser__set_rb_top(self, self->curr_hot); +		self->b.navkeypressed = false; +	} + +	nd = self->curr_hot; + +	while (1) { +		key = ui_browser__run(&self->b, delay_secs); + +		if (delay_secs != 0) { +			annotate_browser__calc_percent(self, evidx); +			/* +			 * Current line focus got out of the list of most active +			 * lines, NULL it so that if TAB|UNTAB is pressed, we +			 * move to curr_hot (current hottest line). +			 */ +			if (nd != NULL && RB_EMPTY_NODE(nd)) +				nd = NULL; +		} + +		switch (key) { +		case K_TIMER: +			if (timer != NULL) +				timer(arg); + +			if (delay_secs != 0) +				symbol__annotate_decay_histogram(sym, evidx); +			continue; +		case K_TAB: +			if (nd != NULL) { +				nd = rb_prev(nd); +				if (nd == NULL) +					nd = rb_last(&self->entries); +			} else +				nd = self->curr_hot; +			break; +		case K_UNTAB: +			if (nd != NULL) +				nd = rb_next(nd); +				if (nd == NULL) +					nd = rb_first(&self->entries); +			else +				nd = self->curr_hot; +			break; +		case K_F1: +		case 'h': +			ui_browser__help_window(&self->b, +		"UP/DOWN/PGUP\n" +		"PGDN/SPACE    Navigate\n" +		"q/ESC/CTRL+C  Exit\n\n" +		"->            Go to target\n" +		"<-            Exit\n" +		"h             Cycle thru hottest instructions\n" +		"j             Toggle showing jump to target arrows\n" +		"J             Toggle showing number of jump sources on targets\n" +		"n             Search next string\n" +		"o             Toggle disassembler output/simplified view\n" +		"s             Toggle source code view\n" +		"/             Search string\n" +		"?             Search previous string\n"); +			continue; +		case 'H': +			nd = self->curr_hot; +			break; +		case 's': +			if (annotate_browser__toggle_source(self)) +				ui_helpline__puts(help); +			continue; +		case 'o': +			self->use_offset = !self->use_offset; +			if (self->use_offset) +				self->target_width = self->min_addr_width; +			else +				self->target_width = self->max_addr_width; +update_addr_width: +			self->addr_width = self->target_width; +			if (self->show_nr_jumps) +				self->addr_width += self->jumps_width + 1; +			continue; +		case 'j': +			self->jump_arrows = !self->jump_arrows; +			continue; +		case 'J': +			self->show_nr_jumps = !self->show_nr_jumps; +			goto update_addr_width; +		case '/': +			if (annotate_browser__search(self, delay_secs)) { +show_help: +				ui_helpline__puts(help); +			} +			continue; +		case 'n': +			if (self->searching_backwards ? +			    annotate_browser__continue_search_reverse(self, delay_secs) : +			    annotate_browser__continue_search(self, delay_secs)) +				goto show_help; +			continue; +		case '?': +			if (annotate_browser__search_reverse(self, delay_secs)) +				goto show_help; +			continue; +		case K_ENTER: +		case K_RIGHT: +			if (self->selection == NULL) +				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); +			else if (self->selection->offset == -1) +				ui_helpline__puts("Actions are only available for assembly lines."); +			else if (!self->selection->ins) { +				if (strcmp(self->selection->name, "retq")) +					goto show_sup_ins; +				goto out; +			} else if (!(annotate_browser__jump(self) || +				     annotate_browser__callq(self, evidx, timer, arg, delay_secs))) { +show_sup_ins: +				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); +			} +			continue; +		case K_LEFT: +		case K_ESC: +		case 'q': +		case CTRL('c'): +			goto out; +		default: +			continue; +		} + +		if (nd != NULL) +			annotate_browser__set_rb_top(self, nd); +	} +out: +	ui_browser__hide(&self->b); +	return key; +} + +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, +			     void(*timer)(void *arg), void *arg, int delay_secs) +{ +	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, +				    timer, arg, delay_secs); +} + +static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, +						size_t size) +{ +	u64 offset; + +	for (offset = 0; offset < size; ++offset) { +		struct disasm_line *dl = browser->offsets[offset], *dlt; +		struct browser_disasm_line *bdlt; + +		if (!dl || !dl->ins || !ins__is_jump(dl->ins) || +		    !disasm_line__has_offset(dl)) +			continue; + +		if (dl->ops.target.offset >= size) { +			ui__error("jump to after symbol!\n" +				  "size: %zx, jump target: %" PRIx64, +				  size, dl->ops.target.offset); +			continue; +		} + +		dlt = browser->offsets[dl->ops.target.offset]; +		/* + 		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we + 		 * have to adjust to the previous offset? + 		 */ +		if (dlt == NULL) +			continue; + +		bdlt = disasm_line__browser(dlt); +		if (++bdlt->jump_sources > browser->max_jump_sources) +			browser->max_jump_sources = bdlt->jump_sources; + +		++browser->nr_jumps; +	} +		 +} + +static inline int width_jumps(int n) +{ +	if (n >= 100) +		return 5; +	if (n / 10) +		return 2; +	return 1; +} + +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, +			 void(*timer)(void *arg), void *arg, +			 int delay_secs) +{ +	struct disasm_line *pos, *n; +	struct annotation *notes; +	const size_t size = symbol__size(sym); +	struct map_symbol ms = { +		.map = map, +		.sym = sym, +	}; +	struct annotate_browser browser = { +		.b = { +			.refresh = annotate_browser__refresh, +			.seek	 = ui_browser__list_head_seek, +			.write	 = annotate_browser__write, +			.filter  = disasm_line__filter, +			.priv	 = &ms, +			.use_navkeypressed = true, +		}, +		.use_offset = true, +		.jump_arrows = true, +	}; +	int ret = -1; + +	if (sym == NULL) +		return -1; + +	if (map->dso->annotate_warned) +		return -1; + +	browser.offsets = zalloc(size * sizeof(struct disasm_line *)); +	if (browser.offsets == NULL) { +		ui__error("Not enough memory!"); +		return -1; +	} + +	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { +		ui__error("%s", ui_helpline__last_msg); +		goto out_free_offsets; +	} + +	ui_helpline__push("Press <- or ESC to exit"); + +	notes = symbol__annotation(sym); +	browser.start = map__rip_2objdump(map, sym->start); + +	list_for_each_entry(pos, ¬es->src->source, node) { +		struct browser_disasm_line *bpos; +		size_t line_len = strlen(pos->line); + +		if (browser.b.width < line_len) +			browser.b.width = line_len; +		bpos = disasm_line__browser(pos); +		bpos->idx = browser.nr_entries++; +		if (pos->offset != -1) { +			bpos->idx_asm = browser.nr_asm_entries++; +			/* +			 * FIXME: short term bandaid to cope with assembly +			 * routines that comes with labels in the same column +			 * as the address in objdump, sigh. +			 * +			 * E.g. copy_user_generic_unrolled + 			 */ +			if (pos->offset < (s64)size) +				browser.offsets[pos->offset] = pos; +		} else +			bpos->idx_asm = -1; +	} + +	annotate_browser__mark_jump_targets(&browser, size); + +	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); +	browser.max_addr_width = hex_width(sym->end); +	browser.jumps_width = width_jumps(browser.max_jump_sources); +	browser.b.nr_entries = browser.nr_entries; +	browser.b.entries = ¬es->src->source, +	browser.b.width += 18; /* Percentage */ +	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); +	list_for_each_entry_safe(pos, n, ¬es->src->source, node) { +		list_del(&pos->node); +		disasm_line__free(pos); +	} + +out_free_offsets: +	free(browser.offsets); +	return ret; +} diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 2f83e5dc996..a372a4b0263 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -5,12 +5,12 @@  #include <newt.h>  #include <linux/rbtree.h> -#include "../../evsel.h" -#include "../../evlist.h" -#include "../../hist.h" -#include "../../pstack.h" -#include "../../sort.h" -#include "../../util.h" +#include "../../util/evsel.h" +#include "../../util/evlist.h" +#include "../../util/hist.h" +#include "../../util/pstack.h" +#include "../../util/sort.h" +#include "../../util/util.h"  #include "../browser.h"  #include "../helpline.h" @@ -840,10 +840,14 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,  	int printed;  	const struct dso *dso = self->dso_filter;  	const struct thread *thread = self->thread_filter; -	unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; +	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; +	u64 nr_events = self->stats.total_period; + +	nr_samples = convert_unit(nr_samples, &unit); +	printed = scnprintf(bf, size, +			   "Samples: %lu%c of event '%s', Event count (approx.): %lu", +			   nr_samples, unit, ev_name, nr_events); -	nr_events = convert_unit(nr_events, &unit); -	printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);  	if (self->uid_filter_str)  		printed += snprintf(bf + printed, size - printed, @@ -937,7 +941,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  			goto zoom_dso;  		case 't':  			goto zoom_thread; -		case 's': +		case '/':  			if (ui_browser__input_window("Symbol to show",  					"Please enter the name of symbol you want to see",  					buf, "ENTER: OK, ESC: Cancel", @@ -965,7 +969,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  					"E             Expand all callchains\n"  					"d             Zoom into current DSO\n"  					"t             Zoom into current Thread\n" -					"s             Filter symbol by name"); +					"/             Filter symbol by name");  			continue;  		case K_ENTER:  		case K_RIGHT: diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index eca6575abfd..98851d55a53 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -5,9 +5,9 @@  #include <sys/ttydefaults.h>  #include <string.h>  #include <linux/bitops.h> -#include "../../util.h" -#include "../../debug.h" -#include "../../symbol.h" +#include "../../util/util.h" +#include "../../util/debug.h" +#include "../../util/symbol.h"  #include "../browser.h"  #include "../helpline.h"  #include "map.h" diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/ui/browsers/map.h index df8581a43e1..df8581a43e1 100644 --- a/tools/perf/util/ui/browsers/map.h +++ b/tools/perf/ui/browsers/map.h diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 258352a2356..0656c381a89 100644 --- a/tools/perf/util/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -9,24 +9,13 @@  #define MAX_COLUMNS			32 -void perf_gtk_setup_browser(int argc, const char *argv[], -			    bool fallback_to_pager __used) -{ -	gtk_init(&argc, (char ***)&argv); -} - -void perf_gtk_exit_browser(bool wait_for_ok __used) -{ -	gtk_main_quit(); -} - -static void perf_gtk_signal(int sig) +static void perf_gtk__signal(int sig)  {  	psignal(sig, "perf");  	gtk_main_quit();  } -static void perf_gtk_resize_window(GtkWidget *window) +static void perf_gtk__resize_window(GtkWidget *window)  {  	GdkRectangle rect;  	GdkScreen *screen; @@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)  	gtk_window_resize(GTK_WINDOW(window), width, height);  } -static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists) +static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)  {  	GType col_types[MAX_COLUMNS];  	GtkCellRenderer *renderer; @@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,  	GtkWidget *notebook;  	GtkWidget *window; -	signal(SIGSEGV, perf_gtk_signal); -	signal(SIGFPE,  perf_gtk_signal); -	signal(SIGINT,  perf_gtk_signal); -	signal(SIGQUIT, perf_gtk_signal); -	signal(SIGTERM, perf_gtk_signal); +	signal(SIGSEGV, perf_gtk__signal); +	signal(SIGFPE,  perf_gtk__signal); +	signal(SIGINT,  perf_gtk__signal); +	signal(SIGQUIT, perf_gtk__signal); +	signal(SIGTERM, perf_gtk__signal);  	window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -168,7 +157,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,  							GTK_POLICY_AUTOMATIC,  							GTK_POLICY_AUTOMATIC); -		perf_gtk_show_hists(scrolled_window, hists); +		perf_gtk__show_hists(scrolled_window, hists);  		tab_label = gtk_label_new(evname); @@ -179,7 +168,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,  	gtk_widget_show_all(window); -	perf_gtk_resize_window(window); +	perf_gtk__resize_window(window);  	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 75177ee0403..75177ee0403 100644 --- a/tools/perf/util/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c new file mode 100644 index 00000000000..82952995776 --- /dev/null +++ b/tools/perf/ui/gtk/setup.c @@ -0,0 +1,12 @@ +#include "gtk.h" +#include "../../util/cache.h" + +int perf_gtk__init(void) +{ +	return gtk_init_check(NULL, NULL) ? 0 : -1; +} + +void perf_gtk__exit(bool wait_for_ok __used) +{ +	gtk_main_quit(); +} diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/ui/helpline.c index 2f950c2641c..2f950c2641c 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/ui/helpline.c diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/ui/helpline.h index 7bab6b34e35..7bab6b34e35 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/ui/helpline.h diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/ui/keysyms.h index 809eca5707f..809eca5707f 100644 --- a/tools/perf/util/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/ui/libslang.h index 4d54b6450f5..4d54b6450f5 100644 --- a/tools/perf/util/ui/libslang.h +++ b/tools/perf/ui/libslang.h diff --git a/tools/perf/util/ui/progress.c b/tools/perf/ui/progress.c index 13aa64e50e1..13aa64e50e1 100644 --- a/tools/perf/util/ui/progress.c +++ b/tools/perf/ui/progress.c diff --git a/tools/perf/util/ui/progress.h b/tools/perf/ui/progress.h index d9c205b59aa..d9c205b59aa 100644 --- a/tools/perf/util/ui/progress.h +++ b/tools/perf/ui/progress.h diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c new file mode 100644 index 00000000000..9f5f888f73e --- /dev/null +++ b/tools/perf/ui/setup.c @@ -0,0 +1,45 @@ +#include "../cache.h" +#include "../debug.h" + + +void setup_browser(bool fallback_to_pager) +{ +	if (!isatty(1) || dump_trace) +		use_browser = 0; + +	/* default to TUI */ +	if (use_browser < 0) +		use_browser = 1; + +	switch (use_browser) { +	case 2: +		if (perf_gtk__init() == 0) +			break; +		/* fall through */ +	case 1: +		use_browser = 1; +		if (ui__init() == 0) +			break; +		/* fall through */ +	default: +		if (fallback_to_pager) +			setup_pager(); +		break; +	} +} + +void exit_browser(bool wait_for_ok) +{ +	switch (use_browser) { +	case 2: +		perf_gtk__exit(wait_for_ok); +		break; + +	case 1: +		ui__exit(wait_for_ok); +		break; + +	default: +		break; +	} +} diff --git a/tools/perf/util/ui/setup.c b/tools/perf/ui/tui/setup.c index 85a69faa09a..d33e943ac43 100644 --- a/tools/perf/util/ui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -2,14 +2,14 @@  #include <signal.h>  #include <stdbool.h> -#include "../cache.h" -#include "../debug.h" -#include "browser.h" -#include "helpline.h" -#include "ui.h" -#include "util.h" -#include "libslang.h" -#include "keysyms.h" +#include "../../util/cache.h" +#include "../../util/debug.h" +#include "../browser.h" +#include "../helpline.h" +#include "../ui.h" +#include "../util.h" +#include "../libslang.h" +#include "../keysyms.h"  pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; @@ -93,45 +93,26 @@ static void newt_suspend(void *d __used)  	newtResume();  } -static int ui__init(void) -{ -	int err = SLkp_init(); - -	if (err < 0) -		goto out; - -	SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); -out: -	return err; -} - -static void ui__exit(void) -{ -	SLtt_set_cursor_visibility(1); -	SLsmg_refresh(); -	SLsmg_reset_smg(); -	SLang_reset_tty(); -} -  static void ui__signal(int sig)  { -	ui__exit(); +	ui__exit(false);  	psignal(sig, "perf");  	exit(0);  } -void setup_browser(bool fallback_to_pager) +int ui__init(void)  { -	if (!isatty(1) || !use_browser || dump_trace) { -		use_browser = 0; -		if (fallback_to_pager) -			setup_pager(); -		return; -	} +	int err; -	use_browser = 1;  	newtInit(); -	ui__init(); +	err = SLkp_init(); +	if (err < 0) { +		pr_err("TUI initialization failed.\n"); +		goto out; +	} + +	SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); +  	newtSetSuspendCallback(newt_suspend, NULL);  	ui_helpline__init();  	ui_browser__init(); @@ -141,15 +122,19 @@ void setup_browser(bool fallback_to_pager)  	signal(SIGINT, ui__signal);  	signal(SIGQUIT, ui__signal);  	signal(SIGTERM, ui__signal); +out: +	return err;  } -void exit_browser(bool wait_for_ok) +void ui__exit(bool wait_for_ok)  { -	if (use_browser > 0) { -		if (wait_for_ok) -			ui__question_window("Fatal Error", -					    ui_helpline__last_msg, -					    "Press any key...", 0); -		ui__exit(); -	} +	if (wait_for_ok) +		ui__question_window("Fatal Error", +				    ui_helpline__last_msg, +				    "Press any key...", 0); + +	SLtt_set_cursor_visibility(1); +	SLsmg_refresh(); +	SLsmg_reset_smg(); +	SLang_reset_tty();  } diff --git a/tools/perf/util/ui/ui.h b/tools/perf/ui/ui.h index 7b67045479f..7b67045479f 100644 --- a/tools/perf/util/ui/ui.h +++ b/tools/perf/ui/ui.h diff --git a/tools/perf/util/ui/util.c b/tools/perf/ui/util.c index ad4374a16bb..ad4374a16bb 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/ui/util.c diff --git a/tools/perf/util/ui/util.h b/tools/perf/ui/util.h index 2d1738bd71c..2d1738bd71c 100644 --- a/tools/perf/util/ui/util.h +++ b/tools/perf/ui/util.h diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 08c6d138a65..8069dfb5ba7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,403 @@  const char 	*disassembler_style; +static struct ins *ins__find(const char *name); +static int disasm_line__parse(char *line, char **namep, char **rawp); + +static void ins__delete(struct ins_operands *ops) +{ +	free(ops->source.raw); +	free(ops->source.name); +	free(ops->target.raw); +	free(ops->target.name); +} + +static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, +			      struct ins_operands *ops) +{ +	return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); +} + +int ins__scnprintf(struct ins *ins, char *bf, size_t size, +		  struct ins_operands *ops) +{ +	if (ins->ops->scnprintf) +		return ins->ops->scnprintf(ins, bf, size, ops); + +	return ins__raw_scnprintf(ins, bf, size, ops); +} + +static int call__parse(struct ins_operands *ops) +{ +	char *endptr, *tok, *name; + +	ops->target.addr = strtoull(ops->raw, &endptr, 16); + +	name = strchr(endptr, '<'); +	if (name == NULL) +		goto indirect_call; + +	name++; + +	tok = strchr(name, '>'); +	if (tok == NULL) +		return -1; + +	*tok = '\0'; +	ops->target.name = strdup(name); +	*tok = '>'; + +	return ops->target.name == NULL ? -1 : 0; + +indirect_call: +	tok = strchr(endptr, '('); +	if (tok != NULL) { +		ops->target.addr = 0; +		return 0; +	} + +	tok = strchr(endptr, '*'); +	if (tok == NULL) +		return -1; + +	ops->target.addr = strtoull(tok + 1, NULL, 16); +	return 0; +} + +static int call__scnprintf(struct ins *ins, char *bf, size_t size, +			   struct ins_operands *ops) +{ +	if (ops->target.name) +		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); + +	if (ops->target.addr == 0) +		return ins__raw_scnprintf(ins, bf, size, ops); + +	return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); +} + +static struct ins_ops call_ops = { +	.parse	   = call__parse, +	.scnprintf = call__scnprintf, +}; + +bool ins__is_call(const struct ins *ins) +{ +	return ins->ops == &call_ops; +} + +static int jump__parse(struct ins_operands *ops) +{ +	const char *s = strchr(ops->raw, '+'); + +	ops->target.addr = strtoll(ops->raw, NULL, 16); + +	if (s++ != NULL) +		ops->target.offset = strtoll(s, NULL, 16); +	else +		ops->target.offset = UINT64_MAX; + +	return 0; +} + +static int jump__scnprintf(struct ins *ins, char *bf, size_t size, +			   struct ins_operands *ops) +{ +	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); +} + +static struct ins_ops jump_ops = { +	.parse	   = jump__parse, +	.scnprintf = jump__scnprintf, +}; + +bool ins__is_jump(const struct ins *ins) +{ +	return ins->ops == &jump_ops; +} + +static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) +{ +	char *endptr, *name, *t; + +	if (strstr(raw, "(%rip)") == NULL) +		return 0; + +	*addrp = strtoull(comment, &endptr, 16); +	name = strchr(endptr, '<'); +	if (name == NULL) +		return -1; + +	name++; + +	t = strchr(name, '>'); +	if (t == NULL) +		return 0; + +	*t = '\0'; +	*namep = strdup(name); +	*t = '>'; + +	return 0; +} + +static int lock__parse(struct ins_operands *ops) +{ +	char *name; + +	ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); +	if (ops->locked.ops == NULL) +		return 0; + +	if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) +		goto out_free_ops; + +        ops->locked.ins = ins__find(name); +        if (ops->locked.ins == NULL) +                goto out_free_ops; + +        if (!ops->locked.ins->ops) +                return 0; + +        if (ops->locked.ins->ops->parse) +                ops->locked.ins->ops->parse(ops->locked.ops); + +	return 0; + +out_free_ops: +	free(ops->locked.ops); +	ops->locked.ops = NULL; +	return 0; +} + +static int lock__scnprintf(struct ins *ins, char *bf, size_t size, +			   struct ins_operands *ops) +{ +	int printed; + +	if (ops->locked.ins == NULL) +		return ins__raw_scnprintf(ins, bf, size, ops); + +	printed = scnprintf(bf, size, "%-6.6s ", ins->name); +	return printed + ins__scnprintf(ops->locked.ins, bf + printed, +					size - printed, ops->locked.ops); +} + +static void lock__delete(struct ins_operands *ops) +{ +	free(ops->locked.ops); +	free(ops->target.raw); +	free(ops->target.name); +} + +static struct ins_ops lock_ops = { +	.free	   = lock__delete, +	.parse	   = lock__parse, +	.scnprintf = lock__scnprintf, +}; + +static int mov__parse(struct ins_operands *ops) +{ +	char *s = strchr(ops->raw, ','), *target, *comment, prev; + +	if (s == NULL) +		return -1; + +	*s = '\0'; +	ops->source.raw = strdup(ops->raw); +	*s = ','; +	 +	if (ops->source.raw == NULL) +		return -1; + +	target = ++s; + +	while (s[0] != '\0' && !isspace(s[0])) +		++s; +	prev = *s; +	*s = '\0'; + +	ops->target.raw = strdup(target); +	*s = prev; + +	if (ops->target.raw == NULL) +		goto out_free_source; + +	comment = strchr(s, '#'); +	if (comment == NULL) +		return 0; + +	while (comment[0] != '\0' && isspace(comment[0])) +		++comment; + +	comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); +	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); + +	return 0; + +out_free_source: +	free(ops->source.raw); +	ops->source.raw = NULL; +	return -1; +} + +static int mov__scnprintf(struct ins *ins, char *bf, size_t size, +			   struct ins_operands *ops) +{ +	return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, +			 ops->source.name ?: ops->source.raw, +			 ops->target.name ?: ops->target.raw); +} + +static struct ins_ops mov_ops = { +	.parse	   = mov__parse, +	.scnprintf = mov__scnprintf, +}; + +static int dec__parse(struct ins_operands *ops) +{ +	char *target, *comment, *s, prev; + +	target = s = ops->raw; + +	while (s[0] != '\0' && !isspace(s[0])) +		++s; +	prev = *s; +	*s = '\0'; + +	ops->target.raw = strdup(target); +	*s = prev; + +	if (ops->target.raw == NULL) +		return -1; + +	comment = strchr(s, '#'); +	if (comment == NULL) +		return 0; + +	while (comment[0] != '\0' && isspace(comment[0])) +		++comment; + +	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); + +	return 0; +} + +static int dec__scnprintf(struct ins *ins, char *bf, size_t size, +			   struct ins_operands *ops) +{ +	return scnprintf(bf, size, "%-6.6s %s", ins->name, +			 ops->target.name ?: ops->target.raw); +} + +static struct ins_ops dec_ops = { +	.parse	   = dec__parse, +	.scnprintf = dec__scnprintf, +}; + +static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, +			  struct ins_operands *ops __used) +{ +	return scnprintf(bf, size, "%-6.6s", "nop"); +} + +static struct ins_ops nop_ops = { +	.scnprintf = nop__scnprintf, +}; + +/* + * Must be sorted by name! + */ +static struct ins instructions[] = { +	{ .name = "add",   .ops  = &mov_ops, }, +	{ .name = "addl",  .ops  = &mov_ops, }, +	{ .name = "addq",  .ops  = &mov_ops, }, +	{ .name = "addw",  .ops  = &mov_ops, }, +	{ .name = "and",   .ops  = &mov_ops, }, +	{ .name = "bts",   .ops  = &mov_ops, }, +	{ .name = "call",  .ops  = &call_ops, }, +	{ .name = "callq", .ops  = &call_ops, }, +	{ .name = "cmp",   .ops  = &mov_ops, }, +	{ .name = "cmpb",  .ops  = &mov_ops, }, +	{ .name = "cmpl",  .ops  = &mov_ops, }, +	{ .name = "cmpq",  .ops  = &mov_ops, }, +	{ .name = "cmpw",  .ops  = &mov_ops, }, +	{ .name = "cmpxch", .ops  = &mov_ops, }, +	{ .name = "dec",   .ops  = &dec_ops, }, +	{ .name = "decl",  .ops  = &dec_ops, }, +	{ .name = "imul",  .ops  = &mov_ops, }, +	{ .name = "inc",   .ops  = &dec_ops, }, +	{ .name = "incl",  .ops  = &dec_ops, }, +	{ .name = "ja",	   .ops  = &jump_ops, }, +	{ .name = "jae",   .ops  = &jump_ops, }, +	{ .name = "jb",	   .ops  = &jump_ops, }, +	{ .name = "jbe",   .ops  = &jump_ops, }, +	{ .name = "jc",	   .ops  = &jump_ops, }, +	{ .name = "jcxz",  .ops  = &jump_ops, }, +	{ .name = "je",	   .ops  = &jump_ops, }, +	{ .name = "jecxz", .ops  = &jump_ops, }, +	{ .name = "jg",	   .ops  = &jump_ops, }, +	{ .name = "jge",   .ops  = &jump_ops, }, +	{ .name = "jl",    .ops  = &jump_ops, }, +	{ .name = "jle",   .ops  = &jump_ops, }, +	{ .name = "jmp",   .ops  = &jump_ops, }, +	{ .name = "jmpq",  .ops  = &jump_ops, }, +	{ .name = "jna",   .ops  = &jump_ops, }, +	{ .name = "jnae",  .ops  = &jump_ops, }, +	{ .name = "jnb",   .ops  = &jump_ops, }, +	{ .name = "jnbe",  .ops  = &jump_ops, }, +	{ .name = "jnc",   .ops  = &jump_ops, }, +	{ .name = "jne",   .ops  = &jump_ops, }, +	{ .name = "jng",   .ops  = &jump_ops, }, +	{ .name = "jnge",  .ops  = &jump_ops, }, +	{ .name = "jnl",   .ops  = &jump_ops, }, +	{ .name = "jnle",  .ops  = &jump_ops, }, +	{ .name = "jno",   .ops  = &jump_ops, }, +	{ .name = "jnp",   .ops  = &jump_ops, }, +	{ .name = "jns",   .ops  = &jump_ops, }, +	{ .name = "jnz",   .ops  = &jump_ops, }, +	{ .name = "jo",	   .ops  = &jump_ops, }, +	{ .name = "jp",	   .ops  = &jump_ops, }, +	{ .name = "jpe",   .ops  = &jump_ops, }, +	{ .name = "jpo",   .ops  = &jump_ops, }, +	{ .name = "jrcxz", .ops  = &jump_ops, }, +	{ .name = "js",	   .ops  = &jump_ops, }, +	{ .name = "jz",	   .ops  = &jump_ops, }, +	{ .name = "lea",   .ops  = &mov_ops, }, +	{ .name = "lock",  .ops  = &lock_ops, }, +	{ .name = "mov",   .ops  = &mov_ops, }, +	{ .name = "movb",  .ops  = &mov_ops, }, +	{ .name = "movdqa",.ops  = &mov_ops, }, +	{ .name = "movl",  .ops  = &mov_ops, }, +	{ .name = "movq",  .ops  = &mov_ops, }, +	{ .name = "movslq", .ops  = &mov_ops, }, +	{ .name = "movzbl", .ops  = &mov_ops, }, +	{ .name = "movzwl", .ops  = &mov_ops, }, +	{ .name = "nop",   .ops  = &nop_ops, }, +	{ .name = "nopl",  .ops  = &nop_ops, }, +	{ .name = "nopw",  .ops  = &nop_ops, }, +	{ .name = "or",    .ops  = &mov_ops, }, +	{ .name = "orl",   .ops  = &mov_ops, }, +	{ .name = "test",  .ops  = &mov_ops, }, +	{ .name = "testb", .ops  = &mov_ops, }, +	{ .name = "testl", .ops  = &mov_ops, }, +	{ .name = "xadd",  .ops  = &mov_ops, }, +}; + +static int ins__cmp(const void *name, const void *insp) +{ +	const struct ins *ins = insp; + +	return strcmp(name, ins->name); +} + +static struct ins *ins__find(const char *name) +{ +	const int nmemb = ARRAY_SIZE(instructions); + +	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); +} +  int symbol__annotate_init(struct map *map __used, struct symbol *sym)  {  	struct annotation *notes = symbol__annotation(sym); @@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)  int symbol__alloc_hist(struct symbol *sym)  {  	struct annotation *notes = symbol__annotation(sym); -	const size_t size = sym->end - sym->start + 1; +	const size_t size = symbol__size(sym);  	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));  	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); @@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,  	return 0;  } -static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) +static void disasm_line__init_ins(struct disasm_line *dl) +{ +	dl->ins = ins__find(dl->name); + +	if (dl->ins == NULL) +		return; + +	if (!dl->ins->ops) +		return; + +	if (dl->ins->ops->parse) +		dl->ins->ops->parse(&dl->ops); +} + +static int disasm_line__parse(char *line, char **namep, char **rawp) +{ +	char *name = line, tmp; + +	while (isspace(name[0])) +		++name; + +	if (name[0] == '\0') +		return -1; + +	*rawp = name + 1; + +	while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) +		++*rawp; + +	tmp = (*rawp)[0]; +	(*rawp)[0] = '\0'; +	*namep = strdup(name); + +	if (*namep == NULL) +		goto out_free_name; + +	(*rawp)[0] = tmp; + +	if ((*rawp)[0] != '\0') { +		(*rawp)++; +		while (isspace((*rawp)[0])) +			++(*rawp); +	} + +	return 0; + +out_free_name: +	free(*namep); +	*namep = NULL; +	return -1; +} + +static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)  { -	struct objdump_line *self = malloc(sizeof(*self) + privsize); +	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); -	if (self != NULL) { -		self->offset = offset; -		self->line = line; +	if (dl != NULL) { +		dl->offset = offset; +		dl->line = strdup(line); +		if (dl->line == NULL) +			goto out_delete; + +		if (offset != -1) { +			if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) +				goto out_free_line; + +			disasm_line__init_ins(dl); +		}  	} -	return self; +	return dl; + +out_free_line: +	free(dl->line); +out_delete: +	free(dl); +	return NULL; +} + +void disasm_line__free(struct disasm_line *dl) +{ +	free(dl->line); +	free(dl->name); +	if (dl->ins && dl->ins->ops->free) +		dl->ins->ops->free(&dl->ops); +	else +		ins__delete(&dl->ops); +	free(dl);  } -void objdump_line__free(struct objdump_line *self) +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)  { -	free(self->line); -	free(self); +	if (raw || !dl->ins) +		return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); + +	return ins__scnprintf(dl->ins, bf, size, &dl->ops);  } -static void objdump__add_line(struct list_head *head, struct objdump_line *line) +static void disasm__add(struct list_head *head, struct disasm_line *line)  {  	list_add_tail(&line->node, head);  } -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, -					       struct objdump_line *pos) +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)  {  	list_for_each_entry_continue(pos, head, node)  		if (pos->offset >= 0) @@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,  	return NULL;  } -static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, -			       int evidx, u64 len, int min_pcnt, -			       int printed, int max_lines, -			       struct objdump_line *queue) +static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, +		      int evidx, u64 len, int min_pcnt, int printed, +		      int max_lines, struct disasm_line *queue)  {  	static const char *prev_line;  	static const char *prev_color; -	if (oline->offset != -1) { +	if (dl->offset != -1) {  		const char *path = NULL;  		unsigned int hits = 0;  		double percent = 0.0; @@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,  		struct annotation *notes = symbol__annotation(sym);  		struct source_line *src_line = notes->src->lines;  		struct sym_hist *h = annotation__histogram(notes, evidx); -		s64 offset = oline->offset; -		struct objdump_line *next; +		s64 offset = dl->offset; +		const u64 addr = start + offset; +		struct disasm_line *next; -		next = objdump__get_next_ip_line(¬es->src->source, oline); +		next = disasm__get_next_ip_line(¬es->src->source, dl);  		while (offset < (s64)len &&  		       (next == NULL || offset < next->offset)) { @@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,  		if (queue != NULL) {  			list_for_each_entry_from(queue, ¬es->src->source, node) { -				if (queue == oline) +				if (queue == dl)  					break; -				objdump_line__print(queue, sym, evidx, len, +				disasm_line__print(queue, sym, start, evidx, len,  						    0, 0, 1, NULL);  			}  		} @@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,  		color_fprintf(stdout, color, " %7.2f", percent);  		printf(" :	"); -		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); +		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr); +		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);  	} else if (max_lines && printed >= max_lines)  		return 1;  	else {  		if (queue)  			return -1; -		if (!*oline->line) +		if (!*dl->line)  			printf("         :\n");  		else -			printf("         :	%s\n", oline->line); +			printf("         :	%s\n", dl->line);  	}  	return 0; @@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,  				      FILE *file, size_t privsize)  {  	struct annotation *notes = symbol__annotation(sym); -	struct objdump_line *objdump_line; -	char *line = NULL, *tmp, *tmp2, *c; +	struct disasm_line *dl; +	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;  	size_t line_len;  	s64 line_ip, offset = -1; @@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,  		*c = 0;  	line_ip = -1; +	parsed_line = line;  	/*  	 * Strip leading spaces: @@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,  		offset = line_ip - start;  		if (offset < 0 || (u64)line_ip > end)  			offset = -1; +		else +			parsed_line = tmp2 + 1;  	} -	objdump_line = objdump_line__new(offset, line, privsize); -	if (objdump_line == NULL) { -		free(line); +	dl = disasm_line__new(offset, parsed_line, privsize); +	free(line); + +	if (dl == NULL)  		return -1; -	} -	objdump__add_line(¬es->src->source, objdump_line); + +	disasm__add(¬es->src->source, dl);  	return 0;  } @@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)  {  	struct annotation *notes = symbol__annotation(sym);  	struct sym_hist *h = annotation__histogram(notes, evidx); -	u64 len = sym->end - sym->start, offset; +	u64 len = symbol__size(sym), offset;  	for (offset = 0; offset < len; ++offset)  		if (h->addr[offset] != 0) @@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  	struct dso *dso = map->dso;  	const char *filename = dso->long_name, *d_filename;  	struct annotation *notes = symbol__annotation(sym); -	struct objdump_line *pos, *queue = NULL; +	struct disasm_line *pos, *queue = NULL; +	u64 start = map__rip_2objdump(map, sym->start);  	int printed = 2, queue_len = 0;  	int more = 0;  	u64 len; @@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  	else  		d_filename = basename(filename); -	len = sym->end - sym->start; +	len = symbol__size(sym);  	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);  	printf("------------------------------------------------\n"); @@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  			queue_len = 0;  		} -		switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, -					    printed, max_lines, queue)) { +		switch (disasm_line__print(pos, sym, start, evidx, len, +					    min_pcnt, printed, max_lines, +					    queue)) {  		case 0:  			++printed;  			if (context) { @@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)  {  	struct annotation *notes = symbol__annotation(sym);  	struct sym_hist *h = annotation__histogram(notes, evidx); -	int len = sym->end - sym->start, offset; +	int len = symbol__size(sym), offset;  	h->sum = 0;  	for (offset = 0; offset < len; ++offset) { @@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)  	}  } -void objdump_line_list__purge(struct list_head *head) +void disasm__purge(struct list_head *head)  { -	struct objdump_line *pos, *n; +	struct disasm_line *pos, *n;  	list_for_each_entry_safe(pos, n, head, node) {  		list_del(&pos->node); -		objdump_line__free(pos); +		disasm_line__free(pos); +	} +} + +static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) +{ +	size_t printed; + +	if (dl->offset == -1) +		return fprintf(fp, "%s\n", dl->line); + +	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); + +	if (dl->ops.raw[0] != '\0') { +		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", +				   dl->ops.raw);  	} + +	return printed + fprintf(fp, "\n"); +} + +size_t disasm__fprintf(struct list_head *head, FILE *fp) +{ +	struct disasm_line *pos; +	size_t printed = 0; + +	list_for_each_entry(pos, head, node) +		printed += disasm_line__fprintf(pos, fp); + +	return printed;  }  int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, @@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,  	if (symbol__annotate(sym, map, 0) < 0)  		return -1; -	len = sym->end - sym->start; +	len = symbol__size(sym);  	if (print_lines) {  		symbol__get_source_line(sym, map, evidx, &source_line, @@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,  	if (print_lines)  		symbol__free_source_line(sym, len); -	objdump_line_list__purge(&symbol__annotation(sym)->src->source); +	disasm__purge(&symbol__annotation(sym)->src->source);  	return 0;  } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index efa5dc82bfa..78a5692dd71 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -2,20 +2,69 @@  #define __PERF_ANNOTATE_H  #include <stdbool.h> +#include <stdint.h>  #include "types.h"  #include "symbol.h"  #include <linux/list.h>  #include <linux/rbtree.h> -struct objdump_line { -	struct list_head node; -	s64		 offset; -	char		 *line; +struct ins; + +struct ins_operands { +	char	*raw; +	struct { +		char	*raw; +		char	*name; +		u64	addr; +		u64	offset; +	} target; +	union { +		struct { +			char	*raw; +			char	*name; +			u64	addr; +		} source; +		struct { +			struct ins *ins; +			struct ins_operands *ops; +		} locked; +	}; +}; + +struct ins_ops { +	void (*free)(struct ins_operands *ops); +	int (*parse)(struct ins_operands *ops); +	int (*scnprintf)(struct ins *ins, char *bf, size_t size, +			 struct ins_operands *ops);  }; -void objdump_line__free(struct objdump_line *self); -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, -					       struct objdump_line *pos); +struct ins { +	const char     *name; +	struct ins_ops *ops; +}; + +bool ins__is_jump(const struct ins *ins); +bool ins__is_call(const struct ins *ins); +int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); + +struct disasm_line { +	struct list_head    node; +	s64		    offset; +	char		    *line; +	char		    *name; +	struct ins	    *ins; +	struct ins_operands ops; +}; + +static inline bool disasm_line__has_offset(const struct disasm_line *dl) +{ +	return dl->ops.target.offset != UINT64_MAX; +} + +void disasm_line__free(struct disasm_line *dl); +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); +size_t disasm__fprintf(struct list_head *head, FILE *fp);  struct sym_hist {  	u64		sum; @@ -32,7 +81,7 @@ struct source_line {   *   * @histogram: Array of addr hit histograms per event being monitored   * @lines: If 'print_lines' is specified, per source code line percentages - * @source: source parsed from objdump -dS + * @source: source parsed from a disassembler like objdump -dS   *   * lines is allocated, percentages calculated and all sorted by percentage   * when the annotation is about to be presented, so the percentages are for @@ -82,7 +131,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,  			    int context);  void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);  void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); -void objdump_line_list__purge(struct list_head *head); +void disasm__purge(struct list_head *head);  int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,  			 bool print_lines, bool full_paths, int min_pcnt, diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index dff9c7a725f..fd9a5944b62 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {  	.mmap	= perf_event__process_mmap,  	.fork	= perf_event__process_task,  	.exit	= perf_event__exit_del_thread, +	.attr		 = perf_event__process_attr, +	.build_id	 = perf_event__process_build_id,  };  char *dso__build_id_filename(struct dso *self, char *bf, size_t size) diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 8dd224df3e5..cff18c617d1 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -33,7 +33,7 @@ extern int pager_use_color;  extern int use_browser; -#ifdef NO_NEWT_SUPPORT +#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)  static inline void setup_browser(bool fallback_to_pager)  {  	if (fallback_to_pager) @@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}  #else  void setup_browser(bool fallback_to_pager);  void exit_browser(bool wait_for_ok); + +#ifdef NO_NEWT_SUPPORT +static inline int ui__init(void) +{ +	return -1; +} +static inline void ui__exit(bool wait_for_ok __used) {} +#else +int ui__init(void); +void ui__exit(bool wait_for_ok);  #endif  #ifdef NO_GTK2_SUPPORT -static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) +static inline int perf_gtk__init(void)  { -	if (fallback_to_pager) -		setup_pager(); +	return -1;  } -static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} +static inline void perf_gtk__exit(bool wait_for_ok __used) {}  #else -void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); -void perf_gtk_exit_browser(bool wait_for_ok); +int perf_gtk__init(void); +void perf_gtk__exit(bool wait_for_ok);  #endif +#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */  char *alias_lookup(const char *alias);  int split_cmdline(char *cmdline, const char ***argv); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 26817daa296..efb1fce259a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -11,6 +11,7 @@  #include "event.h"  #include "debug.h"  #include "util.h" +#include "target.h"  int verbose;  bool dump_trace = false, quiet = false; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index f2ce88d04f5..6bebe7f0a20 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,  #else  extern char ui_helpline__last_msg[];  int ui_helpline__show_help(const char *format, va_list ap); -#include "ui/progress.h" +#include "../ui/progress.h"  int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));  #endif diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1986d8051bd..4ac5f5ae4ce 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -11,6 +11,7 @@  #include <poll.h>  #include "cpumap.h"  #include "thread_map.h" +#include "target.h"  #include "evlist.h"  #include "evsel.h"  #include <unistd.h> @@ -599,18 +600,21 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,  	return perf_evlist__mmap_per_cpu(evlist, prot, mask);  } -int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, -			     const char *target_tid, uid_t uid, const char *cpu_list) +int perf_evlist__create_maps(struct perf_evlist *evlist, +			     struct perf_target *target)  { -	evlist->threads = thread_map__new_str(target_pid, target_tid, uid); +	evlist->threads = thread_map__new_str(target->pid, target->tid, +					      target->uid);  	if (evlist->threads == NULL)  		return -1; -	if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) +	if (perf_target__has_task(target)) +		evlist->cpus = cpu_map__dummy_new(); +	else if (!perf_target__has_cpu(target) && !target->uses_mmap)  		evlist->cpus = cpu_map__dummy_new();  	else -		evlist->cpus = cpu_map__new(cpu_list); +		evlist->cpus = cpu_map__new(target->cpu_list);  	if (evlist->cpus == NULL)  		goto out_delete_threads; @@ -827,7 +831,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,  		exit(-1);  	} -	if (!opts->system_wide && !opts->target_tid && !opts->target_pid) +	if (perf_target__none(&opts->target))  		evlist->threads->map[0] = evlist->workload.pid;  	close(child_ready_pipe[1]); diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 21f1c9e57f1..58abb63ac13 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,  	evlist->threads	= threads;  } -int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, -			     const char *tid, uid_t uid, const char *cpu_list); +int perf_evlist__create_maps(struct perf_evlist *evlist, +			     struct perf_target *target);  void perf_evlist__delete_maps(struct perf_evlist *evlist);  int perf_evlist__set_filters(struct perf_evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8c13dbcb84b..57e4ce57bbc 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -14,6 +14,7 @@  #include "util.h"  #include "cpumap.h"  #include "thread_map.h" +#include "target.h"  #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))  #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) @@ -69,6 +70,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,  	struct perf_event_attr *attr = &evsel->attr;  	int track = !evsel->idx; /* only the first counter needs these */ +	attr->disabled = 1;  	attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;  	attr->inherit	    = !opts->no_inherit;  	attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED | @@ -106,15 +108,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,  	if (opts->call_graph)  		attr->sample_type	|= PERF_SAMPLE_CALLCHAIN; -	if (opts->system_wide) +	if (perf_target__has_cpu(&opts->target))  		attr->sample_type	|= PERF_SAMPLE_CPU;  	if (opts->period)  		attr->sample_type	|= PERF_SAMPLE_PERIOD;  	if (!opts->sample_id_all_missing && -	    (opts->sample_time || opts->system_wide || -	     !opts->no_inherit || opts->cpu_list)) +	    (opts->sample_time || !opts->no_inherit || +	     perf_target__has_cpu(&opts->target)))  		attr->sample_type	|= PERF_SAMPLE_TIME;  	if (opts->raw_samples) { @@ -135,9 +137,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,  	attr->mmap = track;  	attr->comm = track; -	if (!opts->target_pid && !opts->target_tid && !opts->system_wide && +	if (perf_target__none(&opts->target) &&  	    (!opts->group || evsel == first)) { -		attr->disabled = 1;  		attr->enable_on_exec = 1;  	}  } @@ -461,10 +462,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,  	 * used for cross-endian analysis. See git commit 65014ab3  	 * for why this goofiness is needed.  	 */ -	union { -		u64 val64; -		u32 val32[2]; -	} u; +	union u64_swap u;  	memset(data, 0, sizeof(*data));  	data->cpu = data->pid = data->tid = -1; @@ -607,10 +605,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,  	 * used for cross-endian analysis. See git commit 65014ab3  	 * for why this goofiness is needed.  	 */ -	union { -		u64 val64; -		u32 val32[2]; -	} u; +	union u64_swap u;  	array = event->sample.array; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index c0b70c697a3..2dd5edf161b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -31,21 +31,16 @@ static const char **header_argv;  int perf_header__push_event(u64 id, const char *name)  { +	struct perf_trace_event_type *nevents; +  	if (strlen(name) > MAX_EVENT_NAME)  		pr_warning("Event %s will be truncated\n", name); -	if (!events) { -		events = malloc(sizeof(struct perf_trace_event_type)); -		if (events == NULL) -			return -ENOMEM; -	} else { -		struct perf_trace_event_type *nevents; +	nevents = realloc(events, (event_count + 1) * sizeof(*events)); +	if (nevents == NULL) +		return -ENOMEM; +	events = nevents; -		nevents = realloc(events, (event_count + 1) * sizeof(*events)); -		if (nevents == NULL) -			return -ENOMEM; -		events = nevents; -	}  	memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));  	events[event_count].event_id = id;  	strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); @@ -442,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with  	return ret;  } -static int write_trace_info(int fd, struct perf_header *h __used, +static int write_tracing_data(int fd, struct perf_header *h __used,  			    struct perf_evlist *evlist)  {  	return read_tracing_data(fd, &evlist->entries); @@ -1477,7 +1472,7 @@ out:  	return err;  } -static int process_trace_info(struct perf_file_section *section __unused, +static int process_tracing_data(struct perf_file_section *section __unused,  			      struct perf_header *ph __unused,  			      int feat __unused, int fd)  { @@ -1513,11 +1508,11 @@ struct feature_ops {  		.full_only = true }  /* feature_ops not implemented: */ -#define print_trace_info		NULL -#define print_build_id			NULL +#define print_tracing_data	NULL +#define print_build_id		NULL  static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { -	FEAT_OPP(HEADER_TRACE_INFO,	trace_info), +	FEAT_OPP(HEADER_TRACING_DATA,	tracing_data),  	FEAT_OPP(HEADER_BUILD_ID,	build_id),  	FEAT_OPA(HEADER_HOSTNAME,	hostname),  	FEAT_OPA(HEADER_OSRELEASE,	osrelease), diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 21a6be09c12..2d42b3e1826 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -12,7 +12,7 @@  enum {  	HEADER_RESERVED		= 0,	/* always cleared */  	HEADER_FIRST_FEATURE	= 1, -	HEADER_TRACE_INFO	= 1, +	HEADER_TRACING_DATA	= 1,  	HEADER_BUILD_ID,  	HEADER_HOSTNAME, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9f6d630d531..1293b5ebea4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -599,7 +599,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,  	if (chain->ms.sym)  		ret += fprintf(fp, "%s\n", chain->ms.sym->name);  	else -		ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); +		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);  	return ret;  } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2cae9df40e0..cfc64e293f9 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -138,7 +138,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,  #define K_LEFT -1  #define K_RIGHT -2  #else -#include "ui/keysyms.h" +#include "../ui/keysyms.h"  int hist_entry__tui_annotate(struct hist_entry *he, int evidx,  			     void(*timer)(void *arg), void *arg, int delay_secs); diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c new file mode 100644 index 00000000000..76b98e2a587 --- /dev/null +++ b/tools/perf/util/parse-events-test.c @@ -0,0 +1,625 @@ + +#include "parse-events.h" +#include "evsel.h" +#include "evlist.h" +#include "sysfs.h" +#include "../../../include/linux/hw_breakpoint.h" + +#define TEST_ASSERT_VAL(text, cond) \ +do { \ +	if (!(cond)) { \ +		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ +		return -1; \ +	} \ +} while (0) + +static int test__checkevent_tracepoint(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong sample_type", +		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == +		evsel->attr.sample_type); +	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); +	return 0; +} + +static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel; + +	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); + +	list_for_each_entry(evsel, &evlist->entries, node) { +		TEST_ASSERT_VAL("wrong type", +			PERF_TYPE_TRACEPOINT == evsel->attr.type); +		TEST_ASSERT_VAL("wrong sample_type", +			(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) +			== evsel->attr.sample_type); +		TEST_ASSERT_VAL("wrong sample_period", +			1 == evsel->attr.sample_period); +	} +	return 0; +} + +static int test__checkevent_raw(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config); +	return 0; +} + +static int test__checkevent_numeric(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); +	return 0; +} + +static int test__checkevent_symbolic_name(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", +			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); +	return 0; +} + +static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", +			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); +	TEST_ASSERT_VAL("wrong period", +			100000 == evsel->attr.sample_period); +	TEST_ASSERT_VAL("wrong config1", +			0 == evsel->attr.config1); +	TEST_ASSERT_VAL("wrong config2", +			1 == evsel->attr.config2); +	return 0; +} + +static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", +			PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); +	return 0; +} + +static int test__checkevent_genhw(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config); +	return 0; +} + +static int test__checkevent_breakpoint(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == +					 evsel->attr.bp_type); +	TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 == +					evsel->attr.bp_len); +	return 0; +} + +static int test__checkevent_breakpoint_x(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong bp_type", +			HW_BREAKPOINT_X == evsel->attr.bp_type); +	TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len); +	return 0; +} + +static int test__checkevent_breakpoint_r(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", +			PERF_TYPE_BREAKPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong bp_type", +			HW_BREAKPOINT_R == evsel->attr.bp_type); +	TEST_ASSERT_VAL("wrong bp_len", +			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); +	return 0; +} + +static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", +			PERF_TYPE_BREAKPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong bp_type", +			HW_BREAKPOINT_W == evsel->attr.bp_type); +	TEST_ASSERT_VAL("wrong bp_len", +			HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); +	return 0; +} + +static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	return test__checkevent_tracepoint(evlist); +} + +static int +test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel; + +	TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); + +	list_for_each_entry(evsel, &evlist->entries, node) { +		TEST_ASSERT_VAL("wrong exclude_user", +				!evsel->attr.exclude_user); +		TEST_ASSERT_VAL("wrong exclude_kernel", +				evsel->attr.exclude_kernel); +		TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +		TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); +	} + +	return test__checkevent_tracepoint_multi(evlist); +} + +static int test__checkevent_raw_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return test__checkevent_raw(evlist); +} + +static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return test__checkevent_numeric(evlist); +} + +static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); +	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); + +	return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); +	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); + +	return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	return test__checkevent_symbolic_alias(evlist); +} + +static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return test__checkevent_genhw(evlist); +} + +static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	return test__checkevent_breakpoint(evlist); +} + +static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	return test__checkevent_breakpoint_x(evlist); +} + +static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return test__checkevent_breakpoint_r(evlist); +} + +static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return test__checkevent_breakpoint_w(evlist); +} + +static int test__checkevent_pmu(struct perf_evlist *evlist) +{ + +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1); +	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2); +	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period); + +	return 0; +} + +static int test__checkevent_list(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel; + +	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + +	/* r1 */ +	evsel = list_entry(evlist->entries.next, struct perf_evsel, node); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); +	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); +	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	/* syscalls:sys_enter_open:k */ +	evsel = list_entry(evsel->node.next, struct perf_evsel, node); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); +	TEST_ASSERT_VAL("wrong sample_type", +		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == +		evsel->attr.sample_type); +	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + +	/* 1:1:hp */ +	evsel = list_entry(evsel->node.next, struct perf_evsel, node); +	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); +	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); +	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); +	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + +	return 0; +} + +static int test__checkevent_pmu_name(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel; + +	/* cpu/config=1,name=krava1/u */ +	evsel = list_entry(evlist->entries.next, struct perf_evsel, node); +	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava")); + +	/* cpu/config=2/" */ +	evsel = list_entry(evsel->node.next, struct perf_evsel, node); +	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); +	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); +	TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config); +	TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2")); + +	return 0; +} + +struct test__event_st { +	const char *name; +	__u32 type; +	int (*check)(struct perf_evlist *evlist); +}; + +static struct test__event_st test__events[] = { +	[0] = { +		.name  = "syscalls:sys_enter_open", +		.check = test__checkevent_tracepoint, +	}, +	[1] = { +		.name  = "syscalls:*", +		.check = test__checkevent_tracepoint_multi, +	}, +	[2] = { +		.name  = "r1a", +		.check = test__checkevent_raw, +	}, +	[3] = { +		.name  = "1:1", +		.check = test__checkevent_numeric, +	}, +	[4] = { +		.name  = "instructions", +		.check = test__checkevent_symbolic_name, +	}, +	[5] = { +		.name  = "cycles/period=100000,config2/", +		.check = test__checkevent_symbolic_name_config, +	}, +	[6] = { +		.name  = "faults", +		.check = test__checkevent_symbolic_alias, +	}, +	[7] = { +		.name  = "L1-dcache-load-miss", +		.check = test__checkevent_genhw, +	}, +	[8] = { +		.name  = "mem:0", +		.check = test__checkevent_breakpoint, +	}, +	[9] = { +		.name  = "mem:0:x", +		.check = test__checkevent_breakpoint_x, +	}, +	[10] = { +		.name  = "mem:0:r", +		.check = test__checkevent_breakpoint_r, +	}, +	[11] = { +		.name  = "mem:0:w", +		.check = test__checkevent_breakpoint_w, +	}, +	[12] = { +		.name  = "syscalls:sys_enter_open:k", +		.check = test__checkevent_tracepoint_modifier, +	}, +	[13] = { +		.name  = "syscalls:*:u", +		.check = test__checkevent_tracepoint_multi_modifier, +	}, +	[14] = { +		.name  = "r1a:kp", +		.check = test__checkevent_raw_modifier, +	}, +	[15] = { +		.name  = "1:1:hp", +		.check = test__checkevent_numeric_modifier, +	}, +	[16] = { +		.name  = "instructions:h", +		.check = test__checkevent_symbolic_name_modifier, +	}, +	[17] = { +		.name  = "faults:u", +		.check = test__checkevent_symbolic_alias_modifier, +	}, +	[18] = { +		.name  = "L1-dcache-load-miss:kp", +		.check = test__checkevent_genhw_modifier, +	}, +	[19] = { +		.name  = "mem:0:u", +		.check = test__checkevent_breakpoint_modifier, +	}, +	[20] = { +		.name  = "mem:0:x:k", +		.check = test__checkevent_breakpoint_x_modifier, +	}, +	[21] = { +		.name  = "mem:0:r:hp", +		.check = test__checkevent_breakpoint_r_modifier, +	}, +	[22] = { +		.name  = "mem:0:w:up", +		.check = test__checkevent_breakpoint_w_modifier, +	}, +	[23] = { +		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp", +		.check = test__checkevent_list, +	}, +	[24] = { +		.name  = "instructions:G", +		.check = test__checkevent_exclude_host_modifier, +	}, +	[25] = { +		.name  = "instructions:H", +		.check = test__checkevent_exclude_guest_modifier, +	}, +}; + +#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) + +static struct test__event_st test__events_pmu[] = { +	[0] = { +		.name  = "cpu/config=10,config1,config2=3,period=1000/u", +		.check = test__checkevent_pmu, +	}, +	[1] = { +		.name  = "cpu/config=1,name=krava/u,cpu/config=2/u", +		.check = test__checkevent_pmu_name, +	}, +}; + +#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ +			      sizeof(struct test__event_st)) + +static int test(struct test__event_st *e) +{ +	struct perf_evlist *evlist; +	int ret; + +	evlist = perf_evlist__new(NULL, NULL); +	if (evlist == NULL) +		return -ENOMEM; + +	ret = parse_events(evlist, e->name, 0); +	if (ret) { +		pr_debug("failed to parse event '%s', err %d\n", +			 e->name, ret); +		return ret; +	} + +	ret = e->check(evlist); +	perf_evlist__delete(evlist); + +	return ret; +} + +static int test_events(struct test__event_st *events, unsigned cnt) +{ +	int ret = 0; +	unsigned i; + +	for (i = 0; i < cnt; i++) { +		struct test__event_st *e = &events[i]; + +		pr_debug("running test %d '%s'\n", i, e->name); +		ret = test(e); +		if (ret) +			break; +	} + +	return ret; +} + +static int test_pmu(void) +{ +	struct stat st; +	char path[PATH_MAX]; +	int ret; + +	snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/", +		 sysfs_find_mountpoint()); + +	ret = stat(path, &st); +	if (ret) +		pr_debug("ommiting PMU cpu tests\n"); +	return !ret; +} + +int parse_events__test(void) +{ +	int ret; + +	ret = test_events(test__events, TEST__EVENTS_CNT); +	if (!ret && test_pmu()) +		ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT); + +	return ret; +} diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5b3a0ef4e23..fac7d59309b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -23,8 +23,10 @@ struct event_symbol {  	const char	*alias;  }; -int parse_events_parse(struct list_head *list, struct list_head *list_tmp, -		       int *idx); +#ifdef PARSER_DEBUG +extern int parse_events_debug; +#endif +int parse_events_parse(struct list_head *list, int *idx);  #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x  #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x @@ -355,20 +357,30 @@ const char *__event_name(int type, u64 config)  	return "unknown";  } -static int add_event(struct list_head *list, int *idx, +static int add_event(struct list_head **_list, int *idx,  		     struct perf_event_attr *attr, char *name)  {  	struct perf_evsel *evsel; +	struct list_head *list = *_list; + +	if (!list) { +		list = malloc(sizeof(*list)); +		if (!list) +			return -ENOMEM; +		INIT_LIST_HEAD(list); +	}  	event_attr_init(attr);  	evsel = perf_evsel__new(attr, (*idx)++); -	if (!evsel) +	if (!evsel) { +		free(list);  		return -ENOMEM; - -	list_add_tail(&evsel->node, list); +	}  	evsel->name = strdup(name); +	list_add_tail(&evsel->node, list); +	*_list = list;  	return 0;  } @@ -390,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)  	return -1;  } -int parse_events_add_cache(struct list_head *list, int *idx, +int parse_events_add_cache(struct list_head **list, int *idx,  			   char *type, char *op_result1, char *op_result2)  {  	struct perf_event_attr attr; @@ -451,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,  	return add_event(list, idx, &attr, name);  } -static int add_tracepoint(struct list_head *list, int *idx, +static int add_tracepoint(struct list_head **list, int *idx,  			  char *sys_name, char *evt_name)  {  	struct perf_event_attr attr; @@ -488,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx,  	return add_event(list, idx, &attr, name);  } -static int add_tracepoint_multi(struct list_head *list, int *idx, +static int add_tracepoint_multi(struct list_head **list, int *idx,  				char *sys_name, char *evt_name)  {  	char evt_path[MAXPATHLEN]; @@ -519,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,  	return ret;  } -int parse_events_add_tracepoint(struct list_head *list, int *idx, +int parse_events_add_tracepoint(struct list_head **list, int *idx,  				char *sys, char *event)  {  	int ret; @@ -563,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)  	return 0;  } -int parse_events_add_breakpoint(struct list_head *list, int *idx, +int parse_events_add_breakpoint(struct list_head **list, int *idx,  				void *ptr, char *type)  {  	struct perf_event_attr attr; @@ -593,17 +605,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,  static int config_term(struct perf_event_attr *attr,  		       struct parse_events__term *term)  { -	switch (term->type) { +#define CHECK_TYPE_VAL(type)					\ +do {								\ +	if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val)	\ +		return -EINVAL;					\ +} while (0) + +	switch (term->type_term) {  	case PARSE_EVENTS__TERM_TYPE_CONFIG: +		CHECK_TYPE_VAL(NUM);  		attr->config = term->val.num;  		break;  	case PARSE_EVENTS__TERM_TYPE_CONFIG1: +		CHECK_TYPE_VAL(NUM);  		attr->config1 = term->val.num;  		break;  	case PARSE_EVENTS__TERM_TYPE_CONFIG2: +		CHECK_TYPE_VAL(NUM);  		attr->config2 = term->val.num;  		break;  	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: +		CHECK_TYPE_VAL(NUM);  		attr->sample_period = term->val.num;  		break;  	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: @@ -612,10 +634,15 @@ static int config_term(struct perf_event_attr *attr,  		 * attr->branch_sample_type = term->val.num;  		 */  		break; +	case PARSE_EVENTS__TERM_TYPE_NAME: +		CHECK_TYPE_VAL(STR); +		break;  	default:  		return -EINVAL;  	} +  	return 0; +#undef CHECK_TYPE_VAL  }  static int config_attr(struct perf_event_attr *attr, @@ -630,7 +657,7 @@ static int config_attr(struct perf_event_attr *attr,  	return 0;  } -int parse_events_add_numeric(struct list_head *list, int *idx, +int parse_events_add_numeric(struct list_head **list, int *idx,  			     unsigned long type, unsigned long config,  			     struct list_head *head_config)  { @@ -648,7 +675,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,  			 (char *) __event_name(type, config));  } -int parse_events_add_pmu(struct list_head *list, int *idx, +static int parse_events__is_name_term(struct parse_events__term *term) +{ +	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; +} + +static char *pmu_event_name(struct perf_event_attr *attr, +			    struct list_head *head_terms) +{ +	struct parse_events__term *term; + +	list_for_each_entry(term, head_terms, list) +		if (parse_events__is_name_term(term)) +			return term->val.str; + +	return (char *) __event_name(PERF_TYPE_RAW, attr->config); +} + +int parse_events_add_pmu(struct list_head **list, int *idx,  			 char *name, struct list_head *head_config)  {  	struct perf_event_attr attr; @@ -669,7 +713,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,  	if (perf_pmu__config(pmu, &attr, head_config))  		return -EINVAL; -	return add_event(list, idx, &attr, (char *) "pmu"); +	return add_event(list, idx, &attr, +			 pmu_event_name(&attr, head_config));  }  void parse_events_update_lists(struct list_head *list_event, @@ -681,7 +726,7 @@ void parse_events_update_lists(struct list_head *list_event,  	 * list, for next event definition.  	 */  	list_splice_tail(list_event, list_all); -	INIT_LIST_HEAD(list_event); +	free(list_event);  }  int parse_events_modifier(struct list_head *list, char *str) @@ -756,10 +801,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)  	buffer = parse_events__scan_string(str); -	ret = parse_events_parse(&list, &list_tmp, &idx); +#ifdef PARSER_DEBUG +	parse_events_debug = 1; +#endif +	ret = parse_events_parse(&list, &idx);  	parse_events__flush_buffer(buffer);  	parse_events__delete_buffer(buffer); +	parse_events_lex_destroy();  	if (!ret) {  		int entries = idx - evlist->nr_entries; @@ -1015,11 +1064,12 @@ void print_events(const char *event_glob)  int parse_events__is_hardcoded_term(struct parse_events__term *term)  { -	return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; +	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;  } -int parse_events__new_term(struct parse_events__term **_term, int type, -			   char *config, char *str, long num) +static int new_term(struct parse_events__term **_term, int type_val, +		    int type_term, char *config, +		    char *str, long num)  {  	struct parse_events__term *term; @@ -1028,15 +1078,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,  		return -ENOMEM;  	INIT_LIST_HEAD(&term->list); -	term->type = type; +	term->type_val  = type_val; +	term->type_term = type_term;  	term->config = config; -	switch (type) { -	case PARSE_EVENTS__TERM_TYPE_CONFIG: -	case PARSE_EVENTS__TERM_TYPE_CONFIG1: -	case PARSE_EVENTS__TERM_TYPE_CONFIG2: -	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: -	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: +	switch (type_val) {  	case PARSE_EVENTS__TERM_TYPE_NUM:  		term->val.num = num;  		break; @@ -1051,6 +1097,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,  	return 0;  } +int parse_events__term_num(struct parse_events__term **term, +			   int type_term, char *config, long num) +{ +	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, +			config, NULL, num); +} + +int parse_events__term_str(struct parse_events__term **term, +			   int type_term, char *config, char *str) +{ +	return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, +			config, str, 0); +} +  void parse_events__free_terms(struct list_head *terms)  {  	struct parse_events__term *term, *h; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index ca069f89338..8cac57ab4ee 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -4,7 +4,11 @@   * Parse symbolic events/counts passed in as options:   */ +#include <linux/list.h> +#include <stdbool.h> +#include "types.h"  #include "../../../include/linux/perf_event.h" +#include "types.h"  struct list_head;  struct perf_evsel; @@ -34,16 +38,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);  #define EVENTS_HELP_MAX (128*1024)  enum { +	PARSE_EVENTS__TERM_TYPE_NUM, +	PARSE_EVENTS__TERM_TYPE_STR, +}; + +enum { +	PARSE_EVENTS__TERM_TYPE_USER,  	PARSE_EVENTS__TERM_TYPE_CONFIG,  	PARSE_EVENTS__TERM_TYPE_CONFIG1,  	PARSE_EVENTS__TERM_TYPE_CONFIG2, +	PARSE_EVENTS__TERM_TYPE_NAME,  	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,  	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, -	PARSE_EVENTS__TERM_TYPE_NUM, -	PARSE_EVENTS__TERM_TYPE_STR, - -	PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX = -		PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,  };  struct parse_events__term { @@ -52,35 +58,34 @@ struct parse_events__term {  		char *str;  		long  num;  	} val; -	int type; - +	int type_val; +	int type_term;  	struct list_head list;  };  int parse_events__is_hardcoded_term(struct parse_events__term *term); -int parse_events__new_term(struct parse_events__term **term, int type, -			   char *config, char *str, long num); +int parse_events__term_num(struct parse_events__term **_term, +			   int type_term, char *config, long num); +int parse_events__term_str(struct parse_events__term **_term, +			   int type_term, char *config, char *str);  void parse_events__free_terms(struct list_head *terms); -int parse_events_modifier(struct list_head *list __used, char *str __used); -int parse_events_add_tracepoint(struct list_head *list, int *idx, +int parse_events_modifier(struct list_head *list, char *str); +int parse_events_add_tracepoint(struct list_head **list, int *idx,  				char *sys, char *event); -int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, -			 unsigned long config1, unsigned long config2, -			 char *mod); -int parse_events_add_numeric(struct list_head *list, int *idx, +int parse_events_add_numeric(struct list_head **list, int *idx,  			     unsigned long type, unsigned long config,  			     struct list_head *head_config); -int parse_events_add_cache(struct list_head *list, int *idx, +int parse_events_add_cache(struct list_head **list, int *idx,  			   char *type, char *op_result1, char *op_result2); -int parse_events_add_breakpoint(struct list_head *list, int *idx, +int parse_events_add_breakpoint(struct list_head **list, int *idx,  				void *ptr, char *type); -int parse_events_add_pmu(struct list_head *list, int *idx, +int parse_events_add_pmu(struct list_head **list, int *idx,  			 char *pmu , struct list_head *head_config);  void parse_events_update_lists(struct list_head *list_event,  			       struct list_head *list_all);  void parse_events_error(struct list_head *list_all, -			struct list_head *list_event,  			int *idx, char const *msg); +int parse_events__test(void);  void print_events(const char *event_glob);  void print_events_type(u8 type); diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 1fcf1bbc545..618a8e78839 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -1,5 +1,6 @@  %option prefix="parse_events_" +%option stack  %{  #include <errno.h> @@ -50,6 +51,8 @@ static int term(int type)  %} +%x mem +  num_dec		[0-9]+  num_hex		0x[a-fA-F0-9]+  num_raw_hex	[a-fA-F0-9]+ @@ -102,16 +105,16 @@ misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }  config			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }  config1			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }  config2			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } +name			{ return term(PARSE_EVENTS__TERM_TYPE_NAME); }  period			{ return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }  branch_type		{ return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } -mem:			{ return PE_PREFIX_MEM; } +mem:			{ BEGIN(mem); return PE_PREFIX_MEM; }  r{num_raw_hex}		{ return raw(); }  {num_dec}		{ return value(10); }  {num_hex}		{ return value(16); }  {modifier_event}	{ return str(PE_MODIFIER_EVENT); } -{modifier_bp}		{ return str(PE_MODIFIER_BP); }  {name}			{ return str(PE_NAME); }  "/"			{ return '/'; }  -			{ return '-'; } @@ -119,6 +122,25 @@ r{num_raw_hex}		{ return raw(); }  :			{ return ':'; }  =			{ return '='; } +<mem>{ +{modifier_bp}		{ return str(PE_MODIFIER_BP); } +:			{ return ':'; } +{num_dec}		{ return value(10); } +{num_hex}		{ return value(16); } +	/* +	 * We need to separate 'mem:' scanner part, in order to get specific +	 * modifier bits parsed out. Otherwise we would need to handle PE_NAME +	 * and we'd need to parse it manually. During the escape from <mem> +	 * state we need to put the escaping char back, so we dont miss it. +	 */ +.			{ unput(*parse_events_text); BEGIN(INITIAL); } +	/* +	 * We destroy the scanner after reaching EOF, +	 * but anyway just to be sure get back to INIT state. +	 */ +<<EOF>>			{ BEGIN(INITIAL); } +} +  %%  int parse_events_wrap(void) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index d9637da7333..362cc59332a 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -1,7 +1,6 @@  %name-prefix "parse_events_"  %parse-param {struct list_head *list_all} -%parse-param {struct list_head *list_event}  %parse-param {int *idx}  %{ @@ -41,6 +40,14 @@ do { \  %type <str> PE_MODIFIER_BP  %type <head> event_config  %type <term> event_term +%type <head> event_pmu +%type <head> event_legacy_symbol +%type <head> event_legacy_cache +%type <head> event_legacy_mem +%type <head> event_legacy_tracepoint +%type <head> event_legacy_numeric +%type <head> event_legacy_raw +%type <head> event_def  %union  { @@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT  	 * (there could be more events added for multiple tracepoint  	 * definitions via '*?'.  	 */ -	ABORT_ON(parse_events_modifier(list_event, $2)); -	parse_events_update_lists(list_event, list_all); +	ABORT_ON(parse_events_modifier($1, $2)); +	parse_events_update_lists($1, list_all);  }  |  event_def  { -	parse_events_update_lists(list_event, list_all); +	parse_events_update_lists($1, list_all);  }  event_def: event_pmu | @@ -82,71 +89,102 @@ event_def: event_pmu |  event_pmu:  PE_NAME '/' event_config '/'  { -	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));  	parse_events__free_terms($3); +	$$ = list;  }  event_legacy_symbol:  PE_VALUE_SYM '/' event_config '/'  { +	struct list_head *list = NULL;  	int type = $1 >> 16;  	int config = $1 & 255; -	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); +	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));  	parse_events__free_terms($3); +	$$ = list;  }  |  PE_VALUE_SYM sep_slash_dc  { +	struct list_head *list = NULL;  	int type = $1 >> 16;  	int config = $1 & 255; -	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); +	ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL)); +	$$ = list;  }  event_legacy_cache:  PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT  { -	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5)); +	$$ = list;  }  |  PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT  { -	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL)); +	$$ = list;  }  |  PE_NAME_CACHE_TYPE  { -	ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL)); +	$$ = list;  }  event_legacy_mem:  PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc  { -	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4)); +	$$ = list;  }  |  PE_PREFIX_MEM PE_VALUE sep_dc  { -	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL)); +	$$ = list;  }  event_legacy_tracepoint:  PE_NAME ':' PE_NAME  { -	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3)); +	$$ = list;  }  event_legacy_numeric:  PE_VALUE ':' PE_VALUE  { -	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL)); +	$$ = list;  }  event_legacy_raw:  PE_RAW  { -	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); +	struct list_head *list = NULL; + +	ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL)); +	$$ = list;  }  event_config: @@ -176,8 +214,8 @@ PE_NAME '=' PE_NAME  {  	struct parse_events__term *term; -	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR, -		 $1, $3, 0)); +	ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, +					$1, $3));  	$$ = term;  }  | @@ -185,8 +223,8 @@ PE_NAME '=' PE_VALUE  {  	struct parse_events__term *term; -	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, -		 $1, NULL, $3)); +	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, +					$1, $3));  	$$ = term;  }  | @@ -194,8 +232,16 @@ PE_NAME  {  	struct parse_events__term *term; -	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, -		 $1, NULL, 1)); +	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, +					$1, 1)); +	$$ = term; +} +| +PE_TERM '=' PE_NAME +{ +	struct parse_events__term *term; + +	ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));  	$$ = term;  }  | @@ -203,7 +249,7 @@ PE_TERM '=' PE_VALUE  {  	struct parse_events__term *term; -	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3)); +	ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));  	$$ = term;  }  | @@ -211,7 +257,7 @@ PE_TERM  {  	struct parse_events__term *term; -	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1)); +	ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));  	$$ = term;  } @@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |  %%  void parse_events_error(struct list_head *list_all __used, -			struct list_head *list_event __used,  			int *idx __used,  			char const *msg __used)  { diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index cb08a118e81..a119a537169 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,  	if (parse_events__is_hardcoded_term(term))  		return 0; -	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM) +	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)  		return -EINVAL;  	format = pmu_find_format(formats, term->config); @@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,  		return -EINVAL;  	} +	/* +	 * XXX If we ever decide to go with string values for +	 * non-hardcoded terms, here's the place to translate +	 * them into value. +	 */  	*vp |= pmu_format_value(format->bits, term->val.num);  	return 0;  } @@ -253,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,  static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,  		      struct list_head *head_terms)  { -	struct parse_events__term *term, *h; +	struct parse_events__term *term; -	list_for_each_entry_safe(term, h, head_terms, list) +	list_for_each_entry(term, head_terms, list)  		if (pmu_config_term(formats, attr, term))  			return -EINVAL; @@ -324,49 +329,58 @@ static struct test_format {  /* Simulated users input. */  static struct parse_events__term test_terms[] = {  	{ -		.config  = (char *) "krava01", -		.val.num = 15, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava01", +		.val.num   = 15, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava02", -		.val.num = 170, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava02", +		.val.num   = 170, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava03", -		.val.num = 1, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava03", +		.val.num   = 1, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava11", -		.val.num = 27, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava11", +		.val.num   = 27, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava12", -		.val.num = 1, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava12", +		.val.num   = 1, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava13", -		.val.num = 2, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava13", +		.val.num   = 2, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava21", -		.val.num = 119, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava21", +		.val.num   = 119, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava22", -		.val.num = 11, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava22", +		.val.num   = 11, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  	{ -		.config  = (char *) "krava23", -		.val.num = 2, -		.type    = PARSE_EVENTS__TERM_TYPE_NUM, +		.config    = (char *) "krava23", +		.val.num   = 2, +		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM, +		.type_term = PARSE_EVENTS__TERM_TYPE_USER,  	},  };  #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index e30749e38a9..4c1b3d72a1d 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -56,7 +56,7 @@ INTERP my_perl;  #define FTRACE_MAX_EVENT				\  	((1 << (sizeof(unsigned short) * 8)) - 1) -struct event *events[FTRACE_MAX_EVENT]; +struct event_format *events[FTRACE_MAX_EVENT];  extern struct scripting_context *scripting_context; @@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,  	LEAVE;  } -static void define_event_symbols(struct event *event, +static void define_event_symbols(struct event_format *event,  				 const char *ev_name,  				 struct print_arg *args)  { @@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,  		define_symbolic_values(args->symbol.symbols, ev_name,  				       cur_field_name);  		break; +	case PRINT_BSTRING: +	case PRINT_DYNAMIC_ARRAY:  	case PRINT_STRING:  		break;  	case PRINT_TYPE: @@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,  		define_event_symbols(event, ev_name, args->op.left);  		define_event_symbols(event, ev_name, args->op.right);  		break; +	case PRINT_FUNC:  	default: +		pr_err("Unsupported print arg type\n");  		/* we should warn... */  		return;  	} @@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,  		define_event_symbols(event, ev_name, args->next);  } -static inline struct event *find_cache_event(int type) +static inline struct event_format *find_cache_event(int type)  {  	static char ev_name[256]; -	struct event *event; +	struct event_format *event;  	if (events[type])  		return events[type]; @@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,  	static char handler[256];  	unsigned long long val;  	unsigned long s, ns; -	struct event *event; +	struct event_format *event;  	int type;  	int pid;  	int cpu = sample->cpu; @@ -446,7 +450,7 @@ static int perl_stop_script(void)  static int perl_generate_script(const char *outfile)  { -	struct event *event = NULL; +	struct event_format *event = NULL;  	struct format_field *f;  	char fname[PATH_MAX];  	int not_first, count; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index c2623c6f9b5..acb9795286c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -37,7 +37,7 @@ PyMODINIT_FUNC initperf_trace_context(void);  #define FTRACE_MAX_EVENT				\  	((1 << (sizeof(unsigned short) * 8)) - 1) -struct event *events[FTRACE_MAX_EVENT]; +struct event_format *events[FTRACE_MAX_EVENT];  #define MAX_FIELDS	64  #define N_COMMON_FIELDS	7 @@ -136,7 +136,7 @@ static void define_field(enum print_arg_type field_type,  	Py_DECREF(t);  } -static void define_event_symbols(struct event *event, +static void define_event_symbols(struct event_format *event,  				 const char *ev_name,  				 struct print_arg *args)  { @@ -178,6 +178,10 @@ static void define_event_symbols(struct event *event,  		define_event_symbols(event, ev_name, args->op.right);  		break;  	default: +		/* gcc warns for these? */ +	case PRINT_BSTRING: +	case PRINT_DYNAMIC_ARRAY: +	case PRINT_FUNC:  		/* we should warn... */  		return;  	} @@ -186,10 +190,10 @@ static void define_event_symbols(struct event *event,  		define_event_symbols(event, ev_name, args->next);  } -static inline struct event *find_cache_event(int type) +static inline struct event_format *find_cache_event(int type)  {  	static char ev_name[256]; -	struct event *event; +	struct event_format *event;  	if (events[type])  		return events[type]; @@ -216,7 +220,7 @@ static void python_process_event(union perf_event *pevent __unused,  	struct format_field *field;  	unsigned long long val;  	unsigned long s, ns; -	struct event *event; +	struct event_format *event;  	unsigned n = 0;  	int type;  	int pid; @@ -436,7 +440,7 @@ out:  static int python_generate_script(const char *outfile)  { -	struct event *event = NULL; +	struct event_format *event = NULL;  	struct format_field *f;  	char fname[PATH_MAX];  	int not_first, count; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1efd3bee633..93d355d2710 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -481,6 +481,38 @@ static void perf_event__read_swap(union perf_event *event)  	event->read.id		 = bswap_64(event->read.id);  } +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)  { @@ -494,6 +526,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr)  	attr->bp_type		= bswap_32(attr->bp_type);  	attr->bp_addr		= bswap_64(attr->bp_addr);  	attr->bp_len		= bswap_64(attr->bp_len); + +	swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));  }  static void perf_event__hdr_attr_swap(union perf_event *event) @@ -1064,8 +1098,9 @@ volatile int session_done;  static int __perf_session__process_pipe_events(struct perf_session *self,  					       struct perf_tool *tool)  { -	union perf_event event; -	uint32_t size; +	union perf_event *event; +	uint32_t size, cur_size = 0; +	void *buf = NULL;  	int skip = 0;  	u64 head;  	int err; @@ -1074,8 +1109,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,  	perf_tool__fill_defaults(tool);  	head = 0; +	cur_size = sizeof(union perf_event); + +	buf = malloc(cur_size); +	if (!buf) +		return -errno;  more: -	err = readn(self->fd, &event, sizeof(struct perf_event_header)); +	event = buf; +	err = readn(self->fd, event, sizeof(struct perf_event_header));  	if (err <= 0) {  		if (err == 0)  			goto done; @@ -1085,13 +1126,23 @@ more:  	}  	if (self->header.needs_swap) -		perf_event_header__bswap(&event.header); +		perf_event_header__bswap(&event->header); -	size = event.header.size; +	size = event->header.size;  	if (size == 0)  		size = 8; -	p = &event; +	if (size > cur_size) { +		void *new = realloc(buf, size); +		if (!new) { +			pr_err("failed to allocate memory to read event\n"); +			goto out_err; +		} +		buf = new; +		cur_size = size; +		event = buf; +	} +	p = event;  	p += sizeof(struct perf_event_header);  	if (size - sizeof(struct perf_event_header)) { @@ -1107,17 +1158,11 @@ more:  		}  	} -	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); -		/* -		 * assume we lost track of the stream, check alignment, and -		 * increment a single u64 in the hope to catch on again 'soon'. -		 */ -		if (unlikely(head & 7)) -			head &= ~7ULL; - -		size = 8; +	if ((skip = perf_session__process_event(self, event, tool, head)) < 0) { +		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", +		       head, event->header.size, event->header.type); +		err = -EINVAL; +		goto out_err;  	}  	head += size; @@ -1130,6 +1175,7 @@ more:  done:  	err = 0;  out_err: +	free(buf);  	perf_session__warn_about_errors(self, tool);  	perf_session_free_sample_buffers(self);  	return err; @@ -1226,17 +1272,11 @@ more:  	if (size == 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); -		/* -		 * assume we lost track of the stream, check alignment, and -		 * increment a single u64 in the hope to catch on again 'soon'. -		 */ -		if (unlikely(head & 7)) -			head &= ~7ULL; - -		size = 8; +		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", +		       file_offset + head, event->header.size, +		       event->header.type); +		err = -EINVAL; +		goto out_err;  	}  	head += size; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ac49ef208a5..1f003884f1a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -65,6 +65,11 @@ struct symbol {  void symbol__delete(struct symbol *sym); +static inline size_t symbol__size(const struct symbol *sym) +{ +	return sym->end - sym->start + 1; +} +  struct strlist;  struct symbol_conf { diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c new file mode 100644 index 00000000000..1064d5b148a --- /dev/null +++ b/tools/perf/util/target.c @@ -0,0 +1,142 @@ +/* + * Helper functions for handling target threads/cpus + * + * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com> + * + * Released under the GPL v2. + */ + +#include "target.h" +#include "debug.h" + +#include <pwd.h> +#include <string.h> + + +enum perf_target_errno perf_target__validate(struct perf_target *target) +{ +	enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS; + +	if (target->pid) +		target->tid = target->pid; + +	/* CPU and PID are mutually exclusive */ +	if (target->tid && target->cpu_list) { +		target->cpu_list = NULL; +		if (ret == PERF_ERRNO_TARGET__SUCCESS) +			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU; +	} + +	/* UID and PID are mutually exclusive */ +	if (target->tid && target->uid_str) { +		target->uid_str = NULL; +		if (ret == PERF_ERRNO_TARGET__SUCCESS) +			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID; +	} + +	/* UID and CPU are mutually exclusive */ +	if (target->uid_str && target->cpu_list) { +		target->cpu_list = NULL; +		if (ret == PERF_ERRNO_TARGET__SUCCESS) +			ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU; +	} + +	/* PID and SYSTEM are mutually exclusive */ +	if (target->tid && target->system_wide) { +		target->system_wide = false; +		if (ret == PERF_ERRNO_TARGET__SUCCESS) +			ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM; +	} + +	/* UID and SYSTEM are mutually exclusive */ +	if (target->uid_str && target->system_wide) { +		target->system_wide = false; +		if (ret == PERF_ERRNO_TARGET__SUCCESS) +			ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM; +	} + +	return ret; +} + +enum perf_target_errno perf_target__parse_uid(struct perf_target *target) +{ +	struct passwd pwd, *result; +	char buf[1024]; +	const char *str = target->uid_str; + +	target->uid = UINT_MAX; +	if (str == NULL) +		return PERF_ERRNO_TARGET__SUCCESS; + +	/* Try user name first */ +	getpwnam_r(str, &pwd, buf, sizeof(buf), &result); + +	if (result == NULL) { +		/* +		 * The user name not found. Maybe it's a UID number. +		 */ +		char *endptr; +		int uid = strtol(str, &endptr, 10); + +		if (*endptr != '\0') +			return PERF_ERRNO_TARGET__INVALID_UID; + +		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); + +		if (result == NULL) +			return PERF_ERRNO_TARGET__USER_NOT_FOUND; +	} + +	target->uid = result->pw_uid; +	return PERF_ERRNO_TARGET__SUCCESS; +} + +/* + * This must have a same ordering as the enum perf_target_errno. + */ +static const char *perf_target__error_str[] = { +	"PID/TID switch overriding CPU", +	"PID/TID switch overriding UID", +	"UID switch overriding CPU", +	"PID/TID switch overriding SYSTEM", +	"UID switch overriding SYSTEM", +	"Invalid User: %s", +	"Problems obtaining information for user %s", +}; + +int perf_target__strerror(struct perf_target *target, int errnum, +			  char *buf, size_t buflen) +{ +	int idx; +	const char *msg; + +	if (errnum >= 0) { +		strerror_r(errnum, buf, buflen); +		return 0; +	} + +	if (errnum <  __PERF_ERRNO_TARGET__START || +	    errnum >= __PERF_ERRNO_TARGET__END) +		return -1; + +	idx = errnum - __PERF_ERRNO_TARGET__START; +	msg = perf_target__error_str[idx]; + +	switch (errnum) { +	case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU +	 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM: +		snprintf(buf, buflen, "%s", msg); +		break; + +	case PERF_ERRNO_TARGET__INVALID_UID: +	case PERF_ERRNO_TARGET__USER_NOT_FOUND: +		snprintf(buf, buflen, msg, target->uid_str); +		break; + +	default: +		/* cannot reach here */ +		break; +	} + +	return 0; +} diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h new file mode 100644 index 00000000000..a4be8575fda --- /dev/null +++ b/tools/perf/util/target.h @@ -0,0 +1,65 @@ +#ifndef _PERF_TARGET_H +#define _PERF_TARGET_H + +#include <stdbool.h> +#include <sys/types.h> + +struct perf_target { +	const char   *pid; +	const char   *tid; +	const char   *cpu_list; +	const char   *uid_str; +	uid_t	     uid; +	bool	     system_wide; +	bool	     uses_mmap; +}; + +enum perf_target_errno { +	PERF_ERRNO_TARGET__SUCCESS		= 0, + +	/* +	 * Choose an arbitrary negative big number not to clash with standard +	 * errno since SUS requires the errno has distinct positive values. +	 * See 'Issue 6' in the link below. +	 * +	 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html +	 */ +	__PERF_ERRNO_TARGET__START		= -10000, + + +	/* for perf_target__validate() */ +	PERF_ERRNO_TARGET__PID_OVERRIDE_CPU	= __PERF_ERRNO_TARGET__START, +	PERF_ERRNO_TARGET__PID_OVERRIDE_UID, +	PERF_ERRNO_TARGET__UID_OVERRIDE_CPU, +	PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM, +	PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM, + +	/* for perf_target__parse_uid() */ +	PERF_ERRNO_TARGET__INVALID_UID, +	PERF_ERRNO_TARGET__USER_NOT_FOUND, + +	__PERF_ERRNO_TARGET__END, +}; + +enum perf_target_errno perf_target__validate(struct perf_target *target); +enum perf_target_errno perf_target__parse_uid(struct perf_target *target); + +int perf_target__strerror(struct perf_target *target, int errnum, char *buf, +			  size_t buflen); + +static inline bool perf_target__has_task(struct perf_target *target) +{ +	return target->tid || target->pid || target->uid_str; +} + +static inline bool perf_target__has_cpu(struct perf_target *target) +{ +	return target->system_wide || target->cpu_list; +} + +static inline bool perf_target__none(struct perf_target *target) +{ +	return !perf_target__has_task(target) && !perf_target__has_cpu(target); +} + +#endif /* _PERF_TARGET_H */ diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 7da80f14418..f718df8a3c5 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -6,7 +6,7 @@  struct thread_map {  	int nr; -	int map[]; +	pid_t map[];  };  struct thread_map *thread_map__new_by_pid(pid_t pid); diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 09fe579ccaf..abe0e8e9506 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)  	ret += SNPRINTF(bf + ret, size - ret, "], "); -	if (top->target_pid) +	if (top->target.pid)  		ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", -				top->target_pid); -	else if (top->target_tid) +				top->target.pid); +	else if (top->target.tid)  		ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", -				top->target_tid); -	else if (top->uid_str != NULL) +				top->target.tid); +	else if (top->target.uid_str != NULL)  		ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", -				top->uid_str); +				top->target.uid_str);  	else  		ret += SNPRINTF(bf + ret, size - ret, " (all"); -	if (top->cpu_list) +	if (top->target.cpu_list)  		ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", -				top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); +				top->evlist->cpus->nr > 1 ? "s" : "", +				top->target.cpu_list);  	else { -		if (top->target_tid) +		if (top->target.tid)  			ret += SNPRINTF(bf + ret, size - ret, ")");  		else  			ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index ce61cb2d1ac..33347ca89ee 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -13,6 +13,7 @@ struct perf_session;  struct perf_top {  	struct perf_tool   tool;  	struct perf_evlist *evlist; +	struct perf_target target;  	/*  	 * Symbols will be added here in perf_event__process_sample and will  	 * get out after decayed. @@ -23,10 +24,7 @@ struct perf_top {  	u64		   guest_us_samples, guest_kernel_samples;  	int		   print_entries, count_filter, delay_secs;  	int		   freq; -	const char	   *target_pid, *target_tid; -	uid_t		   uid;  	bool		   hide_kernel_symbols, hide_user_symbols, zero; -	bool		   system_wide;  	bool		   use_tui, use_stdio;  	bool		   sort_has_symbols;  	bool		   dont_use_callchains; @@ -37,7 +35,6 @@ struct perf_top {  	bool		   sample_id_all_missing;  	bool		   exclude_guest_missing;  	bool		   dump_symtab; -	const char	   *cpu_list;  	struct hist_entry  *sym_filter_entry;  	struct perf_evsel  *sym_evsel;  	struct perf_session *session; @@ -47,7 +44,6 @@ struct perf_top {  	int		   realtime_prio;  	int		   sym_pcnt_filter;  	const char	   *sym_filter; -	const char	   *uid_str;  };  size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index fc22cf5c605..a8d81c35ef6 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -68,7 +68,7 @@ struct events {  }; -void *malloc_or_die(unsigned int size) +static void *malloc_or_die(unsigned int size)  {  	void *data; @@ -448,6 +448,8 @@ static void tracing_data_header(void)  	else  		buf[0] = 0; +	read_trace_init(buf[0], buf[0]); +  	write_or_die(buf, 1);  	/* save size of long */ diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index dfd1bd8371a..df2fddbf0cd 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -17,2169 +17,305 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   *   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - *  The parts for function graph printing was taken and modified from the - *  Linux Kernel that were written by Frederic Weisbecker.   */ -  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <ctype.h>  #include <errno.h>  #include "../perf.h"  #include "util.h"  #include "trace-event.h" -int header_page_ts_offset; -int header_page_ts_size; -int header_page_size_offset;  int header_page_size_size; -int header_page_overwrite_offset; -int header_page_overwrite_size; +int header_page_ts_size;  int header_page_data_offset; -int header_page_data_size; - -bool latency_format; - -static char *input_buf; -static unsigned long long input_buf_ptr; -static unsigned long long input_buf_siz; - -static int cpus; -static int long_size; -static int is_flag_field; -static int is_symbolic_field; -static struct format_field * -find_any_field(struct event *event, const char *name); +struct pevent *perf_pevent; +static struct pevent *pevent; -static void init_input_buf(char *buf, unsigned long long size) -{ -	input_buf = buf; -	input_buf_siz = size; -	input_buf_ptr = 0; -} - -struct cmdline { -	char *comm; -	int pid; -}; - -static struct cmdline *cmdlines; -static int cmdline_count; - -static int cmdline_cmp(const void *a, const void *b) -{ -	const struct cmdline *ca = a; -	const struct cmdline *cb = b; - -	if (ca->pid < cb->pid) -		return -1; -	if (ca->pid > cb->pid) -		return 1; - -	return 0; -} - -void parse_cmdlines(char *file, int size __unused) -{ -	struct cmdline_list { -		struct cmdline_list	*next; -		char			*comm; -		int			pid; -	} *list = NULL, *item; -	char *line; -	char *next = NULL; -	int i; - -	line = strtok_r(file, "\n", &next); -	while (line) { -		item = malloc_or_die(sizeof(*item)); -		sscanf(line, "%d %as", &item->pid, -		       (float *)(void *)&item->comm); /* workaround gcc warning */ -		item->next = list; -		list = item; -		line = strtok_r(NULL, "\n", &next); -		cmdline_count++; -	} - -	cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count); - -	i = 0; -	while (list) { -		cmdlines[i].pid = list->pid; -		cmdlines[i].comm = list->comm; -		i++; -		item = list; -		list = list->next; -		free(item); -	} - -	qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp); -} - -static struct func_map { -	unsigned long long		addr; -	char				*func; -	char				*mod; -} *func_list; -static unsigned int func_count; - -static int func_cmp(const void *a, const void *b) -{ -	const struct func_map *fa = a; -	const struct func_map *fb = b; - -	if (fa->addr < fb->addr) -		return -1; -	if (fa->addr > fb->addr) -		return 1; - -	return 0; -} - -void parse_proc_kallsyms(char *file, unsigned int size __unused) -{ -	struct func_list { -		struct func_list	*next; -		unsigned long long	addr; -		char			*func; -		char			*mod; -	} *list = NULL, *item; -	char *line; -	char *next = NULL; -	char *addr_str; -	char ch; -	int ret __used; -	int i; - -	line = strtok_r(file, "\n", &next); -	while (line) { -		item = malloc_or_die(sizeof(*item)); -		item->mod = NULL; -		ret = sscanf(line, "%as %c %as\t[%as", -			     (float *)(void *)&addr_str, /* workaround gcc warning */ -			     &ch, -			     (float *)(void *)&item->func, -			     (float *)(void *)&item->mod); -		item->addr = strtoull(addr_str, NULL, 16); -		free(addr_str); - -		/* truncate the extra ']' */ -		if (item->mod) -			item->mod[strlen(item->mod) - 1] = 0; - - -		item->next = list; -		list = item; -		line = strtok_r(NULL, "\n", &next); -		func_count++; -	} - -	func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1)); - -	i = 0; -	while (list) { -		func_list[i].func = list->func; -		func_list[i].addr = list->addr; -		func_list[i].mod = list->mod; -		i++; -		item = list; -		list = list->next; -		free(item); -	} - -	qsort(func_list, func_count, sizeof(*func_list), func_cmp); - -	/* -	 * Add a special record at the end. -	 */ -	func_list[func_count].func = NULL; -	func_list[func_count].addr = 0; -	func_list[func_count].mod = NULL; -} +bool latency_format; -/* - * We are searching for a record in between, not an exact - * match. - */ -static int func_bcmp(const void *a, const void *b) +int read_trace_init(int file_bigendian, int host_bigendian)  { -	const struct func_map *fa = a; -	const struct func_map *fb = b; - -	if ((fa->addr == fb->addr) || - -	    (fa->addr > fb->addr && -	     fa->addr < (fb+1)->addr)) +	if (pevent)  		return 0; -	if (fa->addr < fb->addr) -		return -1; - -	return 1; -} - -static struct func_map *find_func(unsigned long long addr) -{ -	struct func_map *func; -	struct func_map key; - -	key.addr = addr; - -	func = bsearch(&key, func_list, func_count, sizeof(*func_list), -		       func_bcmp); - -	return func; -} - -void print_funcs(void) -{ -	int i; - -	for (i = 0; i < (int)func_count; i++) { -		printf("%016llx %s", -		       func_list[i].addr, -		       func_list[i].func); -		if (func_list[i].mod) -			printf(" [%s]\n", func_list[i].mod); -		else -			printf("\n"); -	} -} - -static struct printk_map { -	unsigned long long		addr; -	char				*printk; -} *printk_list; -static unsigned int printk_count; +	perf_pevent = pevent_alloc(); +	pevent = perf_pevent; -static int printk_cmp(const void *a, const void *b) -{ -	const struct func_map *fa = a; -	const struct func_map *fb = b; - -	if (fa->addr < fb->addr) -		return -1; -	if (fa->addr > fb->addr) -		return 1; +	pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); +	pevent_set_file_bigendian(pevent, file_bigendian); +	pevent_set_host_bigendian(pevent, host_bigendian);  	return 0;  } -static struct printk_map *find_printk(unsigned long long addr) -{ -	struct printk_map *printk; -	struct printk_map key; - -	key.addr = addr; - -	printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list), -			 printk_cmp); - -	return printk; -} - -void parse_ftrace_printk(char *file, unsigned int size __unused) -{ -	struct printk_list { -		struct printk_list	*next; -		unsigned long long	addr; -		char			*printk; -	} *list = NULL, *item; -	char *line; -	char *next = NULL; -	char *addr_str; -	int i; - -	line = strtok_r(file, "\n", &next); -	while (line) { -		addr_str = strsep(&line, ":"); -		if (!line) { -			warning("error parsing print strings"); -			break; -		} -		item = malloc_or_die(sizeof(*item)); -		item->addr = strtoull(addr_str, NULL, 16); -		/* fmt still has a space, skip it */ -		item->printk = strdup(line+1); -		item->next = list; -		list = item; -		line = strtok_r(NULL, "\n", &next); -		printk_count++; -	} - -	printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1); - -	i = 0; -	while (list) { -		printk_list[i].printk = list->printk; -		printk_list[i].addr = list->addr; -		i++; -		item = list; -		list = list->next; -		free(item); -	} - -	qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp); -} - -void print_printk(void) -{ -	int i; - -	for (i = 0; i < (int)printk_count; i++) { -		printf("%016llx %s\n", -		       printk_list[i].addr, -		       printk_list[i].printk); -	} -} - -static struct event *alloc_event(void) -{ -	struct event *event; - -	event = malloc_or_die(sizeof(*event)); -	memset(event, 0, sizeof(*event)); - -	return event; -} - -enum event_type { -	EVENT_ERROR, -	EVENT_NONE, -	EVENT_SPACE, -	EVENT_NEWLINE, -	EVENT_OP, -	EVENT_DELIM, -	EVENT_ITEM, -	EVENT_DQUOTE, -	EVENT_SQUOTE, -}; - -static struct event *event_list; - -static void add_event(struct event *event) -{ -	event->next = event_list; -	event_list = event; -} - -static int event_item_type(enum event_type type) +static int get_common_field(struct scripting_context *context, +			    int *offset, int *size, const char *type)  { -	switch (type) { -	case EVENT_ITEM ... EVENT_SQUOTE: -		return 1; -	case EVENT_ERROR ... EVENT_DELIM: -	default: -		return 0; -	} -} - -static void free_arg(struct print_arg *arg) -{ -	if (!arg) -		return; - -	switch (arg->type) { -	case PRINT_ATOM: -		if (arg->atom.atom) -			free(arg->atom.atom); -		break; -	case PRINT_NULL: -	case PRINT_FIELD ... PRINT_OP: -	default: -		/* todo */ -		break; -	} - -	free(arg); -} - -static enum event_type get_type(int ch) -{ -	if (ch == '\n') -		return EVENT_NEWLINE; -	if (isspace(ch)) -		return EVENT_SPACE; -	if (isalnum(ch) || ch == '_') -		return EVENT_ITEM; -	if (ch == '\'') -		return EVENT_SQUOTE; -	if (ch == '"') -		return EVENT_DQUOTE; -	if (!isprint(ch)) -		return EVENT_NONE; -	if (ch == '(' || ch == ')' || ch == ',') -		return EVENT_DELIM; - -	return EVENT_OP; -} - -static int __read_char(void) -{ -	if (input_buf_ptr >= input_buf_siz) -		return -1; - -	return input_buf[input_buf_ptr++]; -} - -static int __peek_char(void) -{ -	if (input_buf_ptr >= input_buf_siz) -		return -1; - -	return input_buf[input_buf_ptr]; -} - -static enum event_type __read_token(char **tok) -{ -	char buf[BUFSIZ]; -	int ch, last_ch, quote_ch, next_ch; -	int i = 0; -	int tok_size = 0; -	enum event_type type; - -	*tok = NULL; - - -	ch = __read_char(); -	if (ch < 0) -		return EVENT_NONE; - -	type = get_type(ch); -	if (type == EVENT_NONE) -		return type; - -	buf[i++] = ch; - -	switch (type) { -	case EVENT_NEWLINE: -	case EVENT_DELIM: -		*tok = malloc_or_die(2); -		(*tok)[0] = ch; -		(*tok)[1] = 0; -		return type; - -	case EVENT_OP: -		switch (ch) { -		case '-': -			next_ch = __peek_char(); -			if (next_ch == '>') { -				buf[i++] = __read_char(); -				break; -			} -			/* fall through */ -		case '+': -		case '|': -		case '&': -		case '>': -		case '<': -			last_ch = ch; -			ch = __peek_char(); -			if (ch != last_ch) -				goto test_equal; -			buf[i++] = __read_char(); -			switch (last_ch) { -			case '>': -			case '<': -				goto test_equal; -			default: -				break; -			} -			break; -		case '!': -		case '=': -			goto test_equal; -		default: /* what should we do instead? */ -			break; -		} -		buf[i] = 0; -		*tok = strdup(buf); -		return type; - - test_equal: -		ch = __peek_char(); -		if (ch == '=') -			buf[i++] = __read_char(); -		break; - -	case EVENT_DQUOTE: -	case EVENT_SQUOTE: -		/* don't keep quotes */ -		i--; -		quote_ch = ch; -		last_ch = 0; -		do { -			if (i == (BUFSIZ - 1)) { -				buf[i] = 0; -				if (*tok) { -					*tok = realloc(*tok, tok_size + BUFSIZ); -					if (!*tok) -						return EVENT_NONE; -					strcat(*tok, buf); -				} else -					*tok = strdup(buf); - -				if (!*tok) -					return EVENT_NONE; -				tok_size += BUFSIZ; -				i = 0; -			} -			last_ch = ch; -			ch = __read_char(); -			buf[i++] = ch; -			/* the '\' '\' will cancel itself */ -			if (ch == '\\' && last_ch == '\\') -				last_ch = 0; -		} while (ch != quote_ch || last_ch == '\\'); -		/* remove the last quote */ -		i--; -		goto out; - -	case EVENT_ERROR ... EVENT_SPACE: -	case EVENT_ITEM: -	default: -		break; -	} - -	while (get_type(__peek_char()) == type) { -		if (i == (BUFSIZ - 1)) { -			buf[i] = 0; -			if (*tok) { -				*tok = realloc(*tok, tok_size + BUFSIZ); -				if (!*tok) -					return EVENT_NONE; -				strcat(*tok, buf); -			} else -				*tok = strdup(buf); - -			if (!*tok) -				return EVENT_NONE; -			tok_size += BUFSIZ; -			i = 0; -		} -		ch = __read_char(); -		buf[i++] = ch; -	} - - out: -	buf[i] = 0; -	if (*tok) { -		*tok = realloc(*tok, tok_size + i); -		if (!*tok) -			return EVENT_NONE; -		strcat(*tok, buf); -	} else -		*tok = strdup(buf); -	if (!*tok) -		return EVENT_NONE; - -	return type; -} - -static void free_token(char *tok) -{ -	if (tok) -		free(tok); -} - -static enum event_type read_token(char **tok) -{ -	enum event_type type; - -	for (;;) { -		type = __read_token(tok); -		if (type != EVENT_SPACE) -			return type; - -		free_token(*tok); -	} - -	/* not reached */ -	return EVENT_NONE; -} - -/* no newline */ -static enum event_type read_token_item(char **tok) -{ -	enum event_type type; - -	for (;;) { -		type = __read_token(tok); -		if (type != EVENT_SPACE && type != EVENT_NEWLINE) -			return type; - -		free_token(*tok); -	} - -	/* not reached */ -	return EVENT_NONE; -} - -static int test_type(enum event_type type, enum event_type expect) -{ -	if (type != expect) { -		warning("Error: expected type %d but read %d", -		    expect, type); -		return -1; -	} -	return 0; -} +	struct event_format *event; +	struct format_field *field; -static int __test_type_token(enum event_type type, char *token, -			     enum event_type expect, const char *expect_tok, -			     bool warn) -{ -	if (type != expect) { -		if (warn) -			warning("Error: expected type %d but read %d", -				expect, type); -		return -1; -	} +	if (!*size) { +		if (!pevent->events) +			return 0; -	if (strcmp(token, expect_tok) != 0) { -		if (warn) -			warning("Error: expected '%s' but read '%s'", -				expect_tok, token); -		return -1; +		event = pevent->events[0]; +		field = pevent_find_common_field(event, type); +		if (!field) +			return 0; +		*offset = field->offset; +		*size = field->size;  	} -	return 0; -} -static int test_type_token(enum event_type type, char *token, -			   enum event_type expect, const char *expect_tok) -{ -	return __test_type_token(type, token, expect, expect_tok, true); +	return pevent_read_number(pevent, context->event_data + *offset, *size);  } -static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) -{ -	enum event_type type; - -	if (newline_ok) -		type = read_token(tok); -	else -		type = read_token_item(tok); -	return test_type(type, expect); -} - -static int read_expect_type(enum event_type expect, char **tok) -{ -	return __read_expect_type(expect, tok, 1); -} - -static int __read_expected(enum event_type expect, const char *str, -			   int newline_ok, bool warn) +int common_lock_depth(struct scripting_context *context)  { -	enum event_type type; -	char *token; +	static int offset; +	static int size;  	int ret; -	if (newline_ok) -		type = read_token(&token); -	else -		type = read_token_item(&token); - -	ret = __test_type_token(type, token, expect, str, warn); - -	free_token(token); +	ret = get_common_field(context, &size, &offset, +			       "common_lock_depth"); +	if (ret < 0) +		return -1;  	return ret;  } -static int read_expected(enum event_type expect, const char *str) -{ -	return __read_expected(expect, str, 1, true); -} - -static int read_expected_item(enum event_type expect, const char *str) -{ -	return __read_expected(expect, str, 0, true); -} - -static char *event_read_name(void) -{ -	char *token; - -	if (read_expected(EVENT_ITEM, "name") < 0) -		return NULL; - -	if (read_expected(EVENT_OP, ":") < 0) -		return NULL; - -	if (read_expect_type(EVENT_ITEM, &token) < 0) -		goto fail; - -	return token; - - fail: -	free_token(token); -	return NULL; -} - -static int event_read_id(void) +int common_flags(struct scripting_context *context)  { -	char *token; -	int id = -1; - -	if (read_expected_item(EVENT_ITEM, "ID") < 0) -		return -1; +	static int offset; +	static int size; +	int ret; -	if (read_expected(EVENT_OP, ":") < 0) +	ret = get_common_field(context, &size, &offset, +			       "common_flags"); +	if (ret < 0)  		return -1; -	if (read_expect_type(EVENT_ITEM, &token) < 0) -		goto free; - -	id = strtoul(token, NULL, 0); - - free: -	free_token(token); -	return id; -} - -static int field_is_string(struct format_field *field) -{ -	if ((field->flags & FIELD_IS_ARRAY) && -	    (!strstr(field->type, "char") || !strstr(field->type, "u8") || -	     !strstr(field->type, "s8"))) -		return 1; - -	return 0; -} - -static int field_is_dynamic(struct format_field *field) -{ -	if (!strncmp(field->type, "__data_loc", 10)) -		return 1; - -	return 0; -} - -static int event_read_fields(struct event *event, struct format_field **fields) -{ -	struct format_field *field = NULL; -	enum event_type type; -	char *token; -	char *last_token; -	int count = 0; - -	do { -		type = read_token(&token); -		if (type == EVENT_NEWLINE) { -			free_token(token); -			return count; -		} - -		count++; - -		if (test_type_token(type, token, EVENT_ITEM, "field")) -			goto fail; -		free_token(token); - -		type = read_token(&token); -		/* -		 * The ftrace fields may still use the "special" name. -		 * Just ignore it. -		 */ -		if (event->flags & EVENT_FL_ISFTRACE && -		    type == EVENT_ITEM && strcmp(token, "special") == 0) { -			free_token(token); -			type = read_token(&token); -		} - -		if (test_type_token(type, token, EVENT_OP, ":") < 0) -			return -1; - -		if (read_expect_type(EVENT_ITEM, &token) < 0) -			goto fail; - -		last_token = token; - -		field = malloc_or_die(sizeof(*field)); -		memset(field, 0, sizeof(*field)); - -		/* read the rest of the type */ -		for (;;) { -			type = read_token(&token); -			if (type == EVENT_ITEM || -			    (type == EVENT_OP && strcmp(token, "*") == 0) || -			    /* -			     * Some of the ftrace fields are broken and have -			     * an illegal "." in them. -			     */ -			    (event->flags & EVENT_FL_ISFTRACE && -			     type == EVENT_OP && strcmp(token, ".") == 0)) { - -				if (strcmp(token, "*") == 0) -					field->flags |= FIELD_IS_POINTER; - -				if (field->type) { -					field->type = realloc(field->type, -							      strlen(field->type) + -							      strlen(last_token) + 2); -					strcat(field->type, " "); -					strcat(field->type, last_token); -				} else -					field->type = last_token; -				last_token = token; -				continue; -			} - -			break; -		} - -		if (!field->type) { -			die("no type found"); -			goto fail; -		} -		field->name = last_token; - -		if (test_type(type, EVENT_OP)) -			goto fail; - -		if (strcmp(token, "[") == 0) { -			enum event_type last_type = type; -			char *brackets = token; -			int len; - -			field->flags |= FIELD_IS_ARRAY; - -			type = read_token(&token); -		        while (strcmp(token, "]") != 0) { -				if (last_type == EVENT_ITEM && -				    type == EVENT_ITEM) -					len = 2; -				else -					len = 1; -				last_type = type; - -				brackets = realloc(brackets, -						   strlen(brackets) + -						   strlen(token) + len); -				if (len == 2) -					strcat(brackets, " "); -				strcat(brackets, token); -				free_token(token); -				type = read_token(&token); -				if (type == EVENT_NONE) { -					die("failed to find token"); -					goto fail; -				} -			} - -			free_token(token); - -			brackets = realloc(brackets, strlen(brackets) + 2); -			strcat(brackets, "]"); - -			/* add brackets to type */ - -			type = read_token(&token); -			/* -			 * If the next token is not an OP, then it is of -			 * the format: type [] item; -			 */ -			if (type == EVENT_ITEM) { -				field->type = realloc(field->type, -						      strlen(field->type) + -						      strlen(field->name) + -						      strlen(brackets) + 2); -				strcat(field->type, " "); -				strcat(field->type, field->name); -				free_token(field->name); -				strcat(field->type, brackets); -				field->name = token; -				type = read_token(&token); -			} else { -				field->type = realloc(field->type, -						      strlen(field->type) + -						      strlen(brackets) + 1); -				strcat(field->type, brackets); -			} -			free(brackets); -		} - -		if (field_is_string(field)) { -			field->flags |= FIELD_IS_STRING; -			if (field_is_dynamic(field)) -				field->flags |= FIELD_IS_DYNAMIC; -		} - -		if (test_type_token(type, token,  EVENT_OP, ";")) -			goto fail; -		free_token(token); - -		if (read_expected(EVENT_ITEM, "offset") < 0) -			goto fail_expect; - -		if (read_expected(EVENT_OP, ":") < 0) -			goto fail_expect; - -		if (read_expect_type(EVENT_ITEM, &token)) -			goto fail; -		field->offset = strtoul(token, NULL, 0); -		free_token(token); - -		if (read_expected(EVENT_OP, ";") < 0) -			goto fail_expect; - -		if (read_expected(EVENT_ITEM, "size") < 0) -			goto fail_expect; - -		if (read_expected(EVENT_OP, ":") < 0) -			goto fail_expect; - -		if (read_expect_type(EVENT_ITEM, &token)) -			goto fail; -		field->size = strtoul(token, NULL, 0); -		free_token(token); - -		if (read_expected(EVENT_OP, ";") < 0) -			goto fail_expect; - -		type = read_token(&token); -		if (type != EVENT_NEWLINE) { -			/* newer versions of the kernel have a "signed" type */ -			if (test_type_token(type, token, EVENT_ITEM, "signed")) -				goto fail; - -			free_token(token); - -			if (read_expected(EVENT_OP, ":") < 0) -				goto fail_expect; - -			if (read_expect_type(EVENT_ITEM, &token)) -				goto fail; - -			if (strtoul(token, NULL, 0)) -				field->flags |= FIELD_IS_SIGNED; - -			free_token(token); -			if (read_expected(EVENT_OP, ";") < 0) -				goto fail_expect; - -			if (read_expect_type(EVENT_NEWLINE, &token)) -				goto fail; -		} - -		free_token(token); - -		*fields = field; -		fields = &field->next; - -	} while (1); - -	return 0; - -fail: -	free_token(token); -fail_expect: -	if (field) -		free(field); -	return -1; +	return ret;  } -static int event_read_format(struct event *event) +int common_pc(struct scripting_context *context)  { -	char *token; +	static int offset; +	static int size;  	int ret; -	if (read_expected_item(EVENT_ITEM, "format") < 0) -		return -1; - -	if (read_expected(EVENT_OP, ":") < 0) -		return -1; - -	if (read_expect_type(EVENT_NEWLINE, &token)) -		goto fail; -	free_token(token); - -	ret = event_read_fields(event, &event->format.common_fields); -	if (ret < 0) -		return ret; -	event->format.nr_common = ret; - -	ret = event_read_fields(event, &event->format.fields); +	ret = get_common_field(context, &size, &offset, +			       "common_preempt_count");  	if (ret < 0) -		return ret; -	event->format.nr_fields = ret; - -	return 0; - - fail: -	free_token(token); -	return -1; -} - -enum event_type -process_arg_token(struct event *event, struct print_arg *arg, -		  char **tok, enum event_type type); - -static enum event_type -process_arg(struct event *event, struct print_arg *arg, char **tok) -{ -	enum event_type type; -	char *token; - -	type = read_token(&token); -	*tok = token; +		return -1; -	return process_arg_token(event, arg, tok, type); +	return ret;  } -static enum event_type -process_cond(struct event *event, struct print_arg *top, char **tok) +unsigned long long +raw_field_value(struct event_format *event, const char *name, void *data)  { -	struct print_arg *arg, *left, *right; -	enum event_type type; -	char *token = NULL; - -	arg = malloc_or_die(sizeof(*arg)); -	memset(arg, 0, sizeof(*arg)); - -	left = malloc_or_die(sizeof(*left)); - -	right = malloc_or_die(sizeof(*right)); - -	arg->type = PRINT_OP; -	arg->op.left = left; -	arg->op.right = right; - -	*tok = NULL; -	type = process_arg(event, left, &token); -	if (test_type_token(type, token, EVENT_OP, ":")) -		goto out_free; - -	arg->op.op = token; - -	type = process_arg(event, right, &token); +	struct format_field *field; +	unsigned long long val; -	top->op.right = arg; +	field = pevent_find_any_field(event, name); +	if (!field) +		return 0ULL; -	*tok = token; -	return type; +	pevent_read_number_field(field, data, &val); -out_free: -	free_token(*tok); -	free(right); -	free(left); -	free_arg(arg); -	return EVENT_ERROR; +	return val;  } -static enum event_type -process_array(struct event *event, struct print_arg *top, char **tok) +void *raw_field_ptr(struct event_format *event, const char *name, void *data)  { -	struct print_arg *arg; -	enum event_type type; -	char *token = NULL; - -	arg = malloc_or_die(sizeof(*arg)); -	memset(arg, 0, sizeof(*arg)); - -	*tok = NULL; -	type = process_arg(event, arg, &token); -	if (test_type_token(type, token, EVENT_OP, "]")) -		goto out_free; - -	top->op.right = arg; - -	free_token(token); -	type = read_token_item(&token); -	*tok = token; - -	return type; +	struct format_field *field; -out_free: -	free_token(*tok); -	free_arg(arg); -	return EVENT_ERROR; -} +	field = pevent_find_any_field(event, name); +	if (!field) +		return NULL; -static int get_op_prio(char *op) -{ -	if (!op[1]) { -		switch (op[0]) { -		case '*': -		case '/': -		case '%': -			return 6; -		case '+': -		case '-': -			return 7; -			/* '>>' and '<<' are 8 */ -		case '<': -		case '>': -			return 9; -			/* '==' and '!=' are 10 */ -		case '&': -			return 11; -		case '^': -			return 12; -		case '|': -			return 13; -		case '?': -			return 16; -		default: -			die("unknown op '%c'", op[0]); -			return -1; -		} -	} else { -		if (strcmp(op, "++") == 0 || -		    strcmp(op, "--") == 0) { -			return 3; -		} else if (strcmp(op, ">>") == 0 || -			   strcmp(op, "<<") == 0) { -			return 8; -		} else if (strcmp(op, ">=") == 0 || -			   strcmp(op, "<=") == 0) { -			return 9; -		} else if (strcmp(op, "==") == 0 || -			   strcmp(op, "!=") == 0) { -			return 10; -		} else if (strcmp(op, "&&") == 0) { -			return 14; -		} else if (strcmp(op, "||") == 0) { -			return 15; -		} else { -			die("unknown op '%s'", op); -			return -1; -		} -	} -} +	if (field->flags & FIELD_IS_DYNAMIC) { +		int offset; -static void set_op_prio(struct print_arg *arg) -{ +		offset = *(int *)(data + field->offset); +		offset &= 0xffff; -	/* single ops are the greatest */ -	if (!arg->op.left || arg->op.left->type == PRINT_NULL) { -		arg->op.prio = 0; -		return; +		return data + offset;  	} -	arg->op.prio = get_op_prio(arg->op.op); +	return data + field->offset;  } -static enum event_type -process_op(struct event *event, struct print_arg *arg, char **tok) +int trace_parse_common_type(void *data)  { -	struct print_arg *left, *right = NULL; -	enum event_type type; -	char *token; - -	/* the op is passed in via tok */ -	token = *tok; - -	if (arg->type == PRINT_OP && !arg->op.left) { -		/* handle single op */ -		if (token[1]) { -			die("bad op token %s", token); -			return EVENT_ERROR; -		} -		switch (token[0]) { -		case '!': -		case '+': -		case '-': -			break; -		default: -			die("bad op token %s", token); -			return EVENT_ERROR; -		} - -		/* make an empty left */ -		left = malloc_or_die(sizeof(*left)); -		left->type = PRINT_NULL; -		arg->op.left = left; - -		right = malloc_or_die(sizeof(*right)); -		arg->op.right = right; - -		type = process_arg(event, right, tok); - -	} else if (strcmp(token, "?") == 0) { - -		left = malloc_or_die(sizeof(*left)); -		/* copy the top arg to the left */ -		*left = *arg; - -		arg->type = PRINT_OP; -		arg->op.op = token; -		arg->op.left = left; -		arg->op.prio = 0; - -		type = process_cond(event, arg, tok); - -	} else if (strcmp(token, ">>") == 0 || -		   strcmp(token, "<<") == 0 || -		   strcmp(token, "&") == 0 || -		   strcmp(token, "|") == 0 || -		   strcmp(token, "&&") == 0 || -		   strcmp(token, "||") == 0 || -		   strcmp(token, "-") == 0 || -		   strcmp(token, "+") == 0 || -		   strcmp(token, "*") == 0 || -		   strcmp(token, "^") == 0 || -		   strcmp(token, "/") == 0 || -		   strcmp(token, "<") == 0 || -		   strcmp(token, ">") == 0 || -		   strcmp(token, "==") == 0 || -		   strcmp(token, "!=") == 0) { - -		left = malloc_or_die(sizeof(*left)); - -		/* copy the top arg to the left */ -		*left = *arg; - -		arg->type = PRINT_OP; -		arg->op.op = token; -		arg->op.left = left; - -		set_op_prio(arg); - -		right = malloc_or_die(sizeof(*right)); +	struct pevent_record record; -		type = read_token_item(&token); -		*tok = token; - -		/* could just be a type pointer */ -		if ((strcmp(arg->op.op, "*") == 0) && -		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) { -			if (left->type != PRINT_ATOM) -				die("bad pointer type"); -			left->atom.atom = realloc(left->atom.atom, -					    sizeof(left->atom.atom) + 3); -			strcat(left->atom.atom, " *"); -			*arg = *left; -			free(arg); - -			return type; -		} - -		type = process_arg_token(event, right, tok, type); - -		arg->op.right = right; - -	} else if (strcmp(token, "[") == 0) { - -		left = malloc_or_die(sizeof(*left)); -		*left = *arg; - -		arg->type = PRINT_OP; -		arg->op.op = token; -		arg->op.left = left; - -		arg->op.prio = 0; -		type = process_array(event, arg, tok); - -	} else { -		warning("unknown op '%s'", token); -		event->flags |= EVENT_FL_FAILED; -		/* the arg is now the left side */ -		return EVENT_NONE; -	} - -	if (type == EVENT_OP) { -		int prio; - -		/* higher prios need to be closer to the root */ -		prio = get_op_prio(*tok); - -		if (prio > arg->op.prio) -			return process_op(event, arg, tok); - -		return process_op(event, right, tok); -	} - -	return type; +	record.data = data; +	return pevent_data_type(pevent, &record);  } -static enum event_type -process_entry(struct event *event __unused, struct print_arg *arg, -	      char **tok) +int trace_parse_common_pid(void *data)  { -	enum event_type type; -	char *field; -	char *token; - -	if (read_expected(EVENT_OP, "->") < 0) -		return EVENT_ERROR; - -	if (read_expect_type(EVENT_ITEM, &token) < 0) -		goto fail; -	field = token; - -	arg->type = PRINT_FIELD; -	arg->field.name = field; - -	if (is_flag_field) { -		arg->field.field = find_any_field(event, arg->field.name); -		arg->field.field->flags |= FIELD_IS_FLAG; -		is_flag_field = 0; -	} else if (is_symbolic_field) { -		arg->field.field = find_any_field(event, arg->field.name); -		arg->field.field->flags |= FIELD_IS_SYMBOLIC; -		is_symbolic_field = 0; -	} +	struct pevent_record record; -	type = read_token(&token); -	*tok = token; - -	return type; - -fail: -	free_token(token); -	return EVENT_ERROR; +	record.data = data; +	return pevent_data_pid(pevent, &record);  } -static char *arg_eval (struct print_arg *arg); - -static long long arg_num_eval(struct print_arg *arg) +unsigned long long read_size(void *ptr, int size)  { -	long long left, right; -	long long val = 0; - -	switch (arg->type) { -	case PRINT_ATOM: -		val = strtoll(arg->atom.atom, NULL, 0); -		break; -	case PRINT_TYPE: -		val = arg_num_eval(arg->typecast.item); -		break; -	case PRINT_OP: -		switch (arg->op.op[0]) { -		case '|': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); -			if (arg->op.op[1]) -				val = left || right; -			else -				val = left | right; -			break; -		case '&': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); -			if (arg->op.op[1]) -				val = left && right; -			else -				val = left & right; -			break; -		case '<': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); -			switch (arg->op.op[1]) { -			case 0: -				val = left < right; -				break; -			case '<': -				val = left << right; -				break; -			case '=': -				val = left <= right; -				break; -			default: -				die("unknown op '%s'", arg->op.op); -			} -			break; -		case '>': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); -			switch (arg->op.op[1]) { -			case 0: -				val = left > right; -				break; -			case '>': -				val = left >> right; -				break; -			case '=': -				val = left >= right; -				break; -			default: -				die("unknown op '%s'", arg->op.op); -			} -			break; -		case '=': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); - -			if (arg->op.op[1] != '=') -				die("unknown op '%s'", arg->op.op); - -			val = left == right; -			break; -		case '!': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); - -			switch (arg->op.op[1]) { -			case '=': -				val = left != right; -				break; -			default: -				die("unknown op '%s'", arg->op.op); -			} -			break; -		case '+': -			left = arg_num_eval(arg->op.left); -			right = arg_num_eval(arg->op.right); -			val = left + right; -			break; -		default: -			die("unknown op '%s'", arg->op.op); -		} -		break; - -	case PRINT_NULL: -	case PRINT_FIELD ... PRINT_SYMBOL: -	case PRINT_STRING: -	default: -		die("invalid eval type %d", arg->type); - -	} -	return val; +	return pevent_read_number(pevent, ptr, size);  } -static char *arg_eval (struct print_arg *arg) +struct event_format *trace_find_event(int type)  { -	long long val; -	static char buf[20]; - -	switch (arg->type) { -	case PRINT_ATOM: -		return arg->atom.atom; -	case PRINT_TYPE: -		return arg_eval(arg->typecast.item); -	case PRINT_OP: -		val = arg_num_eval(arg); -		sprintf(buf, "%lld", val); -		return buf; - -	case PRINT_NULL: -	case PRINT_FIELD ... PRINT_SYMBOL: -	case PRINT_STRING: -	default: -		die("invalid eval type %d", arg->type); -		break; -	} - -	return NULL; +	return pevent_find_event(pevent, type);  } -static enum event_type -process_fields(struct event *event, struct print_flag_sym **list, char **tok) -{ -	enum event_type type; -	struct print_arg *arg = NULL; -	struct print_flag_sym *field; -	char *token = NULL; -	char *value; - -	do { -		free_token(token); -		type = read_token_item(&token); -		if (test_type_token(type, token, EVENT_OP, "{")) -			break; - -		arg = malloc_or_die(sizeof(*arg)); - -		free_token(token); -		type = process_arg(event, arg, &token); - -		if (type == EVENT_OP) -			type = process_op(event, arg, &token); - -		if (type == EVENT_ERROR) -			goto out_free; - -		if (test_type_token(type, token, EVENT_DELIM, ",")) -			goto out_free; - -		field = malloc_or_die(sizeof(*field)); -		memset(field, 0, sizeof(*field)); - -		value = arg_eval(arg); -		field->value = strdup(value); - -		free_token(token); -		type = process_arg(event, arg, &token); -		if (test_type_token(type, token, EVENT_OP, "}")) -			goto out_free; - -		value = arg_eval(arg); -		field->str = strdup(value); -		free_arg(arg); -		arg = NULL; -		*list = field; -		list = &field->next; - -		free_token(token); -		type = read_token_item(&token); -	} while (type == EVENT_DELIM && strcmp(token, ",") == 0); - -	*tok = token; -	return type; - -out_free: -	free_arg(arg); -	free_token(token); - -	return EVENT_ERROR; -} - -static enum event_type -process_flags(struct event *event, struct print_arg *arg, char **tok) +void print_trace_event(int cpu, void *data, int size)  { -	struct print_arg *field; -	enum event_type type; -	char *token; - -	memset(arg, 0, sizeof(*arg)); -	arg->type = PRINT_FLAGS; - -	if (read_expected_item(EVENT_DELIM, "(") < 0) -		return EVENT_ERROR; - -	field = malloc_or_die(sizeof(*field)); - -	type = process_arg(event, field, &token); -	while (type == EVENT_OP) -		type = process_op(event, field, &token); -	if (test_type_token(type, token, EVENT_DELIM, ",")) -		goto out_free; +	struct event_format *event; +	struct pevent_record record; +	struct trace_seq s; +	int type; -	arg->flags.field = field; +	type = trace_parse_common_type(data); -	type = read_token_item(&token); -	if (event_item_type(type)) { -		arg->flags.delim = token; -		type = read_token_item(&token); +	event = trace_find_event(type); +	if (!event) { +		warning("ug! no event found for type %d", type); +		return;  	} -	if (test_type_token(type, token, EVENT_DELIM, ",")) -		goto out_free; - -	type = process_fields(event, &arg->flags.flags, &token); -	if (test_type_token(type, token, EVENT_DELIM, ")")) -		goto out_free; - -	free_token(token); -	type = read_token_item(tok); -	return type; +	memset(&record, 0, sizeof(record)); +	record.cpu = cpu; +	record.size = size; +	record.data = data; -out_free: -	free_token(token); -	return EVENT_ERROR; +	trace_seq_init(&s); +	pevent_print_event(pevent, &s, &record); +	trace_seq_do_printf(&s); +	printf("\n");  } -static enum event_type -process_symbols(struct event *event, struct print_arg *arg, char **tok) +void print_event(int cpu, void *data, int size, unsigned long long nsecs, +		  char *comm)  { -	struct print_arg *field; -	enum event_type type; -	char *token; - -	memset(arg, 0, sizeof(*arg)); -	arg->type = PRINT_SYMBOL; - -	if (read_expected_item(EVENT_DELIM, "(") < 0) -		return EVENT_ERROR; - -	field = malloc_or_die(sizeof(*field)); - -	type = process_arg(event, field, &token); -	if (test_type_token(type, token, EVENT_DELIM, ",")) -		goto out_free; +	struct pevent_record record; +	struct trace_seq s; +	int pid; -	arg->symbol.field = field; +	pevent->latency_format = latency_format; -	type = process_fields(event, &arg->symbol.symbols, &token); -	if (test_type_token(type, token, EVENT_DELIM, ")")) -		goto out_free; +	record.ts = nsecs; +	record.cpu = cpu; +	record.size = size; +	record.data = data; +	pid = pevent_data_pid(pevent, &record); -	free_token(token); -	type = read_token_item(tok); -	return type; +	if (!pevent_pid_is_registered(pevent, pid)) +		pevent_register_comm(pevent, comm, pid); -out_free: -	free_token(token); -	return EVENT_ERROR; +	trace_seq_init(&s); +	pevent_print_event(pevent, &s, &record); +	trace_seq_do_printf(&s); +	printf("\n");  } -static enum event_type -process_paren(struct event *event, struct print_arg *arg, char **tok) +void parse_proc_kallsyms(char *file, unsigned int size __unused)  { -	struct print_arg *item_arg; -	enum event_type type; -	char *token; - -	type = process_arg(event, arg, &token); - -	if (type == EVENT_ERROR) -		return EVENT_ERROR; - -	if (type == EVENT_OP) -		type = process_op(event, arg, &token); - -	if (type == EVENT_ERROR) -		return EVENT_ERROR; - -	if (test_type_token(type, token, EVENT_DELIM, ")")) { -		free_token(token); -		return EVENT_ERROR; -	} - -	free_token(token); -	type = read_token_item(&token); - -	/* -	 * If the next token is an item or another open paren, then -	 * this was a typecast. -	 */ -	if (event_item_type(type) || -	    (type == EVENT_DELIM && strcmp(token, "(") == 0)) { - -		/* make this a typecast and contine */ +	unsigned long long addr; +	char *func; +	char *line; +	char *next = NULL; +	char *addr_str; +	char *mod; +	char ch; -		/* prevous must be an atom */ -		if (arg->type != PRINT_ATOM) -			die("previous needed to be PRINT_ATOM"); +	line = strtok_r(file, "\n", &next); +	while (line) { +		mod = NULL; +		sscanf(line, "%as %c %as\t[%as", +		       (float *)(void *)&addr_str, /* workaround gcc warning */ +		       &ch, (float *)(void *)&func, (float *)(void *)&mod); +		addr = strtoull(addr_str, NULL, 16); +		free(addr_str); -		item_arg = malloc_or_die(sizeof(*item_arg)); +		/* truncate the extra ']' */ +		if (mod) +			mod[strlen(mod) - 1] = 0; -		arg->type = PRINT_TYPE; -		arg->typecast.type = arg->atom.atom; -		arg->typecast.item = item_arg; -		type = process_arg_token(event, item_arg, &token, type); +		pevent_register_function(pevent, func, addr, mod); +		free(func); +		free(mod); +		line = strtok_r(NULL, "\n", &next);  	} - -	*tok = token; -	return type;  } - -static enum event_type -process_str(struct event *event __unused, struct print_arg *arg, char **tok) -{ -	enum event_type type; -	char *token; - -	if (read_expected(EVENT_DELIM, "(") < 0) -		return EVENT_ERROR; - -	if (read_expect_type(EVENT_ITEM, &token) < 0) -		goto fail; - -	arg->type = PRINT_STRING; -	arg->string.string = token; -	arg->string.offset = -1; - -	if (read_expected(EVENT_DELIM, ")") < 0) -		return EVENT_ERROR; - -	type = read_token(&token); -	*tok = token; - -	return type; -fail: -	free_token(token); -	return EVENT_ERROR; -} - -enum event_type -process_arg_token(struct event *event, struct print_arg *arg, -		  char **tok, enum event_type type) +void parse_ftrace_printk(char *file, unsigned int size __unused)  { -	char *token; -	char *atom; - -	token = *tok; - -	switch (type) { -	case EVENT_ITEM: -		if (strcmp(token, "REC") == 0) { -			free_token(token); -			type = process_entry(event, arg, &token); -		} else if (strcmp(token, "__print_flags") == 0) { -			free_token(token); -			is_flag_field = 1; -			type = process_flags(event, arg, &token); -		} else if (strcmp(token, "__print_symbolic") == 0) { -			free_token(token); -			is_symbolic_field = 1; -			type = process_symbols(event, arg, &token); -		} else if (strcmp(token, "__get_str") == 0) { -			free_token(token); -			type = process_str(event, arg, &token); -		} else { -			atom = token; -			/* test the next token */ -			type = read_token_item(&token); - -			/* atoms can be more than one token long */ -			while (type == EVENT_ITEM) { -				atom = realloc(atom, strlen(atom) + strlen(token) + 2); -				strcat(atom, " "); -				strcat(atom, token); -				free_token(token); -				type = read_token_item(&token); -			} - -			/* todo, test for function */ +	unsigned long long addr; +	char *printk; +	char *line; +	char *next = NULL; +	char *addr_str; +	char *fmt; -			arg->type = PRINT_ATOM; -			arg->atom.atom = atom; -		} -		break; -	case EVENT_DQUOTE: -	case EVENT_SQUOTE: -		arg->type = PRINT_ATOM; -		arg->atom.atom = token; -		type = read_token_item(&token); -		break; -	case EVENT_DELIM: -		if (strcmp(token, "(") == 0) { -			free_token(token); -			type = process_paren(event, arg, &token); +	line = strtok_r(file, "\n", &next); +	while (line) { +		addr_str = strtok_r(line, ":", &fmt); +		if (!addr_str) { +			warning("printk format with empty entry");  			break;  		} -	case EVENT_OP: -		/* handle single ops */ -		arg->type = PRINT_OP; -		arg->op.op = token; -		arg->op.left = NULL; -		type = process_op(event, arg, &token); - -		break; - -	case EVENT_ERROR ... EVENT_NEWLINE: -	default: -		die("unexpected type %d", type); -	} -	*tok = token; - -	return type; -} - -static int event_read_print_args(struct event *event, struct print_arg **list) -{ -	enum event_type type = EVENT_ERROR; -	struct print_arg *arg; -	char *token; -	int args = 0; - -	do { -		if (type == EVENT_NEWLINE) { -			free_token(token); -			type = read_token_item(&token); -			continue; -		} - -		arg = malloc_or_die(sizeof(*arg)); -		memset(arg, 0, sizeof(*arg)); - -		type = process_arg(event, arg, &token); - -		if (type == EVENT_ERROR) { -			free_arg(arg); -			return -1; -		} - -		*list = arg; -		args++; - -		if (type == EVENT_OP) { -			type = process_op(event, arg, &token); -			list = &arg->next; -			continue; -		} - -		if (type == EVENT_DELIM && strcmp(token, ",") == 0) { -			free_token(token); -			*list = arg; -			list = &arg->next; -			continue; -		} -		break; -	} while (type != EVENT_NONE); - -	if (type != EVENT_NONE) -		free_token(token); - -	return args; -} - -static int event_read_print(struct event *event) -{ -	enum event_type type; -	char *token; -	int ret; - -	if (read_expected_item(EVENT_ITEM, "print") < 0) -		return -1; - -	if (read_expected(EVENT_ITEM, "fmt") < 0) -		return -1; - -	if (read_expected(EVENT_OP, ":") < 0) -		return -1; - -	if (read_expect_type(EVENT_DQUOTE, &token) < 0) -		goto fail; - - concat: -	event->print_fmt.format = token; -	event->print_fmt.args = NULL; - -	/* ok to have no arg */ -	type = read_token_item(&token); - -	if (type == EVENT_NONE) -		return 0; - -	/* Handle concatination of print lines */ -	if (type == EVENT_DQUOTE) { -		char *cat; - -		cat = malloc_or_die(strlen(event->print_fmt.format) + -				    strlen(token) + 1); -		strcpy(cat, event->print_fmt.format); -		strcat(cat, token); -		free_token(token); -		free_token(event->print_fmt.format); -		event->print_fmt.format = NULL; -		token = cat; -		goto concat; -	} - -	if (test_type_token(type, token, EVENT_DELIM, ",")) -		goto fail; - -	free_token(token); - -	ret = event_read_print_args(event, &event->print_fmt.args); -	if (ret < 0) -		return -1; - -	return ret; - - fail: -	free_token(token); -	return -1; -} - -static struct format_field * -find_common_field(struct event *event, const char *name) -{ -	struct format_field *format; - -	for (format = event->format.common_fields; -	     format; format = format->next) { -		if (strcmp(format->name, name) == 0) -			break; -	} - -	return format; -} - -static struct format_field * -find_field(struct event *event, const char *name) -{ -	struct format_field *format; - -	for (format = event->format.fields; -	     format; format = format->next) { -		if (strcmp(format->name, name) == 0) -			break; +		addr = strtoull(addr_str, NULL, 16); +		/* fmt still has a space, skip it */ +		printk = strdup(fmt+1); +		line = strtok_r(NULL, "\n", &next); +		pevent_register_print_string(pevent, printk, addr);  	} - -	return format; -} - -static struct format_field * -find_any_field(struct event *event, const char *name) -{ -	struct format_field *format; - -	format = find_common_field(event, name); -	if (format) -		return format; -	return find_field(event, name);  } -unsigned long long read_size(void *ptr, int size) +int parse_ftrace_file(char *buf, unsigned long size)  { -	switch (size) { -	case 1: -		return *(unsigned char *)ptr; -	case 2: -		return data2host2(ptr); -	case 4: -		return data2host4(ptr); -	case 8: -		return data2host8(ptr); -	default: -		/* BUG! */ -		return 0; -	} +	return pevent_parse_event(pevent, buf, size, "ftrace");  } -unsigned long long -raw_field_value(struct event *event, const char *name, void *data) +int parse_event_file(char *buf, unsigned long size, char *sys)  { -	struct format_field *field; - -	field = find_any_field(event, name); -	if (!field) -		return 0ULL; - -	return read_size(data + field->offset, field->size); +	return pevent_parse_event(pevent, buf, size, sys);  } -void *raw_field_ptr(struct event *event, const char *name, void *data) +struct event_format *trace_find_next_event(struct event_format *event)  { -	struct format_field *field; +	static int idx; -	field = find_any_field(event, name); -	if (!field) +	if (!pevent->events)  		return NULL; -	if (field->flags & FIELD_IS_DYNAMIC) { -		int offset; - -		offset = *(int *)(data + field->offset); -		offset &= 0xffff; - -		return data + offset; -	} - -	return data + field->offset; -} - -static int get_common_info(const char *type, int *offset, int *size) -{ -	struct event *event; -	struct format_field *field; - -	/* -	 * All events should have the same common elements. -	 * Pick any event to find where the type is; -	 */ -	if (!event_list) -		die("no event_list!"); - -	event = event_list; -	field = find_common_field(event, type); -	if (!field) -		die("field '%s' not found", type); - -	*offset = field->offset; -	*size = field->size; - -	return 0; -} - -static int __parse_common(void *data, int *size, int *offset, -			  const char *name) -{ -	int ret; - -	if (!*size) { -		ret = get_common_info(name, offset, size); -		if (ret < 0) -			return ret; +	if (!event) { +		idx = 0; +		return pevent->events[0];  	} -	return read_size(data + *offset, *size); -} - -int trace_parse_common_type(void *data) -{ -	static int type_offset; -	static int type_size; - -	return __parse_common(data, &type_size, &type_offset, -			      "common_type"); -} - -int trace_parse_common_pid(void *data) -{ -	static int pid_offset; -	static int pid_size; - -	return __parse_common(data, &pid_size, &pid_offset, -			      "common_pid"); -} - -int parse_common_pc(void *data) -{ -	static int pc_offset; -	static int pc_size; - -	return __parse_common(data, &pc_size, &pc_offset, -			      "common_preempt_count"); -} - -int parse_common_flags(void *data) -{ -	static int flags_offset; -	static int flags_size; - -	return __parse_common(data, &flags_size, &flags_offset, -			      "common_flags"); -} - -int parse_common_lock_depth(void *data) -{ -	static int ld_offset; -	static int ld_size; -	int ret; -	ret = __parse_common(data, &ld_size, &ld_offset, -			     "common_lock_depth"); -	if (ret < 0) -		return -1; - -	return ret; -} - -struct event *trace_find_event(int id) -{ -	struct event *event; - -	for (event = event_list; event; event = event->next) { -		if (event->id == id) -			break; +	if (idx < pevent->nr_events && event == pevent->events[idx]) { +		idx++; +		if (idx == pevent->nr_events) +			return NULL; +		return pevent->events[idx];  	} -	return event; -} - -struct event *trace_find_next_event(struct event *event) -{ -	if (!event) -		return event_list; - -	return event->next; -} - -static unsigned long long eval_num_arg(void *data, int size, -				   struct event *event, struct print_arg *arg) -{ -	unsigned long long val = 0; -	unsigned long long left, right; -	struct print_arg *larg; -	switch (arg->type) { -	case PRINT_NULL: -		/* ?? */ -		return 0; -	case PRINT_ATOM: -		return strtoull(arg->atom.atom, NULL, 0); -	case PRINT_FIELD: -		if (!arg->field.field) { -			arg->field.field = find_any_field(event, arg->field.name); -			if (!arg->field.field) -				die("field %s not found", arg->field.name); -		} -		/* must be a number */ -		val = read_size(data + arg->field.field->offset, -				arg->field.field->size); -		break; -	case PRINT_FLAGS: -	case PRINT_SYMBOL: -		break; -	case PRINT_TYPE: -		return eval_num_arg(data, size, event, arg->typecast.item); -	case PRINT_STRING: -		return 0; -		break; -	case PRINT_OP: -		if (strcmp(arg->op.op, "[") == 0) { -			/* -			 * Arrays are special, since we don't want -			 * to read the arg as is. -			 */ -			if (arg->op.left->type != PRINT_FIELD) -				goto default_op; /* oops, all bets off */ -			larg = arg->op.left; -			if (!larg->field.field) { -				larg->field.field = -					find_any_field(event, larg->field.name); -				if (!larg->field.field) -					die("field %s not found", larg->field.name); -			} -			right = eval_num_arg(data, size, event, arg->op.right); -			val = read_size(data + larg->field.field->offset + -					right * long_size, long_size); -			break; -		} - default_op: -		left = eval_num_arg(data, size, event, arg->op.left); -		right = eval_num_arg(data, size, event, arg->op.right); -		switch (arg->op.op[0]) { -		case '|': -			if (arg->op.op[1]) -				val = left || right; -			else -				val = left | right; -			break; -		case '&': -			if (arg->op.op[1]) -				val = left && right; -			else -				val = left & right; -			break; -		case '<': -			switch (arg->op.op[1]) { -			case 0: -				val = left < right; -				break; -			case '<': -				val = left << right; -				break; -			case '=': -				val = left <= right; -				break; -			default: -				die("unknown op '%s'", arg->op.op); -			} -			break; -		case '>': -			switch (arg->op.op[1]) { -			case 0: -				val = left > right; -				break; -			case '>': -				val = left >> right; -				break; -			case '=': -				val = left >= right; -				break; -			default: -				die("unknown op '%s'", arg->op.op); -			} -			break; -		case '=': -			if (arg->op.op[1] != '=') -				die("unknown op '%s'", arg->op.op); -			val = left == right; -			break; -		case '-': -			val = left - right; -			break; -		case '+': -			val = left + right; -			break; -		default: -			die("unknown op '%s'", arg->op.op); -		} -		break; -	default: /* not sure what to do there */ -		return 0; +	for (idx = 1; idx < pevent->nr_events; idx++) { +		if (event == pevent->events[idx - 1]) +			return pevent->events[idx];  	} -	return val; +	return NULL;  }  struct flag { @@ -2221,933 +357,3 @@ unsigned long long eval_flag(const char *flag)  	return 0;  } - -static void print_str_arg(void *data, int size, -			  struct event *event, struct print_arg *arg) -{ -	struct print_flag_sym *flag; -	unsigned long long val, fval; -	char *str; -	int print; - -	switch (arg->type) { -	case PRINT_NULL: -		/* ?? */ -		return; -	case PRINT_ATOM: -		printf("%s", arg->atom.atom); -		return; -	case PRINT_FIELD: -		if (!arg->field.field) { -			arg->field.field = find_any_field(event, arg->field.name); -			if (!arg->field.field) -				die("field %s not found", arg->field.name); -		} -		str = malloc_or_die(arg->field.field->size + 1); -		memcpy(str, data + arg->field.field->offset, -		       arg->field.field->size); -		str[arg->field.field->size] = 0; -		printf("%s", str); -		free(str); -		break; -	case PRINT_FLAGS: -		val = eval_num_arg(data, size, event, arg->flags.field); -		print = 0; -		for (flag = arg->flags.flags; flag; flag = flag->next) { -			fval = eval_flag(flag->value); -			if (!val && !fval) { -				printf("%s", flag->str); -				break; -			} -			if (fval && (val & fval) == fval) { -				if (print && arg->flags.delim) -					printf("%s", arg->flags.delim); -				printf("%s", flag->str); -				print = 1; -				val &= ~fval; -			} -		} -		break; -	case PRINT_SYMBOL: -		val = eval_num_arg(data, size, event, arg->symbol.field); -		for (flag = arg->symbol.symbols; flag; flag = flag->next) { -			fval = eval_flag(flag->value); -			if (val == fval) { -				printf("%s", flag->str); -				break; -			} -		} -		break; - -	case PRINT_TYPE: -		break; -	case PRINT_STRING: { -		int str_offset; - -		if (arg->string.offset == -1) { -			struct format_field *f; - -			f = find_any_field(event, arg->string.string); -			arg->string.offset = f->offset; -		} -		str_offset = *(int *)(data + arg->string.offset); -		str_offset &= 0xffff; -		printf("%s", ((char *)data) + str_offset); -		break; -	} -	case PRINT_OP: -		/* -		 * The only op for string should be ? : -		 */ -		if (arg->op.op[0] != '?') -			return; -		val = eval_num_arg(data, size, event, arg->op.left); -		if (val) -			print_str_arg(data, size, event, arg->op.right->op.left); -		else -			print_str_arg(data, size, event, arg->op.right->op.right); -		break; -	default: -		/* well... */ -		break; -	} -} - -static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event) -{ -	static struct format_field *field, *ip_field; -	struct print_arg *args, *arg, **next; -	unsigned long long ip, val; -	char *ptr; -	void *bptr; - -	if (!field) { -		field = find_field(event, "buf"); -		if (!field) -			die("can't find buffer field for binary printk"); -		ip_field = find_field(event, "ip"); -		if (!ip_field) -			die("can't find ip field for binary printk"); -	} - -	ip = read_size(data + ip_field->offset, ip_field->size); - -	/* -	 * The first arg is the IP pointer. -	 */ -	args = malloc_or_die(sizeof(*args)); -	arg = args; -	arg->next = NULL; -	next = &arg->next; - -	arg->type = PRINT_ATOM; -	arg->atom.atom = malloc_or_die(32); -	sprintf(arg->atom.atom, "%lld", ip); - -	/* skip the first "%pf : " */ -	for (ptr = fmt + 6, bptr = data + field->offset; -	     bptr < data + size && *ptr; ptr++) { -		int ls = 0; - -		if (*ptr == '%') { - process_again: -			ptr++; -			switch (*ptr) { -			case '%': -				break; -			case 'l': -				ls++; -				goto process_again; -			case 'L': -				ls = 2; -				goto process_again; -			case '0' ... '9': -				goto process_again; -			case 'p': -				ls = 1; -				/* fall through */ -			case 'd': -			case 'u': -			case 'x': -			case 'i': -				/* the pointers are always 4 bytes aligned */ -				bptr = (void *)(((unsigned long)bptr + 3) & -						~3); -				switch (ls) { -				case 0: -				case 1: -					ls = long_size; -					break; -				case 2: -					ls = 8; -				default: -					break; -				} -				val = read_size(bptr, ls); -				bptr += ls; -				arg = malloc_or_die(sizeof(*arg)); -				arg->next = NULL; -				arg->type = PRINT_ATOM; -				arg->atom.atom = malloc_or_die(32); -				sprintf(arg->atom.atom, "%lld", val); -				*next = arg; -				next = &arg->next; -				break; -			case 's': -				arg = malloc_or_die(sizeof(*arg)); -				arg->next = NULL; -				arg->type = PRINT_STRING; -				arg->string.string = strdup(bptr); -				bptr += strlen(bptr) + 1; -				*next = arg; -				next = &arg->next; -			default: -				break; -			} -		} -	} - -	return args; -} - -static void free_args(struct print_arg *args) -{ -	struct print_arg *next; - -	while (args) { -		next = args->next; - -		if (args->type == PRINT_ATOM) -			free(args->atom.atom); -		else -			free(args->string.string); -		free(args); -		args = next; -	} -} - -static char *get_bprint_format(void *data, int size __unused, struct event *event) -{ -	unsigned long long addr; -	static struct format_field *field; -	struct printk_map *printk; -	char *format; -	char *p; - -	if (!field) { -		field = find_field(event, "fmt"); -		if (!field) -			die("can't find format field for binary printk"); -		printf("field->offset = %d size=%d\n", field->offset, field->size); -	} - -	addr = read_size(data + field->offset, field->size); - -	printk = find_printk(addr); -	if (!printk) { -		format = malloc_or_die(45); -		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n", -			addr); -		return format; -	} - -	p = printk->printk; -	/* Remove any quotes. */ -	if (*p == '"') -		p++; -	format = malloc_or_die(strlen(p) + 10); -	sprintf(format, "%s : %s", "%pf", p); -	/* remove ending quotes and new line since we will add one too */ -	p = format + strlen(format) - 1; -	if (*p == '"') -		*p = 0; - -	p -= 2; -	if (strcmp(p, "\\n") == 0) -		*p = 0; - -	return format; -} - -static void pretty_print(void *data, int size, struct event *event) -{ -	struct print_fmt *print_fmt = &event->print_fmt; -	struct print_arg *arg = print_fmt->args; -	struct print_arg *args = NULL; -	const char *ptr = print_fmt->format; -	unsigned long long val; -	struct func_map *func; -	const char *saveptr; -	char *bprint_fmt = NULL; -	char format[32]; -	int show_func; -	int len; -	int ls; - -	if (event->flags & EVENT_FL_ISFUNC) -		ptr = " %pF <-- %pF"; - -	if (event->flags & EVENT_FL_ISBPRINT) { -		bprint_fmt = get_bprint_format(data, size, event); -		args = make_bprint_args(bprint_fmt, data, size, event); -		arg = args; -		ptr = bprint_fmt; -	} - -	for (; *ptr; ptr++) { -		ls = 0; -		if (*ptr == '\\') { -			ptr++; -			switch (*ptr) { -			case 'n': -				printf("\n"); -				break; -			case 't': -				printf("\t"); -				break; -			case 'r': -				printf("\r"); -				break; -			case '\\': -				printf("\\"); -				break; -			default: -				printf("%c", *ptr); -				break; -			} - -		} else if (*ptr == '%') { -			saveptr = ptr; -			show_func = 0; - cont_process: -			ptr++; -			switch (*ptr) { -			case '%': -				printf("%%"); -				break; -			case 'l': -				ls++; -				goto cont_process; -			case 'L': -				ls = 2; -				goto cont_process; -			case 'z': -			case 'Z': -			case '0' ... '9': -				goto cont_process; -			case 'p': -				if (long_size == 4) -					ls = 1; -				else -					ls = 2; - -				if (*(ptr+1) == 'F' || -				    *(ptr+1) == 'f') { -					ptr++; -					show_func = *ptr; -				} - -				/* fall through */ -			case 'd': -			case 'i': -			case 'x': -			case 'X': -			case 'u': -				if (!arg) -					die("no argument match"); - -				len = ((unsigned long)ptr + 1) - -					(unsigned long)saveptr; - -				/* should never happen */ -				if (len > 32) -					die("bad format!"); - -				memcpy(format, saveptr, len); -				format[len] = 0; - -				val = eval_num_arg(data, size, event, arg); -				arg = arg->next; - -				if (show_func) { -					func = find_func(val); -					if (func) { -						printf("%s", func->func); -						if (show_func == 'F') -							printf("+0x%llx", -							       val - func->addr); -						break; -					} -				} -				switch (ls) { -				case 0: -					printf(format, (int)val); -					break; -				case 1: -					printf(format, (long)val); -					break; -				case 2: -					printf(format, (long long)val); -					break; -				default: -					die("bad count (%d)", ls); -				} -				break; -			case 's': -				if (!arg) -					die("no matching argument"); - -				print_str_arg(data, size, event, arg); -				arg = arg->next; -				break; -			default: -				printf(">%c<", *ptr); - -			} -		} else -			printf("%c", *ptr); -	} - -	if (args) { -		free_args(args); -		free(bprint_fmt); -	} -} - -static inline int log10_cpu(int nb) -{ -	if (nb / 100) -		return 3; -	if (nb / 10) -		return 2; -	return 1; -} - -static void print_lat_fmt(void *data, int size __unused) -{ -	unsigned int lat_flags; -	unsigned int pc; -	int lock_depth; -	int hardirq; -	int softirq; - -	lat_flags = parse_common_flags(data); -	pc = parse_common_pc(data); -	lock_depth = parse_common_lock_depth(data); - -	hardirq = lat_flags & TRACE_FLAG_HARDIRQ; -	softirq = lat_flags & TRACE_FLAG_SOFTIRQ; - -	printf("%c%c%c", -	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' : -	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ? -	       'X' : '.', -	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ? -	       'N' : '.', -	       (hardirq && softirq) ? 'H' : -	       hardirq ? 'h' : softirq ? 's' : '.'); - -	if (pc) -		printf("%x", pc); -	else -		printf("."); - -	if (lock_depth < 0) -		printf(". "); -	else -		printf("%d ", lock_depth); -} - -#define TRACE_GRAPH_INDENT	2 - -static struct record * -get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, -		    struct record *next) -{ -	struct format_field *field; -	struct event *event; -	unsigned long val; -	int type; -	int pid; - -	type = trace_parse_common_type(next->data); -	event = trace_find_event(type); -	if (!event) -		return NULL; - -	if (!(event->flags & EVENT_FL_ISFUNCRET)) -		return NULL; - -	pid = trace_parse_common_pid(next->data); -	field = find_field(event, "func"); -	if (!field) -		die("function return does not have field func"); - -	val = read_size(next->data + field->offset, field->size); - -	if (cur_pid != pid || cur_func != val) -		return NULL; - -	/* this is a leaf, now advance the iterator */ -	return trace_read_data(cpu); -} - -/* Signal a overhead of time execution to the output */ -static void print_graph_overhead(unsigned long long duration) -{ -	/* Non nested entry or return */ -	if (duration == ~0ULL) -		return (void)printf("  "); - -	/* Duration exceeded 100 msecs */ -	if (duration > 100000ULL) -		return (void)printf("! "); - -	/* Duration exceeded 10 msecs */ -	if (duration > 10000ULL) -		return (void)printf("+ "); - -	printf("  "); -} - -static void print_graph_duration(unsigned long long duration) -{ -	unsigned long usecs = duration / 1000; -	unsigned long nsecs_rem = duration % 1000; -	/* log10(ULONG_MAX) + '\0' */ -	char msecs_str[21]; -	char nsecs_str[5]; -	int len; -	int i; - -	sprintf(msecs_str, "%lu", usecs); - -	/* Print msecs */ -	len = printf("%lu", usecs); - -	/* Print nsecs (we don't want to exceed 7 numbers) */ -	if (len < 7) { -		snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem); -		len += printf(".%s", nsecs_str); -	} - -	printf(" us "); - -	/* Print remaining spaces to fit the row's width */ -	for (i = len; i < 7; i++) -		printf(" "); - -	printf("|  "); -} - -static void -print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec) -{ -	unsigned long long rettime, calltime; -	unsigned long long duration, depth; -	unsigned long long val; -	struct format_field *field; -	struct func_map *func; -	struct event *ret_event; -	int type; -	int i; - -	type = trace_parse_common_type(ret_rec->data); -	ret_event = trace_find_event(type); - -	field = find_field(ret_event, "rettime"); -	if (!field) -		die("can't find rettime in return graph"); -	rettime = read_size(ret_rec->data + field->offset, field->size); - -	field = find_field(ret_event, "calltime"); -	if (!field) -		die("can't find rettime in return graph"); -	calltime = read_size(ret_rec->data + field->offset, field->size); - -	duration = rettime - calltime; - -	/* Overhead */ -	print_graph_overhead(duration); - -	/* Duration */ -	print_graph_duration(duration); - -	field = find_field(event, "depth"); -	if (!field) -		die("can't find depth in entry graph"); -	depth = read_size(data + field->offset, field->size); - -	/* Function */ -	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) -		printf(" "); - -	field = find_field(event, "func"); -	if (!field) -		die("can't find func in entry graph"); -	val = read_size(data + field->offset, field->size); -	func = find_func(val); - -	if (func) -		printf("%s();", func->func); -	else -		printf("%llx();", val); -} - -static void print_graph_nested(struct event *event, void *data) -{ -	struct format_field *field; -	unsigned long long depth; -	unsigned long long val; -	struct func_map *func; -	int i; - -	/* No overhead */ -	print_graph_overhead(-1); - -	/* No time */ -	printf("           |  "); - -	field = find_field(event, "depth"); -	if (!field) -		die("can't find depth in entry graph"); -	depth = read_size(data + field->offset, field->size); - -	/* Function */ -	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) -		printf(" "); - -	field = find_field(event, "func"); -	if (!field) -		die("can't find func in entry graph"); -	val = read_size(data + field->offset, field->size); -	func = find_func(val); - -	if (func) -		printf("%s() {", func->func); -	else -		printf("%llx() {", val); -} - -static void -pretty_print_func_ent(void *data, int size, struct event *event, -		      int cpu, int pid) -{ -	struct format_field *field; -	struct record *rec; -	void *copy_data; -	unsigned long val; - -	if (latency_format) { -		print_lat_fmt(data, size); -		printf(" | "); -	} - -	field = find_field(event, "func"); -	if (!field) -		die("function entry does not have func field"); - -	val = read_size(data + field->offset, field->size); - -	/* -	 * peek_data may unmap the data pointer. Copy it first. -	 */ -	copy_data = malloc_or_die(size); -	memcpy(copy_data, data, size); -	data = copy_data; - -	rec = trace_peek_data(cpu); -	if (rec) { -		rec = get_return_for_leaf(cpu, pid, val, rec); -		if (rec) { -			print_graph_entry_leaf(event, data, rec); -			goto out_free; -		} -	} -	print_graph_nested(event, data); -out_free: -	free(data); -} - -static void -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; - -	if (latency_format) { -		print_lat_fmt(data, size); -		printf(" | "); -	} - -	field = find_field(event, "rettime"); -	if (!field) -		die("can't find rettime in return graph"); -	rettime = read_size(data + field->offset, field->size); - -	field = find_field(event, "calltime"); -	if (!field) -		die("can't find calltime in return graph"); -	calltime = read_size(data + field->offset, field->size); - -	duration = rettime - calltime; - -	/* Overhead */ -	print_graph_overhead(duration); - -	/* Duration */ -	print_graph_duration(duration); - -	field = find_field(event, "depth"); -	if (!field) -		die("can't find depth in entry graph"); -	depth = read_size(data + field->offset, field->size); - -	/* Function */ -	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) -		printf(" "); - -	printf("}"); -} - -static void -pretty_print_func_graph(void *data, int size, struct event *event, -			int cpu, int pid) -{ -	if (event->flags & EVENT_FL_ISFUNCENT) -		pretty_print_func_ent(data, size, event, cpu, pid); -	else if (event->flags & EVENT_FL_ISFUNCRET) -		pretty_print_func_ret(data, size, event); -	printf("\n"); -} - -void print_trace_event(int cpu, void *data, int size) -{ -	struct event *event; -	int type; -	int pid; - -	type = trace_parse_common_type(data); - -	event = trace_find_event(type); -	if (!event) { -		warning("ug! no event found for type %d", type); -		return; -	} - -	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); - -	if (latency_format) -		print_lat_fmt(data, size); - -	if (event->flags & EVENT_FL_FAILED) { -		printf("EVENT '%s' FAILED TO PARSE\n", -		       event->name); -		return; -	} - -	pretty_print(data, size, event); -} - -static void print_fields(struct print_flag_sym *field) -{ -	printf("{ %s, %s }", field->value, field->str); -	if (field->next) { -		printf(", "); -		print_fields(field->next); -	} -} - -static void print_args(struct print_arg *args) -{ -	int print_paren = 1; - -	switch (args->type) { -	case PRINT_NULL: -		printf("null"); -		break; -	case PRINT_ATOM: -		printf("%s", args->atom.atom); -		break; -	case PRINT_FIELD: -		printf("REC->%s", args->field.name); -		break; -	case PRINT_FLAGS: -		printf("__print_flags("); -		print_args(args->flags.field); -		printf(", %s, ", args->flags.delim); -		print_fields(args->flags.flags); -		printf(")"); -		break; -	case PRINT_SYMBOL: -		printf("__print_symbolic("); -		print_args(args->symbol.field); -		printf(", "); -		print_fields(args->symbol.symbols); -		printf(")"); -		break; -	case PRINT_STRING: -		printf("__get_str(%s)", args->string.string); -		break; -	case PRINT_TYPE: -		printf("(%s)", args->typecast.type); -		print_args(args->typecast.item); -		break; -	case PRINT_OP: -		if (strcmp(args->op.op, ":") == 0) -			print_paren = 0; -		if (print_paren) -			printf("("); -		print_args(args->op.left); -		printf(" %s ", args->op.op); -		print_args(args->op.right); -		if (print_paren) -			printf(")"); -		break; -	default: -		/* we should warn... */ -		return; -	} -	if (args->next) { -		printf("\n"); -		print_args(args->next); -	} -} - -int parse_ftrace_file(char *buf, unsigned long size) -{ -	struct format_field *field; -	struct print_arg *arg, **list; -	struct event *event; -	int ret; - -	init_input_buf(buf, size); - -	event = alloc_event(); -	if (!event) -		return -ENOMEM; - -	event->flags |= EVENT_FL_ISFTRACE; - -	event->name = event_read_name(); -	if (!event->name) -		die("failed to read ftrace event name"); - -	if (strcmp(event->name, "function") == 0) -		event->flags |= EVENT_FL_ISFUNC; - -	else if (strcmp(event->name, "funcgraph_entry") == 0) -		event->flags |= EVENT_FL_ISFUNCENT; - -	else if (strcmp(event->name, "funcgraph_exit") == 0) -		event->flags |= EVENT_FL_ISFUNCRET; - -	else if (strcmp(event->name, "bprint") == 0) -		event->flags |= EVENT_FL_ISBPRINT; - -	event->id = event_read_id(); -	if (event->id < 0) -		die("failed to read ftrace event id"); - -	add_event(event); - -	ret = event_read_format(event); -	if (ret < 0) -		die("failed to read ftrace event format"); - -	ret = event_read_print(event); -	if (ret < 0) -		die("failed to read ftrace event print fmt"); - -	/* New ftrace handles args */ -	if (ret > 0) -		return 0; -	/* -	 * The arguments for ftrace files are parsed by the fields. -	 * Set up the fields as their arguments. -	 */ -	list = &event->print_fmt.args; -	for (field = event->format.fields; field; field = field->next) { -		arg = malloc_or_die(sizeof(*arg)); -		memset(arg, 0, sizeof(*arg)); -		*list = arg; -		list = &arg->next; -		arg->type = PRINT_FIELD; -		arg->field.name = field->name; -		arg->field.field = field; -	} -	return 0; -} - -int parse_event_file(char *buf, unsigned long size, char *sys) -{ -	struct event *event; -	int ret; - -	init_input_buf(buf, size); - -	event = alloc_event(); -	if (!event) -		return -ENOMEM; - -	event->name = event_read_name(); -	if (!event->name) -		die("failed to read event name"); - -	event->id = event_read_id(); -	if (event->id < 0) -		die("failed to read event id"); - -	ret = event_read_format(event); -	if (ret < 0) { -		warning("failed to read event format for %s", event->name); -		goto event_failed; -	} - -	ret = event_read_print(event); -	if (ret < 0) { -		warning("failed to read event print fmt for %s", event->name); -		goto event_failed; -	} - -	event->system = strdup(sys); - -#define PRINT_ARGS 0 -	if (PRINT_ARGS && event->print_fmt.args) -		print_args(event->print_fmt.args); - -	add_event(event); -	return 0; - - event_failed: -	event->flags |= EVENT_FL_FAILED; -	/* still add it even if it failed */ -	add_event(event); -	return -1; -} - -void parse_set_info(int nr_cpus, int long_sz) -{ -	cpus = nr_cpus; -	long_size = long_sz; -} - -int common_pc(struct scripting_context *context) -{ -	return parse_common_pc(context->event_data); -} - -int common_flags(struct scripting_context *context) -{ -	return parse_common_flags(context->event_data); -} - -int common_lock_depth(struct scripting_context *context) -{ -	return parse_common_lock_depth(context->event_data); -} diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index b9592e0de8d..f097e0dd6c5 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -52,6 +52,16 @@ static unsigned long	page_size;  static ssize_t calc_data_size;  static bool repipe; +static void *malloc_or_die(int size) +{ +	void *ret; + +	ret = malloc(size); +	if (!ret) +		die("malloc"); +	return ret; +} +  static int do_read(int fd, void *buf, int size)  {  	int rsize = size; @@ -109,7 +119,7 @@ static unsigned int read4(void)  	unsigned int data;  	read_or_die(&data, 4); -	return __data2host4(data); +	return __data2host4(perf_pevent, data);  }  static unsigned long long read8(void) @@ -117,7 +127,7 @@ static unsigned long long read8(void)  	unsigned long long data;  	read_or_die(&data, 8); -	return __data2host8(data); +	return __data2host8(perf_pevent, data);  }  static char *read_string(void) @@ -282,7 +292,7 @@ struct cpu_data {  	unsigned long long	offset;  	unsigned long long	size;  	unsigned long long	timestamp; -	struct record		*next; +	struct pevent_record	*next;  	char			*page;  	int			cpu;  	int			index; @@ -367,9 +377,9 @@ static int calc_index(void *ptr, int cpu)  	return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;  } -struct record *trace_peek_data(int cpu) +struct pevent_record *trace_peek_data(int cpu)  { -	struct record *data; +	struct pevent_record *data;  	void *page = cpu_data[cpu].page;  	int idx = cpu_data[cpu].index;  	void *ptr = page + idx; @@ -389,15 +399,15 @@ struct record *trace_peek_data(int cpu)  		/* FIXME: handle header page */  		if (header_page_ts_size != 8)  			die("expected a long long type for timestamp"); -		cpu_data[cpu].timestamp = data2host8(ptr); +		cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);  		ptr += 8;  		switch (header_page_size_size) {  		case 4: -			cpu_data[cpu].page_size = data2host4(ptr); +			cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);  			ptr += 4;  			break;  		case 8: -			cpu_data[cpu].page_size = data2host8(ptr); +			cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);  			ptr += 8;  			break;  		default: @@ -414,7 +424,7 @@ read_again:  		return trace_peek_data(cpu);  	} -	type_len_ts = data2host4(ptr); +	type_len_ts = data2host4(perf_pevent, ptr);  	ptr += 4;  	type_len = type_len4host(type_len_ts); @@ -424,14 +434,14 @@ read_again:  	case RINGBUF_TYPE_PADDING:  		if (!delta)  			die("error, hit unexpected end of page"); -		length = data2host4(ptr); +		length = data2host4(perf_pevent, ptr);  		ptr += 4;  		length *= 4;  		ptr += length;  		goto read_again;  	case RINGBUF_TYPE_TIME_EXTEND: -		extend = data2host4(ptr); +		extend = data2host4(perf_pevent, ptr);  		ptr += 4;  		extend <<= TS_SHIFT;  		extend += delta; @@ -442,7 +452,7 @@ read_again:  		ptr += 12;  		break;  	case 0: -		length = data2host4(ptr); +		length = data2host4(perf_pevent, ptr);  		ptr += 4;  		die("here! length=%d", length);  		break; @@ -467,9 +477,9 @@ read_again:  	return data;  } -struct record *trace_read_data(int cpu) +struct pevent_record *trace_read_data(int cpu)  { -	struct record *data; +	struct pevent_record *data;  	data = trace_peek_data(cpu);  	cpu_data[cpu].next = NULL; @@ -509,6 +519,8 @@ ssize_t trace_report(int fd, bool __repipe)  	file_bigendian = buf[0];  	host_bigendian = bigendian(); +	read_trace_init(file_bigendian, host_bigendian); +  	read_or_die(buf, 1);  	long_size = buf[0]; @@ -526,11 +538,11 @@ ssize_t trace_report(int fd, bool __repipe)  	repipe = false;  	if (show_funcs) { -		print_funcs(); +		pevent_print_funcs(perf_pevent);  		return size;  	}  	if (show_printk) { -		print_printk(); +		pevent_print_printk(perf_pevent);  		return size;  	} diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 58ae14c5baa..639852ac111 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -1,20 +1,21 @@ -#ifndef __PERF_TRACE_EVENTS_H -#define __PERF_TRACE_EVENTS_H +#ifndef _PERF_UTIL_TRACE_EVENT_H +#define _PERF_UTIL_TRACE_EVENT_H -#include <stdbool.h>  #include "parse-events.h" +#include "event-parse.h" +#include "session.h"  struct machine;  struct perf_sample;  union perf_event;  struct thread; -#define __unused __attribute__((unused)) - +extern int header_page_size_size; +extern int header_page_ts_size; +extern int header_page_data_offset; -#ifndef PAGE_MASK -#define PAGE_MASK (page_size - 1) -#endif +extern bool latency_format; +extern struct pevent *perf_pevent;  enum {  	RINGBUF_TYPE_PADDING		= 29, @@ -26,246 +27,37 @@ enum {  #define TS_SHIFT		27  #endif -#define NSECS_PER_SEC		1000000000ULL -#define NSECS_PER_USEC		1000ULL - -enum format_flags { -	FIELD_IS_ARRAY		= 1, -	FIELD_IS_POINTER	= 2, -	FIELD_IS_SIGNED		= 4, -	FIELD_IS_STRING		= 8, -	FIELD_IS_DYNAMIC	= 16, -	FIELD_IS_FLAG		= 32, -	FIELD_IS_SYMBOLIC	= 64, -}; - -struct format_field { -	struct format_field	*next; -	char			*type; -	char			*name; -	int			offset; -	int			size; -	unsigned long		flags; -}; - -struct format { -	int			nr_common; -	int			nr_fields; -	struct format_field	*common_fields; -	struct format_field	*fields; -}; - -struct print_arg_atom { -	char			*atom; -}; - -struct print_arg_string { -	char			*string; -	int			offset; -}; - -struct print_arg_field { -	char			*name; -	struct format_field	*field; -}; - -struct print_flag_sym { -	struct print_flag_sym	*next; -	char			*value; -	char			*str; -}; - -struct print_arg_typecast { -	char 			*type; -	struct print_arg	*item; -}; - -struct print_arg_flags { -	struct print_arg	*field; -	char			*delim; -	struct print_flag_sym	*flags; -}; - -struct print_arg_symbol { -	struct print_arg	*field; -	struct print_flag_sym	*symbols; -}; - -struct print_arg; - -struct print_arg_op { -	char			*op; -	int			prio; -	struct print_arg	*left; -	struct print_arg	*right; -}; - -struct print_arg_func { -	char			*name; -	struct print_arg	*args; -}; - -enum print_arg_type { -	PRINT_NULL, -	PRINT_ATOM, -	PRINT_FIELD, -	PRINT_FLAGS, -	PRINT_SYMBOL, -	PRINT_TYPE, -	PRINT_STRING, -	PRINT_OP, -}; - -struct print_arg { -	struct print_arg		*next; -	enum print_arg_type		type; -	union { -		struct print_arg_atom		atom; -		struct print_arg_field		field; -		struct print_arg_typecast	typecast; -		struct print_arg_flags		flags; -		struct print_arg_symbol		symbol; -		struct print_arg_func		func; -		struct print_arg_string		string; -		struct print_arg_op		op; -	}; -}; - -struct print_fmt { -	char			*format; -	struct print_arg	*args; -}; - -struct event { -	struct event		*next; -	char			*name; -	int			id; -	int			flags; -	struct format		format; -	struct print_fmt	print_fmt; -	char			*system; -}; - -enum { -	EVENT_FL_ISFTRACE	= 0x01, -	EVENT_FL_ISPRINT	= 0x02, -	EVENT_FL_ISBPRINT	= 0x04, -	EVENT_FL_ISFUNC		= 0x08, -	EVENT_FL_ISFUNCENT	= 0x10, -	EVENT_FL_ISFUNCRET	= 0x20, - -	EVENT_FL_FAILED		= 0x80000000 -}; - -struct record { -	unsigned long long ts; -	int size; -	void *data; -}; - -struct record *trace_peek_data(int cpu); -struct record *trace_read_data(int cpu); - -void parse_set_info(int nr_cpus, int long_sz); - -ssize_t trace_report(int fd, bool repipe); - -void *malloc_or_die(unsigned int size); +int bigendian(void); -void parse_cmdlines(char *file, int size); -void parse_proc_kallsyms(char *file, unsigned int size); -void parse_ftrace_printk(char *file, unsigned int size); +int read_trace_init(int file_bigendian, int host_bigendian); +void print_trace_event(int cpu, void *data, int size); -void print_funcs(void); -void print_printk(void); +void print_event(int cpu, void *data, int size, unsigned long long nsecs, +		  char *comm);  int parse_ftrace_file(char *buf, unsigned long size);  int parse_event_file(char *buf, unsigned long size, char *sys); -void print_trace_event(int cpu, void *data, int size); - -extern int file_bigendian; -extern int host_bigendian; - -int bigendian(void); - -static inline unsigned short __data2host2(unsigned short data) -{ -	unsigned short swap; - -	if (host_bigendian == file_bigendian) -		return data; -	swap = ((data & 0xffULL) << 8) | -		((data & (0xffULL << 8)) >> 8); +struct pevent_record *trace_peek_data(int cpu); +struct event_format *trace_find_event(int type); -	return swap; -} - -static inline unsigned int __data2host4(unsigned int data) -{ -	unsigned int swap; - -	if (host_bigendian == file_bigendian) -		return data; - -	swap = ((data & 0xffULL) << 24) | -		((data & (0xffULL << 8)) << 8) | -		((data & (0xffULL << 16)) >> 8) | -		((data & (0xffULL << 24)) >> 24); - -	return swap; -} - -static inline unsigned long long __data2host8(unsigned long long data) -{ -	unsigned long long swap; - -	if (host_bigendian == file_bigendian) -		return data; - -	swap = ((data & 0xffULL) << 56) | -		((data & (0xffULL << 8)) << 40) | -		((data & (0xffULL << 16)) << 24) | -		((data & (0xffULL << 24)) << 8) | -		((data & (0xffULL << 32)) >> 8) | -		((data & (0xffULL << 40)) >> 24) | -		((data & (0xffULL << 48)) >> 40) | -		((data & (0xffULL << 56)) >> 56); - -	return swap; -} +unsigned long long +raw_field_value(struct event_format *event, const char *name, void *data); +void *raw_field_ptr(struct event_format *event, const char *name, void *data); -#define data2host2(ptr)		__data2host2(*(unsigned short *)ptr) -#define data2host4(ptr)		__data2host4(*(unsigned int *)ptr) -#define data2host8(ptr)		({				\ -	unsigned long long __val;				\ -								\ -	memcpy(&__val, (ptr), sizeof(unsigned long long));	\ -	__data2host8(__val);					\ -}) +void parse_proc_kallsyms(char *file, unsigned int size __unused); +void parse_ftrace_printk(char *file, unsigned int size __unused); -extern int header_page_ts_offset; -extern int header_page_ts_size; -extern int header_page_size_offset; -extern int header_page_size_size; -extern int header_page_data_offset; -extern int header_page_data_size; - -extern bool latency_format; +ssize_t trace_report(int fd, bool repipe);  int trace_parse_common_type(void *data);  int trace_parse_common_pid(void *data); -int parse_common_pc(void *data); -int parse_common_flags(void *data); -int parse_common_lock_depth(void *data); -struct event *trace_find_event(int id); -struct event *trace_find_next_event(struct event *event); + +struct event_format *trace_find_next_event(struct event_format *event);  unsigned long long read_size(void *ptr, int size); -unsigned long long -raw_field_value(struct event *event, const char *name, void *data); -void *raw_field_ptr(struct event *event, const char *name, void *data);  unsigned long long eval_flag(const char *flag); +struct pevent_record *trace_read_data(int cpu);  int read_tracing_data(int fd, struct list_head *pattrs);  struct tracing_data { @@ -280,15 +72,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,  void tracing_data_put(struct tracing_data *tdata); -/* taken from kernel/trace/trace.h */ -enum trace_flag_type { -	TRACE_FLAG_IRQS_OFF		= 0x01, -	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02, -	TRACE_FLAG_NEED_RESCHED		= 0x04, -	TRACE_FLAG_HARDIRQ		= 0x08, -	TRACE_FLAG_SOFTIRQ		= 0x10, -}; -  struct scripting_ops {  	const char *name;  	int (*start_script) (const char *script, int argc, const char **argv); @@ -314,4 +97,4 @@ int common_pc(struct scripting_context *context);  int common_flags(struct scripting_context *context);  int common_lock_depth(struct scripting_context *context); -#endif /* __PERF_TRACE_EVENTS_H */ +#endif /* _PERF_UTIL_TRACE_EVENT_H */ diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h index 5f3689a3d08..c51fa6b70a2 100644 --- a/tools/perf/util/types.h +++ b/tools/perf/util/types.h @@ -16,4 +16,9 @@ typedef signed short	   s16;  typedef unsigned char	   u8;  typedef signed char	   s8; +union u64_swap { +	u64 val64; +	u32 val32[2]; +}; +  #endif /* __PERF_TYPES_H */ diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c deleted file mode 100644 index 57a4c6ef3fd..00000000000 --- a/tools/perf/util/ui/browsers/annotate.c +++ /dev/null @@ -1,433 +0,0 @@ -#include "../../util.h" -#include "../browser.h" -#include "../helpline.h" -#include "../libslang.h" -#include "../ui.h" -#include "../util.h" -#include "../../annotate.h" -#include "../../hist.h" -#include "../../sort.h" -#include "../../symbol.h" -#include <pthread.h> -#include <newt.h> - -struct annotate_browser { -	struct ui_browser b; -	struct rb_root	  entries; -	struct rb_node	  *curr_hot; -	struct objdump_line *selection; -	int		    nr_asm_entries; -	int		    nr_entries; -	bool		    hide_src_code; -}; - -struct objdump_line_rb_node { -	struct rb_node	rb_node; -	double		percent; -	u32		idx; -	int		idx_asm; -}; - -static inline -struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) -{ -	return (struct objdump_line_rb_node *)(self + 1); -} - -static bool objdump_line__filter(struct ui_browser *browser, void *entry) -{ -	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); - -	if (ab->hide_src_code) { -		struct objdump_line *ol = list_entry(entry, struct objdump_line, node); -		return ol->offset == -1; -	} - -	return false; -} - -static void annotate_browser__write(struct ui_browser *self, void *entry, int row) -{ -	struct annotate_browser *ab = container_of(self, struct annotate_browser, b); -	struct objdump_line *ol = list_entry(entry, struct objdump_line, node); -	bool current_entry = ui_browser__is_current_entry(self, row); -	int width = self->width; - -	if (ol->offset != -1) { -		struct objdump_line_rb_node *olrb = objdump_line__rb(ol); -		ui_browser__set_percent_color(self, olrb->percent, current_entry); -		slsmg_printf(" %7.2f ", olrb->percent); -	} else { -		ui_browser__set_percent_color(self, 0, current_entry); -		slsmg_write_nstring(" ", 9); -	} - -	SLsmg_write_char(':'); -	slsmg_write_nstring(" ", 8); - -	/* The scroll bar isn't being used */ -	if (!self->navkeypressed) -		width += 1; - -	if (!ab->hide_src_code && ol->offset != -1) -		if (!current_entry || (self->use_navkeypressed && -				       !self->navkeypressed)) -			ui_browser__set_color(self, HE_COLORSET_CODE); - -	if (!*ol->line) -		slsmg_write_nstring(" ", width - 18); -	else -		slsmg_write_nstring(ol->line, width - 18); - -	if (current_entry) -		ab->selection = ol; -} - -static double objdump_line__calc_percent(struct objdump_line *self, -					 struct symbol *sym, int evidx) -{ -	double percent = 0.0; - -	if (self->offset != -1) { -		int len = sym->end - sym->start; -		unsigned int hits = 0; -		struct annotation *notes = symbol__annotation(sym); -		struct source_line *src_line = notes->src->lines; -		struct sym_hist *h = annotation__histogram(notes, evidx); -		s64 offset = self->offset; -		struct objdump_line *next; - -		next = objdump__get_next_ip_line(¬es->src->source, self); -		while (offset < (s64)len && -		       (next == NULL || offset < next->offset)) { -			if (src_line) { -				percent += src_line[offset].percent; -			} else -				hits += h->addr[offset]; - -			++offset; -		} -		/* - 		 * If the percentage wasn't already calculated in - 		 * symbol__get_source_line, do it now: - 		 */ -		if (src_line == NULL && h->sum) -			percent = 100.0 * hits / h->sum; -	} - -	return percent; -} - -static void objdump__insert_line(struct rb_root *self, -				 struct objdump_line_rb_node *line) -{ -	struct rb_node **p = &self->rb_node; -	struct rb_node *parent = NULL; -	struct objdump_line_rb_node *l; - -	while (*p != NULL) { -		parent = *p; -		l = rb_entry(parent, struct objdump_line_rb_node, rb_node); -		if (line->percent < l->percent) -			p = &(*p)->rb_left; -		else -			p = &(*p)->rb_right; -	} -	rb_link_node(&line->rb_node, parent, p); -	rb_insert_color(&line->rb_node, self); -} - -static void annotate_browser__set_top(struct annotate_browser *self, -				      struct rb_node *nd) -{ -	struct objdump_line_rb_node *rbpos; -	struct objdump_line *pos; -	unsigned back; - -	ui_browser__refresh_dimensions(&self->b); -	back = self->b.height / 2; -	rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); -	pos = ((struct objdump_line *)rbpos) - 1; -	self->b.top_idx = self->b.index = rbpos->idx; - -	while (self->b.top_idx != 0 && back != 0) { -		pos = list_entry(pos->node.prev, struct objdump_line, node); - -		--self->b.top_idx; -		--back; -	} - -	self->b.top = pos; -	self->curr_hot = nd; -} - -static void annotate_browser__calc_percent(struct annotate_browser *browser, -					   int evidx) -{ -	struct map_symbol *ms = browser->b.priv; -	struct symbol *sym = ms->sym; -	struct annotation *notes = symbol__annotation(sym); -	struct objdump_line *pos; - -	browser->entries = RB_ROOT; - -	pthread_mutex_lock(¬es->lock); - -	list_for_each_entry(pos, ¬es->src->source, node) { -		struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); -		rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); -		if (rbpos->percent < 0.01) { -			RB_CLEAR_NODE(&rbpos->rb_node); -			continue; -		} -		objdump__insert_line(&browser->entries, rbpos); -	} -	pthread_mutex_unlock(¬es->lock); - -	browser->curr_hot = rb_last(&browser->entries); -} - -static bool annotate_browser__toggle_source(struct annotate_browser *browser) -{ -	struct objdump_line *ol; -	struct objdump_line_rb_node *olrb; -	off_t offset = browser->b.index - browser->b.top_idx; - -	browser->b.seek(&browser->b, offset, SEEK_CUR); -	ol = list_entry(browser->b.top, struct objdump_line, node); -	olrb = objdump_line__rb(ol); - -	if (browser->hide_src_code) { -		if (olrb->idx_asm < offset) -			offset = olrb->idx; - -		browser->b.nr_entries = browser->nr_entries; -		browser->hide_src_code = false; -		browser->b.seek(&browser->b, -offset, SEEK_CUR); -		browser->b.top_idx = olrb->idx - offset; -		browser->b.index = olrb->idx; -	} else { -		if (olrb->idx_asm < 0) { -			ui_helpline__puts("Only available for assembly lines."); -			browser->b.seek(&browser->b, -offset, SEEK_CUR); -			return false; -		} - -		if (olrb->idx_asm < offset) -			offset = olrb->idx_asm; - -		browser->b.nr_entries = browser->nr_asm_entries; -		browser->hide_src_code = true; -		browser->b.seek(&browser->b, -offset, SEEK_CUR); -		browser->b.top_idx = olrb->idx_asm - offset; -		browser->b.index = olrb->idx_asm; -	} - -	return true; -} - -static int annotate_browser__run(struct annotate_browser *self, int evidx, -				 void(*timer)(void *arg), -				 void *arg, int delay_secs) -{ -	struct rb_node *nd = NULL; -	struct map_symbol *ms = self->b.priv; -	struct symbol *sym = ms->sym; -	const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, " -			   "H: Go to hottest line, ->/ENTER: Line action, " -			   "S: Toggle source code view"; -	int key; - -	if (ui_browser__show(&self->b, sym->name, help) < 0) -		return -1; - -	annotate_browser__calc_percent(self, evidx); - -	if (self->curr_hot) -		annotate_browser__set_top(self, self->curr_hot); - -	nd = self->curr_hot; - -	while (1) { -		key = ui_browser__run(&self->b, delay_secs); - -		if (delay_secs != 0) { -			annotate_browser__calc_percent(self, evidx); -			/* -			 * Current line focus got out of the list of most active -			 * lines, NULL it so that if TAB|UNTAB is pressed, we -			 * move to curr_hot (current hottest line). -			 */ -			if (nd != NULL && RB_EMPTY_NODE(nd)) -				nd = NULL; -		} - -		switch (key) { -		case K_TIMER: -			if (timer != NULL) -				timer(arg); - -			if (delay_secs != 0) -				symbol__annotate_decay_histogram(sym, evidx); -			continue; -		case K_TAB: -			if (nd != NULL) { -				nd = rb_prev(nd); -				if (nd == NULL) -					nd = rb_last(&self->entries); -			} else -				nd = self->curr_hot; -			break; -		case K_UNTAB: -			if (nd != NULL) -				nd = rb_next(nd); -				if (nd == NULL) -					nd = rb_first(&self->entries); -			else -				nd = self->curr_hot; -			break; -		case 'H': -		case 'h': -			nd = self->curr_hot; -			break; -		case 'S': -		case 's': -			if (annotate_browser__toggle_source(self)) -				ui_helpline__puts(help); -			continue; -		case K_ENTER: -		case K_RIGHT: -			if (self->selection == NULL) { -				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); -				continue; -			} - -			if (self->selection->offset == -1) { -				ui_helpline__puts("Actions are only available for assembly lines."); -				continue; -			} else { -				char *s = strstr(self->selection->line, "callq "); -				struct annotation *notes; -				struct symbol *target; -				u64 ip; - -				if (s == NULL) { -					ui_helpline__puts("Actions are only available for the 'callq' instruction."); -					continue; -				} - -				s = strchr(s, ' '); -				if (s++ == NULL) { -					ui_helpline__puts("Invallid callq instruction."); -					continue; -				} - -				ip = strtoull(s, NULL, 16); -				ip = ms->map->map_ip(ms->map, ip); -				target = map__find_symbol(ms->map, ip, NULL); -				if (target == NULL) { -					ui_helpline__puts("The called function was not found."); -					continue; -				} - -				notes = symbol__annotation(target); -				pthread_mutex_lock(¬es->lock); - -				if (notes->src == NULL && symbol__alloc_hist(target) < 0) { -					pthread_mutex_unlock(¬es->lock); -					ui__warning("Not enough memory for annotating '%s' symbol!\n", -						    target->name); -					continue; -				} - -				pthread_mutex_unlock(¬es->lock); -				symbol__tui_annotate(target, ms->map, evidx, -						     timer, arg, delay_secs); -				ui_browser__show_title(&self->b, sym->name); -			} -			continue; -		case K_LEFT: -		case K_ESC: -		case 'q': -		case CTRL('c'): -			goto out; -		default: -			continue; -		} - -		if (nd != NULL) -			annotate_browser__set_top(self, nd); -	} -out: -	ui_browser__hide(&self->b); -	return key; -} - -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, -			     void(*timer)(void *arg), void *arg, int delay_secs) -{ -	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, -				    timer, arg, delay_secs); -} - -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, -			 void(*timer)(void *arg), void *arg, -			 int delay_secs) -{ -	struct objdump_line *pos, *n; -	struct annotation *notes; -	struct map_symbol ms = { -		.map = map, -		.sym = sym, -	}; -	struct annotate_browser browser = { -		.b = { -			.refresh = ui_browser__list_head_refresh, -			.seek	 = ui_browser__list_head_seek, -			.write	 = annotate_browser__write, -			.filter  = objdump_line__filter, -			.priv	 = &ms, -			.use_navkeypressed = true, -		}, -	}; -	int ret; - -	if (sym == NULL) -		return -1; - -	if (map->dso->annotate_warned) -		return -1; - -	if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { -		ui__error("%s", ui_helpline__last_msg); -		return -1; -	} - -	ui_helpline__push("Press <- or ESC to exit"); - -	notes = symbol__annotation(sym); - -	list_for_each_entry(pos, ¬es->src->source, node) { -		struct objdump_line_rb_node *rbpos; -		size_t line_len = strlen(pos->line); - -		if (browser.b.width < line_len) -			browser.b.width = line_len; -		rbpos = objdump_line__rb(pos); -		rbpos->idx = browser.nr_entries++; -		if (pos->offset != -1) -			rbpos->idx_asm = browser.nr_asm_entries++; -		else -			rbpos->idx_asm = -1; -	} - -	browser.b.nr_entries = browser.nr_entries; -	browser.b.entries = ¬es->src->source, -	browser.b.width += 18; /* Percentage */ -	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); -	list_for_each_entry_safe(pos, n, ¬es->src->source, node) { -		list_del(&pos->node); -		objdump_line__free(pos); -	} -	return ret; -} diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 52bb07c6442..4007aca8e0c 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -82,41 +82,3 @@ void warning(const char *warn, ...)  	warn_routine(warn, params);  	va_end(params);  } - -uid_t parse_target_uid(const char *str, const char *tid, const char *pid) -{ -	struct passwd pwd, *result; -	char buf[1024]; - -	if (str == NULL) -		return UINT_MAX; - -	/* UID and PID are mutually exclusive */ -	if (tid || pid) { -		ui__warning("PID/TID switch overriding UID\n"); -		sleep(1); -		return UINT_MAX; -	} - -	getpwnam_r(str, &pwd, buf, sizeof(buf), &result); - -	if (result == NULL) { -		char *endptr; -		int uid = strtol(str, &endptr, 10); - -		if (*endptr != '\0') { -			ui__error("Invalid user %s\n", str); -			return UINT_MAX - 1; -		} - -		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); - -		if (result == NULL) { -			ui__error("Problems obtaining information for user %s\n", -				  str); -			return UINT_MAX - 1; -		} -	} - -	return result->pw_uid; -} diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 8109a907841..d03599fbe78 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n)  	return buf - buf_start;  } + +size_t hex_width(u64 v) +{ +	size_t n = 1; + +	while ((v >>= 4)) +		++n; + +	return n; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0f99f394d8e..2daaedb83d8 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -74,7 +74,6 @@  #include <netinet/tcp.h>  #include <arpa/inet.h>  #include <netdb.h> -#include <pwd.h>  #include <inttypes.h>  #include "../../../include/linux/magic.h"  #include "types.h" @@ -249,8 +248,6 @@ struct perf_event_attr;  void event_attr_init(struct perf_event_attr *attr); -uid_t parse_target_uid(const char *str, const char *tid, const char *pid); -  #define _STR(x) #x  #define STR(x) _STR(x) @@ -265,4 +262,6 @@ bool is_power_of_2(unsigned long n)  	return (n != 0 && ((n & (n - 1)) == 0));  } +size_t hex_width(u64 v); +  #endif  |