diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-09-29 03:43:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-09-29 03:43:46 -0400 |
commit | 9c17dbc6eb73bdd8a6aaea1baefd37ff78d86148 (patch) | |
tree | 5b303f98bc8898f26d2445138904f2fb14403a2d | |
parent | 18ab2cd3ee9d52dc64c5ae984146a261a328c4e8 (diff) | |
parent | e637d17757a10732fa5d573c18f20b3cd4d31245 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
- Accept a zero --itrace period, meaning "as often as possible". In the case
of Intel PT that is the same as a period of 1 and a unit of 'instructions'
(i.e. --itrace=i1i). (Adrian Hunter)
- Harmonize itrace's synthesized callchains with the existing --max-stack
tool option. (Adrian Hunter)
- Allow time to be displayed in nanoseconds in 'perf script'. (Adrian Hunter)
- Fix potential infinite loop when handling Intel PT timestamps. (Adrian Hunter)
- Slighly improve Intel PT debug logging. (Adrian Hunter)
- Warn when AUX data has been lost, just like when processing PERF_RECORD_LOST.
(Adrian Hunter)
- Further document export-to-postgresql.py script. (Adrian Hunter)
- Add option to synthesize branch stack from auxtrace data. (Adrian Hunter)
- Use equivalent logic to avoid using dso->kernel. (Arnaldo Carvalho de Melo)
- Show proper error messages when parsing bad terms for hw/sw events. (He Kuang)
- Tracepoint event parsing improvements. (He Kuang)
- Store tracing mountpoint for better error message. (Jiri Olsa)
- Add fixdep to tools/build, bringing it closer to the kernel counterpart, from
where it is being lifted. (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
47 files changed, 1240 insertions, 167 deletions
diff --git a/tools/build/Build b/tools/build/Build new file mode 100644 index 000000000000..63a6c34c0c88 --- /dev/null +++ b/tools/build/Build | |||
@@ -0,0 +1 @@ | |||
fixdep-y := fixdep.o | |||
diff --git a/tools/build/Build.include b/tools/build/Build.include index 4c8daaccb82a..4d000bc959b4 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include | |||
@@ -55,14 +55,25 @@ make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) | |||
55 | any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) | 55 | any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) |
56 | 56 | ||
57 | ### | 57 | ### |
58 | # Copy dependency data into .cmd file | ||
59 | # - gcc -M dependency info | ||
60 | # - command line to create object 'cmd_object :=' | ||
61 | dep-cmd = $(if $(wildcard $(fixdep)), \ | ||
62 | $(fixdep) $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \ | ||
63 | rm -f $(depfile); \ | ||
64 | mv -f $(dot-target).tmp $(dot-target).cmd, \ | ||
65 | printf '\# cannot find fixdep (%s)\n' $(fixdep) > $(dot-target).cmd; \ | ||
66 | printf '\# using basic dep data\n\n' >> $(dot-target).cmd; \ | ||
67 | cat $(depfile) >> $(dot-target).cmd; \ | ||
68 | printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd) | ||
69 | |||
70 | ### | ||
58 | # if_changed_dep - execute command if any prerequisite is newer than | 71 | # if_changed_dep - execute command if any prerequisite is newer than |
59 | # target, or command line has changed and update | 72 | # target, or command line has changed and update |
60 | # dependencies in the cmd file | 73 | # dependencies in the cmd file |
61 | if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ | 74 | if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ |
62 | @set -e; \ | 75 | @set -e; \ |
63 | $(echo-cmd) $(cmd_$(1)); \ | 76 | $(echo-cmd) $(cmd_$(1)) && $(dep-cmd)) |
64 | cat $(depfile) > $(dot-target).cmd; \ | ||
65 | printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd) | ||
66 | 77 | ||
67 | # if_changed - execute command if any prerequisite is newer than | 78 | # if_changed - execute command if any prerequisite is newer than |
68 | # target, or command line has changed | 79 | # target, or command line has changed |
diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt index aa5e092c4352..a47bffbae159 100644 --- a/tools/build/Documentation/Build.txt +++ b/tools/build/Documentation/Build.txt | |||
@@ -11,8 +11,9 @@ Unlike the kernel we don't have a single build object 'obj-y' list that where | |||
11 | we setup source objects, but we support more. This allows one 'Build' file to | 11 | we setup source objects, but we support more. This allows one 'Build' file to |
12 | carry a sources list for multiple build objects. | 12 | carry a sources list for multiple build objects. |
13 | 13 | ||
14 | a) Build framework makefiles | 14 | |
15 | ---------------------------- | 15 | Build framework makefiles |
16 | ------------------------- | ||
16 | 17 | ||
17 | The build framework consists of 2 Makefiles: | 18 | The build framework consists of 2 Makefiles: |
18 | 19 | ||
@@ -23,7 +24,7 @@ While the 'Build.include' file contains just some generic definitions, the | |||
23 | 'Makefile.build' file is the makefile used from the outside. It's | 24 | 'Makefile.build' file is the makefile used from the outside. It's |
24 | interface/usage is following: | 25 | interface/usage is following: |
25 | 26 | ||
26 | $ make -f tools/build/Makefile srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT) | 27 | $ make -f tools/build/Makefile.build srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT) |
27 | 28 | ||
28 | where: | 29 | where: |
29 | 30 | ||
@@ -38,8 +39,9 @@ called $(OBJECT)-in.o: | |||
38 | 39 | ||
39 | which includes all compiled sources described in 'Build' makefiles. | 40 | which includes all compiled sources described in 'Build' makefiles. |
40 | 41 | ||
41 | a) Build makefiles | 42 | |
42 | ------------------ | 43 | Build makefiles |
44 | --------------- | ||
43 | 45 | ||
44 | The user supplies 'Build' makefiles that contains a objects list, and connects | 46 | The user supplies 'Build' makefiles that contains a objects list, and connects |
45 | the build to nested directories. | 47 | the build to nested directories. |
@@ -95,8 +97,31 @@ It's only a matter of 2 single commands to create the final binaries: | |||
95 | 97 | ||
96 | You can check the 'ex' example in 'tools/build/tests/ex' for more details. | 98 | You can check the 'ex' example in 'tools/build/tests/ex' for more details. |
97 | 99 | ||
98 | b) Rules | 100 | |
99 | -------- | 101 | Makefile.include |
102 | ---------------- | ||
103 | |||
104 | The tools/build/Makefile.include makefile could be included | ||
105 | via user makefiles to get usefull definitions. | ||
106 | |||
107 | It defines following interface: | ||
108 | |||
109 | - build macro definition: | ||
110 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
111 | |||
112 | to make it easier to invoke build like: | ||
113 | make $(build)=ex | ||
114 | |||
115 | |||
116 | Fixdep | ||
117 | ------ | ||
118 | It is necessary to build the fixdep helper before invoking the build. | ||
119 | The Makefile.include file adds the fixdep target, that could be | ||
120 | invoked by the user. | ||
121 | |||
122 | |||
123 | Rules | ||
124 | ----- | ||
100 | 125 | ||
101 | The build framework provides standard compilation rules to handle .S and .c | 126 | The build framework provides standard compilation rules to handle .S and .c |
102 | compilation. | 127 | compilation. |
@@ -104,8 +129,9 @@ compilation. | |||
104 | It's possible to include special rule if needed (like we do for flex or bison | 129 | It's possible to include special rule if needed (like we do for flex or bison |
105 | code generation). | 130 | code generation). |
106 | 131 | ||
107 | c) CFLAGS | 132 | |
108 | --------- | 133 | CFLAGS |
134 | ------ | ||
109 | 135 | ||
110 | It's possible to alter the standard object C flags in the following way: | 136 | It's possible to alter the standard object C flags in the following way: |
111 | 137 | ||
@@ -115,8 +141,8 @@ It's possible to alter the standard object C flags in the following way: | |||
115 | This C flags changes has the scope of the Build makefile they are defined in. | 141 | This C flags changes has the scope of the Build makefile they are defined in. |
116 | 142 | ||
117 | 143 | ||
118 | d) Dependencies | 144 | Dependencies |
119 | --------------- | 145 | ------------ |
120 | 146 | ||
121 | For each built object file 'a.o' the '.a.cmd' is created and holds: | 147 | For each built object file 'a.o' the '.a.cmd' is created and holds: |
122 | 148 | ||
@@ -130,8 +156,8 @@ All existing '.cmd' files are included in the Build process to follow properly | |||
130 | the dependencies and trigger a rebuild when necessary. | 156 | the dependencies and trigger a rebuild when necessary. |
131 | 157 | ||
132 | 158 | ||
133 | e) Single rules | 159 | Single rules |
134 | --------------- | 160 | ------------ |
135 | 161 | ||
136 | It's possible to build single object file by choice, like: | 162 | It's possible to build single object file by choice, like: |
137 | 163 | ||
diff --git a/tools/build/Makefile b/tools/build/Makefile new file mode 100644 index 000000000000..a93036272d43 --- /dev/null +++ b/tools/build/Makefile | |||
@@ -0,0 +1,43 @@ | |||
1 | ifeq ($(srctree),) | ||
2 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
3 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
4 | endif | ||
5 | |||
6 | include $(srctree)/tools//scripts/Makefile.include | ||
7 | |||
8 | define allow-override | ||
9 | $(if $(or $(findstring environment,$(origin $(1))),\ | ||
10 | $(findstring command line,$(origin $(1)))),,\ | ||
11 | $(eval $(1) = $(2))) | ||
12 | endef | ||
13 | |||
14 | $(call allow-override,CC,$(CROSS_COMPILE)gcc) | ||
15 | $(call allow-override,LD,$(CROSS_COMPILE)ld) | ||
16 | |||
17 | ifeq ($(V),1) | ||
18 | Q = | ||
19 | else | ||
20 | Q = @ | ||
21 | endif | ||
22 | |||
23 | export Q srctree CC LD | ||
24 | |||
25 | MAKEFLAGS := --no-print-directory | ||
26 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
27 | |||
28 | all: fixdep | ||
29 | |||
30 | clean: | ||
31 | $(call QUIET_CLEAN, fixdep) | ||
32 | $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | ||
33 | $(Q)rm -f fixdep | ||
34 | |||
35 | $(OUTPUT)fixdep-in.o: FORCE | ||
36 | $(Q)$(MAKE) $(build)=fixdep | ||
37 | |||
38 | $(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o | ||
39 | $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $< | ||
40 | |||
41 | FORCE: | ||
42 | |||
43 | .PHONY: FORCE | ||
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index 0c5f485521d6..4a96473b180f 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build | |||
@@ -21,6 +21,13 @@ endif | |||
21 | 21 | ||
22 | build-dir := $(srctree)/tools/build | 22 | build-dir := $(srctree)/tools/build |
23 | 23 | ||
24 | # Define $(fixdep) for dep-cmd function | ||
25 | ifeq ($(OUTPUT),) | ||
26 | fixdep := $(build-dir)/fixdep | ||
27 | else | ||
28 | fixdep := $(OUTPUT)/fixdep | ||
29 | endif | ||
30 | |||
24 | # Generic definitions | 31 | # Generic definitions |
25 | include $(build-dir)/Build.include | 32 | include $(build-dir)/Build.include |
26 | 33 | ||
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include new file mode 100644 index 000000000000..6572bb023543 --- /dev/null +++ b/tools/build/Makefile.include | |||
@@ -0,0 +1,6 @@ | |||
1 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
2 | |||
3 | fixdep: | ||
4 | $(Q)$(MAKE) -C $(srctree)/tools/build fixdep | ||
5 | |||
6 | .PHONY: fixdep | ||
diff --git a/tools/build/fixdep.c b/tools/build/fixdep.c new file mode 100644 index 000000000000..1521d36cef0d --- /dev/null +++ b/tools/build/fixdep.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * "Optimize" a list of dependencies as spit out by gcc -MD | ||
3 | * for the build framework. | ||
4 | * | ||
5 | * Original author: | ||
6 | * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de> | ||
7 | * | ||
8 | * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c), | ||
9 | * Please check it for detailed explanation. This fixdep borow only the | ||
10 | * base transformation of dependecies without the CONFIG mangle. | ||
11 | */ | ||
12 | |||
13 | #include <sys/types.h> | ||
14 | #include <sys/stat.h> | ||
15 | #include <sys/mman.h> | ||
16 | #include <unistd.h> | ||
17 | #include <fcntl.h> | ||
18 | #include <string.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <stdio.h> | ||
21 | #include <limits.h> | ||
22 | |||
23 | char *target; | ||
24 | char *depfile; | ||
25 | char *cmdline; | ||
26 | |||
27 | static void usage(void) | ||
28 | { | ||
29 | fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n"); | ||
30 | exit(1); | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Print out the commandline prefixed with cmd_<target filename> := | ||
35 | */ | ||
36 | static void print_cmdline(void) | ||
37 | { | ||
38 | printf("cmd_%s := %s\n\n", target, cmdline); | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * Important: The below generated source_foo.o and deps_foo.o variable | ||
43 | * assignments are parsed not only by make, but also by the rather simple | ||
44 | * parser in scripts/mod/sumversion.c. | ||
45 | */ | ||
46 | static void parse_dep_file(void *map, size_t len) | ||
47 | { | ||
48 | char *m = map; | ||
49 | char *end = m + len; | ||
50 | char *p; | ||
51 | char s[PATH_MAX]; | ||
52 | int is_target; | ||
53 | int saw_any_target = 0; | ||
54 | int is_first_dep = 0; | ||
55 | |||
56 | while (m < end) { | ||
57 | /* Skip any "white space" */ | ||
58 | while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) | ||
59 | m++; | ||
60 | /* Find next "white space" */ | ||
61 | p = m; | ||
62 | while (p < end && *p != ' ' && *p != '\\' && *p != '\n') | ||
63 | p++; | ||
64 | /* Is the token we found a target name? */ | ||
65 | is_target = (*(p-1) == ':'); | ||
66 | /* Don't write any target names into the dependency file */ | ||
67 | if (is_target) { | ||
68 | /* The /next/ file is the first dependency */ | ||
69 | is_first_dep = 1; | ||
70 | } else { | ||
71 | /* Save this token/filename */ | ||
72 | memcpy(s, m, p-m); | ||
73 | s[p - m] = 0; | ||
74 | |||
75 | /* | ||
76 | * Do not list the source file as dependency, | ||
77 | * so that kbuild is not confused if a .c file | ||
78 | * is rewritten into .S or vice versa. Storing | ||
79 | * it in source_* is needed for modpost to | ||
80 | * compute srcversions. | ||
81 | */ | ||
82 | if (is_first_dep) { | ||
83 | /* | ||
84 | * If processing the concatenation of | ||
85 | * multiple dependency files, only | ||
86 | * process the first target name, which | ||
87 | * will be the original source name, | ||
88 | * and ignore any other target names, | ||
89 | * which will be intermediate temporary | ||
90 | * files. | ||
91 | */ | ||
92 | if (!saw_any_target) { | ||
93 | saw_any_target = 1; | ||
94 | printf("source_%s := %s\n\n", | ||
95 | target, s); | ||
96 | printf("deps_%s := \\\n", | ||
97 | target); | ||
98 | } | ||
99 | is_first_dep = 0; | ||
100 | } else | ||
101 | printf(" %s \\\n", s); | ||
102 | } | ||
103 | /* | ||
104 | * Start searching for next token immediately after the first | ||
105 | * "whitespace" character that follows this token. | ||
106 | */ | ||
107 | m = p + 1; | ||
108 | } | ||
109 | |||
110 | if (!saw_any_target) { | ||
111 | fprintf(stderr, "fixdep: parse error; no targets found\n"); | ||
112 | exit(1); | ||
113 | } | ||
114 | |||
115 | printf("\n%s: $(deps_%s)\n\n", target, target); | ||
116 | printf("$(deps_%s):\n", target); | ||
117 | } | ||
118 | |||
119 | static void print_deps(void) | ||
120 | { | ||
121 | struct stat st; | ||
122 | int fd; | ||
123 | void *map; | ||
124 | |||
125 | fd = open(depfile, O_RDONLY); | ||
126 | if (fd < 0) { | ||
127 | fprintf(stderr, "fixdep: error opening depfile: "); | ||
128 | perror(depfile); | ||
129 | exit(2); | ||
130 | } | ||
131 | if (fstat(fd, &st) < 0) { | ||
132 | fprintf(stderr, "fixdep: error fstat'ing depfile: "); | ||
133 | perror(depfile); | ||
134 | exit(2); | ||
135 | } | ||
136 | if (st.st_size == 0) { | ||
137 | fprintf(stderr, "fixdep: %s is empty\n", depfile); | ||
138 | close(fd); | ||
139 | return; | ||
140 | } | ||
141 | map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
142 | if ((long) map == -1) { | ||
143 | perror("fixdep: mmap"); | ||
144 | close(fd); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | parse_dep_file(map, st.st_size); | ||
149 | |||
150 | munmap(map, st.st_size); | ||
151 | |||
152 | close(fd); | ||
153 | } | ||
154 | |||
155 | int main(int argc, char **argv) | ||
156 | { | ||
157 | if (argc != 4) | ||
158 | usage(); | ||
159 | |||
160 | depfile = argv[1]; | ||
161 | target = argv[2]; | ||
162 | cmdline = argv[3]; | ||
163 | |||
164 | print_cmdline(); | ||
165 | print_deps(); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
diff --git a/tools/build/tests/ex/Build b/tools/build/tests/ex/Build index 429c7d452101..4d502f9b1a50 100644 --- a/tools/build/tests/ex/Build +++ b/tools/build/tests/ex/Build | |||
@@ -4,6 +4,7 @@ ex-y += b.o | |||
4 | ex-y += b.o | 4 | ex-y += b.o |
5 | ex-y += empty/ | 5 | ex-y += empty/ |
6 | ex-y += empty2/ | 6 | ex-y += empty2/ |
7 | ex-y += inc.o | ||
7 | 8 | ||
8 | libex-y += c.o | 9 | libex-y += c.o |
9 | libex-y += d.o | 10 | libex-y += d.o |
diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile index 52d2476073a3..c50d5782ad5a 100644 --- a/tools/build/tests/ex/Makefile +++ b/tools/build/tests/ex/Makefile | |||
@@ -1,19 +1,22 @@ | |||
1 | export srctree := ../../../.. | 1 | export srctree := $(abspath ../../../..) |
2 | export CC := gcc | 2 | export CC := gcc |
3 | export LD := ld | 3 | export LD := ld |
4 | export AR := ar | 4 | export AR := ar |
5 | 5 | ||
6 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | 6 | ex: |
7 | |||
8 | include $(srctree)/tools/build/Makefile.include | ||
9 | |||
7 | ex: ex-in.o libex-in.o | 10 | ex: ex-in.o libex-in.o |
8 | gcc -o $@ $^ | 11 | gcc -o $@ $^ |
9 | 12 | ||
10 | ex.%: FORCE | 13 | ex.%: fixdep FORCE |
11 | make -f $(srctree)/tools/build/Makefile.build dir=. $@ | 14 | make -f $(srctree)/tools/build/Makefile.build dir=. $@ |
12 | 15 | ||
13 | ex-in.o: FORCE | 16 | ex-in.o: fixdep FORCE |
14 | make $(build)=ex | 17 | make $(build)=ex |
15 | 18 | ||
16 | libex-in.o: FORCE | 19 | libex-in.o: fixdep FORCE |
17 | make $(build)=libex | 20 | make $(build)=libex |
18 | 21 | ||
19 | clean: | 22 | clean: |
diff --git a/tools/build/tests/ex/ex.c b/tools/build/tests/ex/ex.c index dc42eb2e1a67..57de6074d252 100644 --- a/tools/build/tests/ex/ex.c +++ b/tools/build/tests/ex/ex.c | |||
@@ -5,6 +5,7 @@ int c(void); | |||
5 | int d(void); | 5 | int d(void); |
6 | int e(void); | 6 | int e(void); |
7 | int f(void); | 7 | int f(void); |
8 | int inc(void); | ||
8 | 9 | ||
9 | int main(void) | 10 | int main(void) |
10 | { | 11 | { |
@@ -14,6 +15,7 @@ int main(void) | |||
14 | d(); | 15 | d(); |
15 | e(); | 16 | e(); |
16 | f(); | 17 | f(); |
18 | inc(); | ||
17 | 19 | ||
18 | return 0; | 20 | return 0; |
19 | } | 21 | } |
diff --git a/tools/build/tests/ex/inc.c b/tools/build/tests/ex/inc.c new file mode 100644 index 000000000000..c20f1e9033a3 --- /dev/null +++ b/tools/build/tests/ex/inc.c | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifdef INCLUDE | ||
2 | #include "krava.h" | ||
3 | #endif | ||
4 | |||
5 | int inc(void) | ||
6 | { | ||
7 | return 0; | ||
8 | } | ||
diff --git a/tools/build/tests/run.sh b/tools/build/tests/run.sh index 5494f8ea7567..44d2a0fade67 100755 --- a/tools/build/tests/run.sh +++ b/tools/build/tests/run.sh | |||
@@ -34,9 +34,36 @@ function test_ex_suffix { | |||
34 | make -C ex V=1 clean > /dev/null 2>&1 | 34 | make -C ex V=1 clean > /dev/null 2>&1 |
35 | rm -f ex.out | 35 | rm -f ex.out |
36 | } | 36 | } |
37 | |||
38 | function test_ex_include { | ||
39 | make -C ex V=1 clean > ex.out 2>&1 | ||
40 | |||
41 | # build with krava.h include | ||
42 | touch ex/krava.h | ||
43 | make -C ex V=1 CFLAGS=-DINCLUDE >> ex.out 2>&1 | ||
44 | |||
45 | if [ ! -x ./ex/ex ]; then | ||
46 | echo FAILED | ||
47 | exit -1 | ||
48 | fi | ||
49 | |||
50 | # build without the include | ||
51 | rm -f ex/krava.h ex/ex | ||
52 | make -C ex V=1 >> ex.out 2>&1 | ||
53 | |||
54 | if [ ! -x ./ex/ex ]; then | ||
55 | echo FAILED | ||
56 | exit -1 | ||
57 | fi | ||
58 | |||
59 | make -C ex V=1 clean > /dev/null 2>&1 | ||
60 | rm -f ex.out | ||
61 | } | ||
62 | |||
37 | echo -n Testing.. | 63 | echo -n Testing.. |
38 | 64 | ||
39 | test_ex | 65 | test_ex |
40 | test_ex_suffix | 66 | test_ex_suffix |
67 | test_ex_include | ||
41 | 68 | ||
42 | echo OK | 69 | echo OK |
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index fe1b02c2c95b..d85904dc9b38 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile | |||
@@ -21,12 +21,14 @@ CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | |||
21 | 21 | ||
22 | RM = rm -f | 22 | RM = rm -f |
23 | 23 | ||
24 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
25 | API_IN := $(OUTPUT)libapi-in.o | 24 | API_IN := $(OUTPUT)libapi-in.o |
26 | 25 | ||
26 | all: | ||
27 | |||
27 | export srctree OUTPUT CC LD CFLAGS V | 28 | export srctree OUTPUT CC LD CFLAGS V |
29 | include $(srctree)/tools/build/Makefile.include | ||
28 | 30 | ||
29 | all: $(LIBFILE) | 31 | all: fixdep $(LIBFILE) |
30 | 32 | ||
31 | $(API_IN): FORCE | 33 | $(API_IN): FORCE |
32 | @$(MAKE) $(build)=libapi | 34 | @$(MAKE) $(build)=libapi |
diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 38aca2dd1946..0406a7d5c891 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c | |||
@@ -12,12 +12,14 @@ | |||
12 | #include "tracing_path.h" | 12 | #include "tracing_path.h" |
13 | 13 | ||
14 | 14 | ||
15 | char tracing_mnt[PATH_MAX + 1] = "/sys/kernel/debug"; | ||
15 | char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; | 16 | char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; |
16 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; | 17 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; |
17 | 18 | ||
18 | 19 | ||
19 | static void __tracing_path_set(const char *tracing, const char *mountpoint) | 20 | static void __tracing_path_set(const char *tracing, const char *mountpoint) |
20 | { | 21 | { |
22 | snprintf(tracing_mnt, sizeof(tracing_mnt), "%s", mountpoint); | ||
21 | snprintf(tracing_path, sizeof(tracing_path), "%s/%s", | 23 | snprintf(tracing_path, sizeof(tracing_path), "%s/%s", |
22 | mountpoint, tracing); | 24 | mountpoint, tracing); |
23 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", | 25 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", |
@@ -109,19 +111,10 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) | |||
109 | "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); | 111 | "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); |
110 | break; | 112 | break; |
111 | case EACCES: { | 113 | case EACCES: { |
112 | const char *mountpoint = debugfs__mountpoint(); | ||
113 | |||
114 | if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { | ||
115 | const char *tracefs_mntpoint = tracefs__mountpoint(); | ||
116 | |||
117 | if (tracefs_mntpoint) | ||
118 | mountpoint = tracefs__mountpoint(); | ||
119 | } | ||
120 | |||
121 | snprintf(buf, size, | 114 | snprintf(buf, size, |
122 | "Error:\tNo permissions to read %s/%s\n" | 115 | "Error:\tNo permissions to read %s/%s\n" |
123 | "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", | 116 | "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", |
124 | tracing_events_path, filename, mountpoint); | 117 | tracing_events_path, filename, tracing_mnt); |
125 | } | 118 | } |
126 | break; | 119 | break; |
127 | default: | 120 | default: |
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index e630f9fc4fb6..fc9af57b666e 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -123,8 +123,10 @@ endif | |||
123 | # the same command line setup. | 123 | # the same command line setup. |
124 | MAKEOVERRIDES= | 124 | MAKEOVERRIDES= |
125 | 125 | ||
126 | all: | ||
127 | |||
126 | export srctree OUTPUT CC LD CFLAGS V | 128 | export srctree OUTPUT CC LD CFLAGS V |
127 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | 129 | include $(srctree)/tools/build/Makefile.include |
128 | 130 | ||
129 | BPF_IN := $(OUTPUT)libbpf-in.o | 131 | BPF_IN := $(OUTPUT)libbpf-in.o |
130 | LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) | 132 | LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) |
@@ -133,7 +135,7 @@ CMD_TARGETS = $(LIB_FILE) | |||
133 | 135 | ||
134 | TARGETS = $(CMD_TARGETS) | 136 | TARGETS = $(CMD_TARGETS) |
135 | 137 | ||
136 | all: $(VERSION_FILES) all_cmd | 138 | all: fixdep $(VERSION_FILES) all_cmd |
137 | 139 | ||
138 | all_cmd: $(CMD_TARGETS) | 140 | all_cmd: $(CMD_TARGETS) |
139 | 141 | ||
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 18ffccf00426..7e319afac78a 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile | |||
@@ -93,8 +93,10 @@ else | |||
93 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | 93 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; |
94 | endif | 94 | endif |
95 | 95 | ||
96 | all: | ||
97 | |||
96 | export srctree OUTPUT CC LD CFLAGS V | 98 | export srctree OUTPUT CC LD CFLAGS V |
97 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | 99 | include $(srctree)/tools/build/Makefile.include |
98 | 100 | ||
99 | do_compile_shared_library = \ | 101 | do_compile_shared_library = \ |
100 | ($(print_shared_lib_compile) \ | 102 | ($(print_shared_lib_compile) \ |
@@ -109,7 +111,7 @@ CMD_TARGETS = $(LIB_FILE) | |||
109 | TARGETS = $(CMD_TARGETS) | 111 | TARGETS = $(CMD_TARGETS) |
110 | 112 | ||
111 | 113 | ||
112 | all: all_cmd | 114 | all: fixdep all_cmd |
113 | 115 | ||
114 | all_cmd: $(CMD_TARGETS) | 116 | all_cmd: $(CMD_TARGETS) |
115 | 117 | ||
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index c94c9de3173e..be764f9ec769 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -671,6 +671,7 @@ The letters are: | |||
671 | e synthesize tracing error events | 671 | e synthesize tracing error events |
672 | d create a debug log | 672 | d create a debug log |
673 | g synthesize a call chain (use with i or x) | 673 | g synthesize a call chain (use with i or x) |
674 | l synthesize last branch entries (use with i or x) | ||
674 | 675 | ||
675 | "Instructions" events look like they were recorded by "perf record -e | 676 | "Instructions" events look like they were recorded by "perf record -e |
676 | instructions". | 677 | instructions". |
@@ -707,12 +708,26 @@ on the sample is *not* adjusted and reflects the last known value of TSC. | |||
707 | 708 | ||
708 | For Intel PT, the default period is 100us. | 709 | For Intel PT, the default period is 100us. |
709 | 710 | ||
711 | Setting it to a zero period means "as often as possible". | ||
712 | |||
713 | In the case of Intel PT that is the same as a period of 1 and a unit of | ||
714 | 'instructions' (i.e. --itrace=i1i). | ||
715 | |||
710 | Also the call chain size (default 16, max. 1024) for instructions or | 716 | Also the call chain size (default 16, max. 1024) for instructions or |
711 | transactions events can be specified. e.g. | 717 | transactions events can be specified. e.g. |
712 | 718 | ||
713 | --itrace=ig32 | 719 | --itrace=ig32 |
714 | --itrace=xg32 | 720 | --itrace=xg32 |
715 | 721 | ||
722 | Also the number of last branch entries (default 64, max. 1024) for instructions or | ||
723 | transactions events can be specified. e.g. | ||
724 | |||
725 | --itrace=il10 | ||
726 | --itrace=xl10 | ||
727 | |||
728 | Note that last branch entries are cleared for each sample, so there is no overlap | ||
729 | from one sample to the next. | ||
730 | |||
716 | To disable trace decoding entirely, use the option --no-itrace. | 731 | To disable trace decoding entirely, use the option --no-itrace. |
717 | 732 | ||
718 | 733 | ||
@@ -749,3 +764,32 @@ perf inject also accepts the --itrace option in which case tracing data is | |||
749 | removed and replaced with the synthesized events. e.g. | 764 | removed and replaced with the synthesized events. e.g. |
750 | 765 | ||
751 | perf inject --itrace -i perf.data -o perf.data.new | 766 | perf inject --itrace -i perf.data -o perf.data.new |
767 | |||
768 | Below is an example of using Intel PT with autofdo. It requires autofdo | ||
769 | (https://github.com/google/autofdo) and gcc version 5. The bubble | ||
770 | sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial) | ||
771 | amended to take the number of elements as a parameter. | ||
772 | |||
773 | $ gcc-5 -O3 sort.c -o sort_optimized | ||
774 | $ ./sort_optimized 30000 | ||
775 | Bubble sorting array of 30000 elements | ||
776 | 2254 ms | ||
777 | |||
778 | $ cat ~/.perfconfig | ||
779 | [intel-pt] | ||
780 | mispred-all | ||
781 | |||
782 | $ perf record -e intel_pt//u ./sort 3000 | ||
783 | Bubble sorting array of 3000 elements | ||
784 | 58 ms | ||
785 | [ perf record: Woken up 2 times to write data ] | ||
786 | [ perf record: Captured and wrote 3.939 MB perf.data ] | ||
787 | $ perf inject -i perf.data -o inj --itrace=i100usle --strip | ||
788 | $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1 | ||
789 | $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo | ||
790 | $ ./sort_autofdo 30000 | ||
791 | Bubble sorting array of 30000 elements | ||
792 | 2155 ms | ||
793 | |||
794 | Note there is currently no advantage to using Intel PT instead of LBR, but | ||
795 | that may change in the future if greater use is made of the data. | ||
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index 2ff946677e3b..65453f4c7006 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt | |||
@@ -6,6 +6,7 @@ | |||
6 | e synthesize error events | 6 | e synthesize error events |
7 | d create a debug log | 7 | d create a debug log |
8 | g synthesize a call chain (use with i or x) | 8 | g synthesize a call chain (use with i or x) |
9 | l synthesize last branch entries (use with i or x) | ||
9 | 10 | ||
10 | The default is all events i.e. the same as --itrace=ibxe | 11 | The default is all events i.e. the same as --itrace=ibxe |
11 | 12 | ||
@@ -20,3 +21,6 @@ | |||
20 | 21 | ||
21 | Also the call chain size (default 16, max. 1024) for instructions or | 22 | Also the call chain size (default 16, max. 1024) for instructions or |
22 | transactions events can be specified. | 23 | transactions events can be specified. |
24 | |||
25 | Also the number of last branch entries (default 64, max. 1024) for | ||
26 | instructions or transactions events can be specified. | ||
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt index 0c721c3e37e1..0b1cedeef895 100644 --- a/tools/perf/Documentation/perf-inject.txt +++ b/tools/perf/Documentation/perf-inject.txt | |||
@@ -50,6 +50,9 @@ OPTIONS | |||
50 | 50 | ||
51 | include::itrace.txt[] | 51 | include::itrace.txt[] |
52 | 52 | ||
53 | --strip:: | ||
54 | Use with --itrace to strip out non-synthesized events. | ||
55 | |||
53 | SEE ALSO | 56 | SEE ALSO |
54 | -------- | 57 | -------- |
55 | linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] | 58 | linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index dc3ec783b7bd..b3b42f9285df 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -249,6 +249,9 @@ include::itrace.txt[] | |||
249 | --full-source-path:: | 249 | --full-source-path:: |
250 | Show the full path for source files for srcline output. | 250 | Show the full path for source files for srcline output. |
251 | 251 | ||
252 | --ns:: | ||
253 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) | ||
254 | |||
252 | SEE ALSO | 255 | SEE ALSO |
253 | -------- | 256 | -------- |
254 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 257 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 6c5c699002cb..56517d304772 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -297,16 +297,16 @@ strip: $(PROGRAMS) $(OUTPUT)perf | |||
297 | PERF_IN := $(OUTPUT)perf-in.o | 297 | PERF_IN := $(OUTPUT)perf-in.o |
298 | 298 | ||
299 | export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK | 299 | export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK |
300 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | 300 | include $(srctree)/tools/build/Makefile.include |
301 | 301 | ||
302 | $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE | 302 | $(PERF_IN): prepare FORCE |
303 | $(Q)$(MAKE) $(build)=perf | 303 | $(Q)$(MAKE) $(build)=perf |
304 | 304 | ||
305 | $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) | 305 | $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) |
306 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ | 306 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ |
307 | $(PERF_IN) $(LIBS) -o $@ | 307 | $(PERF_IN) $(LIBS) -o $@ |
308 | 308 | ||
309 | $(GTK_IN): FORCE | 309 | $(GTK_IN): fixdep FORCE |
310 | $(Q)$(MAKE) $(build)=gtk | 310 | $(Q)$(MAKE) $(build)=gtk |
311 | 311 | ||
312 | $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS) | 312 | $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS) |
@@ -349,27 +349,27 @@ endif | |||
349 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) | 349 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) |
350 | build-dir = $(if $(__build-dir),$(__build-dir),.) | 350 | build-dir = $(if $(__build-dir),$(__build-dir),.) |
351 | 351 | ||
352 | single_dep: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h | 352 | prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep |
353 | 353 | ||
354 | $(OUTPUT)%.o: %.c single_dep FORCE | 354 | $(OUTPUT)%.o: %.c prepare FORCE |
355 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 355 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
356 | 356 | ||
357 | $(OUTPUT)%.i: %.c single_dep FORCE | 357 | $(OUTPUT)%.i: %.c prepare FORCE |
358 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 358 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
359 | 359 | ||
360 | $(OUTPUT)%.s: %.c single_dep FORCE | 360 | $(OUTPUT)%.s: %.c prepare FORCE |
361 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 361 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
362 | 362 | ||
363 | $(OUTPUT)%-bison.o: %.c single_dep FORCE | 363 | $(OUTPUT)%-bison.o: %.c prepare FORCE |
364 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 364 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
365 | 365 | ||
366 | $(OUTPUT)%-flex.o: %.c single_dep FORCE | 366 | $(OUTPUT)%-flex.o: %.c prepare FORCE |
367 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 367 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
368 | 368 | ||
369 | $(OUTPUT)%.o: %.S single_dep FORCE | 369 | $(OUTPUT)%.o: %.S prepare FORCE |
370 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 370 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
371 | 371 | ||
372 | $(OUTPUT)%.i: %.S single_dep FORCE | 372 | $(OUTPUT)%.i: %.S prepare FORCE |
373 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 373 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
374 | 374 | ||
375 | $(OUTPUT)perf-%: %.o $(PERFLIBS) | 375 | $(OUTPUT)perf-%: %.o $(PERFLIBS) |
@@ -389,7 +389,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) | |||
389 | 389 | ||
390 | LIBPERF_IN := $(OUTPUT)libperf-in.o | 390 | LIBPERF_IN := $(OUTPUT)libperf-in.o |
391 | 391 | ||
392 | $(LIBPERF_IN): FORCE | 392 | $(LIBPERF_IN): fixdep FORCE |
393 | $(Q)$(MAKE) $(build)=libperf | 393 | $(Q)$(MAKE) $(build)=libperf |
394 | 394 | ||
395 | $(LIB_FILE): $(LIBPERF_IN) | 395 | $(LIB_FILE): $(LIBPERF_IN) |
@@ -397,10 +397,10 @@ $(LIB_FILE): $(LIBPERF_IN) | |||
397 | 397 | ||
398 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | 398 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) |
399 | 399 | ||
400 | $(LIBTRACEEVENT): FORCE | 400 | $(LIBTRACEEVENT): fixdep FORCE |
401 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a | 401 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a |
402 | 402 | ||
403 | libtraceevent_plugins: FORCE | 403 | libtraceevent_plugins: fixdep FORCE |
404 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins | 404 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins |
405 | 405 | ||
406 | $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins | 406 | $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins |
@@ -413,7 +413,7 @@ $(LIBTRACEEVENT)-clean: | |||
413 | install-traceevent-plugins: $(LIBTRACEEVENT) | 413 | install-traceevent-plugins: $(LIBTRACEEVENT) |
414 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins | 414 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins |
415 | 415 | ||
416 | $(LIBAPI): FORCE | 416 | $(LIBAPI): fixdep FORCE |
417 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a | 417 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a |
418 | 418 | ||
419 | $(LIBAPI)-clean: | 419 | $(LIBAPI)-clean: |
@@ -591,6 +591,6 @@ FORCE: | |||
591 | 591 | ||
592 | .PHONY: all install clean config-clean strip install-gtk | 592 | .PHONY: all install clean config-clean strip install-gtk |
593 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 593 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
594 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE single_dep | 594 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare |
595 | .PHONY: libtraceevent_plugins | 595 | .PHONY: libtraceevent_plugins |
596 | 596 | ||
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index f62c49b35be0..0a945d2e8ca5 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -28,9 +28,11 @@ struct perf_inject { | |||
28 | bool build_ids; | 28 | bool build_ids; |
29 | bool sched_stat; | 29 | bool sched_stat; |
30 | bool have_auxtrace; | 30 | bool have_auxtrace; |
31 | bool strip; | ||
31 | const char *input_name; | 32 | const char *input_name; |
32 | struct perf_data_file output; | 33 | struct perf_data_file output; |
33 | u64 bytes_written; | 34 | u64 bytes_written; |
35 | u64 aux_id; | ||
34 | struct list_head samples; | 36 | struct list_head samples; |
35 | struct itrace_synth_opts itrace_synth_opts; | 37 | struct itrace_synth_opts itrace_synth_opts; |
36 | }; | 38 | }; |
@@ -176,6 +178,27 @@ static int perf_event__repipe(struct perf_tool *tool, | |||
176 | return perf_event__repipe_synth(tool, event); | 178 | return perf_event__repipe_synth(tool, event); |
177 | } | 179 | } |
178 | 180 | ||
181 | static int perf_event__drop(struct perf_tool *tool __maybe_unused, | ||
182 | union perf_event *event __maybe_unused, | ||
183 | struct perf_sample *sample __maybe_unused, | ||
184 | struct machine *machine __maybe_unused) | ||
185 | { | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int perf_event__drop_aux(struct perf_tool *tool, | ||
190 | union perf_event *event __maybe_unused, | ||
191 | struct perf_sample *sample, | ||
192 | struct machine *machine __maybe_unused) | ||
193 | { | ||
194 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); | ||
195 | |||
196 | if (!inject->aux_id) | ||
197 | inject->aux_id = sample->id; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
179 | typedef int (*inject_handler)(struct perf_tool *tool, | 202 | typedef int (*inject_handler)(struct perf_tool *tool, |
180 | union perf_event *event, | 203 | union perf_event *event, |
181 | struct perf_sample *sample, | 204 | struct perf_sample *sample, |
@@ -466,6 +489,78 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, | |||
466 | return 0; | 489 | return 0; |
467 | } | 490 | } |
468 | 491 | ||
492 | static int drop_sample(struct perf_tool *tool __maybe_unused, | ||
493 | union perf_event *event __maybe_unused, | ||
494 | struct perf_sample *sample __maybe_unused, | ||
495 | struct perf_evsel *evsel __maybe_unused, | ||
496 | struct machine *machine __maybe_unused) | ||
497 | { | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static void strip_init(struct perf_inject *inject) | ||
502 | { | ||
503 | struct perf_evlist *evlist = inject->session->evlist; | ||
504 | struct perf_evsel *evsel; | ||
505 | |||
506 | inject->tool.context_switch = perf_event__drop; | ||
507 | |||
508 | evlist__for_each(evlist, evsel) | ||
509 | evsel->handler = drop_sample; | ||
510 | } | ||
511 | |||
512 | static bool has_tracking(struct perf_evsel *evsel) | ||
513 | { | ||
514 | return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm || | ||
515 | evsel->attr.task; | ||
516 | } | ||
517 | |||
518 | #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \ | ||
519 | PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER) | ||
520 | |||
521 | /* | ||
522 | * In order that the perf.data file is parsable, tracking events like MMAP need | ||
523 | * their selected event to exist, except if there is only 1 selected event left | ||
524 | * and it has a compatible sample type. | ||
525 | */ | ||
526 | static bool ok_to_remove(struct perf_evlist *evlist, | ||
527 | struct perf_evsel *evsel_to_remove) | ||
528 | { | ||
529 | struct perf_evsel *evsel; | ||
530 | int cnt = 0; | ||
531 | bool ok = false; | ||
532 | |||
533 | if (!has_tracking(evsel_to_remove)) | ||
534 | return true; | ||
535 | |||
536 | evlist__for_each(evlist, evsel) { | ||
537 | if (evsel->handler != drop_sample) { | ||
538 | cnt += 1; | ||
539 | if ((evsel->attr.sample_type & COMPAT_MASK) == | ||
540 | (evsel_to_remove->attr.sample_type & COMPAT_MASK)) | ||
541 | ok = true; | ||
542 | } | ||
543 | } | ||
544 | |||
545 | return ok && cnt == 1; | ||
546 | } | ||
547 | |||
548 | static void strip_fini(struct perf_inject *inject) | ||
549 | { | ||
550 | struct perf_evlist *evlist = inject->session->evlist; | ||
551 | struct perf_evsel *evsel, *tmp; | ||
552 | |||
553 | /* Remove non-synthesized evsels if possible */ | ||
554 | evlist__for_each_safe(evlist, tmp, evsel) { | ||
555 | if (evsel->handler == drop_sample && | ||
556 | ok_to_remove(evlist, evsel)) { | ||
557 | pr_debug("Deleting %s\n", perf_evsel__name(evsel)); | ||
558 | perf_evlist__remove(evlist, evsel); | ||
559 | perf_evsel__delete(evsel); | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
469 | static int __cmd_inject(struct perf_inject *inject) | 564 | static int __cmd_inject(struct perf_inject *inject) |
470 | { | 565 | { |
471 | int ret = -EINVAL; | 566 | int ret = -EINVAL; |
@@ -512,10 +607,14 @@ static int __cmd_inject(struct perf_inject *inject) | |||
512 | inject->tool.id_index = perf_event__repipe_id_index; | 607 | inject->tool.id_index = perf_event__repipe_id_index; |
513 | inject->tool.auxtrace_info = perf_event__process_auxtrace_info; | 608 | inject->tool.auxtrace_info = perf_event__process_auxtrace_info; |
514 | inject->tool.auxtrace = perf_event__process_auxtrace; | 609 | inject->tool.auxtrace = perf_event__process_auxtrace; |
610 | inject->tool.aux = perf_event__drop_aux; | ||
611 | inject->tool.itrace_start = perf_event__drop_aux, | ||
515 | inject->tool.ordered_events = true; | 612 | inject->tool.ordered_events = true; |
516 | inject->tool.ordering_requires_timestamps = true; | 613 | inject->tool.ordering_requires_timestamps = true; |
517 | /* Allow space in the header for new attributes */ | 614 | /* Allow space in the header for new attributes */ |
518 | output_data_offset = 4096; | 615 | output_data_offset = 4096; |
616 | if (inject->strip) | ||
617 | strip_init(inject); | ||
519 | } | 618 | } |
520 | 619 | ||
521 | if (!inject->itrace_synth_opts.set) | 620 | if (!inject->itrace_synth_opts.set) |
@@ -535,11 +634,28 @@ static int __cmd_inject(struct perf_inject *inject) | |||
535 | } | 634 | } |
536 | /* | 635 | /* |
537 | * The AUX areas have been removed and replaced with | 636 | * The AUX areas have been removed and replaced with |
538 | * synthesized hardware events, so clear the feature flag. | 637 | * synthesized hardware events, so clear the feature flag and |
638 | * remove the evsel. | ||
539 | */ | 639 | */ |
540 | if (inject->itrace_synth_opts.set) | 640 | if (inject->itrace_synth_opts.set) { |
641 | struct perf_evsel *evsel; | ||
642 | |||
541 | perf_header__clear_feat(&session->header, | 643 | perf_header__clear_feat(&session->header, |
542 | HEADER_AUXTRACE); | 644 | HEADER_AUXTRACE); |
645 | if (inject->itrace_synth_opts.last_branch) | ||
646 | perf_header__set_feat(&session->header, | ||
647 | HEADER_BRANCH_STACK); | ||
648 | evsel = perf_evlist__id2evsel_strict(session->evlist, | ||
649 | inject->aux_id); | ||
650 | if (evsel) { | ||
651 | pr_debug("Deleting %s\n", | ||
652 | perf_evsel__name(evsel)); | ||
653 | perf_evlist__remove(session->evlist, evsel); | ||
654 | perf_evsel__delete(evsel); | ||
655 | } | ||
656 | if (inject->strip) | ||
657 | strip_fini(inject); | ||
658 | } | ||
543 | session->header.data_offset = output_data_offset; | 659 | session->header.data_offset = output_data_offset; |
544 | session->header.data_size = inject->bytes_written; | 660 | session->header.data_size = inject->bytes_written; |
545 | perf_session__write_header(session, session->evlist, fd, true); | 661 | perf_session__write_header(session, session->evlist, fd, true); |
@@ -604,6 +720,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
604 | OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, | 720 | OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, |
605 | NULL, "opts", "Instruction Tracing options", | 721 | NULL, "opts", "Instruction Tracing options", |
606 | itrace_parse_synth_opts), | 722 | itrace_parse_synth_opts), |
723 | OPT_BOOLEAN(0, "strip", &inject.strip, | ||
724 | "strip non-synthesized events (use with --itrace)"), | ||
607 | OPT_END() | 725 | OPT_END() |
608 | }; | 726 | }; |
609 | const char * const inject_usage[] = { | 727 | const char * const inject_usage[] = { |
@@ -619,6 +737,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
619 | if (argc) | 737 | if (argc) |
620 | usage_with_options(inject_usage, options); | 738 | usage_with_options(inject_usage, options); |
621 | 739 | ||
740 | if (inject.strip && !inject.itrace_synth_opts.set) { | ||
741 | pr_err("--strip option requires --itrace option\n"); | ||
742 | return -1; | ||
743 | } | ||
744 | |||
622 | if (perf_data_file__open(&inject.output)) { | 745 | if (perf_data_file__open(&inject.output)) { |
623 | perror("failed to create output file"); | 746 | perror("failed to create output file"); |
624 | return -1; | 747 | return -1; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e4e3f1432622..37c9f5125887 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -163,14 +163,21 @@ static int process_sample_event(struct perf_tool *tool, | |||
163 | if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) | 163 | if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) |
164 | goto out_put; | 164 | goto out_put; |
165 | 165 | ||
166 | if (sort__mode == SORT_MODE__BRANCH) | 166 | if (sort__mode == SORT_MODE__BRANCH) { |
167 | /* | ||
168 | * A non-synthesized event might not have a branch stack if | ||
169 | * branch stacks have been synthesized (using itrace options). | ||
170 | */ | ||
171 | if (!sample->branch_stack) | ||
172 | goto out_put; | ||
167 | iter.ops = &hist_iter_branch; | 173 | iter.ops = &hist_iter_branch; |
168 | else if (rep->mem_mode) | 174 | } else if (rep->mem_mode) { |
169 | iter.ops = &hist_iter_mem; | 175 | iter.ops = &hist_iter_mem; |
170 | else if (symbol_conf.cumulate_callchain) | 176 | } else if (symbol_conf.cumulate_callchain) { |
171 | iter.ops = &hist_iter_cumulative; | 177 | iter.ops = &hist_iter_cumulative; |
172 | else | 178 | } else { |
173 | iter.ops = &hist_iter_normal; | 179 | iter.ops = &hist_iter_normal; |
180 | } | ||
174 | 181 | ||
175 | if (al.map != NULL) | 182 | if (al.map != NULL) |
176 | al.map->dso->hit = 1; | 183 | al.map->dso->hit = 1; |
@@ -214,6 +221,15 @@ static int report__setup_sample_type(struct report *rep) | |||
214 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); | 221 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); |
215 | bool is_pipe = perf_data_file__is_pipe(session->file); | 222 | bool is_pipe = perf_data_file__is_pipe(session->file); |
216 | 223 | ||
224 | if (session->itrace_synth_opts->callchain || | ||
225 | (!is_pipe && | ||
226 | perf_header__has_feat(&session->header, HEADER_AUXTRACE) && | ||
227 | !session->itrace_synth_opts->set)) | ||
228 | sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
229 | |||
230 | if (session->itrace_synth_opts->last_branch) | ||
231 | sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
232 | |||
217 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 233 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
218 | if (sort__has_parent) { | 234 | if (sort__has_parent) { |
219 | ui__error("Selected --sort parent, but no " | 235 | ui__error("Selected --sort parent, but no " |
@@ -793,6 +809,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
793 | if (report.inverted_callchain) | 809 | if (report.inverted_callchain) |
794 | callchain_param.order = ORDER_CALLER; | 810 | callchain_param.order = ORDER_CALLER; |
795 | 811 | ||
812 | if (itrace_synth_opts.callchain && | ||
813 | (int)itrace_synth_opts.callchain_sz > report.max_stack) | ||
814 | report.max_stack = itrace_synth_opts.callchain_sz; | ||
815 | |||
796 | if (!input_name || !strlen(input_name)) { | 816 | if (!input_name || !strlen(input_name)) { |
797 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) | 817 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) |
798 | input_name = "-"; | 818 | input_name = "-"; |
@@ -820,6 +840,9 @@ repeat: | |||
820 | has_br_stack = perf_header__has_feat(&session->header, | 840 | has_br_stack = perf_header__has_feat(&session->header, |
821 | HEADER_BRANCH_STACK); | 841 | HEADER_BRANCH_STACK); |
822 | 842 | ||
843 | if (itrace_synth_opts.last_branch) | ||
844 | has_br_stack = true; | ||
845 | |||
823 | /* | 846 | /* |
824 | * Branch mode is a tristate: | 847 | * Branch mode is a tristate: |
825 | * -1 means default, so decide based on the file having branch data. | 848 | * -1 means default, so decide based on the file having branch data. |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 284a76e04628..8ce1c6bbfa45 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -29,9 +29,12 @@ static bool no_callchain; | |||
29 | static bool latency_format; | 29 | static bool latency_format; |
30 | static bool system_wide; | 30 | static bool system_wide; |
31 | static bool print_flags; | 31 | static bool print_flags; |
32 | static bool nanosecs; | ||
32 | static const char *cpu_list; | 33 | static const char *cpu_list; |
33 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 34 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
34 | 35 | ||
36 | unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; | ||
37 | |||
35 | enum perf_output_field { | 38 | enum perf_output_field { |
36 | PERF_OUTPUT_COMM = 1U << 0, | 39 | PERF_OUTPUT_COMM = 1U << 0, |
37 | PERF_OUTPUT_TID = 1U << 1, | 40 | PERF_OUTPUT_TID = 1U << 1, |
@@ -415,7 +418,10 @@ static void print_sample_start(struct perf_sample *sample, | |||
415 | secs = nsecs / NSECS_PER_SEC; | 418 | secs = nsecs / NSECS_PER_SEC; |
416 | nsecs -= secs * NSECS_PER_SEC; | 419 | nsecs -= secs * NSECS_PER_SEC; |
417 | usecs = nsecs / NSECS_PER_USEC; | 420 | usecs = nsecs / NSECS_PER_USEC; |
418 | printf("%5lu.%06lu: ", secs, usecs); | 421 | if (nanosecs) |
422 | printf("%5lu.%09llu: ", secs, nsecs); | ||
423 | else | ||
424 | printf("%5lu.%06lu: ", secs, usecs); | ||
419 | } | 425 | } |
420 | } | 426 | } |
421 | 427 | ||
@@ -471,7 +477,7 @@ static void print_sample_bts(union perf_event *event, | |||
471 | } | 477 | } |
472 | } | 478 | } |
473 | perf_evsel__print_ip(evsel, sample, al, print_opts, | 479 | perf_evsel__print_ip(evsel, sample, al, print_opts, |
474 | PERF_MAX_STACK_DEPTH); | 480 | scripting_max_stack); |
475 | } | 481 | } |
476 | 482 | ||
477 | /* print branch_to information */ | 483 | /* print branch_to information */ |
@@ -548,7 +554,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
548 | 554 | ||
549 | perf_evsel__print_ip(evsel, sample, al, | 555 | perf_evsel__print_ip(evsel, sample, al, |
550 | output[attr->type].print_ip_opts, | 556 | output[attr->type].print_ip_opts, |
551 | PERF_MAX_STACK_DEPTH); | 557 | scripting_max_stack); |
552 | } | 558 | } |
553 | 559 | ||
554 | if (PRINT_FIELD(IREGS)) | 560 | if (PRINT_FIELD(IREGS)) |
@@ -1695,6 +1701,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1695 | OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, | 1701 | OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, |
1696 | "Show context switch events (if recorded)"), | 1702 | "Show context switch events (if recorded)"), |
1697 | OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), | 1703 | OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), |
1704 | OPT_BOOLEAN(0, "ns", &nanosecs, | ||
1705 | "Use 9 decimal places when displaying time"), | ||
1698 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", | 1706 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", |
1699 | "Instruction Tracing options", | 1707 | "Instruction Tracing options", |
1700 | itrace_parse_synth_opts), | 1708 | itrace_parse_synth_opts), |
@@ -1740,6 +1748,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1740 | } | 1748 | } |
1741 | } | 1749 | } |
1742 | 1750 | ||
1751 | if (itrace_synth_opts.callchain && | ||
1752 | itrace_synth_opts.callchain_sz > scripting_max_stack) | ||
1753 | scripting_max_stack = itrace_synth_opts.callchain_sz; | ||
1754 | |||
1743 | /* make sure PERF_EXEC_PATH is set for scripts */ | 1755 | /* make sure PERF_EXEC_PATH is set for scripts */ |
1744 | perf_set_argv_exec_path(perf_exec_path()); | 1756 | perf_set_argv_exec_path(perf_exec_path()); |
1745 | 1757 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bdaf44f24d5d..38d4d6cac823 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -655,7 +655,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
655 | { | 655 | { |
656 | const char *name = sym->name; | 656 | const char *name = sym->name; |
657 | 657 | ||
658 | if (!map->dso->kernel) | 658 | if (!__map__is_kernel(map)) |
659 | return 0; | 659 | return 0; |
660 | /* | 660 | /* |
661 | * ppc64 uses function descriptors and appends a '.' to the | 661 | * ppc64 uses function descriptors and appends a '.' to the |
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py index 84a32037a80f..1b02cdc0cab6 100644 --- a/tools/perf/scripts/python/export-to-postgresql.py +++ b/tools/perf/scripts/python/export-to-postgresql.py | |||
@@ -61,6 +61,142 @@ import datetime | |||
61 | # | 61 | # |
62 | # An example of using the database is provided by the script | 62 | # An example of using the database is provided by the script |
63 | # call-graph-from-postgresql.py. Refer to that script for details. | 63 | # call-graph-from-postgresql.py. Refer to that script for details. |
64 | # | ||
65 | # Tables: | ||
66 | # | ||
67 | # The tables largely correspond to perf tools' data structures. They are largely self-explanatory. | ||
68 | # | ||
69 | # samples | ||
70 | # | ||
71 | # 'samples' is the main table. It represents what instruction was executing at a point in time | ||
72 | # when something (a selected event) happened. The memory address is the instruction pointer or 'ip'. | ||
73 | # | ||
74 | # calls | ||
75 | # | ||
76 | # 'calls' represents function calls and is related to 'samples' by 'call_id' and 'return_id'. | ||
77 | # 'calls' is only created when the 'calls' option to this script is specified. | ||
78 | # | ||
79 | # call_paths | ||
80 | # | ||
81 | # 'call_paths' represents all the call stacks. Each 'call' has an associated record in 'call_paths'. | ||
82 | # 'calls_paths' is only created when the 'calls' option to this script is specified. | ||
83 | # | ||
84 | # branch_types | ||
85 | # | ||
86 | # 'branch_types' provides descriptions for each type of branch. | ||
87 | # | ||
88 | # comm_threads | ||
89 | # | ||
90 | # 'comm_threads' shows how 'comms' relates to 'threads'. | ||
91 | # | ||
92 | # comms | ||
93 | # | ||
94 | # 'comms' contains a record for each 'comm' - the name given to the executable that is running. | ||
95 | # | ||
96 | # dsos | ||
97 | # | ||
98 | # 'dsos' contains a record for each executable file or library. | ||
99 | # | ||
100 | # machines | ||
101 | # | ||
102 | # 'machines' can be used to distinguish virtual machines if virtualization is supported. | ||
103 | # | ||
104 | # selected_events | ||
105 | # | ||
106 | # 'selected_events' contains a record for each kind of event that has been sampled. | ||
107 | # | ||
108 | # symbols | ||
109 | # | ||
110 | # 'symbols' contains a record for each symbol. Only symbols that have samples are present. | ||
111 | # | ||
112 | # threads | ||
113 | # | ||
114 | # 'threads' contains a record for each thread. | ||
115 | # | ||
116 | # Views: | ||
117 | # | ||
118 | # Most of the tables have views for more friendly display. The views are: | ||
119 | # | ||
120 | # calls_view | ||
121 | # call_paths_view | ||
122 | # comm_threads_view | ||
123 | # dsos_view | ||
124 | # machines_view | ||
125 | # samples_view | ||
126 | # symbols_view | ||
127 | # threads_view | ||
128 | # | ||
129 | # More examples of browsing the database with psql: | ||
130 | # Note that some of the examples are not the most optimal SQL query. | ||
131 | # Note that call information is only available if the script's 'calls' option has been used. | ||
132 | # | ||
133 | # Top 10 function calls (not aggregated by symbol): | ||
134 | # | ||
135 | # SELECT * FROM calls_view ORDER BY elapsed_time DESC LIMIT 10; | ||
136 | # | ||
137 | # Top 10 function calls (aggregated by symbol): | ||
138 | # | ||
139 | # SELECT symbol_id,(SELECT name FROM symbols WHERE id = symbol_id) AS symbol, | ||
140 | # SUM(elapsed_time) AS tot_elapsed_time,SUM(branch_count) AS tot_branch_count | ||
141 | # FROM calls_view GROUP BY symbol_id ORDER BY tot_elapsed_time DESC LIMIT 10; | ||
142 | # | ||
143 | # Note that the branch count gives a rough estimation of cpu usage, so functions | ||
144 | # that took a long time but have a relatively low branch count must have spent time | ||
145 | # waiting. | ||
146 | # | ||
147 | # Find symbols by pattern matching on part of the name (e.g. names containing 'alloc'): | ||
148 | # | ||
149 | # SELECT * FROM symbols_view WHERE name LIKE '%alloc%'; | ||
150 | # | ||
151 | # Top 10 function calls for a specific symbol (e.g. whose symbol_id is 187): | ||
152 | # | ||
153 | # SELECT * FROM calls_view WHERE symbol_id = 187 ORDER BY elapsed_time DESC LIMIT 10; | ||
154 | # | ||
155 | # Show function calls made by function in the same context (i.e. same call path) (e.g. one with call_path_id 254): | ||
156 | # | ||
157 | # SELECT * FROM calls_view WHERE parent_call_path_id = 254; | ||
158 | # | ||
159 | # Show branches made during a function call (e.g. where call_id is 29357 and return_id is 29370 and tid is 29670) | ||
160 | # | ||
161 | # SELECT * FROM samples_view WHERE id >= 29357 AND id <= 29370 AND tid = 29670 AND event LIKE 'branches%'; | ||
162 | # | ||
163 | # Show transactions: | ||
164 | # | ||
165 | # SELECT * FROM samples_view WHERE event = 'transactions'; | ||
166 | # | ||
167 | # Note transaction start has 'in_tx' true whereas, transaction end has 'in_tx' false. | ||
168 | # Transaction aborts have branch_type_name 'transaction abort' | ||
169 | # | ||
170 | # Show transaction aborts: | ||
171 | # | ||
172 | # SELECT * FROM samples_view WHERE event = 'transactions' AND branch_type_name = 'transaction abort'; | ||
173 | # | ||
174 | # To print a call stack requires walking the call_paths table. For example this python script: | ||
175 | # #!/usr/bin/python2 | ||
176 | # | ||
177 | # import sys | ||
178 | # from PySide.QtSql import * | ||
179 | # | ||
180 | # if __name__ == '__main__': | ||
181 | # if (len(sys.argv) < 3): | ||
182 | # print >> sys.stderr, "Usage is: printcallstack.py <database name> <call_path_id>" | ||
183 | # raise Exception("Too few arguments") | ||
184 | # dbname = sys.argv[1] | ||
185 | # call_path_id = sys.argv[2] | ||
186 | # db = QSqlDatabase.addDatabase('QPSQL') | ||
187 | # db.setDatabaseName(dbname) | ||
188 | # if not db.open(): | ||
189 | # raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) | ||
190 | # query = QSqlQuery(db) | ||
191 | # print " id ip symbol_id symbol dso_id dso_short_name" | ||
192 | # while call_path_id != 0 and call_path_id != 1: | ||
193 | # ret = query.exec_('SELECT * FROM call_paths_view WHERE id = ' + str(call_path_id)) | ||
194 | # if not ret: | ||
195 | # raise Exception("Query failed: " + query.lastError().text()) | ||
196 | # if not query.next(): | ||
197 | # raise Exception("Query failed") | ||
198 | # print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5)) | ||
199 | # call_path_id = query.value(6) | ||
64 | 200 | ||
65 | from PySide.QtSql import * | 201 | from PySide.QtSql import * |
66 | 202 | ||
@@ -244,6 +380,91 @@ if perf_db_export_calls: | |||
244 | 'parent_call_path_id bigint,' | 380 | 'parent_call_path_id bigint,' |
245 | 'flags integer)') | 381 | 'flags integer)') |
246 | 382 | ||
383 | do_query(query, 'CREATE VIEW machines_view AS ' | ||
384 | 'SELECT ' | ||
385 | 'id,' | ||
386 | 'pid,' | ||
387 | 'root_dir,' | ||
388 | 'CASE WHEN id=0 THEN \'unknown\' WHEN pid=-1 THEN \'host\' ELSE \'guest\' END AS host_or_guest' | ||
389 | ' FROM machines') | ||
390 | |||
391 | do_query(query, 'CREATE VIEW dsos_view AS ' | ||
392 | 'SELECT ' | ||
393 | 'id,' | ||
394 | 'machine_id,' | ||
395 | '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' | ||
396 | 'short_name,' | ||
397 | 'long_name,' | ||
398 | 'build_id' | ||
399 | ' FROM dsos') | ||
400 | |||
401 | do_query(query, 'CREATE VIEW symbols_view AS ' | ||
402 | 'SELECT ' | ||
403 | 'id,' | ||
404 | 'name,' | ||
405 | '(SELECT short_name FROM dsos WHERE id=dso_id) AS dso,' | ||
406 | 'dso_id,' | ||
407 | 'sym_start,' | ||
408 | 'sym_end,' | ||
409 | 'CASE WHEN binding=0 THEN \'local\' WHEN binding=1 THEN \'global\' ELSE \'weak\' END AS binding' | ||
410 | ' FROM symbols') | ||
411 | |||
412 | do_query(query, 'CREATE VIEW threads_view AS ' | ||
413 | 'SELECT ' | ||
414 | 'id,' | ||
415 | 'machine_id,' | ||
416 | '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' | ||
417 | 'process_id,' | ||
418 | 'pid,' | ||
419 | 'tid' | ||
420 | ' FROM threads') | ||
421 | |||
422 | do_query(query, 'CREATE VIEW comm_threads_view AS ' | ||
423 | 'SELECT ' | ||
424 | 'comm_id,' | ||
425 | '(SELECT comm FROM comms WHERE id = comm_id) AS command,' | ||
426 | 'thread_id,' | ||
427 | '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' | ||
428 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid' | ||
429 | ' FROM comm_threads') | ||
430 | |||
431 | if perf_db_export_calls: | ||
432 | do_query(query, 'CREATE VIEW call_paths_view AS ' | ||
433 | 'SELECT ' | ||
434 | 'c.id,' | ||
435 | 'to_hex(c.ip) AS ip,' | ||
436 | 'c.symbol_id,' | ||
437 | '(SELECT name FROM symbols WHERE id = c.symbol_id) AS symbol,' | ||
438 | '(SELECT dso_id FROM symbols WHERE id = c.symbol_id) AS dso_id,' | ||
439 | '(SELECT dso FROM symbols_view WHERE id = c.symbol_id) AS dso_short_name,' | ||
440 | 'c.parent_id,' | ||
441 | 'to_hex(p.ip) AS parent_ip,' | ||
442 | 'p.symbol_id AS parent_symbol_id,' | ||
443 | '(SELECT name FROM symbols WHERE id = p.symbol_id) AS parent_symbol,' | ||
444 | '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' | ||
445 | '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' | ||
446 | ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') | ||
447 | do_query(query, 'CREATE VIEW calls_view AS ' | ||
448 | 'SELECT ' | ||
449 | 'calls.id,' | ||
450 | 'thread_id,' | ||
451 | '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' | ||
452 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid,' | ||
453 | '(SELECT comm FROM comms WHERE id = comm_id) AS command,' | ||
454 | 'call_path_id,' | ||
455 | 'to_hex(ip) AS ip,' | ||
456 | 'symbol_id,' | ||
457 | '(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,' | ||
458 | 'call_time,' | ||
459 | 'return_time,' | ||
460 | 'return_time - call_time AS elapsed_time,' | ||
461 | 'branch_count,' | ||
462 | 'call_id,' | ||
463 | 'return_id,' | ||
464 | 'CASE WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' ELSE \'\' END AS flags,' | ||
465 | 'parent_call_path_id' | ||
466 | ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') | ||
467 | |||
247 | do_query(query, 'CREATE VIEW samples_view AS ' | 468 | do_query(query, 'CREATE VIEW samples_view AS ' |
248 | 'SELECT ' | 469 | 'SELECT ' |
249 | 'id,' | 470 | 'id,' |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e1f28f4cdc8e..a4e9b370c037 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1527,7 +1527,7 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, | |||
1527 | static int | 1527 | static int |
1528 | do_zoom_dso(struct hist_browser *browser, struct popup_action *act) | 1528 | do_zoom_dso(struct hist_browser *browser, struct popup_action *act) |
1529 | { | 1529 | { |
1530 | struct dso *dso = act->dso; | 1530 | struct map *map = act->ms.map; |
1531 | 1531 | ||
1532 | if (browser->hists->dso_filter) { | 1532 | if (browser->hists->dso_filter) { |
1533 | pstack__remove(browser->pstack, &browser->hists->dso_filter); | 1533 | pstack__remove(browser->pstack, &browser->hists->dso_filter); |
@@ -1535,11 +1535,11 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) | |||
1535 | browser->hists->dso_filter = NULL; | 1535 | browser->hists->dso_filter = NULL; |
1536 | ui_helpline__pop(); | 1536 | ui_helpline__pop(); |
1537 | } else { | 1537 | } else { |
1538 | if (dso == NULL) | 1538 | if (map == NULL) |
1539 | return 0; | 1539 | return 0; |
1540 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", | 1540 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", |
1541 | dso->kernel ? "the Kernel" : dso->short_name); | 1541 | __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); |
1542 | browser->hists->dso_filter = dso; | 1542 | browser->hists->dso_filter = map->dso; |
1543 | perf_hpp__set_elide(HISTC_DSO, true); | 1543 | perf_hpp__set_elide(HISTC_DSO, true); |
1544 | pstack__push(browser->pstack, &browser->hists->dso_filter); | 1544 | pstack__push(browser->pstack, &browser->hists->dso_filter); |
1545 | } | 1545 | } |
@@ -1551,17 +1551,18 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) | |||
1551 | 1551 | ||
1552 | static int | 1552 | static int |
1553 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, | 1553 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, |
1554 | char **optstr, struct dso *dso) | 1554 | char **optstr, struct map *map) |
1555 | { | 1555 | { |
1556 | if (dso == NULL) | 1556 | if (map == NULL) |
1557 | return 0; | 1557 | return 0; |
1558 | 1558 | ||
1559 | if (asprintf(optstr, "Zoom %s %s DSO", | 1559 | if (asprintf(optstr, "Zoom %s %s DSO", |
1560 | browser->hists->dso_filter ? "out of" : "into", | 1560 | browser->hists->dso_filter ? "out of" : "into", |
1561 | dso->kernel ? "the Kernel" : dso->short_name) < 0) | 1561 | __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) |
1562 | return 0; | 1562 | return 0; |
1563 | 1563 | ||
1564 | act->dso = dso; | 1564 | act->ms.map = map; |
1565 | act->dso = map->dso; | ||
1565 | act->fn = do_zoom_dso; | 1566 | act->fn = do_zoom_dso; |
1566 | return 1; | 1567 | return 1; |
1567 | } | 1568 | } |
@@ -1814,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1814 | while (1) { | 1815 | while (1) { |
1815 | struct thread *thread = NULL; | 1816 | struct thread *thread = NULL; |
1816 | struct dso *dso = NULL; | 1817 | struct dso *dso = NULL; |
1818 | struct map *map = NULL; | ||
1817 | int choice = 0; | 1819 | int choice = 0; |
1818 | int socked_id = -1; | 1820 | int socked_id = -1; |
1819 | 1821 | ||
@@ -1823,7 +1825,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1823 | 1825 | ||
1824 | if (browser->he_selection != NULL) { | 1826 | if (browser->he_selection != NULL) { |
1825 | thread = hist_browser__selected_thread(browser); | 1827 | thread = hist_browser__selected_thread(browser); |
1826 | dso = browser->selection->map ? browser->selection->map->dso : NULL; | 1828 | map = browser->selection->map; |
1829 | if (map) | ||
1830 | dso = map->dso; | ||
1827 | socked_id = browser->he_selection->socket; | 1831 | socked_id = browser->he_selection->socket; |
1828 | } | 1832 | } |
1829 | switch (key) { | 1833 | switch (key) { |
@@ -2014,7 +2018,7 @@ skip_annotation: | |||
2014 | nr_options += add_thread_opt(browser, &actions[nr_options], | 2018 | nr_options += add_thread_opt(browser, &actions[nr_options], |
2015 | &options[nr_options], thread); | 2019 | &options[nr_options], thread); |
2016 | nr_options += add_dso_opt(browser, &actions[nr_options], | 2020 | nr_options += add_dso_opt(browser, &actions[nr_options], |
2017 | &options[nr_options], dso); | 2021 | &options[nr_options], map); |
2018 | nr_options += add_map_opt(browser, &actions[nr_options], | 2022 | nr_options += add_map_opt(browser, &actions[nr_options], |
2019 | &options[nr_options], | 2023 | &options[nr_options], |
2020 | browser->selection ? | 2024 | browser->selection ? |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index a980e7c50ee0..7f10430af39c 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -926,6 +926,8 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool, | |||
926 | #define PERF_ITRACE_DEFAULT_PERIOD 100000 | 926 | #define PERF_ITRACE_DEFAULT_PERIOD 100000 |
927 | #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 | 927 | #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 |
928 | #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 | 928 | #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 |
929 | #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 | ||
930 | #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 | ||
929 | 931 | ||
930 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | 932 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) |
931 | { | 933 | { |
@@ -936,6 +938,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | |||
936 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; | 938 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
937 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 939 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
938 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; | 940 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
941 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; | ||
939 | } | 942 | } |
940 | 943 | ||
941 | /* | 944 | /* |
@@ -950,6 +953,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
950 | const char *p; | 953 | const char *p; |
951 | char *endptr; | 954 | char *endptr; |
952 | bool period_type_set = false; | 955 | bool period_type_set = false; |
956 | bool period_set = false; | ||
953 | 957 | ||
954 | synth_opts->set = true; | 958 | synth_opts->set = true; |
955 | 959 | ||
@@ -971,6 +975,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
971 | p += 1; | 975 | p += 1; |
972 | if (isdigit(*p)) { | 976 | if (isdigit(*p)) { |
973 | synth_opts->period = strtoull(p, &endptr, 10); | 977 | synth_opts->period = strtoull(p, &endptr, 10); |
978 | period_set = true; | ||
974 | p = endptr; | 979 | p = endptr; |
975 | while (*p == ' ' || *p == ',') | 980 | while (*p == ' ' || *p == ',') |
976 | p += 1; | 981 | p += 1; |
@@ -1041,6 +1046,23 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
1041 | synth_opts->callchain_sz = val; | 1046 | synth_opts->callchain_sz = val; |
1042 | } | 1047 | } |
1043 | break; | 1048 | break; |
1049 | case 'l': | ||
1050 | synth_opts->last_branch = true; | ||
1051 | synth_opts->last_branch_sz = | ||
1052 | PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; | ||
1053 | while (*p == ' ' || *p == ',') | ||
1054 | p += 1; | ||
1055 | if (isdigit(*p)) { | ||
1056 | unsigned int val; | ||
1057 | |||
1058 | val = strtoul(p, &endptr, 10); | ||
1059 | p = endptr; | ||
1060 | if (!val || | ||
1061 | val > PERF_ITRACE_MAX_LAST_BRANCH_SZ) | ||
1062 | goto out_err; | ||
1063 | synth_opts->last_branch_sz = val; | ||
1064 | } | ||
1065 | break; | ||
1044 | case ' ': | 1066 | case ' ': |
1045 | case ',': | 1067 | case ',': |
1046 | break; | 1068 | break; |
@@ -1053,7 +1075,7 @@ out: | |||
1053 | if (!period_type_set) | 1075 | if (!period_type_set) |
1054 | synth_opts->period_type = | 1076 | synth_opts->period_type = |
1055 | PERF_ITRACE_DEFAULT_PERIOD_TYPE; | 1077 | PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
1056 | if (!synth_opts->period) | 1078 | if (!period_set) |
1057 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 1079 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
1058 | } | 1080 | } |
1059 | 1081 | ||
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index bf72b77a588a..b86f90db1352 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -63,7 +63,9 @@ enum itrace_period_type { | |||
63 | * @calls: limit branch samples to calls (can be combined with @returns) | 63 | * @calls: limit branch samples to calls (can be combined with @returns) |
64 | * @returns: limit branch samples to returns (can be combined with @calls) | 64 | * @returns: limit branch samples to returns (can be combined with @calls) |
65 | * @callchain: add callchain to 'instructions' events | 65 | * @callchain: add callchain to 'instructions' events |
66 | * @last_branch: add branch context to 'instruction' events | ||
66 | * @callchain_sz: maximum callchain size | 67 | * @callchain_sz: maximum callchain size |
68 | * @last_branch_sz: branch context size | ||
67 | * @period: 'instructions' events period | 69 | * @period: 'instructions' events period |
68 | * @period_type: 'instructions' events period type | 70 | * @period_type: 'instructions' events period type |
69 | */ | 71 | */ |
@@ -79,7 +81,9 @@ struct itrace_synth_opts { | |||
79 | bool calls; | 81 | bool calls; |
80 | bool returns; | 82 | bool returns; |
81 | bool callchain; | 83 | bool callchain; |
84 | bool last_branch; | ||
82 | unsigned int callchain_sz; | 85 | unsigned int callchain_sz; |
86 | unsigned int last_branch_sz; | ||
83 | unsigned long long period; | 87 | unsigned long long period; |
84 | enum itrace_period_type period_type; | 88 | enum itrace_period_type period_type; |
85 | }; | 89 | }; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6214ad47d554..b1bb348ec3b6 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -378,7 +378,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool, | |||
378 | for (pos = maps__first(maps); pos; pos = map__next(pos)) { | 378 | for (pos = maps__first(maps); pos; pos = map__next(pos)) { |
379 | size_t size; | 379 | size_t size; |
380 | 380 | ||
381 | if (pos->dso->kernel) | 381 | if (__map__is_kernel(pos)) |
382 | continue; | 382 | continue; |
383 | 383 | ||
384 | size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); | 384 | size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index be5cbc7be889..a0dbcbd4f6d8 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -257,6 +257,7 @@ struct events_stats { | |||
257 | u64 total_non_filtered_period; | 257 | u64 total_non_filtered_period; |
258 | u64 total_lost; | 258 | u64 total_lost; |
259 | u64 total_lost_samples; | 259 | u64 total_lost_samples; |
260 | u64 total_aux_lost; | ||
260 | u64 total_invalid_chains; | 261 | u64 total_invalid_chains; |
261 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 262 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
262 | u32 nr_non_filtered_samples; | 263 | u32 nr_non_filtered_samples; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a8643735dcea..89546228b8ed 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -165,6 +165,13 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) | |||
165 | __perf_evlist__propagate_maps(evlist, entry); | 165 | __perf_evlist__propagate_maps(evlist, entry); |
166 | } | 166 | } |
167 | 167 | ||
168 | void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel) | ||
169 | { | ||
170 | evsel->evlist = NULL; | ||
171 | list_del_init(&evsel->node); | ||
172 | evlist->nr_entries -= 1; | ||
173 | } | ||
174 | |||
168 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, | 175 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
169 | struct list_head *list) | 176 | struct list_head *list) |
170 | { | 177 | { |
@@ -617,6 +624,21 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) | |||
617 | return NULL; | 624 | return NULL; |
618 | } | 625 | } |
619 | 626 | ||
627 | struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, | ||
628 | u64 id) | ||
629 | { | ||
630 | struct perf_sample_id *sid; | ||
631 | |||
632 | if (!id) | ||
633 | return NULL; | ||
634 | |||
635 | sid = perf_evlist__id2sid(evlist, id); | ||
636 | if (sid) | ||
637 | return sid->evsel; | ||
638 | |||
639 | return NULL; | ||
640 | } | ||
641 | |||
620 | static int perf_evlist__event2id(struct perf_evlist *evlist, | 642 | static int perf_evlist__event2id(struct perf_evlist *evlist, |
621 | union perf_event *event, u64 *id) | 643 | union perf_event *event, u64 *id) |
622 | { | 644 | { |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 115d8b53c601..66bc9d4c0869 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -73,6 +73,7 @@ void perf_evlist__exit(struct perf_evlist *evlist); | |||
73 | void perf_evlist__delete(struct perf_evlist *evlist); | 73 | void perf_evlist__delete(struct perf_evlist *evlist); |
74 | 74 | ||
75 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); | 75 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); |
76 | void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel); | ||
76 | int perf_evlist__add_default(struct perf_evlist *evlist); | 77 | int perf_evlist__add_default(struct perf_evlist *evlist); |
77 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | 78 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, |
78 | struct perf_event_attr *attrs, size_t nr_attrs); | 79 | struct perf_event_attr *attrs, size_t nr_attrs); |
@@ -104,6 +105,8 @@ int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mas | |||
104 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout); | 105 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout); |
105 | 106 | ||
106 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | 107 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); |
108 | struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, | ||
109 | u64 id); | ||
107 | 110 | ||
108 | struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); | 111 | struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); |
109 | 112 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b3567a25f0c4..0cad9e07c5b4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -695,7 +695,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, | |||
695 | } | 695 | } |
696 | 696 | ||
697 | static int | 697 | static int |
698 | iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, | 698 | iter_prepare_cumulative_entry(struct hist_entry_iter *iter, |
699 | struct addr_location *al __maybe_unused) | 699 | struct addr_location *al __maybe_unused) |
700 | { | 700 | { |
701 | struct hist_entry **he_cache; | 701 | struct hist_entry **he_cache; |
@@ -707,7 +707,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, | |||
707 | * cumulated only one time to prevent entries more than 100% | 707 | * cumulated only one time to prevent entries more than 100% |
708 | * overhead. | 708 | * overhead. |
709 | */ | 709 | */ |
710 | he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1)); | 710 | he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1)); |
711 | if (he_cache == NULL) | 711 | if (he_cache == NULL) |
712 | return -ENOMEM; | 712 | return -ENOMEM; |
713 | 713 | ||
@@ -868,6 +868,8 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | |||
868 | if (err) | 868 | if (err) |
869 | return err; | 869 | return err; |
870 | 870 | ||
871 | iter->max_stack = max_stack_depth; | ||
872 | |||
871 | err = iter->ops->prepare_entry(iter, al); | 873 | err = iter->ops->prepare_entry(iter, al); |
872 | if (err) | 874 | if (err) |
873 | goto out; | 875 | goto out; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 4d6aa1dbdaee..8c20a8f6b214 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -90,6 +90,7 @@ struct hist_entry_iter { | |||
90 | int curr; | 90 | int curr; |
91 | 91 | ||
92 | bool hide_unresolved; | 92 | bool hide_unresolved; |
93 | int max_stack; | ||
93 | 94 | ||
94 | struct perf_evsel *evsel; | 95 | struct perf_evsel *evsel; |
95 | struct perf_sample *sample; | 96 | struct perf_sample *sample; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 22ba50224319..9409d014b46c 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
@@ -650,7 +650,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
650 | if (data->from_mtc && timestamp < data->timestamp && | 650 | if (data->from_mtc && timestamp < data->timestamp && |
651 | data->timestamp - timestamp < decoder->tsc_slip) | 651 | data->timestamp - timestamp < decoder->tsc_slip) |
652 | return 1; | 652 | return 1; |
653 | while (timestamp < data->timestamp) | 653 | if (timestamp < data->timestamp) |
654 | timestamp += (1ULL << 56); | 654 | timestamp += (1ULL << 56); |
655 | if (pkt_info->last_packet_type != INTEL_PT_CYC) { | 655 | if (pkt_info->last_packet_type != INTEL_PT_CYC) { |
656 | if (data->from_mtc) | 656 | if (data->from_mtc) |
@@ -1191,7 +1191,7 @@ static void intel_pt_calc_tsc_timestamp(struct intel_pt_decoder *decoder) | |||
1191 | timestamp); | 1191 | timestamp); |
1192 | timestamp = decoder->timestamp; | 1192 | timestamp = decoder->timestamp; |
1193 | } | 1193 | } |
1194 | while (timestamp < decoder->timestamp) { | 1194 | if (timestamp < decoder->timestamp) { |
1195 | intel_pt_log_to("Wraparound timestamp", timestamp); | 1195 | intel_pt_log_to("Wraparound timestamp", timestamp); |
1196 | timestamp += (1ULL << 56); | 1196 | timestamp += (1ULL << 56); |
1197 | decoder->tsc_timestamp = timestamp; | 1197 | decoder->tsc_timestamp = timestamp; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.c b/tools/perf/util/intel-pt-decoder/intel-pt-log.c index d09c7d9f9050..319bef33a64b 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.c | |||
@@ -29,18 +29,18 @@ | |||
29 | 29 | ||
30 | static FILE *f; | 30 | static FILE *f; |
31 | static char log_name[MAX_LOG_NAME]; | 31 | static char log_name[MAX_LOG_NAME]; |
32 | static bool enable_logging; | 32 | bool intel_pt_enable_logging; |
33 | 33 | ||
34 | void intel_pt_log_enable(void) | 34 | void intel_pt_log_enable(void) |
35 | { | 35 | { |
36 | enable_logging = true; | 36 | intel_pt_enable_logging = true; |
37 | } | 37 | } |
38 | 38 | ||
39 | void intel_pt_log_disable(void) | 39 | void intel_pt_log_disable(void) |
40 | { | 40 | { |
41 | if (f) | 41 | if (f) |
42 | fflush(f); | 42 | fflush(f); |
43 | enable_logging = false; | 43 | intel_pt_enable_logging = false; |
44 | } | 44 | } |
45 | 45 | ||
46 | void intel_pt_log_set_name(const char *name) | 46 | void intel_pt_log_set_name(const char *name) |
@@ -80,7 +80,7 @@ static void intel_pt_print_no_data(uint64_t pos, int indent) | |||
80 | 80 | ||
81 | static int intel_pt_log_open(void) | 81 | static int intel_pt_log_open(void) |
82 | { | 82 | { |
83 | if (!enable_logging) | 83 | if (!intel_pt_enable_logging) |
84 | return -1; | 84 | return -1; |
85 | 85 | ||
86 | if (f) | 86 | if (f) |
@@ -91,15 +91,15 @@ static int intel_pt_log_open(void) | |||
91 | 91 | ||
92 | f = fopen(log_name, "w+"); | 92 | f = fopen(log_name, "w+"); |
93 | if (!f) { | 93 | if (!f) { |
94 | enable_logging = false; | 94 | intel_pt_enable_logging = false; |
95 | return -1; | 95 | return -1; |
96 | } | 96 | } |
97 | 97 | ||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, | 101 | void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, |
102 | uint64_t pos, const unsigned char *buf) | 102 | uint64_t pos, const unsigned char *buf) |
103 | { | 103 | { |
104 | char desc[INTEL_PT_PKT_DESC_MAX]; | 104 | char desc[INTEL_PT_PKT_DESC_MAX]; |
105 | 105 | ||
@@ -111,7 +111,7 @@ void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, | |||
111 | fprintf(f, "%s\n", desc); | 111 | fprintf(f, "%s\n", desc); |
112 | } | 112 | } |
113 | 113 | ||
114 | void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) | 114 | void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) |
115 | { | 115 | { |
116 | char desc[INTEL_PT_INSN_DESC_MAX]; | 116 | char desc[INTEL_PT_INSN_DESC_MAX]; |
117 | size_t len = intel_pt_insn->length; | 117 | size_t len = intel_pt_insn->length; |
@@ -128,7 +128,8 @@ void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) | |||
128 | fprintf(f, "Bad instruction!\n"); | 128 | fprintf(f, "Bad instruction!\n"); |
129 | } | 129 | } |
130 | 130 | ||
131 | void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, uint64_t ip) | 131 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, |
132 | uint64_t ip) | ||
132 | { | 133 | { |
133 | char desc[INTEL_PT_INSN_DESC_MAX]; | 134 | char desc[INTEL_PT_INSN_DESC_MAX]; |
134 | 135 | ||
@@ -142,7 +143,7 @@ void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, uint64_t ip) | |||
142 | fprintf(f, "Bad instruction!\n"); | 143 | fprintf(f, "Bad instruction!\n"); |
143 | } | 144 | } |
144 | 145 | ||
145 | void intel_pt_log(const char *fmt, ...) | 146 | void __intel_pt_log(const char *fmt, ...) |
146 | { | 147 | { |
147 | va_list args; | 148 | va_list args; |
148 | 149 | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h index db3942f83677..debe751dc3d6 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h | |||
@@ -25,20 +25,46 @@ void intel_pt_log_enable(void); | |||
25 | void intel_pt_log_disable(void); | 25 | void intel_pt_log_disable(void); |
26 | void intel_pt_log_set_name(const char *name); | 26 | void intel_pt_log_set_name(const char *name); |
27 | 27 | ||
28 | void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, | 28 | void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, |
29 | uint64_t pos, const unsigned char *buf); | 29 | uint64_t pos, const unsigned char *buf); |
30 | 30 | ||
31 | struct intel_pt_insn; | 31 | struct intel_pt_insn; |
32 | 32 | ||
33 | void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); | 33 | void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); |
34 | void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, | 34 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, |
35 | uint64_t ip); | 35 | uint64_t ip); |
36 | 36 | ||
37 | __attribute__((format(printf, 1, 2))) | 37 | __attribute__((format(printf, 1, 2))) |
38 | void intel_pt_log(const char *fmt, ...); | 38 | void __intel_pt_log(const char *fmt, ...); |
39 | |||
40 | #define intel_pt_log(fmt, ...) \ | ||
41 | do { \ | ||
42 | if (intel_pt_enable_logging) \ | ||
43 | __intel_pt_log(fmt, ##__VA_ARGS__); \ | ||
44 | } while (0) | ||
45 | |||
46 | #define intel_pt_log_packet(arg, ...) \ | ||
47 | do { \ | ||
48 | if (intel_pt_enable_logging) \ | ||
49 | __intel_pt_log_packet(arg, ##__VA_ARGS__); \ | ||
50 | } while (0) | ||
51 | |||
52 | #define intel_pt_log_insn(arg, ...) \ | ||
53 | do { \ | ||
54 | if (intel_pt_enable_logging) \ | ||
55 | __intel_pt_log_insn(arg, ##__VA_ARGS__); \ | ||
56 | } while (0) | ||
57 | |||
58 | #define intel_pt_log_insn_no_data(arg, ...) \ | ||
59 | do { \ | ||
60 | if (intel_pt_enable_logging) \ | ||
61 | __intel_pt_log_insn_no_data(arg, ##__VA_ARGS__); \ | ||
62 | } while (0) | ||
39 | 63 | ||
40 | #define x64_fmt "0x%" PRIx64 | 64 | #define x64_fmt "0x%" PRIx64 |
41 | 65 | ||
66 | extern bool intel_pt_enable_logging; | ||
67 | |||
42 | static inline void intel_pt_log_at(const char *msg, uint64_t u) | 68 | static inline void intel_pt_log_at(const char *msg, uint64_t u) |
43 | { | 69 | { |
44 | intel_pt_log("%s at " x64_fmt "\n", msg, u); | 70 | intel_pt_log("%s at " x64_fmt "\n", msg, u); |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 38942e1eac8f..03ff072b5993 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "../perf.h" | 22 | #include "../perf.h" |
23 | #include "session.h" | 23 | #include "session.h" |
24 | #include "machine.h" | 24 | #include "machine.h" |
25 | #include "sort.h" | ||
25 | #include "tool.h" | 26 | #include "tool.h" |
26 | #include "event.h" | 27 | #include "event.h" |
27 | #include "evlist.h" | 28 | #include "evlist.h" |
@@ -63,6 +64,7 @@ struct intel_pt { | |||
63 | bool data_queued; | 64 | bool data_queued; |
64 | bool est_tsc; | 65 | bool est_tsc; |
65 | bool sync_switch; | 66 | bool sync_switch; |
67 | bool mispred_all; | ||
66 | int have_sched_switch; | 68 | int have_sched_switch; |
67 | u32 pmu_type; | 69 | u32 pmu_type; |
68 | u64 kernel_start; | 70 | u64 kernel_start; |
@@ -115,6 +117,9 @@ struct intel_pt_queue { | |||
115 | void *decoder; | 117 | void *decoder; |
116 | const struct intel_pt_state *state; | 118 | const struct intel_pt_state *state; |
117 | struct ip_callchain *chain; | 119 | struct ip_callchain *chain; |
120 | struct branch_stack *last_branch; | ||
121 | struct branch_stack *last_branch_rb; | ||
122 | size_t last_branch_pos; | ||
118 | union perf_event *event_buf; | 123 | union perf_event *event_buf; |
119 | bool on_heap; | 124 | bool on_heap; |
120 | bool stop; | 125 | bool stop; |
@@ -675,6 +680,19 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
675 | goto out_free; | 680 | goto out_free; |
676 | } | 681 | } |
677 | 682 | ||
683 | if (pt->synth_opts.last_branch) { | ||
684 | size_t sz = sizeof(struct branch_stack); | ||
685 | |||
686 | sz += pt->synth_opts.last_branch_sz * | ||
687 | sizeof(struct branch_entry); | ||
688 | ptq->last_branch = zalloc(sz); | ||
689 | if (!ptq->last_branch) | ||
690 | goto out_free; | ||
691 | ptq->last_branch_rb = zalloc(sz); | ||
692 | if (!ptq->last_branch_rb) | ||
693 | goto out_free; | ||
694 | } | ||
695 | |||
678 | ptq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); | 696 | ptq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); |
679 | if (!ptq->event_buf) | 697 | if (!ptq->event_buf) |
680 | goto out_free; | 698 | goto out_free; |
@@ -720,7 +738,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
720 | 738 | ||
721 | if (!params.period) { | 739 | if (!params.period) { |
722 | params.period_type = INTEL_PT_PERIOD_INSTRUCTIONS; | 740 | params.period_type = INTEL_PT_PERIOD_INSTRUCTIONS; |
723 | params.period = 1000; | 741 | params.period = 1; |
724 | } | 742 | } |
725 | } | 743 | } |
726 | 744 | ||
@@ -732,6 +750,8 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
732 | 750 | ||
733 | out_free: | 751 | out_free: |
734 | zfree(&ptq->event_buf); | 752 | zfree(&ptq->event_buf); |
753 | zfree(&ptq->last_branch); | ||
754 | zfree(&ptq->last_branch_rb); | ||
735 | zfree(&ptq->chain); | 755 | zfree(&ptq->chain); |
736 | free(ptq); | 756 | free(ptq); |
737 | return NULL; | 757 | return NULL; |
@@ -746,6 +766,8 @@ static void intel_pt_free_queue(void *priv) | |||
746 | thread__zput(ptq->thread); | 766 | thread__zput(ptq->thread); |
747 | intel_pt_decoder_free(ptq->decoder); | 767 | intel_pt_decoder_free(ptq->decoder); |
748 | zfree(&ptq->event_buf); | 768 | zfree(&ptq->event_buf); |
769 | zfree(&ptq->last_branch); | ||
770 | zfree(&ptq->last_branch_rb); | ||
749 | zfree(&ptq->chain); | 771 | zfree(&ptq->chain); |
750 | free(ptq); | 772 | free(ptq); |
751 | } | 773 | } |
@@ -876,6 +898,58 @@ static int intel_pt_setup_queues(struct intel_pt *pt) | |||
876 | return 0; | 898 | return 0; |
877 | } | 899 | } |
878 | 900 | ||
901 | static inline void intel_pt_copy_last_branch_rb(struct intel_pt_queue *ptq) | ||
902 | { | ||
903 | struct branch_stack *bs_src = ptq->last_branch_rb; | ||
904 | struct branch_stack *bs_dst = ptq->last_branch; | ||
905 | size_t nr = 0; | ||
906 | |||
907 | bs_dst->nr = bs_src->nr; | ||
908 | |||
909 | if (!bs_src->nr) | ||
910 | return; | ||
911 | |||
912 | nr = ptq->pt->synth_opts.last_branch_sz - ptq->last_branch_pos; | ||
913 | memcpy(&bs_dst->entries[0], | ||
914 | &bs_src->entries[ptq->last_branch_pos], | ||
915 | sizeof(struct branch_entry) * nr); | ||
916 | |||
917 | if (bs_src->nr >= ptq->pt->synth_opts.last_branch_sz) { | ||
918 | memcpy(&bs_dst->entries[nr], | ||
919 | &bs_src->entries[0], | ||
920 | sizeof(struct branch_entry) * ptq->last_branch_pos); | ||
921 | } | ||
922 | } | ||
923 | |||
924 | static inline void intel_pt_reset_last_branch_rb(struct intel_pt_queue *ptq) | ||
925 | { | ||
926 | ptq->last_branch_pos = 0; | ||
927 | ptq->last_branch_rb->nr = 0; | ||
928 | } | ||
929 | |||
930 | static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) | ||
931 | { | ||
932 | const struct intel_pt_state *state = ptq->state; | ||
933 | struct branch_stack *bs = ptq->last_branch_rb; | ||
934 | struct branch_entry *be; | ||
935 | |||
936 | if (!ptq->last_branch_pos) | ||
937 | ptq->last_branch_pos = ptq->pt->synth_opts.last_branch_sz; | ||
938 | |||
939 | ptq->last_branch_pos -= 1; | ||
940 | |||
941 | be = &bs->entries[ptq->last_branch_pos]; | ||
942 | be->from = state->from_ip; | ||
943 | be->to = state->to_ip; | ||
944 | be->flags.abort = !!(state->flags & INTEL_PT_ABORT_TX); | ||
945 | be->flags.in_tx = !!(state->flags & INTEL_PT_IN_TX); | ||
946 | /* No support for mispredict */ | ||
947 | be->flags.mispred = ptq->pt->mispred_all; | ||
948 | |||
949 | if (bs->nr < ptq->pt->synth_opts.last_branch_sz) | ||
950 | bs->nr += 1; | ||
951 | } | ||
952 | |||
879 | static int intel_pt_inject_event(union perf_event *event, | 953 | static int intel_pt_inject_event(union perf_event *event, |
880 | struct perf_sample *sample, u64 type, | 954 | struct perf_sample *sample, u64 type, |
881 | bool swapped) | 955 | bool swapped) |
@@ -890,6 +964,13 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
890 | struct intel_pt *pt = ptq->pt; | 964 | struct intel_pt *pt = ptq->pt; |
891 | union perf_event *event = ptq->event_buf; | 965 | union perf_event *event = ptq->event_buf; |
892 | struct perf_sample sample = { .ip = 0, }; | 966 | struct perf_sample sample = { .ip = 0, }; |
967 | struct dummy_branch_stack { | ||
968 | u64 nr; | ||
969 | struct branch_entry entries; | ||
970 | } dummy_bs; | ||
971 | |||
972 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | ||
973 | return 0; | ||
893 | 974 | ||
894 | event->sample.header.type = PERF_RECORD_SAMPLE; | 975 | event->sample.header.type = PERF_RECORD_SAMPLE; |
895 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 976 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
@@ -909,8 +990,20 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
909 | sample.flags = ptq->flags; | 990 | sample.flags = ptq->flags; |
910 | sample.insn_len = ptq->insn_len; | 991 | sample.insn_len = ptq->insn_len; |
911 | 992 | ||
912 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | 993 | /* |
913 | return 0; | 994 | * perf report cannot handle events without a branch stack when using |
995 | * SORT_MODE__BRANCH so make a dummy one. | ||
996 | */ | ||
997 | if (pt->synth_opts.last_branch && sort__mode == SORT_MODE__BRANCH) { | ||
998 | dummy_bs = (struct dummy_branch_stack){ | ||
999 | .nr = 1, | ||
1000 | .entries = { | ||
1001 | .from = sample.ip, | ||
1002 | .to = sample.addr, | ||
1003 | }, | ||
1004 | }; | ||
1005 | sample.branch_stack = (struct branch_stack *)&dummy_bs; | ||
1006 | } | ||
914 | 1007 | ||
915 | if (pt->synth_opts.inject) { | 1008 | if (pt->synth_opts.inject) { |
916 | ret = intel_pt_inject_event(event, &sample, | 1009 | ret = intel_pt_inject_event(event, &sample, |
@@ -961,6 +1054,11 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) | |||
961 | sample.callchain = ptq->chain; | 1054 | sample.callchain = ptq->chain; |
962 | } | 1055 | } |
963 | 1056 | ||
1057 | if (pt->synth_opts.last_branch) { | ||
1058 | intel_pt_copy_last_branch_rb(ptq); | ||
1059 | sample.branch_stack = ptq->last_branch; | ||
1060 | } | ||
1061 | |||
964 | if (pt->synth_opts.inject) { | 1062 | if (pt->synth_opts.inject) { |
965 | ret = intel_pt_inject_event(event, &sample, | 1063 | ret = intel_pt_inject_event(event, &sample, |
966 | pt->instructions_sample_type, | 1064 | pt->instructions_sample_type, |
@@ -974,6 +1072,9 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) | |||
974 | pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", | 1072 | pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", |
975 | ret); | 1073 | ret); |
976 | 1074 | ||
1075 | if (pt->synth_opts.last_branch) | ||
1076 | intel_pt_reset_last_branch_rb(ptq); | ||
1077 | |||
977 | return ret; | 1078 | return ret; |
978 | } | 1079 | } |
979 | 1080 | ||
@@ -1008,6 +1109,11 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | |||
1008 | sample.callchain = ptq->chain; | 1109 | sample.callchain = ptq->chain; |
1009 | } | 1110 | } |
1010 | 1111 | ||
1112 | if (pt->synth_opts.last_branch) { | ||
1113 | intel_pt_copy_last_branch_rb(ptq); | ||
1114 | sample.branch_stack = ptq->last_branch; | ||
1115 | } | ||
1116 | |||
1011 | if (pt->synth_opts.inject) { | 1117 | if (pt->synth_opts.inject) { |
1012 | ret = intel_pt_inject_event(event, &sample, | 1118 | ret = intel_pt_inject_event(event, &sample, |
1013 | pt->transactions_sample_type, | 1119 | pt->transactions_sample_type, |
@@ -1021,6 +1127,9 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | |||
1021 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", | 1127 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", |
1022 | ret); | 1128 | ret); |
1023 | 1129 | ||
1130 | if (pt->synth_opts.callchain) | ||
1131 | intel_pt_reset_last_branch_rb(ptq); | ||
1132 | |||
1024 | return ret; | 1133 | return ret; |
1025 | } | 1134 | } |
1026 | 1135 | ||
@@ -1116,6 +1225,9 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) | |||
1116 | return err; | 1225 | return err; |
1117 | } | 1226 | } |
1118 | 1227 | ||
1228 | if (pt->synth_opts.last_branch) | ||
1229 | intel_pt_update_last_branch_rb(ptq); | ||
1230 | |||
1119 | if (!pt->sync_switch) | 1231 | if (!pt->sync_switch) |
1120 | return 0; | 1232 | return 0; |
1121 | 1233 | ||
@@ -1763,6 +1875,8 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
1763 | pt->instructions_sample_period = attr.sample_period; | 1875 | pt->instructions_sample_period = attr.sample_period; |
1764 | if (pt->synth_opts.callchain) | 1876 | if (pt->synth_opts.callchain) |
1765 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | 1877 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; |
1878 | if (pt->synth_opts.last_branch) | ||
1879 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
1766 | pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | 1880 | pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", |
1767 | id, (u64)attr.sample_type); | 1881 | id, (u64)attr.sample_type); |
1768 | err = intel_pt_synth_event(session, &attr, id); | 1882 | err = intel_pt_synth_event(session, &attr, id); |
@@ -1782,6 +1896,8 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
1782 | attr.sample_period = 1; | 1896 | attr.sample_period = 1; |
1783 | if (pt->synth_opts.callchain) | 1897 | if (pt->synth_opts.callchain) |
1784 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | 1898 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; |
1899 | if (pt->synth_opts.last_branch) | ||
1900 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
1785 | pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | 1901 | pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", |
1786 | id, (u64)attr.sample_type); | 1902 | id, (u64)attr.sample_type); |
1787 | err = intel_pt_synth_event(session, &attr, id); | 1903 | err = intel_pt_synth_event(session, &attr, id); |
@@ -1808,6 +1924,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
1808 | attr.sample_period = 1; | 1924 | attr.sample_period = 1; |
1809 | attr.sample_type |= PERF_SAMPLE_ADDR; | 1925 | attr.sample_type |= PERF_SAMPLE_ADDR; |
1810 | attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; | 1926 | attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; |
1927 | attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; | ||
1811 | pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | 1928 | pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", |
1812 | id, (u64)attr.sample_type); | 1929 | id, (u64)attr.sample_type); |
1813 | err = intel_pt_synth_event(session, &attr, id); | 1930 | err = intel_pt_synth_event(session, &attr, id); |
@@ -1852,6 +1969,16 @@ static bool intel_pt_find_switch(struct perf_evlist *evlist) | |||
1852 | return false; | 1969 | return false; |
1853 | } | 1970 | } |
1854 | 1971 | ||
1972 | static int intel_pt_perf_config(const char *var, const char *value, void *data) | ||
1973 | { | ||
1974 | struct intel_pt *pt = data; | ||
1975 | |||
1976 | if (!strcmp(var, "intel-pt.mispred-all")) | ||
1977 | pt->mispred_all = perf_config_bool(var, value); | ||
1978 | |||
1979 | return 0; | ||
1980 | } | ||
1981 | |||
1855 | static const char * const intel_pt_info_fmts[] = { | 1982 | static const char * const intel_pt_info_fmts[] = { |
1856 | [INTEL_PT_PMU_TYPE] = " PMU Type %"PRId64"\n", | 1983 | [INTEL_PT_PMU_TYPE] = " PMU Type %"PRId64"\n", |
1857 | [INTEL_PT_TIME_SHIFT] = " Time Shift %"PRIu64"\n", | 1984 | [INTEL_PT_TIME_SHIFT] = " Time Shift %"PRIu64"\n", |
@@ -1896,6 +2023,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
1896 | if (!pt) | 2023 | if (!pt) |
1897 | return -ENOMEM; | 2024 | return -ENOMEM; |
1898 | 2025 | ||
2026 | perf_config(intel_pt_perf_config, pt); | ||
2027 | |||
1899 | err = auxtrace_queues__init(&pt->queues); | 2028 | err = auxtrace_queues__init(&pt->queues); |
1900 | if (err) | 2029 | if (err) |
1901 | goto err_free; | 2030 | goto err_free; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 61c2bc20926d..5ffb356cbcc6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -27,6 +27,8 @@ | |||
27 | extern int parse_events_debug; | 27 | extern int parse_events_debug; |
28 | #endif | 28 | #endif |
29 | int parse_events_parse(void *data, void *scanner); | 29 | int parse_events_parse(void *data, void *scanner); |
30 | static int get_config_terms(struct list_head *head_config, | ||
31 | struct list_head *head_terms __maybe_unused); | ||
30 | 32 | ||
31 | static struct perf_pmu_event_symbol *perf_pmu_events_list; | 33 | static struct perf_pmu_event_symbol *perf_pmu_events_list; |
32 | /* | 34 | /* |
@@ -416,7 +418,8 @@ static void tracepoint_error(struct parse_events_error *error, int err, | |||
416 | 418 | ||
417 | static int add_tracepoint(struct list_head *list, int *idx, | 419 | static int add_tracepoint(struct list_head *list, int *idx, |
418 | char *sys_name, char *evt_name, | 420 | char *sys_name, char *evt_name, |
419 | struct parse_events_error *error __maybe_unused) | 421 | struct parse_events_error *error __maybe_unused, |
422 | struct list_head *head_config) | ||
420 | { | 423 | { |
421 | struct perf_evsel *evsel; | 424 | struct perf_evsel *evsel; |
422 | 425 | ||
@@ -426,13 +429,22 @@ static int add_tracepoint(struct list_head *list, int *idx, | |||
426 | return PTR_ERR(evsel); | 429 | return PTR_ERR(evsel); |
427 | } | 430 | } |
428 | 431 | ||
432 | if (head_config) { | ||
433 | LIST_HEAD(config_terms); | ||
434 | |||
435 | if (get_config_terms(head_config, &config_terms)) | ||
436 | return -ENOMEM; | ||
437 | list_splice(&config_terms, &evsel->config_terms); | ||
438 | } | ||
439 | |||
429 | list_add_tail(&evsel->node, list); | 440 | list_add_tail(&evsel->node, list); |
430 | return 0; | 441 | return 0; |
431 | } | 442 | } |
432 | 443 | ||
433 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, | 444 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, |
434 | char *sys_name, char *evt_name, | 445 | char *sys_name, char *evt_name, |
435 | struct parse_events_error *error) | 446 | struct parse_events_error *error, |
447 | struct list_head *head_config) | ||
436 | { | 448 | { |
437 | char evt_path[MAXPATHLEN]; | 449 | char evt_path[MAXPATHLEN]; |
438 | struct dirent *evt_ent; | 450 | struct dirent *evt_ent; |
@@ -456,7 +468,8 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, | |||
456 | if (!strglobmatch(evt_ent->d_name, evt_name)) | 468 | if (!strglobmatch(evt_ent->d_name, evt_name)) |
457 | continue; | 469 | continue; |
458 | 470 | ||
459 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, error); | 471 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, |
472 | error, head_config); | ||
460 | } | 473 | } |
461 | 474 | ||
462 | closedir(evt_dir); | 475 | closedir(evt_dir); |
@@ -465,16 +478,20 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, | |||
465 | 478 | ||
466 | static int add_tracepoint_event(struct list_head *list, int *idx, | 479 | static int add_tracepoint_event(struct list_head *list, int *idx, |
467 | char *sys_name, char *evt_name, | 480 | char *sys_name, char *evt_name, |
468 | struct parse_events_error *error) | 481 | struct parse_events_error *error, |
482 | struct list_head *head_config) | ||
469 | { | 483 | { |
470 | return strpbrk(evt_name, "*?") ? | 484 | return strpbrk(evt_name, "*?") ? |
471 | add_tracepoint_multi_event(list, idx, sys_name, evt_name, error) : | 485 | add_tracepoint_multi_event(list, idx, sys_name, evt_name, |
472 | add_tracepoint(list, idx, sys_name, evt_name, error); | 486 | error, head_config) : |
487 | add_tracepoint(list, idx, sys_name, evt_name, | ||
488 | error, head_config); | ||
473 | } | 489 | } |
474 | 490 | ||
475 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, | 491 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, |
476 | char *sys_name, char *evt_name, | 492 | char *sys_name, char *evt_name, |
477 | struct parse_events_error *error) | 493 | struct parse_events_error *error, |
494 | struct list_head *head_config) | ||
478 | { | 495 | { |
479 | struct dirent *events_ent; | 496 | struct dirent *events_ent; |
480 | DIR *events_dir; | 497 | DIR *events_dir; |
@@ -498,23 +515,13 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, | |||
498 | continue; | 515 | continue; |
499 | 516 | ||
500 | ret = add_tracepoint_event(list, idx, events_ent->d_name, | 517 | ret = add_tracepoint_event(list, idx, events_ent->d_name, |
501 | evt_name, error); | 518 | evt_name, error, head_config); |
502 | } | 519 | } |
503 | 520 | ||
504 | closedir(events_dir); | 521 | closedir(events_dir); |
505 | return ret; | 522 | return ret; |
506 | } | 523 | } |
507 | 524 | ||
508 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | ||
509 | char *sys, char *event, | ||
510 | struct parse_events_error *error) | ||
511 | { | ||
512 | if (strpbrk(sys, "*?")) | ||
513 | return add_tracepoint_multi_sys(list, idx, sys, event, error); | ||
514 | else | ||
515 | return add_tracepoint_event(list, idx, sys, event, error); | ||
516 | } | ||
517 | |||
518 | static int | 525 | static int |
519 | parse_breakpoint_type(const char *type, struct perf_event_attr *attr) | 526 | parse_breakpoint_type(const char *type, struct perf_event_attr *attr) |
520 | { | 527 | { |
@@ -599,9 +606,13 @@ static int check_type_val(struct parse_events_term *term, | |||
599 | return -EINVAL; | 606 | return -EINVAL; |
600 | } | 607 | } |
601 | 608 | ||
602 | static int config_term(struct perf_event_attr *attr, | 609 | typedef int config_term_func_t(struct perf_event_attr *attr, |
603 | struct parse_events_term *term, | 610 | struct parse_events_term *term, |
604 | struct parse_events_error *err) | 611 | struct parse_events_error *err); |
612 | |||
613 | static int config_term_common(struct perf_event_attr *attr, | ||
614 | struct parse_events_term *term, | ||
615 | struct parse_events_error *err) | ||
605 | { | 616 | { |
606 | #define CHECK_TYPE_VAL(type) \ | 617 | #define CHECK_TYPE_VAL(type) \ |
607 | do { \ | 618 | do { \ |
@@ -610,12 +621,6 @@ do { \ | |||
610 | } while (0) | 621 | } while (0) |
611 | 622 | ||
612 | switch (term->type_term) { | 623 | switch (term->type_term) { |
613 | case PARSE_EVENTS__TERM_TYPE_USER: | ||
614 | /* | ||
615 | * Always succeed for sysfs terms, as we dont know | ||
616 | * at this point what type they need to have. | ||
617 | */ | ||
618 | return 0; | ||
619 | case PARSE_EVENTS__TERM_TYPE_CONFIG: | 624 | case PARSE_EVENTS__TERM_TYPE_CONFIG: |
620 | CHECK_TYPE_VAL(NUM); | 625 | CHECK_TYPE_VAL(NUM); |
621 | attr->config = term->val.num; | 626 | attr->config = term->val.num; |
@@ -658,6 +663,9 @@ do { \ | |||
658 | CHECK_TYPE_VAL(STR); | 663 | CHECK_TYPE_VAL(STR); |
659 | break; | 664 | break; |
660 | default: | 665 | default: |
666 | err->str = strdup("unknown term"); | ||
667 | err->idx = term->err_term; | ||
668 | err->help = parse_events_formats_error_string(NULL); | ||
661 | return -EINVAL; | 669 | return -EINVAL; |
662 | } | 670 | } |
663 | 671 | ||
@@ -665,9 +673,44 @@ do { \ | |||
665 | #undef CHECK_TYPE_VAL | 673 | #undef CHECK_TYPE_VAL |
666 | } | 674 | } |
667 | 675 | ||
676 | static int config_term_pmu(struct perf_event_attr *attr, | ||
677 | struct parse_events_term *term, | ||
678 | struct parse_events_error *err) | ||
679 | { | ||
680 | if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) | ||
681 | /* | ||
682 | * Always succeed for sysfs terms, as we dont know | ||
683 | * at this point what type they need to have. | ||
684 | */ | ||
685 | return 0; | ||
686 | else | ||
687 | return config_term_common(attr, term, err); | ||
688 | } | ||
689 | |||
690 | static int config_term_tracepoint(struct perf_event_attr *attr, | ||
691 | struct parse_events_term *term, | ||
692 | struct parse_events_error *err) | ||
693 | { | ||
694 | switch (term->type_term) { | ||
695 | case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: | ||
696 | case PARSE_EVENTS__TERM_TYPE_STACKSIZE: | ||
697 | return config_term_common(attr, term, err); | ||
698 | default: | ||
699 | if (err) { | ||
700 | err->idx = term->err_term; | ||
701 | err->str = strdup("unknown term"); | ||
702 | err->help = strdup("valid terms: call-graph,stack-size\n"); | ||
703 | } | ||
704 | return -EINVAL; | ||
705 | } | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
668 | static int config_attr(struct perf_event_attr *attr, | 710 | static int config_attr(struct perf_event_attr *attr, |
669 | struct list_head *head, | 711 | struct list_head *head, |
670 | struct parse_events_error *err) | 712 | struct parse_events_error *err, |
713 | config_term_func_t config_term) | ||
671 | { | 714 | { |
672 | struct parse_events_term *term; | 715 | struct parse_events_term *term; |
673 | 716 | ||
@@ -722,6 +765,27 @@ do { \ | |||
722 | return 0; | 765 | return 0; |
723 | } | 766 | } |
724 | 767 | ||
768 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | ||
769 | char *sys, char *event, | ||
770 | struct parse_events_error *error, | ||
771 | struct list_head *head_config) | ||
772 | { | ||
773 | if (head_config) { | ||
774 | struct perf_event_attr attr; | ||
775 | |||
776 | if (config_attr(&attr, head_config, error, | ||
777 | config_term_tracepoint)) | ||
778 | return -EINVAL; | ||
779 | } | ||
780 | |||
781 | if (strpbrk(sys, "*?")) | ||
782 | return add_tracepoint_multi_sys(list, idx, sys, event, | ||
783 | error, head_config); | ||
784 | else | ||
785 | return add_tracepoint_event(list, idx, sys, event, | ||
786 | error, head_config); | ||
787 | } | ||
788 | |||
725 | int parse_events_add_numeric(struct parse_events_evlist *data, | 789 | int parse_events_add_numeric(struct parse_events_evlist *data, |
726 | struct list_head *list, | 790 | struct list_head *list, |
727 | u32 type, u64 config, | 791 | u32 type, u64 config, |
@@ -735,7 +799,8 @@ int parse_events_add_numeric(struct parse_events_evlist *data, | |||
735 | attr.config = config; | 799 | attr.config = config; |
736 | 800 | ||
737 | if (head_config) { | 801 | if (head_config) { |
738 | if (config_attr(&attr, head_config, data->error)) | 802 | if (config_attr(&attr, head_config, data->error, |
803 | config_term_common)) | ||
739 | return -EINVAL; | 804 | return -EINVAL; |
740 | 805 | ||
741 | if (get_config_terms(head_config, &config_terms)) | 806 | if (get_config_terms(head_config, &config_terms)) |
@@ -795,7 +860,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data, | |||
795 | * Configure hardcoded terms first, no need to check | 860 | * Configure hardcoded terms first, no need to check |
796 | * return value when called with fail == 0 ;) | 861 | * return value when called with fail == 0 ;) |
797 | */ | 862 | */ |
798 | if (config_attr(&attr, head_config, data->error)) | 863 | if (config_attr(&attr, head_config, data->error, config_term_pmu)) |
799 | return -EINVAL; | 864 | return -EINVAL; |
800 | 865 | ||
801 | if (get_config_terms(head_config, &config_terms)) | 866 | if (get_config_terms(head_config, &config_terms)) |
@@ -1861,3 +1926,29 @@ void parse_events_evlist_error(struct parse_events_evlist *data, | |||
1861 | err->str = strdup(str); | 1926 | err->str = strdup(str); |
1862 | WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); | 1927 | WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); |
1863 | } | 1928 | } |
1929 | |||
1930 | /* | ||
1931 | * Return string contains valid config terms of an event. | ||
1932 | * @additional_terms: For terms such as PMU sysfs terms. | ||
1933 | */ | ||
1934 | char *parse_events_formats_error_string(char *additional_terms) | ||
1935 | { | ||
1936 | char *str; | ||
1937 | static const char *static_terms = "config,config1,config2,name," | ||
1938 | "period,freq,branch_type,time," | ||
1939 | "call-graph,stack-size\n"; | ||
1940 | |||
1941 | /* valid terms */ | ||
1942 | if (additional_terms) { | ||
1943 | if (!asprintf(&str, "valid terms: %s,%s", | ||
1944 | additional_terms, static_terms)) | ||
1945 | goto fail; | ||
1946 | } else { | ||
1947 | if (!asprintf(&str, "valid terms: %s", static_terms)) | ||
1948 | goto fail; | ||
1949 | } | ||
1950 | return str; | ||
1951 | |||
1952 | fail: | ||
1953 | return NULL; | ||
1954 | } | ||
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index ffee7ece75a6..f13d3ccda444 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -119,7 +119,8 @@ int parse_events__modifier_group(struct list_head *list, char *event_mod); | |||
119 | int parse_events_name(struct list_head *list, char *name); | 119 | int parse_events_name(struct list_head *list, char *name); |
120 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | 120 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
121 | char *sys, char *event, | 121 | char *sys, char *event, |
122 | struct parse_events_error *error); | 122 | struct parse_events_error *error, |
123 | struct list_head *head_config); | ||
123 | int parse_events_add_numeric(struct parse_events_evlist *data, | 124 | int parse_events_add_numeric(struct parse_events_evlist *data, |
124 | struct list_head *list, | 125 | struct list_head *list, |
125 | u32 type, u64 config, | 126 | u32 type, u64 config, |
@@ -156,5 +157,6 @@ int print_hwcache_events(const char *event_glob, bool name_only); | |||
156 | extern int is_valid_tracepoint(const char *event_string); | 157 | extern int is_valid_tracepoint(const char *event_string); |
157 | 158 | ||
158 | int valid_event_mount(const char *eventfs); | 159 | int valid_event_mount(const char *eventfs); |
160 | char *parse_events_formats_error_string(char *additional_terms); | ||
159 | 161 | ||
160 | #endif /* __PERF_PARSE_EVENTS_H */ | 162 | #endif /* __PERF_PARSE_EVENTS_H */ |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 936d566f48d8..c29832bce496 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -174,7 +174,7 @@ modifier_bp [rwx]{1,3} | |||
174 | 174 | ||
175 | <config>{ | 175 | <config>{ |
176 | /* | 176 | /* |
177 | * Please update formats_error_string any time | 177 | * Please update parse_events_formats_error_string any time |
178 | * new static term is added. | 178 | * new static term is added. |
179 | */ | 179 | */ |
180 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } | 180 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 8bcc45868457..ae6af269f9c9 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -67,6 +67,7 @@ static inc_group_count(struct list_head *list, | |||
67 | %type <head> event_legacy_cache | 67 | %type <head> event_legacy_cache |
68 | %type <head> event_legacy_mem | 68 | %type <head> event_legacy_mem |
69 | %type <head> event_legacy_tracepoint | 69 | %type <head> event_legacy_tracepoint |
70 | %type <tracepoint_name> tracepoint_name | ||
70 | %type <head> event_legacy_numeric | 71 | %type <head> event_legacy_numeric |
71 | %type <head> event_legacy_raw | 72 | %type <head> event_legacy_raw |
72 | %type <head> event_def | 73 | %type <head> event_def |
@@ -84,6 +85,10 @@ static inc_group_count(struct list_head *list, | |||
84 | u64 num; | 85 | u64 num; |
85 | struct list_head *head; | 86 | struct list_head *head; |
86 | struct parse_events_term *term; | 87 | struct parse_events_term *term; |
88 | struct tracepoint_name { | ||
89 | char *sys; | ||
90 | char *event; | ||
91 | } tracepoint_name; | ||
87 | } | 92 | } |
88 | %% | 93 | %% |
89 | 94 | ||
@@ -368,38 +373,60 @@ PE_PREFIX_MEM PE_VALUE sep_dc | |||
368 | } | 373 | } |
369 | 374 | ||
370 | event_legacy_tracepoint: | 375 | event_legacy_tracepoint: |
371 | PE_NAME '-' PE_NAME ':' PE_NAME | 376 | tracepoint_name |
372 | { | 377 | { |
373 | struct parse_events_evlist *data = _data; | 378 | struct parse_events_evlist *data = _data; |
374 | struct parse_events_error *error = data->error; | 379 | struct parse_events_error *error = data->error; |
375 | struct list_head *list; | 380 | struct list_head *list; |
376 | char sys_name[128]; | ||
377 | snprintf(&sys_name, 128, "%s-%s", $1, $3); | ||
378 | 381 | ||
379 | ALLOC_LIST(list); | 382 | ALLOC_LIST(list); |
380 | if (parse_events_add_tracepoint(list, &data->idx, &sys_name, $5, error)) { | 383 | if (error) |
381 | if (error) | 384 | error->idx = @1.first_column; |
382 | error->idx = @1.first_column; | 385 | |
386 | if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, | ||
387 | error, NULL)) | ||
383 | return -1; | 388 | return -1; |
384 | } | 389 | |
385 | $$ = list; | 390 | $$ = list; |
386 | } | 391 | } |
387 | | | 392 | | |
388 | PE_NAME ':' PE_NAME | 393 | tracepoint_name '/' event_config '/' |
389 | { | 394 | { |
390 | struct parse_events_evlist *data = _data; | 395 | struct parse_events_evlist *data = _data; |
391 | struct parse_events_error *error = data->error; | 396 | struct parse_events_error *error = data->error; |
392 | struct list_head *list; | 397 | struct list_head *list; |
393 | 398 | ||
394 | ALLOC_LIST(list); | 399 | ALLOC_LIST(list); |
395 | if (parse_events_add_tracepoint(list, &data->idx, $1, $3, error)) { | 400 | if (error) |
396 | if (error) | 401 | error->idx = @1.first_column; |
397 | error->idx = @1.first_column; | 402 | |
403 | if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, | ||
404 | error, $3)) | ||
398 | return -1; | 405 | return -1; |
399 | } | 406 | |
400 | $$ = list; | 407 | $$ = list; |
401 | } | 408 | } |
402 | 409 | ||
410 | tracepoint_name: | ||
411 | PE_NAME '-' PE_NAME ':' PE_NAME | ||
412 | { | ||
413 | char sys_name[128]; | ||
414 | struct tracepoint_name tracepoint; | ||
415 | |||
416 | snprintf(&sys_name, 128, "%s-%s", $1, $3); | ||
417 | tracepoint.sys = &sys_name; | ||
418 | tracepoint.event = $5; | ||
419 | |||
420 | $$ = tracepoint; | ||
421 | } | ||
422 | | | ||
423 | PE_NAME ':' PE_NAME | ||
424 | { | ||
425 | struct tracepoint_name tracepoint = {$1, $3}; | ||
426 | |||
427 | $$ = tracepoint; | ||
428 | } | ||
429 | |||
403 | event_legacy_numeric: | 430 | event_legacy_numeric: |
404 | PE_VALUE ':' PE_VALUE | 431 | PE_VALUE ':' PE_VALUE |
405 | { | 432 | { |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 89c91a1a67e7..ac42c97be9e4 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -626,38 +626,26 @@ static int pmu_resolve_param_term(struct parse_events_term *term, | |||
626 | return -1; | 626 | return -1; |
627 | } | 627 | } |
628 | 628 | ||
629 | static char *formats_error_string(struct list_head *formats) | 629 | static char *pmu_formats_string(struct list_head *formats) |
630 | { | 630 | { |
631 | struct perf_pmu_format *format; | 631 | struct perf_pmu_format *format; |
632 | char *err, *str; | 632 | char *str; |
633 | static const char *static_terms = "config,config1,config2,name," | 633 | struct strbuf buf; |
634 | "period,freq,branch_type,time," | ||
635 | "call-graph,stack-size\n"; | ||
636 | unsigned i = 0; | 634 | unsigned i = 0; |
637 | 635 | ||
638 | if (!asprintf(&str, "valid terms:")) | 636 | if (!formats) |
639 | return NULL; | 637 | return NULL; |
640 | 638 | ||
639 | strbuf_init(&buf, 0); | ||
641 | /* sysfs exported terms */ | 640 | /* sysfs exported terms */ |
642 | list_for_each_entry(format, formats, list) { | 641 | list_for_each_entry(format, formats, list) |
643 | char c = i++ ? ',' : ' '; | 642 | strbuf_addf(&buf, i++ ? ",%s" : "%s", |
644 | 643 | format->name); | |
645 | err = str; | ||
646 | if (!asprintf(&str, "%s%c%s", err, c, format->name)) | ||
647 | goto fail; | ||
648 | free(err); | ||
649 | } | ||
650 | 644 | ||
651 | /* static terms */ | 645 | str = strbuf_detach(&buf, NULL); |
652 | err = str; | 646 | strbuf_release(&buf); |
653 | if (!asprintf(&str, "%s,%s", err, static_terms)) | ||
654 | goto fail; | ||
655 | 647 | ||
656 | free(err); | ||
657 | return str; | 648 | return str; |
658 | fail: | ||
659 | free(err); | ||
660 | return NULL; | ||
661 | } | 649 | } |
662 | 650 | ||
663 | /* | 651 | /* |
@@ -693,9 +681,12 @@ static int pmu_config_term(struct list_head *formats, | |||
693 | if (verbose) | 681 | if (verbose) |
694 | printf("Invalid event/parameter '%s'\n", term->config); | 682 | printf("Invalid event/parameter '%s'\n", term->config); |
695 | if (err) { | 683 | if (err) { |
684 | char *pmu_term = pmu_formats_string(formats); | ||
685 | |||
696 | err->idx = term->err_term; | 686 | err->idx = term->err_term; |
697 | err->str = strdup("unknown term"); | 687 | err->str = strdup("unknown term"); |
698 | err->help = formats_error_string(formats); | 688 | err->help = parse_events_formats_error_string(pmu_term); |
689 | free(pmu_term); | ||
699 | } | 690 | } |
700 | return -EINVAL; | 691 | return -EINVAL; |
701 | } | 692 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index aa9e1257c1ee..a8e825fca42a 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -319,7 +319,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample, | |||
319 | 319 | ||
320 | if (thread__resolve_callchain(al->thread, evsel, | 320 | if (thread__resolve_callchain(al->thread, evsel, |
321 | sample, NULL, NULL, | 321 | sample, NULL, NULL, |
322 | PERF_MAX_STACK_DEPTH) != 0) { | 322 | scripting_max_stack) != 0) { |
323 | pr_err("Failed to resolve callchain. Skipping\n"); | 323 | pr_err("Failed to resolve callchain. Skipping\n"); |
324 | goto exit; | 324 | goto exit; |
325 | } | 325 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f5e000030a5e..84a02eae4394 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1101,6 +1101,9 @@ static int machines__deliver_event(struct machines *machines, | |||
1101 | case PERF_RECORD_UNTHROTTLE: | 1101 | case PERF_RECORD_UNTHROTTLE: |
1102 | return tool->unthrottle(tool, event, sample, machine); | 1102 | return tool->unthrottle(tool, event, sample, machine); |
1103 | case PERF_RECORD_AUX: | 1103 | case PERF_RECORD_AUX: |
1104 | if (tool->aux == perf_event__process_aux && | ||
1105 | (event->aux.flags & PERF_AUX_FLAG_TRUNCATED)) | ||
1106 | evlist->stats.total_aux_lost += 1; | ||
1104 | return tool->aux(tool, event, sample, machine); | 1107 | return tool->aux(tool, event, sample, machine); |
1105 | case PERF_RECORD_ITRACE_START: | 1108 | case PERF_RECORD_ITRACE_START: |
1106 | return tool->itrace_start(tool, event, sample, machine); | 1109 | return tool->itrace_start(tool, event, sample, machine); |
@@ -1346,6 +1349,13 @@ static void perf_session__warn_about_errors(const struct perf_session *session) | |||
1346 | } | 1349 | } |
1347 | } | 1350 | } |
1348 | 1351 | ||
1352 | if (session->tool->aux == perf_event__process_aux && | ||
1353 | stats->total_aux_lost != 0) { | ||
1354 | ui__warning("AUX data lost %" PRIu64 " times out of %u!\n\n", | ||
1355 | stats->total_aux_lost, | ||
1356 | stats->nr_events[PERF_RECORD_AUX]); | ||
1357 | } | ||
1358 | |||
1349 | if (stats->nr_unknown_events != 0) { | 1359 | if (stats->nr_unknown_events != 0) { |
1350 | ui__warning("Found %u unknown events!\n\n" | 1360 | ui__warning("Found %u unknown events!\n\n" |
1351 | "Is this an older tool processing a perf.data " | 1361 | "Is this an older tool processing a perf.data " |
@@ -1790,7 +1800,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | |||
1790 | 1800 | ||
1791 | if (thread__resolve_callchain(al->thread, evsel, | 1801 | if (thread__resolve_callchain(al->thread, evsel, |
1792 | sample, NULL, NULL, | 1802 | sample, NULL, NULL, |
1793 | PERF_MAX_STACK_DEPTH) != 0) { | 1803 | stack_depth) != 0) { |
1794 | if (verbose) | 1804 | if (verbose) |
1795 | error("Failed to resolve callchain. Skipping\n"); | 1805 | error("Failed to resolve callchain. Skipping\n"); |
1796 | return; | 1806 | return; |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index da6cc4cc2a4f..b85ee55cca0c 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -78,6 +78,8 @@ struct scripting_ops { | |||
78 | int (*generate_script) (struct pevent *pevent, const char *outfile); | 78 | int (*generate_script) (struct pevent *pevent, const char *outfile); |
79 | }; | 79 | }; |
80 | 80 | ||
81 | extern unsigned int scripting_max_stack; | ||
82 | |||
81 | int script_spec_register(const char *spec, struct scripting_ops *ops); | 83 | int script_spec_register(const char *spec, struct scripting_ops *ops); |
82 | 84 | ||
83 | void setup_perl_scripting(void); | 85 | void setup_perl_scripting(void); |