diff options
57 files changed, 1483 insertions, 1519 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index ef6d22e879eb..eb30044a922a 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile | |||
@@ -222,10 +222,14 @@ install-pdf: pdf | |||
222 | #install-html: html | 222 | #install-html: html |
223 | # '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) | 223 | # '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) |
224 | 224 | ||
225 | ifneq ($(MAKECMDGOALS),clean) | ||
226 | ifneq ($(MAKECMDGOALS),tags) | ||
225 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 227 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
226 | $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE | 228 | $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE |
227 | 229 | ||
228 | -include $(OUTPUT)PERF-VERSION-FILE | 230 | -include $(OUTPUT)PERF-VERSION-FILE |
231 | endif | ||
232 | endif | ||
229 | 233 | ||
230 | # | 234 | # |
231 | # Determine "include::" file references in asciidoc files. | 235 | # Determine "include::" file references in asciidoc files. |
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt index c1057701a7dc..8e798baae0fd 100644 --- a/tools/perf/Documentation/perf-buildid-cache.txt +++ b/tools/perf/Documentation/perf-buildid-cache.txt | |||
@@ -24,6 +24,9 @@ OPTIONS | |||
24 | -r:: | 24 | -r:: |
25 | --remove=:: | 25 | --remove=:: |
26 | Remove specified file from the cache. | 26 | Remove specified file from the cache. |
27 | -M:: | ||
28 | --missing=:: | ||
29 | List missing build ids in the cache for the specified file. | ||
27 | -v:: | 30 | -v:: |
28 | --verbose:: | 31 | --verbose:: |
29 | Be more verbose. | 32 | Be more verbose. |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 194f37d635df..5b3123d5721f 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -22,10 +22,6 @@ specified perf.data files. | |||
22 | 22 | ||
23 | OPTIONS | 23 | OPTIONS |
24 | ------- | 24 | ------- |
25 | -M:: | ||
26 | --displacement:: | ||
27 | Show position displacement relative to baseline. | ||
28 | |||
29 | -D:: | 25 | -D:: |
30 | --dump-raw-trace:: | 26 | --dump-raw-trace:: |
31 | Dump raw trace in ASCII. | 27 | Dump raw trace in ASCII. |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 5b80d84d6b4a..a414bc95fd52 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -60,7 +60,7 @@ Default is to monitor all CPUS. | |||
60 | 60 | ||
61 | -i:: | 61 | -i:: |
62 | --inherit:: | 62 | --inherit:: |
63 | Child tasks inherit counters, only makes sens with -p option. | 63 | Child tasks do not inherit counters. |
64 | 64 | ||
65 | -k <path>:: | 65 | -k <path>:: |
66 | --vmlinux=<path>:: | 66 | --vmlinux=<path>:: |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 8ab05e543ef4..2cbaad83a6e2 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -153,6 +153,8 @@ INSTALL = install | |||
153 | # explicitly what architecture to check for. Fix this up for yours.. | 153 | # explicitly what architecture to check for. Fix this up for yours.. |
154 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | 154 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ |
155 | 155 | ||
156 | ifneq ($(MAKECMDGOALS),clean) | ||
157 | ifneq ($(MAKECMDGOALS),tags) | ||
156 | -include config/feature-tests.mak | 158 | -include config/feature-tests.mak |
157 | 159 | ||
158 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | 160 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) |
@@ -206,6 +208,8 @@ ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) | |||
206 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) | 208 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) |
207 | BASIC_CFLAGS += -I. | 209 | BASIC_CFLAGS += -I. |
208 | endif | 210 | endif |
211 | endif # MAKECMDGOALS != tags | ||
212 | endif # MAKECMDGOALS != clean | ||
209 | 213 | ||
210 | # Guard against environment variables | 214 | # Guard against environment variables |
211 | BUILTIN_OBJS = | 215 | BUILTIN_OBJS = |
@@ -230,11 +234,19 @@ endif | |||
230 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 234 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
231 | TE_LIB := -L$(TE_PATH) -ltraceevent | 235 | TE_LIB := -L$(TE_PATH) -ltraceevent |
232 | 236 | ||
237 | export LIBTRACEEVENT | ||
238 | |||
239 | # python extension build directories | ||
240 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | ||
241 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | ||
242 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
243 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
244 | |||
245 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
246 | |||
233 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 247 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
234 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | 248 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py |
235 | 249 | ||
236 | export LIBTRACEEVENT | ||
237 | |||
238 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 250 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
239 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 251 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
240 | --quiet build_ext; \ | 252 | --quiet build_ext; \ |
@@ -378,8 +390,11 @@ LIB_H += util/rblist.h | |||
378 | LIB_H += util/intlist.h | 390 | LIB_H += util/intlist.h |
379 | LIB_H += util/perf_regs.h | 391 | LIB_H += util/perf_regs.h |
380 | LIB_H += util/unwind.h | 392 | LIB_H += util/unwind.h |
381 | LIB_H += ui/helpline.h | ||
382 | LIB_H += util/vdso.h | 393 | LIB_H += util/vdso.h |
394 | LIB_H += ui/helpline.h | ||
395 | LIB_H += ui/progress.h | ||
396 | LIB_H += ui/util.h | ||
397 | LIB_H += ui/ui.h | ||
383 | 398 | ||
384 | LIB_OBJS += $(OUTPUT)util/abspath.o | 399 | LIB_OBJS += $(OUTPUT)util/abspath.o |
385 | LIB_OBJS += $(OUTPUT)util/alias.o | 400 | LIB_OBJS += $(OUTPUT)util/alias.o |
@@ -453,6 +468,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o | |||
453 | LIB_OBJS += $(OUTPUT)ui/setup.o | 468 | LIB_OBJS += $(OUTPUT)ui/setup.o |
454 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 469 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
455 | LIB_OBJS += $(OUTPUT)ui/progress.o | 470 | LIB_OBJS += $(OUTPUT)ui/progress.o |
471 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
456 | LIB_OBJS += $(OUTPUT)ui/hist.o | 472 | LIB_OBJS += $(OUTPUT)ui/hist.o |
457 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o | 473 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o |
458 | 474 | ||
@@ -471,7 +487,6 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o | |||
471 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 487 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
472 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 488 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
473 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 489 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
474 | LIB_OBJS += $(OUTPUT)tests/util.o | ||
475 | 490 | ||
476 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 491 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
477 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 492 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
@@ -510,6 +525,8 @@ PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) | |||
510 | # | 525 | # |
511 | # Platform specific tweaks | 526 | # Platform specific tweaks |
512 | # | 527 | # |
528 | ifneq ($(MAKECMDGOALS),clean) | ||
529 | ifneq ($(MAKECMDGOALS),tags) | ||
513 | 530 | ||
514 | # We choose to avoid "if .. else if .. else .. endif endif" | 531 | # We choose to avoid "if .. else if .. else .. endif endif" |
515 | # because maintaining the nesting to match is a pain. If | 532 | # because maintaining the nesting to match is a pain. If |
@@ -646,7 +663,6 @@ ifndef NO_NEWT | |||
646 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | 663 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o |
647 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o | 664 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o |
648 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | 665 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o |
649 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
650 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 666 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
651 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | 667 | LIB_OBJS += $(OUTPUT)ui/tui/util.o |
652 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | 668 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o |
@@ -655,9 +671,6 @@ ifndef NO_NEWT | |||
655 | LIB_H += ui/browsers/map.h | 671 | LIB_H += ui/browsers/map.h |
656 | LIB_H += ui/keysyms.h | 672 | LIB_H += ui/keysyms.h |
657 | LIB_H += ui/libslang.h | 673 | LIB_H += ui/libslang.h |
658 | LIB_H += ui/progress.h | ||
659 | LIB_H += ui/util.h | ||
660 | LIB_H += ui/ui.h | ||
661 | endif | 674 | endif |
662 | endif | 675 | endif |
663 | 676 | ||
@@ -677,10 +690,6 @@ ifndef NO_GTK2 | |||
677 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | 690 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o |
678 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | 691 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o |
679 | LIB_OBJS += $(OUTPUT)ui/gtk/progress.o | 692 | LIB_OBJS += $(OUTPUT)ui/gtk/progress.o |
680 | # Make sure that it'd be included only once. | ||
681 | ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) | ||
682 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
683 | endif | ||
684 | endif | 693 | endif |
685 | endif | 694 | endif |
686 | 695 | ||
@@ -707,7 +716,7 @@ disable-python = $(eval $(disable-python_code)) | |||
707 | define disable-python_code | 716 | define disable-python_code |
708 | BASIC_CFLAGS += -DNO_LIBPYTHON | 717 | BASIC_CFLAGS += -DNO_LIBPYTHON |
709 | $(if $(1),$(warning No $(1) was found)) | 718 | $(if $(1),$(warning No $(1) was found)) |
710 | $(warning Python support won't be built) | 719 | $(warning Python support will not be built) |
711 | endef | 720 | endef |
712 | 721 | ||
713 | override PYTHON := \ | 722 | override PYTHON := \ |
@@ -715,19 +724,10 @@ override PYTHON := \ | |||
715 | 724 | ||
716 | ifndef PYTHON | 725 | ifndef PYTHON |
717 | $(call disable-python,python interpreter) | 726 | $(call disable-python,python interpreter) |
718 | python-clean := | ||
719 | else | 727 | else |
720 | 728 | ||
721 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 729 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
722 | 730 | ||
723 | # python extension build directories | ||
724 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | ||
725 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | ||
726 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
727 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
728 | |||
729 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
730 | |||
731 | ifdef NO_LIBPYTHON | 731 | ifdef NO_LIBPYTHON |
732 | $(call disable-python) | 732 | $(call disable-python) |
733 | else | 733 | else |
@@ -843,6 +843,9 @@ ifdef ASCIIDOC8 | |||
843 | export ASCIIDOC8 | 843 | export ASCIIDOC8 |
844 | endif | 844 | endif |
845 | 845 | ||
846 | endif # MAKECMDGOALS != tags | ||
847 | endif # MAKECMDGOALS != clean | ||
848 | |||
846 | # Shell quote (do not use $(call) to accommodate ancient setups); | 849 | # Shell quote (do not use $(call) to accommodate ancient setups); |
847 | 850 | ||
848 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | 851 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) |
@@ -1099,7 +1102,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir) | |||
1099 | endif | 1102 | endif |
1100 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 1103 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
1101 | 1104 | ||
1102 | install: all try-install-man | 1105 | install-bin: all |
1103 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' | 1106 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
1104 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' | 1107 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' |
1105 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 1108 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
@@ -1120,6 +1123,8 @@ install: all try-install-man | |||
1120 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 1123 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
1121 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 1124 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
1122 | 1125 | ||
1126 | install: install-bin try-install-man | ||
1127 | |||
1123 | install-python_ext: | 1128 | install-python_ext: |
1124 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 1129 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
1125 | 1130 | ||
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index fae8b250b2ca..a336014e0286 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "util/parse-options.h" | 14 | #include "util/parse-options.h" |
15 | #include "util/strlist.h" | 15 | #include "util/strlist.h" |
16 | #include "util/build-id.h" | 16 | #include "util/build-id.h" |
17 | #include "util/session.h" | ||
17 | #include "util/symbol.h" | 18 | #include "util/symbol.h" |
18 | 19 | ||
19 | static int build_id_cache__add_file(const char *filename, const char *debugdir) | 20 | static int build_id_cache__add_file(const char *filename, const char *debugdir) |
@@ -58,19 +59,59 @@ static int build_id_cache__remove_file(const char *filename, | |||
58 | return err; | 59 | return err; |
59 | } | 60 | } |
60 | 61 | ||
62 | static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) | ||
63 | { | ||
64 | char filename[PATH_MAX]; | ||
65 | u8 build_id[BUILD_ID_SIZE]; | ||
66 | |||
67 | if (dso__build_id_filename(dso, filename, sizeof(filename)) && | ||
68 | filename__read_build_id(filename, build_id, | ||
69 | sizeof(build_id)) != sizeof(build_id)) { | ||
70 | if (errno == ENOENT) | ||
71 | return false; | ||
72 | |||
73 | pr_warning("Problems with %s file, consider removing it from the cache\n", | ||
74 | filename); | ||
75 | } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { | ||
76 | pr_warning("Problems with %s file, consider removing it from the cache\n", | ||
77 | filename); | ||
78 | } | ||
79 | |||
80 | return true; | ||
81 | } | ||
82 | |||
83 | static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) | ||
84 | { | ||
85 | struct perf_session *session = perf_session__new(filename, O_RDONLY, | ||
86 | force, false, NULL); | ||
87 | if (session == NULL) | ||
88 | return -1; | ||
89 | |||
90 | perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); | ||
91 | perf_session__delete(session); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
61 | int cmd_buildid_cache(int argc, const char **argv, | 96 | int cmd_buildid_cache(int argc, const char **argv, |
62 | const char *prefix __maybe_unused) | 97 | const char *prefix __maybe_unused) |
63 | { | 98 | { |
64 | struct strlist *list; | 99 | struct strlist *list; |
65 | struct str_node *pos; | 100 | struct str_node *pos; |
101 | int ret = 0; | ||
102 | bool force = false; | ||
66 | char debugdir[PATH_MAX]; | 103 | char debugdir[PATH_MAX]; |
67 | char const *add_name_list_str = NULL, | 104 | char const *add_name_list_str = NULL, |
68 | *remove_name_list_str = NULL; | 105 | *remove_name_list_str = NULL, |
106 | *missing_filename = NULL; | ||
69 | const struct option buildid_cache_options[] = { | 107 | const struct option buildid_cache_options[] = { |
70 | OPT_STRING('a', "add", &add_name_list_str, | 108 | OPT_STRING('a', "add", &add_name_list_str, |
71 | "file list", "file(s) to add"), | 109 | "file list", "file(s) to add"), |
72 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | 110 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", |
73 | "file(s) to remove"), | 111 | "file(s) to remove"), |
112 | OPT_STRING('M', "missing", &missing_filename, "file", | ||
113 | "to find missing build ids in the cache"), | ||
114 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
74 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | 115 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
75 | OPT_END() | 116 | OPT_END() |
76 | }; | 117 | }; |
@@ -125,5 +166,8 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
125 | } | 166 | } |
126 | } | 167 | } |
127 | 168 | ||
128 | return 0; | 169 | if (missing_filename) |
170 | ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); | ||
171 | |||
172 | return ret; | ||
129 | } | 173 | } |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index a82d99fec83e..e74366a13218 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -44,23 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) | |||
44 | return fprintf(fp, "%s\n", sbuild_id); | 44 | return fprintf(fp, "%s\n", sbuild_id); |
45 | } | 45 | } |
46 | 46 | ||
47 | static bool dso__skip_buildid(struct dso *dso, int with_hits) | ||
48 | { | ||
49 | return with_hits && !dso->hit; | ||
50 | } | ||
51 | |||
47 | static int perf_session__list_build_ids(bool force, bool with_hits) | 52 | static int perf_session__list_build_ids(bool force, bool with_hits) |
48 | { | 53 | { |
49 | struct perf_session *session; | 54 | struct perf_session *session; |
50 | 55 | ||
51 | symbol__elf_init(); | 56 | symbol__elf_init(); |
52 | |||
53 | session = perf_session__new(input_name, O_RDONLY, force, false, | ||
54 | &build_id__mark_dso_hit_ops); | ||
55 | if (session == NULL) | ||
56 | return -1; | ||
57 | |||
58 | /* | 57 | /* |
59 | * See if this is an ELF file first: | 58 | * See if this is an ELF file first: |
60 | */ | 59 | */ |
61 | if (filename__fprintf_build_id(session->filename, stdout)) | 60 | if (filename__fprintf_build_id(input_name, stdout)) |
62 | goto out; | 61 | goto out; |
63 | 62 | ||
63 | session = perf_session__new(input_name, O_RDONLY, force, false, | ||
64 | &build_id__mark_dso_hit_ops); | ||
65 | if (session == NULL) | ||
66 | return -1; | ||
64 | /* | 67 | /* |
65 | * in pipe-mode, the only way to get the buildids is to parse | 68 | * in pipe-mode, the only way to get the buildids is to parse |
66 | * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID | 69 | * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID |
@@ -68,9 +71,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits) | |||
68 | if (with_hits || session->fd_pipe) | 71 | if (with_hits || session->fd_pipe) |
69 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); | 72 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); |
70 | 73 | ||
71 | perf_session__fprintf_dsos_buildid(session, stdout, with_hits); | 74 | perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits); |
72 | out: | ||
73 | perf_session__delete(session); | 75 | perf_session__delete(session); |
76 | out: | ||
74 | return 0; | 77 | return 0; |
75 | } | 78 | } |
76 | 79 | ||
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 93b852f8a5d5..b2e7d39f099b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old", | |||
23 | *input_new = "perf.data"; | 23 | *input_new = "perf.data"; |
24 | static char diff__default_sort_order[] = "dso,symbol"; | 24 | static char diff__default_sort_order[] = "dso,symbol"; |
25 | static bool force; | 25 | static bool force; |
26 | static bool show_displacement; | ||
27 | static bool show_period; | 26 | static bool show_period; |
28 | static bool show_formula; | 27 | static bool show_formula; |
29 | static bool show_baseline_only; | 28 | static bool show_baseline_only; |
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str, | |||
146 | return -EINVAL; | 145 | return -EINVAL; |
147 | } | 146 | } |
148 | 147 | ||
149 | static double get_period_percent(struct hist_entry *he, u64 period) | 148 | double perf_diff__period_percent(struct hist_entry *he, u64 period) |
150 | { | 149 | { |
151 | u64 total = he->hists->stats.total_period; | 150 | u64 total = he->hists->stats.total_period; |
152 | return (period * 100.0) / total; | 151 | return (period * 100.0) / total; |
153 | } | 152 | } |
154 | 153 | ||
155 | double perf_diff__compute_delta(struct hist_entry *he) | 154 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) |
156 | { | 155 | { |
157 | struct hist_entry *pair = hist_entry__next_pair(he); | 156 | double new_percent = perf_diff__period_percent(he, he->stat.period); |
158 | double new_percent = get_period_percent(he, he->stat.period); | 157 | double old_percent = perf_diff__period_percent(pair, pair->stat.period); |
159 | double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0; | ||
160 | 158 | ||
161 | he->diff.period_ratio_delta = new_percent - old_percent; | 159 | he->diff.period_ratio_delta = new_percent - old_percent; |
162 | he->diff.computed = true; | 160 | he->diff.computed = true; |
163 | return he->diff.period_ratio_delta; | 161 | return he->diff.period_ratio_delta; |
164 | } | 162 | } |
165 | 163 | ||
166 | double perf_diff__compute_ratio(struct hist_entry *he) | 164 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) |
167 | { | 165 | { |
168 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
169 | double new_period = he->stat.period; | 166 | double new_period = he->stat.period; |
170 | double old_period = pair ? pair->stat.period : 0; | 167 | double old_period = pair->stat.period; |
171 | 168 | ||
172 | he->diff.computed = true; | 169 | he->diff.computed = true; |
173 | he->diff.period_ratio = pair ? (new_period / old_period) : 0; | 170 | he->diff.period_ratio = new_period / old_period; |
174 | return he->diff.period_ratio; | 171 | return he->diff.period_ratio; |
175 | } | 172 | } |
176 | 173 | ||
177 | s64 perf_diff__compute_wdiff(struct hist_entry *he) | 174 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) |
178 | { | 175 | { |
179 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
180 | u64 new_period = he->stat.period; | 176 | u64 new_period = he->stat.period; |
181 | u64 old_period = pair ? pair->stat.period : 0; | 177 | u64 old_period = pair->stat.period; |
182 | 178 | ||
183 | he->diff.computed = true; | 179 | he->diff.computed = true; |
184 | 180 | he->diff.wdiff = new_period * compute_wdiff_w2 - | |
185 | if (!pair) | 181 | old_period * compute_wdiff_w1; |
186 | he->diff.wdiff = 0; | ||
187 | else | ||
188 | he->diff.wdiff = new_period * compute_wdiff_w2 - | ||
189 | old_period * compute_wdiff_w1; | ||
190 | 182 | ||
191 | return he->diff.wdiff; | 183 | return he->diff.wdiff; |
192 | } | 184 | } |
193 | 185 | ||
194 | static int formula_delta(struct hist_entry *he, char *buf, size_t size) | 186 | static int formula_delta(struct hist_entry *he, struct hist_entry *pair, |
187 | char *buf, size_t size) | ||
195 | { | 188 | { |
196 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
197 | |||
198 | if (!pair) | ||
199 | return -1; | ||
200 | |||
201 | return scnprintf(buf, size, | 189 | return scnprintf(buf, size, |
202 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " | 190 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " |
203 | "(%" PRIu64 " * 100 / %" PRIu64 ")", | 191 | "(%" PRIu64 " * 100 / %" PRIu64 ")", |
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size) | |||
205 | pair->stat.period, pair->hists->stats.total_period); | 193 | pair->stat.period, pair->hists->stats.total_period); |
206 | } | 194 | } |
207 | 195 | ||
208 | static int formula_ratio(struct hist_entry *he, char *buf, size_t size) | 196 | static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, |
197 | char *buf, size_t size) | ||
209 | { | 198 | { |
210 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
211 | double new_period = he->stat.period; | 199 | double new_period = he->stat.period; |
212 | double old_period = pair ? pair->stat.period : 0; | 200 | double old_period = pair->stat.period; |
213 | |||
214 | if (!pair) | ||
215 | return -1; | ||
216 | 201 | ||
217 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); | 202 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); |
218 | } | 203 | } |
219 | 204 | ||
220 | static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) | 205 | static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, |
206 | char *buf, size_t size) | ||
221 | { | 207 | { |
222 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
223 | u64 new_period = he->stat.period; | 208 | u64 new_period = he->stat.period; |
224 | u64 old_period = pair ? pair->stat.period : 0; | 209 | u64 old_period = pair->stat.period; |
225 | |||
226 | if (!pair) | ||
227 | return -1; | ||
228 | 210 | ||
229 | return scnprintf(buf, size, | 211 | return scnprintf(buf, size, |
230 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", | 212 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", |
231 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); | 213 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); |
232 | } | 214 | } |
233 | 215 | ||
234 | int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) | 216 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, |
217 | char *buf, size_t size) | ||
235 | { | 218 | { |
236 | switch (compute) { | 219 | switch (compute) { |
237 | case COMPUTE_DELTA: | 220 | case COMPUTE_DELTA: |
238 | return formula_delta(he, buf, size); | 221 | return formula_delta(he, pair, buf, size); |
239 | case COMPUTE_RATIO: | 222 | case COMPUTE_RATIO: |
240 | return formula_ratio(he, buf, size); | 223 | return formula_ratio(he, pair, buf, size); |
241 | case COMPUTE_WEIGHTED_DIFF: | 224 | case COMPUTE_WEIGHTED_DIFF: |
242 | return formula_wdiff(he, buf, size); | 225 | return formula_wdiff(he, pair, buf, size); |
243 | default: | 226 | default: |
244 | BUG_ON(1); | 227 | BUG_ON(1); |
245 | } | 228 | } |
@@ -312,9 +295,8 @@ static void insert_hist_entry_by_name(struct rb_root *root, | |||
312 | rb_insert_color(&he->rb_node, root); | 295 | rb_insert_color(&he->rb_node, root); |
313 | } | 296 | } |
314 | 297 | ||
315 | static void hists__name_resort(struct hists *self, bool sort) | 298 | static void hists__name_resort(struct hists *self) |
316 | { | 299 | { |
317 | unsigned long position = 1; | ||
318 | struct rb_root tmp = RB_ROOT; | 300 | struct rb_root tmp = RB_ROOT; |
319 | struct rb_node *next = rb_first(&self->entries); | 301 | struct rb_node *next = rb_first(&self->entries); |
320 | 302 | ||
@@ -322,16 +304,12 @@ static void hists__name_resort(struct hists *self, bool sort) | |||
322 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); | 304 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); |
323 | 305 | ||
324 | next = rb_next(&n->rb_node); | 306 | next = rb_next(&n->rb_node); |
325 | n->position = position++; | ||
326 | 307 | ||
327 | if (sort) { | 308 | rb_erase(&n->rb_node, &self->entries); |
328 | rb_erase(&n->rb_node, &self->entries); | 309 | insert_hist_entry_by_name(&tmp, n); |
329 | insert_hist_entry_by_name(&tmp, n); | ||
330 | } | ||
331 | } | 310 | } |
332 | 311 | ||
333 | if (sort) | 312 | self->entries = tmp; |
334 | self->entries = tmp; | ||
335 | } | 313 | } |
336 | 314 | ||
337 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | 315 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, |
@@ -355,12 +333,8 @@ static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) | |||
355 | 333 | ||
356 | hists__output_resort(hists); | 334 | hists__output_resort(hists); |
357 | 335 | ||
358 | /* | 336 | if (name) |
359 | * The hists__name_resort only sets possition | 337 | hists__name_resort(hists); |
360 | * if name is false. | ||
361 | */ | ||
362 | if (name || ((!name) && show_displacement)) | ||
363 | hists__name_resort(hists, name); | ||
364 | } | 338 | } |
365 | } | 339 | } |
366 | 340 | ||
@@ -385,18 +359,21 @@ static void hists__precompute(struct hists *hists) | |||
385 | 359 | ||
386 | while (next != NULL) { | 360 | while (next != NULL) { |
387 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 361 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); |
362 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
388 | 363 | ||
389 | next = rb_next(&he->rb_node); | 364 | next = rb_next(&he->rb_node); |
365 | if (!pair) | ||
366 | continue; | ||
390 | 367 | ||
391 | switch (compute) { | 368 | switch (compute) { |
392 | case COMPUTE_DELTA: | 369 | case COMPUTE_DELTA: |
393 | perf_diff__compute_delta(he); | 370 | perf_diff__compute_delta(he, pair); |
394 | break; | 371 | break; |
395 | case COMPUTE_RATIO: | 372 | case COMPUTE_RATIO: |
396 | perf_diff__compute_ratio(he); | 373 | perf_diff__compute_ratio(he, pair); |
397 | break; | 374 | break; |
398 | case COMPUTE_WEIGHTED_DIFF: | 375 | case COMPUTE_WEIGHTED_DIFF: |
399 | perf_diff__compute_wdiff(he); | 376 | perf_diff__compute_wdiff(he, pair); |
400 | break; | 377 | break; |
401 | default: | 378 | default: |
402 | BUG_ON(1); | 379 | BUG_ON(1); |
@@ -562,8 +539,6 @@ static const char * const diff_usage[] = { | |||
562 | static const struct option options[] = { | 539 | static const struct option options[] = { |
563 | OPT_INCR('v', "verbose", &verbose, | 540 | OPT_INCR('v', "verbose", &verbose, |
564 | "be more verbose (show symbol address, etc)"), | 541 | "be more verbose (show symbol address, etc)"), |
565 | OPT_BOOLEAN('M', "displacement", &show_displacement, | ||
566 | "Show position displacement relative to baseline"), | ||
567 | OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, | 542 | OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, |
568 | "Show only items with match in baseline"), | 543 | "Show only items with match in baseline"), |
569 | OPT_CALLBACK('c', "compute", &compute, | 544 | OPT_CALLBACK('c', "compute", &compute, |
@@ -597,40 +572,32 @@ static const struct option options[] = { | |||
597 | 572 | ||
598 | static void ui_init(void) | 573 | static void ui_init(void) |
599 | { | 574 | { |
600 | perf_hpp__init(); | ||
601 | |||
602 | /* No overhead column. */ | ||
603 | perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); | ||
604 | |||
605 | /* | 575 | /* |
606 | * Display baseline/delta/ratio/displacement/ | 576 | * Display baseline/delta/ratio |
607 | * formula/periods columns. | 577 | * formula/periods columns. |
608 | */ | 578 | */ |
609 | perf_hpp__column_enable(PERF_HPP__BASELINE, true); | 579 | perf_hpp__column_enable(PERF_HPP__BASELINE); |
610 | 580 | ||
611 | switch (compute) { | 581 | switch (compute) { |
612 | case COMPUTE_DELTA: | 582 | case COMPUTE_DELTA: |
613 | perf_hpp__column_enable(PERF_HPP__DELTA, true); | 583 | perf_hpp__column_enable(PERF_HPP__DELTA); |
614 | break; | 584 | break; |
615 | case COMPUTE_RATIO: | 585 | case COMPUTE_RATIO: |
616 | perf_hpp__column_enable(PERF_HPP__RATIO, true); | 586 | perf_hpp__column_enable(PERF_HPP__RATIO); |
617 | break; | 587 | break; |
618 | case COMPUTE_WEIGHTED_DIFF: | 588 | case COMPUTE_WEIGHTED_DIFF: |
619 | perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); | 589 | perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); |
620 | break; | 590 | break; |
621 | default: | 591 | default: |
622 | BUG_ON(1); | 592 | BUG_ON(1); |
623 | }; | 593 | }; |
624 | 594 | ||
625 | if (show_displacement) | ||
626 | perf_hpp__column_enable(PERF_HPP__DISPL, true); | ||
627 | |||
628 | if (show_formula) | 595 | if (show_formula) |
629 | perf_hpp__column_enable(PERF_HPP__FORMULA, true); | 596 | perf_hpp__column_enable(PERF_HPP__FORMULA); |
630 | 597 | ||
631 | if (show_period) { | 598 | if (show_period) { |
632 | perf_hpp__column_enable(PERF_HPP__PERIOD, true); | 599 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
633 | perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); | 600 | perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); |
634 | } | 601 | } |
635 | } | 602 | } |
636 | 603 | ||
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index c20f1dcfb7e2..1312a5e03ec7 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -15,39 +15,6 @@ | |||
15 | #include "util/parse-options.h" | 15 | #include "util/parse-options.h" |
16 | #include "util/session.h" | 16 | #include "util/session.h" |
17 | 17 | ||
18 | struct perf_attr_details { | ||
19 | bool freq; | ||
20 | bool verbose; | ||
21 | }; | ||
22 | |||
23 | static int comma_printf(bool *first, const char *fmt, ...) | ||
24 | { | ||
25 | va_list args; | ||
26 | int ret = 0; | ||
27 | |||
28 | if (!*first) { | ||
29 | ret += printf(","); | ||
30 | } else { | ||
31 | ret += printf(":"); | ||
32 | *first = false; | ||
33 | } | ||
34 | |||
35 | va_start(args, fmt); | ||
36 | ret += vprintf(fmt, args); | ||
37 | va_end(args); | ||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | static int __if_print(bool *first, const char *field, u64 value) | ||
42 | { | ||
43 | if (value == 0) | ||
44 | return 0; | ||
45 | |||
46 | return comma_printf(first, " %s: %" PRIu64, field, value); | ||
47 | } | ||
48 | |||
49 | #define if_print(field) __if_print(&first, #field, pos->attr.field) | ||
50 | |||
51 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) | 18 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) |
52 | { | 19 | { |
53 | struct perf_session *session; | 20 | struct perf_session *session; |
@@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
57 | if (session == NULL) | 24 | if (session == NULL) |
58 | return -ENOMEM; | 25 | return -ENOMEM; |
59 | 26 | ||
60 | list_for_each_entry(pos, &session->evlist->entries, node) { | 27 | list_for_each_entry(pos, &session->evlist->entries, node) |
61 | bool first = true; | 28 | perf_evsel__fprintf(pos, details, stdout); |
62 | |||
63 | printf("%s", perf_evsel__name(pos)); | ||
64 | |||
65 | if (details->verbose || details->freq) { | ||
66 | comma_printf(&first, " sample_freq=%" PRIu64, | ||
67 | (u64)pos->attr.sample_freq); | ||
68 | } | ||
69 | |||
70 | if (details->verbose) { | ||
71 | if_print(type); | ||
72 | if_print(config); | ||
73 | if_print(config1); | ||
74 | if_print(config2); | ||
75 | if_print(size); | ||
76 | if_print(sample_type); | ||
77 | if_print(read_format); | ||
78 | if_print(disabled); | ||
79 | if_print(inherit); | ||
80 | if_print(pinned); | ||
81 | if_print(exclusive); | ||
82 | if_print(exclude_user); | ||
83 | if_print(exclude_kernel); | ||
84 | if_print(exclude_hv); | ||
85 | if_print(exclude_idle); | ||
86 | if_print(mmap); | ||
87 | if_print(comm); | ||
88 | if_print(freq); | ||
89 | if_print(inherit_stat); | ||
90 | if_print(enable_on_exec); | ||
91 | if_print(task); | ||
92 | if_print(watermark); | ||
93 | if_print(precise_ip); | ||
94 | if_print(mmap_data); | ||
95 | if_print(sample_id_all); | ||
96 | if_print(exclude_host); | ||
97 | if_print(exclude_guest); | ||
98 | if_print(__reserved_1); | ||
99 | if_print(wakeup_events); | ||
100 | if_print(bp_type); | ||
101 | if_print(branch_sample_type); | ||
102 | } | ||
103 | |||
104 | putchar('\n'); | ||
105 | } | ||
106 | 29 | ||
107 | perf_session__delete(session); | 30 | perf_session__delete(session); |
108 | return 0; | 31 | return 0; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f3151d3c70ce..028de726b832 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -230,14 +230,7 @@ static int perf_record__open(struct perf_record *rec) | |||
230 | struct perf_record_opts *opts = &rec->opts; | 230 | struct perf_record_opts *opts = &rec->opts; |
231 | int rc = 0; | 231 | int rc = 0; |
232 | 232 | ||
233 | /* | 233 | perf_evlist__config(evlist, opts); |
234 | * Set the evsel leader links before we configure attributes, | ||
235 | * since some might depend on this info. | ||
236 | */ | ||
237 | if (opts->group) | ||
238 | perf_evlist__set_leader(evlist); | ||
239 | |||
240 | perf_evlist__config_attrs(evlist, opts); | ||
241 | 234 | ||
242 | list_for_each_entry(pos, &evlist->entries, node) { | 235 | list_for_each_entry(pos, &evlist->entries, node) { |
243 | struct perf_event_attr *attr = &pos->attr; | 236 | struct perf_event_attr *attr = &pos->attr; |
@@ -286,7 +279,7 @@ try_again: | |||
286 | */ | 279 | */ |
287 | opts->sample_id_all_missing = true; | 280 | opts->sample_id_all_missing = true; |
288 | if (!opts->sample_time && !opts->raw_samples && !time_needed) | 281 | if (!opts->sample_time && !opts->raw_samples && !time_needed) |
289 | attr->sample_type &= ~PERF_SAMPLE_TIME; | 282 | perf_evsel__reset_sample_bit(pos, TIME); |
290 | 283 | ||
291 | goto retry_sample_id; | 284 | goto retry_sample_id; |
292 | } | 285 | } |
@@ -875,11 +868,10 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
875 | } | 868 | } |
876 | #endif /* LIBUNWIND_SUPPORT */ | 869 | #endif /* LIBUNWIND_SUPPORT */ |
877 | 870 | ||
878 | static int | 871 | int record_parse_callchain_opt(const struct option *opt, |
879 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | 872 | const char *arg, int unset) |
880 | int unset) | ||
881 | { | 873 | { |
882 | struct perf_record *rec = (struct perf_record *)opt->value; | 874 | struct perf_record_opts *opts = opt->value; |
883 | char *tok, *name, *saveptr = NULL; | 875 | char *tok, *name, *saveptr = NULL; |
884 | char *buf; | 876 | char *buf; |
885 | int ret = -1; | 877 | int ret = -1; |
@@ -905,7 +897,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
905 | /* Framepointer style */ | 897 | /* Framepointer style */ |
906 | if (!strncmp(name, "fp", sizeof("fp"))) { | 898 | if (!strncmp(name, "fp", sizeof("fp"))) { |
907 | if (!strtok_r(NULL, ",", &saveptr)) { | 899 | if (!strtok_r(NULL, ",", &saveptr)) { |
908 | rec->opts.call_graph = CALLCHAIN_FP; | 900 | opts->call_graph = CALLCHAIN_FP; |
909 | ret = 0; | 901 | ret = 0; |
910 | } else | 902 | } else |
911 | pr_err("callchain: No more arguments " | 903 | pr_err("callchain: No more arguments " |
@@ -918,20 +910,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
918 | const unsigned long default_stack_dump_size = 8192; | 910 | const unsigned long default_stack_dump_size = 8192; |
919 | 911 | ||
920 | ret = 0; | 912 | ret = 0; |
921 | rec->opts.call_graph = CALLCHAIN_DWARF; | 913 | opts->call_graph = CALLCHAIN_DWARF; |
922 | rec->opts.stack_dump_size = default_stack_dump_size; | 914 | opts->stack_dump_size = default_stack_dump_size; |
923 | 915 | ||
924 | tok = strtok_r(NULL, ",", &saveptr); | 916 | tok = strtok_r(NULL, ",", &saveptr); |
925 | if (tok) { | 917 | if (tok) { |
926 | unsigned long size = 0; | 918 | unsigned long size = 0; |
927 | 919 | ||
928 | ret = get_stack_size(tok, &size); | 920 | ret = get_stack_size(tok, &size); |
929 | rec->opts.stack_dump_size = size; | 921 | opts->stack_dump_size = size; |
930 | } | 922 | } |
931 | 923 | ||
932 | if (!ret) | 924 | if (!ret) |
933 | pr_debug("callchain: stack dump size %d\n", | 925 | pr_debug("callchain: stack dump size %d\n", |
934 | rec->opts.stack_dump_size); | 926 | opts->stack_dump_size); |
935 | #endif /* LIBUNWIND_SUPPORT */ | 927 | #endif /* LIBUNWIND_SUPPORT */ |
936 | } else { | 928 | } else { |
937 | pr_err("callchain: Unknown -g option " | 929 | pr_err("callchain: Unknown -g option " |
@@ -944,7 +936,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
944 | free(buf); | 936 | free(buf); |
945 | 937 | ||
946 | if (!ret) | 938 | if (!ret) |
947 | pr_debug("callchain: type %d\n", rec->opts.call_graph); | 939 | pr_debug("callchain: type %d\n", opts->call_graph); |
948 | 940 | ||
949 | return ret; | 941 | return ret; |
950 | } | 942 | } |
@@ -982,9 +974,9 @@ static struct perf_record record = { | |||
982 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | 974 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " |
983 | 975 | ||
984 | #ifdef LIBUNWIND_SUPPORT | 976 | #ifdef LIBUNWIND_SUPPORT |
985 | static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | 977 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; |
986 | #else | 978 | #else |
987 | static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; | 979 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; |
988 | #endif | 980 | #endif |
989 | 981 | ||
990 | /* | 982 | /* |
@@ -1028,9 +1020,9 @@ const struct option record_options[] = { | |||
1028 | "number of mmap data pages"), | 1020 | "number of mmap data pages"), |
1029 | OPT_BOOLEAN(0, "group", &record.opts.group, | 1021 | OPT_BOOLEAN(0, "group", &record.opts.group, |
1030 | "put the counters into a counter group"), | 1022 | "put the counters into a counter group"), |
1031 | OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", | 1023 | OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, |
1032 | callchain_help, &parse_callchain_opt, | 1024 | "mode[,dump_size]", record_callchain_help, |
1033 | "fp"), | 1025 | &record_parse_callchain_opt, "fp"), |
1034 | OPT_INCR('v', "verbose", &verbose, | 1026 | OPT_INCR('v', "verbose", &verbose, |
1035 | "be more verbose (show counter open errors, etc)"), | 1027 | "be more verbose (show counter open errors, etc)"), |
1036 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), | 1028 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fc251005dd3d..5134acf1c39a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -692,6 +692,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
692 | setup_browser(true); | 692 | setup_browser(true); |
693 | else { | 693 | else { |
694 | use_browser = 0; | 694 | use_browser = 0; |
695 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
695 | perf_hpp__init(); | 696 | perf_hpp__init(); |
696 | } | 697 | } |
697 | 698 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c247faca7127..c12655af2b88 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -153,7 +153,7 @@ retry: | |||
153 | } | 153 | } |
154 | 154 | ||
155 | if (!perf_target__has_task(&target) && | 155 | if (!perf_target__has_task(&target) && |
156 | !perf_evsel__is_group_member(evsel)) { | 156 | perf_evsel__is_group_leader(evsel)) { |
157 | attr->disabled = 1; | 157 | attr->disabled = 1; |
158 | attr->enable_on_exec = 1; | 158 | attr->enable_on_exec = 1; |
159 | } | 159 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9ff3950cd4b..b7d2ea62dbc6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -596,7 +596,7 @@ static void *display_thread_tui(void *arg) | |||
596 | * via --uid. | 596 | * via --uid. |
597 | */ | 597 | */ |
598 | list_for_each_entry(pos, &top->evlist->entries, node) | 598 | list_for_each_entry(pos, &top->evlist->entries, node) |
599 | pos->hists.uid_filter_str = top->target.uid_str; | 599 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
600 | 600 | ||
601 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | 601 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
602 | &top->session->header.env); | 602 | &top->session->header.env); |
@@ -727,7 +727,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
727 | } | 727 | } |
728 | 728 | ||
729 | if (!machine) { | 729 | if (!machine) { |
730 | pr_err("%u unprocessable samples recorded.", | 730 | pr_err("%u unprocessable samples recorded.\n", |
731 | top->session->hists.stats.nr_unprocessable_samples++); | 731 | top->session->hists.stats.nr_unprocessable_samples++); |
732 | return; | 732 | return; |
733 | } | 733 | } |
@@ -894,35 +894,13 @@ static void perf_top__start_counters(struct perf_top *top) | |||
894 | { | 894 | { |
895 | struct perf_evsel *counter; | 895 | struct perf_evsel *counter; |
896 | struct perf_evlist *evlist = top->evlist; | 896 | struct perf_evlist *evlist = top->evlist; |
897 | struct perf_record_opts *opts = &top->record_opts; | ||
897 | 898 | ||
898 | if (top->group) | 899 | perf_evlist__config(evlist, opts); |
899 | perf_evlist__set_leader(evlist); | ||
900 | 900 | ||
901 | list_for_each_entry(counter, &evlist->entries, node) { | 901 | list_for_each_entry(counter, &evlist->entries, node) { |
902 | struct perf_event_attr *attr = &counter->attr; | 902 | struct perf_event_attr *attr = &counter->attr; |
903 | 903 | ||
904 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | ||
905 | |||
906 | if (top->freq) { | ||
907 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
908 | attr->freq = 1; | ||
909 | attr->sample_freq = top->freq; | ||
910 | } | ||
911 | |||
912 | if (evlist->nr_entries > 1) { | ||
913 | attr->sample_type |= PERF_SAMPLE_ID; | ||
914 | attr->read_format |= PERF_FORMAT_ID; | ||
915 | } | ||
916 | |||
917 | if (perf_target__has_cpu(&top->target)) | ||
918 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
919 | |||
920 | if (symbol_conf.use_callchain) | ||
921 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
922 | |||
923 | attr->mmap = 1; | ||
924 | attr->comm = 1; | ||
925 | attr->inherit = top->inherit; | ||
926 | fallback_missing_features: | 904 | fallback_missing_features: |
927 | if (top->exclude_guest_missing) | 905 | if (top->exclude_guest_missing) |
928 | attr->exclude_guest = attr->exclude_host = 0; | 906 | attr->exclude_guest = attr->exclude_host = 0; |
@@ -996,7 +974,7 @@ try_again: | |||
996 | } | 974 | } |
997 | } | 975 | } |
998 | 976 | ||
999 | if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { | 977 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
1000 | ui__error("Failed to mmap with %d (%s)\n", | 978 | ui__error("Failed to mmap with %d (%s)\n", |
1001 | errno, strerror(errno)); | 979 | errno, strerror(errno)); |
1002 | goto out_err; | 980 | goto out_err; |
@@ -1016,7 +994,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1016 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 994 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
1017 | return -EINVAL; | 995 | return -EINVAL; |
1018 | } | 996 | } |
1019 | } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { | 997 | } else if (callchain_param.mode != CHAIN_NONE) { |
1020 | if (callchain_register_param(&callchain_param) < 0) { | 998 | if (callchain_register_param(&callchain_param) < 0) { |
1021 | ui__error("Can't register callchain params.\n"); | 999 | ui__error("Can't register callchain params.\n"); |
1022 | return -EINVAL; | 1000 | return -EINVAL; |
@@ -1028,6 +1006,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1028 | 1006 | ||
1029 | static int __cmd_top(struct perf_top *top) | 1007 | static int __cmd_top(struct perf_top *top) |
1030 | { | 1008 | { |
1009 | struct perf_record_opts *opts = &top->record_opts; | ||
1031 | pthread_t thread; | 1010 | pthread_t thread; |
1032 | int ret; | 1011 | int ret; |
1033 | /* | 1012 | /* |
@@ -1042,7 +1021,7 @@ static int __cmd_top(struct perf_top *top) | |||
1042 | if (ret) | 1021 | if (ret) |
1043 | goto out_delete; | 1022 | goto out_delete; |
1044 | 1023 | ||
1045 | if (perf_target__has_task(&top->target)) | 1024 | if (perf_target__has_task(&opts->target)) |
1046 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 1025 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
1047 | perf_event__process, | 1026 | perf_event__process, |
1048 | &top->session->host_machine); | 1027 | &top->session->host_machine); |
@@ -1053,6 +1032,17 @@ static int __cmd_top(struct perf_top *top) | |||
1053 | top->session->evlist = top->evlist; | 1032 | top->session->evlist = top->evlist; |
1054 | perf_session__set_id_hdr_size(top->session); | 1033 | perf_session__set_id_hdr_size(top->session); |
1055 | 1034 | ||
1035 | /* | ||
1036 | * When perf is starting the traced process, all the events (apart from | ||
1037 | * group members) have enable_on_exec=1 set, so don't spoil it by | ||
1038 | * prematurely enabling them. | ||
1039 | * | ||
1040 | * XXX 'top' still doesn't start workloads like record, trace, but should, | ||
1041 | * so leave the check here. | ||
1042 | */ | ||
1043 | if (!perf_target__none(&opts->target)) | ||
1044 | perf_evlist__enable(top->evlist); | ||
1045 | |||
1056 | /* Wait for a minimal set of events before starting the snapshot */ | 1046 | /* Wait for a minimal set of events before starting the snapshot */ |
1057 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 1047 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1058 | 1048 | ||
@@ -1093,116 +1083,56 @@ out_delete: | |||
1093 | static int | 1083 | static int |
1094 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1084 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1095 | { | 1085 | { |
1096 | struct perf_top *top = (struct perf_top *)opt->value; | ||
1097 | char *tok, *tok2; | ||
1098 | char *endptr; | ||
1099 | |||
1100 | /* | 1086 | /* |
1101 | * --no-call-graph | 1087 | * --no-call-graph |
1102 | */ | 1088 | */ |
1103 | if (unset) { | 1089 | if (unset) |
1104 | top->dont_use_callchains = true; | ||
1105 | return 0; | 1090 | return 0; |
1106 | } | ||
1107 | 1091 | ||
1108 | symbol_conf.use_callchain = true; | 1092 | symbol_conf.use_callchain = true; |
1109 | 1093 | ||
1110 | if (!arg) | 1094 | return record_parse_callchain_opt(opt, arg, unset); |
1111 | return 0; | ||
1112 | |||
1113 | tok = strtok((char *)arg, ","); | ||
1114 | if (!tok) | ||
1115 | return -1; | ||
1116 | |||
1117 | /* get the output mode */ | ||
1118 | if (!strncmp(tok, "graph", strlen(arg))) | ||
1119 | callchain_param.mode = CHAIN_GRAPH_ABS; | ||
1120 | |||
1121 | else if (!strncmp(tok, "flat", strlen(arg))) | ||
1122 | callchain_param.mode = CHAIN_FLAT; | ||
1123 | |||
1124 | else if (!strncmp(tok, "fractal", strlen(arg))) | ||
1125 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
1126 | |||
1127 | else if (!strncmp(tok, "none", strlen(arg))) { | ||
1128 | callchain_param.mode = CHAIN_NONE; | ||
1129 | symbol_conf.use_callchain = false; | ||
1130 | |||
1131 | return 0; | ||
1132 | } else | ||
1133 | return -1; | ||
1134 | |||
1135 | /* get the min percentage */ | ||
1136 | tok = strtok(NULL, ","); | ||
1137 | if (!tok) | ||
1138 | goto setup; | ||
1139 | |||
1140 | callchain_param.min_percent = strtod(tok, &endptr); | ||
1141 | if (tok == endptr) | ||
1142 | return -1; | ||
1143 | |||
1144 | /* get the print limit */ | ||
1145 | tok2 = strtok(NULL, ","); | ||
1146 | if (!tok2) | ||
1147 | goto setup; | ||
1148 | |||
1149 | if (tok2[0] != 'c') { | ||
1150 | callchain_param.print_limit = strtod(tok2, &endptr); | ||
1151 | tok2 = strtok(NULL, ","); | ||
1152 | if (!tok2) | ||
1153 | goto setup; | ||
1154 | } | ||
1155 | |||
1156 | /* get the call chain order */ | ||
1157 | if (!strcmp(tok2, "caller")) | ||
1158 | callchain_param.order = ORDER_CALLER; | ||
1159 | else if (!strcmp(tok2, "callee")) | ||
1160 | callchain_param.order = ORDER_CALLEE; | ||
1161 | else | ||
1162 | return -1; | ||
1163 | setup: | ||
1164 | if (callchain_register_param(&callchain_param) < 0) { | ||
1165 | fprintf(stderr, "Can't register callchain params\n"); | ||
1166 | return -1; | ||
1167 | } | ||
1168 | return 0; | ||
1169 | } | 1095 | } |
1170 | 1096 | ||
1171 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1097 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1172 | { | 1098 | { |
1173 | struct perf_evsel *pos; | ||
1174 | int status; | 1099 | int status; |
1175 | char errbuf[BUFSIZ]; | 1100 | char errbuf[BUFSIZ]; |
1176 | struct perf_top top = { | 1101 | struct perf_top top = { |
1177 | .count_filter = 5, | 1102 | .count_filter = 5, |
1178 | .delay_secs = 2, | 1103 | .delay_secs = 2, |
1179 | .freq = 4000, /* 4 KHz */ | 1104 | .record_opts = { |
1180 | .mmap_pages = 128, | 1105 | .mmap_pages = UINT_MAX, |
1181 | .sym_pcnt_filter = 5, | 1106 | .user_freq = UINT_MAX, |
1182 | .target = { | 1107 | .user_interval = ULLONG_MAX, |
1183 | .uses_mmap = true, | 1108 | .freq = 4000, /* 4 KHz */ |
1109 | .target = { | ||
1110 | .uses_mmap = true, | ||
1111 | }, | ||
1184 | }, | 1112 | }, |
1113 | .sym_pcnt_filter = 5, | ||
1185 | }; | 1114 | }; |
1186 | char callchain_default_opt[] = "fractal,0.5,callee"; | 1115 | struct perf_record_opts *opts = &top.record_opts; |
1116 | struct perf_target *target = &opts->target; | ||
1187 | const struct option options[] = { | 1117 | const struct option options[] = { |
1188 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1118 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1189 | "event selector. use 'perf list' to list available events", | 1119 | "event selector. use 'perf list' to list available events", |
1190 | parse_events_option), | 1120 | parse_events_option), |
1191 | OPT_INTEGER('c', "count", &top.default_interval, | 1121 | OPT_U64('c', "count", &opts->user_interval, "event period to sample"), |
1192 | "event period to sample"), | 1122 | OPT_STRING('p', "pid", &target->pid, "pid", |
1193 | OPT_STRING('p', "pid", &top.target.pid, "pid", | ||
1194 | "profile events on existing process id"), | 1123 | "profile events on existing process id"), |
1195 | OPT_STRING('t', "tid", &top.target.tid, "tid", | 1124 | OPT_STRING('t', "tid", &target->tid, "tid", |
1196 | "profile events on existing thread id"), | 1125 | "profile events on existing thread id"), |
1197 | OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, | 1126 | OPT_BOOLEAN('a', "all-cpus", &target->system_wide, |
1198 | "system-wide collection from all CPUs"), | 1127 | "system-wide collection from all CPUs"), |
1199 | OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", | 1128 | OPT_STRING('C', "cpu", &target->cpu_list, "cpu", |
1200 | "list of cpus to monitor"), | 1129 | "list of cpus to monitor"), |
1201 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1130 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1202 | "file", "vmlinux pathname"), | 1131 | "file", "vmlinux pathname"), |
1203 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1132 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1204 | "hide kernel symbols"), | 1133 | "hide kernel symbols"), |
1205 | OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), | 1134 | OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, |
1135 | "number of mmap data pages"), | ||
1206 | OPT_INTEGER('r', "realtime", &top.realtime_prio, | 1136 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1207 | "collect data with this RT SCHED_FIFO priority"), | 1137 | "collect data with this RT SCHED_FIFO priority"), |
1208 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1138 | OPT_INTEGER('d', "delay", &top.delay_secs, |
@@ -1211,16 +1141,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1211 | "dump the symbol table used for profiling"), | 1141 | "dump the symbol table used for profiling"), |
1212 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1142 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1213 | "only display functions with more events than this"), | 1143 | "only display functions with more events than this"), |
1214 | OPT_BOOLEAN('g', "group", &top.group, | 1144 | OPT_BOOLEAN('g', "group", &opts->group, |
1215 | "put the counters into a counter group"), | 1145 | "put the counters into a counter group"), |
1216 | OPT_BOOLEAN('i', "inherit", &top.inherit, | 1146 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1217 | "child tasks inherit counters"), | 1147 | "child tasks do not inherit counters"), |
1218 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", | 1148 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", |
1219 | "symbol to annotate"), | 1149 | "symbol to annotate"), |
1220 | OPT_BOOLEAN('z', "zero", &top.zero, | 1150 | OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), |
1221 | "zero history across updates"), | 1151 | OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), |
1222 | OPT_INTEGER('F', "freq", &top.freq, | ||
1223 | "profile at this frequency"), | ||
1224 | OPT_INTEGER('E', "entries", &top.print_entries, | 1152 | OPT_INTEGER('E', "entries", &top.print_entries, |
1225 | "display this many functions"), | 1153 | "display this many functions"), |
1226 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1154 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
@@ -1233,10 +1161,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1233 | "sort by key(s): pid, comm, dso, symbol, parent"), | 1161 | "sort by key(s): pid, comm, dso, symbol, parent"), |
1234 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1162 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1235 | "Show a column with the number of samples"), | 1163 | "Show a column with the number of samples"), |
1236 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", | 1164 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, |
1237 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " | 1165 | "mode[,dump_size]", record_callchain_help, |
1238 | "Default: fractal,0.5,callee", &parse_callchain_opt, | 1166 | &parse_callchain_opt, "fp"), |
1239 | callchain_default_opt), | ||
1240 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1167 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
1241 | "Show a column with the sum of periods"), | 1168 | "Show a column with the sum of periods"), |
1242 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 1169 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -1251,7 +1178,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1251 | "Display raw encoding of assembly instructions (default)"), | 1178 | "Display raw encoding of assembly instructions (default)"), |
1252 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1179 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1253 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1180 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1254 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), | 1181 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
1255 | OPT_END() | 1182 | OPT_END() |
1256 | }; | 1183 | }; |
1257 | const char * const top_usage[] = { | 1184 | const char * const top_usage[] = { |
@@ -1281,27 +1208,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1281 | 1208 | ||
1282 | setup_browser(false); | 1209 | setup_browser(false); |
1283 | 1210 | ||
1284 | status = perf_target__validate(&top.target); | 1211 | status = perf_target__validate(target); |
1285 | if (status) { | 1212 | if (status) { |
1286 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1213 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1287 | ui__warning("%s", errbuf); | 1214 | ui__warning("%s", errbuf); |
1288 | } | 1215 | } |
1289 | 1216 | ||
1290 | status = perf_target__parse_uid(&top.target); | 1217 | status = perf_target__parse_uid(target); |
1291 | if (status) { | 1218 | if (status) { |
1292 | int saved_errno = errno; | 1219 | int saved_errno = errno; |
1293 | 1220 | ||
1294 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1221 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1295 | ui__error("%s", errbuf); | 1222 | ui__error("%s", errbuf); |
1296 | 1223 | ||
1297 | status = -saved_errno; | 1224 | status = -saved_errno; |
1298 | goto out_delete_evlist; | 1225 | goto out_delete_evlist; |
1299 | } | 1226 | } |
1300 | 1227 | ||
1301 | if (perf_target__none(&top.target)) | 1228 | if (perf_target__none(target)) |
1302 | top.target.system_wide = true; | 1229 | target->system_wide = true; |
1303 | 1230 | ||
1304 | if (perf_evlist__create_maps(top.evlist, &top.target) < 0) | 1231 | if (perf_evlist__create_maps(top.evlist, target) < 0) |
1305 | usage_with_options(top_usage, options); | 1232 | usage_with_options(top_usage, options); |
1306 | 1233 | ||
1307 | if (!top.evlist->nr_entries && | 1234 | if (!top.evlist->nr_entries && |
@@ -1315,24 +1242,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1315 | if (top.delay_secs < 1) | 1242 | if (top.delay_secs < 1) |
1316 | top.delay_secs = 1; | 1243 | top.delay_secs = 1; |
1317 | 1244 | ||
1245 | if (opts->user_interval != ULLONG_MAX) | ||
1246 | opts->default_interval = opts->user_interval; | ||
1247 | if (opts->user_freq != UINT_MAX) | ||
1248 | opts->freq = opts->user_freq; | ||
1249 | |||
1318 | /* | 1250 | /* |
1319 | * User specified count overrides default frequency. | 1251 | * User specified count overrides default frequency. |
1320 | */ | 1252 | */ |
1321 | if (top.default_interval) | 1253 | if (opts->default_interval) |
1322 | top.freq = 0; | 1254 | opts->freq = 0; |
1323 | else if (top.freq) { | 1255 | else if (opts->freq) { |
1324 | top.default_interval = top.freq; | 1256 | opts->default_interval = opts->freq; |
1325 | } else { | 1257 | } else { |
1326 | ui__error("frequency and count are zero, aborting\n"); | 1258 | ui__error("frequency and count are zero, aborting\n"); |
1327 | exit(EXIT_FAILURE); | 1259 | status = -EINVAL; |
1328 | } | 1260 | goto out_delete_evlist; |
1329 | |||
1330 | list_for_each_entry(pos, &top.evlist->entries, node) { | ||
1331 | /* | ||
1332 | * Fill in the ones not specifically initialized via -c: | ||
1333 | */ | ||
1334 | if (!pos->attr.sample_period) | ||
1335 | pos->attr.sample_period = top.default_interval; | ||
1336 | } | 1261 | } |
1337 | 1262 | ||
1338 | top.sym_evsel = perf_evlist__first(top.evlist); | 1263 | top.sym_evsel = perf_evlist__first(top.evlist); |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 7932ffa29889..d222d7fc7e96 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
455 | goto out_delete_evlist; | 455 | goto out_delete_evlist; |
456 | } | 456 | } |
457 | 457 | ||
458 | perf_evlist__config_attrs(evlist, &trace->opts); | 458 | perf_evlist__config(evlist, &trace->opts); |
459 | 459 | ||
460 | signal(SIGCHLD, sig_handler); | 460 | signal(SIGCHLD, sig_handler); |
461 | signal(SIGINT, sig_handler); | 461 | signal(SIGINT, sig_handler); |
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index f1485d8e6a0b..5bc3880f7be5 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record | |||
@@ -7,7 +7,7 @@ size=96 | |||
7 | config=0 | 7 | config=0 |
8 | sample_period=4000 | 8 | sample_period=4000 |
9 | sample_type=263 | 9 | sample_type=263 |
10 | read_format=7 | 10 | read_format=0 |
11 | disabled=1 | 11 | disabled=1 |
12 | inherit=1 | 12 | inherit=1 |
13 | pinned=0 | 13 | pinned=0 |
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group index a6599e9a19d3..57739cacdb2a 100644 --- a/tools/perf/tests/attr/test-record-group +++ b/tools/perf/tests/attr/test-record-group | |||
@@ -6,12 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1 | |||
6 | fd=1 | 6 | fd=1 |
7 | group_fd=-1 | 7 | group_fd=-1 |
8 | sample_type=327 | 8 | sample_type=327 |
9 | read_format=4 | ||
9 | 10 | ||
10 | [event-2:base-record] | 11 | [event-2:base-record] |
11 | fd=2 | 12 | fd=2 |
12 | group_fd=1 | 13 | group_fd=1 |
13 | config=1 | 14 | config=1 |
14 | sample_type=327 | 15 | sample_type=327 |
16 | read_format=4 | ||
15 | mmap=0 | 17 | mmap=0 |
16 | comm=0 | 18 | comm=0 |
17 | enable_on_exec=0 | 19 | enable_on_exec=0 |
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 index 5a8359da38af..4d688a13fd2f 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/attr/test-record-group1 | |||
@@ -6,6 +6,7 @@ args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 | |||
6 | fd=1 | 6 | fd=1 |
7 | group_fd=-1 | 7 | group_fd=-1 |
8 | sample_type=327 | 8 | sample_type=327 |
9 | read_format=4 | ||
9 | 10 | ||
10 | [event-2:base-record] | 11 | [event-2:base-record] |
11 | fd=2 | 12 | fd=2 |
@@ -13,6 +14,7 @@ group_fd=1 | |||
13 | type=0 | 14 | type=0 |
14 | config=1 | 15 | config=1 |
15 | sample_type=327 | 16 | sample_type=327 |
17 | read_format=4 | ||
16 | mmap=0 | 18 | mmap=0 |
17 | comm=0 | 19 | comm=0 |
18 | enable_on_exec=0 | 20 | enable_on_exec=0 |
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index e1746811e14b..cdd50755af51 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
@@ -22,36 +22,16 @@ int test__basic_mmap(void) | |||
22 | struct thread_map *threads; | 22 | struct thread_map *threads; |
23 | struct cpu_map *cpus; | 23 | struct cpu_map *cpus; |
24 | struct perf_evlist *evlist; | 24 | struct perf_evlist *evlist; |
25 | struct perf_event_attr attr = { | ||
26 | .type = PERF_TYPE_TRACEPOINT, | ||
27 | .read_format = PERF_FORMAT_ID, | ||
28 | .sample_type = PERF_SAMPLE_ID, | ||
29 | .watermark = 0, | ||
30 | }; | ||
31 | cpu_set_t cpu_set; | 25 | cpu_set_t cpu_set; |
32 | const char *syscall_names[] = { "getsid", "getppid", "getpgrp", | 26 | const char *syscall_names[] = { "getsid", "getppid", "getpgrp", |
33 | "getpgid", }; | 27 | "getpgid", }; |
34 | pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, | 28 | pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, |
35 | (void*)getpgid }; | 29 | (void*)getpgid }; |
36 | #define nsyscalls ARRAY_SIZE(syscall_names) | 30 | #define nsyscalls ARRAY_SIZE(syscall_names) |
37 | int ids[nsyscalls]; | ||
38 | unsigned int nr_events[nsyscalls], | 31 | unsigned int nr_events[nsyscalls], |
39 | expected_nr_events[nsyscalls], i, j; | 32 | expected_nr_events[nsyscalls], i, j; |
40 | struct perf_evsel *evsels[nsyscalls], *evsel; | 33 | struct perf_evsel *evsels[nsyscalls], *evsel; |
41 | 34 | ||
42 | for (i = 0; i < nsyscalls; ++i) { | ||
43 | char name[64]; | ||
44 | |||
45 | snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); | ||
46 | ids[i] = trace_event__id(name); | ||
47 | if (ids[i] < 0) { | ||
48 | pr_debug("Is debugfs mounted on /sys/kernel/debug?\n"); | ||
49 | return -1; | ||
50 | } | ||
51 | nr_events[i] = 0; | ||
52 | expected_nr_events[i] = random() % 257; | ||
53 | } | ||
54 | |||
55 | threads = thread_map__new(-1, getpid(), UINT_MAX); | 35 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
56 | if (threads == NULL) { | 36 | if (threads == NULL) { |
57 | pr_debug("thread_map__new\n"); | 37 | pr_debug("thread_map__new\n"); |
@@ -79,18 +59,19 @@ int test__basic_mmap(void) | |||
79 | goto out_free_cpus; | 59 | goto out_free_cpus; |
80 | } | 60 | } |
81 | 61 | ||
82 | /* anonymous union fields, can't be initialized above */ | ||
83 | attr.wakeup_events = 1; | ||
84 | attr.sample_period = 1; | ||
85 | |||
86 | for (i = 0; i < nsyscalls; ++i) { | 62 | for (i = 0; i < nsyscalls; ++i) { |
87 | attr.config = ids[i]; | 63 | char name[64]; |
88 | evsels[i] = perf_evsel__new(&attr, i); | 64 | |
65 | snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); | ||
66 | evsels[i] = perf_evsel__newtp("syscalls", name, i); | ||
89 | if (evsels[i] == NULL) { | 67 | if (evsels[i] == NULL) { |
90 | pr_debug("perf_evsel__new\n"); | 68 | pr_debug("perf_evsel__new\n"); |
91 | goto out_free_evlist; | 69 | goto out_free_evlist; |
92 | } | 70 | } |
93 | 71 | ||
72 | evsels[i]->attr.wakeup_events = 1; | ||
73 | perf_evsel__set_sample_id(evsels[i]); | ||
74 | |||
94 | perf_evlist__add(evlist, evsels[i]); | 75 | perf_evlist__add(evlist, evsels[i]); |
95 | 76 | ||
96 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { | 77 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { |
@@ -99,6 +80,9 @@ int test__basic_mmap(void) | |||
99 | strerror(errno)); | 80 | strerror(errno)); |
100 | goto out_close_fd; | 81 | goto out_close_fd; |
101 | } | 82 | } |
83 | |||
84 | nr_events[i] = 0; | ||
85 | expected_nr_events[i] = 1 + rand() % 127; | ||
102 | } | 86 | } |
103 | 87 | ||
104 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 88 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
@@ -128,6 +112,7 @@ int test__basic_mmap(void) | |||
128 | goto out_munmap; | 112 | goto out_munmap; |
129 | } | 113 | } |
130 | 114 | ||
115 | err = -1; | ||
131 | evsel = perf_evlist__id2evsel(evlist, sample.id); | 116 | evsel = perf_evlist__id2evsel(evlist, sample.id); |
132 | if (evsel == NULL) { | 117 | if (evsel == NULL) { |
133 | pr_debug("event with id %" PRIu64 | 118 | pr_debug("event with id %" PRIu64 |
@@ -137,16 +122,17 @@ int test__basic_mmap(void) | |||
137 | nr_events[evsel->idx]++; | 122 | nr_events[evsel->idx]++; |
138 | } | 123 | } |
139 | 124 | ||
125 | err = 0; | ||
140 | list_for_each_entry(evsel, &evlist->entries, node) { | 126 | list_for_each_entry(evsel, &evlist->entries, node) { |
141 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { | 127 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { |
142 | pr_debug("expected %d %s events, got %d\n", | 128 | pr_debug("expected %d %s events, got %d\n", |
143 | expected_nr_events[evsel->idx], | 129 | expected_nr_events[evsel->idx], |
144 | perf_evsel__name(evsel), nr_events[evsel->idx]); | 130 | perf_evsel__name(evsel), nr_events[evsel->idx]); |
131 | err = -1; | ||
145 | goto out_munmap; | 132 | goto out_munmap; |
146 | } | 133 | } |
147 | } | 134 | } |
148 | 135 | ||
149 | err = 0; | ||
150 | out_munmap: | 136 | out_munmap: |
151 | perf_evlist__munmap(evlist); | 137 | perf_evlist__munmap(evlist); |
152 | out_close_fd: | 138 | out_close_fd: |
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c index 31072aba0d54..9b920a0cce79 100644 --- a/tools/perf/tests/open-syscall-all-cpus.c +++ b/tools/perf/tests/open-syscall-all-cpus.c | |||
@@ -7,20 +7,12 @@ | |||
7 | int test__open_syscall_event_on_all_cpus(void) | 7 | int test__open_syscall_event_on_all_cpus(void) |
8 | { | 8 | { |
9 | int err = -1, fd, cpu; | 9 | int err = -1, fd, cpu; |
10 | struct thread_map *threads; | ||
11 | struct cpu_map *cpus; | 10 | struct cpu_map *cpus; |
12 | struct perf_evsel *evsel; | 11 | struct perf_evsel *evsel; |
13 | struct perf_event_attr attr; | ||
14 | unsigned int nr_open_calls = 111, i; | 12 | unsigned int nr_open_calls = 111, i; |
15 | cpu_set_t cpu_set; | 13 | cpu_set_t cpu_set; |
16 | int id = trace_event__id("sys_enter_open"); | 14 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
17 | 15 | ||
18 | if (id < 0) { | ||
19 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); | ||
20 | return -1; | ||
21 | } | ||
22 | |||
23 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
24 | if (threads == NULL) { | 16 | if (threads == NULL) { |
25 | pr_debug("thread_map__new\n"); | 17 | pr_debug("thread_map__new\n"); |
26 | return -1; | 18 | return -1; |
@@ -32,15 +24,11 @@ int test__open_syscall_event_on_all_cpus(void) | |||
32 | goto out_thread_map_delete; | 24 | goto out_thread_map_delete; |
33 | } | 25 | } |
34 | 26 | ||
35 | |||
36 | CPU_ZERO(&cpu_set); | 27 | CPU_ZERO(&cpu_set); |
37 | 28 | ||
38 | memset(&attr, 0, sizeof(attr)); | 29 | evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); |
39 | attr.type = PERF_TYPE_TRACEPOINT; | ||
40 | attr.config = id; | ||
41 | evsel = perf_evsel__new(&attr, 0); | ||
42 | if (evsel == NULL) { | 30 | if (evsel == NULL) { |
43 | pr_debug("perf_evsel__new\n"); | 31 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); |
44 | goto out_thread_map_delete; | 32 | goto out_thread_map_delete; |
45 | } | 33 | } |
46 | 34 | ||
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c index 98be8b518b4f..befc0671f95d 100644 --- a/tools/perf/tests/open-syscall.c +++ b/tools/perf/tests/open-syscall.c | |||
@@ -6,29 +6,18 @@ | |||
6 | int test__open_syscall_event(void) | 6 | int test__open_syscall_event(void) |
7 | { | 7 | { |
8 | int err = -1, fd; | 8 | int err = -1, fd; |
9 | struct thread_map *threads; | ||
10 | struct perf_evsel *evsel; | 9 | struct perf_evsel *evsel; |
11 | struct perf_event_attr attr; | ||
12 | unsigned int nr_open_calls = 111, i; | 10 | unsigned int nr_open_calls = 111, i; |
13 | int id = trace_event__id("sys_enter_open"); | 11 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
14 | 12 | ||
15 | if (id < 0) { | ||
16 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); | ||
17 | return -1; | ||
18 | } | ||
19 | |||
20 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
21 | if (threads == NULL) { | 13 | if (threads == NULL) { |
22 | pr_debug("thread_map__new\n"); | 14 | pr_debug("thread_map__new\n"); |
23 | return -1; | 15 | return -1; |
24 | } | 16 | } |
25 | 17 | ||
26 | memset(&attr, 0, sizeof(attr)); | 18 | evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); |
27 | attr.type = PERF_TYPE_TRACEPOINT; | ||
28 | attr.config = id; | ||
29 | evsel = perf_evsel__new(&attr, 0); | ||
30 | if (evsel == NULL) { | 19 | if (evsel == NULL) { |
31 | pr_debug("perf_evsel__new\n"); | 20 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); |
32 | goto out_thread_map_delete; | 21 | goto out_thread_map_delete; |
33 | } | 22 | } |
34 | 23 | ||
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 32ee478905eb..294ffddfbf42 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -521,7 +521,7 @@ static int test__group1(struct perf_evlist *evlist) | |||
521 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 521 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
522 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 522 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
523 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 523 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
524 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 524 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
525 | 525 | ||
526 | /* cycles:upp */ | 526 | /* cycles:upp */ |
527 | evsel = perf_evsel__next(evsel); | 527 | evsel = perf_evsel__next(evsel); |
@@ -557,7 +557,7 @@ static int test__group2(struct perf_evlist *evlist) | |||
557 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 557 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
558 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 558 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
559 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 559 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
560 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 560 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
561 | 561 | ||
562 | /* cache-references + :u modifier */ | 562 | /* cache-references + :u modifier */ |
563 | evsel = perf_evsel__next(evsel); | 563 | evsel = perf_evsel__next(evsel); |
@@ -583,7 +583,7 @@ static int test__group2(struct perf_evlist *evlist) | |||
583 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 583 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
584 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 584 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
585 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 585 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
586 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 586 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
587 | 587 | ||
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
@@ -606,7 +606,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
606 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | 606 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
607 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 607 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
608 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 608 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
609 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 609 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
610 | TEST_ASSERT_VAL("wrong group name", | 610 | TEST_ASSERT_VAL("wrong group name", |
611 | !strcmp(leader->group_name, "group1")); | 611 | !strcmp(leader->group_name, "group1")); |
612 | 612 | ||
@@ -636,7 +636,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
636 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 636 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
637 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 637 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
638 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 638 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
639 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 639 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
640 | TEST_ASSERT_VAL("wrong group name", | 640 | TEST_ASSERT_VAL("wrong group name", |
641 | !strcmp(leader->group_name, "group2")); | 641 | !strcmp(leader->group_name, "group2")); |
642 | 642 | ||
@@ -663,7 +663,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
663 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 663 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
664 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 664 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
665 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 665 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
666 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 666 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
667 | 667 | ||
668 | return 0; | 668 | return 0; |
669 | } | 669 | } |
@@ -687,7 +687,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
687 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 687 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
688 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); | 688 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); |
689 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 689 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
690 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 690 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
691 | 691 | ||
692 | /* instructions:kp + p */ | 692 | /* instructions:kp + p */ |
693 | evsel = perf_evsel__next(evsel); | 693 | evsel = perf_evsel__next(evsel); |
@@ -724,7 +724,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
724 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 724 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
725 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 725 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
726 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 726 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
727 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 727 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
728 | 728 | ||
729 | /* instructions + G */ | 729 | /* instructions + G */ |
730 | evsel = perf_evsel__next(evsel); | 730 | evsel = perf_evsel__next(evsel); |
@@ -751,7 +751,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
751 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 751 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
752 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 752 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
753 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 753 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
754 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 754 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
755 | 755 | ||
756 | /* instructions:G */ | 756 | /* instructions:G */ |
757 | evsel = perf_evsel__next(evsel); | 757 | evsel = perf_evsel__next(evsel); |
@@ -777,7 +777,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
777 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | 777 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
778 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 778 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
779 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 779 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
780 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 780 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
781 | 781 | ||
782 | return 0; | 782 | return 0; |
783 | } | 783 | } |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 70e0d4421df8..6ea66cf6791b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -103,10 +103,10 @@ int test__PERF_RECORD(void) | |||
103 | * Config the evsels, setting attr->comm on the first one, etc. | 103 | * Config the evsels, setting attr->comm on the first one, etc. |
104 | */ | 104 | */ |
105 | evsel = perf_evlist__first(evlist); | 105 | evsel = perf_evlist__first(evlist); |
106 | evsel->attr.sample_type |= PERF_SAMPLE_CPU; | 106 | perf_evsel__set_sample_bit(evsel, CPU); |
107 | evsel->attr.sample_type |= PERF_SAMPLE_TID; | 107 | perf_evsel__set_sample_bit(evsel, TID); |
108 | evsel->attr.sample_type |= PERF_SAMPLE_TIME; | 108 | perf_evsel__set_sample_bit(evsel, TIME); |
109 | perf_evlist__config_attrs(evlist, &opts); | 109 | perf_evlist__config(evlist, &opts); |
110 | 110 | ||
111 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 111 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
112 | if (err < 0) { | 112 | if (err < 0) { |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index fc121edab016..0fd94657960e 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -16,7 +16,4 @@ int test__attr(void); | |||
16 | int test__dso_data(void); | 16 | int test__dso_data(void); |
17 | int test__parse_events(void); | 17 | int test__parse_events(void); |
18 | 18 | ||
19 | /* Util */ | ||
20 | int trace_event__id(const char *evname); | ||
21 | |||
22 | #endif /* TESTS_H */ | 19 | #endif /* TESTS_H */ |
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c deleted file mode 100644 index 748f2e8f6961..000000000000 --- a/tools/perf/tests/util.c +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <fcntl.h> | ||
7 | #include "tests.h" | ||
8 | #include "debugfs.h" | ||
9 | |||
10 | int trace_event__id(const char *evname) | ||
11 | { | ||
12 | char *filename; | ||
13 | int err = -1, fd; | ||
14 | |||
15 | if (asprintf(&filename, | ||
16 | "%s/syscalls/%s/id", | ||
17 | tracing_events_path, evname) < 0) | ||
18 | return -1; | ||
19 | |||
20 | fd = open(filename, O_RDONLY); | ||
21 | if (fd >= 0) { | ||
22 | char id[16]; | ||
23 | if (read(fd, id, sizeof(id)) > 0) | ||
24 | err = atoi(id); | ||
25 | close(fd); | ||
26 | } | ||
27 | |||
28 | free(filename); | ||
29 | return err; | ||
30 | } | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ccc4bd161420..57b82c26cd05 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -587,6 +587,8 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
587 | 587 | ||
588 | void hist_browser__init_hpp(void) | 588 | void hist_browser__init_hpp(void) |
589 | { | 589 | { |
590 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
591 | |||
590 | perf_hpp__init(); | 592 | perf_hpp__init(); |
591 | 593 | ||
592 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 594 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
@@ -607,12 +609,13 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
607 | { | 609 | { |
608 | char s[256]; | 610 | char s[256]; |
609 | double percent; | 611 | double percent; |
610 | int i, printed = 0; | 612 | int printed = 0; |
611 | int width = browser->b.width; | 613 | int width = browser->b.width; |
612 | char folded_sign = ' '; | 614 | char folded_sign = ' '; |
613 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 615 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
614 | off_t row_offset = entry->row_offset; | 616 | off_t row_offset = entry->row_offset; |
615 | bool first = true; | 617 | bool first = true; |
618 | struct perf_hpp_fmt *fmt; | ||
616 | 619 | ||
617 | if (current_entry) { | 620 | if (current_entry) { |
618 | browser->he_selection = entry; | 621 | browser->he_selection = entry; |
@@ -629,12 +632,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
629 | .buf = s, | 632 | .buf = s, |
630 | .size = sizeof(s), | 633 | .size = sizeof(s), |
631 | }; | 634 | }; |
635 | int i = 0; | ||
632 | 636 | ||
633 | ui_browser__gotorc(&browser->b, row, 0); | 637 | ui_browser__gotorc(&browser->b, row, 0); |
634 | 638 | ||
635 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 639 | perf_hpp__for_each_format(fmt) { |
636 | if (!perf_hpp__format[i].cond) | ||
637 | continue; | ||
638 | 640 | ||
639 | if (!first) { | 641 | if (!first) { |
640 | slsmg_printf(" "); | 642 | slsmg_printf(" "); |
@@ -642,14 +644,14 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
642 | } | 644 | } |
643 | first = false; | 645 | first = false; |
644 | 646 | ||
645 | if (perf_hpp__format[i].color) { | 647 | if (fmt->color) { |
646 | hpp.ptr = &percent; | 648 | hpp.ptr = &percent; |
647 | /* It will set percent for us. See HPP__COLOR_FN above. */ | 649 | /* It will set percent for us. See HPP__COLOR_FN above. */ |
648 | width -= perf_hpp__format[i].color(&hpp, entry); | 650 | width -= fmt->color(&hpp, entry); |
649 | 651 | ||
650 | ui_browser__set_percent_color(&browser->b, percent, current_entry); | 652 | ui_browser__set_percent_color(&browser->b, percent, current_entry); |
651 | 653 | ||
652 | if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { | 654 | if (!i && symbol_conf.use_callchain) { |
653 | slsmg_printf("%c ", folded_sign); | 655 | slsmg_printf("%c ", folded_sign); |
654 | width -= 2; | 656 | width -= 2; |
655 | } | 657 | } |
@@ -659,9 +661,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
659 | if (!current_entry || !browser->b.navkeypressed) | 661 | if (!current_entry || !browser->b.navkeypressed) |
660 | ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); | 662 | ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); |
661 | } else { | 663 | } else { |
662 | width -= perf_hpp__format[i].entry(&hpp, entry); | 664 | width -= fmt->entry(&hpp, entry); |
663 | slsmg_printf("%s", s); | 665 | slsmg_printf("%s", s); |
664 | } | 666 | } |
667 | |||
668 | i++; | ||
665 | } | 669 | } |
666 | 670 | ||
667 | /* The scroll bar isn't being used */ | 671 | /* The scroll bar isn't being used */ |
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 253b6219a39e..e59ba337f494 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
@@ -74,6 +74,8 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
74 | 74 | ||
75 | void perf_gtk__init_hpp(void) | 75 | void perf_gtk__init_hpp(void) |
76 | { | 76 | { |
77 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
78 | |||
77 | perf_hpp__init(); | 79 | perf_hpp__init(); |
78 | 80 | ||
79 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 81 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
@@ -90,13 +92,14 @@ void perf_gtk__init_hpp(void) | |||
90 | 92 | ||
91 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | 93 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) |
92 | { | 94 | { |
95 | struct perf_hpp_fmt *fmt; | ||
93 | GType col_types[MAX_COLUMNS]; | 96 | GType col_types[MAX_COLUMNS]; |
94 | GtkCellRenderer *renderer; | 97 | GtkCellRenderer *renderer; |
95 | struct sort_entry *se; | 98 | struct sort_entry *se; |
96 | GtkListStore *store; | 99 | GtkListStore *store; |
97 | struct rb_node *nd; | 100 | struct rb_node *nd; |
98 | GtkWidget *view; | 101 | GtkWidget *view; |
99 | int i, col_idx; | 102 | int col_idx; |
100 | int nr_cols; | 103 | int nr_cols; |
101 | char s[512]; | 104 | char s[512]; |
102 | 105 | ||
@@ -107,12 +110,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
107 | 110 | ||
108 | nr_cols = 0; | 111 | nr_cols = 0; |
109 | 112 | ||
110 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 113 | perf_hpp__for_each_format(fmt) |
111 | if (!perf_hpp__format[i].cond) | ||
112 | continue; | ||
113 | |||
114 | col_types[nr_cols++] = G_TYPE_STRING; | 114 | col_types[nr_cols++] = G_TYPE_STRING; |
115 | } | ||
116 | 115 | ||
117 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 116 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
118 | if (se->elide) | 117 | if (se->elide) |
@@ -129,12 +128,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
129 | 128 | ||
130 | col_idx = 0; | 129 | col_idx = 0; |
131 | 130 | ||
132 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 131 | perf_hpp__for_each_format(fmt) { |
133 | if (!perf_hpp__format[i].cond) | 132 | fmt->header(&hpp); |
134 | continue; | ||
135 | |||
136 | perf_hpp__format[i].header(&hpp); | ||
137 | |||
138 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | 133 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), |
139 | -1, s, | 134 | -1, s, |
140 | renderer, "markup", | 135 | renderer, "markup", |
@@ -166,14 +161,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
166 | 161 | ||
167 | col_idx = 0; | 162 | col_idx = 0; |
168 | 163 | ||
169 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 164 | perf_hpp__for_each_format(fmt) { |
170 | if (!perf_hpp__format[i].cond) | 165 | if (fmt->color) |
171 | continue; | 166 | fmt->color(&hpp, h); |
172 | |||
173 | if (perf_hpp__format[i].color) | ||
174 | perf_hpp__format[i].color(&hpp, h); | ||
175 | else | 167 | else |
176 | perf_hpp__format[i].entry(&hpp, h); | 168 | fmt->entry(&hpp, h); |
177 | 169 | ||
178 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | 170 | gtk_list_store_set(store, &iter, col_idx++, s, -1); |
179 | } | 171 | } |
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index 5db4432ff12a..3388cbd12186 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c | |||
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg) | |||
24 | pgctx->statbar_ctx_id, msg); | 24 | pgctx->statbar_ctx_id, msg); |
25 | } | 25 | } |
26 | 26 | ||
27 | static struct ui_helpline gtk_helpline_fns = { | 27 | static int gtk_helpline_show(const char *fmt, va_list ap) |
28 | .pop = gtk_helpline_pop, | ||
29 | .push = gtk_helpline_push, | ||
30 | }; | ||
31 | |||
32 | void perf_gtk__init_helpline(void) | ||
33 | { | ||
34 | helpline_fns = >k_helpline_fns; | ||
35 | } | ||
36 | |||
37 | int perf_gtk__show_helpline(const char *fmt, va_list ap) | ||
38 | { | 28 | { |
39 | int ret; | 29 | int ret; |
40 | char *ptr; | 30 | char *ptr; |
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap) | |||
54 | 44 | ||
55 | return ret; | 45 | return ret; |
56 | } | 46 | } |
47 | |||
48 | static struct ui_helpline gtk_helpline_fns = { | ||
49 | .pop = gtk_helpline_pop, | ||
50 | .push = gtk_helpline_push, | ||
51 | .show = gtk_helpline_show, | ||
52 | }; | ||
53 | |||
54 | void perf_gtk__init_helpline(void) | ||
55 | { | ||
56 | helpline_fns = >k_helpline_fns; | ||
57 | } | ||
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index a49bcf3c190b..700fb3cfa1c7 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c | |||
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused) | |||
16 | { | 16 | { |
17 | } | 17 | } |
18 | 18 | ||
19 | static int nop_helpline__show(const char *fmt __maybe_unused, | ||
20 | va_list ap __maybe_unused) | ||
21 | { | ||
22 | return 0; | ||
23 | } | ||
24 | |||
19 | static struct ui_helpline default_helpline_fns = { | 25 | static struct ui_helpline default_helpline_fns = { |
20 | .pop = nop_helpline__pop, | 26 | .pop = nop_helpline__pop, |
21 | .push = nop_helpline__push, | 27 | .push = nop_helpline__push, |
28 | .show = nop_helpline__show, | ||
22 | }; | 29 | }; |
23 | 30 | ||
24 | struct ui_helpline *helpline_fns = &default_helpline_fns; | 31 | struct ui_helpline *helpline_fns = &default_helpline_fns; |
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg) | |||
59 | ui_helpline__pop(); | 66 | ui_helpline__pop(); |
60 | ui_helpline__push(msg); | 67 | ui_helpline__push(msg); |
61 | } | 68 | } |
69 | |||
70 | int ui_helpline__vshow(const char *fmt, va_list ap) | ||
71 | { | ||
72 | return helpline_fns->show(fmt, ap); | ||
73 | } | ||
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index baa28a4d16b9..46181f4fc07e 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h | |||
@@ -9,6 +9,7 @@ | |||
9 | struct ui_helpline { | 9 | struct ui_helpline { |
10 | void (*pop)(void); | 10 | void (*pop)(void); |
11 | void (*push)(const char *msg); | 11 | void (*push)(const char *msg); |
12 | int (*show)(const char *fmt, va_list ap); | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | extern struct ui_helpline *helpline_fns; | 15 | extern struct ui_helpline *helpline_fns; |
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg); | |||
20 | void ui_helpline__vpush(const char *fmt, va_list ap); | 21 | void ui_helpline__vpush(const char *fmt, va_list ap); |
21 | void ui_helpline__fpush(const char *fmt, ...); | 22 | void ui_helpline__fpush(const char *fmt, ...); |
22 | void ui_helpline__puts(const char *msg); | 23 | void ui_helpline__puts(const char *msg); |
24 | int ui_helpline__vshow(const char *fmt, va_list ap); | ||
23 | 25 | ||
24 | extern char ui_helpline__current[512]; | 26 | extern char ui_helpline__current[512]; |
25 | |||
26 | #ifdef NEWT_SUPPORT | ||
27 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
28 | int ui_helpline__show_help(const char *format, va_list ap); | ||
29 | #else | ||
30 | static inline int ui_helpline__show_help(const char *format __maybe_unused, | ||
31 | va_list ap __maybe_unused) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | #endif /* NEWT_SUPPORT */ | ||
36 | |||
37 | #ifdef GTK2_SUPPORT | ||
38 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
39 | #else | ||
40 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, | ||
41 | va_list ap __maybe_unused) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | #endif /* GTK2_SUPPORT */ | ||
46 | 28 | ||
47 | #endif /* _PERF_UI_HELPLINE_H_ */ | 29 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index aa84130024d5..1889c12ca81f 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -268,14 +268,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
268 | 268 | ||
269 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 269 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
270 | { | 270 | { |
271 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
271 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 272 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
272 | char buf[32] = " "; | 273 | char buf[32] = " "; |
273 | double diff; | 274 | double diff = 0.0; |
274 | 275 | ||
275 | if (he->diff.computed) | 276 | if (pair) { |
276 | diff = he->diff.period_ratio_delta; | 277 | if (he->diff.computed) |
277 | else | 278 | diff = he->diff.period_ratio_delta; |
278 | diff = perf_diff__compute_delta(he); | 279 | else |
280 | diff = perf_diff__compute_delta(he, pair); | ||
281 | } else | ||
282 | diff = perf_diff__period_percent(he, he->stat.period); | ||
279 | 283 | ||
280 | if (fabs(diff) >= 0.01) | 284 | if (fabs(diff) >= 0.01) |
281 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | 285 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); |
@@ -297,14 +301,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | |||
297 | 301 | ||
298 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | 302 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) |
299 | { | 303 | { |
304 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
300 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 305 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
301 | char buf[32] = " "; | 306 | char buf[32] = " "; |
302 | double ratio; | 307 | double ratio = 0.0; |
303 | 308 | ||
304 | if (he->diff.computed) | 309 | if (pair) { |
305 | ratio = he->diff.period_ratio; | 310 | if (he->diff.computed) |
306 | else | 311 | ratio = he->diff.period_ratio; |
307 | ratio = perf_diff__compute_ratio(he); | 312 | else |
313 | ratio = perf_diff__compute_ratio(he, pair); | ||
314 | } | ||
308 | 315 | ||
309 | if (ratio > 0.0) | 316 | if (ratio > 0.0) |
310 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | 317 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); |
@@ -326,14 +333,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | |||
326 | 333 | ||
327 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | 334 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) |
328 | { | 335 | { |
336 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
329 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 337 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
330 | char buf[32] = " "; | 338 | char buf[32] = " "; |
331 | s64 wdiff; | 339 | s64 wdiff = 0; |
332 | 340 | ||
333 | if (he->diff.computed) | 341 | if (pair) { |
334 | wdiff = he->diff.wdiff; | 342 | if (he->diff.computed) |
335 | else | 343 | wdiff = he->diff.wdiff; |
336 | wdiff = perf_diff__compute_wdiff(he); | 344 | else |
345 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
346 | } | ||
337 | 347 | ||
338 | if (wdiff != 0) | 348 | if (wdiff != 0) |
339 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | 349 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); |
@@ -341,30 +351,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | |||
341 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 351 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
342 | } | 352 | } |
343 | 353 | ||
344 | static int hpp__header_displ(struct perf_hpp *hpp) | ||
345 | { | ||
346 | return scnprintf(hpp->buf, hpp->size, "Displ."); | ||
347 | } | ||
348 | |||
349 | static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) | ||
350 | { | ||
351 | return 6; | ||
352 | } | ||
353 | |||
354 | static int hpp__entry_displ(struct perf_hpp *hpp, | ||
355 | struct hist_entry *he) | ||
356 | { | ||
357 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
358 | long displacement = pair ? pair->position - he->position : 0; | ||
359 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; | ||
360 | char buf[32] = " "; | ||
361 | |||
362 | if (displacement) | ||
363 | scnprintf(buf, sizeof(buf), "%+4ld", displacement); | ||
364 | |||
365 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
366 | } | ||
367 | |||
368 | static int hpp__header_formula(struct perf_hpp *hpp) | 354 | static int hpp__header_formula(struct perf_hpp *hpp) |
369 | { | 355 | { |
370 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | 356 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; |
@@ -379,67 +365,80 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | |||
379 | 365 | ||
380 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | 366 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) |
381 | { | 367 | { |
368 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
382 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | 369 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; |
383 | char buf[96] = " "; | 370 | char buf[96] = " "; |
384 | 371 | ||
385 | perf_diff__formula(buf, sizeof(buf), he); | 372 | if (pair) |
373 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
374 | |||
386 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 375 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
387 | } | 376 | } |
388 | 377 | ||
389 | #define HPP__COLOR_PRINT_FNS(_name) \ | 378 | #define HPP__COLOR_PRINT_FNS(_name) \ |
390 | .header = hpp__header_ ## _name, \ | 379 | { \ |
391 | .width = hpp__width_ ## _name, \ | 380 | .header = hpp__header_ ## _name, \ |
392 | .color = hpp__color_ ## _name, \ | 381 | .width = hpp__width_ ## _name, \ |
393 | .entry = hpp__entry_ ## _name | 382 | .color = hpp__color_ ## _name, \ |
383 | .entry = hpp__entry_ ## _name \ | ||
384 | } | ||
394 | 385 | ||
395 | #define HPP__PRINT_FNS(_name) \ | 386 | #define HPP__PRINT_FNS(_name) \ |
396 | .header = hpp__header_ ## _name, \ | 387 | { \ |
397 | .width = hpp__width_ ## _name, \ | 388 | .header = hpp__header_ ## _name, \ |
398 | .entry = hpp__entry_ ## _name | 389 | .width = hpp__width_ ## _name, \ |
390 | .entry = hpp__entry_ ## _name \ | ||
391 | } | ||
399 | 392 | ||
400 | struct perf_hpp_fmt perf_hpp__format[] = { | 393 | struct perf_hpp_fmt perf_hpp__format[] = { |
401 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | 394 | HPP__COLOR_PRINT_FNS(baseline), |
402 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 395 | HPP__COLOR_PRINT_FNS(overhead), |
403 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 396 | HPP__COLOR_PRINT_FNS(overhead_sys), |
404 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 397 | HPP__COLOR_PRINT_FNS(overhead_us), |
405 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, | 398 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
406 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, | 399 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
407 | { .cond = false, HPP__PRINT_FNS(samples) }, | 400 | HPP__PRINT_FNS(samples), |
408 | { .cond = false, HPP__PRINT_FNS(period) }, | 401 | HPP__PRINT_FNS(period), |
409 | { .cond = false, HPP__PRINT_FNS(period_baseline) }, | 402 | HPP__PRINT_FNS(period_baseline), |
410 | { .cond = false, HPP__PRINT_FNS(delta) }, | 403 | HPP__PRINT_FNS(delta), |
411 | { .cond = false, HPP__PRINT_FNS(ratio) }, | 404 | HPP__PRINT_FNS(ratio), |
412 | { .cond = false, HPP__PRINT_FNS(wdiff) }, | 405 | HPP__PRINT_FNS(wdiff), |
413 | { .cond = false, HPP__PRINT_FNS(displ) }, | 406 | HPP__PRINT_FNS(formula) |
414 | { .cond = false, HPP__PRINT_FNS(formula) } | ||
415 | }; | 407 | }; |
416 | 408 | ||
409 | LIST_HEAD(perf_hpp__list); | ||
410 | |||
417 | #undef HPP__COLOR_PRINT_FNS | 411 | #undef HPP__COLOR_PRINT_FNS |
418 | #undef HPP__PRINT_FNS | 412 | #undef HPP__PRINT_FNS |
419 | 413 | ||
420 | void perf_hpp__init(void) | 414 | void perf_hpp__init(void) |
421 | { | 415 | { |
422 | if (symbol_conf.show_cpu_utilization) { | 416 | if (symbol_conf.show_cpu_utilization) { |
423 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 417 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
424 | perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; | 418 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
425 | 419 | ||
426 | if (perf_guest) { | 420 | if (perf_guest) { |
427 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; | 421 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
428 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; | 422 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); |
429 | } | 423 | } |
430 | } | 424 | } |
431 | 425 | ||
432 | if (symbol_conf.show_nr_samples) | 426 | if (symbol_conf.show_nr_samples) |
433 | perf_hpp__format[PERF_HPP__SAMPLES].cond = true; | 427 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
434 | 428 | ||
435 | if (symbol_conf.show_total_period) | 429 | if (symbol_conf.show_total_period) |
436 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 430 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
431 | } | ||
432 | |||
433 | void perf_hpp__column_register(struct perf_hpp_fmt *format) | ||
434 | { | ||
435 | list_add_tail(&format->list, &perf_hpp__list); | ||
437 | } | 436 | } |
438 | 437 | ||
439 | void perf_hpp__column_enable(unsigned col, bool enable) | 438 | void perf_hpp__column_enable(unsigned col) |
440 | { | 439 | { |
441 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | 440 | BUG_ON(col >= PERF_HPP__MAX_INDEX); |
442 | perf_hpp__format[col].cond = enable; | 441 | perf_hpp__column_register(&perf_hpp__format[col]); |
443 | } | 442 | } |
444 | 443 | ||
445 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 444 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
@@ -452,27 +451,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
452 | bool color) | 451 | bool color) |
453 | { | 452 | { |
454 | const char *sep = symbol_conf.field_sep; | 453 | const char *sep = symbol_conf.field_sep; |
454 | struct perf_hpp_fmt *fmt; | ||
455 | char *start = hpp->buf; | 455 | char *start = hpp->buf; |
456 | int i, ret; | 456 | int ret; |
457 | bool first = true; | 457 | bool first = true; |
458 | 458 | ||
459 | if (symbol_conf.exclude_other && !he->parent) | 459 | if (symbol_conf.exclude_other && !he->parent) |
460 | return 0; | 460 | return 0; |
461 | 461 | ||
462 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 462 | perf_hpp__for_each_format(fmt) { |
463 | if (!perf_hpp__format[i].cond) | 463 | /* |
464 | continue; | 464 | * If there's no field_sep, we still need |
465 | 465 | * to display initial ' '. | |
466 | */ | ||
466 | if (!sep || !first) { | 467 | if (!sep || !first) { |
467 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 468 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
468 | advance_hpp(hpp, ret); | 469 | advance_hpp(hpp, ret); |
470 | } else | ||
469 | first = false; | 471 | first = false; |
470 | } | ||
471 | 472 | ||
472 | if (color && perf_hpp__format[i].color) | 473 | if (color && fmt->color) |
473 | ret = perf_hpp__format[i].color(hpp, he); | 474 | ret = fmt->color(hpp, he); |
474 | else | 475 | else |
475 | ret = perf_hpp__format[i].entry(hpp, he); | 476 | ret = fmt->entry(hpp, he); |
476 | 477 | ||
477 | advance_hpp(hpp, ret); | 478 | advance_hpp(hpp, ret); |
478 | } | 479 | } |
@@ -504,16 +505,15 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | |||
504 | */ | 505 | */ |
505 | unsigned int hists__sort_list_width(struct hists *hists) | 506 | unsigned int hists__sort_list_width(struct hists *hists) |
506 | { | 507 | { |
508 | struct perf_hpp_fmt *fmt; | ||
507 | struct sort_entry *se; | 509 | struct sort_entry *se; |
508 | int i, ret = 0; | 510 | int i = 0, ret = 0; |
509 | 511 | ||
510 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 512 | perf_hpp__for_each_format(fmt) { |
511 | if (!perf_hpp__format[i].cond) | ||
512 | continue; | ||
513 | if (i) | 513 | if (i) |
514 | ret += 2; | 514 | ret += 2; |
515 | 515 | ||
516 | ret += perf_hpp__format[i].width(NULL); | 516 | ret += fmt->width(NULL); |
517 | } | 517 | } |
518 | 518 | ||
519 | list_for_each_entry(se, &hist_entry__sort_list, list) | 519 | list_for_each_entry(se, &hist_entry__sort_list, list) |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ebb4cc107876..166f13df3134 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager) | |||
30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
31 | setup_pager(); | 31 | setup_pager(); |
32 | 32 | ||
33 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
33 | perf_hpp__init(); | 34 | perf_hpp__init(); |
34 | break; | 35 | break; |
35 | } | 36 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index f0ee204f99bb..0eae3b2c32f2 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -335,13 +335,14 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
336 | int max_cols, FILE *fp) | 336 | int max_cols, FILE *fp) |
337 | { | 337 | { |
338 | struct perf_hpp_fmt *fmt; | ||
338 | struct sort_entry *se; | 339 | struct sort_entry *se; |
339 | struct rb_node *nd; | 340 | struct rb_node *nd; |
340 | size_t ret = 0; | 341 | size_t ret = 0; |
341 | unsigned int width; | 342 | unsigned int width; |
342 | const char *sep = symbol_conf.field_sep; | 343 | const char *sep = symbol_conf.field_sep; |
343 | const char *col_width = symbol_conf.col_width_list_str; | 344 | const char *col_width = symbol_conf.col_width_list_str; |
344 | int idx, nr_rows = 0; | 345 | int nr_rows = 0; |
345 | char bf[96]; | 346 | char bf[96]; |
346 | struct perf_hpp dummy_hpp = { | 347 | struct perf_hpp dummy_hpp = { |
347 | .buf = bf, | 348 | .buf = bf, |
@@ -355,16 +356,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
355 | goto print_entries; | 356 | goto print_entries; |
356 | 357 | ||
357 | fprintf(fp, "# "); | 358 | fprintf(fp, "# "); |
358 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
359 | if (!perf_hpp__format[idx].cond) | ||
360 | continue; | ||
361 | 359 | ||
360 | perf_hpp__for_each_format(fmt) { | ||
362 | if (!first) | 361 | if (!first) |
363 | fprintf(fp, "%s", sep ?: " "); | 362 | fprintf(fp, "%s", sep ?: " "); |
364 | else | 363 | else |
365 | first = false; | 364 | first = false; |
366 | 365 | ||
367 | perf_hpp__format[idx].header(&dummy_hpp); | 366 | fmt->header(&dummy_hpp); |
368 | fprintf(fp, "%s", bf); | 367 | fprintf(fp, "%s", bf); |
369 | } | 368 | } |
370 | 369 | ||
@@ -400,18 +399,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
400 | first = true; | 399 | first = true; |
401 | 400 | ||
402 | fprintf(fp, "# "); | 401 | fprintf(fp, "# "); |
403 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
404 | unsigned int i; | ||
405 | 402 | ||
406 | if (!perf_hpp__format[idx].cond) | 403 | perf_hpp__for_each_format(fmt) { |
407 | continue; | 404 | unsigned int i; |
408 | 405 | ||
409 | if (!first) | 406 | if (!first) |
410 | fprintf(fp, "%s", sep ?: " "); | 407 | fprintf(fp, "%s", sep ?: " "); |
411 | else | 408 | else |
412 | first = false; | 409 | first = false; |
413 | 410 | ||
414 | width = perf_hpp__format[idx].width(&dummy_hpp); | 411 | width = fmt->width(&dummy_hpp); |
415 | for (i = 0; i < width; i++) | 412 | for (i = 0; i < width; i++) |
416 | fprintf(fp, "."); | 413 | fprintf(fp, "."); |
417 | } | 414 | } |
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 2884d2f41e33..1c8b9afd5d6e 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include "../ui.h" | 8 | #include "../ui.h" |
9 | #include "../libslang.h" | 9 | #include "../libslang.h" |
10 | 10 | ||
11 | char ui_helpline__last_msg[1024]; | ||
12 | |||
11 | static void tui_helpline__pop(void) | 13 | static void tui_helpline__pop(void) |
12 | { | 14 | { |
13 | } | 15 | } |
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg) | |||
23 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; | 25 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; |
24 | } | 26 | } |
25 | 27 | ||
26 | struct ui_helpline tui_helpline_fns = { | 28 | static int tui_helpline__show(const char *format, va_list ap) |
27 | .pop = tui_helpline__pop, | ||
28 | .push = tui_helpline__push, | ||
29 | }; | ||
30 | |||
31 | void ui_helpline__init(void) | ||
32 | { | ||
33 | helpline_fns = &tui_helpline_fns; | ||
34 | ui_helpline__puts(" "); | ||
35 | } | ||
36 | |||
37 | char ui_helpline__last_msg[1024]; | ||
38 | |||
39 | int ui_helpline__show_help(const char *format, va_list ap) | ||
40 | { | 29 | { |
41 | int ret; | 30 | int ret; |
42 | static int backlog; | 31 | static int backlog; |
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
55 | 44 | ||
56 | return ret; | 45 | return ret; |
57 | } | 46 | } |
47 | |||
48 | struct ui_helpline tui_helpline_fns = { | ||
49 | .pop = tui_helpline__pop, | ||
50 | .push = tui_helpline__push, | ||
51 | .show = tui_helpline__show, | ||
52 | }; | ||
53 | |||
54 | void ui_helpline__init(void) | ||
55 | { | ||
56 | helpline_fns = &tui_helpline_fns; | ||
57 | ui_helpline__puts(" "); | ||
58 | } | ||
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 4f989774c8c6..3014a7cd5271 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c | |||
@@ -52,6 +52,16 @@ int ui__warning(const char *format, ...) | |||
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | int ui__error_paranoid(void) | ||
56 | { | ||
57 | return ui__error("Permission error - are you root?\n" | ||
58 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
59 | " -1 - Not paranoid at all\n" | ||
60 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
61 | " 1 - Disallow cpu events for unpriv\n" | ||
62 | " 2 - Disallow kernel profiling for unpriv\n"); | ||
63 | } | ||
64 | |||
55 | 65 | ||
56 | /** | 66 | /** |
57 | * perf_error__register - Register error logging functions | 67 | * perf_error__register - Register error logging functions |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index eb340571e7d6..3ee9f67d5af0 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
143 | cursor->curr = cursor->curr->next; | 143 | cursor->curr = cursor->curr->next; |
144 | cursor->pos++; | 144 | cursor->pos++; |
145 | } | 145 | } |
146 | |||
147 | struct option; | ||
148 | |||
149 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | ||
150 | extern const char record_callchain_help[]; | ||
146 | #endif /* __PERF_CALLCHAIN_H */ | 151 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 03f830b48148..399e74c34c1a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...) | |||
23 | 23 | ||
24 | if (verbose >= level) { | 24 | if (verbose >= level) { |
25 | va_start(args, fmt); | 25 | va_start(args, fmt); |
26 | if (use_browser == 1) | 26 | if (use_browser >= 1) |
27 | ret = ui_helpline__show_help(fmt, args); | 27 | ui_helpline__vshow(fmt, args); |
28 | else if (use_browser == 2) | ||
29 | ret = perf_gtk__show_helpline(fmt, args); | ||
30 | else | 28 | else |
31 | ret = vfprintf(stderr, fmt, args); | 29 | ret = vfprintf(stderr, fmt, args); |
32 | va_end(args); | 30 | va_end(args); |
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...) | |||
49 | return ret; | 47 | return ret; |
50 | } | 48 | } |
51 | 49 | ||
52 | #if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) | ||
53 | int ui__warning(const char *format, ...) | ||
54 | { | ||
55 | va_list args; | ||
56 | |||
57 | va_start(args, format); | ||
58 | vfprintf(stderr, format, args); | ||
59 | va_end(args); | ||
60 | return 0; | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | int ui__error_paranoid(void) | ||
65 | { | ||
66 | return ui__error("Permission error - are you root?\n" | ||
67 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
68 | " -1 - Not paranoid at all\n" | ||
69 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
70 | " 1 - Disallow cpu events for unpriv\n" | ||
71 | " 2 - Disallow kernel profiling for unpriv\n"); | ||
72 | } | ||
73 | |||
74 | void trace_event(union perf_event *event) | 50 | void trace_event(union perf_event *event) |
75 | { | 51 | { |
76 | unsigned char *raw_event = (void *)event; | 52 | unsigned char *raw_event = (void *)event; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 83e8d234af6b..6e2667fb8211 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "event.h" | 6 | #include "event.h" |
7 | #include "../ui/helpline.h" | 7 | #include "../ui/helpline.h" |
8 | #include "../ui/progress.h" | ||
9 | #include "../ui/util.h" | ||
8 | 10 | ||
9 | extern int verbose; | 11 | extern int verbose; |
10 | extern bool quiet, dump_trace; | 12 | extern bool quiet, dump_trace; |
@@ -12,38 +14,7 @@ extern bool quiet, dump_trace; | |||
12 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 14 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
13 | void trace_event(union perf_event *event); | 15 | void trace_event(union perf_event *event); |
14 | 16 | ||
15 | struct ui_progress; | ||
16 | struct perf_error_ops; | ||
17 | |||
18 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) | ||
19 | |||
20 | #include "../ui/progress.h" | ||
21 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
22 | #include "../ui/util.h" | ||
23 | |||
24 | #else | ||
25 | |||
26 | static inline void ui_progress__update(u64 curr __maybe_unused, | ||
27 | u64 total __maybe_unused, | ||
28 | const char *title __maybe_unused) {} | ||
29 | static inline void ui_progress__finish(void) {} | ||
30 | |||
31 | #define ui__error(format, arg...) ui__warning(format, ##arg) | ||
32 | |||
33 | static inline int | ||
34 | perf_error__register(struct perf_error_ops *eops __maybe_unused) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static inline int | ||
40 | perf_error__unregister(struct perf_error_ops *eops __maybe_unused) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
46 | |||
47 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
48 | int ui__error_paranoid(void); | 19 | int ui__error_paranoid(void); |
49 | 20 | ||
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d6d9a465acdb..6f7d5a9d6b05 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name) | |||
539 | } | 539 | } |
540 | 540 | ||
541 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 541 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
542 | bool with_hits) | 542 | bool (skip)(struct dso *dso, int parm), int parm) |
543 | { | 543 | { |
544 | struct dso *pos; | 544 | struct dso *pos; |
545 | size_t ret = 0; | 545 | size_t ret = 0; |
546 | 546 | ||
547 | list_for_each_entry(pos, head, node) { | 547 | list_for_each_entry(pos, head, node) { |
548 | if (with_hits && !pos->hit) | 548 | if (skip && skip(pos, parm)) |
549 | continue; | 549 | continue; |
550 | ret += dso__fprintf_buildid(pos, fp); | 550 | ret += dso__fprintf_buildid(pos, fp); |
551 | ret += fprintf(fp, " %s\n", pos->long_name); | 551 | ret += fprintf(fp, " %s\n", pos->long_name); |
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
583 | if (dso->short_name != dso->long_name) | 583 | if (dso->short_name != dso->long_name) |
584 | ret += fprintf(fp, "%s, ", dso->long_name); | 584 | ret += fprintf(fp, "%s, ", dso->long_name); |
585 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | 585 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], |
586 | dso->loaded ? "" : "NOT "); | 586 | dso__loaded(dso, type) ? "" : "NOT "); |
587 | ret += dso__fprintf_buildid(dso, fp); | 587 | ret += dso__fprintf_buildid(dso, fp); |
588 | ret += fprintf(fp, ")\n"); | 588 | ret += fprintf(fp, ")\n"); |
589 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { | 589 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index e03276940b99..450199ab51b5 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name); | |||
138 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 138 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
139 | 139 | ||
140 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 140 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
141 | bool with_hits); | 141 | bool (skip)(struct dso *dso, int parm), int parm); |
142 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); | 142 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); |
143 | 143 | ||
144 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); | 144 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 705293489e3c..dc8aee97a488 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | |||
49 | return evlist; | 49 | return evlist; |
50 | } | 50 | } |
51 | 51 | ||
52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 52 | void perf_evlist__config(struct perf_evlist *evlist, |
53 | struct perf_record_opts *opts) | 53 | struct perf_record_opts *opts) |
54 | { | 54 | { |
55 | struct perf_evsel *evsel; | 55 | struct perf_evsel *evsel; |
56 | /* | ||
57 | * Set the evsel leader links before we configure attributes, | ||
58 | * since some might depend on this info. | ||
59 | */ | ||
60 | if (opts->group) | ||
61 | perf_evlist__set_leader(evlist); | ||
56 | 62 | ||
57 | if (evlist->cpus->map[0] < 0) | 63 | if (evlist->cpus->map[0] < 0) |
58 | opts->no_inherit = true; | 64 | opts->no_inherit = true; |
@@ -61,7 +67,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist, | |||
61 | perf_evsel__config(evsel, opts); | 67 | perf_evsel__config(evsel, opts); |
62 | 68 | ||
63 | if (evlist->nr_entries > 1) | 69 | if (evlist->nr_entries > 1) |
64 | evsel->attr.sample_type |= PERF_SAMPLE_ID; | 70 | perf_evsel__set_sample_id(evsel); |
65 | } | 71 | } |
66 | } | 72 | } |
67 | 73 | ||
@@ -111,7 +117,6 @@ void __perf_evlist__set_leader(struct list_head *list) | |||
111 | struct perf_evsel *evsel, *leader; | 117 | struct perf_evsel *evsel, *leader; |
112 | 118 | ||
113 | leader = list_entry(list->next, struct perf_evsel, node); | 119 | leader = list_entry(list->next, struct perf_evsel, node); |
114 | leader->leader = NULL; | ||
115 | 120 | ||
116 | list_for_each_entry(evsel, list, node) { | 121 | list_for_each_entry(evsel, list, node) { |
117 | if (evsel != leader) | 122 | if (evsel != leader) |
@@ -222,7 +227,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
222 | 227 | ||
223 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 228 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
224 | list_for_each_entry(pos, &evlist->entries, node) { | 229 | list_for_each_entry(pos, &evlist->entries, node) { |
225 | if (perf_evsel__is_group_member(pos)) | 230 | if (!perf_evsel__is_group_leader(pos)) |
226 | continue; | 231 | continue; |
227 | for (thread = 0; thread < evlist->threads->nr; thread++) | 232 | for (thread = 0; thread < evlist->threads->nr; thread++) |
228 | ioctl(FD(pos, cpu, thread), | 233 | ioctl(FD(pos, cpu, thread), |
@@ -238,7 +243,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
238 | 243 | ||
239 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { | 244 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { |
240 | list_for_each_entry(pos, &evlist->entries, node) { | 245 | list_for_each_entry(pos, &evlist->entries, node) { |
241 | if (perf_evsel__is_group_member(pos)) | 246 | if (!perf_evsel__is_group_leader(pos)) |
242 | continue; | 247 | continue; |
243 | for (thread = 0; thread < evlist->threads->nr; thread++) | 248 | for (thread = 0; thread < evlist->threads->nr; thread++) |
244 | ioctl(FD(pos, cpu, thread), | 249 | ioctl(FD(pos, cpu, thread), |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 56003f779e60..457e2350d21d 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -76,8 +76,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | |||
76 | 76 | ||
77 | int perf_evlist__open(struct perf_evlist *evlist); | 77 | int perf_evlist__open(struct perf_evlist *evlist); |
78 | 78 | ||
79 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 79 | void perf_evlist__config(struct perf_evlist *evlist, |
80 | struct perf_record_opts *opts); | 80 | struct perf_record_opts *opts); |
81 | 81 | ||
82 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 82 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
83 | struct perf_record_opts *opts, | 83 | struct perf_record_opts *opts, |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1b16dd1edc8e..7a2a3dc3ff03 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -50,11 +50,36 @@ void hists__init(struct hists *hists) | |||
50 | pthread_mutex_init(&hists->lock, NULL); | 50 | pthread_mutex_init(&hists->lock, NULL); |
51 | } | 51 | } |
52 | 52 | ||
53 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | ||
54 | enum perf_event_sample_format bit) | ||
55 | { | ||
56 | if (!(evsel->attr.sample_type & bit)) { | ||
57 | evsel->attr.sample_type |= bit; | ||
58 | evsel->sample_size += sizeof(u64); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | ||
63 | enum perf_event_sample_format bit) | ||
64 | { | ||
65 | if (evsel->attr.sample_type & bit) { | ||
66 | evsel->attr.sample_type &= ~bit; | ||
67 | evsel->sample_size -= sizeof(u64); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void perf_evsel__set_sample_id(struct perf_evsel *evsel) | ||
72 | { | ||
73 | perf_evsel__set_sample_bit(evsel, ID); | ||
74 | evsel->attr.read_format |= PERF_FORMAT_ID; | ||
75 | } | ||
76 | |||
53 | void perf_evsel__init(struct perf_evsel *evsel, | 77 | void perf_evsel__init(struct perf_evsel *evsel, |
54 | struct perf_event_attr *attr, int idx) | 78 | struct perf_event_attr *attr, int idx) |
55 | { | 79 | { |
56 | evsel->idx = idx; | 80 | evsel->idx = idx; |
57 | evsel->attr = *attr; | 81 | evsel->attr = *attr; |
82 | evsel->leader = evsel; | ||
58 | INIT_LIST_HEAD(&evsel->node); | 83 | INIT_LIST_HEAD(&evsel->node); |
59 | hists__init(&evsel->hists); | 84 | hists__init(&evsel->hists); |
60 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 85 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
@@ -440,11 +465,9 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
440 | 465 | ||
441 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | 466 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; |
442 | attr->inherit = !opts->no_inherit; | 467 | attr->inherit = !opts->no_inherit; |
443 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
444 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
445 | PERF_FORMAT_ID; | ||
446 | 468 | ||
447 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 469 | perf_evsel__set_sample_bit(evsel, IP); |
470 | perf_evsel__set_sample_bit(evsel, TID); | ||
448 | 471 | ||
449 | /* | 472 | /* |
450 | * We default some events to a 1 default interval. But keep | 473 | * We default some events to a 1 default interval. But keep |
@@ -453,7 +476,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
453 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && | 476 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && |
454 | opts->user_interval != ULLONG_MAX)) { | 477 | opts->user_interval != ULLONG_MAX)) { |
455 | if (opts->freq) { | 478 | if (opts->freq) { |
456 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 479 | perf_evsel__set_sample_bit(evsel, PERIOD); |
457 | attr->freq = 1; | 480 | attr->freq = 1; |
458 | attr->sample_freq = opts->freq; | 481 | attr->sample_freq = opts->freq; |
459 | } else { | 482 | } else { |
@@ -468,16 +491,16 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
468 | attr->inherit_stat = 1; | 491 | attr->inherit_stat = 1; |
469 | 492 | ||
470 | if (opts->sample_address) { | 493 | if (opts->sample_address) { |
471 | attr->sample_type |= PERF_SAMPLE_ADDR; | 494 | perf_evsel__set_sample_bit(evsel, ADDR); |
472 | attr->mmap_data = track; | 495 | attr->mmap_data = track; |
473 | } | 496 | } |
474 | 497 | ||
475 | if (opts->call_graph) { | 498 | if (opts->call_graph) { |
476 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 499 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); |
477 | 500 | ||
478 | if (opts->call_graph == CALLCHAIN_DWARF) { | 501 | if (opts->call_graph == CALLCHAIN_DWARF) { |
479 | attr->sample_type |= PERF_SAMPLE_REGS_USER | | 502 | perf_evsel__set_sample_bit(evsel, REGS_USER); |
480 | PERF_SAMPLE_STACK_USER; | 503 | perf_evsel__set_sample_bit(evsel, STACK_USER); |
481 | attr->sample_regs_user = PERF_REGS_MASK; | 504 | attr->sample_regs_user = PERF_REGS_MASK; |
482 | attr->sample_stack_user = opts->stack_dump_size; | 505 | attr->sample_stack_user = opts->stack_dump_size; |
483 | attr->exclude_callchain_user = 1; | 506 | attr->exclude_callchain_user = 1; |
@@ -485,20 +508,20 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
485 | } | 508 | } |
486 | 509 | ||
487 | if (perf_target__has_cpu(&opts->target)) | 510 | if (perf_target__has_cpu(&opts->target)) |
488 | attr->sample_type |= PERF_SAMPLE_CPU; | 511 | perf_evsel__set_sample_bit(evsel, CPU); |
489 | 512 | ||
490 | if (opts->period) | 513 | if (opts->period) |
491 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 514 | perf_evsel__set_sample_bit(evsel, PERIOD); |
492 | 515 | ||
493 | if (!opts->sample_id_all_missing && | 516 | if (!opts->sample_id_all_missing && |
494 | (opts->sample_time || !opts->no_inherit || | 517 | (opts->sample_time || !opts->no_inherit || |
495 | perf_target__has_cpu(&opts->target))) | 518 | perf_target__has_cpu(&opts->target))) |
496 | attr->sample_type |= PERF_SAMPLE_TIME; | 519 | perf_evsel__set_sample_bit(evsel, TIME); |
497 | 520 | ||
498 | if (opts->raw_samples) { | 521 | if (opts->raw_samples) { |
499 | attr->sample_type |= PERF_SAMPLE_TIME; | 522 | perf_evsel__set_sample_bit(evsel, TIME); |
500 | attr->sample_type |= PERF_SAMPLE_RAW; | 523 | perf_evsel__set_sample_bit(evsel, RAW); |
501 | attr->sample_type |= PERF_SAMPLE_CPU; | 524 | perf_evsel__set_sample_bit(evsel, CPU); |
502 | } | 525 | } |
503 | 526 | ||
504 | if (opts->no_delay) { | 527 | if (opts->no_delay) { |
@@ -506,7 +529,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
506 | attr->wakeup_events = 1; | 529 | attr->wakeup_events = 1; |
507 | } | 530 | } |
508 | if (opts->branch_stack) { | 531 | if (opts->branch_stack) { |
509 | attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; | 532 | perf_evsel__set_sample_bit(evsel, BRANCH_STACK); |
510 | attr->branch_sample_type = opts->branch_stack; | 533 | attr->branch_sample_type = opts->branch_stack; |
511 | } | 534 | } |
512 | 535 | ||
@@ -519,14 +542,14 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
519 | * Disabling only independent events or group leaders, | 542 | * Disabling only independent events or group leaders, |
520 | * keeping group members enabled. | 543 | * keeping group members enabled. |
521 | */ | 544 | */ |
522 | if (!perf_evsel__is_group_member(evsel)) | 545 | if (perf_evsel__is_group_leader(evsel)) |
523 | attr->disabled = 1; | 546 | attr->disabled = 1; |
524 | 547 | ||
525 | /* | 548 | /* |
526 | * Setting enable_on_exec for independent events and | 549 | * Setting enable_on_exec for independent events and |
527 | * group leaders for traced executed by perf. | 550 | * group leaders for traced executed by perf. |
528 | */ | 551 | */ |
529 | if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) | 552 | if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) |
530 | attr->enable_on_exec = 1; | 553 | attr->enable_on_exec = 1; |
531 | } | 554 | } |
532 | 555 | ||
@@ -707,7 +730,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) | |||
707 | struct perf_evsel *leader = evsel->leader; | 730 | struct perf_evsel *leader = evsel->leader; |
708 | int fd; | 731 | int fd; |
709 | 732 | ||
710 | if (!perf_evsel__is_group_member(evsel)) | 733 | if (perf_evsel__is_group_leader(evsel)) |
711 | return -1; | 734 | return -1; |
712 | 735 | ||
713 | /* | 736 | /* |
@@ -1205,3 +1228,128 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, | |||
1205 | 1228 | ||
1206 | return 0; | 1229 | return 0; |
1207 | } | 1230 | } |
1231 | |||
1232 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
1233 | { | ||
1234 | va_list args; | ||
1235 | int ret = 0; | ||
1236 | |||
1237 | if (!*first) { | ||
1238 | ret += fprintf(fp, ","); | ||
1239 | } else { | ||
1240 | ret += fprintf(fp, ":"); | ||
1241 | *first = false; | ||
1242 | } | ||
1243 | |||
1244 | va_start(args, fmt); | ||
1245 | ret += vfprintf(fp, fmt, args); | ||
1246 | va_end(args); | ||
1247 | return ret; | ||
1248 | } | ||
1249 | |||
1250 | static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value) | ||
1251 | { | ||
1252 | if (value == 0) | ||
1253 | return 0; | ||
1254 | |||
1255 | return comma_fprintf(fp, first, " %s: %" PRIu64, field, value); | ||
1256 | } | ||
1257 | |||
1258 | #define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field) | ||
1259 | |||
1260 | struct bit_names { | ||
1261 | int bit; | ||
1262 | const char *name; | ||
1263 | }; | ||
1264 | |||
1265 | static int bits__fprintf(FILE *fp, const char *field, u64 value, | ||
1266 | struct bit_names *bits, bool *first) | ||
1267 | { | ||
1268 | int i = 0, printed = comma_fprintf(fp, first, " %s: ", field); | ||
1269 | bool first_bit = true; | ||
1270 | |||
1271 | do { | ||
1272 | if (value & bits[i].bit) { | ||
1273 | printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name); | ||
1274 | first_bit = false; | ||
1275 | } | ||
1276 | } while (bits[++i].name != NULL); | ||
1277 | |||
1278 | return printed; | ||
1279 | } | ||
1280 | |||
1281 | static int sample_type__fprintf(FILE *fp, bool *first, u64 value) | ||
1282 | { | ||
1283 | #define bit_name(n) { PERF_SAMPLE_##n, #n } | ||
1284 | struct bit_names bits[] = { | ||
1285 | bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), | ||
1286 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), | ||
1287 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | ||
1288 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | ||
1289 | { .name = NULL, } | ||
1290 | }; | ||
1291 | #undef bit_name | ||
1292 | return bits__fprintf(fp, "sample_type", value, bits, first); | ||
1293 | } | ||
1294 | |||
1295 | static int read_format__fprintf(FILE *fp, bool *first, u64 value) | ||
1296 | { | ||
1297 | #define bit_name(n) { PERF_FORMAT_##n, #n } | ||
1298 | struct bit_names bits[] = { | ||
1299 | bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), | ||
1300 | bit_name(ID), bit_name(GROUP), | ||
1301 | { .name = NULL, } | ||
1302 | }; | ||
1303 | #undef bit_name | ||
1304 | return bits__fprintf(fp, "read_format", value, bits, first); | ||
1305 | } | ||
1306 | |||
1307 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
1308 | struct perf_attr_details *details, FILE *fp) | ||
1309 | { | ||
1310 | bool first = true; | ||
1311 | int printed = fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
1312 | |||
1313 | if (details->verbose || details->freq) { | ||
1314 | printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, | ||
1315 | (u64)evsel->attr.sample_freq); | ||
1316 | } | ||
1317 | |||
1318 | if (details->verbose) { | ||
1319 | if_print(type); | ||
1320 | if_print(config); | ||
1321 | if_print(config1); | ||
1322 | if_print(config2); | ||
1323 | if_print(size); | ||
1324 | printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type); | ||
1325 | if (evsel->attr.read_format) | ||
1326 | printed += read_format__fprintf(fp, &first, evsel->attr.read_format); | ||
1327 | if_print(disabled); | ||
1328 | if_print(inherit); | ||
1329 | if_print(pinned); | ||
1330 | if_print(exclusive); | ||
1331 | if_print(exclude_user); | ||
1332 | if_print(exclude_kernel); | ||
1333 | if_print(exclude_hv); | ||
1334 | if_print(exclude_idle); | ||
1335 | if_print(mmap); | ||
1336 | if_print(comm); | ||
1337 | if_print(freq); | ||
1338 | if_print(inherit_stat); | ||
1339 | if_print(enable_on_exec); | ||
1340 | if_print(task); | ||
1341 | if_print(watermark); | ||
1342 | if_print(precise_ip); | ||
1343 | if_print(mmap_data); | ||
1344 | if_print(sample_id_all); | ||
1345 | if_print(exclude_host); | ||
1346 | if_print(exclude_guest); | ||
1347 | if_print(__reserved_1); | ||
1348 | if_print(wakeup_events); | ||
1349 | if_print(bp_type); | ||
1350 | if_print(branch_sample_type); | ||
1351 | } | ||
1352 | |||
1353 | fputc('\n', fp); | ||
1354 | return ++printed; | ||
1355 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3d2b8017438c..9cb8a0215711 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -118,6 +118,19 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); | |||
118 | void perf_evsel__free_id(struct perf_evsel *evsel); | 118 | void perf_evsel__free_id(struct perf_evsel *evsel); |
119 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 119 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
120 | 120 | ||
121 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | ||
122 | enum perf_event_sample_format bit); | ||
123 | void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | ||
124 | enum perf_event_sample_format bit); | ||
125 | |||
126 | #define perf_evsel__set_sample_bit(evsel, bit) \ | ||
127 | __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit) | ||
128 | |||
129 | #define perf_evsel__reset_sample_bit(evsel, bit) \ | ||
130 | __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) | ||
131 | |||
132 | void perf_evsel__set_sample_id(struct perf_evsel *evsel); | ||
133 | |||
121 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, | 134 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, |
122 | const char *filter); | 135 | const char *filter); |
123 | 136 | ||
@@ -226,8 +239,16 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | |||
226 | return list_entry(evsel->node.next, struct perf_evsel, node); | 239 | return list_entry(evsel->node.next, struct perf_evsel, node); |
227 | } | 240 | } |
228 | 241 | ||
229 | static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) | 242 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) |
230 | { | 243 | { |
231 | return evsel->leader != NULL; | 244 | return evsel->leader == evsel; |
232 | } | 245 | } |
246 | |||
247 | struct perf_attr_details { | ||
248 | bool freq; | ||
249 | bool verbose; | ||
250 | }; | ||
251 | |||
252 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
253 | struct perf_attr_details *details, FILE *fp); | ||
233 | #endif /* __PERF_EVSEL_H */ | 254 | #endif /* __PERF_EVSEL_H */ |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index cb17e2a8c6ed..82df1b26f0d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -785,7 +785,7 @@ void hists__match(struct hists *leader, struct hists *other) | |||
785 | pair = hists__find_entry(other, pos); | 785 | pair = hists__find_entry(other, pos); |
786 | 786 | ||
787 | if (pair) | 787 | if (pair) |
788 | hist__entry_add_pair(pos, pair); | 788 | hist_entry__add_pair(pair, pos); |
789 | } | 789 | } |
790 | } | 790 | } |
791 | 791 | ||
@@ -806,7 +806,7 @@ int hists__link(struct hists *leader, struct hists *other) | |||
806 | pair = hists__add_dummy_entry(leader, pos); | 806 | pair = hists__add_dummy_entry(leader, pos); |
807 | if (pair == NULL) | 807 | if (pair == NULL) |
808 | return -1; | 808 | return -1; |
809 | hist__entry_add_pair(pair, pos); | 809 | hist_entry__add_pair(pos, pair); |
810 | } | 810 | } |
811 | } | 811 | } |
812 | 812 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8b091a51e4a2..5b3b0075be64 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -126,13 +126,19 @@ struct perf_hpp { | |||
126 | }; | 126 | }; |
127 | 127 | ||
128 | struct perf_hpp_fmt { | 128 | struct perf_hpp_fmt { |
129 | bool cond; | ||
130 | int (*header)(struct perf_hpp *hpp); | 129 | int (*header)(struct perf_hpp *hpp); |
131 | int (*width)(struct perf_hpp *hpp); | 130 | int (*width)(struct perf_hpp *hpp); |
132 | int (*color)(struct perf_hpp *hpp, struct hist_entry *he); | 131 | int (*color)(struct perf_hpp *hpp, struct hist_entry *he); |
133 | int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); | 132 | int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); |
133 | |||
134 | struct list_head list; | ||
134 | }; | 135 | }; |
135 | 136 | ||
137 | extern struct list_head perf_hpp__list; | ||
138 | |||
139 | #define perf_hpp__for_each_format(format) \ | ||
140 | list_for_each_entry(format, &perf_hpp__list, list) | ||
141 | |||
136 | extern struct perf_hpp_fmt perf_hpp__format[]; | 142 | extern struct perf_hpp_fmt perf_hpp__format[]; |
137 | 143 | ||
138 | enum { | 144 | enum { |
@@ -148,14 +154,14 @@ enum { | |||
148 | PERF_HPP__DELTA, | 154 | PERF_HPP__DELTA, |
149 | PERF_HPP__RATIO, | 155 | PERF_HPP__RATIO, |
150 | PERF_HPP__WEIGHTED_DIFF, | 156 | PERF_HPP__WEIGHTED_DIFF, |
151 | PERF_HPP__DISPL, | ||
152 | PERF_HPP__FORMULA, | 157 | PERF_HPP__FORMULA, |
153 | 158 | ||
154 | PERF_HPP__MAX_INDEX | 159 | PERF_HPP__MAX_INDEX |
155 | }; | 160 | }; |
156 | 161 | ||
157 | void perf_hpp__init(void); | 162 | void perf_hpp__init(void); |
158 | void perf_hpp__column_enable(unsigned col, bool enable); | 163 | void perf_hpp__column_register(struct perf_hpp_fmt *format); |
164 | void perf_hpp__column_enable(unsigned col); | ||
159 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | 165 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, |
160 | bool color); | 166 | bool color); |
161 | 167 | ||
@@ -219,8 +225,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
219 | 225 | ||
220 | unsigned int hists__sort_list_width(struct hists *self); | 226 | unsigned int hists__sort_list_width(struct hists *self); |
221 | 227 | ||
222 | double perf_diff__compute_delta(struct hist_entry *he); | 228 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); |
223 | double perf_diff__compute_ratio(struct hist_entry *he); | 229 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); |
224 | s64 perf_diff__compute_wdiff(struct hist_entry *he); | 230 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); |
225 | int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); | 231 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, |
232 | char *buf, size_t size); | ||
233 | double perf_diff__period_percent(struct hist_entry *he, u64 period); | ||
226 | #endif /* __PERF_HIST_H */ | 234 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1f09d0581e6b..71fa90391fe4 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1,10 +1,15 @@ | |||
1 | #include "callchain.h" | ||
1 | #include "debug.h" | 2 | #include "debug.h" |
2 | #include "event.h" | 3 | #include "event.h" |
4 | #include "evsel.h" | ||
5 | #include "hist.h" | ||
3 | #include "machine.h" | 6 | #include "machine.h" |
4 | #include "map.h" | 7 | #include "map.h" |
8 | #include "sort.h" | ||
5 | #include "strlist.h" | 9 | #include "strlist.h" |
6 | #include "thread.h" | 10 | #include "thread.h" |
7 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | #include "unwind.h" | ||
8 | 13 | ||
9 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 14 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
10 | { | 15 | { |
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos) | |||
48 | } | 53 | } |
49 | } | 54 | } |
50 | 55 | ||
56 | void machine__delete_dead_threads(struct machine *machine) | ||
57 | { | ||
58 | struct thread *n, *t; | ||
59 | |||
60 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | ||
61 | list_del(&t->node); | ||
62 | thread__delete(t); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | void machine__delete_threads(struct machine *machine) | ||
67 | { | ||
68 | struct rb_node *nd = rb_first(&machine->threads); | ||
69 | |||
70 | while (nd) { | ||
71 | struct thread *t = rb_entry(nd, struct thread, rb_node); | ||
72 | |||
73 | rb_erase(&t->rb_node, &machine->threads); | ||
74 | nd = rb_next(nd); | ||
75 | thread__delete(t); | ||
76 | } | ||
77 | } | ||
78 | |||
51 | void machine__exit(struct machine *machine) | 79 | void machine__exit(struct machine *machine) |
52 | { | 80 | { |
53 | map_groups__exit(&machine->kmaps); | 81 | map_groups__exit(&machine->kmaps); |
@@ -264,6 +292,534 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, | |||
264 | return 0; | 292 | return 0; |
265 | } | 293 | } |
266 | 294 | ||
295 | struct map *machine__new_module(struct machine *machine, u64 start, | ||
296 | const char *filename) | ||
297 | { | ||
298 | struct map *map; | ||
299 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | ||
300 | |||
301 | if (dso == NULL) | ||
302 | return NULL; | ||
303 | |||
304 | map = map__new2(start, dso, MAP__FUNCTION); | ||
305 | if (map == NULL) | ||
306 | return NULL; | ||
307 | |||
308 | if (machine__is_host(machine)) | ||
309 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
310 | else | ||
311 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
312 | map_groups__insert(&machine->kmaps, map); | ||
313 | return map; | ||
314 | } | ||
315 | |||
316 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | ||
317 | { | ||
318 | struct rb_node *nd; | ||
319 | size_t ret = 0; | ||
320 | |||
321 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
322 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
323 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | ||
324 | ret += __dsos__fprintf(&pos->user_dsos, fp); | ||
325 | } | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | ||
331 | bool (skip)(struct dso *dso, int parm), int parm) | ||
332 | { | ||
333 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + | ||
334 | __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); | ||
335 | } | ||
336 | |||
337 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, | ||
338 | bool (skip)(struct dso *dso, int parm), int parm) | ||
339 | { | ||
340 | struct rb_node *nd; | ||
341 | size_t ret = 0; | ||
342 | |||
343 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
344 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
345 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); | ||
346 | } | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | ||
351 | { | ||
352 | int i; | ||
353 | size_t printed = 0; | ||
354 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; | ||
355 | |||
356 | if (kdso->has_build_id) { | ||
357 | char filename[PATH_MAX]; | ||
358 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) | ||
359 | printed += fprintf(fp, "[0] %s\n", filename); | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < vmlinux_path__nr_entries; ++i) | ||
363 | printed += fprintf(fp, "[%d] %s\n", | ||
364 | i + kdso->has_build_id, vmlinux_path[i]); | ||
365 | |||
366 | return printed; | ||
367 | } | ||
368 | |||
369 | size_t machine__fprintf(struct machine *machine, FILE *fp) | ||
370 | { | ||
371 | size_t ret = 0; | ||
372 | struct rb_node *nd; | ||
373 | |||
374 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | ||
375 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
376 | |||
377 | ret += thread__fprintf(pos, fp); | ||
378 | } | ||
379 | |||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static struct dso *machine__get_kernel(struct machine *machine) | ||
384 | { | ||
385 | const char *vmlinux_name = NULL; | ||
386 | struct dso *kernel; | ||
387 | |||
388 | if (machine__is_host(machine)) { | ||
389 | vmlinux_name = symbol_conf.vmlinux_name; | ||
390 | if (!vmlinux_name) | ||
391 | vmlinux_name = "[kernel.kallsyms]"; | ||
392 | |||
393 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
394 | "[kernel]", | ||
395 | DSO_TYPE_KERNEL); | ||
396 | } else { | ||
397 | char bf[PATH_MAX]; | ||
398 | |||
399 | if (machine__is_default_guest(machine)) | ||
400 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | ||
401 | if (!vmlinux_name) | ||
402 | vmlinux_name = machine__mmap_name(machine, bf, | ||
403 | sizeof(bf)); | ||
404 | |||
405 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
406 | "[guest.kernel]", | ||
407 | DSO_TYPE_GUEST_KERNEL); | ||
408 | } | ||
409 | |||
410 | if (kernel != NULL && (!kernel->has_build_id)) | ||
411 | dso__read_running_kernel_build_id(kernel, machine); | ||
412 | |||
413 | return kernel; | ||
414 | } | ||
415 | |||
416 | struct process_args { | ||
417 | u64 start; | ||
418 | }; | ||
419 | |||
420 | static int symbol__in_kernel(void *arg, const char *name, | ||
421 | char type __maybe_unused, u64 start) | ||
422 | { | ||
423 | struct process_args *args = arg; | ||
424 | |||
425 | if (strchr(name, '[')) | ||
426 | return 0; | ||
427 | |||
428 | args->start = start; | ||
429 | return 1; | ||
430 | } | ||
431 | |||
432 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
433 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
434 | { | ||
435 | const char *filename; | ||
436 | char path[PATH_MAX]; | ||
437 | struct process_args args; | ||
438 | |||
439 | if (machine__is_host(machine)) { | ||
440 | filename = "/proc/kallsyms"; | ||
441 | } else { | ||
442 | if (machine__is_default_guest(machine)) | ||
443 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
444 | else { | ||
445 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
446 | filename = path; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
451 | return 0; | ||
452 | |||
453 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
454 | return 0; | ||
455 | |||
456 | return args.start; | ||
457 | } | ||
458 | |||
459 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | ||
460 | { | ||
461 | enum map_type type; | ||
462 | u64 start = machine__get_kernel_start_addr(machine); | ||
463 | |||
464 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
465 | struct kmap *kmap; | ||
466 | |||
467 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); | ||
468 | if (machine->vmlinux_maps[type] == NULL) | ||
469 | return -1; | ||
470 | |||
471 | machine->vmlinux_maps[type]->map_ip = | ||
472 | machine->vmlinux_maps[type]->unmap_ip = | ||
473 | identity__map_ip; | ||
474 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
475 | kmap->kmaps = &machine->kmaps; | ||
476 | map_groups__insert(&machine->kmaps, | ||
477 | machine->vmlinux_maps[type]); | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | void machine__destroy_kernel_maps(struct machine *machine) | ||
484 | { | ||
485 | enum map_type type; | ||
486 | |||
487 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
488 | struct kmap *kmap; | ||
489 | |||
490 | if (machine->vmlinux_maps[type] == NULL) | ||
491 | continue; | ||
492 | |||
493 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
494 | map_groups__remove(&machine->kmaps, | ||
495 | machine->vmlinux_maps[type]); | ||
496 | if (kmap->ref_reloc_sym) { | ||
497 | /* | ||
498 | * ref_reloc_sym is shared among all maps, so free just | ||
499 | * on one of them. | ||
500 | */ | ||
501 | if (type == MAP__FUNCTION) { | ||
502 | free((char *)kmap->ref_reloc_sym->name); | ||
503 | kmap->ref_reloc_sym->name = NULL; | ||
504 | free(kmap->ref_reloc_sym); | ||
505 | } | ||
506 | kmap->ref_reloc_sym = NULL; | ||
507 | } | ||
508 | |||
509 | map__delete(machine->vmlinux_maps[type]); | ||
510 | machine->vmlinux_maps[type] = NULL; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | int machines__create_guest_kernel_maps(struct rb_root *machines) | ||
515 | { | ||
516 | int ret = 0; | ||
517 | struct dirent **namelist = NULL; | ||
518 | int i, items = 0; | ||
519 | char path[PATH_MAX]; | ||
520 | pid_t pid; | ||
521 | char *endp; | ||
522 | |||
523 | if (symbol_conf.default_guest_vmlinux_name || | ||
524 | symbol_conf.default_guest_modules || | ||
525 | symbol_conf.default_guest_kallsyms) { | ||
526 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); | ||
527 | } | ||
528 | |||
529 | if (symbol_conf.guestmount) { | ||
530 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | ||
531 | if (items <= 0) | ||
532 | return -ENOENT; | ||
533 | for (i = 0; i < items; i++) { | ||
534 | if (!isdigit(namelist[i]->d_name[0])) { | ||
535 | /* Filter out . and .. */ | ||
536 | continue; | ||
537 | } | ||
538 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); | ||
539 | if ((*endp != '\0') || | ||
540 | (endp == namelist[i]->d_name) || | ||
541 | (errno == ERANGE)) { | ||
542 | pr_debug("invalid directory (%s). Skipping.\n", | ||
543 | namelist[i]->d_name); | ||
544 | continue; | ||
545 | } | ||
546 | sprintf(path, "%s/%s/proc/kallsyms", | ||
547 | symbol_conf.guestmount, | ||
548 | namelist[i]->d_name); | ||
549 | ret = access(path, R_OK); | ||
550 | if (ret) { | ||
551 | pr_debug("Can't access file %s\n", path); | ||
552 | goto failure; | ||
553 | } | ||
554 | machines__create_kernel_maps(machines, pid); | ||
555 | } | ||
556 | failure: | ||
557 | free(namelist); | ||
558 | } | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | void machines__destroy_guest_kernel_maps(struct rb_root *machines) | ||
564 | { | ||
565 | struct rb_node *next = rb_first(machines); | ||
566 | |||
567 | while (next) { | ||
568 | struct machine *pos = rb_entry(next, struct machine, rb_node); | ||
569 | |||
570 | next = rb_next(&pos->rb_node); | ||
571 | rb_erase(&pos->rb_node, machines); | ||
572 | machine__delete(pos); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | ||
577 | { | ||
578 | struct machine *machine = machines__findnew(machines, pid); | ||
579 | |||
580 | if (machine == NULL) | ||
581 | return -1; | ||
582 | |||
583 | return machine__create_kernel_maps(machine); | ||
584 | } | ||
585 | |||
586 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
587 | enum map_type type, symbol_filter_t filter) | ||
588 | { | ||
589 | struct map *map = machine->vmlinux_maps[type]; | ||
590 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | ||
591 | |||
592 | if (ret > 0) { | ||
593 | dso__set_loaded(map->dso, type); | ||
594 | /* | ||
595 | * Since /proc/kallsyms will have multiple sessions for the | ||
596 | * kernel, with modules between them, fixup the end of all | ||
597 | * sections. | ||
598 | */ | ||
599 | __map_groups__fixup_end(&machine->kmaps, type); | ||
600 | } | ||
601 | |||
602 | return ret; | ||
603 | } | ||
604 | |||
605 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
606 | symbol_filter_t filter) | ||
607 | { | ||
608 | struct map *map = machine->vmlinux_maps[type]; | ||
609 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | ||
610 | |||
611 | if (ret > 0) { | ||
612 | dso__set_loaded(map->dso, type); | ||
613 | map__reloc_vmlinux(map); | ||
614 | } | ||
615 | |||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static void map_groups__fixup_end(struct map_groups *mg) | ||
620 | { | ||
621 | int i; | ||
622 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
623 | __map_groups__fixup_end(mg, i); | ||
624 | } | ||
625 | |||
626 | static char *get_kernel_version(const char *root_dir) | ||
627 | { | ||
628 | char version[PATH_MAX]; | ||
629 | FILE *file; | ||
630 | char *name, *tmp; | ||
631 | const char *prefix = "Linux version "; | ||
632 | |||
633 | sprintf(version, "%s/proc/version", root_dir); | ||
634 | file = fopen(version, "r"); | ||
635 | if (!file) | ||
636 | return NULL; | ||
637 | |||
638 | version[0] = '\0'; | ||
639 | tmp = fgets(version, sizeof(version), file); | ||
640 | fclose(file); | ||
641 | |||
642 | name = strstr(version, prefix); | ||
643 | if (!name) | ||
644 | return NULL; | ||
645 | name += strlen(prefix); | ||
646 | tmp = strchr(name, ' '); | ||
647 | if (tmp) | ||
648 | *tmp = '\0'; | ||
649 | |||
650 | return strdup(name); | ||
651 | } | ||
652 | |||
653 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | ||
654 | const char *dir_name) | ||
655 | { | ||
656 | struct dirent *dent; | ||
657 | DIR *dir = opendir(dir_name); | ||
658 | int ret = 0; | ||
659 | |||
660 | if (!dir) { | ||
661 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); | ||
662 | return -1; | ||
663 | } | ||
664 | |||
665 | while ((dent = readdir(dir)) != NULL) { | ||
666 | char path[PATH_MAX]; | ||
667 | struct stat st; | ||
668 | |||
669 | /*sshfs might return bad dent->d_type, so we have to stat*/ | ||
670 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | ||
671 | if (stat(path, &st)) | ||
672 | continue; | ||
673 | |||
674 | if (S_ISDIR(st.st_mode)) { | ||
675 | if (!strcmp(dent->d_name, ".") || | ||
676 | !strcmp(dent->d_name, "..")) | ||
677 | continue; | ||
678 | |||
679 | ret = map_groups__set_modules_path_dir(mg, path); | ||
680 | if (ret < 0) | ||
681 | goto out; | ||
682 | } else { | ||
683 | char *dot = strrchr(dent->d_name, '.'), | ||
684 | dso_name[PATH_MAX]; | ||
685 | struct map *map; | ||
686 | char *long_name; | ||
687 | |||
688 | if (dot == NULL || strcmp(dot, ".ko")) | ||
689 | continue; | ||
690 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
691 | (int)(dot - dent->d_name), dent->d_name); | ||
692 | |||
693 | strxfrchar(dso_name, '-', '_'); | ||
694 | map = map_groups__find_by_name(mg, MAP__FUNCTION, | ||
695 | dso_name); | ||
696 | if (map == NULL) | ||
697 | continue; | ||
698 | |||
699 | long_name = strdup(path); | ||
700 | if (long_name == NULL) { | ||
701 | ret = -1; | ||
702 | goto out; | ||
703 | } | ||
704 | dso__set_long_name(map->dso, long_name); | ||
705 | map->dso->lname_alloc = 1; | ||
706 | dso__kernel_module_get_build_id(map->dso, ""); | ||
707 | } | ||
708 | } | ||
709 | |||
710 | out: | ||
711 | closedir(dir); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | static int machine__set_modules_path(struct machine *machine) | ||
716 | { | ||
717 | char *version; | ||
718 | char modules_path[PATH_MAX]; | ||
719 | |||
720 | version = get_kernel_version(machine->root_dir); | ||
721 | if (!version) | ||
722 | return -1; | ||
723 | |||
724 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", | ||
725 | machine->root_dir, version); | ||
726 | free(version); | ||
727 | |||
728 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | ||
729 | } | ||
730 | |||
731 | static int machine__create_modules(struct machine *machine) | ||
732 | { | ||
733 | char *line = NULL; | ||
734 | size_t n; | ||
735 | FILE *file; | ||
736 | struct map *map; | ||
737 | const char *modules; | ||
738 | char path[PATH_MAX]; | ||
739 | |||
740 | if (machine__is_default_guest(machine)) | ||
741 | modules = symbol_conf.default_guest_modules; | ||
742 | else { | ||
743 | sprintf(path, "%s/proc/modules", machine->root_dir); | ||
744 | modules = path; | ||
745 | } | ||
746 | |||
747 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
748 | return -1; | ||
749 | |||
750 | file = fopen(modules, "r"); | ||
751 | if (file == NULL) | ||
752 | return -1; | ||
753 | |||
754 | while (!feof(file)) { | ||
755 | char name[PATH_MAX]; | ||
756 | u64 start; | ||
757 | char *sep; | ||
758 | int line_len; | ||
759 | |||
760 | line_len = getline(&line, &n, file); | ||
761 | if (line_len < 0) | ||
762 | break; | ||
763 | |||
764 | if (!line) | ||
765 | goto out_failure; | ||
766 | |||
767 | line[--line_len] = '\0'; /* \n */ | ||
768 | |||
769 | sep = strrchr(line, 'x'); | ||
770 | if (sep == NULL) | ||
771 | continue; | ||
772 | |||
773 | hex2u64(sep + 1, &start); | ||
774 | |||
775 | sep = strchr(line, ' '); | ||
776 | if (sep == NULL) | ||
777 | continue; | ||
778 | |||
779 | *sep = '\0'; | ||
780 | |||
781 | snprintf(name, sizeof(name), "[%s]", line); | ||
782 | map = machine__new_module(machine, start, name); | ||
783 | if (map == NULL) | ||
784 | goto out_delete_line; | ||
785 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
786 | } | ||
787 | |||
788 | free(line); | ||
789 | fclose(file); | ||
790 | |||
791 | return machine__set_modules_path(machine); | ||
792 | |||
793 | out_delete_line: | ||
794 | free(line); | ||
795 | out_failure: | ||
796 | return -1; | ||
797 | } | ||
798 | |||
799 | int machine__create_kernel_maps(struct machine *machine) | ||
800 | { | ||
801 | struct dso *kernel = machine__get_kernel(machine); | ||
802 | |||
803 | if (kernel == NULL || | ||
804 | __machine__create_kernel_maps(machine, kernel) < 0) | ||
805 | return -1; | ||
806 | |||
807 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { | ||
808 | if (machine__is_host(machine)) | ||
809 | pr_debug("Problems creating module maps, " | ||
810 | "continuing anyway...\n"); | ||
811 | else | ||
812 | pr_debug("Problems creating module maps for guest %d, " | ||
813 | "continuing anyway...\n", machine->pid); | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * Now that we have all the maps created, just set the ->end of them: | ||
818 | */ | ||
819 | map_groups__fixup_end(&machine->kmaps); | ||
820 | return 0; | ||
821 | } | ||
822 | |||
267 | static void machine__set_kernel_mmap_len(struct machine *machine, | 823 | static void machine__set_kernel_mmap_len(struct machine *machine, |
268 | union perf_event *event) | 824 | union perf_event *event) |
269 | { | 825 | { |
@@ -462,3 +1018,189 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
462 | 1018 | ||
463 | return ret; | 1019 | return ret; |
464 | } | 1020 | } |
1021 | |||
1022 | void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1023 | { | ||
1024 | machine->last_match = NULL; | ||
1025 | rb_erase(&th->rb_node, &machine->threads); | ||
1026 | /* | ||
1027 | * We may have references to this thread, for instance in some hist_entry | ||
1028 | * instances, so just move them to a separate list. | ||
1029 | */ | ||
1030 | list_add_tail(&th->node, &machine->dead_threads); | ||
1031 | } | ||
1032 | |||
1033 | static bool symbol__match_parent_regex(struct symbol *sym) | ||
1034 | { | ||
1035 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | ||
1036 | return 1; | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static const u8 cpumodes[] = { | ||
1042 | PERF_RECORD_MISC_USER, | ||
1043 | PERF_RECORD_MISC_KERNEL, | ||
1044 | PERF_RECORD_MISC_GUEST_USER, | ||
1045 | PERF_RECORD_MISC_GUEST_KERNEL | ||
1046 | }; | ||
1047 | #define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) | ||
1048 | |||
1049 | static void ip__resolve_ams(struct machine *machine, struct thread *thread, | ||
1050 | struct addr_map_symbol *ams, | ||
1051 | u64 ip) | ||
1052 | { | ||
1053 | struct addr_location al; | ||
1054 | size_t i; | ||
1055 | u8 m; | ||
1056 | |||
1057 | memset(&al, 0, sizeof(al)); | ||
1058 | |||
1059 | for (i = 0; i < NCPUMODES; i++) { | ||
1060 | m = cpumodes[i]; | ||
1061 | /* | ||
1062 | * We cannot use the header.misc hint to determine whether a | ||
1063 | * branch stack address is user, kernel, guest, hypervisor. | ||
1064 | * Branches may straddle the kernel/user/hypervisor boundaries. | ||
1065 | * Thus, we have to try consecutively until we find a match | ||
1066 | * or else, the symbol is unknown | ||
1067 | */ | ||
1068 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | ||
1069 | ip, &al, NULL); | ||
1070 | if (al.sym) | ||
1071 | goto found; | ||
1072 | } | ||
1073 | found: | ||
1074 | ams->addr = ip; | ||
1075 | ams->al_addr = al.addr; | ||
1076 | ams->sym = al.sym; | ||
1077 | ams->map = al.map; | ||
1078 | } | ||
1079 | |||
1080 | struct branch_info *machine__resolve_bstack(struct machine *machine, | ||
1081 | struct thread *thr, | ||
1082 | struct branch_stack *bs) | ||
1083 | { | ||
1084 | struct branch_info *bi; | ||
1085 | unsigned int i; | ||
1086 | |||
1087 | bi = calloc(bs->nr, sizeof(struct branch_info)); | ||
1088 | if (!bi) | ||
1089 | return NULL; | ||
1090 | |||
1091 | for (i = 0; i < bs->nr; i++) { | ||
1092 | ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to); | ||
1093 | ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from); | ||
1094 | bi[i].flags = bs->entries[i].flags; | ||
1095 | } | ||
1096 | return bi; | ||
1097 | } | ||
1098 | |||
1099 | static int machine__resolve_callchain_sample(struct machine *machine, | ||
1100 | struct thread *thread, | ||
1101 | struct ip_callchain *chain, | ||
1102 | struct symbol **parent) | ||
1103 | |||
1104 | { | ||
1105 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
1106 | unsigned int i; | ||
1107 | int err; | ||
1108 | |||
1109 | callchain_cursor_reset(&callchain_cursor); | ||
1110 | |||
1111 | if (chain->nr > PERF_MAX_STACK_DEPTH) { | ||
1112 | pr_warning("corrupted callchain. skipping...\n"); | ||
1113 | return 0; | ||
1114 | } | ||
1115 | |||
1116 | for (i = 0; i < chain->nr; i++) { | ||
1117 | u64 ip; | ||
1118 | struct addr_location al; | ||
1119 | |||
1120 | if (callchain_param.order == ORDER_CALLEE) | ||
1121 | ip = chain->ips[i]; | ||
1122 | else | ||
1123 | ip = chain->ips[chain->nr - i - 1]; | ||
1124 | |||
1125 | if (ip >= PERF_CONTEXT_MAX) { | ||
1126 | switch (ip) { | ||
1127 | case PERF_CONTEXT_HV: | ||
1128 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | ||
1129 | break; | ||
1130 | case PERF_CONTEXT_KERNEL: | ||
1131 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
1132 | break; | ||
1133 | case PERF_CONTEXT_USER: | ||
1134 | cpumode = PERF_RECORD_MISC_USER; | ||
1135 | break; | ||
1136 | default: | ||
1137 | pr_debug("invalid callchain context: " | ||
1138 | "%"PRId64"\n", (s64) ip); | ||
1139 | /* | ||
1140 | * It seems the callchain is corrupted. | ||
1141 | * Discard all. | ||
1142 | */ | ||
1143 | callchain_cursor_reset(&callchain_cursor); | ||
1144 | return 0; | ||
1145 | } | ||
1146 | continue; | ||
1147 | } | ||
1148 | |||
1149 | al.filtered = false; | ||
1150 | thread__find_addr_location(thread, machine, cpumode, | ||
1151 | MAP__FUNCTION, ip, &al, NULL); | ||
1152 | if (al.sym != NULL) { | ||
1153 | if (sort__has_parent && !*parent && | ||
1154 | symbol__match_parent_regex(al.sym)) | ||
1155 | *parent = al.sym; | ||
1156 | if (!symbol_conf.use_callchain) | ||
1157 | break; | ||
1158 | } | ||
1159 | |||
1160 | err = callchain_cursor_append(&callchain_cursor, | ||
1161 | ip, al.map, al.sym); | ||
1162 | if (err) | ||
1163 | return err; | ||
1164 | } | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static int unwind_entry(struct unwind_entry *entry, void *arg) | ||
1170 | { | ||
1171 | struct callchain_cursor *cursor = arg; | ||
1172 | return callchain_cursor_append(cursor, entry->ip, | ||
1173 | entry->map, entry->sym); | ||
1174 | } | ||
1175 | |||
1176 | int machine__resolve_callchain(struct machine *machine, | ||
1177 | struct perf_evsel *evsel, | ||
1178 | struct thread *thread, | ||
1179 | struct perf_sample *sample, | ||
1180 | struct symbol **parent) | ||
1181 | |||
1182 | { | ||
1183 | int ret; | ||
1184 | |||
1185 | callchain_cursor_reset(&callchain_cursor); | ||
1186 | |||
1187 | ret = machine__resolve_callchain_sample(machine, thread, | ||
1188 | sample->callchain, parent); | ||
1189 | if (ret) | ||
1190 | return ret; | ||
1191 | |||
1192 | /* Can we do dwarf post unwind? */ | ||
1193 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
1194 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
1195 | return 0; | ||
1196 | |||
1197 | /* Bail out if nothing was captured. */ | ||
1198 | if ((!sample->user_regs.regs) || | ||
1199 | (!sample->user_stack.size)) | ||
1200 | return 0; | ||
1201 | |||
1202 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
1203 | thread, evsel->attr.sample_regs_user, | ||
1204 | sample); | ||
1205 | |||
1206 | } | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b7cde7467d55..e11236878ec1 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -61,9 +61,10 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | |||
61 | 61 | ||
62 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 62 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
63 | void machine__exit(struct machine *machine); | 63 | void machine__exit(struct machine *machine); |
64 | void machine__delete_dead_threads(struct machine *machine); | ||
65 | void machine__delete_threads(struct machine *machine); | ||
64 | void machine__delete(struct machine *machine); | 66 | void machine__delete(struct machine *machine); |
65 | 67 | ||
66 | |||
67 | struct branch_info *machine__resolve_bstack(struct machine *machine, | 68 | struct branch_info *machine__resolve_bstack(struct machine *machine, |
68 | struct thread *thread, | 69 | struct thread *thread, |
69 | struct branch_stack *bs); | 70 | struct branch_stack *bs); |
@@ -129,11 +130,11 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, | |||
129 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 130 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
130 | symbol_filter_t filter); | 131 | symbol_filter_t filter); |
131 | 132 | ||
132 | size_t machine__fprintf_dsos_buildid(struct machine *machine, | 133 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
133 | FILE *fp, bool with_hits); | 134 | bool (skip)(struct dso *dso, int parm), int parm); |
134 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); | 135 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); |
135 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | 136 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, |
136 | FILE *fp, bool with_hits); | 137 | bool (skip)(struct dso *dso, int parm), int parm); |
137 | 138 | ||
138 | void machine__destroy_kernel_maps(struct machine *machine); | 139 | void machine__destroy_kernel_maps(struct machine *machine); |
139 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | 140 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ce6f51162386..76d6e257b8a4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include "cpumap.h" | 16 | #include "cpumap.h" |
17 | #include "event-parse.h" | 17 | #include "event-parse.h" |
18 | #include "perf_regs.h" | 18 | #include "perf_regs.h" |
19 | #include "unwind.h" | ||
20 | #include "vdso.h" | 19 | #include "vdso.h" |
21 | 20 | ||
22 | static int perf_session__open(struct perf_session *self, bool force) | 21 | static int perf_session__open(struct perf_session *self, bool force) |
@@ -128,15 +127,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
128 | goto out; | 127 | goto out; |
129 | 128 | ||
130 | memcpy(self->filename, filename, len); | 129 | memcpy(self->filename, filename, len); |
131 | /* | ||
132 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | ||
133 | * slices. On 32bit we use 32MB. | ||
134 | */ | ||
135 | #if BITS_PER_LONG == 64 | ||
136 | self->mmap_window = ULLONG_MAX; | ||
137 | #else | ||
138 | self->mmap_window = 32 * 1024 * 1024ULL; | ||
139 | #endif | ||
140 | self->machines = RB_ROOT; | 130 | self->machines = RB_ROOT; |
141 | self->repipe = repipe; | 131 | self->repipe = repipe; |
142 | INIT_LIST_HEAD(&self->ordered_samples.samples); | 132 | INIT_LIST_HEAD(&self->ordered_samples.samples); |
@@ -171,37 +161,30 @@ out_delete: | |||
171 | return NULL; | 161 | return NULL; |
172 | } | 162 | } |
173 | 163 | ||
174 | static void machine__delete_dead_threads(struct machine *machine) | ||
175 | { | ||
176 | struct thread *n, *t; | ||
177 | |||
178 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | ||
179 | list_del(&t->node); | ||
180 | thread__delete(t); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void perf_session__delete_dead_threads(struct perf_session *session) | 164 | static void perf_session__delete_dead_threads(struct perf_session *session) |
185 | { | 165 | { |
186 | machine__delete_dead_threads(&session->host_machine); | 166 | machine__delete_dead_threads(&session->host_machine); |
187 | } | 167 | } |
188 | 168 | ||
189 | static void machine__delete_threads(struct machine *self) | 169 | static void perf_session__delete_threads(struct perf_session *session) |
190 | { | 170 | { |
191 | struct rb_node *nd = rb_first(&self->threads); | 171 | machine__delete_threads(&session->host_machine); |
192 | |||
193 | while (nd) { | ||
194 | struct thread *t = rb_entry(nd, struct thread, rb_node); | ||
195 | |||
196 | rb_erase(&t->rb_node, &self->threads); | ||
197 | nd = rb_next(nd); | ||
198 | thread__delete(t); | ||
199 | } | ||
200 | } | 172 | } |
201 | 173 | ||
202 | static void perf_session__delete_threads(struct perf_session *session) | 174 | static void perf_session_env__delete(struct perf_session_env *env) |
203 | { | 175 | { |
204 | machine__delete_threads(&session->host_machine); | 176 | free(env->hostname); |
177 | free(env->os_release); | ||
178 | free(env->version); | ||
179 | free(env->arch); | ||
180 | free(env->cpu_desc); | ||
181 | free(env->cpuid); | ||
182 | |||
183 | free(env->cmdline); | ||
184 | free(env->sibling_cores); | ||
185 | free(env->sibling_threads); | ||
186 | free(env->numa_nodes); | ||
187 | free(env->pmu_mappings); | ||
205 | } | 188 | } |
206 | 189 | ||
207 | void perf_session__delete(struct perf_session *self) | 190 | void perf_session__delete(struct perf_session *self) |
@@ -209,198 +192,13 @@ void perf_session__delete(struct perf_session *self) | |||
209 | perf_session__destroy_kernel_maps(self); | 192 | perf_session__destroy_kernel_maps(self); |
210 | perf_session__delete_dead_threads(self); | 193 | perf_session__delete_dead_threads(self); |
211 | perf_session__delete_threads(self); | 194 | perf_session__delete_threads(self); |
195 | perf_session_env__delete(&self->header.env); | ||
212 | machine__exit(&self->host_machine); | 196 | machine__exit(&self->host_machine); |
213 | close(self->fd); | 197 | close(self->fd); |
214 | free(self); | 198 | free(self); |
215 | vdso__exit(); | 199 | vdso__exit(); |
216 | } | 200 | } |
217 | 201 | ||
218 | void machine__remove_thread(struct machine *self, struct thread *th) | ||
219 | { | ||
220 | self->last_match = NULL; | ||
221 | rb_erase(&th->rb_node, &self->threads); | ||
222 | /* | ||
223 | * We may have references to this thread, for instance in some hist_entry | ||
224 | * instances, so just move them to a separate list. | ||
225 | */ | ||
226 | list_add_tail(&th->node, &self->dead_threads); | ||
227 | } | ||
228 | |||
229 | static bool symbol__match_parent_regex(struct symbol *sym) | ||
230 | { | ||
231 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | ||
232 | return 1; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static const u8 cpumodes[] = { | ||
238 | PERF_RECORD_MISC_USER, | ||
239 | PERF_RECORD_MISC_KERNEL, | ||
240 | PERF_RECORD_MISC_GUEST_USER, | ||
241 | PERF_RECORD_MISC_GUEST_KERNEL | ||
242 | }; | ||
243 | #define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) | ||
244 | |||
245 | static void ip__resolve_ams(struct machine *self, struct thread *thread, | ||
246 | struct addr_map_symbol *ams, | ||
247 | u64 ip) | ||
248 | { | ||
249 | struct addr_location al; | ||
250 | size_t i; | ||
251 | u8 m; | ||
252 | |||
253 | memset(&al, 0, sizeof(al)); | ||
254 | |||
255 | for (i = 0; i < NCPUMODES; i++) { | ||
256 | m = cpumodes[i]; | ||
257 | /* | ||
258 | * We cannot use the header.misc hint to determine whether a | ||
259 | * branch stack address is user, kernel, guest, hypervisor. | ||
260 | * Branches may straddle the kernel/user/hypervisor boundaries. | ||
261 | * Thus, we have to try consecutively until we find a match | ||
262 | * or else, the symbol is unknown | ||
263 | */ | ||
264 | thread__find_addr_location(thread, self, m, MAP__FUNCTION, | ||
265 | ip, &al, NULL); | ||
266 | if (al.sym) | ||
267 | goto found; | ||
268 | } | ||
269 | found: | ||
270 | ams->addr = ip; | ||
271 | ams->al_addr = al.addr; | ||
272 | ams->sym = al.sym; | ||
273 | ams->map = al.map; | ||
274 | } | ||
275 | |||
276 | struct branch_info *machine__resolve_bstack(struct machine *self, | ||
277 | struct thread *thr, | ||
278 | struct branch_stack *bs) | ||
279 | { | ||
280 | struct branch_info *bi; | ||
281 | unsigned int i; | ||
282 | |||
283 | bi = calloc(bs->nr, sizeof(struct branch_info)); | ||
284 | if (!bi) | ||
285 | return NULL; | ||
286 | |||
287 | for (i = 0; i < bs->nr; i++) { | ||
288 | ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to); | ||
289 | ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from); | ||
290 | bi[i].flags = bs->entries[i].flags; | ||
291 | } | ||
292 | return bi; | ||
293 | } | ||
294 | |||
295 | static int machine__resolve_callchain_sample(struct machine *machine, | ||
296 | struct thread *thread, | ||
297 | struct ip_callchain *chain, | ||
298 | struct symbol **parent) | ||
299 | |||
300 | { | ||
301 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
302 | unsigned int i; | ||
303 | int err; | ||
304 | |||
305 | callchain_cursor_reset(&callchain_cursor); | ||
306 | |||
307 | if (chain->nr > PERF_MAX_STACK_DEPTH) { | ||
308 | pr_warning("corrupted callchain. skipping...\n"); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | for (i = 0; i < chain->nr; i++) { | ||
313 | u64 ip; | ||
314 | struct addr_location al; | ||
315 | |||
316 | if (callchain_param.order == ORDER_CALLEE) | ||
317 | ip = chain->ips[i]; | ||
318 | else | ||
319 | ip = chain->ips[chain->nr - i - 1]; | ||
320 | |||
321 | if (ip >= PERF_CONTEXT_MAX) { | ||
322 | switch (ip) { | ||
323 | case PERF_CONTEXT_HV: | ||
324 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | ||
325 | break; | ||
326 | case PERF_CONTEXT_KERNEL: | ||
327 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
328 | break; | ||
329 | case PERF_CONTEXT_USER: | ||
330 | cpumode = PERF_RECORD_MISC_USER; | ||
331 | break; | ||
332 | default: | ||
333 | pr_debug("invalid callchain context: " | ||
334 | "%"PRId64"\n", (s64) ip); | ||
335 | /* | ||
336 | * It seems the callchain is corrupted. | ||
337 | * Discard all. | ||
338 | */ | ||
339 | callchain_cursor_reset(&callchain_cursor); | ||
340 | return 0; | ||
341 | } | ||
342 | continue; | ||
343 | } | ||
344 | |||
345 | al.filtered = false; | ||
346 | thread__find_addr_location(thread, machine, cpumode, | ||
347 | MAP__FUNCTION, ip, &al, NULL); | ||
348 | if (al.sym != NULL) { | ||
349 | if (sort__has_parent && !*parent && | ||
350 | symbol__match_parent_regex(al.sym)) | ||
351 | *parent = al.sym; | ||
352 | if (!symbol_conf.use_callchain) | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | err = callchain_cursor_append(&callchain_cursor, | ||
357 | ip, al.map, al.sym); | ||
358 | if (err) | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int unwind_entry(struct unwind_entry *entry, void *arg) | ||
366 | { | ||
367 | struct callchain_cursor *cursor = arg; | ||
368 | return callchain_cursor_append(cursor, entry->ip, | ||
369 | entry->map, entry->sym); | ||
370 | } | ||
371 | |||
372 | int machine__resolve_callchain(struct machine *machine, | ||
373 | struct perf_evsel *evsel, | ||
374 | struct thread *thread, | ||
375 | struct perf_sample *sample, | ||
376 | struct symbol **parent) | ||
377 | |||
378 | { | ||
379 | int ret; | ||
380 | |||
381 | callchain_cursor_reset(&callchain_cursor); | ||
382 | |||
383 | ret = machine__resolve_callchain_sample(machine, thread, | ||
384 | sample->callchain, parent); | ||
385 | if (ret) | ||
386 | return ret; | ||
387 | |||
388 | /* Can we do dwarf post unwind? */ | ||
389 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
390 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
391 | return 0; | ||
392 | |||
393 | /* Bail out if nothing was captured. */ | ||
394 | if ((!sample->user_regs.regs) || | ||
395 | (!sample->user_stack.size)) | ||
396 | return 0; | ||
397 | |||
398 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
399 | thread, evsel->attr.sample_regs_user, | ||
400 | sample); | ||
401 | |||
402 | } | ||
403 | |||
404 | static int process_event_synth_tracing_data_stub(union perf_event *event | 202 | static int process_event_synth_tracing_data_stub(union perf_event *event |
405 | __maybe_unused, | 203 | __maybe_unused, |
406 | struct perf_session *session | 204 | struct perf_session *session |
@@ -1369,6 +1167,18 @@ fetch_mmaped_event(struct perf_session *session, | |||
1369 | return event; | 1167 | return event; |
1370 | } | 1168 | } |
1371 | 1169 | ||
1170 | /* | ||
1171 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | ||
1172 | * slices. On 32bit we use 32MB. | ||
1173 | */ | ||
1174 | #if BITS_PER_LONG == 64 | ||
1175 | #define MMAP_SIZE ULLONG_MAX | ||
1176 | #define NUM_MMAPS 1 | ||
1177 | #else | ||
1178 | #define MMAP_SIZE (32 * 1024 * 1024ULL) | ||
1179 | #define NUM_MMAPS 128 | ||
1180 | #endif | ||
1181 | |||
1372 | int __perf_session__process_events(struct perf_session *session, | 1182 | int __perf_session__process_events(struct perf_session *session, |
1373 | u64 data_offset, u64 data_size, | 1183 | u64 data_offset, u64 data_size, |
1374 | u64 file_size, struct perf_tool *tool) | 1184 | u64 file_size, struct perf_tool *tool) |
@@ -1376,7 +1186,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1376 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1186 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1377 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1187 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1378 | size_t mmap_size; | 1188 | size_t mmap_size; |
1379 | char *buf, *mmaps[8]; | 1189 | char *buf, *mmaps[NUM_MMAPS]; |
1380 | union perf_event *event; | 1190 | union perf_event *event; |
1381 | uint32_t size; | 1191 | uint32_t size; |
1382 | 1192 | ||
@@ -1391,7 +1201,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1391 | 1201 | ||
1392 | progress_next = file_size / 16; | 1202 | progress_next = file_size / 16; |
1393 | 1203 | ||
1394 | mmap_size = session->mmap_window; | 1204 | mmap_size = MMAP_SIZE; |
1395 | if (mmap_size > file_size) | 1205 | if (mmap_size > file_size) |
1396 | mmap_size = file_size; | 1206 | mmap_size = file_size; |
1397 | 1207 | ||
@@ -1532,10 +1342,10 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) | |||
1532 | } | 1342 | } |
1533 | 1343 | ||
1534 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, | 1344 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, |
1535 | bool with_hits) | 1345 | bool (skip)(struct dso *dso, int parm), int parm) |
1536 | { | 1346 | { |
1537 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); | 1347 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); |
1538 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); | 1348 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); |
1539 | } | 1349 | } |
1540 | 1350 | ||
1541 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | 1351 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index cea133a6bdf1..8c2302504199 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -30,7 +30,6 @@ struct ordered_samples { | |||
30 | struct perf_session { | 30 | struct perf_session { |
31 | struct perf_header header; | 31 | struct perf_header header; |
32 | unsigned long size; | 32 | unsigned long size; |
33 | unsigned long mmap_window; | ||
34 | struct machine host_machine; | 33 | struct machine host_machine; |
35 | struct rb_root machines; | 34 | struct rb_root machines; |
36 | struct perf_evlist *evlist; | 35 | struct perf_evlist *evlist; |
@@ -116,8 +115,8 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp); | |||
116 | 115 | ||
117 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); | 116 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); |
118 | 117 | ||
119 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, | 118 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp, |
120 | FILE *fp, bool with_hits); | 119 | bool (fn)(struct dso *dso, int parm), int parm); |
121 | 120 | ||
122 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | 121 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); |
123 | 122 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b4e8c3ba559d..a1c0d56b6885 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -55,9 +55,6 @@ struct he_stat { | |||
55 | struct hist_entry_diff { | 55 | struct hist_entry_diff { |
56 | bool computed; | 56 | bool computed; |
57 | 57 | ||
58 | /* PERF_HPP__DISPL */ | ||
59 | int displacement; | ||
60 | |||
61 | /* PERF_HPP__DELTA */ | 58 | /* PERF_HPP__DELTA */ |
62 | double period_ratio_delta; | 59 | double period_ratio_delta; |
63 | 60 | ||
@@ -118,7 +115,7 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) | |||
118 | return NULL; | 115 | return NULL; |
119 | } | 116 | } |
120 | 117 | ||
121 | static inline void hist__entry_add_pair(struct hist_entry *he, | 118 | static inline void hist_entry__add_pair(struct hist_entry *he, |
122 | struct hist_entry *pair) | 119 | struct hist_entry *pair) |
123 | { | 120 | { |
124 | list_add_tail(&he->pairs.head, &pair->pairs.node); | 121 | list_add_tail(&he->pairs.head, &pair->pairs.node); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index db0cc92cf2ea..f63557b59c06 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -718,6 +718,17 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
718 | sym.st_value); | 718 | sym.st_value); |
719 | used_opd = true; | 719 | used_opd = true; |
720 | } | 720 | } |
721 | /* | ||
722 | * When loading symbols in a data mapping, ABS symbols (which | ||
723 | * has a value of SHN_ABS in its st_shndx) failed at | ||
724 | * elf_getscn(). And it marks the loading as a failure so | ||
725 | * already loaded symbols cannot be fixed up. | ||
726 | * | ||
727 | * I'm not sure what should be done. Just ignore them for now. | ||
728 | * - Namhyung Kim | ||
729 | */ | ||
730 | if (sym.st_shndx == SHN_ABS) | ||
731 | continue; | ||
721 | 732 | ||
722 | sec = elf_getscn(runtime_ss->elf, sym.st_shndx); | 733 | sec = elf_getscn(runtime_ss->elf, sym.st_shndx); |
723 | if (!sec) | 734 | if (!sec) |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 295f8d4feedf..2960284d6ae1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
28 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
30 | symbol_filter_t filter); | 30 | symbol_filter_t filter); |
31 | static int vmlinux_path__nr_entries; | 31 | int vmlinux_path__nr_entries; |
32 | static char **vmlinux_path; | 32 | char **vmlinux_path; |
33 | 33 | ||
34 | struct symbol_conf symbol_conf = { | 34 | struct symbol_conf symbol_conf = { |
35 | .exclude_other = true, | 35 | .exclude_other = true, |
@@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) | |||
202 | curr->end = ~0ULL; | 202 | curr->end = ~0ULL; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void map_groups__fixup_end(struct map_groups *mg) | ||
206 | { | ||
207 | int i; | ||
208 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
209 | __map_groups__fixup_end(mg, i); | ||
210 | } | ||
211 | |||
212 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) | 205 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) |
213 | { | 206 | { |
214 | size_t namelen = strlen(name) + 1; | 207 | size_t namelen = strlen(name) + 1; |
@@ -652,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
652 | return count + moved; | 645 | return count + moved; |
653 | } | 646 | } |
654 | 647 | ||
655 | static bool symbol__restricted_filename(const char *filename, | 648 | bool symbol__restricted_filename(const char *filename, |
656 | const char *restricted_filename) | 649 | const char *restricted_filename) |
657 | { | 650 | { |
658 | bool restricted = false; | 651 | bool restricted = false; |
659 | 652 | ||
@@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
887 | return NULL; | 880 | return NULL; |
888 | } | 881 | } |
889 | 882 | ||
890 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | ||
891 | const char *dir_name) | ||
892 | { | ||
893 | struct dirent *dent; | ||
894 | DIR *dir = opendir(dir_name); | ||
895 | int ret = 0; | ||
896 | |||
897 | if (!dir) { | ||
898 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); | ||
899 | return -1; | ||
900 | } | ||
901 | |||
902 | while ((dent = readdir(dir)) != NULL) { | ||
903 | char path[PATH_MAX]; | ||
904 | struct stat st; | ||
905 | |||
906 | /*sshfs might return bad dent->d_type, so we have to stat*/ | ||
907 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | ||
908 | if (stat(path, &st)) | ||
909 | continue; | ||
910 | |||
911 | if (S_ISDIR(st.st_mode)) { | ||
912 | if (!strcmp(dent->d_name, ".") || | ||
913 | !strcmp(dent->d_name, "..")) | ||
914 | continue; | ||
915 | |||
916 | ret = map_groups__set_modules_path_dir(mg, path); | ||
917 | if (ret < 0) | ||
918 | goto out; | ||
919 | } else { | ||
920 | char *dot = strrchr(dent->d_name, '.'), | ||
921 | dso_name[PATH_MAX]; | ||
922 | struct map *map; | ||
923 | char *long_name; | ||
924 | |||
925 | if (dot == NULL || strcmp(dot, ".ko")) | ||
926 | continue; | ||
927 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
928 | (int)(dot - dent->d_name), dent->d_name); | ||
929 | |||
930 | strxfrchar(dso_name, '-', '_'); | ||
931 | map = map_groups__find_by_name(mg, MAP__FUNCTION, | ||
932 | dso_name); | ||
933 | if (map == NULL) | ||
934 | continue; | ||
935 | |||
936 | long_name = strdup(path); | ||
937 | if (long_name == NULL) { | ||
938 | ret = -1; | ||
939 | goto out; | ||
940 | } | ||
941 | dso__set_long_name(map->dso, long_name); | ||
942 | map->dso->lname_alloc = 1; | ||
943 | dso__kernel_module_get_build_id(map->dso, ""); | ||
944 | } | ||
945 | } | ||
946 | |||
947 | out: | ||
948 | closedir(dir); | ||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | static char *get_kernel_version(const char *root_dir) | ||
953 | { | ||
954 | char version[PATH_MAX]; | ||
955 | FILE *file; | ||
956 | char *name, *tmp; | ||
957 | const char *prefix = "Linux version "; | ||
958 | |||
959 | sprintf(version, "%s/proc/version", root_dir); | ||
960 | file = fopen(version, "r"); | ||
961 | if (!file) | ||
962 | return NULL; | ||
963 | |||
964 | version[0] = '\0'; | ||
965 | tmp = fgets(version, sizeof(version), file); | ||
966 | fclose(file); | ||
967 | |||
968 | name = strstr(version, prefix); | ||
969 | if (!name) | ||
970 | return NULL; | ||
971 | name += strlen(prefix); | ||
972 | tmp = strchr(name, ' '); | ||
973 | if (tmp) | ||
974 | *tmp = '\0'; | ||
975 | |||
976 | return strdup(name); | ||
977 | } | ||
978 | |||
979 | static int machine__set_modules_path(struct machine *machine) | ||
980 | { | ||
981 | char *version; | ||
982 | char modules_path[PATH_MAX]; | ||
983 | |||
984 | version = get_kernel_version(machine->root_dir); | ||
985 | if (!version) | ||
986 | return -1; | ||
987 | |||
988 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", | ||
989 | machine->root_dir, version); | ||
990 | free(version); | ||
991 | |||
992 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | ||
993 | } | ||
994 | |||
995 | struct map *machine__new_module(struct machine *machine, u64 start, | ||
996 | const char *filename) | ||
997 | { | ||
998 | struct map *map; | ||
999 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | ||
1000 | |||
1001 | if (dso == NULL) | ||
1002 | return NULL; | ||
1003 | |||
1004 | map = map__new2(start, dso, MAP__FUNCTION); | ||
1005 | if (map == NULL) | ||
1006 | return NULL; | ||
1007 | |||
1008 | if (machine__is_host(machine)) | ||
1009 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
1010 | else | ||
1011 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
1012 | map_groups__insert(&machine->kmaps, map); | ||
1013 | return map; | ||
1014 | } | ||
1015 | |||
1016 | static int machine__create_modules(struct machine *machine) | ||
1017 | { | ||
1018 | char *line = NULL; | ||
1019 | size_t n; | ||
1020 | FILE *file; | ||
1021 | struct map *map; | ||
1022 | const char *modules; | ||
1023 | char path[PATH_MAX]; | ||
1024 | |||
1025 | if (machine__is_default_guest(machine)) | ||
1026 | modules = symbol_conf.default_guest_modules; | ||
1027 | else { | ||
1028 | sprintf(path, "%s/proc/modules", machine->root_dir); | ||
1029 | modules = path; | ||
1030 | } | ||
1031 | |||
1032 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
1033 | return -1; | ||
1034 | |||
1035 | file = fopen(modules, "r"); | ||
1036 | if (file == NULL) | ||
1037 | return -1; | ||
1038 | |||
1039 | while (!feof(file)) { | ||
1040 | char name[PATH_MAX]; | ||
1041 | u64 start; | ||
1042 | char *sep; | ||
1043 | int line_len; | ||
1044 | |||
1045 | line_len = getline(&line, &n, file); | ||
1046 | if (line_len < 0) | ||
1047 | break; | ||
1048 | |||
1049 | if (!line) | ||
1050 | goto out_failure; | ||
1051 | |||
1052 | line[--line_len] = '\0'; /* \n */ | ||
1053 | |||
1054 | sep = strrchr(line, 'x'); | ||
1055 | if (sep == NULL) | ||
1056 | continue; | ||
1057 | |||
1058 | hex2u64(sep + 1, &start); | ||
1059 | |||
1060 | sep = strchr(line, ' '); | ||
1061 | if (sep == NULL) | ||
1062 | continue; | ||
1063 | |||
1064 | *sep = '\0'; | ||
1065 | |||
1066 | snprintf(name, sizeof(name), "[%s]", line); | ||
1067 | map = machine__new_module(machine, start, name); | ||
1068 | if (map == NULL) | ||
1069 | goto out_delete_line; | ||
1070 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
1071 | } | ||
1072 | |||
1073 | free(line); | ||
1074 | fclose(file); | ||
1075 | |||
1076 | return machine__set_modules_path(machine); | ||
1077 | |||
1078 | out_delete_line: | ||
1079 | free(line); | ||
1080 | out_failure: | ||
1081 | return -1; | ||
1082 | } | ||
1083 | |||
1084 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 883 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1085 | const char *vmlinux, symbol_filter_t filter) | 884 | const char *vmlinux, symbol_filter_t filter) |
1086 | { | 885 | { |
@@ -1300,195 +1099,6 @@ out_try_fixup: | |||
1300 | return err; | 1099 | return err; |
1301 | } | 1100 | } |
1302 | 1101 | ||
1303 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | ||
1304 | { | ||
1305 | struct rb_node *nd; | ||
1306 | size_t ret = 0; | ||
1307 | |||
1308 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
1309 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
1310 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | ||
1311 | ret += __dsos__fprintf(&pos->user_dsos, fp); | ||
1312 | } | ||
1313 | |||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | ||
1318 | bool with_hits) | ||
1319 | { | ||
1320 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + | ||
1321 | __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); | ||
1322 | } | ||
1323 | |||
1324 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | ||
1325 | FILE *fp, bool with_hits) | ||
1326 | { | ||
1327 | struct rb_node *nd; | ||
1328 | size_t ret = 0; | ||
1329 | |||
1330 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
1331 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
1332 | ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); | ||
1333 | } | ||
1334 | return ret; | ||
1335 | } | ||
1336 | |||
1337 | static struct dso *machine__get_kernel(struct machine *machine) | ||
1338 | { | ||
1339 | const char *vmlinux_name = NULL; | ||
1340 | struct dso *kernel; | ||
1341 | |||
1342 | if (machine__is_host(machine)) { | ||
1343 | vmlinux_name = symbol_conf.vmlinux_name; | ||
1344 | if (!vmlinux_name) | ||
1345 | vmlinux_name = "[kernel.kallsyms]"; | ||
1346 | |||
1347 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
1348 | "[kernel]", | ||
1349 | DSO_TYPE_KERNEL); | ||
1350 | } else { | ||
1351 | char bf[PATH_MAX]; | ||
1352 | |||
1353 | if (machine__is_default_guest(machine)) | ||
1354 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | ||
1355 | if (!vmlinux_name) | ||
1356 | vmlinux_name = machine__mmap_name(machine, bf, | ||
1357 | sizeof(bf)); | ||
1358 | |||
1359 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
1360 | "[guest.kernel]", | ||
1361 | DSO_TYPE_GUEST_KERNEL); | ||
1362 | } | ||
1363 | |||
1364 | if (kernel != NULL && (!kernel->has_build_id)) | ||
1365 | dso__read_running_kernel_build_id(kernel, machine); | ||
1366 | |||
1367 | return kernel; | ||
1368 | } | ||
1369 | |||
1370 | struct process_args { | ||
1371 | u64 start; | ||
1372 | }; | ||
1373 | |||
1374 | static int symbol__in_kernel(void *arg, const char *name, | ||
1375 | char type __maybe_unused, u64 start) | ||
1376 | { | ||
1377 | struct process_args *args = arg; | ||
1378 | |||
1379 | if (strchr(name, '[')) | ||
1380 | return 0; | ||
1381 | |||
1382 | args->start = start; | ||
1383 | return 1; | ||
1384 | } | ||
1385 | |||
1386 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
1387 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
1388 | { | ||
1389 | const char *filename; | ||
1390 | char path[PATH_MAX]; | ||
1391 | struct process_args args; | ||
1392 | |||
1393 | if (machine__is_host(machine)) { | ||
1394 | filename = "/proc/kallsyms"; | ||
1395 | } else { | ||
1396 | if (machine__is_default_guest(machine)) | ||
1397 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
1398 | else { | ||
1399 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
1400 | filename = path; | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
1405 | return 0; | ||
1406 | |||
1407 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
1408 | return 0; | ||
1409 | |||
1410 | return args.start; | ||
1411 | } | ||
1412 | |||
1413 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | ||
1414 | { | ||
1415 | enum map_type type; | ||
1416 | u64 start = machine__get_kernel_start_addr(machine); | ||
1417 | |||
1418 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
1419 | struct kmap *kmap; | ||
1420 | |||
1421 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); | ||
1422 | if (machine->vmlinux_maps[type] == NULL) | ||
1423 | return -1; | ||
1424 | |||
1425 | machine->vmlinux_maps[type]->map_ip = | ||
1426 | machine->vmlinux_maps[type]->unmap_ip = | ||
1427 | identity__map_ip; | ||
1428 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
1429 | kmap->kmaps = &machine->kmaps; | ||
1430 | map_groups__insert(&machine->kmaps, | ||
1431 | machine->vmlinux_maps[type]); | ||
1432 | } | ||
1433 | |||
1434 | return 0; | ||
1435 | } | ||
1436 | |||
1437 | void machine__destroy_kernel_maps(struct machine *machine) | ||
1438 | { | ||
1439 | enum map_type type; | ||
1440 | |||
1441 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
1442 | struct kmap *kmap; | ||
1443 | |||
1444 | if (machine->vmlinux_maps[type] == NULL) | ||
1445 | continue; | ||
1446 | |||
1447 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
1448 | map_groups__remove(&machine->kmaps, | ||
1449 | machine->vmlinux_maps[type]); | ||
1450 | if (kmap->ref_reloc_sym) { | ||
1451 | /* | ||
1452 | * ref_reloc_sym is shared among all maps, so free just | ||
1453 | * on one of them. | ||
1454 | */ | ||
1455 | if (type == MAP__FUNCTION) { | ||
1456 | free((char *)kmap->ref_reloc_sym->name); | ||
1457 | kmap->ref_reloc_sym->name = NULL; | ||
1458 | free(kmap->ref_reloc_sym); | ||
1459 | } | ||
1460 | kmap->ref_reloc_sym = NULL; | ||
1461 | } | ||
1462 | |||
1463 | map__delete(machine->vmlinux_maps[type]); | ||
1464 | machine->vmlinux_maps[type] = NULL; | ||
1465 | } | ||
1466 | } | ||
1467 | |||
1468 | int machine__create_kernel_maps(struct machine *machine) | ||
1469 | { | ||
1470 | struct dso *kernel = machine__get_kernel(machine); | ||
1471 | |||
1472 | if (kernel == NULL || | ||
1473 | __machine__create_kernel_maps(machine, kernel) < 0) | ||
1474 | return -1; | ||
1475 | |||
1476 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { | ||
1477 | if (machine__is_host(machine)) | ||
1478 | pr_debug("Problems creating module maps, " | ||
1479 | "continuing anyway...\n"); | ||
1480 | else | ||
1481 | pr_debug("Problems creating module maps for guest %d, " | ||
1482 | "continuing anyway...\n", machine->pid); | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * Now that we have all the maps created, just set the ->end of them: | ||
1487 | */ | ||
1488 | map_groups__fixup_end(&machine->kmaps); | ||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | static void vmlinux_path__exit(void) | 1102 | static void vmlinux_path__exit(void) |
1493 | { | 1103 | { |
1494 | while (--vmlinux_path__nr_entries >= 0) { | 1104 | while (--vmlinux_path__nr_entries >= 0) { |
@@ -1549,25 +1159,6 @@ out_fail: | |||
1549 | return -1; | 1159 | return -1; |
1550 | } | 1160 | } |
1551 | 1161 | ||
1552 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | ||
1553 | { | ||
1554 | int i; | ||
1555 | size_t printed = 0; | ||
1556 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; | ||
1557 | |||
1558 | if (kdso->has_build_id) { | ||
1559 | char filename[PATH_MAX]; | ||
1560 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) | ||
1561 | printed += fprintf(fp, "[0] %s\n", filename); | ||
1562 | } | ||
1563 | |||
1564 | for (i = 0; i < vmlinux_path__nr_entries; ++i) | ||
1565 | printed += fprintf(fp, "[%d] %s\n", | ||
1566 | i + kdso->has_build_id, vmlinux_path[i]); | ||
1567 | |||
1568 | return printed; | ||
1569 | } | ||
1570 | |||
1571 | static int setup_list(struct strlist **list, const char *list_str, | 1162 | static int setup_list(struct strlist **list, const char *list_str, |
1572 | const char *list_name) | 1163 | const char *list_name) |
1573 | { | 1164 | { |
@@ -1671,108 +1262,3 @@ void symbol__exit(void) | |||
1671 | symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; | 1262 | symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; |
1672 | symbol_conf.initialized = false; | 1263 | symbol_conf.initialized = false; |
1673 | } | 1264 | } |
1674 | |||
1675 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | ||
1676 | { | ||
1677 | struct machine *machine = machines__findnew(machines, pid); | ||
1678 | |||
1679 | if (machine == NULL) | ||
1680 | return -1; | ||
1681 | |||
1682 | return machine__create_kernel_maps(machine); | ||
1683 | } | ||
1684 | |||
1685 | int machines__create_guest_kernel_maps(struct rb_root *machines) | ||
1686 | { | ||
1687 | int ret = 0; | ||
1688 | struct dirent **namelist = NULL; | ||
1689 | int i, items = 0; | ||
1690 | char path[PATH_MAX]; | ||
1691 | pid_t pid; | ||
1692 | char *endp; | ||
1693 | |||
1694 | if (symbol_conf.default_guest_vmlinux_name || | ||
1695 | symbol_conf.default_guest_modules || | ||
1696 | symbol_conf.default_guest_kallsyms) { | ||
1697 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); | ||
1698 | } | ||
1699 | |||
1700 | if (symbol_conf.guestmount) { | ||
1701 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | ||
1702 | if (items <= 0) | ||
1703 | return -ENOENT; | ||
1704 | for (i = 0; i < items; i++) { | ||
1705 | if (!isdigit(namelist[i]->d_name[0])) { | ||
1706 | /* Filter out . and .. */ | ||
1707 | continue; | ||
1708 | } | ||
1709 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); | ||
1710 | if ((*endp != '\0') || | ||
1711 | (endp == namelist[i]->d_name) || | ||
1712 | (errno == ERANGE)) { | ||
1713 | pr_debug("invalid directory (%s). Skipping.\n", | ||
1714 | namelist[i]->d_name); | ||
1715 | continue; | ||
1716 | } | ||
1717 | sprintf(path, "%s/%s/proc/kallsyms", | ||
1718 | symbol_conf.guestmount, | ||
1719 | namelist[i]->d_name); | ||
1720 | ret = access(path, R_OK); | ||
1721 | if (ret) { | ||
1722 | pr_debug("Can't access file %s\n", path); | ||
1723 | goto failure; | ||
1724 | } | ||
1725 | machines__create_kernel_maps(machines, pid); | ||
1726 | } | ||
1727 | failure: | ||
1728 | free(namelist); | ||
1729 | } | ||
1730 | |||
1731 | return ret; | ||
1732 | } | ||
1733 | |||
1734 | void machines__destroy_guest_kernel_maps(struct rb_root *machines) | ||
1735 | { | ||
1736 | struct rb_node *next = rb_first(machines); | ||
1737 | |||
1738 | while (next) { | ||
1739 | struct machine *pos = rb_entry(next, struct machine, rb_node); | ||
1740 | |||
1741 | next = rb_next(&pos->rb_node); | ||
1742 | rb_erase(&pos->rb_node, machines); | ||
1743 | machine__delete(pos); | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
1748 | enum map_type type, symbol_filter_t filter) | ||
1749 | { | ||
1750 | struct map *map = machine->vmlinux_maps[type]; | ||
1751 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | ||
1752 | |||
1753 | if (ret > 0) { | ||
1754 | dso__set_loaded(map->dso, type); | ||
1755 | /* | ||
1756 | * Since /proc/kallsyms will have multiple sessions for the | ||
1757 | * kernel, with modules between them, fixup the end of all | ||
1758 | * sections. | ||
1759 | */ | ||
1760 | __map_groups__fixup_end(&machine->kmaps, type); | ||
1761 | } | ||
1762 | |||
1763 | return ret; | ||
1764 | } | ||
1765 | |||
1766 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
1767 | symbol_filter_t filter) | ||
1768 | { | ||
1769 | struct map *map = machine->vmlinux_maps[type]; | ||
1770 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | ||
1771 | |||
1772 | if (ret > 0) { | ||
1773 | dso__set_loaded(map->dso, type); | ||
1774 | map__reloc_vmlinux(map); | ||
1775 | } | ||
1776 | |||
1777 | return ret; | ||
1778 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index de68f98b236d..ec7b2405c377 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -120,6 +120,8 @@ struct symbol_conf { | |||
120 | }; | 120 | }; |
121 | 121 | ||
122 | extern struct symbol_conf symbol_conf; | 122 | extern struct symbol_conf symbol_conf; |
123 | extern int vmlinux_path__nr_entries; | ||
124 | extern char **vmlinux_path; | ||
123 | 125 | ||
124 | static inline void *symbol__priv(struct symbol *sym) | 126 | static inline void *symbol__priv(struct symbol *sym) |
125 | { | 127 | { |
@@ -223,6 +225,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym, | |||
223 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 225 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
224 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | 226 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); |
225 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 227 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
228 | bool symbol__restricted_filename(const char *filename, | ||
229 | const char *restricted_filename); | ||
226 | 230 | ||
227 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 231 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
228 | struct symsrc *runtime_ss, symbol_filter_t filter, | 232 | struct symsrc *runtime_ss, symbol_filter_t filter, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index df59623ac763..632e40e5ceca 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self) | |||
54 | return self->comm_len; | 54 | return self->comm_len; |
55 | } | 55 | } |
56 | 56 | ||
57 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 57 | size_t thread__fprintf(struct thread *thread, FILE *fp) |
58 | { | 58 | { |
59 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + | 59 | return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + |
60 | map_groups__fprintf(&self->mg, verbose, fp); | 60 | map_groups__fprintf(&thread->mg, verbose, fp); |
61 | } | 61 | } |
62 | 62 | ||
63 | void thread__insert_map(struct thread *self, struct map *map) | 63 | void thread__insert_map(struct thread *self, struct map *map) |
@@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
84 | return -ENOMEM; | 84 | return -ENOMEM; |
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | |||
88 | size_t machine__fprintf(struct machine *machine, FILE *fp) | ||
89 | { | ||
90 | size_t ret = 0; | ||
91 | struct rb_node *nd; | ||
92 | |||
93 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | ||
94 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
95 | |||
96 | ret += thread__fprintf(pos, fp); | ||
97 | } | ||
98 | |||
99 | return ret; | ||
100 | } | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index f2fa17caa7d5..5ad266403098 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm); | |||
30 | int thread__comm_len(struct thread *self); | 30 | int thread__comm_len(struct thread *self); |
31 | void thread__insert_map(struct thread *self, struct map *map); | 31 | void thread__insert_map(struct thread *self, struct map *map); |
32 | int thread__fork(struct thread *self, struct thread *parent); | 32 | int thread__fork(struct thread *self, struct thread *parent); |
33 | size_t thread__fprintf(struct thread *thread, FILE *fp); | ||
33 | 34 | ||
34 | static inline struct map *thread__find_map(struct thread *self, | 35 | static inline struct map *thread__find_map(struct thread *self, |
35 | enum map_type type, u64 addr) | 36 | enum map_type type, u64 addr) |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 884dde9b9bc1..54d37a4753c5 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
26 | float samples_per_sec = top->samples / top->delay_secs; | 26 | float samples_per_sec = top->samples / top->delay_secs; |
27 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; | 27 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; |
28 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; | 28 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; |
29 | struct perf_record_opts *opts = &top->record_opts; | ||
30 | struct perf_target *target = &opts->target; | ||
29 | size_t ret = 0; | 31 | size_t ret = 0; |
30 | 32 | ||
31 | if (!perf_guest) { | 33 | if (!perf_guest) { |
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
61 | struct perf_evsel *first = perf_evlist__first(top->evlist); | 63 | struct perf_evsel *first = perf_evlist__first(top->evlist); |
62 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", | 64 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", |
63 | (uint64_t)first->attr.sample_period, | 65 | (uint64_t)first->attr.sample_period, |
64 | top->freq ? "Hz" : ""); | 66 | opts->freq ? "Hz" : ""); |
65 | } | 67 | } |
66 | 68 | ||
67 | ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); | 69 | ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); |
68 | 70 | ||
69 | ret += SNPRINTF(bf + ret, size - ret, "], "); | 71 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
70 | 72 | ||
71 | if (top->target.pid) | 73 | if (target->pid) |
72 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", | 74 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", |
73 | top->target.pid); | 75 | target->pid); |
74 | else if (top->target.tid) | 76 | else if (target->tid) |
75 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", | 77 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", |
76 | top->target.tid); | 78 | target->tid); |
77 | else if (top->target.uid_str != NULL) | 79 | else if (target->uid_str != NULL) |
78 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", | 80 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", |
79 | top->target.uid_str); | 81 | target->uid_str); |
80 | else | 82 | else |
81 | ret += SNPRINTF(bf + ret, size - ret, " (all"); | 83 | ret += SNPRINTF(bf + ret, size - ret, " (all"); |
82 | 84 | ||
83 | if (top->target.cpu_list) | 85 | if (target->cpu_list) |
84 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", | 86 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", |
85 | top->evlist->cpus->nr > 1 ? "s" : "", | 87 | top->evlist->cpus->nr > 1 ? "s" : "", |
86 | top->target.cpu_list); | 88 | target->cpu_list); |
87 | else { | 89 | else { |
88 | if (top->target.tid) | 90 | if (target->tid) |
89 | ret += SNPRINTF(bf + ret, size - ret, ")"); | 91 | ret += SNPRINTF(bf + ret, size - ret, ")"); |
90 | else | 92 | else |
91 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", | 93 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 86ff1b15059b..927c229c2d9a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -14,7 +14,7 @@ struct perf_session; | |||
14 | struct perf_top { | 14 | struct perf_top { |
15 | struct perf_tool tool; | 15 | struct perf_tool tool; |
16 | struct perf_evlist *evlist; | 16 | struct perf_evlist *evlist; |
17 | struct perf_target target; | 17 | struct perf_record_opts record_opts; |
18 | /* | 18 | /* |
19 | * Symbols will be added here in perf_event__process_sample and will | 19 | * Symbols will be added here in perf_event__process_sample and will |
20 | * get out after decayed. | 20 | * get out after decayed. |
@@ -24,15 +24,11 @@ struct perf_top { | |||
24 | u64 exact_samples; | 24 | u64 exact_samples; |
25 | u64 guest_us_samples, guest_kernel_samples; | 25 | u64 guest_us_samples, guest_kernel_samples; |
26 | int print_entries, count_filter, delay_secs; | 26 | int print_entries, count_filter, delay_secs; |
27 | int freq; | ||
28 | bool hide_kernel_symbols, hide_user_symbols, zero; | 27 | bool hide_kernel_symbols, hide_user_symbols, zero; |
29 | bool use_tui, use_stdio; | 28 | bool use_tui, use_stdio; |
30 | bool sort_has_symbols; | 29 | bool sort_has_symbols; |
31 | bool dont_use_callchains; | ||
32 | bool kptr_restrict_warned; | 30 | bool kptr_restrict_warned; |
33 | bool vmlinux_warned; | 31 | bool vmlinux_warned; |
34 | bool inherit; | ||
35 | bool group; | ||
36 | bool sample_id_all_missing; | 32 | bool sample_id_all_missing; |
37 | bool exclude_guest_missing; | 33 | bool exclude_guest_missing; |
38 | bool dump_symtab; | 34 | bool dump_symtab; |
@@ -40,8 +36,6 @@ struct perf_top { | |||
40 | struct perf_evsel *sym_evsel; | 36 | struct perf_evsel *sym_evsel; |
41 | struct perf_session *session; | 37 | struct perf_session *session; |
42 | struct winsize winsize; | 38 | struct winsize winsize; |
43 | unsigned int mmap_pages; | ||
44 | int default_interval; | ||
45 | int realtime_prio; | 39 | int realtime_prio; |
46 | int sym_pcnt_filter; | 40 | int sym_pcnt_filter; |
47 | const char *sym_filter; | 41 | const char *sym_filter; |