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 /tools | |
| 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>
Diffstat (limited to 'tools')
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); |
