diff options
author | Ingo Molnar <mingo@kernel.org> | 2017-07-26 13:07:30 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-07-26 13:07:30 -0400 |
commit | ee438ec8f33c5af0d4a4ffb935c5b9272e8c2680 (patch) | |
tree | d95fe900307968a2874b5cd64e09bbb378c77e23 | |
parent | 510457ec9dc259b002879bcfe475f89d4514a0fc (diff) | |
parent | 62e6039f02888efdd824e8c596c4927616a97ce3 (diff) |
Merge tag 'perf-core-for-mingo-4.14-20170725' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvemends and fixes for v4.14:
New features:
- Filter out 'sshd' in the tracer ancestry in 'perf trace' syswide tracing,
to elliminate tracing loops (Arnaldo Carvalho de Melo)
- Support lookup of symbols in other mount namespaces in 'perf top' (Krister Johansen)
- Initial 'clone' syscall args beautifier in 'perf trace' (Arnaldo Carvalho de Melo)
User visible changes:
- Ignore 'fd' and 'offset' args for MAP_ANONYMOUS in 'perf trace'
(Arnaldo Carvalho de Melo)
- Process tracing data in 'perf annotate' pipe mode (David Carrillo-Cisneros)
- Make 'perf report --branch-history' work without callgraphs(-g) option
in perf record (Jin Yao)
- Tag branch type/flag on "to" and tag cycles on "from" in 'perf report' (Jin Yao)
Fixes:
- Fix jvmti linker error when libelf config is disabled (Sudeep Holla)
- Fix cgroups refcount usage (Arnaldo Carvalho de Melo)
- Fix kernel symbol adjustment for s390x (Thomas Richter)
- Fix 'perf report --stdio --show-total-period', it was showing the
number of samples, not the total period (Taeung Song)
Infrastructure changes:
- Add perf_sample dictionary to tracepoint handlers in 'perf script'
python, which were already present for other types of events
(hardware, etc) (Arun Kalyanasundaram)
- Make build fail on vendor events JSON parse error (Andi Kleen)
- Adopt strstarts() from the kernel (Arnaldo Carvalho de Melo)
Arch specific changes:
- Set no_aux_samples for the tracking event in Intel PT (Kan Liang)
- Always set no branch for Intel PT dummy event (Kan Liang)
Trivial changes:
- Simplify some error handlers in 'perf script' (Dan Carpenter)
- Add EXCLUDE_EXTLIBS and EXTRA_PERFLIBS to makefile (David Carrillo-Cisneros)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
43 files changed, 798 insertions, 300 deletions
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index d62b56cf8c12..a30fad536f52 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h | |||
@@ -1,8 +1,8 @@ | |||
1 | #ifndef _TOOLS_LINUX_STRING_H_ | 1 | #ifndef _TOOLS_LINUX_STRING_H_ |
2 | #define _TOOLS_LINUX_STRING_H_ | 2 | #define _TOOLS_LINUX_STRING_H_ |
3 | 3 | ||
4 | |||
5 | #include <linux/types.h> /* for size_t */ | 4 | #include <linux/types.h> /* for size_t */ |
5 | #include <string.h> | ||
6 | 6 | ||
7 | void *memdup(const void *src, size_t len); | 7 | void *memdup(const void *src, size_t len); |
8 | 8 | ||
@@ -18,6 +18,14 @@ extern size_t strlcpy(char *dest, const char *src, size_t size); | |||
18 | 18 | ||
19 | char *str_error_r(int errnum, char *buf, size_t buflen); | 19 | char *str_error_r(int errnum, char *buf, size_t buflen); |
20 | 20 | ||
21 | int prefixcmp(const char *str, const char *prefix); | 21 | /** |
22 | * strstarts - does @str start with @prefix? | ||
23 | * @str: string to examine | ||
24 | * @prefix: prefix to look for. | ||
25 | */ | ||
26 | static inline bool strstarts(const char *str, const char *prefix) | ||
27 | { | ||
28 | return strncmp(str, prefix, strlen(prefix)) == 0; | ||
29 | } | ||
22 | 30 | ||
23 | #endif /* _LINUX_STRING_H_ */ | 31 | #endif /* _LINUX_STRING_H_ */ |
diff --git a/tools/include/uapi/linux/sched.h b/tools/include/uapi/linux/sched.h new file mode 100644 index 000000000000..e2a6c7b3510b --- /dev/null +++ b/tools/include/uapi/linux/sched.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifndef _UAPI_LINUX_SCHED_H | ||
2 | #define _UAPI_LINUX_SCHED_H | ||
3 | |||
4 | /* | ||
5 | * cloning flags: | ||
6 | */ | ||
7 | #define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ | ||
8 | #define CLONE_VM 0x00000100 /* set if VM shared between processes */ | ||
9 | #define CLONE_FS 0x00000200 /* set if fs info shared between processes */ | ||
10 | #define CLONE_FILES 0x00000400 /* set if open files shared between processes */ | ||
11 | #define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ | ||
12 | #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ | ||
13 | #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ | ||
14 | #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ | ||
15 | #define CLONE_THREAD 0x00010000 /* Same thread group? */ | ||
16 | #define CLONE_NEWNS 0x00020000 /* New mount namespace group */ | ||
17 | #define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ | ||
18 | #define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ | ||
19 | #define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */ | ||
20 | #define CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */ | ||
21 | #define CLONE_DETACHED 0x00400000 /* Unused, ignored */ | ||
22 | #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ | ||
23 | #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ | ||
24 | #define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ | ||
25 | #define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ | ||
26 | #define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ | ||
27 | #define CLONE_NEWUSER 0x10000000 /* New user namespace */ | ||
28 | #define CLONE_NEWPID 0x20000000 /* New pid namespace */ | ||
29 | #define CLONE_NEWNET 0x40000000 /* New network namespace */ | ||
30 | #define CLONE_IO 0x80000000 /* Clone io context */ | ||
31 | |||
32 | /* | ||
33 | * Scheduling policies | ||
34 | */ | ||
35 | #define SCHED_NORMAL 0 | ||
36 | #define SCHED_FIFO 1 | ||
37 | #define SCHED_RR 2 | ||
38 | #define SCHED_BATCH 3 | ||
39 | /* SCHED_ISO: reserved but not implemented yet */ | ||
40 | #define SCHED_IDLE 5 | ||
41 | #define SCHED_DEADLINE 6 | ||
42 | |||
43 | /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ | ||
44 | #define SCHED_RESET_ON_FORK 0x40000000 | ||
45 | |||
46 | /* | ||
47 | * For the sched_{set,get}attr() calls | ||
48 | */ | ||
49 | #define SCHED_FLAG_RESET_ON_FORK 0x01 | ||
50 | #define SCHED_FLAG_RECLAIM 0x02 | ||
51 | |||
52 | #endif /* _UAPI_LINUX_SCHED_H */ | ||
diff --git a/tools/lib/string.c b/tools/lib/string.c index 8e678af1c6ee..a4246f14ded1 100644 --- a/tools/lib/string.c +++ b/tools/lib/string.c | |||
@@ -39,27 +39,45 @@ void *memdup(const void *src, size_t len) | |||
39 | * @s: input string | 39 | * @s: input string |
40 | * @res: result | 40 | * @res: result |
41 | * | 41 | * |
42 | * This routine returns 0 iff the first character is one of 'Yy1Nn0'. | 42 | * This routine returns 0 iff the first character is one of 'Yy1Nn0', or |
43 | * Otherwise it will return -EINVAL. Value pointed to by res is | 43 | * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value |
44 | * updated upon finding a match. | 44 | * pointed to by res is updated upon finding a match. |
45 | */ | 45 | */ |
46 | int strtobool(const char *s, bool *res) | 46 | int strtobool(const char *s, bool *res) |
47 | { | 47 | { |
48 | if (!s) | ||
49 | return -EINVAL; | ||
50 | |||
48 | switch (s[0]) { | 51 | switch (s[0]) { |
49 | case 'y': | 52 | case 'y': |
50 | case 'Y': | 53 | case 'Y': |
51 | case '1': | 54 | case '1': |
52 | *res = true; | 55 | *res = true; |
53 | break; | 56 | return 0; |
54 | case 'n': | 57 | case 'n': |
55 | case 'N': | 58 | case 'N': |
56 | case '0': | 59 | case '0': |
57 | *res = false; | 60 | *res = false; |
58 | break; | 61 | return 0; |
62 | case 'o': | ||
63 | case 'O': | ||
64 | switch (s[1]) { | ||
65 | case 'n': | ||
66 | case 'N': | ||
67 | *res = true; | ||
68 | return 0; | ||
69 | case 'f': | ||
70 | case 'F': | ||
71 | *res = false; | ||
72 | return 0; | ||
73 | default: | ||
74 | break; | ||
75 | } | ||
59 | default: | 76 | default: |
60 | return -EINVAL; | 77 | break; |
61 | } | 78 | } |
62 | return 0; | 79 | |
80 | return -EINVAL; | ||
63 | } | 81 | } |
64 | 82 | ||
65 | /** | 83 | /** |
@@ -87,12 +105,3 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) | |||
87 | } | 105 | } |
88 | return ret; | 106 | return ret; |
89 | } | 107 | } |
90 | |||
91 | int prefixcmp(const char *str, const char *prefix) | ||
92 | { | ||
93 | for (; ; str++, prefix++) | ||
94 | if (!*prefix) | ||
95 | return 0; | ||
96 | else if (*str != *prefix) | ||
97 | return (unsigned char)*prefix - (unsigned char)*str; | ||
98 | } | ||
diff --git a/tools/lib/subcmd/help.c b/tools/lib/subcmd/help.c index ba970a73d053..0310520f918e 100644 --- a/tools/lib/subcmd/help.c +++ b/tools/lib/subcmd/help.c | |||
@@ -171,7 +171,7 @@ static void list_commands_in_dir(struct cmdnames *cmds, | |||
171 | while ((de = readdir(dir)) != NULL) { | 171 | while ((de = readdir(dir)) != NULL) { |
172 | int entlen; | 172 | int entlen; |
173 | 173 | ||
174 | if (prefixcmp(de->d_name, prefix)) | 174 | if (!strstarts(de->d_name, prefix)) |
175 | continue; | 175 | continue; |
176 | 176 | ||
177 | astrcat(&buf, de->d_name); | 177 | astrcat(&buf, de->d_name); |
diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c index 359bfa77f39c..2bd6fd0c1d40 100644 --- a/tools/lib/subcmd/parse-options.c +++ b/tools/lib/subcmd/parse-options.c | |||
@@ -368,7 +368,7 @@ retry: | |||
368 | return 0; | 368 | return 0; |
369 | } | 369 | } |
370 | if (!rest) { | 370 | if (!rest) { |
371 | if (!prefixcmp(options->long_name, "no-")) { | 371 | if (strstarts(options->long_name, "no-")) { |
372 | /* | 372 | /* |
373 | * The long name itself starts with "no-", so | 373 | * The long name itself starts with "no-", so |
374 | * accept the option without "no-" so that users | 374 | * accept the option without "no-" so that users |
@@ -381,7 +381,7 @@ retry: | |||
381 | goto match; | 381 | goto match; |
382 | } | 382 | } |
383 | /* Abbreviated case */ | 383 | /* Abbreviated case */ |
384 | if (!prefixcmp(options->long_name + 3, arg)) { | 384 | if (strstarts(options->long_name + 3, arg)) { |
385 | flags |= OPT_UNSET; | 385 | flags |= OPT_UNSET; |
386 | goto is_abbreviated; | 386 | goto is_abbreviated; |
387 | } | 387 | } |
@@ -406,7 +406,7 @@ is_abbreviated: | |||
406 | continue; | 406 | continue; |
407 | } | 407 | } |
408 | /* negated and abbreviated very much? */ | 408 | /* negated and abbreviated very much? */ |
409 | if (!prefixcmp("no-", arg)) { | 409 | if (strstarts("no-", arg)) { |
410 | flags |= OPT_UNSET; | 410 | flags |= OPT_UNSET; |
411 | goto is_abbreviated; | 411 | goto is_abbreviated; |
412 | } | 412 | } |
@@ -416,7 +416,7 @@ is_abbreviated: | |||
416 | flags |= OPT_UNSET; | 416 | flags |= OPT_UNSET; |
417 | rest = skip_prefix(arg + 3, options->long_name); | 417 | rest = skip_prefix(arg + 3, options->long_name); |
418 | /* abbreviated and negated? */ | 418 | /* abbreviated and negated? */ |
419 | if (!rest && !prefixcmp(options->long_name, arg + 3)) | 419 | if (!rest && strstarts(options->long_name, arg + 3)) |
420 | goto is_abbreviated; | 420 | goto is_abbreviated; |
421 | if (!rest) | 421 | if (!rest) |
422 | continue; | 422 | continue; |
@@ -456,7 +456,7 @@ static void check_typos(const char *arg, const struct option *options) | |||
456 | if (strlen(arg) < 3) | 456 | if (strlen(arg) < 3) |
457 | return; | 457 | return; |
458 | 458 | ||
459 | if (!prefixcmp(arg, "no-")) { | 459 | if (strstarts(arg, "no-")) { |
460 | fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); | 460 | fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); |
461 | exit(129); | 461 | exit(129); |
462 | } | 462 | } |
@@ -464,7 +464,7 @@ static void check_typos(const char *arg, const struct option *options) | |||
464 | for (; options->type != OPTION_END; options++) { | 464 | for (; options->type != OPTION_END; options++) { |
465 | if (!options->long_name) | 465 | if (!options->long_name) |
466 | continue; | 466 | continue; |
467 | if (!prefixcmp(options->long_name, arg)) { | 467 | if (strstarts(options->long_name, arg)) { |
468 | fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); | 468 | fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); |
469 | exit(129); | 469 | exit(129); |
470 | } | 470 | } |
@@ -933,10 +933,10 @@ opt: | |||
933 | if (opts->long_name == NULL) | 933 | if (opts->long_name == NULL) |
934 | continue; | 934 | continue; |
935 | 935 | ||
936 | if (!prefixcmp(opts->long_name, optstr)) | 936 | if (strstarts(opts->long_name, optstr)) |
937 | print_option_help(opts, 0); | 937 | print_option_help(opts, 0); |
938 | if (!prefixcmp("no-", optstr) && | 938 | if (strstarts("no-", optstr) && |
939 | !prefixcmp(opts->long_name, optstr + 3)) | 939 | strstarts(opts->long_name, optstr + 3)) |
940 | print_option_help(opts, 0); | 940 | print_option_help(opts, 0); |
941 | } | 941 | } |
942 | 942 | ||
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index e71d63843f45..d864ea6fd367 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -237,6 +237,10 @@ Default is to monitor all CPUS. | |||
237 | --hierarchy:: | 237 | --hierarchy:: |
238 | Enable hierarchy output. | 238 | Enable hierarchy output. |
239 | 239 | ||
240 | --force:: | ||
241 | Don't do ownership validation. | ||
242 | |||
243 | |||
240 | INTERACTIVE PROMPTING KEYS | 244 | INTERACTIVE PROMPTING KEYS |
241 | -------------------------- | 245 | -------------------------- |
242 | 246 | ||
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index a29da46d180f..705bdb147e73 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -70,6 +70,7 @@ tools/include/linux/hash.h | |||
70 | tools/include/linux/kernel.h | 70 | tools/include/linux/kernel.h |
71 | tools/include/linux/list.h | 71 | tools/include/linux/list.h |
72 | tools/include/linux/log2.h | 72 | tools/include/linux/log2.h |
73 | tools/include/uapi/asm-generic/fcntl.h | ||
73 | tools/include/uapi/asm-generic/mman-common.h | 74 | tools/include/uapi/asm-generic/mman-common.h |
74 | tools/include/uapi/asm-generic/mman.h | 75 | tools/include/uapi/asm-generic/mman.h |
75 | tools/include/uapi/linux/bpf.h | 76 | tools/include/uapi/linux/bpf.h |
@@ -78,6 +79,7 @@ tools/include/uapi/linux/fcntl.h | |||
78 | tools/include/uapi/linux/hw_breakpoint.h | 79 | tools/include/uapi/linux/hw_breakpoint.h |
79 | tools/include/uapi/linux/mman.h | 80 | tools/include/uapi/linux/mman.h |
80 | tools/include/uapi/linux/perf_event.h | 81 | tools/include/uapi/linux/perf_event.h |
82 | tools/include/uapi/linux/sched.h | ||
81 | tools/include/uapi/linux/stat.h | 83 | tools/include/uapi/linux/stat.h |
82 | tools/include/linux/poison.h | 84 | tools/include/linux/poison.h |
83 | tools/include/linux/rbtree.h | 85 | tools/include/linux/rbtree.h |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5008f51a08a2..d66f90e6be5c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -33,6 +33,11 @@ include ../scripts/utilities.mak | |||
33 | # | 33 | # |
34 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 34 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
35 | # | 35 | # |
36 | # Define EXCLUDE_EXTLIBS=-lmylib to exclude libmylib from the auto-generated | ||
37 | # EXTLIBS. | ||
38 | # | ||
39 | # Define EXTRA_PERFLIBS to pass extra libraries to PERFLIBS. | ||
40 | # | ||
36 | # Define NO_DWARF if you do not want debug-info analysis feature at all. | 41 | # Define NO_DWARF if you do not want debug-info analysis feature at all. |
37 | # | 42 | # |
38 | # Define WERROR=0 to disable treating any warnings as errors. | 43 | # Define WERROR=0 to disable treating any warnings as errors. |
@@ -352,7 +357,8 @@ ifdef ASCIIDOC8 | |||
352 | export ASCIIDOC8 | 357 | export ASCIIDOC8 |
353 | endif | 358 | endif |
354 | 359 | ||
355 | LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group | 360 | EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS)) |
361 | LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group | ||
356 | 362 | ||
357 | ifeq ($(USE_CLANG), 1) | 363 | ifeq ($(USE_CLANG), 1) |
358 | CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization | 364 | CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization |
@@ -512,7 +518,7 @@ $(LIBJVMTI_IN): FORCE | |||
512 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=jvmti obj=jvmti | 518 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=jvmti obj=jvmti |
513 | 519 | ||
514 | $(OUTPUT)$(LIBJVMTI): $(LIBJVMTI_IN) | 520 | $(OUTPUT)$(LIBJVMTI): $(LIBJVMTI_IN) |
515 | $(QUIET_LINK)$(CC) -shared -Wl,-soname -Wl,$(LIBJVMTI) -o $@ $< -lelf -lrt | 521 | $(QUIET_LINK)$(CC) -shared -Wl,-soname -Wl,$(LIBJVMTI) -o $@ $< |
516 | endif | 522 | endif |
517 | 523 | ||
518 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) | 524 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) |
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 5bd7b9260cc0..bd518b623d7a 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build | |||
@@ -1,4 +1,5 @@ | |||
1 | libperf-y += header.o | 1 | libperf-y += header.o |
2 | libperf-y += sym-handling.o | ||
2 | libperf-y += kvm-stat.o | 3 | libperf-y += kvm-stat.o |
3 | 4 | ||
4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 5 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
diff --git a/tools/perf/arch/s390/util/sym-handling.c b/tools/perf/arch/s390/util/sym-handling.c new file mode 100644 index 000000000000..b6cd056ccf71 --- /dev/null +++ b/tools/perf/arch/s390/util/sym-handling.c | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Architecture specific ELF symbol handling and relocation mapping. | ||
3 | * | ||
4 | * Copyright 2017 IBM Corp. | ||
5 | * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License (version 2 only) | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include "symbol.h" | ||
13 | |||
14 | #ifdef HAVE_LIBELF_SUPPORT | ||
15 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) | ||
16 | { | ||
17 | if (ehdr.e_type == ET_EXEC) | ||
18 | return false; | ||
19 | return ehdr.e_type == ET_REL || ehdr.e_type == ET_DYN; | ||
20 | } | ||
21 | |||
22 | #endif | ||
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 9535be57033f..db0ba8caf5a2 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c | |||
@@ -701,6 +701,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, | |||
701 | perf_evsel__set_sample_bit(switch_evsel, TID); | 701 | perf_evsel__set_sample_bit(switch_evsel, TID); |
702 | perf_evsel__set_sample_bit(switch_evsel, TIME); | 702 | perf_evsel__set_sample_bit(switch_evsel, TIME); |
703 | perf_evsel__set_sample_bit(switch_evsel, CPU); | 703 | perf_evsel__set_sample_bit(switch_evsel, CPU); |
704 | perf_evsel__reset_sample_bit(switch_evsel, BRANCH_STACK); | ||
704 | 705 | ||
705 | opts->record_switch_events = false; | 706 | opts->record_switch_events = false; |
706 | ptr->have_sched_switch = 3; | 707 | ptr->have_sched_switch = 3; |
@@ -752,6 +753,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, | |||
752 | tracking_evsel->attr.freq = 0; | 753 | tracking_evsel->attr.freq = 0; |
753 | tracking_evsel->attr.sample_period = 1; | 754 | tracking_evsel->attr.sample_period = 1; |
754 | 755 | ||
756 | tracking_evsel->no_aux_samples = true; | ||
755 | if (need_immediate) | 757 | if (need_immediate) |
756 | tracking_evsel->immediate = true; | 758 | tracking_evsel->immediate = true; |
757 | 759 | ||
@@ -761,6 +763,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, | |||
761 | /* And the CPU for switch events */ | 763 | /* And the CPU for switch events */ |
762 | perf_evsel__set_sample_bit(tracking_evsel, CPU); | 764 | perf_evsel__set_sample_bit(tracking_evsel, CPU); |
763 | } | 765 | } |
766 | perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK); | ||
764 | } | 767 | } |
765 | 768 | ||
766 | /* | 769 | /* |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5205408e795b..6db782dfce96 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -177,14 +177,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
177 | */ | 177 | */ |
178 | process_branch_stack(sample->branch_stack, al, sample); | 178 | process_branch_stack(sample->branch_stack, al, sample); |
179 | 179 | ||
180 | sample->period = 1; | ||
181 | sample->weight = 1; | 180 | sample->weight = 1; |
182 | 181 | ||
183 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | 182 | he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); |
184 | if (he == NULL) | 183 | if (he == NULL) |
185 | return -ENOMEM; | 184 | return -ENOMEM; |
186 | 185 | ||
187 | ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 186 | ret = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); |
188 | hists__inc_nr_samples(hists, true); | 187 | hists__inc_nr_samples(hists, true); |
189 | return ret; | 188 | return ret; |
190 | } | 189 | } |
@@ -397,6 +396,7 @@ int cmd_annotate(int argc, const char **argv) | |||
397 | .namespaces = perf_event__process_namespaces, | 396 | .namespaces = perf_event__process_namespaces, |
398 | .attr = perf_event__process_attr, | 397 | .attr = perf_event__process_attr, |
399 | .build_id = perf_event__process_build_id, | 398 | .build_id = perf_event__process_build_id, |
399 | .tracing_data = perf_event__process_tracing_data, | ||
400 | .feature = perf_event__process_feature, | 400 | .feature = perf_event__process_feature, |
401 | .ordered_events = true, | 401 | .ordered_events = true, |
402 | .ordering_requires_timestamps = true, | 402 | .ordering_requires_timestamps = true, |
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index ece45582a48d..3ddcc6e2abeb 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "util/util.h" | 13 | #include "util/util.h" |
14 | #include "util/debug.h" | 14 | #include "util/debug.h" |
15 | #include "util/config.h" | 15 | #include "util/config.h" |
16 | #include <linux/string.h> | ||
16 | 17 | ||
17 | static bool use_system_config, use_user_config; | 18 | static bool use_system_config, use_user_config; |
18 | 19 | ||
@@ -79,7 +80,7 @@ static int show_spec_config(struct perf_config_set *set, const char *var) | |||
79 | return -1; | 80 | return -1; |
80 | 81 | ||
81 | perf_config_items__for_each_entry(&set->sections, section) { | 82 | perf_config_items__for_each_entry(&set->sections, section) { |
82 | if (prefixcmp(var, section->name) != 0) | 83 | if (!strstarts(var, section->name)) |
83 | continue; | 84 | continue; |
84 | 85 | ||
85 | perf_config_items__for_each_entry(§ion->items, item) { | 86 | perf_config_items__for_each_entry(§ion->items, item) { |
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index dd26c62c9893..25a42acabee1 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c | |||
@@ -381,7 +381,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) | |||
381 | { | 381 | { |
382 | struct perf_ftrace *ftrace = cb; | 382 | struct perf_ftrace *ftrace = cb; |
383 | 383 | ||
384 | if (prefixcmp(var, "ftrace.")) | 384 | if (!strstarts(var, "ftrace.")) |
385 | return 0; | 385 | return 0; |
386 | 386 | ||
387 | if (strcmp(var, "ftrace.tracer")) | 387 | if (strcmp(var, "ftrace.tracer")) |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 530a7f2fa0f3..dbe4e4153bcf 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -90,7 +90,7 @@ static int check_emacsclient_version(void) | |||
90 | */ | 90 | */ |
91 | finish_command(&ec_process); | 91 | finish_command(&ec_process); |
92 | 92 | ||
93 | if (prefixcmp(buffer.buf, "emacsclient")) { | 93 | if (!strstarts(buffer.buf, "emacsclient")) { |
94 | fprintf(stderr, "Failed to parse emacsclient version.\n"); | 94 | fprintf(stderr, "Failed to parse emacsclient version.\n"); |
95 | goto out; | 95 | goto out; |
96 | } | 96 | } |
@@ -283,7 +283,7 @@ static int perf_help_config(const char *var, const char *value, void *cb) | |||
283 | add_man_viewer(value); | 283 | add_man_viewer(value); |
284 | return 0; | 284 | return 0; |
285 | } | 285 | } |
286 | if (!prefixcmp(var, "man.")) | 286 | if (!strstarts(var, "man.")) |
287 | return add_man_viewer_info(var, value); | 287 | return add_man_viewer_info(var, value); |
288 | 288 | ||
289 | return 0; | 289 | return 0; |
@@ -313,7 +313,7 @@ static const char *cmd_to_page(const char *perf_cmd) | |||
313 | 313 | ||
314 | if (!perf_cmd) | 314 | if (!perf_cmd) |
315 | return "perf"; | 315 | return "perf"; |
316 | else if (!prefixcmp(perf_cmd, "perf")) | 316 | else if (!strstarts(perf_cmd, "perf")) |
317 | return perf_cmd; | 317 | return perf_cmd; |
318 | 318 | ||
319 | return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s; | 319 | return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cea25d03f4dd..bace3429c030 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -115,37 +115,38 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, | |||
115 | struct report *rep = arg; | 115 | struct report *rep = arg; |
116 | struct hist_entry *he = iter->he; | 116 | struct hist_entry *he = iter->he; |
117 | struct perf_evsel *evsel = iter->evsel; | 117 | struct perf_evsel *evsel = iter->evsel; |
118 | struct perf_sample *sample = iter->sample; | ||
118 | struct mem_info *mi; | 119 | struct mem_info *mi; |
119 | struct branch_info *bi; | 120 | struct branch_info *bi; |
120 | 121 | ||
121 | if (!ui__has_annotation()) | 122 | if (!ui__has_annotation()) |
122 | return 0; | 123 | return 0; |
123 | 124 | ||
124 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 125 | hist__account_cycles(sample->branch_stack, al, sample, |
125 | rep->nonany_branch_mode); | 126 | rep->nonany_branch_mode); |
126 | 127 | ||
127 | if (sort__mode == SORT_MODE__BRANCH) { | 128 | if (sort__mode == SORT_MODE__BRANCH) { |
128 | bi = he->branch_info; | 129 | bi = he->branch_info; |
129 | err = addr_map_symbol__inc_samples(&bi->from, evsel->idx); | 130 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); |
130 | if (err) | 131 | if (err) |
131 | goto out; | 132 | goto out; |
132 | 133 | ||
133 | err = addr_map_symbol__inc_samples(&bi->to, evsel->idx); | 134 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); |
134 | 135 | ||
135 | } else if (rep->mem_mode) { | 136 | } else if (rep->mem_mode) { |
136 | mi = he->mem_info; | 137 | mi = he->mem_info; |
137 | err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx); | 138 | err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel->idx); |
138 | if (err) | 139 | if (err) |
139 | goto out; | 140 | goto out; |
140 | 141 | ||
141 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 142 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); |
142 | 143 | ||
143 | } else if (symbol_conf.cumulate_callchain) { | 144 | } else if (symbol_conf.cumulate_callchain) { |
144 | if (single) | 145 | if (single) |
145 | err = hist_entry__inc_addr_samples(he, evsel->idx, | 146 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, |
146 | al->addr); | 147 | al->addr); |
147 | } else { | 148 | } else { |
148 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 149 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); |
149 | } | 150 | } |
150 | 151 | ||
151 | out: | 152 | out: |
@@ -278,10 +279,11 @@ static int report__setup_sample_type(struct report *rep) | |||
278 | "'perf record' without -g?\n"); | 279 | "'perf record' without -g?\n"); |
279 | return -EINVAL; | 280 | return -EINVAL; |
280 | } | 281 | } |
281 | if (symbol_conf.use_callchain) { | 282 | if (symbol_conf.use_callchain && |
282 | ui__error("Selected -g or --branch-history but no " | 283 | !symbol_conf.show_branchflag_count) { |
283 | "callchain data. Did\n" | 284 | ui__error("Selected -g or --branch-history.\n" |
284 | "you call 'perf record' without -g?\n"); | 285 | "But no callchain or branch data.\n" |
286 | "Did you call 'perf record' without -g or -b?\n"); | ||
285 | return -1; | 287 | return -1; |
286 | } | 288 | } |
287 | } else if (!callchain_param.enabled && | 289 | } else if (!callchain_param.enabled && |
@@ -416,7 +418,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
416 | 418 | ||
417 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); | 419 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); |
418 | hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, | 420 | hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, |
419 | symbol_conf.use_callchain); | 421 | symbol_conf.use_callchain || |
422 | symbol_conf.show_branchflag_count); | ||
420 | fprintf(stdout, "\n\n"); | 423 | fprintf(stdout, "\n\n"); |
421 | } | 424 | } |
422 | 425 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d430ff42208a..378f76cdf923 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -2199,16 +2199,11 @@ static struct script_desc *script_desc__findnew(const char *name) | |||
2199 | 2199 | ||
2200 | s = script_desc__new(name); | 2200 | s = script_desc__new(name); |
2201 | if (!s) | 2201 | if (!s) |
2202 | goto out_delete_desc; | 2202 | return NULL; |
2203 | 2203 | ||
2204 | script_desc__add(s); | 2204 | script_desc__add(s); |
2205 | 2205 | ||
2206 | return s; | 2206 | return s; |
2207 | |||
2208 | out_delete_desc: | ||
2209 | script_desc__delete(s); | ||
2210 | |||
2211 | return NULL; | ||
2212 | } | 2207 | } |
2213 | 2208 | ||
2214 | static const char *ends_with(const char *str, const char *suffix) | 2209 | static const char *ends_with(const char *str, const char *suffix) |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 022486dc67f5..ee954bde7e3e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -183,6 +183,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) | |||
183 | 183 | ||
184 | static void perf_top__record_precise_ip(struct perf_top *top, | 184 | static void perf_top__record_precise_ip(struct perf_top *top, |
185 | struct hist_entry *he, | 185 | struct hist_entry *he, |
186 | struct perf_sample *sample, | ||
186 | int counter, u64 ip) | 187 | int counter, u64 ip) |
187 | { | 188 | { |
188 | struct annotation *notes; | 189 | struct annotation *notes; |
@@ -199,7 +200,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
199 | if (pthread_mutex_trylock(¬es->lock)) | 200 | if (pthread_mutex_trylock(¬es->lock)) |
200 | return; | 201 | return; |
201 | 202 | ||
202 | err = hist_entry__inc_addr_samples(he, counter, ip); | 203 | err = hist_entry__inc_addr_samples(he, sample, counter, ip); |
203 | 204 | ||
204 | pthread_mutex_unlock(¬es->lock); | 205 | pthread_mutex_unlock(¬es->lock); |
205 | 206 | ||
@@ -586,6 +587,13 @@ static void *display_thread_tui(void *arg) | |||
586 | .refresh = top->delay_secs, | 587 | .refresh = top->delay_secs, |
587 | }; | 588 | }; |
588 | 589 | ||
590 | /* In order to read symbols from other namespaces perf to needs to call | ||
591 | * setns(2). This isn't permitted if the struct_fs has multiple users. | ||
592 | * unshare(2) the fs so that we may continue to setns into namespaces | ||
593 | * that we're observing. | ||
594 | */ | ||
595 | unshare(CLONE_FS); | ||
596 | |||
589 | perf_top__sort_new_samples(top); | 597 | perf_top__sort_new_samples(top); |
590 | 598 | ||
591 | /* | 599 | /* |
@@ -627,6 +635,13 @@ static void *display_thread(void *arg) | |||
627 | struct perf_top *top = arg; | 635 | struct perf_top *top = arg; |
628 | int delay_msecs, c; | 636 | int delay_msecs, c; |
629 | 637 | ||
638 | /* In order to read symbols from other namespaces perf to needs to call | ||
639 | * setns(2). This isn't permitted if the struct_fs has multiple users. | ||
640 | * unshare(2) the fs so that we may continue to setns into namespaces | ||
641 | * that we're observing. | ||
642 | */ | ||
643 | unshare(CLONE_FS); | ||
644 | |||
630 | display_setup_sig(); | 645 | display_setup_sig(); |
631 | pthread__unblock_sigwinch(); | 646 | pthread__unblock_sigwinch(); |
632 | repeat: | 647 | repeat: |
@@ -671,7 +686,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, | |||
671 | struct perf_evsel *evsel = iter->evsel; | 686 | struct perf_evsel *evsel = iter->evsel; |
672 | 687 | ||
673 | if (perf_hpp_list.sym && single) | 688 | if (perf_hpp_list.sym && single) |
674 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); | 689 | perf_top__record_precise_ip(top, he, iter->sample, evsel->idx, al->addr); |
675 | 690 | ||
676 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 691 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, |
677 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); | 692 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); |
@@ -1205,6 +1220,7 @@ int cmd_top(int argc, const char **argv) | |||
1205 | "Show raw trace event output (do not use print fmt or plugins)"), | 1220 | "Show raw trace event output (do not use print fmt or plugins)"), |
1206 | OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, | 1221 | OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, |
1207 | "Show entries in a hierarchy"), | 1222 | "Show entries in a hierarchy"), |
1223 | OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), | ||
1208 | OPT_END() | 1224 | OPT_END() |
1209 | }; | 1225 | }; |
1210 | const char * const top_usage[] = { | 1226 | const char * const top_usage[] = { |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1e4c0657b712..05d24b6570ee 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -604,6 +604,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, | |||
604 | struct syscall_arg_fmt { | 604 | struct syscall_arg_fmt { |
605 | size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); | 605 | size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); |
606 | void *parm; | 606 | void *parm; |
607 | const char *name; | ||
607 | bool show_zero; | 608 | bool show_zero; |
608 | }; | 609 | }; |
609 | 610 | ||
@@ -611,6 +612,7 @@ static struct syscall_fmt { | |||
611 | const char *name; | 612 | const char *name; |
612 | const char *alias; | 613 | const char *alias; |
613 | struct syscall_arg_fmt arg[6]; | 614 | struct syscall_arg_fmt arg[6]; |
615 | u8 nr_args; | ||
614 | bool errpid; | 616 | bool errpid; |
615 | bool timeout; | 617 | bool timeout; |
616 | bool hexret; | 618 | bool hexret; |
@@ -624,7 +626,12 @@ static struct syscall_fmt { | |||
624 | .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, }, | 626 | .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, }, |
625 | { .name = "clock_gettime", | 627 | { .name = "clock_gettime", |
626 | .arg = { [0] = STRARRAY(clk_id, clockid), }, }, | 628 | .arg = { [0] = STRARRAY(clk_id, clockid), }, }, |
627 | { .name = "clone", .errpid = true, }, | 629 | { .name = "clone", .errpid = true, .nr_args = 5, |
630 | .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, }, | ||
631 | [1] = { .name = "child_stack", .scnprintf = SCA_HEX, }, | ||
632 | [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, }, | ||
633 | [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, }, | ||
634 | [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, }, | ||
628 | { .name = "close", | 635 | { .name = "close", |
629 | .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, | 636 | .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, |
630 | { .name = "epoll_ctl", | 637 | { .name = "epoll_ctl", |
@@ -1165,22 +1172,34 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) | |||
1165 | return err; | 1172 | return err; |
1166 | } | 1173 | } |
1167 | 1174 | ||
1168 | static int syscall__set_arg_fmts(struct syscall *sc) | 1175 | static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args) |
1169 | { | 1176 | { |
1170 | struct format_field *field; | 1177 | int idx; |
1171 | int idx = 0, len; | 1178 | |
1179 | if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0) | ||
1180 | nr_args = sc->fmt->nr_args; | ||
1172 | 1181 | ||
1173 | sc->arg_fmt = calloc(sc->nr_args, sizeof(*sc->arg_fmt)); | 1182 | sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt)); |
1174 | if (sc->arg_fmt == NULL) | 1183 | if (sc->arg_fmt == NULL) |
1175 | return -1; | 1184 | return -1; |
1176 | 1185 | ||
1177 | for (field = sc->args; field; field = field->next, ++idx) { | 1186 | for (idx = 0; idx < nr_args; ++idx) { |
1178 | if (sc->fmt) { | 1187 | if (sc->fmt) |
1179 | sc->arg_fmt[idx] = sc->fmt->arg[idx]; | 1188 | sc->arg_fmt[idx] = sc->fmt->arg[idx]; |
1189 | } | ||
1180 | 1190 | ||
1181 | if (sc->fmt->arg[idx].scnprintf) | 1191 | sc->nr_args = nr_args; |
1182 | continue; | 1192 | return 0; |
1183 | } | 1193 | } |
1194 | |||
1195 | static int syscall__set_arg_fmts(struct syscall *sc) | ||
1196 | { | ||
1197 | struct format_field *field; | ||
1198 | int idx = 0, len; | ||
1199 | |||
1200 | for (field = sc->args; field; field = field->next, ++idx) { | ||
1201 | if (sc->fmt && sc->fmt->arg[idx].scnprintf) | ||
1202 | continue; | ||
1184 | 1203 | ||
1185 | if (strcmp(field->type, "const char *") == 0 && | 1204 | if (strcmp(field->type, "const char *") == 0 && |
1186 | (strcmp(field->name, "filename") == 0 || | 1205 | (strcmp(field->name, "filename") == 0 || |
@@ -1251,11 +1270,13 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1251 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); | 1270 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1252 | } | 1271 | } |
1253 | 1272 | ||
1273 | if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields)) | ||
1274 | return -1; | ||
1275 | |||
1254 | if (IS_ERR(sc->tp_format)) | 1276 | if (IS_ERR(sc->tp_format)) |
1255 | return -1; | 1277 | return -1; |
1256 | 1278 | ||
1257 | sc->args = sc->tp_format->format.fields; | 1279 | sc->args = sc->tp_format->format.fields; |
1258 | sc->nr_args = sc->tp_format->format.nr_fields; | ||
1259 | /* | 1280 | /* |
1260 | * We need to check and discard the first variable '__syscall_nr' | 1281 | * We need to check and discard the first variable '__syscall_nr' |
1261 | * or 'nr' that mean the syscall number. It is needless here. | 1282 | * or 'nr' that mean the syscall number. It is needless here. |
@@ -1325,18 +1346,34 @@ out: | |||
1325 | * variable to read it. Most notably this avoids extended load instructions | 1346 | * variable to read it. Most notably this avoids extended load instructions |
1326 | * on unaligned addresses | 1347 | * on unaligned addresses |
1327 | */ | 1348 | */ |
1328 | static unsigned long __syscall_arg__val(unsigned char *args, u8 idx) | 1349 | unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx) |
1329 | { | 1350 | { |
1330 | unsigned long val; | 1351 | unsigned long val; |
1331 | unsigned char *p = args + sizeof(unsigned long) * idx; | 1352 | unsigned char *p = arg->args + sizeof(unsigned long) * idx; |
1332 | 1353 | ||
1333 | memcpy(&val, p, sizeof(val)); | 1354 | memcpy(&val, p, sizeof(val)); |
1334 | return val; | 1355 | return val; |
1335 | } | 1356 | } |
1336 | 1357 | ||
1337 | unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx) | 1358 | static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size, |
1359 | struct syscall_arg *arg) | ||
1360 | { | ||
1361 | if (sc->arg_fmt && sc->arg_fmt[arg->idx].name) | ||
1362 | return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name); | ||
1363 | |||
1364 | return scnprintf(bf, size, "arg%d: ", arg->idx); | ||
1365 | } | ||
1366 | |||
1367 | static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size, | ||
1368 | struct syscall_arg *arg, unsigned long val) | ||
1338 | { | 1369 | { |
1339 | return __syscall_arg__val(arg->args, idx); | 1370 | if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) { |
1371 | arg->val = val; | ||
1372 | if (sc->arg_fmt[arg->idx].parm) | ||
1373 | arg->parm = sc->arg_fmt[arg->idx].parm; | ||
1374 | return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg); | ||
1375 | } | ||
1376 | return scnprintf(bf, size, "%ld", val); | ||
1340 | } | 1377 | } |
1341 | 1378 | ||
1342 | static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | 1379 | static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, |
@@ -1345,6 +1382,14 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1345 | { | 1382 | { |
1346 | size_t printed = 0; | 1383 | size_t printed = 0; |
1347 | unsigned long val; | 1384 | unsigned long val; |
1385 | u8 bit = 1; | ||
1386 | struct syscall_arg arg = { | ||
1387 | .args = args, | ||
1388 | .idx = 0, | ||
1389 | .mask = 0, | ||
1390 | .trace = trace, | ||
1391 | .thread = thread, | ||
1392 | }; | ||
1348 | struct thread_trace *ttrace = thread__priv(thread); | 1393 | struct thread_trace *ttrace = thread__priv(thread); |
1349 | 1394 | ||
1350 | /* | 1395 | /* |
@@ -1356,14 +1401,6 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1356 | 1401 | ||
1357 | if (sc->args != NULL) { | 1402 | if (sc->args != NULL) { |
1358 | struct format_field *field; | 1403 | struct format_field *field; |
1359 | u8 bit = 1; | ||
1360 | struct syscall_arg arg = { | ||
1361 | .args = args, | ||
1362 | .idx = 0, | ||
1363 | .mask = 0, | ||
1364 | .trace = trace, | ||
1365 | .thread = thread, | ||
1366 | }; | ||
1367 | 1404 | ||
1368 | for (field = sc->args; field; | 1405 | for (field = sc->args; field; |
1369 | field = field->next, ++arg.idx, bit <<= 1) { | 1406 | field = field->next, ++arg.idx, bit <<= 1) { |
@@ -1387,15 +1424,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1387 | 1424 | ||
1388 | printed += scnprintf(bf + printed, size - printed, | 1425 | printed += scnprintf(bf + printed, size - printed, |
1389 | "%s%s: ", printed ? ", " : "", field->name); | 1426 | "%s%s: ", printed ? ", " : "", field->name); |
1390 | if (sc->arg_fmt && sc->arg_fmt[arg.idx].scnprintf) { | 1427 | printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val); |
1391 | arg.val = val; | ||
1392 | if (sc->arg_fmt[arg.idx].parm) | ||
1393 | arg.parm = sc->arg_fmt[arg.idx].parm; | ||
1394 | printed += sc->arg_fmt[arg.idx].scnprintf(bf + printed, size - printed, &arg); | ||
1395 | } else { | ||
1396 | printed += scnprintf(bf + printed, size - printed, | ||
1397 | "%ld", val); | ||
1398 | } | ||
1399 | } | 1428 | } |
1400 | } else if (IS_ERR(sc->tp_format)) { | 1429 | } else if (IS_ERR(sc->tp_format)) { |
1401 | /* | 1430 | /* |
@@ -1403,14 +1432,17 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1403 | * may end up not having any args, like with gettid(), so only | 1432 | * may end up not having any args, like with gettid(), so only |
1404 | * print the raw args when we didn't manage to read it. | 1433 | * print the raw args when we didn't manage to read it. |
1405 | */ | 1434 | */ |
1406 | int i = 0; | 1435 | while (arg.idx < sc->nr_args) { |
1407 | 1436 | if (arg.mask & bit) | |
1408 | while (i < 6) { | 1437 | goto next_arg; |
1409 | val = __syscall_arg__val(args, i); | 1438 | val = syscall_arg__val(&arg, arg.idx); |
1410 | printed += scnprintf(bf + printed, size - printed, | 1439 | if (printed) |
1411 | "%sarg%d: %ld", | 1440 | printed += scnprintf(bf + printed, size - printed, ", "); |
1412 | printed ? ", " : "", i, val); | 1441 | printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg); |
1413 | ++i; | 1442 | printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val); |
1443 | next_arg: | ||
1444 | ++arg.idx; | ||
1445 | bit <<= 1; | ||
1414 | } | 1446 | } |
1415 | } | 1447 | } |
1416 | 1448 | ||
@@ -1660,7 +1692,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
1660 | if (ret < 0) | 1692 | if (ret < 0) |
1661 | goto errno_print; | 1693 | goto errno_print; |
1662 | signed_print: | 1694 | signed_print: |
1663 | fprintf(trace->output, ") %ld", ret); | 1695 | fprintf(trace->output, ") = %ld", ret); |
1664 | } else if (ret < 0) { | 1696 | } else if (ret < 0) { |
1665 | errno_print: { | 1697 | errno_print: { |
1666 | char bf[STRERR_BUFSIZE]; | 1698 | char bf[STRERR_BUFSIZE]; |
@@ -2207,6 +2239,30 @@ out_enomem: | |||
2207 | goto out; | 2239 | goto out; |
2208 | } | 2240 | } |
2209 | 2241 | ||
2242 | static int trace__set_filter_loop_pids(struct trace *trace) | ||
2243 | { | ||
2244 | unsigned int nr = 1; | ||
2245 | pid_t pids[32] = { | ||
2246 | getpid(), | ||
2247 | }; | ||
2248 | struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]); | ||
2249 | |||
2250 | while (thread && nr < ARRAY_SIZE(pids)) { | ||
2251 | struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid); | ||
2252 | |||
2253 | if (parent == NULL) | ||
2254 | break; | ||
2255 | |||
2256 | if (!strcmp(thread__comm_str(parent), "sshd")) { | ||
2257 | pids[nr++] = parent->tid; | ||
2258 | break; | ||
2259 | } | ||
2260 | thread = parent; | ||
2261 | } | ||
2262 | |||
2263 | return perf_evlist__set_filter_pids(trace->evlist, nr, pids); | ||
2264 | } | ||
2265 | |||
2210 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2266 | static int trace__run(struct trace *trace, int argc, const char **argv) |
2211 | { | 2267 | { |
2212 | struct perf_evlist *evlist = trace->evlist; | 2268 | struct perf_evlist *evlist = trace->evlist; |
@@ -2330,7 +2386,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2330 | if (trace->filter_pids.nr > 0) | 2386 | if (trace->filter_pids.nr > 0) |
2331 | err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); | 2387 | err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); |
2332 | else if (thread_map__pid(evlist->threads, 0) == -1) | 2388 | else if (thread_map__pid(evlist->threads, 0) == -1) |
2333 | err = perf_evlist__set_filter_pid(evlist, getpid()); | 2389 | err = trace__set_filter_loop_pids(trace); |
2334 | 2390 | ||
2335 | if (err < 0) | 2391 | if (err < 0) |
2336 | goto out_error_mem; | 2392 | goto out_error_mem; |
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 47abd3325190..9b6295809a3b 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh | |||
@@ -3,6 +3,7 @@ | |||
3 | HEADERS=' | 3 | HEADERS=' |
4 | include/uapi/linux/fcntl.h | 4 | include/uapi/linux/fcntl.h |
5 | include/uapi/linux/perf_event.h | 5 | include/uapi/linux/perf_event.h |
6 | include/uapi/linux/sched.h | ||
6 | include/uapi/linux/stat.h | 7 | include/uapi/linux/stat.h |
7 | include/linux/hash.h | 8 | include/linux/hash.h |
8 | include/uapi/linux/hw_breakpoint.h | 9 | include/uapi/linux/hw_breakpoint.h |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 628a5e412cb1..e0279babe0c0 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -89,7 +89,7 @@ struct pager_config { | |||
89 | static int pager_command_config(const char *var, const char *value, void *data) | 89 | static int pager_command_config(const char *var, const char *value, void *data) |
90 | { | 90 | { |
91 | struct pager_config *c = data; | 91 | struct pager_config *c = data; |
92 | if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) | 92 | if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd)) |
93 | c->val = perf_config_bool(var, value); | 93 | c->val = perf_config_bool(var, value); |
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
@@ -108,9 +108,9 @@ static int check_pager_config(const char *cmd) | |||
108 | static int browser_command_config(const char *var, const char *value, void *data) | 108 | static int browser_command_config(const char *var, const char *value, void *data) |
109 | { | 109 | { |
110 | struct pager_config *c = data; | 110 | struct pager_config *c = data; |
111 | if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) | 111 | if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd)) |
112 | c->val = perf_config_bool(var, value); | 112 | c->val = perf_config_bool(var, value); |
113 | if (!prefixcmp(var, "gtk.") && !strcmp(var + 4, c->cmd)) | 113 | if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd)) |
114 | c->val = perf_config_bool(var, value) ? 2 : 0; | 114 | c->val = perf_config_bool(var, value) ? 2 : 0; |
115 | return 0; | 115 | return 0; |
116 | } | 116 | } |
@@ -192,7 +192,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
192 | /* | 192 | /* |
193 | * Check remaining flags. | 193 | * Check remaining flags. |
194 | */ | 194 | */ |
195 | if (!prefixcmp(cmd, CMD_EXEC_PATH)) { | 195 | if (strstarts(cmd, CMD_EXEC_PATH)) { |
196 | cmd += strlen(CMD_EXEC_PATH); | 196 | cmd += strlen(CMD_EXEC_PATH); |
197 | if (*cmd == '=') | 197 | if (*cmd == '=') |
198 | set_argv_exec_path(cmd + 1); | 198 | set_argv_exec_path(cmd + 1); |
@@ -229,7 +229,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
229 | *envchanged = 1; | 229 | *envchanged = 1; |
230 | (*argv)++; | 230 | (*argv)++; |
231 | (*argc)--; | 231 | (*argc)--; |
232 | } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { | 232 | } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) { |
233 | tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); | 233 | tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); |
234 | fprintf(stderr, "dir: %s\n", tracing_path); | 234 | fprintf(stderr, "dir: %s\n", tracing_path); |
235 | if (envchanged) | 235 | if (envchanged) |
@@ -470,14 +470,14 @@ int main(int argc, const char **argv) | |||
470 | * So we just directly call the internal command handler, and | 470 | * So we just directly call the internal command handler, and |
471 | * die if that one cannot handle it. | 471 | * die if that one cannot handle it. |
472 | */ | 472 | */ |
473 | if (!prefixcmp(cmd, "perf-")) { | 473 | if (strstarts(cmd, "perf-")) { |
474 | cmd += 5; | 474 | cmd += 5; |
475 | argv[0] = cmd; | 475 | argv[0] = cmd; |
476 | handle_internal_command(argc, argv); | 476 | handle_internal_command(argc, argv); |
477 | fprintf(stderr, "cannot handle %s internally", cmd); | 477 | fprintf(stderr, "cannot handle %s internally", cmd); |
478 | goto out; | 478 | goto out; |
479 | } | 479 | } |
480 | if (!prefixcmp(cmd, "trace")) { | 480 | if (strstarts(cmd, "trace")) { |
481 | #ifdef HAVE_LIBAUDIT_SUPPORT | 481 | #ifdef HAVE_LIBAUDIT_SUPPORT |
482 | setup_path(); | 482 | setup_path(); |
483 | argv[0] = "trace"; | 483 | argv[0] = "trace"; |
@@ -495,7 +495,7 @@ int main(int argc, const char **argv) | |||
495 | commit_pager_choice(); | 495 | commit_pager_choice(); |
496 | 496 | ||
497 | if (argc > 0) { | 497 | if (argc > 0) { |
498 | if (!prefixcmp(argv[0], "--")) | 498 | if (strstarts(argv[0], "--")) |
499 | argv[0] += 2; | 499 | argv[0] += 2; |
500 | } else { | 500 | } else { |
501 | /* The user didn't specify a command; give them help */ | 501 | /* The user didn't specify a command; give them help */ |
diff --git a/tools/perf/pmu-events/README b/tools/perf/pmu-events/README index 1408ade0d773..c2ee3e4417fe 100644 --- a/tools/perf/pmu-events/README +++ b/tools/perf/pmu-events/README | |||
@@ -85,10 +85,6 @@ users to specify events by their name: | |||
85 | 85 | ||
86 | where 'pm_1plus_ppc_cmpl' is a Power8 PMU event. | 86 | where 'pm_1plus_ppc_cmpl' is a Power8 PMU event. |
87 | 87 | ||
88 | In case of errors when processing files in the tools/perf/pmu-events/arch | ||
89 | directory, 'jevents' tries to create an empty mapping file to allow the perf | ||
90 | build to succeed even if the PMU event aliases cannot be used. | ||
91 | |||
92 | However some errors in processing may cause the perf build to fail. | 88 | However some errors in processing may cause the perf build to fail. |
93 | 89 | ||
94 | Mapfile format | 90 | Mapfile format |
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index bd0aabb2bd0f..2350f6099a46 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c | |||
@@ -822,10 +822,6 @@ static int process_one_file(const char *fpath, const struct stat *sb, | |||
822 | * PMU event tables (see struct pmu_events_map). | 822 | * PMU event tables (see struct pmu_events_map). |
823 | * | 823 | * |
824 | * Write out the PMU events tables and the mapping table to pmu-event.c. | 824 | * Write out the PMU events tables and the mapping table to pmu-event.c. |
825 | * | ||
826 | * If unable to process the JSON or arch files, create an empty mapping | ||
827 | * table so we can continue to build/use perf even if we cannot use the | ||
828 | * PMU event aliases. | ||
829 | */ | 825 | */ |
830 | int main(int argc, char *argv[]) | 826 | int main(int argc, char *argv[]) |
831 | { | 827 | { |
@@ -836,6 +832,7 @@ int main(int argc, char *argv[]) | |||
836 | const char *arch; | 832 | const char *arch; |
837 | const char *output_file; | 833 | const char *output_file; |
838 | const char *start_dirname; | 834 | const char *start_dirname; |
835 | struct stat stbuf; | ||
839 | 836 | ||
840 | prog = basename(argv[0]); | 837 | prog = basename(argv[0]); |
841 | if (argc < 4) { | 838 | if (argc < 4) { |
@@ -857,11 +854,17 @@ int main(int argc, char *argv[]) | |||
857 | return 2; | 854 | return 2; |
858 | } | 855 | } |
859 | 856 | ||
857 | sprintf(ldirname, "%s/%s", start_dirname, arch); | ||
858 | |||
859 | /* If architecture does not have any event lists, bail out */ | ||
860 | if (stat(ldirname, &stbuf) < 0) { | ||
861 | pr_info("%s: Arch %s has no PMU event lists\n", prog, arch); | ||
862 | goto empty_map; | ||
863 | } | ||
864 | |||
860 | /* Include pmu-events.h first */ | 865 | /* Include pmu-events.h first */ |
861 | fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n"); | 866 | fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n"); |
862 | 867 | ||
863 | sprintf(ldirname, "%s/%s", start_dirname, arch); | ||
864 | |||
865 | /* | 868 | /* |
866 | * The mapfile allows multiple CPUids to point to the same JSON file, | 869 | * The mapfile allows multiple CPUids to point to the same JSON file, |
867 | * so, not sure if there is a need for symlinks within the pmu-events | 870 | * so, not sure if there is a need for symlinks within the pmu-events |
@@ -878,6 +881,9 @@ int main(int argc, char *argv[]) | |||
878 | if (rc && verbose) { | 881 | if (rc && verbose) { |
879 | pr_info("%s: Error walking file tree %s\n", prog, ldirname); | 882 | pr_info("%s: Error walking file tree %s\n", prog, ldirname); |
880 | goto empty_map; | 883 | goto empty_map; |
884 | } else if (rc < 0) { | ||
885 | /* Make build fail */ | ||
886 | return 1; | ||
881 | } else if (rc) { | 887 | } else if (rc) { |
882 | goto empty_map; | 888 | goto empty_map; |
883 | } | 889 | } |
@@ -892,7 +898,8 @@ int main(int argc, char *argv[]) | |||
892 | 898 | ||
893 | if (process_mapfile(eventsfp, mapfile)) { | 899 | if (process_mapfile(eventsfp, mapfile)) { |
894 | pr_info("%s: Error processing mapfile %s\n", prog, mapfile); | 900 | pr_info("%s: Error processing mapfile %s\n", prog, mapfile); |
895 | goto empty_map; | 901 | /* Make build fail */ |
902 | return 1; | ||
896 | } | 903 | } |
897 | 904 | ||
898 | return 0; | 905 | return 0; |
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build index c9e215b806f1..eaa1e8e8e100 100644 --- a/tools/perf/trace/beauty/Build +++ b/tools/perf/trace/beauty/Build | |||
@@ -1,2 +1,3 @@ | |||
1 | libperf-y += clone.o | ||
1 | libperf-y += fcntl.o | 2 | libperf-y += fcntl.o |
2 | libperf-y += statx.o | 3 | libperf-y += statx.o |
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index f75ef7d0b303..69a5c8a2d420 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h | |||
@@ -66,6 +66,9 @@ size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *ar | |||
66 | size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg); | 66 | size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg); |
67 | #define SCA_PID syscall_arg__scnprintf_pid | 67 | #define SCA_PID syscall_arg__scnprintf_pid |
68 | 68 | ||
69 | size_t syscall_arg__scnprintf_clone_flags(char *bf, size_t size, struct syscall_arg *arg); | ||
70 | #define SCA_CLONE_FLAGS syscall_arg__scnprintf_clone_flags | ||
71 | |||
69 | size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arg *arg); | 72 | size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arg *arg); |
70 | #define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd | 73 | #define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd |
71 | 74 | ||
diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c new file mode 100644 index 000000000000..d64d049ab991 --- /dev/null +++ b/tools/perf/trace/beauty/clone.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * trace/beauty/cone.c | ||
3 | * | ||
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | ||
8 | |||
9 | #include "trace/beauty/beauty.h" | ||
10 | #include <linux/kernel.h> | ||
11 | #include <sys/types.h> | ||
12 | #include <uapi/linux/sched.h> | ||
13 | |||
14 | static size_t clone__scnprintf_flags(unsigned long flags, char *bf, size_t size) | ||
15 | { | ||
16 | int printed = 0; | ||
17 | |||
18 | #define P_FLAG(n) \ | ||
19 | if (flags & CLONE_##n) { \ | ||
20 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
21 | flags &= ~CLONE_##n; \ | ||
22 | } | ||
23 | |||
24 | P_FLAG(VM); | ||
25 | P_FLAG(FS); | ||
26 | P_FLAG(FILES); | ||
27 | P_FLAG(SIGHAND); | ||
28 | P_FLAG(PTRACE); | ||
29 | P_FLAG(VFORK); | ||
30 | P_FLAG(PARENT); | ||
31 | P_FLAG(THREAD); | ||
32 | P_FLAG(NEWNS); | ||
33 | P_FLAG(SYSVSEM); | ||
34 | P_FLAG(SETTLS); | ||
35 | P_FLAG(PARENT_SETTID); | ||
36 | P_FLAG(CHILD_CLEARTID); | ||
37 | P_FLAG(DETACHED); | ||
38 | P_FLAG(UNTRACED); | ||
39 | P_FLAG(CHILD_SETTID); | ||
40 | P_FLAG(NEWCGROUP); | ||
41 | P_FLAG(NEWUTS); | ||
42 | P_FLAG(NEWIPC); | ||
43 | P_FLAG(NEWUSER); | ||
44 | P_FLAG(NEWPID); | ||
45 | P_FLAG(NEWNET); | ||
46 | P_FLAG(IO); | ||
47 | #undef P_FLAG | ||
48 | |||
49 | if (flags) | ||
50 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
51 | |||
52 | return printed; | ||
53 | } | ||
54 | |||
55 | size_t syscall_arg__scnprintf_clone_flags(char *bf, size_t size, struct syscall_arg *arg) | ||
56 | { | ||
57 | unsigned long flags = arg->val; | ||
58 | enum syscall_clone_args { | ||
59 | SCC_FLAGS = (1 << 0), | ||
60 | SCC_CHILD_STACK = (1 << 1), | ||
61 | SCC_PARENT_TIDPTR = (1 << 2), | ||
62 | SCC_CHILD_TIDPTR = (1 << 3), | ||
63 | SCC_TLS = (1 << 4), | ||
64 | }; | ||
65 | if (!(flags & CLONE_PARENT_SETTID)) | ||
66 | arg->mask |= SCC_PARENT_TIDPTR; | ||
67 | |||
68 | if (!(flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))) | ||
69 | arg->mask |= SCC_CHILD_TIDPTR; | ||
70 | |||
71 | if (!(flags & CLONE_SETTLS)) | ||
72 | arg->mask |= SCC_TLS; | ||
73 | |||
74 | return clone__scnprintf_flags(flags, bf, size); | ||
75 | } | ||
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index af1cfde6b97b..754558f9009d 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c | |||
@@ -34,6 +34,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | |||
34 | { | 34 | { |
35 | int printed = 0, flags = arg->val; | 35 | int printed = 0, flags = arg->val; |
36 | 36 | ||
37 | if (flags & MAP_ANONYMOUS) | ||
38 | arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ | ||
39 | |||
37 | #define P_MMAP_FLAG(n) \ | 40 | #define P_MMAP_FLAG(n) \ |
38 | if (flags & MAP_##n) { \ | 41 | if (flags & MAP_##n) { \ |
39 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | 42 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ |
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index f73f3f13e01d..d0c2007c307b 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
9 | #include <linux/list.h> | 9 | #include <linux/list.h> |
10 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
11 | #include <linux/string.h> | ||
11 | #include <stdlib.h> | 12 | #include <stdlib.h> |
12 | #include <sys/ttydefaults.h> | 13 | #include <sys/ttydefaults.h> |
13 | #include "browser.h" | 14 | #include "browser.h" |
@@ -563,7 +564,7 @@ static int ui_browser__color_config(const char *var, const char *value, | |||
563 | int i; | 564 | int i; |
564 | 565 | ||
565 | /* same dir for all commands */ | 566 | /* same dir for all commands */ |
566 | if (prefixcmp(var, "colors.") != 0) | 567 | if (!strstarts(var, "colors.") != 0) |
567 | return 0; | 568 | return 0; |
568 | 569 | ||
569 | for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) { | 570 | for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) { |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8d3f6f53c122..dbe4e630b90f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <inttypes.h> | 13 | #include <inttypes.h> |
14 | #include <pthread.h> | 14 | #include <pthread.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/string.h> | ||
16 | #include <sys/ttydefaults.h> | 17 | #include <sys/ttydefaults.h> |
17 | 18 | ||
18 | struct disasm_line_samples { | 19 | struct disasm_line_samples { |
@@ -449,14 +450,14 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
449 | next = disasm__get_next_ip_line(¬es->src->source, pos); | 450 | next = disasm__get_next_ip_line(¬es->src->source, pos); |
450 | 451 | ||
451 | for (i = 0; i < browser->nr_events; i++) { | 452 | for (i = 0; i < browser->nr_events; i++) { |
452 | u64 nr_samples; | 453 | struct sym_hist_entry sample; |
453 | 454 | ||
454 | bpos->samples[i].percent = disasm__calc_percent(notes, | 455 | bpos->samples[i].percent = disasm__calc_percent(notes, |
455 | evsel->idx + i, | 456 | evsel->idx + i, |
456 | pos->offset, | 457 | pos->offset, |
457 | next ? next->offset : len, | 458 | next ? next->offset : len, |
458 | &path, &nr_samples); | 459 | &path, &sample); |
459 | bpos->samples[i].nr = nr_samples; | 460 | bpos->samples[i].nr = sample.nr_samples; |
460 | 461 | ||
461 | if (max_percent < bpos->samples[i].percent) | 462 | if (max_percent < bpos->samples[i].percent) |
462 | max_percent = bpos->samples[i].percent; | 463 | max_percent = bpos->samples[i].percent; |
@@ -1198,7 +1199,7 @@ static int annotate__config(const char *var, const char *value, | |||
1198 | struct annotate_config *cfg; | 1199 | struct annotate_config *cfg; |
1199 | const char *name; | 1200 | const char *name; |
1200 | 1201 | ||
1201 | if (prefixcmp(var, "annotate.") != 0) | 1202 | if (!strstarts(var, "annotate.")) |
1202 | return 0; | 1203 | return 0; |
1203 | 1204 | ||
1204 | name = var + 9; | 1205 | name = var + 9; |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 87e3760624f2..02176193f427 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c | |||
@@ -34,10 +34,10 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, | |||
34 | return 0; | 34 | return 0; |
35 | 35 | ||
36 | symhist = annotation__histogram(symbol__annotation(sym), evidx); | 36 | symhist = annotation__histogram(symbol__annotation(sym), evidx); |
37 | if (!symbol_conf.event_group && !symhist->addr[dl->offset]) | 37 | if (!symbol_conf.event_group && !symhist->addr[dl->offset].nr_samples) |
38 | return 0; | 38 | return 0; |
39 | 39 | ||
40 | percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; | 40 | percent = 100.0 * symhist->addr[dl->offset].nr_samples / symhist->nr_samples; |
41 | 41 | ||
42 | markup = perf_gtk__get_percent_color(percent); | 42 | markup = perf_gtk__get_percent_color(percent); |
43 | if (markup) | 43 | if (markup) |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 2df8eb1ed3c0..5c95b8301c67 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <linux/string.h> | ||
2 | 3 | ||
3 | #include "../../util/util.h" | 4 | #include "../../util/util.h" |
4 | #include "../../util/hist.h" | 5 | #include "../../util/hist.h" |
@@ -292,7 +293,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, | |||
292 | * displayed twice. | 293 | * displayed twice. |
293 | */ | 294 | */ |
294 | if (!i++ && field_order == NULL && | 295 | if (!i++ && field_order == NULL && |
295 | sort_order && !prefixcmp(sort_order, "sym")) | 296 | sort_order && strstarts(sort_order, "sym")) |
296 | continue; | 297 | continue; |
297 | 298 | ||
298 | if (!printed) { | 299 | if (!printed) { |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1742510f0120..c2b4b00166ed 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -610,10 +610,10 @@ int symbol__alloc_hist(struct symbol *sym) | |||
610 | size_t sizeof_sym_hist; | 610 | size_t sizeof_sym_hist; |
611 | 611 | ||
612 | /* Check for overflow when calculating sizeof_sym_hist */ | 612 | /* Check for overflow when calculating sizeof_sym_hist */ |
613 | if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) | 613 | if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(struct sym_hist_entry)) |
614 | return -1; | 614 | return -1; |
615 | 615 | ||
616 | sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); | 616 | sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); |
617 | 617 | ||
618 | /* Check for overflow in zalloc argument */ | 618 | /* Check for overflow in zalloc argument */ |
619 | if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) | 619 | if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) |
@@ -697,7 +697,8 @@ static int __symbol__account_cycles(struct annotation *notes, | |||
697 | } | 697 | } |
698 | 698 | ||
699 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 699 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
700 | struct annotation *notes, int evidx, u64 addr) | 700 | struct annotation *notes, int evidx, u64 addr, |
701 | struct perf_sample *sample) | ||
701 | { | 702 | { |
702 | unsigned offset; | 703 | unsigned offset; |
703 | struct sym_hist *h; | 704 | struct sym_hist *h; |
@@ -713,12 +714,15 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
713 | 714 | ||
714 | offset = addr - sym->start; | 715 | offset = addr - sym->start; |
715 | h = annotation__histogram(notes, evidx); | 716 | h = annotation__histogram(notes, evidx); |
716 | h->sum++; | 717 | h->nr_samples++; |
717 | h->addr[offset]++; | 718 | h->addr[offset].nr_samples++; |
719 | h->period += sample->period; | ||
720 | h->addr[offset].period += sample->period; | ||
718 | 721 | ||
719 | pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 | 722 | pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 |
720 | ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, | 723 | ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n", |
721 | addr, addr - sym->start, evidx, h->addr[offset]); | 724 | sym->start, sym->name, addr, addr - sym->start, evidx, |
725 | h->addr[offset].nr_samples, h->addr[offset].period); | ||
722 | return 0; | 726 | return 0; |
723 | } | 727 | } |
724 | 728 | ||
@@ -738,7 +742,8 @@ static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles | |||
738 | } | 742 | } |
739 | 743 | ||
740 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 744 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
741 | int evidx, u64 addr) | 745 | int evidx, u64 addr, |
746 | struct perf_sample *sample) | ||
742 | { | 747 | { |
743 | struct annotation *notes; | 748 | struct annotation *notes; |
744 | 749 | ||
@@ -747,7 +752,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
747 | notes = symbol__get_annotation(sym, false); | 752 | notes = symbol__get_annotation(sym, false); |
748 | if (notes == NULL) | 753 | if (notes == NULL) |
749 | return -ENOMEM; | 754 | return -ENOMEM; |
750 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); | 755 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr, sample); |
751 | } | 756 | } |
752 | 757 | ||
753 | static int symbol__account_cycles(u64 addr, u64 start, | 758 | static int symbol__account_cycles(u64 addr, u64 start, |
@@ -811,14 +816,16 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, | |||
811 | return err; | 816 | return err; |
812 | } | 817 | } |
813 | 818 | ||
814 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) | 819 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, |
820 | int evidx) | ||
815 | { | 821 | { |
816 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); | 822 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr, sample); |
817 | } | 823 | } |
818 | 824 | ||
819 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | 825 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, |
826 | int evidx, u64 ip) | ||
820 | { | 827 | { |
821 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | 828 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample); |
822 | } | 829 | } |
823 | 830 | ||
824 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) | 831 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) |
@@ -928,11 +935,12 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa | |||
928 | } | 935 | } |
929 | 936 | ||
930 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | 937 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, |
931 | s64 end, const char **path, u64 *nr_samples) | 938 | s64 end, const char **path, struct sym_hist_entry *sample) |
932 | { | 939 | { |
933 | struct source_line *src_line = notes->src->lines; | 940 | struct source_line *src_line = notes->src->lines; |
934 | double percent = 0.0; | 941 | double percent = 0.0; |
935 | *nr_samples = 0; | 942 | |
943 | sample->nr_samples = sample->period = 0; | ||
936 | 944 | ||
937 | if (src_line) { | 945 | if (src_line) { |
938 | size_t sizeof_src_line = sizeof(*src_line) + | 946 | size_t sizeof_src_line = sizeof(*src_line) + |
@@ -946,19 +954,23 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | |||
946 | *path = src_line->path; | 954 | *path = src_line->path; |
947 | 955 | ||
948 | percent += src_line->samples[evidx].percent; | 956 | percent += src_line->samples[evidx].percent; |
949 | *nr_samples += src_line->samples[evidx].nr; | 957 | sample->nr_samples += src_line->samples[evidx].nr; |
950 | offset++; | 958 | offset++; |
951 | } | 959 | } |
952 | } else { | 960 | } else { |
953 | struct sym_hist *h = annotation__histogram(notes, evidx); | 961 | struct sym_hist *h = annotation__histogram(notes, evidx); |
954 | unsigned int hits = 0; | 962 | unsigned int hits = 0; |
963 | u64 period = 0; | ||
955 | 964 | ||
956 | while (offset < end) | 965 | while (offset < end) { |
957 | hits += h->addr[offset++]; | 966 | hits += h->addr[offset++].nr_samples; |
967 | period += h->addr[offset++].period; | ||
968 | } | ||
958 | 969 | ||
959 | if (h->sum) { | 970 | if (h->nr_samples) { |
960 | *nr_samples = hits; | 971 | sample->period = period; |
961 | percent = 100.0 * hits / h->sum; | 972 | sample->nr_samples = hits; |
973 | percent = 100.0 * hits / h->nr_samples; | ||
962 | } | 974 | } |
963 | } | 975 | } |
964 | 976 | ||
@@ -1057,10 +1069,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1057 | 1069 | ||
1058 | if (dl->offset != -1) { | 1070 | if (dl->offset != -1) { |
1059 | const char *path = NULL; | 1071 | const char *path = NULL; |
1060 | u64 nr_samples; | ||
1061 | double percent, max_percent = 0.0; | 1072 | double percent, max_percent = 0.0; |
1062 | double *ppercents = &percent; | 1073 | double *ppercents = &percent; |
1063 | u64 *psamples = &nr_samples; | 1074 | struct sym_hist_entry sample; |
1075 | struct sym_hist_entry *psamples = &sample; | ||
1064 | int i, nr_percent = 1; | 1076 | int i, nr_percent = 1; |
1065 | const char *color; | 1077 | const char *color; |
1066 | struct annotation *notes = symbol__annotation(sym); | 1078 | struct annotation *notes = symbol__annotation(sym); |
@@ -1074,7 +1086,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1074 | if (perf_evsel__is_group_event(evsel)) { | 1086 | if (perf_evsel__is_group_event(evsel)) { |
1075 | nr_percent = evsel->nr_members; | 1087 | nr_percent = evsel->nr_members; |
1076 | ppercents = calloc(nr_percent, sizeof(double)); | 1088 | ppercents = calloc(nr_percent, sizeof(double)); |
1077 | psamples = calloc(nr_percent, sizeof(u64)); | 1089 | psamples = calloc(nr_percent, sizeof(struct sym_hist_entry)); |
1078 | if (ppercents == NULL || psamples == NULL) { | 1090 | if (ppercents == NULL || psamples == NULL) { |
1079 | return -1; | 1091 | return -1; |
1080 | } | 1092 | } |
@@ -1085,10 +1097,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1085 | notes->src->lines ? i : evsel->idx + i, | 1097 | notes->src->lines ? i : evsel->idx + i, |
1086 | offset, | 1098 | offset, |
1087 | next ? next->offset : (s64) len, | 1099 | next ? next->offset : (s64) len, |
1088 | &path, &nr_samples); | 1100 | &path, &sample); |
1089 | 1101 | ||
1090 | ppercents[i] = percent; | 1102 | ppercents[i] = percent; |
1091 | psamples[i] = nr_samples; | 1103 | psamples[i] = sample; |
1092 | if (percent > max_percent) | 1104 | if (percent > max_percent) |
1093 | max_percent = percent; | 1105 | max_percent = percent; |
1094 | } | 1106 | } |
@@ -1126,12 +1138,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1126 | 1138 | ||
1127 | for (i = 0; i < nr_percent; i++) { | 1139 | for (i = 0; i < nr_percent; i++) { |
1128 | percent = ppercents[i]; | 1140 | percent = ppercents[i]; |
1129 | nr_samples = psamples[i]; | 1141 | sample = psamples[i]; |
1130 | color = get_percent_color(percent); | 1142 | color = get_percent_color(percent); |
1131 | 1143 | ||
1132 | if (symbol_conf.show_total_period) | 1144 | if (symbol_conf.show_total_period) |
1133 | color_fprintf(stdout, color, " %7" PRIu64, | 1145 | color_fprintf(stdout, color, " %7" PRIu64, |
1134 | nr_samples); | 1146 | sample.period); |
1135 | else | 1147 | else |
1136 | color_fprintf(stdout, color, " %7.2f", percent); | 1148 | color_fprintf(stdout, color, " %7.2f", percent); |
1137 | } | 1149 | } |
@@ -1147,7 +1159,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1147 | if (ppercents != &percent) | 1159 | if (ppercents != &percent) |
1148 | free(ppercents); | 1160 | free(ppercents); |
1149 | 1161 | ||
1150 | if (psamples != &nr_samples) | 1162 | if (psamples != &sample) |
1151 | free(psamples); | 1163 | free(psamples); |
1152 | 1164 | ||
1153 | } else if (max_lines && printed >= max_lines) | 1165 | } else if (max_lines && printed >= max_lines) |
@@ -1671,19 +1683,19 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
1671 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1683 | struct sym_hist *h = annotation__histogram(notes, evidx); |
1672 | struct rb_root tmp_root = RB_ROOT; | 1684 | struct rb_root tmp_root = RB_ROOT; |
1673 | int nr_pcnt = 1; | 1685 | int nr_pcnt = 1; |
1674 | u64 h_sum = h->sum; | 1686 | u64 nr_samples = h->nr_samples; |
1675 | size_t sizeof_src_line = sizeof(struct source_line); | 1687 | size_t sizeof_src_line = sizeof(struct source_line); |
1676 | 1688 | ||
1677 | if (perf_evsel__is_group_event(evsel)) { | 1689 | if (perf_evsel__is_group_event(evsel)) { |
1678 | for (i = 1; i < evsel->nr_members; i++) { | 1690 | for (i = 1; i < evsel->nr_members; i++) { |
1679 | h = annotation__histogram(notes, evidx + i); | 1691 | h = annotation__histogram(notes, evidx + i); |
1680 | h_sum += h->sum; | 1692 | nr_samples += h->nr_samples; |
1681 | } | 1693 | } |
1682 | nr_pcnt = evsel->nr_members; | 1694 | nr_pcnt = evsel->nr_members; |
1683 | sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples); | 1695 | sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples); |
1684 | } | 1696 | } |
1685 | 1697 | ||
1686 | if (!h_sum) | 1698 | if (!nr_samples) |
1687 | return 0; | 1699 | return 0; |
1688 | 1700 | ||
1689 | src_line = notes->src->lines = calloc(len, sizeof_src_line); | 1701 | src_line = notes->src->lines = calloc(len, sizeof_src_line); |
@@ -1693,7 +1705,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
1693 | start = map__rip_2objdump(map, sym->start); | 1705 | start = map__rip_2objdump(map, sym->start); |
1694 | 1706 | ||
1695 | for (i = 0; i < len; i++) { | 1707 | for (i = 0; i < len; i++) { |
1696 | u64 offset, nr_samples; | 1708 | u64 offset; |
1697 | double percent_max = 0.0; | 1709 | double percent_max = 0.0; |
1698 | 1710 | ||
1699 | src_line->nr_pcnt = nr_pcnt; | 1711 | src_line->nr_pcnt = nr_pcnt; |
@@ -1702,9 +1714,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
1702 | double percent = 0.0; | 1714 | double percent = 0.0; |
1703 | 1715 | ||
1704 | h = annotation__histogram(notes, evidx + k); | 1716 | h = annotation__histogram(notes, evidx + k); |
1705 | nr_samples = h->addr[i]; | 1717 | nr_samples = h->addr[i].nr_samples; |
1706 | if (h->sum) | 1718 | if (h->nr_samples) |
1707 | percent = 100.0 * nr_samples / h->sum; | 1719 | percent = 100.0 * nr_samples / h->nr_samples; |
1708 | 1720 | ||
1709 | if (percent > percent_max) | 1721 | if (percent > percent_max) |
1710 | percent_max = percent; | 1722 | percent_max = percent; |
@@ -1773,10 +1785,10 @@ static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) | |||
1773 | u64 len = symbol__size(sym), offset; | 1785 | u64 len = symbol__size(sym), offset; |
1774 | 1786 | ||
1775 | for (offset = 0; offset < len; ++offset) | 1787 | for (offset = 0; offset < len; ++offset) |
1776 | if (h->addr[offset] != 0) | 1788 | if (h->addr[offset].nr_samples != 0) |
1777 | printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, | 1789 | printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, |
1778 | sym->start + offset, h->addr[offset]); | 1790 | sym->start + offset, h->addr[offset].nr_samples); |
1779 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); | 1791 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); |
1780 | } | 1792 | } |
1781 | 1793 | ||
1782 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 1794 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
@@ -1812,7 +1824,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1812 | width *= evsel->nr_members; | 1824 | width *= evsel->nr_members; |
1813 | 1825 | ||
1814 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", | 1826 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", |
1815 | width, width, "Percent", d_filename, evsel_name, h->sum); | 1827 | width, width, symbol_conf.show_total_period ? "Event count" : "Percent", |
1828 | d_filename, evsel_name, h->nr_samples); | ||
1816 | 1829 | ||
1817 | printf("%-*.*s----\n", | 1830 | printf("%-*.*s----\n", |
1818 | graph_dotted_len, graph_dotted_len, graph_dotted_line); | 1831 | graph_dotted_len, graph_dotted_len, graph_dotted_line); |
@@ -1876,10 +1889,10 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) | |||
1876 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1889 | struct sym_hist *h = annotation__histogram(notes, evidx); |
1877 | int len = symbol__size(sym), offset; | 1890 | int len = symbol__size(sym), offset; |
1878 | 1891 | ||
1879 | h->sum = 0; | 1892 | h->nr_samples = 0; |
1880 | for (offset = 0; offset < len; ++offset) { | 1893 | for (offset = 0; offset < len; ++offset) { |
1881 | h->addr[offset] = h->addr[offset] * 7 / 8; | 1894 | h->addr[offset].nr_samples = h->addr[offset].nr_samples * 7 / 8; |
1882 | h->sum += h->addr[offset]; | 1895 | h->nr_samples += h->addr[offset].nr_samples; |
1883 | } | 1896 | } |
1884 | } | 1897 | } |
1885 | 1898 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index bac698d7cc6a..9ce575c25fd9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -74,16 +74,22 @@ static inline bool disasm_line__has_offset(const struct disasm_line *dl) | |||
74 | return dl->ops.target.offset_avail; | 74 | return dl->ops.target.offset_avail; |
75 | } | 75 | } |
76 | 76 | ||
77 | struct sym_hist_entry { | ||
78 | u64 nr_samples; | ||
79 | u64 period; | ||
80 | }; | ||
81 | |||
77 | void disasm_line__free(struct disasm_line *dl); | 82 | void disasm_line__free(struct disasm_line *dl); |
78 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); | 83 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); |
79 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 84 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
80 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 85 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
81 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | 86 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, |
82 | s64 end, const char **path, u64 *nr_samples); | 87 | s64 end, const char **path, struct sym_hist_entry *sample); |
83 | 88 | ||
84 | struct sym_hist { | 89 | struct sym_hist { |
85 | u64 sum; | 90 | u64 nr_samples; |
86 | u64 addr[0]; | 91 | u64 period; |
92 | struct sym_hist_entry addr[0]; | ||
87 | }; | 93 | }; |
88 | 94 | ||
89 | struct cyc_hist { | 95 | struct cyc_hist { |
@@ -149,13 +155,15 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) | |||
149 | return (void *)sym - symbol_conf.priv_size; | 155 | return (void *)sym - symbol_conf.priv_size; |
150 | } | 156 | } |
151 | 157 | ||
152 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); | 158 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, |
159 | int evidx); | ||
153 | 160 | ||
154 | int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, | 161 | int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, |
155 | struct addr_map_symbol *start, | 162 | struct addr_map_symbol *start, |
156 | unsigned cycles); | 163 | unsigned cycles); |
157 | 164 | ||
158 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | 165 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, |
166 | int evidx, u64 addr); | ||
159 | 167 | ||
160 | int symbol__alloc_hist(struct symbol *sym); | 168 | int symbol__alloc_hist(struct symbol *sym); |
161 | void symbol__annotate_zero_histograms(struct symbol *sym); | 169 | void symbol__annotate_zero_histograms(struct symbol *sym); |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 4bd2d1d882af..4a1264c66101 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -1246,7 +1246,7 @@ int bpf__config_obj(struct bpf_object *obj, | |||
1246 | if (!obj || !term || !term->config) | 1246 | if (!obj || !term || !term->config) |
1247 | return -EINVAL; | 1247 | return -EINVAL; |
1248 | 1248 | ||
1249 | if (!prefixcmp(term->config, "map:")) { | 1249 | if (strstarts(term->config, "map:")) { |
1250 | key_scan_pos = sizeof("map:") - 1; | 1250 | key_scan_pos = sizeof("map:") - 1; |
1251 | err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos); | 1251 | err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos); |
1252 | goto out; | 1252 | goto out; |
diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h index 686f2b65ba84..1e3c7c5cdc63 100644 --- a/tools/perf/util/branch.h +++ b/tools/perf/util/branch.h | |||
@@ -5,11 +5,12 @@ | |||
5 | #include "../perf.h" | 5 | #include "../perf.h" |
6 | 6 | ||
7 | struct branch_type_stat { | 7 | struct branch_type_stat { |
8 | u64 counts[PERF_BR_MAX]; | 8 | bool branch_to; |
9 | u64 cond_fwd; | 9 | u64 counts[PERF_BR_MAX]; |
10 | u64 cond_bwd; | 10 | u64 cond_fwd; |
11 | u64 cross_4k; | 11 | u64 cond_bwd; |
12 | u64 cross_2m; | 12 | u64 cross_4k; |
13 | u64 cross_2m; | ||
13 | }; | 14 | }; |
14 | 15 | ||
15 | struct branch_flags; | 16 | struct branch_flags; |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 22d413ae6025..f320b0777e0d 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -304,7 +304,7 @@ int perf_callchain_config(const char *var, const char *value) | |||
304 | { | 304 | { |
305 | char *endptr; | 305 | char *endptr; |
306 | 306 | ||
307 | if (prefixcmp(var, "call-graph.")) | 307 | if (!strstarts(var, "call-graph.")) |
308 | return 0; | 308 | return 0; |
309 | var += sizeof("call-graph.") - 1; | 309 | var += sizeof("call-graph.") - 1; |
310 | 310 | ||
@@ -563,20 +563,33 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) | |||
563 | if (cursor_node->branch) { | 563 | if (cursor_node->branch) { |
564 | call->branch_count = 1; | 564 | call->branch_count = 1; |
565 | 565 | ||
566 | if (cursor_node->branch_flags.predicted) | 566 | if (cursor_node->branch_from) { |
567 | call->predicted_count = 1; | 567 | /* |
568 | 568 | * branch_from is set with value somewhere else | |
569 | if (cursor_node->branch_flags.abort) | 569 | * to imply it's "to" of a branch. |
570 | call->abort_count = 1; | 570 | */ |
571 | 571 | call->brtype_stat.branch_to = true; | |
572 | call->cycles_count = cursor_node->branch_flags.cycles; | 572 | |
573 | call->iter_count = cursor_node->nr_loop_iter; | 573 | if (cursor_node->branch_flags.predicted) |
574 | call->samples_count = cursor_node->samples; | 574 | call->predicted_count = 1; |
575 | 575 | ||
576 | branch_type_count(&call->brtype_stat, | 576 | if (cursor_node->branch_flags.abort) |
577 | &cursor_node->branch_flags, | 577 | call->abort_count = 1; |
578 | cursor_node->branch_from, | 578 | |
579 | cursor_node->ip); | 579 | branch_type_count(&call->brtype_stat, |
580 | &cursor_node->branch_flags, | ||
581 | cursor_node->branch_from, | ||
582 | cursor_node->ip); | ||
583 | } else { | ||
584 | /* | ||
585 | * It's "from" of a branch | ||
586 | */ | ||
587 | call->brtype_stat.branch_to = false; | ||
588 | call->cycles_count = | ||
589 | cursor_node->branch_flags.cycles; | ||
590 | call->iter_count = cursor_node->nr_loop_iter; | ||
591 | call->samples_count = cursor_node->samples; | ||
592 | } | ||
580 | } | 593 | } |
581 | 594 | ||
582 | list_add_tail(&call->list, &node->val); | 595 | list_add_tail(&call->list, &node->val); |
@@ -685,20 +698,32 @@ static enum match_result match_chain(struct callchain_cursor_node *node, | |||
685 | if (node->branch) { | 698 | if (node->branch) { |
686 | cnode->branch_count++; | 699 | cnode->branch_count++; |
687 | 700 | ||
688 | if (node->branch_flags.predicted) | 701 | if (node->branch_from) { |
689 | cnode->predicted_count++; | 702 | /* |
690 | 703 | * It's "to" of a branch | |
691 | if (node->branch_flags.abort) | 704 | */ |
692 | cnode->abort_count++; | 705 | cnode->brtype_stat.branch_to = true; |
693 | 706 | ||
694 | cnode->cycles_count += node->branch_flags.cycles; | 707 | if (node->branch_flags.predicted) |
695 | cnode->iter_count += node->nr_loop_iter; | 708 | cnode->predicted_count++; |
696 | cnode->samples_count += node->samples; | 709 | |
697 | 710 | if (node->branch_flags.abort) | |
698 | branch_type_count(&cnode->brtype_stat, | 711 | cnode->abort_count++; |
699 | &node->branch_flags, | 712 | |
700 | node->branch_from, | 713 | branch_type_count(&cnode->brtype_stat, |
701 | node->ip); | 714 | &node->branch_flags, |
715 | node->branch_from, | ||
716 | node->ip); | ||
717 | } else { | ||
718 | /* | ||
719 | * It's "from" of a branch | ||
720 | */ | ||
721 | cnode->brtype_stat.branch_to = false; | ||
722 | cnode->cycles_count += | ||
723 | node->branch_flags.cycles; | ||
724 | cnode->iter_count += node->nr_loop_iter; | ||
725 | cnode->samples_count += node->samples; | ||
726 | } | ||
702 | } | 727 | } |
703 | 728 | ||
704 | return MATCH_EQ; | 729 | return MATCH_EQ; |
@@ -1010,11 +1035,11 @@ int sample__resolve_callchain(struct perf_sample *sample, | |||
1010 | struct perf_evsel *evsel, struct addr_location *al, | 1035 | struct perf_evsel *evsel, struct addr_location *al, |
1011 | int max_stack) | 1036 | int max_stack) |
1012 | { | 1037 | { |
1013 | if (sample->callchain == NULL) | 1038 | if (sample->callchain == NULL && !symbol_conf.show_branchflag_count) |
1014 | return 0; | 1039 | return 0; |
1015 | 1040 | ||
1016 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || | 1041 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || |
1017 | perf_hpp_list.parent) { | 1042 | perf_hpp_list.parent || symbol_conf.show_branchflag_count) { |
1018 | return thread__resolve_callchain(al->thread, cursor, evsel, sample, | 1043 | return thread__resolve_callchain(al->thread, cursor, evsel, sample, |
1019 | parent, al, max_stack); | 1044 | parent, al, max_stack); |
1020 | } | 1045 | } |
@@ -1023,7 +1048,8 @@ int sample__resolve_callchain(struct perf_sample *sample, | |||
1023 | 1048 | ||
1024 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) | 1049 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) |
1025 | { | 1050 | { |
1026 | if (!symbol_conf.use_callchain || sample->callchain == NULL) | 1051 | if ((!symbol_conf.use_callchain || sample->callchain == NULL) && |
1052 | !symbol_conf.show_branchflag_count) | ||
1027 | return 0; | 1053 | return 0; |
1028 | return callchain_append(he->callchain, &callchain_cursor, sample->period); | 1054 | return callchain_append(he->callchain, &callchain_cursor, sample->period); |
1029 | } | 1055 | } |
@@ -1235,27 +1261,26 @@ static int count_pri64_printf(int idx, const char *str, u64 value, char *bf, int | |||
1235 | return printed; | 1261 | return printed; |
1236 | } | 1262 | } |
1237 | 1263 | ||
1238 | static int count_float_printf(int idx, const char *str, float value, char *bf, int bfsize) | 1264 | static int count_float_printf(int idx, const char *str, float value, |
1265 | char *bf, int bfsize, float threshold) | ||
1239 | { | 1266 | { |
1240 | int printed; | 1267 | int printed; |
1241 | 1268 | ||
1269 | if (threshold != 0.0 && value < threshold) | ||
1270 | return 0; | ||
1271 | |||
1242 | printed = scnprintf(bf, bfsize, "%s%s:%.1f%%", (idx) ? " " : " (", str, value); | 1272 | printed = scnprintf(bf, bfsize, "%s%s:%.1f%%", (idx) ? " " : " (", str, value); |
1243 | 1273 | ||
1244 | return printed; | 1274 | return printed; |
1245 | } | 1275 | } |
1246 | 1276 | ||
1247 | static int counts_str_build(char *bf, int bfsize, | 1277 | static int branch_to_str(char *bf, int bfsize, |
1248 | u64 branch_count, u64 predicted_count, | 1278 | u64 branch_count, u64 predicted_count, |
1249 | u64 abort_count, u64 cycles_count, | 1279 | u64 abort_count, |
1250 | u64 iter_count, u64 samples_count, | 1280 | struct branch_type_stat *brtype_stat) |
1251 | struct branch_type_stat *brtype_stat) | ||
1252 | { | 1281 | { |
1253 | u64 cycles; | ||
1254 | int printed, i = 0; | 1282 | int printed, i = 0; |
1255 | 1283 | ||
1256 | if (branch_count == 0) | ||
1257 | return scnprintf(bf, bfsize, " (calltrace)"); | ||
1258 | |||
1259 | printed = branch_type_str(brtype_stat, bf, bfsize); | 1284 | printed = branch_type_str(brtype_stat, bf, bfsize); |
1260 | if (printed) | 1285 | if (printed) |
1261 | i++; | 1286 | i++; |
@@ -1263,15 +1288,29 @@ static int counts_str_build(char *bf, int bfsize, | |||
1263 | if (predicted_count < branch_count) { | 1288 | if (predicted_count < branch_count) { |
1264 | printed += count_float_printf(i++, "predicted", | 1289 | printed += count_float_printf(i++, "predicted", |
1265 | predicted_count * 100.0 / branch_count, | 1290 | predicted_count * 100.0 / branch_count, |
1266 | bf + printed, bfsize - printed); | 1291 | bf + printed, bfsize - printed, 0.0); |
1267 | } | 1292 | } |
1268 | 1293 | ||
1269 | if (abort_count) { | 1294 | if (abort_count) { |
1270 | printed += count_float_printf(i++, "abort", | 1295 | printed += count_float_printf(i++, "abort", |
1271 | abort_count * 100.0 / branch_count, | 1296 | abort_count * 100.0 / branch_count, |
1272 | bf + printed, bfsize - printed); | 1297 | bf + printed, bfsize - printed, 0.1); |
1273 | } | 1298 | } |
1274 | 1299 | ||
1300 | if (i) | ||
1301 | printed += scnprintf(bf + printed, bfsize - printed, ")"); | ||
1302 | |||
1303 | return printed; | ||
1304 | } | ||
1305 | |||
1306 | static int branch_from_str(char *bf, int bfsize, | ||
1307 | u64 branch_count, | ||
1308 | u64 cycles_count, u64 iter_count, | ||
1309 | u64 samples_count) | ||
1310 | { | ||
1311 | int printed = 0, i = 0; | ||
1312 | u64 cycles; | ||
1313 | |||
1275 | cycles = cycles_count / branch_count; | 1314 | cycles = cycles_count / branch_count; |
1276 | if (cycles) { | 1315 | if (cycles) { |
1277 | printed += count_pri64_printf(i++, "cycles", | 1316 | printed += count_pri64_printf(i++, "cycles", |
@@ -1286,10 +1325,34 @@ static int counts_str_build(char *bf, int bfsize, | |||
1286 | } | 1325 | } |
1287 | 1326 | ||
1288 | if (i) | 1327 | if (i) |
1289 | return scnprintf(bf + printed, bfsize - printed, ")"); | 1328 | printed += scnprintf(bf + printed, bfsize - printed, ")"); |
1290 | 1329 | ||
1291 | bf[0] = 0; | 1330 | return printed; |
1292 | return 0; | 1331 | } |
1332 | |||
1333 | static int counts_str_build(char *bf, int bfsize, | ||
1334 | u64 branch_count, u64 predicted_count, | ||
1335 | u64 abort_count, u64 cycles_count, | ||
1336 | u64 iter_count, u64 samples_count, | ||
1337 | struct branch_type_stat *brtype_stat) | ||
1338 | { | ||
1339 | int printed; | ||
1340 | |||
1341 | if (branch_count == 0) | ||
1342 | return scnprintf(bf, bfsize, " (calltrace)"); | ||
1343 | |||
1344 | if (brtype_stat->branch_to) { | ||
1345 | printed = branch_to_str(bf, bfsize, branch_count, | ||
1346 | predicted_count, abort_count, brtype_stat); | ||
1347 | } else { | ||
1348 | printed = branch_from_str(bf, bfsize, branch_count, | ||
1349 | cycles_count, iter_count, samples_count); | ||
1350 | } | ||
1351 | |||
1352 | if (!printed) | ||
1353 | bf[0] = 0; | ||
1354 | |||
1355 | return printed; | ||
1293 | } | 1356 | } |
1294 | 1357 | ||
1295 | static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, | 1358 | static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, |
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 03347748f3fa..0e77bc9e5f3c 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c | |||
@@ -98,8 +98,10 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
98 | cgrp = counter->cgrp; | 98 | cgrp = counter->cgrp; |
99 | if (!cgrp) | 99 | if (!cgrp) |
100 | continue; | 100 | continue; |
101 | if (!strcmp(cgrp->name, str)) | 101 | if (!strcmp(cgrp->name, str)) { |
102 | refcount_inc(&cgrp->refcnt); | ||
102 | break; | 103 | break; |
104 | } | ||
103 | 105 | ||
104 | cgrp = NULL; | 106 | cgrp = NULL; |
105 | } | 107 | } |
@@ -110,6 +112,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
110 | return -1; | 112 | return -1; |
111 | 113 | ||
112 | cgrp->name = str; | 114 | cgrp->name = str; |
115 | refcount_set(&cgrp->refcnt, 1); | ||
113 | 116 | ||
114 | cgrp->fd = open_cgroup(str); | 117 | cgrp->fd = open_cgroup(str); |
115 | if (cgrp->fd == -1) { | 118 | if (cgrp->fd == -1) { |
@@ -128,12 +131,11 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
128 | goto found; | 131 | goto found; |
129 | n++; | 132 | n++; |
130 | } | 133 | } |
131 | if (refcount_read(&cgrp->refcnt) == 0) | 134 | if (refcount_dec_and_test(&cgrp->refcnt)) |
132 | free(cgrp); | 135 | free(cgrp); |
133 | 136 | ||
134 | return -1; | 137 | return -1; |
135 | found: | 138 | found: |
136 | refcount_inc(&cgrp->refcnt); | ||
137 | counter->cgrp = cgrp; | 139 | counter->cgrp = cgrp; |
138 | return 0; | 140 | return 0; |
139 | } | 141 | } |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 31a7dea248d0..bc75596f9e79 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sys/types.h> | 19 | #include <sys/types.h> |
20 | #include <sys/stat.h> | 20 | #include <sys/stat.h> |
21 | #include <unistd.h> | 21 | #include <unistd.h> |
22 | #include <linux/string.h> | ||
22 | 23 | ||
23 | #include "sane_ctype.h" | 24 | #include "sane_ctype.h" |
24 | 25 | ||
@@ -433,22 +434,22 @@ static int perf_ui_config(const char *var, const char *value) | |||
433 | int perf_default_config(const char *var, const char *value, | 434 | int perf_default_config(const char *var, const char *value, |
434 | void *dummy __maybe_unused) | 435 | void *dummy __maybe_unused) |
435 | { | 436 | { |
436 | if (!prefixcmp(var, "core.")) | 437 | if (strstarts(var, "core.")) |
437 | return perf_default_core_config(var, value); | 438 | return perf_default_core_config(var, value); |
438 | 439 | ||
439 | if (!prefixcmp(var, "hist.")) | 440 | if (strstarts(var, "hist.")) |
440 | return perf_hist_config(var, value); | 441 | return perf_hist_config(var, value); |
441 | 442 | ||
442 | if (!prefixcmp(var, "ui.")) | 443 | if (strstarts(var, "ui.")) |
443 | return perf_ui_config(var, value); | 444 | return perf_ui_config(var, value); |
444 | 445 | ||
445 | if (!prefixcmp(var, "call-graph.")) | 446 | if (strstarts(var, "call-graph.")) |
446 | return perf_callchain_config(var, value); | 447 | return perf_callchain_config(var, value); |
447 | 448 | ||
448 | if (!prefixcmp(var, "llvm.")) | 449 | if (strstarts(var, "llvm.")) |
449 | return perf_llvm_config(var, value); | 450 | return perf_llvm_config(var, value); |
450 | 451 | ||
451 | if (!prefixcmp(var, "buildid.")) | 452 | if (strstarts(var, "buildid.")) |
452 | return perf_buildid_config(var, value); | 453 | return perf_buildid_config(var, value); |
453 | 454 | ||
454 | /* Add other config variables here. */ | 455 | /* Add other config variables here. */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 6dd069a41ac3..450b5fadf8cb 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1671,31 +1671,39 @@ try_fallback: | |||
1671 | */ | 1671 | */ |
1672 | if (!perf_missing_features.write_backward && evsel->attr.write_backward) { | 1672 | if (!perf_missing_features.write_backward && evsel->attr.write_backward) { |
1673 | perf_missing_features.write_backward = true; | 1673 | perf_missing_features.write_backward = true; |
1674 | pr_debug2("switching off write_backward\n"); | ||
1674 | goto out_close; | 1675 | goto out_close; |
1675 | } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { | 1676 | } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { |
1676 | perf_missing_features.clockid_wrong = true; | 1677 | perf_missing_features.clockid_wrong = true; |
1678 | pr_debug2("switching off clockid\n"); | ||
1677 | goto fallback_missing_features; | 1679 | goto fallback_missing_features; |
1678 | } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { | 1680 | } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { |
1679 | perf_missing_features.clockid = true; | 1681 | perf_missing_features.clockid = true; |
1682 | pr_debug2("switching off use_clockid\n"); | ||
1680 | goto fallback_missing_features; | 1683 | goto fallback_missing_features; |
1681 | } else if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { | 1684 | } else if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { |
1682 | perf_missing_features.cloexec = true; | 1685 | perf_missing_features.cloexec = true; |
1686 | pr_debug2("switching off cloexec flag\n"); | ||
1683 | goto fallback_missing_features; | 1687 | goto fallback_missing_features; |
1684 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { | 1688 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { |
1685 | perf_missing_features.mmap2 = true; | 1689 | perf_missing_features.mmap2 = true; |
1690 | pr_debug2("switching off mmap2\n"); | ||
1686 | goto fallback_missing_features; | 1691 | goto fallback_missing_features; |
1687 | } else if (!perf_missing_features.exclude_guest && | 1692 | } else if (!perf_missing_features.exclude_guest && |
1688 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | 1693 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { |
1689 | perf_missing_features.exclude_guest = true; | 1694 | perf_missing_features.exclude_guest = true; |
1695 | pr_debug2("switching off exclude_guest, exclude_host\n"); | ||
1690 | goto fallback_missing_features; | 1696 | goto fallback_missing_features; |
1691 | } else if (!perf_missing_features.sample_id_all) { | 1697 | } else if (!perf_missing_features.sample_id_all) { |
1692 | perf_missing_features.sample_id_all = true; | 1698 | perf_missing_features.sample_id_all = true; |
1699 | pr_debug2("switching off sample_id_all\n"); | ||
1693 | goto retry_sample_id; | 1700 | goto retry_sample_id; |
1694 | } else if (!perf_missing_features.lbr_flags && | 1701 | } else if (!perf_missing_features.lbr_flags && |
1695 | (evsel->attr.branch_sample_type & | 1702 | (evsel->attr.branch_sample_type & |
1696 | (PERF_SAMPLE_BRANCH_NO_CYCLES | | 1703 | (PERF_SAMPLE_BRANCH_NO_CYCLES | |
1697 | PERF_SAMPLE_BRANCH_NO_FLAGS))) { | 1704 | PERF_SAMPLE_BRANCH_NO_FLAGS))) { |
1698 | perf_missing_features.lbr_flags = true; | 1705 | perf_missing_features.lbr_flags = true; |
1706 | pr_debug2("switching off branch sample type no (cycles/flags)\n"); | ||
1699 | goto fallback_missing_features; | 1707 | goto fallback_missing_features; |
1700 | } | 1708 | } |
1701 | out_close: | 1709 | out_close: |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2f6c5e6c16f9..9453b2e27015 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1759,6 +1759,8 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro | |||
1759 | else | 1759 | else |
1760 | use_callchain = symbol_conf.use_callchain; | 1760 | use_callchain = symbol_conf.use_callchain; |
1761 | 1761 | ||
1762 | use_callchain |= symbol_conf.show_branchflag_count; | ||
1763 | |||
1762 | output_resort(evsel__hists(evsel), prog, use_callchain, NULL); | 1764 | output_resort(evsel__hists(evsel), prog, use_callchain, NULL); |
1763 | } | 1765 | } |
1764 | 1766 | ||
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index c6a15f204c03..209b0c82eff4 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c | |||
@@ -33,7 +33,7 @@ struct llvm_param llvm_param = { | |||
33 | 33 | ||
34 | int perf_llvm_config(const char *var, const char *value) | 34 | int perf_llvm_config(const char *var, const char *value) |
35 | { | 35 | { |
36 | if (prefixcmp(var, "llvm.")) | 36 | if (!strstarts(var, "llvm.")) |
37 | return 0; | 37 | return 0; |
38 | var += sizeof("llvm.") - 1; | 38 | var += sizeof("llvm.") - 1; |
39 | 39 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 79d08ea694da..d4df353051af 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1902,13 +1902,16 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1902 | { | 1902 | { |
1903 | struct branch_stack *branch = sample->branch_stack; | 1903 | struct branch_stack *branch = sample->branch_stack; |
1904 | struct ip_callchain *chain = sample->callchain; | 1904 | struct ip_callchain *chain = sample->callchain; |
1905 | int chain_nr = chain->nr; | 1905 | int chain_nr = 0; |
1906 | u8 cpumode = PERF_RECORD_MISC_USER; | 1906 | u8 cpumode = PERF_RECORD_MISC_USER; |
1907 | int i, j, err, nr_entries; | 1907 | int i, j, err, nr_entries; |
1908 | int skip_idx = -1; | 1908 | int skip_idx = -1; |
1909 | int first_call = 0; | 1909 | int first_call = 0; |
1910 | int nr_loop_iter; | 1910 | int nr_loop_iter; |
1911 | 1911 | ||
1912 | if (chain) | ||
1913 | chain_nr = chain->nr; | ||
1914 | |||
1912 | if (perf_evsel__has_branch_callstack(evsel)) { | 1915 | if (perf_evsel__has_branch_callstack(evsel)) { |
1913 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, | 1916 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, |
1914 | root_al, max_stack); | 1917 | root_al, max_stack); |
@@ -1946,6 +1949,10 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1946 | for (i = 0; i < nr; i++) { | 1949 | for (i = 0; i < nr; i++) { |
1947 | if (callchain_param.order == ORDER_CALLEE) { | 1950 | if (callchain_param.order == ORDER_CALLEE) { |
1948 | be[i] = branch->entries[i]; | 1951 | be[i] = branch->entries[i]; |
1952 | |||
1953 | if (chain == NULL) | ||
1954 | continue; | ||
1955 | |||
1949 | /* | 1956 | /* |
1950 | * Check for overlap into the callchain. | 1957 | * Check for overlap into the callchain. |
1951 | * The return address is one off compared to | 1958 | * The return address is one off compared to |
@@ -2000,6 +2007,10 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
2000 | if (err) | 2007 | if (err) |
2001 | return err; | 2008 | return err; |
2002 | } | 2009 | } |
2010 | |||
2011 | if (chain_nr == 0) | ||
2012 | return 0; | ||
2013 | |||
2003 | chain_nr -= nr; | 2014 | chain_nr -= nr; |
2004 | } | 2015 | } |
2005 | 2016 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -116,6 +116,34 @@ static PyObject *get_handler(const char *handler_name) | |||
116 | return handler; | 116 | return handler; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int get_argument_count(PyObject *handler) | ||
120 | { | ||
121 | int arg_count = 0; | ||
122 | |||
123 | /* | ||
124 | * The attribute for the code object is func_code in Python 2, | ||
125 | * whereas it is __code__ in Python 3.0+. | ||
126 | */ | ||
127 | PyObject *code_obj = PyObject_GetAttrString(handler, | ||
128 | "func_code"); | ||
129 | if (PyErr_Occurred()) { | ||
130 | PyErr_Clear(); | ||
131 | code_obj = PyObject_GetAttrString(handler, | ||
132 | "__code__"); | ||
133 | } | ||
134 | PyErr_Clear(); | ||
135 | if (code_obj) { | ||
136 | PyObject *arg_count_obj = PyObject_GetAttrString(code_obj, | ||
137 | "co_argcount"); | ||
138 | if (arg_count_obj) { | ||
139 | arg_count = (int) PyInt_AsLong(arg_count_obj); | ||
140 | Py_DECREF(arg_count_obj); | ||
141 | } | ||
142 | Py_DECREF(code_obj); | ||
143 | } | ||
144 | return arg_count; | ||
145 | } | ||
146 | |||
119 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) | 147 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) |
120 | { | 148 | { |
121 | PyObject *retval; | 149 | PyObject *retval; |
@@ -391,13 +419,115 @@ exit: | |||
391 | return pylist; | 419 | return pylist; |
392 | } | 420 | } |
393 | 421 | ||
422 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) | ||
423 | { | ||
424 | PyObject *t; | ||
425 | |||
426 | t = PyTuple_New(2); | ||
427 | if (!t) | ||
428 | Py_FatalError("couldn't create Python tuple"); | ||
429 | PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id)); | ||
430 | PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value)); | ||
431 | return t; | ||
432 | } | ||
433 | |||
434 | static void set_sample_read_in_dict(PyObject *dict_sample, | ||
435 | struct perf_sample *sample, | ||
436 | struct perf_evsel *evsel) | ||
437 | { | ||
438 | u64 read_format = evsel->attr.read_format; | ||
439 | PyObject *values; | ||
440 | unsigned int i; | ||
441 | |||
442 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | ||
443 | pydict_set_item_string_decref(dict_sample, "time_enabled", | ||
444 | PyLong_FromUnsignedLongLong(sample->read.time_enabled)); | ||
445 | } | ||
446 | |||
447 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { | ||
448 | pydict_set_item_string_decref(dict_sample, "time_running", | ||
449 | PyLong_FromUnsignedLongLong(sample->read.time_running)); | ||
450 | } | ||
451 | |||
452 | if (read_format & PERF_FORMAT_GROUP) | ||
453 | values = PyList_New(sample->read.group.nr); | ||
454 | else | ||
455 | values = PyList_New(1); | ||
456 | |||
457 | if (!values) | ||
458 | Py_FatalError("couldn't create Python list"); | ||
459 | |||
460 | if (read_format & PERF_FORMAT_GROUP) { | ||
461 | for (i = 0; i < sample->read.group.nr; i++) { | ||
462 | PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]); | ||
463 | PyList_SET_ITEM(values, i, t); | ||
464 | } | ||
465 | } else { | ||
466 | PyObject *t = get_sample_value_as_tuple(&sample->read.one); | ||
467 | PyList_SET_ITEM(values, 0, t); | ||
468 | } | ||
469 | pydict_set_item_string_decref(dict_sample, "values", values); | ||
470 | } | ||
471 | |||
472 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, | ||
473 | struct perf_evsel *evsel, | ||
474 | struct addr_location *al, | ||
475 | PyObject *callchain) | ||
476 | { | ||
477 | PyObject *dict, *dict_sample; | ||
478 | |||
479 | dict = PyDict_New(); | ||
480 | if (!dict) | ||
481 | Py_FatalError("couldn't create Python dictionary"); | ||
482 | |||
483 | dict_sample = PyDict_New(); | ||
484 | if (!dict_sample) | ||
485 | Py_FatalError("couldn't create Python dictionary"); | ||
486 | |||
487 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | ||
488 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( | ||
489 | (const char *)&evsel->attr, sizeof(evsel->attr))); | ||
490 | |||
491 | pydict_set_item_string_decref(dict_sample, "pid", | ||
492 | PyInt_FromLong(sample->pid)); | ||
493 | pydict_set_item_string_decref(dict_sample, "tid", | ||
494 | PyInt_FromLong(sample->tid)); | ||
495 | pydict_set_item_string_decref(dict_sample, "cpu", | ||
496 | PyInt_FromLong(sample->cpu)); | ||
497 | pydict_set_item_string_decref(dict_sample, "ip", | ||
498 | PyLong_FromUnsignedLongLong(sample->ip)); | ||
499 | pydict_set_item_string_decref(dict_sample, "time", | ||
500 | PyLong_FromUnsignedLongLong(sample->time)); | ||
501 | pydict_set_item_string_decref(dict_sample, "period", | ||
502 | PyLong_FromUnsignedLongLong(sample->period)); | ||
503 | set_sample_read_in_dict(dict_sample, sample, evsel); | ||
504 | pydict_set_item_string_decref(dict, "sample", dict_sample); | ||
505 | |||
506 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | ||
507 | (const char *)sample->raw_data, sample->raw_size)); | ||
508 | pydict_set_item_string_decref(dict, "comm", | ||
509 | PyString_FromString(thread__comm_str(al->thread))); | ||
510 | if (al->map) { | ||
511 | pydict_set_item_string_decref(dict, "dso", | ||
512 | PyString_FromString(al->map->dso->name)); | ||
513 | } | ||
514 | if (al->sym) { | ||
515 | pydict_set_item_string_decref(dict, "symbol", | ||
516 | PyString_FromString(al->sym->name)); | ||
517 | } | ||
518 | |||
519 | pydict_set_item_string_decref(dict, "callchain", callchain); | ||
520 | |||
521 | return dict; | ||
522 | } | ||
523 | |||
394 | static void python_process_tracepoint(struct perf_sample *sample, | 524 | static void python_process_tracepoint(struct perf_sample *sample, |
395 | struct perf_evsel *evsel, | 525 | struct perf_evsel *evsel, |
396 | struct addr_location *al) | 526 | struct addr_location *al) |
397 | { | 527 | { |
398 | struct event_format *event = evsel->tp_format; | 528 | struct event_format *event = evsel->tp_format; |
399 | PyObject *handler, *context, *t, *obj = NULL, *callchain; | 529 | PyObject *handler, *context, *t, *obj = NULL, *callchain; |
400 | PyObject *dict = NULL; | 530 | PyObject *dict = NULL, *all_entries_dict = NULL; |
401 | static char handler_name[256]; | 531 | static char handler_name[256]; |
402 | struct format_field *field; | 532 | struct format_field *field; |
403 | unsigned long s, ns; | 533 | unsigned long s, ns; |
@@ -407,10 +537,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
407 | void *data = sample->raw_data; | 537 | void *data = sample->raw_data; |
408 | unsigned long long nsecs = sample->time; | 538 | unsigned long long nsecs = sample->time; |
409 | const char *comm = thread__comm_str(al->thread); | 539 | const char *comm = thread__comm_str(al->thread); |
410 | 540 | const char *default_handler_name = "trace_unhandled"; | |
411 | t = PyTuple_New(MAX_FIELDS); | ||
412 | if (!t) | ||
413 | Py_FatalError("couldn't create Python tuple"); | ||
414 | 541 | ||
415 | if (!event) { | 542 | if (!event) { |
416 | snprintf(handler_name, sizeof(handler_name), | 543 | snprintf(handler_name, sizeof(handler_name), |
@@ -427,10 +554,19 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
427 | 554 | ||
428 | handler = get_handler(handler_name); | 555 | handler = get_handler(handler_name); |
429 | if (!handler) { | 556 | if (!handler) { |
557 | handler = get_handler(default_handler_name); | ||
558 | if (!handler) | ||
559 | return; | ||
430 | dict = PyDict_New(); | 560 | dict = PyDict_New(); |
431 | if (!dict) | 561 | if (!dict) |
432 | Py_FatalError("couldn't create Python dict"); | 562 | Py_FatalError("couldn't create Python dict"); |
433 | } | 563 | } |
564 | |||
565 | t = PyTuple_New(MAX_FIELDS); | ||
566 | if (!t) | ||
567 | Py_FatalError("couldn't create Python tuple"); | ||
568 | |||
569 | |||
434 | s = nsecs / NSEC_PER_SEC; | 570 | s = nsecs / NSEC_PER_SEC; |
435 | ns = nsecs - s * NSEC_PER_SEC; | 571 | ns = nsecs - s * NSEC_PER_SEC; |
436 | 572 | ||
@@ -444,8 +580,10 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
444 | 580 | ||
445 | /* ip unwinding */ | 581 | /* ip unwinding */ |
446 | callchain = python_process_callchain(sample, evsel, al); | 582 | callchain = python_process_callchain(sample, evsel, al); |
583 | /* Need an additional reference for the perf_sample dict */ | ||
584 | Py_INCREF(callchain); | ||
447 | 585 | ||
448 | if (handler) { | 586 | if (!dict) { |
449 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | 587 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); |
450 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); | 588 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); |
451 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); | 589 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); |
@@ -484,26 +622,35 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
484 | } else { /* FIELD_IS_NUMERIC */ | 622 | } else { /* FIELD_IS_NUMERIC */ |
485 | obj = get_field_numeric_entry(event, field, data); | 623 | obj = get_field_numeric_entry(event, field, data); |
486 | } | 624 | } |
487 | if (handler) | 625 | if (!dict) |
488 | PyTuple_SetItem(t, n++, obj); | 626 | PyTuple_SetItem(t, n++, obj); |
489 | else | 627 | else |
490 | pydict_set_item_string_decref(dict, field->name, obj); | 628 | pydict_set_item_string_decref(dict, field->name, obj); |
491 | 629 | ||
492 | } | 630 | } |
493 | 631 | ||
494 | if (!handler) | 632 | if (dict) |
495 | PyTuple_SetItem(t, n++, dict); | 633 | PyTuple_SetItem(t, n++, dict); |
496 | 634 | ||
635 | if (get_argument_count(handler) == (int) n + 1) { | ||
636 | all_entries_dict = get_perf_sample_dict(sample, evsel, al, | ||
637 | callchain); | ||
638 | PyTuple_SetItem(t, n++, all_entries_dict); | ||
639 | } else { | ||
640 | Py_DECREF(callchain); | ||
641 | } | ||
642 | |||
497 | if (_PyTuple_Resize(&t, n) == -1) | 643 | if (_PyTuple_Resize(&t, n) == -1) |
498 | Py_FatalError("error resizing Python tuple"); | 644 | Py_FatalError("error resizing Python tuple"); |
499 | 645 | ||
500 | if (handler) { | 646 | if (!dict) { |
501 | call_object(handler, t, handler_name); | 647 | call_object(handler, t, handler_name); |
502 | } else { | 648 | } else { |
503 | try_call_object("trace_unhandled", t); | 649 | call_object(handler, t, default_handler_name); |
504 | Py_DECREF(dict); | 650 | Py_DECREF(dict); |
505 | } | 651 | } |
506 | 652 | ||
653 | Py_XDECREF(all_entries_dict); | ||
507 | Py_DECREF(t); | 654 | Py_DECREF(t); |
508 | } | 655 | } |
509 | 656 | ||
@@ -795,10 +942,16 @@ static void python_process_general_event(struct perf_sample *sample, | |||
795 | struct perf_evsel *evsel, | 942 | struct perf_evsel *evsel, |
796 | struct addr_location *al) | 943 | struct addr_location *al) |
797 | { | 944 | { |
798 | PyObject *handler, *t, *dict, *callchain, *dict_sample; | 945 | PyObject *handler, *t, *dict, *callchain; |
799 | static char handler_name[64]; | 946 | static char handler_name[64]; |
800 | unsigned n = 0; | 947 | unsigned n = 0; |
801 | 948 | ||
949 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | ||
950 | |||
951 | handler = get_handler(handler_name); | ||
952 | if (!handler) | ||
953 | return; | ||
954 | |||
802 | /* | 955 | /* |
803 | * Use the MAX_FIELDS to make the function expandable, though | 956 | * Use the MAX_FIELDS to make the function expandable, though |
804 | * currently there is only one item for the tuple. | 957 | * currently there is only one item for the tuple. |
@@ -807,61 +960,16 @@ static void python_process_general_event(struct perf_sample *sample, | |||
807 | if (!t) | 960 | if (!t) |
808 | Py_FatalError("couldn't create Python tuple"); | 961 | Py_FatalError("couldn't create Python tuple"); |
809 | 962 | ||
810 | dict = PyDict_New(); | ||
811 | if (!dict) | ||
812 | Py_FatalError("couldn't create Python dictionary"); | ||
813 | |||
814 | dict_sample = PyDict_New(); | ||
815 | if (!dict_sample) | ||
816 | Py_FatalError("couldn't create Python dictionary"); | ||
817 | |||
818 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | ||
819 | |||
820 | handler = get_handler(handler_name); | ||
821 | if (!handler) | ||
822 | goto exit; | ||
823 | |||
824 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | ||
825 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( | ||
826 | (const char *)&evsel->attr, sizeof(evsel->attr))); | ||
827 | |||
828 | pydict_set_item_string_decref(dict_sample, "pid", | ||
829 | PyInt_FromLong(sample->pid)); | ||
830 | pydict_set_item_string_decref(dict_sample, "tid", | ||
831 | PyInt_FromLong(sample->tid)); | ||
832 | pydict_set_item_string_decref(dict_sample, "cpu", | ||
833 | PyInt_FromLong(sample->cpu)); | ||
834 | pydict_set_item_string_decref(dict_sample, "ip", | ||
835 | PyLong_FromUnsignedLongLong(sample->ip)); | ||
836 | pydict_set_item_string_decref(dict_sample, "time", | ||
837 | PyLong_FromUnsignedLongLong(sample->time)); | ||
838 | pydict_set_item_string_decref(dict_sample, "period", | ||
839 | PyLong_FromUnsignedLongLong(sample->period)); | ||
840 | pydict_set_item_string_decref(dict, "sample", dict_sample); | ||
841 | |||
842 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | ||
843 | (const char *)sample->raw_data, sample->raw_size)); | ||
844 | pydict_set_item_string_decref(dict, "comm", | ||
845 | PyString_FromString(thread__comm_str(al->thread))); | ||
846 | if (al->map) { | ||
847 | pydict_set_item_string_decref(dict, "dso", | ||
848 | PyString_FromString(al->map->dso->name)); | ||
849 | } | ||
850 | if (al->sym) { | ||
851 | pydict_set_item_string_decref(dict, "symbol", | ||
852 | PyString_FromString(al->sym->name)); | ||
853 | } | ||
854 | |||
855 | /* ip unwinding */ | 963 | /* ip unwinding */ |
856 | callchain = python_process_callchain(sample, evsel, al); | 964 | callchain = python_process_callchain(sample, evsel, al); |
857 | pydict_set_item_string_decref(dict, "callchain", callchain); | 965 | dict = get_perf_sample_dict(sample, evsel, al, callchain); |
858 | 966 | ||
859 | PyTuple_SetItem(t, n++, dict); | 967 | PyTuple_SetItem(t, n++, dict); |
860 | if (_PyTuple_Resize(&t, n) == -1) | 968 | if (_PyTuple_Resize(&t, n) == -1) |
861 | Py_FatalError("error resizing Python tuple"); | 969 | Py_FatalError("error resizing Python tuple"); |
862 | 970 | ||
863 | call_object(handler, t, handler_name); | 971 | call_object(handler, t, handler_name); |
864 | exit: | 972 | |
865 | Py_DECREF(dict); | 973 | Py_DECREF(dict); |
866 | Py_DECREF(t); | 974 | Py_DECREF(t); |
867 | } | 975 | } |
@@ -1259,6 +1367,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1259 | 1367 | ||
1260 | fprintf(ofp, "%s", f->name); | 1368 | fprintf(ofp, "%s", f->name); |
1261 | } | 1369 | } |
1370 | if (not_first++) | ||
1371 | fprintf(ofp, ", "); | ||
1372 | if (++count % 5 == 0) | ||
1373 | fprintf(ofp, "\n\t\t"); | ||
1374 | fprintf(ofp, "perf_sample_dict"); | ||
1375 | |||
1262 | fprintf(ofp, "):\n"); | 1376 | fprintf(ofp, "):\n"); |
1263 | 1377 | ||
1264 | fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " | 1378 | fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " |
@@ -1328,6 +1442,9 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1328 | 1442 | ||
1329 | fprintf(ofp, ")\n\n"); | 1443 | fprintf(ofp, ")\n\n"); |
1330 | 1444 | ||
1445 | fprintf(ofp, "\t\tprint 'Sample: {'+" | ||
1446 | "get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\n\n"); | ||
1447 | |||
1331 | fprintf(ofp, "\t\tfor node in common_callchain:"); | 1448 | fprintf(ofp, "\t\tfor node in common_callchain:"); |
1332 | fprintf(ofp, "\n\t\t\tif 'sym' in node:"); | 1449 | fprintf(ofp, "\n\t\t\tif 'sym' in node:"); |
1333 | fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); | 1450 | fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); |
@@ -1338,15 +1455,20 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1338 | } | 1455 | } |
1339 | 1456 | ||
1340 | fprintf(ofp, "def trace_unhandled(event_name, context, " | 1457 | fprintf(ofp, "def trace_unhandled(event_name, context, " |
1341 | "event_fields_dict):\n"); | 1458 | "event_fields_dict, perf_sample_dict):\n"); |
1342 | 1459 | ||
1343 | fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))" | 1460 | fprintf(ofp, "\t\tprint get_dict_as_string(event_fields_dict)\n"); |
1344 | "for k,v in sorted(event_fields_dict.items())])\n\n"); | 1461 | fprintf(ofp, "\t\tprint 'Sample: {'+" |
1462 | "get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\n\n"); | ||
1345 | 1463 | ||
1346 | fprintf(ofp, "def print_header(" | 1464 | fprintf(ofp, "def print_header(" |
1347 | "event_name, cpu, secs, nsecs, pid, comm):\n" | 1465 | "event_name, cpu, secs, nsecs, pid, comm):\n" |
1348 | "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t" | 1466 | "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t" |
1349 | "(event_name, cpu, secs, nsecs, pid, comm),\n"); | 1467 | "(event_name, cpu, secs, nsecs, pid, comm),\n\n"); |
1468 | |||
1469 | fprintf(ofp, "def get_dict_as_string(a_dict, delimiter=' '):\n" | ||
1470 | "\treturn delimiter.join" | ||
1471 | "(['%%s=%%s'%%(k,str(v))for k,v in sorted(a_dict.items())])\n"); | ||
1350 | 1472 | ||
1351 | fclose(ofp); | 1473 | fclose(ofp); |
1352 | 1474 | ||