diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-07-18 00:16:06 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-07-18 00:16:06 -0400 |
commit | ec6dbcb7ade2a616675cbe3185cf299ee1615c9f (patch) | |
tree | 4953f7eca477e011aa9e16cdb236220ed9cec4be | |
parent | ff2ebe46e15bd49d52b9c2f3fc77f3a9d94eac7b (diff) | |
parent | 0b437860818dc717f6a9e8a5089223a8414f5fff (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
o Support S/390 in 'perf kvm stat' (Alexander Yarygin)
Developer Stuff:
o Various fixes and prep work related to supporting Intel PT (Adrian Hunter)
o Introduce multiple debug variables control (Jiri Olsa)
o Add callchain and additional sample information for python scripts (Joseph Schuchart)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
85 files changed, 1170 insertions, 470 deletions
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild index 6a9a9eb645f5..0e2b54db82bc 100644 --- a/arch/s390/include/uapi/asm/Kbuild +++ b/arch/s390/include/uapi/asm/Kbuild | |||
@@ -16,6 +16,7 @@ header-y += ioctls.h | |||
16 | header-y += ipcbuf.h | 16 | header-y += ipcbuf.h |
17 | header-y += kvm.h | 17 | header-y += kvm.h |
18 | header-y += kvm_para.h | 18 | header-y += kvm_para.h |
19 | header-y += kvm_perf.h | ||
19 | header-y += kvm_virtio.h | 20 | header-y += kvm_virtio.h |
20 | header-y += mman.h | 21 | header-y += mman.h |
21 | header-y += monwriter.h | 22 | header-y += monwriter.h |
diff --git a/arch/s390/include/uapi/asm/kvm_perf.h b/arch/s390/include/uapi/asm/kvm_perf.h new file mode 100644 index 000000000000..397282727e21 --- /dev/null +++ b/arch/s390/include/uapi/asm/kvm_perf.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Definitions for perf-kvm on s390 | ||
3 | * | ||
4 | * Copyright 2014 IBM Corp. | ||
5 | * Author(s): Alexander Yarygin <yarygin@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 | #ifndef __LINUX_KVM_PERF_S390_H | ||
13 | #define __LINUX_KVM_PERF_S390_H | ||
14 | |||
15 | #include <asm/sie.h> | ||
16 | |||
17 | #define DECODE_STR_LEN 40 | ||
18 | |||
19 | #define VCPU_ID "id" | ||
20 | |||
21 | #define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" | ||
22 | #define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" | ||
23 | #define KVM_EXIT_REASON "icptcode" | ||
24 | |||
25 | #endif | ||
diff --git a/arch/x86/include/uapi/asm/Kbuild b/arch/x86/include/uapi/asm/Kbuild index 09409c44f9a5..3dec769cadf7 100644 --- a/arch/x86/include/uapi/asm/Kbuild +++ b/arch/x86/include/uapi/asm/Kbuild | |||
@@ -22,6 +22,7 @@ header-y += ipcbuf.h | |||
22 | header-y += ist.h | 22 | header-y += ist.h |
23 | header-y += kvm.h | 23 | header-y += kvm.h |
24 | header-y += kvm_para.h | 24 | header-y += kvm_para.h |
25 | header-y += kvm_perf.h | ||
25 | header-y += ldt.h | 26 | header-y += ldt.h |
26 | header-y += mce.h | 27 | header-y += mce.h |
27 | header-y += mman.h | 28 | header-y += mman.h |
diff --git a/arch/x86/include/uapi/asm/kvm_perf.h b/arch/x86/include/uapi/asm/kvm_perf.h new file mode 100644 index 000000000000..3bb964f88aa1 --- /dev/null +++ b/arch/x86/include/uapi/asm/kvm_perf.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef _ASM_X86_KVM_PERF_H | ||
2 | #define _ASM_X86_KVM_PERF_H | ||
3 | |||
4 | #include <asm/svm.h> | ||
5 | #include <asm/vmx.h> | ||
6 | #include <asm/kvm.h> | ||
7 | |||
8 | #define DECODE_STR_LEN 20 | ||
9 | |||
10 | #define VCPU_ID "vcpu_id" | ||
11 | |||
12 | #define KVM_ENTRY_TRACE "kvm:kvm_entry" | ||
13 | #define KVM_EXIT_TRACE "kvm:kvm_exit" | ||
14 | #define KVM_EXIT_REASON "exit_reason" | ||
15 | |||
16 | #endif /* _ASM_X86_KVM_PERF_H */ | ||
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 52276a6d2b75..6e689dc89a2f 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt | |||
@@ -51,9 +51,9 @@ There are a couple of variants of perf kvm: | |||
51 | 'perf kvm stat <command>' to run a command and gather performance counter | 51 | 'perf kvm stat <command>' to run a command and gather performance counter |
52 | statistics. | 52 | statistics. |
53 | Especially, perf 'kvm stat record/report' generates a statistical analysis | 53 | Especially, perf 'kvm stat record/report' generates a statistical analysis |
54 | of KVM events. Currently, vmexit, mmio and ioport events are supported. | 54 | of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only) |
55 | 'perf kvm stat record <command>' records kvm events and the events between | 55 | events are supported. 'perf kvm stat record <command>' records kvm events |
56 | start and end <command>. | 56 | and the events between start and end <command>. |
57 | And this command produces a file which contains tracing results of kvm | 57 | And this command produces a file which contains tracing results of kvm |
58 | events. | 58 | events. |
59 | 59 | ||
@@ -103,8 +103,8 @@ STAT REPORT OPTIONS | |||
103 | analyze events which occures on this vcpu. (default: all vcpus) | 103 | analyze events which occures on this vcpu. (default: all vcpus) |
104 | 104 | ||
105 | --event=<value>:: | 105 | --event=<value>:: |
106 | event to be analyzed. Possible values: vmexit, mmio, ioport. | 106 | event to be analyzed. Possible values: vmexit, mmio (x86 only), |
107 | (default: vmexit) | 107 | ioport (x86 only). (default: vmexit) |
108 | -k:: | 108 | -k:: |
109 | --key=<value>:: | 109 | --key=<value>:: |
110 | Sorting key. Possible values: sample (default, sort by samples | 110 | Sorting key. Possible values: sample (default, sort by samples |
@@ -138,7 +138,8 @@ STAT LIVE OPTIONS | |||
138 | 138 | ||
139 | 139 | ||
140 | --event=<value>:: | 140 | --event=<value>:: |
141 | event to be analyzed. Possible values: vmexit, mmio, ioport. | 141 | event to be analyzed. Possible values: vmexit, |
142 | mmio (x86 only), ioport (x86 only). | ||
142 | (default: vmexit) | 143 | (default: vmexit) |
143 | 144 | ||
144 | -k:: | 145 | -k:: |
@@ -147,7 +148,8 @@ STAT LIVE OPTIONS | |||
147 | number), time (sort by average time). | 148 | number), time (sort by average time). |
148 | 149 | ||
149 | --duration=<value>:: | 150 | --duration=<value>:: |
150 | Show events other than HLT that take longer than duration usecs. | 151 | Show events other than HLT (x86 only) or Wait state (s390 only) |
152 | that take longer than duration usecs. | ||
151 | 153 | ||
152 | SEE ALSO | 154 | SEE ALSO |
153 | -------- | 155 | -------- |
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 0eeb247dc7d2..d240bb2e5b22 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt | |||
@@ -8,7 +8,15 @@ perf - Performance analysis tools for Linux | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf' [--version] [--help] COMMAND [ARGS] | 11 | 'perf' [--version] [--help] [OPTIONS] COMMAND [ARGS] |
12 | |||
13 | OPTIONS | ||
14 | ------- | ||
15 | --debug:: | ||
16 | Setup debug variable (just verbose for now) in value | ||
17 | range (0, 10). Use like: | ||
18 | --debug verbose # sets verbose = 1 | ||
19 | --debug verbose=2 # sets verbose = 2 | ||
12 | 20 | ||
13 | DESCRIPTION | 21 | DESCRIPTION |
14 | ----------- | 22 | ----------- |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 45da209b6ed3..344c4d3d0a4a 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -37,3 +37,6 @@ arch/x86/include/asm/kvm_host.h | |||
37 | arch/x86/include/uapi/asm/svm.h | 37 | arch/x86/include/uapi/asm/svm.h |
38 | arch/x86/include/uapi/asm/vmx.h | 38 | arch/x86/include/uapi/asm/vmx.h |
39 | arch/x86/include/uapi/asm/kvm.h | 39 | arch/x86/include/uapi/asm/kvm.h |
40 | arch/x86/include/uapi/asm/kvm_perf.h | ||
41 | arch/s390/include/uapi/asm/sie.h | ||
42 | arch/s390/include/uapi/asm/kvm_perf.h | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 9670a16fa577..3308b22a1660 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -295,11 +295,13 @@ LIB_H += util/intlist.h | |||
295 | LIB_H += util/perf_regs.h | 295 | LIB_H += util/perf_regs.h |
296 | LIB_H += util/unwind.h | 296 | LIB_H += util/unwind.h |
297 | LIB_H += util/vdso.h | 297 | LIB_H += util/vdso.h |
298 | LIB_H += util/tsc.h | ||
298 | LIB_H += ui/helpline.h | 299 | LIB_H += ui/helpline.h |
299 | LIB_H += ui/progress.h | 300 | LIB_H += ui/progress.h |
300 | LIB_H += ui/util.h | 301 | LIB_H += ui/util.h |
301 | LIB_H += ui/ui.h | 302 | LIB_H += ui/ui.h |
302 | LIB_H += util/data.h | 303 | LIB_H += util/data.h |
304 | LIB_H += util/kvm-stat.h | ||
303 | 305 | ||
304 | LIB_OBJS += $(OUTPUT)util/abspath.o | 306 | LIB_OBJS += $(OUTPUT)util/abspath.o |
305 | LIB_OBJS += $(OUTPUT)util/alias.o | 307 | LIB_OBJS += $(OUTPUT)util/alias.o |
@@ -373,6 +375,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o | |||
373 | LIB_OBJS += $(OUTPUT)util/record.o | 375 | LIB_OBJS += $(OUTPUT)util/record.o |
374 | LIB_OBJS += $(OUTPUT)util/srcline.o | 376 | LIB_OBJS += $(OUTPUT)util/srcline.o |
375 | LIB_OBJS += $(OUTPUT)util/data.o | 377 | LIB_OBJS += $(OUTPUT)util/data.o |
378 | LIB_OBJS += $(OUTPUT)util/tsc.o | ||
376 | 379 | ||
377 | LIB_OBJS += $(OUTPUT)ui/setup.o | 380 | LIB_OBJS += $(OUTPUT)ui/setup.o |
378 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 381 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile index 744e629797be..798ac7379c5f 100644 --- a/tools/perf/arch/s390/Makefile +++ b/tools/perf/arch/s390/Makefile | |||
@@ -3,3 +3,5 @@ PERF_HAVE_DWARF_REGS := 1 | |||
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | 3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o |
4 | endif | 4 | endif |
5 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o | 5 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o |
6 | HAVE_KVM_STAT_SUPPORT := 1 | ||
7 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o | ||
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c new file mode 100644 index 000000000000..a5dbc07ec9dc --- /dev/null +++ b/tools/perf/arch/s390/util/kvm-stat.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Arch specific functions for perf kvm stat. | ||
3 | * | ||
4 | * Copyright 2014 IBM Corp. | ||
5 | * Author(s): Alexander Yarygin <yarygin@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 "../../util/kvm-stat.h" | ||
13 | #include <asm/kvm_perf.h> | ||
14 | |||
15 | define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); | ||
16 | define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); | ||
17 | define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes); | ||
18 | define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); | ||
19 | define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); | ||
20 | |||
21 | static void event_icpt_insn_get_key(struct perf_evsel *evsel, | ||
22 | struct perf_sample *sample, | ||
23 | struct event_key *key) | ||
24 | { | ||
25 | unsigned long insn; | ||
26 | |||
27 | insn = perf_evsel__intval(evsel, sample, "instruction"); | ||
28 | key->key = icpt_insn_decoder(insn); | ||
29 | key->exit_reasons = sie_icpt_insn_codes; | ||
30 | } | ||
31 | |||
32 | static void event_sigp_get_key(struct perf_evsel *evsel, | ||
33 | struct perf_sample *sample, | ||
34 | struct event_key *key) | ||
35 | { | ||
36 | key->key = perf_evsel__intval(evsel, sample, "order_code"); | ||
37 | key->exit_reasons = sie_sigp_order_codes; | ||
38 | } | ||
39 | |||
40 | static void event_diag_get_key(struct perf_evsel *evsel, | ||
41 | struct perf_sample *sample, | ||
42 | struct event_key *key) | ||
43 | { | ||
44 | key->key = perf_evsel__intval(evsel, sample, "code"); | ||
45 | key->exit_reasons = sie_diagnose_codes; | ||
46 | } | ||
47 | |||
48 | static void event_icpt_prog_get_key(struct perf_evsel *evsel, | ||
49 | struct perf_sample *sample, | ||
50 | struct event_key *key) | ||
51 | { | ||
52 | key->key = perf_evsel__intval(evsel, sample, "code"); | ||
53 | key->exit_reasons = sie_icpt_prog_codes; | ||
54 | } | ||
55 | |||
56 | static struct child_event_ops child_events[] = { | ||
57 | { .name = "kvm:kvm_s390_intercept_instruction", | ||
58 | .get_key = event_icpt_insn_get_key }, | ||
59 | { .name = "kvm:kvm_s390_handle_sigp", | ||
60 | .get_key = event_sigp_get_key }, | ||
61 | { .name = "kvm:kvm_s390_handle_diag", | ||
62 | .get_key = event_diag_get_key }, | ||
63 | { .name = "kvm:kvm_s390_intercept_prog", | ||
64 | .get_key = event_icpt_prog_get_key }, | ||
65 | { NULL, NULL }, | ||
66 | }; | ||
67 | |||
68 | static struct kvm_events_ops exit_events = { | ||
69 | .is_begin_event = exit_event_begin, | ||
70 | .is_end_event = exit_event_end, | ||
71 | .child_ops = child_events, | ||
72 | .decode_key = exit_event_decode_key, | ||
73 | .name = "VM-EXIT" | ||
74 | }; | ||
75 | |||
76 | const char * const kvm_events_tp[] = { | ||
77 | "kvm:kvm_s390_sie_enter", | ||
78 | "kvm:kvm_s390_sie_exit", | ||
79 | "kvm:kvm_s390_intercept_instruction", | ||
80 | "kvm:kvm_s390_handle_sigp", | ||
81 | "kvm:kvm_s390_handle_diag", | ||
82 | "kvm:kvm_s390_intercept_prog", | ||
83 | NULL, | ||
84 | }; | ||
85 | |||
86 | struct kvm_reg_events_ops kvm_reg_events_ops[] = { | ||
87 | { .name = "vmexit", .ops = &exit_events }, | ||
88 | { NULL, NULL }, | ||
89 | }; | ||
90 | |||
91 | const char * const kvm_skip_events[] = { | ||
92 | "Wait state", | ||
93 | NULL, | ||
94 | }; | ||
95 | |||
96 | int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) | ||
97 | { | ||
98 | if (strstr(cpuid, "IBM/S390")) { | ||
99 | kvm->exit_reasons = sie_exit_reasons; | ||
100 | kvm->exit_reasons_isa = "SIE"; | ||
101 | } else | ||
102 | return -ENOTSUP; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index d3939014a877..9b21881db52f 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile | |||
@@ -16,3 +16,4 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o | |||
16 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o | 16 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o |
17 | LIB_H += arch/$(ARCH)/util/tsc.h | 17 | LIB_H += arch/$(ARCH)/util/tsc.h |
18 | HAVE_KVM_STAT_SUPPORT := 1 | 18 | HAVE_KVM_STAT_SUPPORT := 1 |
19 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o | ||
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c index 9f89f899ccc7..d8bbf7ad1681 100644 --- a/tools/perf/arch/x86/tests/dwarf-unwind.c +++ b/tools/perf/arch/x86/tests/dwarf-unwind.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "thread.h" | 3 | #include "thread.h" |
4 | #include "map.h" | 4 | #include "map.h" |
5 | #include "event.h" | 5 | #include "event.h" |
6 | #include "debug.h" | ||
6 | #include "tests/tests.h" | 7 | #include "tests/tests.h" |
7 | 8 | ||
8 | #define STACK_SIZE 8192 | 9 | #define STACK_SIZE 8192 |
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c new file mode 100644 index 000000000000..14e4e668fad7 --- /dev/null +++ b/tools/perf/arch/x86/util/kvm-stat.c | |||
@@ -0,0 +1,156 @@ | |||
1 | #include "../../util/kvm-stat.h" | ||
2 | #include <asm/kvm_perf.h> | ||
3 | |||
4 | define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); | ||
5 | define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); | ||
6 | |||
7 | static struct kvm_events_ops exit_events = { | ||
8 | .is_begin_event = exit_event_begin, | ||
9 | .is_end_event = exit_event_end, | ||
10 | .decode_key = exit_event_decode_key, | ||
11 | .name = "VM-EXIT" | ||
12 | }; | ||
13 | |||
14 | /* | ||
15 | * For the mmio events, we treat: | ||
16 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry | ||
17 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). | ||
18 | */ | ||
19 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, | ||
20 | struct event_key *key) | ||
21 | { | ||
22 | key->key = perf_evsel__intval(evsel, sample, "gpa"); | ||
23 | key->info = perf_evsel__intval(evsel, sample, "type"); | ||
24 | } | ||
25 | |||
26 | #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 | ||
27 | #define KVM_TRACE_MMIO_READ 1 | ||
28 | #define KVM_TRACE_MMIO_WRITE 2 | ||
29 | |||
30 | static bool mmio_event_begin(struct perf_evsel *evsel, | ||
31 | struct perf_sample *sample, struct event_key *key) | ||
32 | { | ||
33 | /* MMIO read begin event in kernel. */ | ||
34 | if (kvm_exit_event(evsel)) | ||
35 | return true; | ||
36 | |||
37 | /* MMIO write begin event in kernel. */ | ||
38 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
39 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { | ||
40 | mmio_event_get_key(evsel, sample, key); | ||
41 | return true; | ||
42 | } | ||
43 | |||
44 | return false; | ||
45 | } | ||
46 | |||
47 | static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, | ||
48 | struct event_key *key) | ||
49 | { | ||
50 | /* MMIO write end event in kernel. */ | ||
51 | if (kvm_entry_event(evsel)) | ||
52 | return true; | ||
53 | |||
54 | /* MMIO read end event in kernel.*/ | ||
55 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
56 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { | ||
57 | mmio_event_get_key(evsel, sample, key); | ||
58 | return true; | ||
59 | } | ||
60 | |||
61 | return false; | ||
62 | } | ||
63 | |||
64 | static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
65 | struct event_key *key, | ||
66 | char *decode) | ||
67 | { | ||
68 | scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", | ||
69 | (unsigned long)key->key, | ||
70 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); | ||
71 | } | ||
72 | |||
73 | static struct kvm_events_ops mmio_events = { | ||
74 | .is_begin_event = mmio_event_begin, | ||
75 | .is_end_event = mmio_event_end, | ||
76 | .decode_key = mmio_event_decode_key, | ||
77 | .name = "MMIO Access" | ||
78 | }; | ||
79 | |||
80 | /* The time of emulation pio access is from kvm_pio to kvm_entry. */ | ||
81 | static void ioport_event_get_key(struct perf_evsel *evsel, | ||
82 | struct perf_sample *sample, | ||
83 | struct event_key *key) | ||
84 | { | ||
85 | key->key = perf_evsel__intval(evsel, sample, "port"); | ||
86 | key->info = perf_evsel__intval(evsel, sample, "rw"); | ||
87 | } | ||
88 | |||
89 | static bool ioport_event_begin(struct perf_evsel *evsel, | ||
90 | struct perf_sample *sample, | ||
91 | struct event_key *key) | ||
92 | { | ||
93 | if (!strcmp(evsel->name, "kvm:kvm_pio")) { | ||
94 | ioport_event_get_key(evsel, sample, key); | ||
95 | return true; | ||
96 | } | ||
97 | |||
98 | return false; | ||
99 | } | ||
100 | |||
101 | static bool ioport_event_end(struct perf_evsel *evsel, | ||
102 | struct perf_sample *sample __maybe_unused, | ||
103 | struct event_key *key __maybe_unused) | ||
104 | { | ||
105 | return kvm_entry_event(evsel); | ||
106 | } | ||
107 | |||
108 | static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
109 | struct event_key *key, | ||
110 | char *decode) | ||
111 | { | ||
112 | scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", | ||
113 | (unsigned long long)key->key, | ||
114 | key->info ? "POUT" : "PIN"); | ||
115 | } | ||
116 | |||
117 | static struct kvm_events_ops ioport_events = { | ||
118 | .is_begin_event = ioport_event_begin, | ||
119 | .is_end_event = ioport_event_end, | ||
120 | .decode_key = ioport_event_decode_key, | ||
121 | .name = "IO Port Access" | ||
122 | }; | ||
123 | |||
124 | const char * const kvm_events_tp[] = { | ||
125 | "kvm:kvm_entry", | ||
126 | "kvm:kvm_exit", | ||
127 | "kvm:kvm_mmio", | ||
128 | "kvm:kvm_pio", | ||
129 | NULL, | ||
130 | }; | ||
131 | |||
132 | struct kvm_reg_events_ops kvm_reg_events_ops[] = { | ||
133 | { .name = "vmexit", .ops = &exit_events }, | ||
134 | { .name = "mmio", .ops = &mmio_events }, | ||
135 | { .name = "ioport", .ops = &ioport_events }, | ||
136 | { NULL, NULL }, | ||
137 | }; | ||
138 | |||
139 | const char * const kvm_skip_events[] = { | ||
140 | "HLT", | ||
141 | NULL, | ||
142 | }; | ||
143 | |||
144 | int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) | ||
145 | { | ||
146 | if (strstr(cpuid, "Intel")) { | ||
147 | kvm->exit_reasons = vmx_exit_reasons; | ||
148 | kvm->exit_reasons_isa = "VMX"; | ||
149 | } else if (strstr(cpuid, "AMD")) { | ||
150 | kvm->exit_reasons = svm_exit_reasons; | ||
151 | kvm->exit_reasons_isa = "SVM"; | ||
152 | } else | ||
153 | return -ENOTSUP; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 40021fa3129b..3655f24c3170 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c | |||
@@ -6,29 +6,9 @@ | |||
6 | #include "../../perf.h" | 6 | #include "../../perf.h" |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include "../../util/debug.h" | 8 | #include "../../util/debug.h" |
9 | #include "../../util/tsc.h" | ||
9 | #include "tsc.h" | 10 | #include "tsc.h" |
10 | 11 | ||
11 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) | ||
12 | { | ||
13 | u64 t, quot, rem; | ||
14 | |||
15 | t = ns - tc->time_zero; | ||
16 | quot = t / tc->time_mult; | ||
17 | rem = t % tc->time_mult; | ||
18 | return (quot << tc->time_shift) + | ||
19 | (rem << tc->time_shift) / tc->time_mult; | ||
20 | } | ||
21 | |||
22 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) | ||
23 | { | ||
24 | u64 quot, rem; | ||
25 | |||
26 | quot = cyc >> tc->time_shift; | ||
27 | rem = cyc & ((1 << tc->time_shift) - 1); | ||
28 | return tc->time_zero + quot * tc->time_mult + | ||
29 | ((rem * tc->time_mult) >> tc->time_shift); | ||
30 | } | ||
31 | |||
32 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 12 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
33 | struct perf_tsc_conversion *tc) | 13 | struct perf_tsc_conversion *tc) |
34 | { | 14 | { |
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h index 2affe0366b59..2edc4d31065c 100644 --- a/tools/perf/arch/x86/util/tsc.h +++ b/tools/perf/arch/x86/util/tsc.h | |||
@@ -14,7 +14,4 @@ struct perf_event_mmap_page; | |||
14 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 14 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
15 | struct perf_tsc_conversion *tc); | 15 | struct perf_tsc_conversion *tc); |
16 | 16 | ||
17 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | ||
18 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | ||
19 | |||
20 | #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ | 17 | #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ |
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index 3261f68c6a7c..db25e93d989c 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <libunwind.h> | 3 | #include <libunwind.h> |
4 | #include "perf_regs.h" | 4 | #include "perf_regs.h" |
5 | #include "../../util/unwind.h" | 5 | #include "../../util/unwind.h" |
6 | #include "../../util/debug.h" | ||
6 | 7 | ||
7 | #ifdef HAVE_ARCH_X86_64_SUPPORT | 8 | #ifdef HAVE_ARCH_X86_64_SUPPORT |
8 | int libunwind__arch_reg_id(int regnum) | 9 | int libunwind__arch_reg_id(int regnum) |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index b22dbb16f877..2a2c78f80876 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, | |||
125 | return ret; | 125 | return ret; |
126 | } | 126 | } |
127 | 127 | ||
128 | static int build_id_cache__add_kcore(const char *filename, const char *debugdir) | 128 | static int build_id_cache__add_kcore(const char *filename, const char *debugdir, |
129 | bool force) | ||
129 | { | 130 | { |
130 | char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; | 131 | char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; |
131 | char from_dir[PATH_MAX], to_dir[PATH_MAX]; | 132 | char from_dir[PATH_MAX], to_dir[PATH_MAX]; |
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir) | |||
144 | scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", | 145 | scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", |
145 | debugdir, sbuildid); | 146 | debugdir, sbuildid); |
146 | 147 | ||
147 | if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { | 148 | if (!force && |
149 | !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { | ||
148 | pr_debug("same kcore found in %s\n", to_dir); | 150 | pr_debug("same kcore found in %s\n", to_dir); |
149 | return 0; | 151 | return 0; |
150 | } | 152 | } |
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
389 | } | 391 | } |
390 | 392 | ||
391 | if (kcore_filename && | 393 | if (kcore_filename && |
392 | build_id_cache__add_kcore(kcore_filename, debugdir)) | 394 | build_id_cache__add_kcore(kcore_filename, debugdir, force)) |
393 | pr_warning("Couldn't add %s\n", kcore_filename); | 395 | pr_warning("Couldn't add %s\n", kcore_filename); |
394 | 396 | ||
395 | return ret; | 397 | return ret; |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index c99e0de7e54a..66e12f55c052 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "util/parse-options.h" | 15 | #include "util/parse-options.h" |
16 | #include "util/session.h" | 16 | #include "util/session.h" |
17 | #include "util/data.h" | 17 | #include "util/data.h" |
18 | #include "util/debug.h" | ||
18 | 19 | ||
19 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) | 20 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) |
20 | { | 21 | { |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 178b88ae3d2f..0384d930480b 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "util/parse-options.h" | 11 | #include "util/parse-options.h" |
12 | #include "util/run-command.h" | 12 | #include "util/run-command.h" |
13 | #include "util/help.h" | 13 | #include "util/help.h" |
14 | #include "util/debug.h" | ||
14 | 15 | ||
15 | static struct man_viewer_list { | 16 | static struct man_viewer_list { |
16 | struct man_viewer_list *next; | 17 | struct man_viewer_list *next; |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 16c7c11ad06e..cf6a605a13e8 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject) | |||
389 | ret = perf_session__process_events(session, &inject->tool); | 389 | ret = perf_session__process_events(session, &inject->tool); |
390 | 390 | ||
391 | if (!file_out->is_pipe) { | 391 | if (!file_out->is_pipe) { |
392 | if (inject->build_ids) | ||
393 | perf_header__set_feat(&session->header, | ||
394 | HEADER_BUILD_ID); | ||
392 | session->header.data_size = inject->bytes_written; | 395 | session->header.data_size = inject->bytes_written; |
393 | perf_session__write_header(session, session->evlist, file_out->fd, true); | 396 | perf_session__write_header(session, session->evlist, file_out->fd, true); |
394 | } | 397 | } |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 41dbeaf8cc11..43367eb00510 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -30,112 +30,24 @@ | |||
30 | #include <math.h> | 30 | #include <math.h> |
31 | 31 | ||
32 | #ifdef HAVE_KVM_STAT_SUPPORT | 32 | #ifdef HAVE_KVM_STAT_SUPPORT |
33 | #include <asm/svm.h> | 33 | #include <asm/kvm_perf.h> |
34 | #include <asm/vmx.h> | 34 | #include "util/kvm-stat.h" |
35 | #include <asm/kvm.h> | ||
36 | |||
37 | struct event_key { | ||
38 | #define INVALID_KEY (~0ULL) | ||
39 | u64 key; | ||
40 | int info; | ||
41 | }; | ||
42 | |||
43 | struct kvm_event_stats { | ||
44 | u64 time; | ||
45 | struct stats stats; | ||
46 | }; | ||
47 | |||
48 | struct kvm_event { | ||
49 | struct list_head hash_entry; | ||
50 | struct rb_node rb; | ||
51 | |||
52 | struct event_key key; | ||
53 | |||
54 | struct kvm_event_stats total; | ||
55 | |||
56 | #define DEFAULT_VCPU_NUM 8 | ||
57 | int max_vcpu; | ||
58 | struct kvm_event_stats *vcpu; | ||
59 | }; | ||
60 | |||
61 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
62 | |||
63 | struct kvm_event_key { | ||
64 | const char *name; | ||
65 | key_cmp_fun key; | ||
66 | }; | ||
67 | |||
68 | |||
69 | struct perf_kvm_stat; | ||
70 | |||
71 | struct kvm_events_ops { | ||
72 | bool (*is_begin_event)(struct perf_evsel *evsel, | ||
73 | struct perf_sample *sample, | ||
74 | struct event_key *key); | ||
75 | bool (*is_end_event)(struct perf_evsel *evsel, | ||
76 | struct perf_sample *sample, struct event_key *key); | ||
77 | void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, | ||
78 | char decode[20]); | ||
79 | const char *name; | ||
80 | }; | ||
81 | |||
82 | struct exit_reasons_table { | ||
83 | unsigned long exit_code; | ||
84 | const char *reason; | ||
85 | }; | ||
86 | |||
87 | #define EVENTS_BITS 12 | ||
88 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
89 | |||
90 | struct perf_kvm_stat { | ||
91 | struct perf_tool tool; | ||
92 | struct record_opts opts; | ||
93 | struct perf_evlist *evlist; | ||
94 | struct perf_session *session; | ||
95 | |||
96 | const char *file_name; | ||
97 | const char *report_event; | ||
98 | const char *sort_key; | ||
99 | int trace_vcpu; | ||
100 | |||
101 | struct exit_reasons_table *exit_reasons; | ||
102 | const char *exit_reasons_isa; | ||
103 | |||
104 | struct kvm_events_ops *events_ops; | ||
105 | key_cmp_fun compare; | ||
106 | struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
107 | |||
108 | u64 total_time; | ||
109 | u64 total_count; | ||
110 | u64 lost_events; | ||
111 | u64 duration; | ||
112 | |||
113 | const char *pid_str; | ||
114 | struct intlist *pid_list; | ||
115 | 35 | ||
116 | struct rb_root result; | 36 | void exit_event_get_key(struct perf_evsel *evsel, |
117 | 37 | struct perf_sample *sample, | |
118 | int timerfd; | 38 | struct event_key *key) |
119 | unsigned int display_time; | ||
120 | bool live; | ||
121 | }; | ||
122 | |||
123 | |||
124 | static void exit_event_get_key(struct perf_evsel *evsel, | ||
125 | struct perf_sample *sample, | ||
126 | struct event_key *key) | ||
127 | { | 39 | { |
128 | key->info = 0; | 40 | key->info = 0; |
129 | key->key = perf_evsel__intval(evsel, sample, "exit_reason"); | 41 | key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); |
130 | } | 42 | } |
131 | 43 | ||
132 | static bool kvm_exit_event(struct perf_evsel *evsel) | 44 | bool kvm_exit_event(struct perf_evsel *evsel) |
133 | { | 45 | { |
134 | return !strcmp(evsel->name, "kvm:kvm_exit"); | 46 | return !strcmp(evsel->name, KVM_EXIT_TRACE); |
135 | } | 47 | } |
136 | 48 | ||
137 | static bool exit_event_begin(struct perf_evsel *evsel, | 49 | bool exit_event_begin(struct perf_evsel *evsel, |
138 | struct perf_sample *sample, struct event_key *key) | 50 | struct perf_sample *sample, struct event_key *key) |
139 | { | 51 | { |
140 | if (kvm_exit_event(evsel)) { | 52 | if (kvm_exit_event(evsel)) { |
141 | exit_event_get_key(evsel, sample, key); | 53 | exit_event_get_key(evsel, sample, key); |
@@ -145,26 +57,18 @@ static bool exit_event_begin(struct perf_evsel *evsel, | |||
145 | return false; | 57 | return false; |
146 | } | 58 | } |
147 | 59 | ||
148 | static bool kvm_entry_event(struct perf_evsel *evsel) | 60 | bool kvm_entry_event(struct perf_evsel *evsel) |
149 | { | 61 | { |
150 | return !strcmp(evsel->name, "kvm:kvm_entry"); | 62 | return !strcmp(evsel->name, KVM_ENTRY_TRACE); |
151 | } | 63 | } |
152 | 64 | ||
153 | static bool exit_event_end(struct perf_evsel *evsel, | 65 | bool exit_event_end(struct perf_evsel *evsel, |
154 | struct perf_sample *sample __maybe_unused, | 66 | struct perf_sample *sample __maybe_unused, |
155 | struct event_key *key __maybe_unused) | 67 | struct event_key *key __maybe_unused) |
156 | { | 68 | { |
157 | return kvm_entry_event(evsel); | 69 | return kvm_entry_event(evsel); |
158 | } | 70 | } |
159 | 71 | ||
160 | #define define_exit_reasons_table(name, symbols) \ | ||
161 | static struct exit_reasons_table name[] = { \ | ||
162 | symbols, { -1, NULL } \ | ||
163 | } | ||
164 | |||
165 | define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); | ||
166 | define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); | ||
167 | |||
168 | static const char *get_exit_reason(struct perf_kvm_stat *kvm, | 72 | static const char *get_exit_reason(struct perf_kvm_stat *kvm, |
169 | struct exit_reasons_table *tbl, | 73 | struct exit_reasons_table *tbl, |
170 | u64 exit_code) | 74 | u64 exit_code) |
@@ -180,149 +84,30 @@ static const char *get_exit_reason(struct perf_kvm_stat *kvm, | |||
180 | return "UNKNOWN"; | 84 | return "UNKNOWN"; |
181 | } | 85 | } |
182 | 86 | ||
183 | static void exit_event_decode_key(struct perf_kvm_stat *kvm, | 87 | void exit_event_decode_key(struct perf_kvm_stat *kvm, |
184 | struct event_key *key, | 88 | struct event_key *key, |
185 | char decode[20]) | 89 | char *decode) |
186 | { | 90 | { |
187 | const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons, | 91 | const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, |
188 | key->key); | 92 | key->key); |
189 | 93 | ||
190 | scnprintf(decode, 20, "%s", exit_reason); | 94 | scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); |
191 | } | 95 | } |
192 | 96 | ||
193 | static struct kvm_events_ops exit_events = { | 97 | static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) |
194 | .is_begin_event = exit_event_begin, | ||
195 | .is_end_event = exit_event_end, | ||
196 | .decode_key = exit_event_decode_key, | ||
197 | .name = "VM-EXIT" | ||
198 | }; | ||
199 | |||
200 | /* | ||
201 | * For the mmio events, we treat: | ||
202 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry | ||
203 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). | ||
204 | */ | ||
205 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, | ||
206 | struct event_key *key) | ||
207 | { | ||
208 | key->key = perf_evsel__intval(evsel, sample, "gpa"); | ||
209 | key->info = perf_evsel__intval(evsel, sample, "type"); | ||
210 | } | ||
211 | |||
212 | #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 | ||
213 | #define KVM_TRACE_MMIO_READ 1 | ||
214 | #define KVM_TRACE_MMIO_WRITE 2 | ||
215 | |||
216 | static bool mmio_event_begin(struct perf_evsel *evsel, | ||
217 | struct perf_sample *sample, struct event_key *key) | ||
218 | { | ||
219 | /* MMIO read begin event in kernel. */ | ||
220 | if (kvm_exit_event(evsel)) | ||
221 | return true; | ||
222 | |||
223 | /* MMIO write begin event in kernel. */ | ||
224 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
225 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { | ||
226 | mmio_event_get_key(evsel, sample, key); | ||
227 | return true; | ||
228 | } | ||
229 | |||
230 | return false; | ||
231 | } | ||
232 | |||
233 | static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, | ||
234 | struct event_key *key) | ||
235 | { | ||
236 | /* MMIO write end event in kernel. */ | ||
237 | if (kvm_entry_event(evsel)) | ||
238 | return true; | ||
239 | |||
240 | /* MMIO read end event in kernel.*/ | ||
241 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
242 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { | ||
243 | mmio_event_get_key(evsel, sample, key); | ||
244 | return true; | ||
245 | } | ||
246 | |||
247 | return false; | ||
248 | } | ||
249 | |||
250 | static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
251 | struct event_key *key, | ||
252 | char decode[20]) | ||
253 | { | ||
254 | scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, | ||
255 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); | ||
256 | } | ||
257 | |||
258 | static struct kvm_events_ops mmio_events = { | ||
259 | .is_begin_event = mmio_event_begin, | ||
260 | .is_end_event = mmio_event_end, | ||
261 | .decode_key = mmio_event_decode_key, | ||
262 | .name = "MMIO Access" | ||
263 | }; | ||
264 | |||
265 | /* The time of emulation pio access is from kvm_pio to kvm_entry. */ | ||
266 | static void ioport_event_get_key(struct perf_evsel *evsel, | ||
267 | struct perf_sample *sample, | ||
268 | struct event_key *key) | ||
269 | { | 98 | { |
270 | key->key = perf_evsel__intval(evsel, sample, "port"); | 99 | struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops; |
271 | key->info = perf_evsel__intval(evsel, sample, "rw"); | ||
272 | } | ||
273 | 100 | ||
274 | static bool ioport_event_begin(struct perf_evsel *evsel, | 101 | for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) { |
275 | struct perf_sample *sample, | 102 | if (!strcmp(events_ops->name, kvm->report_event)) { |
276 | struct event_key *key) | 103 | kvm->events_ops = events_ops->ops; |
277 | { | 104 | return true; |
278 | if (!strcmp(evsel->name, "kvm:kvm_pio")) { | 105 | } |
279 | ioport_event_get_key(evsel, sample, key); | ||
280 | return true; | ||
281 | } | 106 | } |
282 | 107 | ||
283 | return false; | 108 | return false; |
284 | } | 109 | } |
285 | 110 | ||
286 | static bool ioport_event_end(struct perf_evsel *evsel, | ||
287 | struct perf_sample *sample __maybe_unused, | ||
288 | struct event_key *key __maybe_unused) | ||
289 | { | ||
290 | return kvm_entry_event(evsel); | ||
291 | } | ||
292 | |||
293 | static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
294 | struct event_key *key, | ||
295 | char decode[20]) | ||
296 | { | ||
297 | scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, | ||
298 | key->info ? "POUT" : "PIN"); | ||
299 | } | ||
300 | |||
301 | static struct kvm_events_ops ioport_events = { | ||
302 | .is_begin_event = ioport_event_begin, | ||
303 | .is_end_event = ioport_event_end, | ||
304 | .decode_key = ioport_event_decode_key, | ||
305 | .name = "IO Port Access" | ||
306 | }; | ||
307 | |||
308 | static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) | ||
309 | { | ||
310 | bool ret = true; | ||
311 | |||
312 | if (!strcmp(kvm->report_event, "vmexit")) | ||
313 | kvm->events_ops = &exit_events; | ||
314 | else if (!strcmp(kvm->report_event, "mmio")) | ||
315 | kvm->events_ops = &mmio_events; | ||
316 | else if (!strcmp(kvm->report_event, "ioport")) | ||
317 | kvm->events_ops = &ioport_events; | ||
318 | else { | ||
319 | pr_err("Unknown report event:%s\n", kvm->report_event); | ||
320 | ret = false; | ||
321 | } | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | struct vcpu_event_record { | 111 | struct vcpu_event_record { |
327 | int vcpu_id; | 112 | int vcpu_id; |
328 | u64 start_time; | 113 | u64 start_time; |
@@ -476,6 +261,54 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, | |||
476 | return true; | 261 | return true; |
477 | } | 262 | } |
478 | 263 | ||
264 | static bool is_child_event(struct perf_kvm_stat *kvm, | ||
265 | struct perf_evsel *evsel, | ||
266 | struct perf_sample *sample, | ||
267 | struct event_key *key) | ||
268 | { | ||
269 | struct child_event_ops *child_ops; | ||
270 | |||
271 | child_ops = kvm->events_ops->child_ops; | ||
272 | |||
273 | if (!child_ops) | ||
274 | return false; | ||
275 | |||
276 | for (; child_ops->name; child_ops++) { | ||
277 | if (!strcmp(evsel->name, child_ops->name)) { | ||
278 | child_ops->get_key(evsel, sample, key); | ||
279 | return true; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | return false; | ||
284 | } | ||
285 | |||
286 | static bool handle_child_event(struct perf_kvm_stat *kvm, | ||
287 | struct vcpu_event_record *vcpu_record, | ||
288 | struct event_key *key, | ||
289 | struct perf_sample *sample __maybe_unused) | ||
290 | { | ||
291 | struct kvm_event *event = NULL; | ||
292 | |||
293 | if (key->key != INVALID_KEY) | ||
294 | event = find_create_kvm_event(kvm, key); | ||
295 | |||
296 | vcpu_record->last_event = event; | ||
297 | |||
298 | return true; | ||
299 | } | ||
300 | |||
301 | static bool skip_event(const char *event) | ||
302 | { | ||
303 | const char * const *skip_events; | ||
304 | |||
305 | for (skip_events = kvm_skip_events; *skip_events; skip_events++) | ||
306 | if (!strcmp(event, *skip_events)) | ||
307 | return true; | ||
308 | |||
309 | return false; | ||
310 | } | ||
311 | |||
479 | static bool handle_end_event(struct perf_kvm_stat *kvm, | 312 | static bool handle_end_event(struct perf_kvm_stat *kvm, |
480 | struct vcpu_event_record *vcpu_record, | 313 | struct vcpu_event_record *vcpu_record, |
481 | struct event_key *key, | 314 | struct event_key *key, |
@@ -524,10 +357,10 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, | |||
524 | time_diff = sample->time - time_begin; | 357 | time_diff = sample->time - time_begin; |
525 | 358 | ||
526 | if (kvm->duration && time_diff > kvm->duration) { | 359 | if (kvm->duration && time_diff > kvm->duration) { |
527 | char decode[32]; | 360 | char decode[DECODE_STR_LEN]; |
528 | 361 | ||
529 | kvm->events_ops->decode_key(kvm, &event->key, decode); | 362 | kvm->events_ops->decode_key(kvm, &event->key, decode); |
530 | if (strcmp(decode, "HLT")) { | 363 | if (!skip_event(decode)) { |
531 | pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", | 364 | pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", |
532 | sample->time, sample->pid, vcpu_record->vcpu_id, | 365 | sample->time, sample->pid, vcpu_record->vcpu_id, |
533 | decode, time_diff/1000); | 366 | decode, time_diff/1000); |
@@ -552,7 +385,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, | |||
552 | return NULL; | 385 | return NULL; |
553 | } | 386 | } |
554 | 387 | ||
555 | vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); | 388 | vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); |
556 | thread->priv = vcpu_record; | 389 | thread->priv = vcpu_record; |
557 | } | 390 | } |
558 | 391 | ||
@@ -565,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, | |||
565 | struct perf_sample *sample) | 398 | struct perf_sample *sample) |
566 | { | 399 | { |
567 | struct vcpu_event_record *vcpu_record; | 400 | struct vcpu_event_record *vcpu_record; |
568 | struct event_key key = {.key = INVALID_KEY}; | 401 | struct event_key key = { .key = INVALID_KEY, |
402 | .exit_reasons = kvm->exit_reasons }; | ||
569 | 403 | ||
570 | vcpu_record = per_vcpu_record(thread, evsel, sample); | 404 | vcpu_record = per_vcpu_record(thread, evsel, sample); |
571 | if (!vcpu_record) | 405 | if (!vcpu_record) |
@@ -579,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, | |||
579 | if (kvm->events_ops->is_begin_event(evsel, sample, &key)) | 413 | if (kvm->events_ops->is_begin_event(evsel, sample, &key)) |
580 | return handle_begin_event(kvm, vcpu_record, &key, sample->time); | 414 | return handle_begin_event(kvm, vcpu_record, &key, sample->time); |
581 | 415 | ||
416 | if (is_child_event(kvm, evsel, sample, &key)) | ||
417 | return handle_child_event(kvm, vcpu_record, &key, sample); | ||
418 | |||
582 | if (kvm->events_ops->is_end_event(evsel, sample, &key)) | 419 | if (kvm->events_ops->is_end_event(evsel, sample, &key)) |
583 | return handle_end_event(kvm, vcpu_record, &key, sample); | 420 | return handle_end_event(kvm, vcpu_record, &key, sample); |
584 | 421 | ||
@@ -739,7 +576,7 @@ static void show_timeofday(void) | |||
739 | 576 | ||
740 | static void print_result(struct perf_kvm_stat *kvm) | 577 | static void print_result(struct perf_kvm_stat *kvm) |
741 | { | 578 | { |
742 | char decode[20]; | 579 | char decode[DECODE_STR_LEN]; |
743 | struct kvm_event *event; | 580 | struct kvm_event *event; |
744 | int vcpu = kvm->trace_vcpu; | 581 | int vcpu = kvm->trace_vcpu; |
745 | 582 | ||
@@ -750,7 +587,7 @@ static void print_result(struct perf_kvm_stat *kvm) | |||
750 | 587 | ||
751 | pr_info("\n\n"); | 588 | pr_info("\n\n"); |
752 | print_vcpu_info(kvm); | 589 | print_vcpu_info(kvm); |
753 | pr_info("%20s ", kvm->events_ops->name); | 590 | pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name); |
754 | pr_info("%10s ", "Samples"); | 591 | pr_info("%10s ", "Samples"); |
755 | pr_info("%9s ", "Samples%"); | 592 | pr_info("%9s ", "Samples%"); |
756 | 593 | ||
@@ -769,7 +606,7 @@ static void print_result(struct perf_kvm_stat *kvm) | |||
769 | min = get_event_min(event, vcpu); | 606 | min = get_event_min(event, vcpu); |
770 | 607 | ||
771 | kvm->events_ops->decode_key(kvm, &event->key, decode); | 608 | kvm->events_ops->decode_key(kvm, &event->key, decode); |
772 | pr_info("%20s ", decode); | 609 | pr_info("%*s ", DECODE_STR_LEN, decode); |
773 | pr_info("%10llu ", (unsigned long long)ecount); | 610 | pr_info("%10llu ", (unsigned long long)ecount); |
774 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); | 611 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); |
775 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); | 612 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); |
@@ -835,20 +672,6 @@ static int process_sample_event(struct perf_tool *tool, | |||
835 | return 0; | 672 | return 0; |
836 | } | 673 | } |
837 | 674 | ||
838 | static int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) | ||
839 | { | ||
840 | if (strstr(cpuid, "Intel")) { | ||
841 | kvm->exit_reasons = vmx_exit_reasons; | ||
842 | kvm->exit_reasons_isa = "VMX"; | ||
843 | } else if (strstr(cpuid, "AMD")) { | ||
844 | kvm->exit_reasons = svm_exit_reasons; | ||
845 | kvm->exit_reasons_isa = "SVM"; | ||
846 | } else | ||
847 | return -ENOTSUP; | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static int cpu_isa_config(struct perf_kvm_stat *kvm) | 675 | static int cpu_isa_config(struct perf_kvm_stat *kvm) |
853 | { | 676 | { |
854 | char buf[64], *cpuid; | 677 | char buf[64], *cpuid; |
@@ -1307,13 +1130,6 @@ exit: | |||
1307 | return ret; | 1130 | return ret; |
1308 | } | 1131 | } |
1309 | 1132 | ||
1310 | static const char * const kvm_events_tp[] = { | ||
1311 | "kvm:kvm_entry", | ||
1312 | "kvm:kvm_exit", | ||
1313 | "kvm:kvm_mmio", | ||
1314 | "kvm:kvm_pio", | ||
1315 | }; | ||
1316 | |||
1317 | #define STRDUP_FAIL_EXIT(s) \ | 1133 | #define STRDUP_FAIL_EXIT(s) \ |
1318 | ({ char *_p; \ | 1134 | ({ char *_p; \ |
1319 | _p = strdup(s); \ | 1135 | _p = strdup(s); \ |
@@ -1325,7 +1141,7 @@ static const char * const kvm_events_tp[] = { | |||
1325 | static int | 1141 | static int |
1326 | kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) | 1142 | kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) |
1327 | { | 1143 | { |
1328 | unsigned int rec_argc, i, j; | 1144 | unsigned int rec_argc, i, j, events_tp_size; |
1329 | const char **rec_argv; | 1145 | const char **rec_argv; |
1330 | const char * const record_args[] = { | 1146 | const char * const record_args[] = { |
1331 | "record", | 1147 | "record", |
@@ -1333,9 +1149,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1333 | "-m", "1024", | 1149 | "-m", "1024", |
1334 | "-c", "1", | 1150 | "-c", "1", |
1335 | }; | 1151 | }; |
1152 | const char * const *events_tp; | ||
1153 | events_tp_size = 0; | ||
1154 | |||
1155 | for (events_tp = kvm_events_tp; *events_tp; events_tp++) | ||
1156 | events_tp_size++; | ||
1336 | 1157 | ||
1337 | rec_argc = ARRAY_SIZE(record_args) + argc + 2 + | 1158 | rec_argc = ARRAY_SIZE(record_args) + argc + 2 + |
1338 | 2 * ARRAY_SIZE(kvm_events_tp); | 1159 | 2 * events_tp_size; |
1339 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1160 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1340 | 1161 | ||
1341 | if (rec_argv == NULL) | 1162 | if (rec_argv == NULL) |
@@ -1344,7 +1165,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1344 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1165 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1345 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); | 1166 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); |
1346 | 1167 | ||
1347 | for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { | 1168 | for (j = 0; j < events_tp_size; j++) { |
1348 | rec_argv[i++] = "-e"; | 1169 | rec_argv[i++] = "-e"; |
1349 | rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); | 1170 | rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); |
1350 | } | 1171 | } |
@@ -1363,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1363 | { | 1184 | { |
1364 | const struct option kvm_events_report_options[] = { | 1185 | const struct option kvm_events_report_options[] = { |
1365 | OPT_STRING(0, "event", &kvm->report_event, "report event", | 1186 | OPT_STRING(0, "event", &kvm->report_event, "report event", |
1366 | "event for reporting: vmexit, mmio, ioport"), | 1187 | "event for reporting: vmexit, " |
1188 | "mmio (x86 only), ioport (x86 only)"), | ||
1367 | OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, | 1189 | OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, |
1368 | "vcpu id to report"), | 1190 | "vcpu id to report"), |
1369 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", | 1191 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", |
@@ -1398,16 +1220,16 @@ static struct perf_evlist *kvm_live_event_list(void) | |||
1398 | { | 1220 | { |
1399 | struct perf_evlist *evlist; | 1221 | struct perf_evlist *evlist; |
1400 | char *tp, *name, *sys; | 1222 | char *tp, *name, *sys; |
1401 | unsigned int j; | ||
1402 | int err = -1; | 1223 | int err = -1; |
1224 | const char * const *events_tp; | ||
1403 | 1225 | ||
1404 | evlist = perf_evlist__new(); | 1226 | evlist = perf_evlist__new(); |
1405 | if (evlist == NULL) | 1227 | if (evlist == NULL) |
1406 | return NULL; | 1228 | return NULL; |
1407 | 1229 | ||
1408 | for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { | 1230 | for (events_tp = kvm_events_tp; *events_tp; events_tp++) { |
1409 | 1231 | ||
1410 | tp = strdup(kvm_events_tp[j]); | 1232 | tp = strdup(*events_tp); |
1411 | if (tp == NULL) | 1233 | if (tp == NULL) |
1412 | goto out; | 1234 | goto out; |
1413 | 1235 | ||
@@ -1416,7 +1238,7 @@ static struct perf_evlist *kvm_live_event_list(void) | |||
1416 | name = strchr(tp, ':'); | 1238 | name = strchr(tp, ':'); |
1417 | if (name == NULL) { | 1239 | if (name == NULL) { |
1418 | pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", | 1240 | pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", |
1419 | kvm_events_tp[j]); | 1241 | *events_tp); |
1420 | free(tp); | 1242 | free(tp); |
1421 | goto out; | 1243 | goto out; |
1422 | } | 1244 | } |
@@ -1424,7 +1246,7 @@ static struct perf_evlist *kvm_live_event_list(void) | |||
1424 | name++; | 1246 | name++; |
1425 | 1247 | ||
1426 | if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { | 1248 | if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { |
1427 | pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]); | 1249 | pr_err("Failed to add %s tracepoint to the list\n", *events_tp); |
1428 | free(tp); | 1250 | free(tp); |
1429 | goto out; | 1251 | goto out; |
1430 | } | 1252 | } |
@@ -1469,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, | |||
1469 | "key for sorting: sample(sort by samples number)" | 1291 | "key for sorting: sample(sort by samples number)" |
1470 | " time (sort by avg time)"), | 1292 | " time (sort by avg time)"), |
1471 | OPT_U64(0, "duration", &kvm->duration, | 1293 | OPT_U64(0, "duration", &kvm->duration, |
1472 | "show events other than HALT that take longer than duration usecs"), | 1294 | "show events other than" |
1295 | " HLT (x86 only) or Wait state (s390 only)" | ||
1296 | " that take longer than duration usecs"), | ||
1473 | OPT_END() | 1297 | OPT_END() |
1474 | }; | 1298 | }; |
1475 | const char * const live_usage[] = { | 1299 | const char * const live_usage[] = { |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index c38d06c04775..b7f555add0c8 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched, | |||
935 | return -1; | 935 | return -1; |
936 | } | 936 | } |
937 | 937 | ||
938 | sched_out = machine__findnew_thread(machine, 0, prev_pid); | 938 | sched_out = machine__findnew_thread(machine, -1, prev_pid); |
939 | sched_in = machine__findnew_thread(machine, 0, next_pid); | 939 | sched_in = machine__findnew_thread(machine, -1, next_pid); |
940 | 940 | ||
941 | out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); | 941 | out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); |
942 | if (!out_events) { | 942 | if (!out_events) { |
@@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched, | |||
979 | { | 979 | { |
980 | const u32 pid = perf_evsel__intval(evsel, sample, "pid"); | 980 | const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
981 | const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); | 981 | const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); |
982 | struct thread *thread = machine__findnew_thread(machine, 0, pid); | 982 | struct thread *thread = machine__findnew_thread(machine, -1, pid); |
983 | struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); | 983 | struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); |
984 | u64 timestamp = sample->time; | 984 | u64 timestamp = sample->time; |
985 | int cpu = sample->cpu; | 985 | int cpu = sample->cpu; |
@@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched, | |||
1012 | struct thread *wakee; | 1012 | struct thread *wakee; |
1013 | u64 timestamp = sample->time; | 1013 | u64 timestamp = sample->time; |
1014 | 1014 | ||
1015 | wakee = machine__findnew_thread(machine, 0, pid); | 1015 | wakee = machine__findnew_thread(machine, -1, pid); |
1016 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); | 1016 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); |
1017 | if (!atoms) { | 1017 | if (!atoms) { |
1018 | if (thread_atoms_insert(sched, wakee)) | 1018 | if (thread_atoms_insert(sched, wakee)) |
@@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, | |||
1072 | if (sched->profile_cpu == -1) | 1072 | if (sched->profile_cpu == -1) |
1073 | return 0; | 1073 | return 0; |
1074 | 1074 | ||
1075 | migrant = machine__findnew_thread(machine, 0, pid); | 1075 | migrant = machine__findnew_thread(machine, -1, pid); |
1076 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1076 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
1077 | if (!atoms) { | 1077 | if (!atoms) { |
1078 | if (thread_atoms_insert(sched, migrant)) | 1078 | if (thread_atoms_insert(sched, migrant)) |
@@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1290 | return -1; | 1290 | return -1; |
1291 | } | 1291 | } |
1292 | 1292 | ||
1293 | sched_in = machine__findnew_thread(machine, 0, next_pid); | 1293 | sched_in = machine__findnew_thread(machine, -1, next_pid); |
1294 | 1294 | ||
1295 | sched->curr_thread[this_cpu] = sched_in; | 1295 | sched->curr_thread[this_cpu] = sched_in; |
1296 | 1296 | ||
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 04c9c53becad..2f1a5220c090 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "util/svghelper.h" | 37 | #include "util/svghelper.h" |
38 | #include "util/tool.h" | 38 | #include "util/tool.h" |
39 | #include "util/data.h" | 39 | #include "util/data.h" |
40 | #include "util/debug.h" | ||
40 | 41 | ||
41 | #define SUPPORT_OLD_POWER_EVENTS 1 | 42 | #define SUPPORT_OLD_POWER_EVENTS 1 |
42 | #define PWR_EVENT_EXIT -1 | 43 | #define PWR_EVENT_EXIT -1 |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b7f42d577c4e..1f67aa02d240 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -164,6 +164,7 @@ CORE_FEATURE_TESTS = \ | |||
164 | backtrace \ | 164 | backtrace \ |
165 | dwarf \ | 165 | dwarf \ |
166 | fortify-source \ | 166 | fortify-source \ |
167 | sync-compare-and-swap \ | ||
167 | glibc \ | 168 | glibc \ |
168 | gtk2 \ | 169 | gtk2 \ |
169 | gtk2-infobar \ | 170 | gtk2-infobar \ |
@@ -199,6 +200,7 @@ LIB_FEATURE_TESTS = \ | |||
199 | VF_FEATURE_TESTS = \ | 200 | VF_FEATURE_TESTS = \ |
200 | backtrace \ | 201 | backtrace \ |
201 | fortify-source \ | 202 | fortify-source \ |
203 | sync-compare-and-swap \ | ||
202 | gtk2-infobar \ | 204 | gtk2-infobar \ |
203 | libelf-getphdrnum \ | 205 | libelf-getphdrnum \ |
204 | libelf-mmap \ | 206 | libelf-mmap \ |
@@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE) | |||
272 | 274 | ||
273 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | 275 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE |
274 | 276 | ||
277 | ifeq ($(feature-sync-compare-and-swap), 1) | ||
278 | CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT | ||
279 | endif | ||
280 | |||
275 | ifndef NO_BIONIC | 281 | ifndef NO_BIONIC |
276 | $(call feature_check,bionic) | 282 | $(call feature_check,bionic) |
277 | ifeq ($(feature-bionic), 1) | 283 | ifeq ($(feature-bionic), 1) |
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 64c84e5f0514..6088f8d8a434 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -5,6 +5,7 @@ FILES= \ | |||
5 | test-bionic.bin \ | 5 | test-bionic.bin \ |
6 | test-dwarf.bin \ | 6 | test-dwarf.bin \ |
7 | test-fortify-source.bin \ | 7 | test-fortify-source.bin \ |
8 | test-sync-compare-and-swap.bin \ | ||
8 | test-glibc.bin \ | 9 | test-glibc.bin \ |
9 | test-gtk2.bin \ | 10 | test-gtk2.bin \ |
10 | test-gtk2-infobar.bin \ | 11 | test-gtk2-infobar.bin \ |
@@ -141,6 +142,9 @@ test-timerfd.bin: | |||
141 | test-libdw-dwarf-unwind.bin: | 142 | test-libdw-dwarf-unwind.bin: |
142 | $(BUILD) | 143 | $(BUILD) |
143 | 144 | ||
145 | test-sync-compare-and-swap.bin: | ||
146 | $(BUILD) -Werror | ||
147 | |||
144 | -include *.d | 148 | -include *.d |
145 | 149 | ||
146 | ############################### | 150 | ############################### |
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index fe5c1e5c952f..a7d022e161c0 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c | |||
@@ -89,6 +89,10 @@ | |||
89 | # include "test-libdw-dwarf-unwind.c" | 89 | # include "test-libdw-dwarf-unwind.c" |
90 | #undef main | 90 | #undef main |
91 | 91 | ||
92 | #define main main_test_sync_compare_and_swap | ||
93 | # include "test-sync-compare-and-swap.c" | ||
94 | #undef main | ||
95 | |||
92 | int main(int argc, char *argv[]) | 96 | int main(int argc, char *argv[]) |
93 | { | 97 | { |
94 | main_test_libpython(); | 98 | main_test_libpython(); |
@@ -111,6 +115,7 @@ int main(int argc, char *argv[]) | |||
111 | main_test_timerfd(); | 115 | main_test_timerfd(); |
112 | main_test_stackprotector_all(); | 116 | main_test_stackprotector_all(); |
113 | main_test_libdw_dwarf_unwind(); | 117 | main_test_libdw_dwarf_unwind(); |
118 | main_test_sync_compare_and_swap(argc, argv); | ||
114 | 119 | ||
115 | return 0; | 120 | return 0; |
116 | } | 121 | } |
diff --git a/tools/perf/config/feature-checks/test-sync-compare-and-swap.c b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file mode 100644 index 000000000000..c34d4ca4af56 --- /dev/null +++ b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c | |||
@@ -0,0 +1,14 @@ | |||
1 | #include <stdint.h> | ||
2 | |||
3 | volatile uint64_t x; | ||
4 | |||
5 | int main(int argc, char *argv[]) | ||
6 | { | ||
7 | uint64_t old, new = argc; | ||
8 | |||
9 | argv = argv; | ||
10 | do { | ||
11 | old = __sync_val_compare_and_swap(&x, 0, 0); | ||
12 | } while (!__sync_bool_compare_and_swap(&x, old, new)); | ||
13 | return old == new; | ||
14 | } | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 95c58fc15284..eed3fb2a3af0 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -13,11 +13,12 @@ | |||
13 | #include "util/quote.h" | 13 | #include "util/quote.h" |
14 | #include "util/run-command.h" | 14 | #include "util/run-command.h" |
15 | #include "util/parse-events.h" | 15 | #include "util/parse-events.h" |
16 | #include "util/debug.h" | ||
16 | #include <api/fs/debugfs.h> | 17 | #include <api/fs/debugfs.h> |
17 | #include <pthread.h> | 18 | #include <pthread.h> |
18 | 19 | ||
19 | const char perf_usage_string[] = | 20 | const char perf_usage_string[] = |
20 | "perf [--version] [--help] COMMAND [ARGS]"; | 21 | "perf [--version] [--debug variable[=VALUE]] [--help] COMMAND [ARGS]"; |
21 | 22 | ||
22 | const char perf_more_info_string[] = | 23 | const char perf_more_info_string[] = |
23 | "See 'perf help COMMAND' for more information on a specific command."; | 24 | "See 'perf help COMMAND' for more information on a specific command."; |
@@ -212,6 +213,16 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
212 | printf("%s ", p->cmd); | 213 | printf("%s ", p->cmd); |
213 | } | 214 | } |
214 | exit(0); | 215 | exit(0); |
216 | } else if (!strcmp(cmd, "--debug")) { | ||
217 | if (*argc < 2) { | ||
218 | fprintf(stderr, "No variable specified for --debug.\n"); | ||
219 | usage(perf_usage_string); | ||
220 | } | ||
221 | if (perf_debug_option((*argv)[1])) | ||
222 | usage(perf_usage_string); | ||
223 | |||
224 | (*argv)++; | ||
225 | (*argc)--; | ||
215 | } else { | 226 | } else { |
216 | fprintf(stderr, "Unknown option: %s\n", cmd); | 227 | fprintf(stderr, "Unknown option: %s\n", cmd); |
217 | usage(perf_usage_string); | 228 | usage(perf_usage_string); |
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py index de7211e4fa47..38dfb720fb6f 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py | |||
@@ -107,12 +107,13 @@ def taskState(state): | |||
107 | 107 | ||
108 | class EventHeaders: | 108 | class EventHeaders: |
109 | def __init__(self, common_cpu, common_secs, common_nsecs, | 109 | def __init__(self, common_cpu, common_secs, common_nsecs, |
110 | common_pid, common_comm): | 110 | common_pid, common_comm, common_callchain): |
111 | self.cpu = common_cpu | 111 | self.cpu = common_cpu |
112 | self.secs = common_secs | 112 | self.secs = common_secs |
113 | self.nsecs = common_nsecs | 113 | self.nsecs = common_nsecs |
114 | self.pid = common_pid | 114 | self.pid = common_pid |
115 | self.comm = common_comm | 115 | self.comm = common_comm |
116 | self.callchain = common_callchain | ||
116 | 117 | ||
117 | def ts(self): | 118 | def ts(self): |
118 | return (self.secs * (10 ** 9)) + self.nsecs | 119 | return (self.secs * (10 ** 9)) + self.nsecs |
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py index 4647a7694cf6..334599c6032c 100644 --- a/tools/perf/scripts/python/check-perf-trace.py +++ b/tools/perf/scripts/python/check-perf-trace.py | |||
@@ -27,7 +27,7 @@ def trace_end(): | |||
27 | 27 | ||
28 | def irq__softirq_entry(event_name, context, common_cpu, | 28 | def irq__softirq_entry(event_name, context, common_cpu, |
29 | common_secs, common_nsecs, common_pid, common_comm, | 29 | common_secs, common_nsecs, common_pid, common_comm, |
30 | vec): | 30 | common_callchain, vec): |
31 | print_header(event_name, common_cpu, common_secs, common_nsecs, | 31 | print_header(event_name, common_cpu, common_secs, common_nsecs, |
32 | common_pid, common_comm) | 32 | common_pid, common_comm) |
33 | 33 | ||
@@ -38,7 +38,7 @@ def irq__softirq_entry(event_name, context, common_cpu, | |||
38 | 38 | ||
39 | def kmem__kmalloc(event_name, context, common_cpu, | 39 | def kmem__kmalloc(event_name, context, common_cpu, |
40 | common_secs, common_nsecs, common_pid, common_comm, | 40 | common_secs, common_nsecs, common_pid, common_comm, |
41 | call_site, ptr, bytes_req, bytes_alloc, | 41 | common_callchain, call_site, ptr, bytes_req, bytes_alloc, |
42 | gfp_flags): | 42 | gfp_flags): |
43 | print_header(event_name, common_cpu, common_secs, common_nsecs, | 43 | print_header(event_name, common_cpu, common_secs, common_nsecs, |
44 | common_pid, common_comm) | 44 | common_pid, common_comm) |
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py index 266a8364bce5..cafeff3d74db 100644 --- a/tools/perf/scripts/python/failed-syscalls-by-pid.py +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py | |||
@@ -39,7 +39,7 @@ def trace_end(): | |||
39 | 39 | ||
40 | def raw_syscalls__sys_exit(event_name, context, common_cpu, | 40 | def raw_syscalls__sys_exit(event_name, context, common_cpu, |
41 | common_secs, common_nsecs, common_pid, common_comm, | 41 | common_secs, common_nsecs, common_pid, common_comm, |
42 | id, ret): | 42 | common_callchain, id, ret): |
43 | if (for_comm and common_comm != for_comm) or \ | 43 | if (for_comm and common_comm != for_comm) or \ |
44 | (for_pid and common_pid != for_pid ): | 44 | (for_pid and common_pid != for_pid ): |
45 | return | 45 | return |
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py index 11e70a388d41..0f5cf437b602 100644 --- a/tools/perf/scripts/python/futex-contention.py +++ b/tools/perf/scripts/python/futex-contention.py | |||
@@ -21,7 +21,7 @@ thread_blocktime = {} | |||
21 | lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time | 21 | lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time |
22 | process_names = {} # long-lived pid-to-execname mapping | 22 | process_names = {} # long-lived pid-to-execname mapping |
23 | 23 | ||
24 | def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, | 24 | def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, |
25 | nr, uaddr, op, val, utime, uaddr2, val3): | 25 | nr, uaddr, op, val, utime, uaddr2, val3): |
26 | cmd = op & FUTEX_CMD_MASK | 26 | cmd = op & FUTEX_CMD_MASK |
27 | if cmd != FUTEX_WAIT: | 27 | if cmd != FUTEX_WAIT: |
@@ -31,7 +31,7 @@ def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, | |||
31 | thread_thislock[tid] = uaddr | 31 | thread_thislock[tid] = uaddr |
32 | thread_blocktime[tid] = nsecs(s, ns) | 32 | thread_blocktime[tid] = nsecs(s, ns) |
33 | 33 | ||
34 | def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, | 34 | def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, |
35 | nr, ret): | 35 | nr, ret): |
36 | if thread_blocktime.has_key(tid): | 36 | if thread_blocktime.has_key(tid): |
37 | elapsed = nsecs(s, ns) - thread_blocktime[tid] | 37 | elapsed = nsecs(s, ns) - thread_blocktime[tid] |
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py index b5740599aabd..0b6ce8c253e8 100755 --- a/tools/perf/scripts/python/net_dropmonitor.py +++ b/tools/perf/scripts/python/net_dropmonitor.py | |||
@@ -66,7 +66,7 @@ def trace_end(): | |||
66 | print_drop_table() | 66 | print_drop_table() |
67 | 67 | ||
68 | # called from perf, when it finds a correspoinding event | 68 | # called from perf, when it finds a correspoinding event |
69 | def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, | 69 | def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, |
70 | skbaddr, location, protocol): | 70 | skbaddr, location, protocol): |
71 | slocation = str(location) | 71 | slocation = str(location) |
72 | try: | 72 | try: |
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py index 9aa0a32972e8..4d21ef2d601d 100644 --- a/tools/perf/scripts/python/netdev-times.py +++ b/tools/perf/scripts/python/netdev-times.py | |||
@@ -224,75 +224,75 @@ def trace_end(): | |||
224 | (len(rx_skb_list), of_count_rx_skb_list) | 224 | (len(rx_skb_list), of_count_rx_skb_list) |
225 | 225 | ||
226 | # called from perf, when it finds a correspoinding event | 226 | # called from perf, when it finds a correspoinding event |
227 | def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): | 227 | def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): |
228 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": | 228 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": |
229 | return | 229 | return |
230 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) | 230 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) |
231 | all_event_list.append(event_info) | 231 | all_event_list.append(event_info) |
232 | 232 | ||
233 | def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): | 233 | def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec): |
234 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": | 234 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": |
235 | return | 235 | return |
236 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) | 236 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) |
237 | all_event_list.append(event_info) | 237 | all_event_list.append(event_info) |
238 | 238 | ||
239 | def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): | 239 | def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec): |
240 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": | 240 | if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": |
241 | return | 241 | return |
242 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) | 242 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) |
243 | all_event_list.append(event_info) | 243 | all_event_list.append(event_info) |
244 | 244 | ||
245 | def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, | 245 | def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, |
246 | irq, irq_name): | 246 | callchain, irq, irq_name): |
247 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 247 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
248 | irq, irq_name) | 248 | irq, irq_name) |
249 | all_event_list.append(event_info) | 249 | all_event_list.append(event_info) |
250 | 250 | ||
251 | def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): | 251 | def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret): |
252 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) | 252 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) |
253 | all_event_list.append(event_info) | 253 | all_event_list.append(event_info) |
254 | 254 | ||
255 | def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): | 255 | def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name): |
256 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 256 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
257 | napi, dev_name) | 257 | napi, dev_name) |
258 | all_event_list.append(event_info) | 258 | all_event_list.append(event_info) |
259 | 259 | ||
260 | def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, | 260 | def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, |
261 | skblen, dev_name): | 261 | skblen, dev_name): |
262 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 262 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
263 | skbaddr, skblen, dev_name) | 263 | skbaddr, skblen, dev_name) |
264 | all_event_list.append(event_info) | 264 | all_event_list.append(event_info) |
265 | 265 | ||
266 | def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, | 266 | def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, |
267 | skblen, dev_name): | 267 | skblen, dev_name): |
268 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 268 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
269 | skbaddr, skblen, dev_name) | 269 | skbaddr, skblen, dev_name) |
270 | all_event_list.append(event_info) | 270 | all_event_list.append(event_info) |
271 | 271 | ||
272 | def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, | 272 | def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain, |
273 | skbaddr, skblen, dev_name): | 273 | skbaddr, skblen, dev_name): |
274 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 274 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
275 | skbaddr, skblen, dev_name) | 275 | skbaddr, skblen, dev_name) |
276 | all_event_list.append(event_info) | 276 | all_event_list.append(event_info) |
277 | 277 | ||
278 | def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, | 278 | def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain, |
279 | skbaddr, skblen, rc, dev_name): | 279 | skbaddr, skblen, rc, dev_name): |
280 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 280 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
281 | skbaddr, skblen, rc ,dev_name) | 281 | skbaddr, skblen, rc ,dev_name) |
282 | all_event_list.append(event_info) | 282 | all_event_list.append(event_info) |
283 | 283 | ||
284 | def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, | 284 | def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, |
285 | skbaddr, protocol, location): | 285 | skbaddr, protocol, location): |
286 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 286 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
287 | skbaddr, protocol, location) | 287 | skbaddr, protocol, location) |
288 | all_event_list.append(event_info) | 288 | all_event_list.append(event_info) |
289 | 289 | ||
290 | def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): | 290 | def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr): |
291 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 291 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
292 | skbaddr) | 292 | skbaddr) |
293 | all_event_list.append(event_info) | 293 | all_event_list.append(event_info) |
294 | 294 | ||
295 | def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, | 295 | def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain, |
296 | skbaddr, skblen): | 296 | skbaddr, skblen): |
297 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 297 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
298 | skbaddr, skblen) | 298 | skbaddr, skblen) |
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py index 74d55ec08aed..de66cb3b72c9 100644 --- a/tools/perf/scripts/python/sched-migration.py +++ b/tools/perf/scripts/python/sched-migration.py | |||
@@ -369,93 +369,92 @@ def trace_end(): | |||
369 | 369 | ||
370 | def sched__sched_stat_runtime(event_name, context, common_cpu, | 370 | def sched__sched_stat_runtime(event_name, context, common_cpu, |
371 | common_secs, common_nsecs, common_pid, common_comm, | 371 | common_secs, common_nsecs, common_pid, common_comm, |
372 | comm, pid, runtime, vruntime): | 372 | common_callchain, comm, pid, runtime, vruntime): |
373 | pass | 373 | pass |
374 | 374 | ||
375 | def sched__sched_stat_iowait(event_name, context, common_cpu, | 375 | def sched__sched_stat_iowait(event_name, context, common_cpu, |
376 | common_secs, common_nsecs, common_pid, common_comm, | 376 | common_secs, common_nsecs, common_pid, common_comm, |
377 | comm, pid, delay): | 377 | common_callchain, comm, pid, delay): |
378 | pass | 378 | pass |
379 | 379 | ||
380 | def sched__sched_stat_sleep(event_name, context, common_cpu, | 380 | def sched__sched_stat_sleep(event_name, context, common_cpu, |
381 | common_secs, common_nsecs, common_pid, common_comm, | 381 | common_secs, common_nsecs, common_pid, common_comm, |
382 | comm, pid, delay): | 382 | common_callchain, comm, pid, delay): |
383 | pass | 383 | pass |
384 | 384 | ||
385 | def sched__sched_stat_wait(event_name, context, common_cpu, | 385 | def sched__sched_stat_wait(event_name, context, common_cpu, |
386 | common_secs, common_nsecs, common_pid, common_comm, | 386 | common_secs, common_nsecs, common_pid, common_comm, |
387 | comm, pid, delay): | 387 | common_callchain, comm, pid, delay): |
388 | pass | 388 | pass |
389 | 389 | ||
390 | def sched__sched_process_fork(event_name, context, common_cpu, | 390 | def sched__sched_process_fork(event_name, context, common_cpu, |
391 | common_secs, common_nsecs, common_pid, common_comm, | 391 | common_secs, common_nsecs, common_pid, common_comm, |
392 | parent_comm, parent_pid, child_comm, child_pid): | 392 | common_callchain, parent_comm, parent_pid, child_comm, child_pid): |
393 | pass | 393 | pass |
394 | 394 | ||
395 | def sched__sched_process_wait(event_name, context, common_cpu, | 395 | def sched__sched_process_wait(event_name, context, common_cpu, |
396 | common_secs, common_nsecs, common_pid, common_comm, | 396 | common_secs, common_nsecs, common_pid, common_comm, |
397 | comm, pid, prio): | 397 | common_callchain, comm, pid, prio): |
398 | pass | 398 | pass |
399 | 399 | ||
400 | def sched__sched_process_exit(event_name, context, common_cpu, | 400 | def sched__sched_process_exit(event_name, context, common_cpu, |
401 | common_secs, common_nsecs, common_pid, common_comm, | 401 | common_secs, common_nsecs, common_pid, common_comm, |
402 | comm, pid, prio): | 402 | common_callchain, comm, pid, prio): |
403 | pass | 403 | pass |
404 | 404 | ||
405 | def sched__sched_process_free(event_name, context, common_cpu, | 405 | def sched__sched_process_free(event_name, context, common_cpu, |
406 | common_secs, common_nsecs, common_pid, common_comm, | 406 | common_secs, common_nsecs, common_pid, common_comm, |
407 | comm, pid, prio): | 407 | common_callchain, comm, pid, prio): |
408 | pass | 408 | pass |
409 | 409 | ||
410 | def sched__sched_migrate_task(event_name, context, common_cpu, | 410 | def sched__sched_migrate_task(event_name, context, common_cpu, |
411 | common_secs, common_nsecs, common_pid, common_comm, | 411 | common_secs, common_nsecs, common_pid, common_comm, |
412 | comm, pid, prio, orig_cpu, | 412 | common_callchain, comm, pid, prio, orig_cpu, |
413 | dest_cpu): | 413 | dest_cpu): |
414 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, | 414 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, |
415 | common_pid, common_comm) | 415 | common_pid, common_comm, common_callchain) |
416 | parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) | 416 | parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) |
417 | 417 | ||
418 | def sched__sched_switch(event_name, context, common_cpu, | 418 | def sched__sched_switch(event_name, context, common_cpu, |
419 | common_secs, common_nsecs, common_pid, common_comm, | 419 | common_secs, common_nsecs, common_pid, common_comm, common_callchain, |
420 | prev_comm, prev_pid, prev_prio, prev_state, | 420 | prev_comm, prev_pid, prev_prio, prev_state, |
421 | next_comm, next_pid, next_prio): | 421 | next_comm, next_pid, next_prio): |
422 | 422 | ||
423 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, | 423 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, |
424 | common_pid, common_comm) | 424 | common_pid, common_comm, common_callchain) |
425 | parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, | 425 | parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, |
426 | next_comm, next_pid, next_prio) | 426 | next_comm, next_pid, next_prio) |
427 | 427 | ||
428 | def sched__sched_wakeup_new(event_name, context, common_cpu, | 428 | def sched__sched_wakeup_new(event_name, context, common_cpu, |
429 | common_secs, common_nsecs, common_pid, common_comm, | 429 | common_secs, common_nsecs, common_pid, common_comm, |
430 | comm, pid, prio, success, | 430 | common_callchain, comm, pid, prio, success, |
431 | target_cpu): | 431 | target_cpu): |
432 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, | 432 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, |
433 | common_pid, common_comm) | 433 | common_pid, common_comm, common_callchain) |
434 | parser.wake_up(headers, comm, pid, success, target_cpu, 1) | 434 | parser.wake_up(headers, comm, pid, success, target_cpu, 1) |
435 | 435 | ||
436 | def sched__sched_wakeup(event_name, context, common_cpu, | 436 | def sched__sched_wakeup(event_name, context, common_cpu, |
437 | common_secs, common_nsecs, common_pid, common_comm, | 437 | common_secs, common_nsecs, common_pid, common_comm, |
438 | comm, pid, prio, success, | 438 | common_callchain, comm, pid, prio, success, |
439 | target_cpu): | 439 | target_cpu): |
440 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, | 440 | headers = EventHeaders(common_cpu, common_secs, common_nsecs, |
441 | common_pid, common_comm) | 441 | common_pid, common_comm, common_callchain) |
442 | parser.wake_up(headers, comm, pid, success, target_cpu, 0) | 442 | parser.wake_up(headers, comm, pid, success, target_cpu, 0) |
443 | 443 | ||
444 | def sched__sched_wait_task(event_name, context, common_cpu, | 444 | def sched__sched_wait_task(event_name, context, common_cpu, |
445 | common_secs, common_nsecs, common_pid, common_comm, | 445 | common_secs, common_nsecs, common_pid, common_comm, |
446 | comm, pid, prio): | 446 | common_callchain, comm, pid, prio): |
447 | pass | 447 | pass |
448 | 448 | ||
449 | def sched__sched_kthread_stop_ret(event_name, context, common_cpu, | 449 | def sched__sched_kthread_stop_ret(event_name, context, common_cpu, |
450 | common_secs, common_nsecs, common_pid, common_comm, | 450 | common_secs, common_nsecs, common_pid, common_comm, |
451 | ret): | 451 | common_callchain, ret): |
452 | pass | 452 | pass |
453 | 453 | ||
454 | def sched__sched_kthread_stop(event_name, context, common_cpu, | 454 | def sched__sched_kthread_stop(event_name, context, common_cpu, |
455 | common_secs, common_nsecs, common_pid, common_comm, | 455 | common_secs, common_nsecs, common_pid, common_comm, |
456 | comm, pid): | 456 | common_callchain, comm, pid): |
457 | pass | 457 | pass |
458 | 458 | ||
459 | def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, | 459 | def trace_unhandled(event_name, context, event_fields_dict): |
460 | common_pid, common_comm): | ||
461 | pass | 460 | pass |
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py index c9f3058b7dd4..61621b93affb 100644 --- a/tools/perf/scripts/python/sctop.py +++ b/tools/perf/scripts/python/sctop.py | |||
@@ -44,7 +44,7 @@ def trace_begin(): | |||
44 | 44 | ||
45 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | 45 | def raw_syscalls__sys_enter(event_name, context, common_cpu, |
46 | common_secs, common_nsecs, common_pid, common_comm, | 46 | common_secs, common_nsecs, common_pid, common_comm, |
47 | id, args): | 47 | common_callchain, id, args): |
48 | if for_comm is not None: | 48 | if for_comm is not None: |
49 | if common_comm != for_comm: | 49 | if common_comm != for_comm: |
50 | return | 50 | return |
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py index cf2054c529c9..daf314cc5dd3 100644 --- a/tools/perf/scripts/python/syscall-counts-by-pid.py +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py | |||
@@ -38,7 +38,7 @@ def trace_end(): | |||
38 | 38 | ||
39 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | 39 | def raw_syscalls__sys_enter(event_name, context, common_cpu, |
40 | common_secs, common_nsecs, common_pid, common_comm, | 40 | common_secs, common_nsecs, common_pid, common_comm, |
41 | id, args): | 41 | common_callchain, id, args): |
42 | 42 | ||
43 | if (for_comm and common_comm != for_comm) or \ | 43 | if (for_comm and common_comm != for_comm) or \ |
44 | (for_pid and common_pid != for_pid ): | 44 | (for_pid and common_pid != for_pid ): |
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py index 92b29381bd39..e66a7730aeb5 100644 --- a/tools/perf/scripts/python/syscall-counts.py +++ b/tools/perf/scripts/python/syscall-counts.py | |||
@@ -35,7 +35,7 @@ def trace_end(): | |||
35 | 35 | ||
36 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | 36 | def raw_syscalls__sys_enter(event_name, context, common_cpu, |
37 | common_secs, common_nsecs, common_pid, common_comm, | 37 | common_secs, common_nsecs, common_pid, common_comm, |
38 | id, args): | 38 | common_callchain, id, args): |
39 | if for_comm is not None: | 39 | if for_comm is not None: |
40 | if common_comm != for_comm: | 40 | if common_comm != for_comm: |
41 | return | 41 | return |
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 630808cd7cc2..caaf37f079b1 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "machine.h" | 10 | #include "machine.h" |
11 | #include "symbol.h" | 11 | #include "symbol.h" |
12 | #include "tests.h" | 12 | #include "tests.h" |
13 | #include "debug.h" | ||
13 | 14 | ||
14 | static char *test_file(int size) | 15 | static char *test_file(int size) |
15 | { | 16 | { |
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 465cdbc345cf..b8d8341b383e 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "evsel.h" | 2 | #include "evsel.h" |
3 | #include "parse-events.h" | 3 | #include "parse-events.h" |
4 | #include "tests.h" | 4 | #include "tests.h" |
5 | #include "debug.h" | ||
5 | 6 | ||
6 | static int perf_evsel__roundtrip_cache_name_test(void) | 7 | static int perf_evsel__roundtrip_cache_name_test(void) |
7 | { | 8 | { |
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 35d7fdb2328d..52162425c969 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <traceevent/event-parse.h> | 1 | #include <traceevent/event-parse.h> |
2 | #include "evsel.h" | 2 | #include "evsel.h" |
3 | #include "tests.h" | 3 | #include "tests.h" |
4 | #include "debug.h" | ||
4 | 5 | ||
5 | static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, | 6 | static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, |
6 | int size, bool should_be_signed) | 7 | int size, bool should_be_signed) |
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index c505ef2af245..0785b64ffd6c 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "evsel.h" | 3 | #include "evsel.h" |
4 | #include "thread_map.h" | 4 | #include "thread_map.h" |
5 | #include "tests.h" | 5 | #include "tests.h" |
6 | #include "debug.h" | ||
6 | 7 | ||
7 | int test__syscall_open_tp_fields(void) | 8 | int test__syscall_open_tp_fields(void) |
8 | { | 9 | { |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index deba66955f8c..5941927a4b7f 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <api/fs/fs.h> | 5 | #include <api/fs/fs.h> |
6 | #include <api/fs/debugfs.h> | 6 | #include <api/fs/debugfs.h> |
7 | #include "tests.h" | 7 | #include "tests.h" |
8 | #include "debug.h" | ||
8 | #include <linux/hw_breakpoint.h> | 9 | #include <linux/hw_breakpoint.h> |
9 | 10 | ||
10 | #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ | 11 | #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ |
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 905019f9b740..2c63ea658541 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "evlist.h" | 7 | #include "evlist.h" |
8 | #include "header.h" | 8 | #include "header.h" |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debug.h" | ||
10 | 11 | ||
11 | static int process_event(struct perf_evlist **pevlist, union perf_event *event) | 12 | static int process_event(struct perf_evlist **pevlist, union perf_event *event) |
12 | { | 13 | { |
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 3b7cd4d32dcb..0372f6edca20 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c | |||
@@ -8,10 +8,9 @@ | |||
8 | #include "evsel.h" | 8 | #include "evsel.h" |
9 | #include "thread_map.h" | 9 | #include "thread_map.h" |
10 | #include "cpumap.h" | 10 | #include "cpumap.h" |
11 | #include "tsc.h" | ||
11 | #include "tests.h" | 12 | #include "tests.h" |
12 | 13 | ||
13 | #include "../arch/x86/util/tsc.h" | ||
14 | |||
15 | #define CHECK__(x) { \ | 14 | #define CHECK__(x) { \ |
16 | while ((x) < 0) { \ | 15 | while ((x) < 0) { \ |
17 | pr_debug(#x " failed!\n"); \ | 16 | pr_debug(#x " failed!\n"); \ |
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 7ae8d17db3d9..ca292f9a4ae2 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "util.h" | 4 | #include "util.h" |
5 | #include "event.h" | 5 | #include "event.h" |
6 | #include "evsel.h" | 6 | #include "evsel.h" |
7 | #include "debug.h" | ||
7 | 8 | ||
8 | #include "tests.h" | 9 | #include "tests.h" |
9 | 10 | ||
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c index 2b2e0dbe114f..b028499dd3cf 100644 --- a/tools/perf/tests/thread-mg-share.c +++ b/tools/perf/tests/thread-mg-share.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "machine.h" | 2 | #include "machine.h" |
3 | #include "thread.h" | 3 | #include "thread.h" |
4 | #include "map.h" | 4 | #include "map.h" |
5 | #include "debug.h" | ||
5 | 6 | ||
6 | int test__thread_mg_share(void) | 7 | int test__thread_mg_share(void) |
7 | { | 8 | { |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 90122abd3721..40af0acb4fe9 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -479,7 +479,7 @@ print_entries: | |||
479 | 479 | ||
480 | if (h->ms.map == NULL && verbose > 1) { | 480 | if (h->ms.map == NULL && verbose > 1) { |
481 | __map_groups__fprintf_maps(h->thread->mg, | 481 | __map_groups__fprintf_maps(h->thread->mg, |
482 | MAP__FUNCTION, verbose, fp); | 482 | MAP__FUNCTION, fp); |
483 | fprintf(fp, "%.10s end\n", graph_dotted_line); | 483 | fprintf(fp, "%.10s end\n", graph_dotted_line); |
484 | } | 484 | } |
485 | } | 485 | } |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 48b6d3f50012..437ee09727e6 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent | |||
626 | 626 | ||
627 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) | 627 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) |
628 | { | 628 | { |
629 | if (!symbol_conf.use_callchain) | 629 | if (!symbol_conf.use_callchain || sample->callchain == NULL) |
630 | return 0; | 630 | return 0; |
631 | return callchain_append(he->callchain, &callchain_cursor, sample->period); | 631 | return callchain_append(he->callchain, &callchain_cursor, sample->period); |
632 | } | 632 | } |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index ee370a7f2444..29d720cf5844 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include "data.h" | 8 | #include "data.h" |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debug.h" | ||
10 | 11 | ||
11 | static bool check_pipe(struct perf_data_file *file) | 12 | static bool check_pipe(struct perf_data_file *file) |
12 | { | 13 | { |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 299b55586502..71d419362634 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -16,11 +16,11 @@ | |||
16 | int verbose; | 16 | int verbose; |
17 | bool dump_trace = false, quiet = false; | 17 | bool dump_trace = false, quiet = false; |
18 | 18 | ||
19 | static int _eprintf(int level, const char *fmt, va_list args) | 19 | static int _eprintf(int level, int var, const char *fmt, va_list args) |
20 | { | 20 | { |
21 | int ret = 0; | 21 | int ret = 0; |
22 | 22 | ||
23 | if (verbose >= level) { | 23 | if (var >= level) { |
24 | if (use_browser >= 1) | 24 | if (use_browser >= 1) |
25 | ui_helpline__vshow(fmt, args); | 25 | ui_helpline__vshow(fmt, args); |
26 | else | 26 | else |
@@ -30,13 +30,13 @@ static int _eprintf(int level, const char *fmt, va_list args) | |||
30 | return ret; | 30 | return ret; |
31 | } | 31 | } |
32 | 32 | ||
33 | int eprintf(int level, const char *fmt, ...) | 33 | int eprintf(int level, int var, const char *fmt, ...) |
34 | { | 34 | { |
35 | va_list args; | 35 | va_list args; |
36 | int ret; | 36 | int ret; |
37 | 37 | ||
38 | va_start(args, fmt); | 38 | va_start(args, fmt); |
39 | ret = _eprintf(level, fmt, args); | 39 | ret = _eprintf(level, var, fmt, args); |
40 | va_end(args); | 40 | va_end(args); |
41 | 41 | ||
42 | return ret; | 42 | return ret; |
@@ -51,9 +51,9 @@ void pr_stat(const char *fmt, ...) | |||
51 | va_list args; | 51 | va_list args; |
52 | 52 | ||
53 | va_start(args, fmt); | 53 | va_start(args, fmt); |
54 | _eprintf(1, fmt, args); | 54 | _eprintf(1, verbose, fmt, args); |
55 | va_end(args); | 55 | va_end(args); |
56 | eprintf(1, "\n"); | 56 | eprintf(1, verbose, "\n"); |
57 | } | 57 | } |
58 | 58 | ||
59 | int dump_printf(const char *fmt, ...) | 59 | int dump_printf(const char *fmt, ...) |
@@ -105,3 +105,47 @@ void trace_event(union perf_event *event) | |||
105 | } | 105 | } |
106 | printf(".\n"); | 106 | printf(".\n"); |
107 | } | 107 | } |
108 | |||
109 | static struct debug_variable { | ||
110 | const char *name; | ||
111 | int *ptr; | ||
112 | } debug_variables[] = { | ||
113 | { .name = "verbose", .ptr = &verbose }, | ||
114 | { .name = NULL, } | ||
115 | }; | ||
116 | |||
117 | int perf_debug_option(const char *str) | ||
118 | { | ||
119 | struct debug_variable *var = &debug_variables[0]; | ||
120 | char *vstr, *s = strdup(str); | ||
121 | int v = 1; | ||
122 | |||
123 | vstr = strchr(s, '='); | ||
124 | if (vstr) | ||
125 | *vstr++ = 0; | ||
126 | |||
127 | while (var->name) { | ||
128 | if (!strcmp(s, var->name)) | ||
129 | break; | ||
130 | var++; | ||
131 | } | ||
132 | |||
133 | if (!var->name) { | ||
134 | pr_err("Unknown debug variable name '%s'\n", s); | ||
135 | free(s); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | if (vstr) { | ||
140 | v = atoi(vstr); | ||
141 | /* | ||
142 | * Allow only values in range (0, 10), | ||
143 | * otherwise set 0. | ||
144 | */ | ||
145 | v = (v < 0) || (v > 10) ? 0 : v; | ||
146 | } | ||
147 | |||
148 | *var->ptr = v; | ||
149 | free(s); | ||
150 | return 0; | ||
151 | } | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 443694c36b03..89fb6b0f7ab2 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -11,6 +11,24 @@ | |||
11 | extern int verbose; | 11 | extern int verbose; |
12 | extern bool quiet, dump_trace; | 12 | extern bool quiet, dump_trace; |
13 | 13 | ||
14 | #ifndef pr_fmt | ||
15 | #define pr_fmt(fmt) fmt | ||
16 | #endif | ||
17 | |||
18 | #define pr_err(fmt, ...) \ | ||
19 | eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) | ||
20 | #define pr_warning(fmt, ...) \ | ||
21 | eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) | ||
22 | #define pr_info(fmt, ...) \ | ||
23 | eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) | ||
24 | #define pr_debug(fmt, ...) \ | ||
25 | eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__) | ||
26 | #define pr_debugN(n, fmt, ...) \ | ||
27 | eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__) | ||
28 | #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) | ||
29 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) | ||
30 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) | ||
31 | |||
14 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 32 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
15 | void trace_event(union perf_event *event); | 33 | void trace_event(union perf_event *event); |
16 | 34 | ||
@@ -19,4 +37,8 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | |||
19 | 37 | ||
20 | void pr_stat(const char *fmt, ...); | 38 | void pr_stat(const char *fmt, ...); |
21 | 39 | ||
40 | int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); | ||
41 | |||
42 | int perf_debug_option(const char *str); | ||
43 | |||
22 | #endif /* __PERF_DEBUG_H */ | 44 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 819f10414f08..fc006fed8877 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -703,6 +703,7 @@ struct dso *dso__new(const char *name) | |||
703 | dso->data.fd = -1; | 703 | dso->data.fd = -1; |
704 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | 704 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
705 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; | 705 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
706 | dso->is_64_bit = (sizeof(void *) == 8); | ||
706 | dso->loaded = 0; | 707 | dso->loaded = 0; |
707 | dso->rel = 0; | 708 | dso->rel = 0; |
708 | dso->sorted_by_name = 0; | 709 | dso->sorted_by_name = 0; |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ad553ba257bf..c239e86541a3 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -90,6 +90,7 @@ struct dso { | |||
90 | u8 annotate_warned:1; | 90 | u8 annotate_warned:1; |
91 | u8 short_name_allocated:1; | 91 | u8 short_name_allocated:1; |
92 | u8 long_name_allocated:1; | 92 | u8 long_name_allocated:1; |
93 | u8 is_64_bit:1; | ||
93 | u8 sorted_by_name; | 94 | u8 sorted_by_name; |
94 | u8 loaded; | 95 | u8 loaded; |
95 | u8 rel; | 96 | u8 rel; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index d0281bdfa582..7e0e8ae568ec 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
603 | 603 | ||
604 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) | 604 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) |
605 | { | 605 | { |
606 | return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); | 606 | const char *s; |
607 | |||
608 | if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC) | ||
609 | s = " exec"; | ||
610 | else | ||
611 | s = ""; | ||
612 | |||
613 | return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid); | ||
607 | } | 614 | } |
608 | 615 | ||
609 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, | 616 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, |
@@ -781,6 +788,7 @@ try_again: | |||
781 | cpumode == PERF_RECORD_MISC_USER && | 788 | cpumode == PERF_RECORD_MISC_USER && |
782 | machine && mg != &machine->kmaps) { | 789 | machine && mg != &machine->kmaps) { |
783 | mg = &machine->kmaps; | 790 | mg = &machine->kmaps; |
791 | load_map = true; | ||
784 | goto try_again; | 792 | goto try_again; |
785 | } | 793 | } |
786 | } else { | 794 | } else { |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c51223ac25f4..814e954c1318 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | |||
606 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 606 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
607 | } | 607 | } |
608 | 608 | ||
609 | static int __perf_evlist__mmap(struct perf_evlist *evlist, | 609 | struct mmap_params { |
610 | int idx, int prot, int mask, int fd) | 610 | int prot; |
611 | int mask; | ||
612 | }; | ||
613 | |||
614 | static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, | ||
615 | struct mmap_params *mp, int fd) | ||
611 | { | 616 | { |
612 | evlist->mmap[idx].prev = 0; | 617 | evlist->mmap[idx].prev = 0; |
613 | evlist->mmap[idx].mask = mask; | 618 | evlist->mmap[idx].mask = mp->mask; |
614 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, | 619 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, |
615 | MAP_SHARED, fd, 0); | 620 | MAP_SHARED, fd, 0); |
616 | if (evlist->mmap[idx].base == MAP_FAILED) { | 621 | if (evlist->mmap[idx].base == MAP_FAILED) { |
617 | pr_debug2("failed to mmap perf event ring buffer, error %d\n", | 622 | pr_debug2("failed to mmap perf event ring buffer, error %d\n", |
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, | |||
625 | } | 630 | } |
626 | 631 | ||
627 | static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | 632 | static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, |
628 | int prot, int mask, int cpu, int thread, | 633 | struct mmap_params *mp, int cpu, |
629 | int *output) | 634 | int thread, int *output) |
630 | { | 635 | { |
631 | struct perf_evsel *evsel; | 636 | struct perf_evsel *evsel; |
632 | 637 | ||
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
635 | 640 | ||
636 | if (*output == -1) { | 641 | if (*output == -1) { |
637 | *output = fd; | 642 | *output = fd; |
638 | if (__perf_evlist__mmap(evlist, idx, prot, mask, | 643 | if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0) |
639 | *output) < 0) | ||
640 | return -1; | 644 | return -1; |
641 | } else { | 645 | } else { |
642 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) | 646 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) |
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
651 | return 0; | 655 | return 0; |
652 | } | 656 | } |
653 | 657 | ||
654 | static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, | 658 | static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, |
655 | int mask) | 659 | struct mmap_params *mp) |
656 | { | 660 | { |
657 | int cpu, thread; | 661 | int cpu, thread; |
658 | int nr_cpus = cpu_map__nr(evlist->cpus); | 662 | int nr_cpus = cpu_map__nr(evlist->cpus); |
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, | |||
663 | int output = -1; | 667 | int output = -1; |
664 | 668 | ||
665 | for (thread = 0; thread < nr_threads; thread++) { | 669 | for (thread = 0; thread < nr_threads; thread++) { |
666 | if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, | 670 | if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, |
667 | cpu, thread, &output)) | 671 | thread, &output)) |
668 | goto out_unmap; | 672 | goto out_unmap; |
669 | } | 673 | } |
670 | } | 674 | } |
@@ -677,8 +681,8 @@ out_unmap: | |||
677 | return -1; | 681 | return -1; |
678 | } | 682 | } |
679 | 683 | ||
680 | static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, | 684 | static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, |
681 | int mask) | 685 | struct mmap_params *mp) |
682 | { | 686 | { |
683 | int thread; | 687 | int thread; |
684 | int nr_threads = thread_map__nr(evlist->threads); | 688 | int nr_threads = thread_map__nr(evlist->threads); |
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, | |||
687 | for (thread = 0; thread < nr_threads; thread++) { | 691 | for (thread = 0; thread < nr_threads; thread++) { |
688 | int output = -1; | 692 | int output = -1; |
689 | 693 | ||
690 | if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, | 694 | if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, |
691 | thread, &output)) | 695 | &output)) |
692 | goto out_unmap; | 696 | goto out_unmap; |
693 | } | 697 | } |
694 | 698 | ||
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
793 | struct perf_evsel *evsel; | 797 | struct perf_evsel *evsel; |
794 | const struct cpu_map *cpus = evlist->cpus; | 798 | const struct cpu_map *cpus = evlist->cpus; |
795 | const struct thread_map *threads = evlist->threads; | 799 | const struct thread_map *threads = evlist->threads; |
796 | int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; | 800 | struct mmap_params mp = { |
801 | .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), | ||
802 | }; | ||
797 | 803 | ||
798 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) | 804 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) |
799 | return -ENOMEM; | 805 | return -ENOMEM; |
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
804 | evlist->overwrite = overwrite; | 810 | evlist->overwrite = overwrite; |
805 | evlist->mmap_len = perf_evlist__mmap_size(pages); | 811 | evlist->mmap_len = perf_evlist__mmap_size(pages); |
806 | pr_debug("mmap size %zuB\n", evlist->mmap_len); | 812 | pr_debug("mmap size %zuB\n", evlist->mmap_len); |
807 | mask = evlist->mmap_len - page_size - 1; | 813 | mp.mask = evlist->mmap_len - page_size - 1; |
808 | 814 | ||
809 | evlist__for_each(evlist, evsel) { | 815 | evlist__for_each(evlist, evsel) { |
810 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 816 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
814 | } | 820 | } |
815 | 821 | ||
816 | if (cpu_map__empty(cpus)) | 822 | if (cpu_map__empty(cpus)) |
817 | return perf_evlist__mmap_per_thread(evlist, prot, mask); | 823 | return perf_evlist__mmap_per_thread(evlist, &mp); |
818 | 824 | ||
819 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); | 825 | return perf_evlist__mmap_per_cpu(evlist, &mp); |
820 | } | 826 | } |
821 | 827 | ||
822 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | 828 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8606175fe1e8..90f58cdd0fb0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
623 | attr->mmap_data = track; | 623 | attr->mmap_data = track; |
624 | } | 624 | } |
625 | 625 | ||
626 | if (opts->call_graph_enabled) | 626 | if (opts->call_graph_enabled && !evsel->no_aux_samples) |
627 | perf_evsel__config_callgraph(evsel, opts); | 627 | perf_evsel__config_callgraph(evsel, opts); |
628 | 628 | ||
629 | if (target__has_cpu(&opts->target)) | 629 | if (target__has_cpu(&opts->target)) |
@@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
637 | target__has_cpu(&opts->target) || per_cpu)) | 637 | target__has_cpu(&opts->target) || per_cpu)) |
638 | perf_evsel__set_sample_bit(evsel, TIME); | 638 | perf_evsel__set_sample_bit(evsel, TIME); |
639 | 639 | ||
640 | if (opts->raw_samples) { | 640 | if (opts->raw_samples && !evsel->no_aux_samples) { |
641 | perf_evsel__set_sample_bit(evsel, TIME); | 641 | perf_evsel__set_sample_bit(evsel, TIME); |
642 | perf_evsel__set_sample_bit(evsel, RAW); | 642 | perf_evsel__set_sample_bit(evsel, RAW); |
643 | perf_evsel__set_sample_bit(evsel, CPU); | 643 | perf_evsel__set_sample_bit(evsel, CPU); |
@@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
650 | attr->watermark = 0; | 650 | attr->watermark = 0; |
651 | attr->wakeup_events = 1; | 651 | attr->wakeup_events = 1; |
652 | } | 652 | } |
653 | if (opts->branch_stack) { | 653 | if (opts->branch_stack && !evsel->no_aux_samples) { |
654 | perf_evsel__set_sample_bit(evsel, BRANCH_STACK); | 654 | perf_evsel__set_sample_bit(evsel, BRANCH_STACK); |
655 | attr->branch_sample_type = opts->branch_stack; | 655 | attr->branch_sample_type = opts->branch_stack; |
656 | } | 656 | } |
@@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
681 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && | 681 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && |
682 | !opts->initial_delay) | 682 | !opts->initial_delay) |
683 | attr->enable_on_exec = 1; | 683 | attr->enable_on_exec = 1; |
684 | |||
685 | if (evsel->immediate) { | ||
686 | attr->disabled = 0; | ||
687 | attr->enable_on_exec = 0; | ||
688 | } | ||
684 | } | 689 | } |
685 | 690 | ||
686 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 691 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -960,6 +965,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
960 | ret += PRINT_ATTR2(exclude_user, exclude_kernel); | 965 | ret += PRINT_ATTR2(exclude_user, exclude_kernel); |
961 | ret += PRINT_ATTR2(exclude_hv, exclude_idle); | 966 | ret += PRINT_ATTR2(exclude_hv, exclude_idle); |
962 | ret += PRINT_ATTR2(mmap, comm); | 967 | ret += PRINT_ATTR2(mmap, comm); |
968 | ret += PRINT_ATTR2(mmap2, comm_exec); | ||
963 | ret += PRINT_ATTR2(freq, inherit_stat); | 969 | ret += PRINT_ATTR2(freq, inherit_stat); |
964 | ret += PRINT_ATTR2(enable_on_exec, task); | 970 | ret += PRINT_ATTR2(enable_on_exec, task); |
965 | ret += PRINT_ATTR2(watermark, precise_ip); | 971 | ret += PRINT_ATTR2(watermark, precise_ip); |
@@ -967,7 +973,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
967 | ret += PRINT_ATTR2(exclude_host, exclude_guest); | 973 | ret += PRINT_ATTR2(exclude_host, exclude_guest); |
968 | ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, | 974 | ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, |
969 | "excl.callchain_user", exclude_callchain_user); | 975 | "excl.callchain_user", exclude_callchain_user); |
970 | ret += PRINT_ATTR_U32(mmap2); | ||
971 | 976 | ||
972 | ret += PRINT_ATTR_U32(wakeup_events); | 977 | ret += PRINT_ATTR_U32(wakeup_events); |
973 | ret += PRINT_ATTR_U32(wakeup_watermark); | 978 | ret += PRINT_ATTR_U32(wakeup_watermark); |
@@ -1940,6 +1945,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
1940 | if_print(mmap); | 1945 | if_print(mmap); |
1941 | if_print(mmap2); | 1946 | if_print(mmap2); |
1942 | if_print(comm); | 1947 | if_print(comm); |
1948 | if_print(comm_exec); | ||
1943 | if_print(freq); | 1949 | if_print(freq); |
1944 | if_print(inherit_stat); | 1950 | if_print(inherit_stat); |
1945 | if_print(enable_on_exec); | 1951 | if_print(enable_on_exec); |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a52e9a5bb2d0..d7f93ce0ebc1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -83,6 +83,8 @@ struct perf_evsel { | |||
83 | int is_pos; | 83 | int is_pos; |
84 | bool supported; | 84 | bool supported; |
85 | bool needs_swap; | 85 | bool needs_swap; |
86 | bool no_aux_samples; | ||
87 | bool immediate; | ||
86 | /* parse modifier helper */ | 88 | /* parse modifier helper */ |
87 | int exclude_GH; | 89 | int exclude_GH; |
88 | int nr_members; | 90 | int nr_members; |
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 9844c31b7c2b..09e8e7aea7c6 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h | |||
@@ -94,27 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...) | |||
94 | return (i >= ssize) ? (ssize - 1) : i; | 94 | return (i >= ssize) ? (ssize - 1) : i; |
95 | } | 95 | } |
96 | 96 | ||
97 | int eprintf(int level, | ||
98 | const char *fmt, ...) __attribute__((format(printf, 2, 3))); | ||
99 | |||
100 | #ifndef pr_fmt | ||
101 | #define pr_fmt(fmt) fmt | ||
102 | #endif | ||
103 | |||
104 | #define pr_err(fmt, ...) \ | ||
105 | eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) | ||
106 | #define pr_warning(fmt, ...) \ | ||
107 | eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) | ||
108 | #define pr_info(fmt, ...) \ | ||
109 | eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) | ||
110 | #define pr_debug(fmt, ...) \ | ||
111 | eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) | ||
112 | #define pr_debugN(n, fmt, ...) \ | ||
113 | eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) | ||
114 | #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) | ||
115 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) | ||
116 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) | ||
117 | |||
118 | /* | 97 | /* |
119 | * This looks more complex than it should be. But we need to | 98 | * This looks more complex than it should be. But we need to |
120 | * get the type for the ~ right in round_down (it needs to be | 99 | * get the type for the ~ right in round_down (it needs to be |
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h new file mode 100644 index 000000000000..0b5a8cd2ee79 --- /dev/null +++ b/tools/perf/util/kvm-stat.h | |||
@@ -0,0 +1,140 @@ | |||
1 | #ifndef __PERF_KVM_STAT_H | ||
2 | #define __PERF_KVM_STAT_H | ||
3 | |||
4 | #include "../perf.h" | ||
5 | #include "evsel.h" | ||
6 | #include "evlist.h" | ||
7 | #include "session.h" | ||
8 | #include "tool.h" | ||
9 | #include "stat.h" | ||
10 | |||
11 | struct event_key { | ||
12 | #define INVALID_KEY (~0ULL) | ||
13 | u64 key; | ||
14 | int info; | ||
15 | struct exit_reasons_table *exit_reasons; | ||
16 | }; | ||
17 | |||
18 | struct kvm_event_stats { | ||
19 | u64 time; | ||
20 | struct stats stats; | ||
21 | }; | ||
22 | |||
23 | struct kvm_event { | ||
24 | struct list_head hash_entry; | ||
25 | struct rb_node rb; | ||
26 | |||
27 | struct event_key key; | ||
28 | |||
29 | struct kvm_event_stats total; | ||
30 | |||
31 | #define DEFAULT_VCPU_NUM 8 | ||
32 | int max_vcpu; | ||
33 | struct kvm_event_stats *vcpu; | ||
34 | }; | ||
35 | |||
36 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
37 | |||
38 | struct kvm_event_key { | ||
39 | const char *name; | ||
40 | key_cmp_fun key; | ||
41 | }; | ||
42 | |||
43 | struct perf_kvm_stat; | ||
44 | |||
45 | struct child_event_ops { | ||
46 | void (*get_key)(struct perf_evsel *evsel, | ||
47 | struct perf_sample *sample, | ||
48 | struct event_key *key); | ||
49 | const char *name; | ||
50 | }; | ||
51 | |||
52 | struct kvm_events_ops { | ||
53 | bool (*is_begin_event)(struct perf_evsel *evsel, | ||
54 | struct perf_sample *sample, | ||
55 | struct event_key *key); | ||
56 | bool (*is_end_event)(struct perf_evsel *evsel, | ||
57 | struct perf_sample *sample, struct event_key *key); | ||
58 | struct child_event_ops *child_ops; | ||
59 | void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, | ||
60 | char *decode); | ||
61 | const char *name; | ||
62 | }; | ||
63 | |||
64 | struct exit_reasons_table { | ||
65 | unsigned long exit_code; | ||
66 | const char *reason; | ||
67 | }; | ||
68 | |||
69 | #define EVENTS_BITS 12 | ||
70 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
71 | |||
72 | struct perf_kvm_stat { | ||
73 | struct perf_tool tool; | ||
74 | struct record_opts opts; | ||
75 | struct perf_evlist *evlist; | ||
76 | struct perf_session *session; | ||
77 | |||
78 | const char *file_name; | ||
79 | const char *report_event; | ||
80 | const char *sort_key; | ||
81 | int trace_vcpu; | ||
82 | |||
83 | struct exit_reasons_table *exit_reasons; | ||
84 | const char *exit_reasons_isa; | ||
85 | |||
86 | struct kvm_events_ops *events_ops; | ||
87 | key_cmp_fun compare; | ||
88 | struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
89 | |||
90 | u64 total_time; | ||
91 | u64 total_count; | ||
92 | u64 lost_events; | ||
93 | u64 duration; | ||
94 | |||
95 | const char *pid_str; | ||
96 | struct intlist *pid_list; | ||
97 | |||
98 | struct rb_root result; | ||
99 | |||
100 | int timerfd; | ||
101 | unsigned int display_time; | ||
102 | bool live; | ||
103 | }; | ||
104 | |||
105 | struct kvm_reg_events_ops { | ||
106 | const char *name; | ||
107 | struct kvm_events_ops *ops; | ||
108 | }; | ||
109 | |||
110 | void exit_event_get_key(struct perf_evsel *evsel, | ||
111 | struct perf_sample *sample, | ||
112 | struct event_key *key); | ||
113 | bool exit_event_begin(struct perf_evsel *evsel, | ||
114 | struct perf_sample *sample, | ||
115 | struct event_key *key); | ||
116 | bool exit_event_end(struct perf_evsel *evsel, | ||
117 | struct perf_sample *sample, | ||
118 | struct event_key *key); | ||
119 | void exit_event_decode_key(struct perf_kvm_stat *kvm, | ||
120 | struct event_key *key, | ||
121 | char *decode); | ||
122 | |||
123 | bool kvm_exit_event(struct perf_evsel *evsel); | ||
124 | bool kvm_entry_event(struct perf_evsel *evsel); | ||
125 | |||
126 | #define define_exit_reasons_table(name, symbols) \ | ||
127 | static struct exit_reasons_table name[] = { \ | ||
128 | symbols, { -1, NULL } \ | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * arch specific callbacks and data structures | ||
133 | */ | ||
134 | int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid); | ||
135 | |||
136 | extern const char * const kvm_events_tp[]; | ||
137 | extern struct kvm_reg_events_ops kvm_reg_events_ops[]; | ||
138 | extern const char * const kvm_skip_events[]; | ||
139 | |||
140 | #endif /* __PERF_KVM_STAT_H */ | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e9b943acaa5e..93c8b6fbc799 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
34 | return -ENOMEM; | 34 | return -ENOMEM; |
35 | 35 | ||
36 | if (pid != HOST_KERNEL_ID) { | 36 | if (pid != HOST_KERNEL_ID) { |
37 | struct thread *thread = machine__findnew_thread(machine, 0, | 37 | struct thread *thread = machine__findnew_thread(machine, -1, |
38 | pid); | 38 | pid); |
39 | char comm[64]; | 39 | char comm[64]; |
40 | 40 | ||
@@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) | |||
272 | return; | 272 | return; |
273 | } | 273 | } |
274 | 274 | ||
275 | static void machine__update_thread_pid(struct machine *machine, | ||
276 | struct thread *th, pid_t pid) | ||
277 | { | ||
278 | struct thread *leader; | ||
279 | |||
280 | if (pid == th->pid_ || pid == -1 || th->pid_ != -1) | ||
281 | return; | ||
282 | |||
283 | th->pid_ = pid; | ||
284 | |||
285 | if (th->pid_ == th->tid) | ||
286 | return; | ||
287 | |||
288 | leader = machine__findnew_thread(machine, th->pid_, th->pid_); | ||
289 | if (!leader) | ||
290 | goto out_err; | ||
291 | |||
292 | if (!leader->mg) | ||
293 | leader->mg = map_groups__new(); | ||
294 | |||
295 | if (!leader->mg) | ||
296 | goto out_err; | ||
297 | |||
298 | if (th->mg == leader->mg) | ||
299 | return; | ||
300 | |||
301 | if (th->mg) { | ||
302 | /* | ||
303 | * Maps are created from MMAP events which provide the pid and | ||
304 | * tid. Consequently there never should be any maps on a thread | ||
305 | * with an unknown pid. Just print an error if there are. | ||
306 | */ | ||
307 | if (!map_groups__empty(th->mg)) | ||
308 | pr_err("Discarding thread maps for %d:%d\n", | ||
309 | th->pid_, th->tid); | ||
310 | map_groups__delete(th->mg); | ||
311 | } | ||
312 | |||
313 | th->mg = map_groups__get(leader->mg); | ||
314 | |||
315 | return; | ||
316 | |||
317 | out_err: | ||
318 | pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); | ||
319 | } | ||
320 | |||
275 | static struct thread *__machine__findnew_thread(struct machine *machine, | 321 | static struct thread *__machine__findnew_thread(struct machine *machine, |
276 | pid_t pid, pid_t tid, | 322 | pid_t pid, pid_t tid, |
277 | bool create) | 323 | bool create) |
@@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
285 | * so most of the time we dont have to look up | 331 | * so most of the time we dont have to look up |
286 | * the full rbtree: | 332 | * the full rbtree: |
287 | */ | 333 | */ |
288 | if (machine->last_match && machine->last_match->tid == tid) { | 334 | th = machine->last_match; |
289 | if (pid && pid != machine->last_match->pid_) | 335 | if (th && th->tid == tid) { |
290 | machine->last_match->pid_ = pid; | 336 | machine__update_thread_pid(machine, th, pid); |
291 | return machine->last_match; | 337 | return th; |
292 | } | 338 | } |
293 | 339 | ||
294 | while (*p != NULL) { | 340 | while (*p != NULL) { |
@@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
297 | 343 | ||
298 | if (th->tid == tid) { | 344 | if (th->tid == tid) { |
299 | machine->last_match = th; | 345 | machine->last_match = th; |
300 | if (pid && pid != th->pid_) | 346 | machine__update_thread_pid(machine, th, pid); |
301 | th->pid_ = pid; | ||
302 | return th; | 347 | return th; |
303 | } | 348 | } |
304 | 349 | ||
@@ -325,8 +370,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
325 | * within thread__init_map_groups to find the thread | 370 | * within thread__init_map_groups to find the thread |
326 | * leader and that would screwed the rb tree. | 371 | * leader and that would screwed the rb tree. |
327 | */ | 372 | */ |
328 | if (thread__init_map_groups(th, machine)) | 373 | if (thread__init_map_groups(th, machine)) { |
374 | thread__delete(th); | ||
329 | return NULL; | 375 | return NULL; |
376 | } | ||
330 | } | 377 | } |
331 | 378 | ||
332 | return th; | 379 | return th; |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 25c571f4cba6..845f627e45f4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "vdso.h" | 12 | #include "vdso.h" |
13 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "debug.h" | ||
15 | #include <linux/string.h> | 16 | #include <linux/string.h> |
16 | 17 | ||
17 | const char *map_type__name[MAP__NR_TYPES] = { | 18 | const char *map_type__name[MAP__NR_TYPES] = { |
@@ -454,6 +455,20 @@ void map_groups__exit(struct map_groups *mg) | |||
454 | } | 455 | } |
455 | } | 456 | } |
456 | 457 | ||
458 | bool map_groups__empty(struct map_groups *mg) | ||
459 | { | ||
460 | int i; | ||
461 | |||
462 | for (i = 0; i < MAP__NR_TYPES; ++i) { | ||
463 | if (maps__first(&mg->maps[i])) | ||
464 | return false; | ||
465 | if (!list_empty(&mg->removed_maps[i])) | ||
466 | return false; | ||
467 | } | ||
468 | |||
469 | return true; | ||
470 | } | ||
471 | |||
457 | struct map_groups *map_groups__new(void) | 472 | struct map_groups *map_groups__new(void) |
458 | { | 473 | { |
459 | struct map_groups *mg = malloc(sizeof(*mg)); | 474 | struct map_groups *mg = malloc(sizeof(*mg)); |
@@ -554,8 +569,8 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) | |||
554 | return ams->sym ? 0 : -1; | 569 | return ams->sym ? 0 : -1; |
555 | } | 570 | } |
556 | 571 | ||
557 | size_t __map_groups__fprintf_maps(struct map_groups *mg, | 572 | size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, |
558 | enum map_type type, int verbose, FILE *fp) | 573 | FILE *fp) |
559 | { | 574 | { |
560 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | 575 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); |
561 | struct rb_node *nd; | 576 | struct rb_node *nd; |
@@ -573,17 +588,16 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg, | |||
573 | return printed; | 588 | return printed; |
574 | } | 589 | } |
575 | 590 | ||
576 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) | 591 | static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) |
577 | { | 592 | { |
578 | size_t printed = 0, i; | 593 | size_t printed = 0, i; |
579 | for (i = 0; i < MAP__NR_TYPES; ++i) | 594 | for (i = 0; i < MAP__NR_TYPES; ++i) |
580 | printed += __map_groups__fprintf_maps(mg, i, verbose, fp); | 595 | printed += __map_groups__fprintf_maps(mg, i, fp); |
581 | return printed; | 596 | return printed; |
582 | } | 597 | } |
583 | 598 | ||
584 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, | 599 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, |
585 | enum map_type type, | 600 | enum map_type type, FILE *fp) |
586 | int verbose, FILE *fp) | ||
587 | { | 601 | { |
588 | struct map *pos; | 602 | struct map *pos; |
589 | size_t printed = 0; | 603 | size_t printed = 0; |
@@ -600,23 +614,23 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, | |||
600 | } | 614 | } |
601 | 615 | ||
602 | static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, | 616 | static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, |
603 | int verbose, FILE *fp) | 617 | FILE *fp) |
604 | { | 618 | { |
605 | size_t printed = 0, i; | 619 | size_t printed = 0, i; |
606 | for (i = 0; i < MAP__NR_TYPES; ++i) | 620 | for (i = 0; i < MAP__NR_TYPES; ++i) |
607 | printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); | 621 | printed += __map_groups__fprintf_removed_maps(mg, i, fp); |
608 | return printed; | 622 | return printed; |
609 | } | 623 | } |
610 | 624 | ||
611 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) | 625 | size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) |
612 | { | 626 | { |
613 | size_t printed = map_groups__fprintf_maps(mg, verbose, fp); | 627 | size_t printed = map_groups__fprintf_maps(mg, fp); |
614 | printed += fprintf(fp, "Removed maps:\n"); | 628 | printed += fprintf(fp, "Removed maps:\n"); |
615 | return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); | 629 | return printed + map_groups__fprintf_removed_maps(mg, fp); |
616 | } | 630 | } |
617 | 631 | ||
618 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, | 632 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
619 | int verbose, FILE *fp) | 633 | FILE *fp) |
620 | { | 634 | { |
621 | struct rb_root *root = &mg->maps[map->type]; | 635 | struct rb_root *root = &mg->maps[map->type]; |
622 | struct rb_node *next = rb_first(root); | 636 | struct rb_node *next = rb_first(root); |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 7758c72522ef..22d13a219590 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -66,6 +66,7 @@ struct map_groups { | |||
66 | 66 | ||
67 | struct map_groups *map_groups__new(void); | 67 | struct map_groups *map_groups__new(void); |
68 | void map_groups__delete(struct map_groups *mg); | 68 | void map_groups__delete(struct map_groups *mg); |
69 | bool map_groups__empty(struct map_groups *mg); | ||
69 | 70 | ||
70 | static inline struct map_groups *map_groups__get(struct map_groups *mg) | 71 | static inline struct map_groups *map_groups__get(struct map_groups *mg) |
71 | { | 72 | { |
@@ -141,8 +142,8 @@ void map__fixup_end(struct map *map); | |||
141 | 142 | ||
142 | void map__reloc_vmlinux(struct map *map); | 143 | void map__reloc_vmlinux(struct map *map); |
143 | 144 | ||
144 | size_t __map_groups__fprintf_maps(struct map_groups *mg, | 145 | size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, |
145 | enum map_type type, int verbose, FILE *fp); | 146 | FILE *fp); |
146 | void maps__insert(struct rb_root *maps, struct map *map); | 147 | void maps__insert(struct rb_root *maps, struct map *map); |
147 | void maps__remove(struct rb_root *maps, struct map *map); | 148 | void maps__remove(struct rb_root *maps, struct map *map); |
148 | struct map *maps__find(struct rb_root *maps, u64 addr); | 149 | struct map *maps__find(struct rb_root *maps, u64 addr); |
@@ -152,8 +153,7 @@ void map_groups__init(struct map_groups *mg); | |||
152 | void map_groups__exit(struct map_groups *mg); | 153 | void map_groups__exit(struct map_groups *mg); |
153 | int map_groups__clone(struct map_groups *mg, | 154 | int map_groups__clone(struct map_groups *mg, |
154 | struct map_groups *parent, enum map_type type); | 155 | struct map_groups *parent, enum map_type type); |
155 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); | 156 | size_t map_groups__fprintf(struct map_groups *mg, FILE *fp); |
156 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); | ||
157 | 157 | ||
158 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, | 158 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, |
159 | u64 addr); | 159 | u64 addr); |
@@ -210,7 +210,7 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg, | |||
210 | } | 210 | } |
211 | 211 | ||
212 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, | 212 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
213 | int verbose, FILE *fp); | 213 | FILE *fp); |
214 | 214 | ||
215 | struct map *map_groups__find_by_name(struct map_groups *mg, | 215 | struct map *map_groups__find_by_name(struct map_groups *mg, |
216 | enum map_type type, const char *name); | 216 | enum map_type type, const char *name); |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index d8dac8ac5f37..b59ba858e73d 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -98,6 +98,7 @@ struct option { | |||
98 | parse_opt_cb *callback; | 98 | parse_opt_cb *callback; |
99 | intptr_t defval; | 99 | intptr_t defval; |
100 | bool *set; | 100 | bool *set; |
101 | void *data; | ||
101 | }; | 102 | }; |
102 | 103 | ||
103 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) | 104 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) |
@@ -131,6 +132,10 @@ struct option { | |||
131 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ | 132 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ |
132 | .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ | 133 | .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ |
133 | .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} | 134 | .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} |
135 | #define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \ | ||
136 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ | ||
137 | .value = (v), (a), .help = (h), .callback = (f), \ | ||
138 | .flags = PARSE_OPT_OPTARG, .data = (d) } | ||
134 | 139 | ||
135 | /* parse_options() will filter out the processed options and leave the | 140 | /* parse_options() will filter out the processed options and leave the |
136 | * non-option argments in argv[]. | 141 | * non-option argments in argv[]. |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 98e304766416..dca9145d704c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include <getopt.h> | ||
30 | #include <stdlib.h> | 29 | #include <stdlib.h> |
31 | #include <string.h> | 30 | #include <string.h> |
32 | #include <stdarg.h> | 31 | #include <stdarg.h> |
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c index daa17aeb6c63..a126e6cc6e73 100644 --- a/tools/perf/util/pstack.c +++ b/tools/perf/util/pstack.c | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | #include "util.h" | 7 | #include "util.h" |
8 | #include "pstack.h" | 8 | #include "pstack.h" |
9 | #include "debug.h" | ||
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
10 | #include <stdlib.h> | 11 | #include <stdlib.h> |
11 | 12 | ||
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 122669c18ff4..12aa9b0d0ba1 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -14,12 +14,12 @@ | |||
14 | */ | 14 | */ |
15 | int verbose; | 15 | int verbose; |
16 | 16 | ||
17 | int eprintf(int level, const char *fmt, ...) | 17 | int eprintf(int level, int var, const char *fmt, ...) |
18 | { | 18 | { |
19 | va_list args; | 19 | va_list args; |
20 | int ret = 0; | 20 | int ret = 0; |
21 | 21 | ||
22 | if (verbose >= level) { | 22 | if (var >= level) { |
23 | va_start(args, fmt); | 23 | va_start(args, fmt); |
24 | ret = vfprintf(stderr, fmt, args); | 24 | ret = vfprintf(stderr, fmt, args); |
25 | va_end(args); | 25 | va_end(args); |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 049e0a09ccd3..165723152cfb 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel) | |||
69 | evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; | 69 | evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; |
70 | } | 70 | } |
71 | 71 | ||
72 | static void perf_probe_comm_exec(struct perf_evsel *evsel) | ||
73 | { | ||
74 | evsel->attr.comm_exec = 1; | ||
75 | } | ||
76 | |||
72 | bool perf_can_sample_identifier(void) | 77 | bool perf_can_sample_identifier(void) |
73 | { | 78 | { |
74 | return perf_probe_api(perf_probe_sample_identifier); | 79 | return perf_probe_api(perf_probe_sample_identifier); |
75 | } | 80 | } |
76 | 81 | ||
82 | static bool perf_can_comm_exec(void) | ||
83 | { | ||
84 | return perf_probe_api(perf_probe_comm_exec); | ||
85 | } | ||
86 | |||
77 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | 87 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) |
78 | { | 88 | { |
79 | struct perf_evsel *evsel; | 89 | struct perf_evsel *evsel; |
80 | bool use_sample_identifier = false; | 90 | bool use_sample_identifier = false; |
91 | bool use_comm_exec; | ||
81 | 92 | ||
82 | /* | 93 | /* |
83 | * Set the evsel leader links before we configure attributes, | 94 | * Set the evsel leader links before we configure attributes, |
@@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | |||
89 | if (evlist->cpus->map[0] < 0) | 100 | if (evlist->cpus->map[0] < 0) |
90 | opts->no_inherit = true; | 101 | opts->no_inherit = true; |
91 | 102 | ||
92 | evlist__for_each(evlist, evsel) | 103 | use_comm_exec = perf_can_comm_exec(); |
104 | |||
105 | evlist__for_each(evlist, evsel) { | ||
93 | perf_evsel__config(evsel, opts); | 106 | perf_evsel__config(evsel, opts); |
107 | if (!evsel->idx && use_comm_exec) | ||
108 | evsel->attr.comm_exec = 1; | ||
109 | } | ||
94 | 110 | ||
95 | if (evlist->nr_entries > 1) { | 111 | if (evlist->nr_entries > 1) { |
96 | struct perf_evsel *first = perf_evlist__first(evlist); | 112 | struct perf_evsel *first = perf_evlist__first(evlist); |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index af7da565a750..b2dba9c0a3a1 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "../event.h" | 34 | #include "../event.h" |
35 | #include "../trace-event.h" | 35 | #include "../trace-event.h" |
36 | #include "../evsel.h" | 36 | #include "../evsel.h" |
37 | #include "../debug.h" | ||
37 | 38 | ||
38 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | 39 | void boot_Perf__Trace__Context(pTHX_ CV *cv); |
39 | void boot_DynaLoader(pTHX_ CV *cv); | 40 | void boot_DynaLoader(pTHX_ CV *cv); |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index e55b65a65558..cbce2545da45 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -27,11 +27,13 @@ | |||
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | 28 | ||
29 | #include "../../perf.h" | 29 | #include "../../perf.h" |
30 | #include "../debug.h" | ||
30 | #include "../evsel.h" | 31 | #include "../evsel.h" |
31 | #include "../util.h" | 32 | #include "../util.h" |
32 | #include "../event.h" | 33 | #include "../event.h" |
33 | #include "../thread.h" | 34 | #include "../thread.h" |
34 | #include "../trace-event.h" | 35 | #include "../trace-event.h" |
36 | #include "../machine.h" | ||
35 | 37 | ||
36 | PyMODINIT_FUNC initperf_trace_context(void); | 38 | PyMODINIT_FUNC initperf_trace_context(void); |
37 | 39 | ||
@@ -50,10 +52,14 @@ static int zero_flag_atom; | |||
50 | 52 | ||
51 | static PyObject *main_module, *main_dict; | 53 | static PyObject *main_module, *main_dict; |
52 | 54 | ||
55 | static void handler_call_die(const char *handler_name) NORETURN; | ||
53 | static void handler_call_die(const char *handler_name) | 56 | static void handler_call_die(const char *handler_name) |
54 | { | 57 | { |
55 | PyErr_Print(); | 58 | PyErr_Print(); |
56 | Py_FatalError("problem in Python trace event handler"); | 59 | Py_FatalError("problem in Python trace event handler"); |
60 | // Py_FatalError does not return | ||
61 | // but we have to make the compiler happy | ||
62 | abort(); | ||
57 | } | 63 | } |
58 | 64 | ||
59 | /* | 65 | /* |
@@ -97,6 +103,7 @@ static void define_value(enum print_arg_type field_type, | |||
97 | retval = PyObject_CallObject(handler, t); | 103 | retval = PyObject_CallObject(handler, t); |
98 | if (retval == NULL) | 104 | if (retval == NULL) |
99 | handler_call_die(handler_name); | 105 | handler_call_die(handler_name); |
106 | Py_DECREF(retval); | ||
100 | } | 107 | } |
101 | 108 | ||
102 | Py_DECREF(t); | 109 | Py_DECREF(t); |
@@ -143,6 +150,7 @@ static void define_field(enum print_arg_type field_type, | |||
143 | retval = PyObject_CallObject(handler, t); | 150 | retval = PyObject_CallObject(handler, t); |
144 | if (retval == NULL) | 151 | if (retval == NULL) |
145 | handler_call_die(handler_name); | 152 | handler_call_die(handler_name); |
153 | Py_DECREF(retval); | ||
146 | } | 154 | } |
147 | 155 | ||
148 | Py_DECREF(t); | 156 | Py_DECREF(t); |
@@ -272,12 +280,90 @@ static PyObject *get_field_numeric_entry(struct event_format *event, | |||
272 | return obj; | 280 | return obj; |
273 | } | 281 | } |
274 | 282 | ||
283 | |||
284 | static PyObject *python_process_callchain(struct perf_sample *sample, | ||
285 | struct perf_evsel *evsel, | ||
286 | struct addr_location *al) | ||
287 | { | ||
288 | PyObject *pylist; | ||
289 | |||
290 | pylist = PyList_New(0); | ||
291 | if (!pylist) | ||
292 | Py_FatalError("couldn't create Python list"); | ||
293 | |||
294 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
295 | goto exit; | ||
296 | |||
297 | if (machine__resolve_callchain(al->machine, evsel, al->thread, | ||
298 | sample, NULL, NULL, | ||
299 | PERF_MAX_STACK_DEPTH) != 0) { | ||
300 | pr_err("Failed to resolve callchain. Skipping\n"); | ||
301 | goto exit; | ||
302 | } | ||
303 | callchain_cursor_commit(&callchain_cursor); | ||
304 | |||
305 | |||
306 | while (1) { | ||
307 | PyObject *pyelem; | ||
308 | struct callchain_cursor_node *node; | ||
309 | node = callchain_cursor_current(&callchain_cursor); | ||
310 | if (!node) | ||
311 | break; | ||
312 | |||
313 | pyelem = PyDict_New(); | ||
314 | if (!pyelem) | ||
315 | Py_FatalError("couldn't create Python dictionary"); | ||
316 | |||
317 | |||
318 | pydict_set_item_string_decref(pyelem, "ip", | ||
319 | PyLong_FromUnsignedLongLong(node->ip)); | ||
320 | |||
321 | if (node->sym) { | ||
322 | PyObject *pysym = PyDict_New(); | ||
323 | if (!pysym) | ||
324 | Py_FatalError("couldn't create Python dictionary"); | ||
325 | pydict_set_item_string_decref(pysym, "start", | ||
326 | PyLong_FromUnsignedLongLong(node->sym->start)); | ||
327 | pydict_set_item_string_decref(pysym, "end", | ||
328 | PyLong_FromUnsignedLongLong(node->sym->end)); | ||
329 | pydict_set_item_string_decref(pysym, "binding", | ||
330 | PyInt_FromLong(node->sym->binding)); | ||
331 | pydict_set_item_string_decref(pysym, "name", | ||
332 | PyString_FromStringAndSize(node->sym->name, | ||
333 | node->sym->namelen)); | ||
334 | pydict_set_item_string_decref(pyelem, "sym", pysym); | ||
335 | } | ||
336 | |||
337 | if (node->map) { | ||
338 | struct map *map = node->map; | ||
339 | const char *dsoname = "[unknown]"; | ||
340 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | ||
341 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
342 | dsoname = map->dso->long_name; | ||
343 | else if (map->dso->name) | ||
344 | dsoname = map->dso->name; | ||
345 | } | ||
346 | pydict_set_item_string_decref(pyelem, "dso", | ||
347 | PyString_FromString(dsoname)); | ||
348 | } | ||
349 | |||
350 | callchain_cursor_advance(&callchain_cursor); | ||
351 | PyList_Append(pylist, pyelem); | ||
352 | Py_DECREF(pyelem); | ||
353 | } | ||
354 | |||
355 | exit: | ||
356 | return pylist; | ||
357 | } | ||
358 | |||
359 | |||
275 | static void python_process_tracepoint(struct perf_sample *sample, | 360 | static void python_process_tracepoint(struct perf_sample *sample, |
276 | struct perf_evsel *evsel, | 361 | struct perf_evsel *evsel, |
277 | struct thread *thread, | 362 | struct thread *thread, |
278 | struct addr_location *al) | 363 | struct addr_location *al) |
279 | { | 364 | { |
280 | PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; | 365 | PyObject *handler, *retval, *context, *t, *obj, *callchain; |
366 | PyObject *dict = NULL; | ||
281 | static char handler_name[256]; | 367 | static char handler_name[256]; |
282 | struct format_field *field; | 368 | struct format_field *field; |
283 | unsigned long s, ns; | 369 | unsigned long s, ns; |
@@ -320,18 +406,23 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
320 | PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); | 406 | PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); |
321 | PyTuple_SetItem(t, n++, context); | 407 | PyTuple_SetItem(t, n++, context); |
322 | 408 | ||
409 | /* ip unwinding */ | ||
410 | callchain = python_process_callchain(sample, evsel, al); | ||
411 | |||
323 | if (handler) { | 412 | if (handler) { |
324 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | 413 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); |
325 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); | 414 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); |
326 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); | 415 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); |
327 | PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); | 416 | PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); |
328 | PyTuple_SetItem(t, n++, PyString_FromString(comm)); | 417 | PyTuple_SetItem(t, n++, PyString_FromString(comm)); |
418 | PyTuple_SetItem(t, n++, callchain); | ||
329 | } else { | 419 | } else { |
330 | pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); | 420 | pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); |
331 | pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); | 421 | pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); |
332 | pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); | 422 | pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); |
333 | pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); | 423 | pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); |
334 | pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); | 424 | pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); |
425 | pydict_set_item_string_decref(dict, "common_callchain", callchain); | ||
335 | } | 426 | } |
336 | for (field = event->format.fields; field; field = field->next) { | 427 | for (field = event->format.fields; field; field = field->next) { |
337 | if (field->flags & FIELD_IS_STRING) { | 428 | if (field->flags & FIELD_IS_STRING) { |
@@ -351,6 +442,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
351 | pydict_set_item_string_decref(dict, field->name, obj); | 442 | pydict_set_item_string_decref(dict, field->name, obj); |
352 | 443 | ||
353 | } | 444 | } |
445 | |||
354 | if (!handler) | 446 | if (!handler) |
355 | PyTuple_SetItem(t, n++, dict); | 447 | PyTuple_SetItem(t, n++, dict); |
356 | 448 | ||
@@ -361,6 +453,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
361 | retval = PyObject_CallObject(handler, t); | 453 | retval = PyObject_CallObject(handler, t); |
362 | if (retval == NULL) | 454 | if (retval == NULL) |
363 | handler_call_die(handler_name); | 455 | handler_call_die(handler_name); |
456 | Py_DECREF(retval); | ||
364 | } else { | 457 | } else { |
365 | handler = PyDict_GetItemString(main_dict, "trace_unhandled"); | 458 | handler = PyDict_GetItemString(main_dict, "trace_unhandled"); |
366 | if (handler && PyCallable_Check(handler)) { | 459 | if (handler && PyCallable_Check(handler)) { |
@@ -368,6 +461,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
368 | retval = PyObject_CallObject(handler, t); | 461 | retval = PyObject_CallObject(handler, t); |
369 | if (retval == NULL) | 462 | if (retval == NULL) |
370 | handler_call_die("trace_unhandled"); | 463 | handler_call_die("trace_unhandled"); |
464 | Py_DECREF(retval); | ||
371 | } | 465 | } |
372 | Py_DECREF(dict); | 466 | Py_DECREF(dict); |
373 | } | 467 | } |
@@ -380,7 +474,7 @@ static void python_process_general_event(struct perf_sample *sample, | |||
380 | struct thread *thread, | 474 | struct thread *thread, |
381 | struct addr_location *al) | 475 | struct addr_location *al) |
382 | { | 476 | { |
383 | PyObject *handler, *retval, *t, *dict; | 477 | PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; |
384 | static char handler_name[64]; | 478 | static char handler_name[64]; |
385 | unsigned n = 0; | 479 | unsigned n = 0; |
386 | 480 | ||
@@ -396,6 +490,10 @@ static void python_process_general_event(struct perf_sample *sample, | |||
396 | if (!dict) | 490 | if (!dict) |
397 | Py_FatalError("couldn't create Python dictionary"); | 491 | Py_FatalError("couldn't create Python dictionary"); |
398 | 492 | ||
493 | dict_sample = PyDict_New(); | ||
494 | if (!dict_sample) | ||
495 | Py_FatalError("couldn't create Python dictionary"); | ||
496 | |||
399 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | 497 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); |
400 | 498 | ||
401 | handler = PyDict_GetItemString(main_dict, handler_name); | 499 | handler = PyDict_GetItemString(main_dict, handler_name); |
@@ -405,8 +503,21 @@ static void python_process_general_event(struct perf_sample *sample, | |||
405 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | 503 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); |
406 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( | 504 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( |
407 | (const char *)&evsel->attr, sizeof(evsel->attr))); | 505 | (const char *)&evsel->attr, sizeof(evsel->attr))); |
408 | pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( | 506 | |
409 | (const char *)sample, sizeof(*sample))); | 507 | pydict_set_item_string_decref(dict_sample, "pid", |
508 | PyInt_FromLong(sample->pid)); | ||
509 | pydict_set_item_string_decref(dict_sample, "tid", | ||
510 | PyInt_FromLong(sample->tid)); | ||
511 | pydict_set_item_string_decref(dict_sample, "cpu", | ||
512 | PyInt_FromLong(sample->cpu)); | ||
513 | pydict_set_item_string_decref(dict_sample, "ip", | ||
514 | PyLong_FromUnsignedLongLong(sample->ip)); | ||
515 | pydict_set_item_string_decref(dict_sample, "time", | ||
516 | PyLong_FromUnsignedLongLong(sample->time)); | ||
517 | pydict_set_item_string_decref(dict_sample, "period", | ||
518 | PyLong_FromUnsignedLongLong(sample->period)); | ||
519 | pydict_set_item_string_decref(dict, "sample", dict_sample); | ||
520 | |||
410 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | 521 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( |
411 | (const char *)sample->raw_data, sample->raw_size)); | 522 | (const char *)sample->raw_data, sample->raw_size)); |
412 | pydict_set_item_string_decref(dict, "comm", | 523 | pydict_set_item_string_decref(dict, "comm", |
@@ -420,6 +531,10 @@ static void python_process_general_event(struct perf_sample *sample, | |||
420 | PyString_FromString(al->sym->name)); | 531 | PyString_FromString(al->sym->name)); |
421 | } | 532 | } |
422 | 533 | ||
534 | /* ip unwinding */ | ||
535 | callchain = python_process_callchain(sample, evsel, al); | ||
536 | pydict_set_item_string_decref(dict, "callchain", callchain); | ||
537 | |||
423 | PyTuple_SetItem(t, n++, dict); | 538 | PyTuple_SetItem(t, n++, dict); |
424 | if (_PyTuple_Resize(&t, n) == -1) | 539 | if (_PyTuple_Resize(&t, n) == -1) |
425 | Py_FatalError("error resizing Python tuple"); | 540 | Py_FatalError("error resizing Python tuple"); |
@@ -427,6 +542,7 @@ static void python_process_general_event(struct perf_sample *sample, | |||
427 | retval = PyObject_CallObject(handler, t); | 542 | retval = PyObject_CallObject(handler, t); |
428 | if (retval == NULL) | 543 | if (retval == NULL) |
429 | handler_call_die(handler_name); | 544 | handler_call_die(handler_name); |
545 | Py_DECREF(retval); | ||
430 | exit: | 546 | exit: |
431 | Py_DECREF(dict); | 547 | Py_DECREF(dict); |
432 | Py_DECREF(t); | 548 | Py_DECREF(t); |
@@ -548,8 +664,7 @@ static int python_stop_script(void) | |||
548 | retval = PyObject_CallObject(handler, NULL); | 664 | retval = PyObject_CallObject(handler, NULL); |
549 | if (retval == NULL) | 665 | if (retval == NULL) |
550 | handler_call_die("trace_end"); | 666 | handler_call_die("trace_end"); |
551 | else | 667 | Py_DECREF(retval); |
552 | Py_DECREF(retval); | ||
553 | out: | 668 | out: |
554 | Py_XDECREF(main_dict); | 669 | Py_XDECREF(main_dict); |
555 | Py_XDECREF(main_module); | 670 | Py_XDECREF(main_module); |
@@ -616,6 +731,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
616 | fprintf(ofp, "common_nsecs, "); | 731 | fprintf(ofp, "common_nsecs, "); |
617 | fprintf(ofp, "common_pid, "); | 732 | fprintf(ofp, "common_pid, "); |
618 | fprintf(ofp, "common_comm,\n\t"); | 733 | fprintf(ofp, "common_comm,\n\t"); |
734 | fprintf(ofp, "common_callchain, "); | ||
619 | 735 | ||
620 | not_first = 0; | 736 | not_first = 0; |
621 | count = 0; | 737 | count = 0; |
@@ -659,7 +775,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
659 | fprintf(ofp, "%%u"); | 775 | fprintf(ofp, "%%u"); |
660 | } | 776 | } |
661 | 777 | ||
662 | fprintf(ofp, "\\n\" %% \\\n\t\t("); | 778 | fprintf(ofp, "\" %% \\\n\t\t("); |
663 | 779 | ||
664 | not_first = 0; | 780 | not_first = 0; |
665 | count = 0; | 781 | count = 0; |
@@ -695,7 +811,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
695 | fprintf(ofp, "%s", f->name); | 811 | fprintf(ofp, "%s", f->name); |
696 | } | 812 | } |
697 | 813 | ||
698 | fprintf(ofp, "),\n\n"); | 814 | fprintf(ofp, ")\n\n"); |
815 | |||
816 | fprintf(ofp, "\t\tfor node in common_callchain:"); | ||
817 | fprintf(ofp, "\n\t\t\tif 'sym' in node:"); | ||
818 | fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); | ||
819 | fprintf(ofp, "\n\t\t\telse:"); | ||
820 | fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n"); | ||
821 | fprintf(ofp, "\t\tprint \"\\n\"\n\n"); | ||
822 | |||
699 | } | 823 | } |
700 | 824 | ||
701 | fprintf(ofp, "def trace_unhandled(event_name, context, " | 825 | fprintf(ofp, "def trace_unhandled(event_name, context, " |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 64a186edc7be..eac14ce0ae8d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr) | |||
1083 | 1083 | ||
1084 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | 1084 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) |
1085 | { | 1085 | { |
1086 | return machine__findnew_thread(&session->machines.host, 0, pid); | 1086 | return machine__findnew_thread(&session->machines.host, -1, pid); |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | static struct thread *perf_session__register_idle_thread(struct perf_session *session) | 1089 | static struct thread *perf_session__register_idle_thread(struct perf_session *session) |
1090 | { | 1090 | { |
1091 | struct thread *thread = perf_session__findnew(session, 0); | 1091 | struct thread *thread; |
1092 | 1092 | ||
1093 | thread = machine__findnew_thread(&session->machines.host, 0, 0); | ||
1093 | if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { | 1094 | if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { |
1094 | pr_err("problem inserting idle task.\n"); | 1095 | pr_err("problem inserting idle task.\n"); |
1095 | thread = NULL; | 1096 | thread = NULL; |
@@ -1296,8 +1297,10 @@ int __perf_session__process_events(struct perf_session *session, | |||
1296 | ui_progress__init(&prog, file_size, "Processing events..."); | 1297 | ui_progress__init(&prog, file_size, "Processing events..."); |
1297 | 1298 | ||
1298 | mmap_size = MMAP_SIZE; | 1299 | mmap_size = MMAP_SIZE; |
1299 | if (mmap_size > file_size) | 1300 | if (mmap_size > file_size) { |
1300 | mmap_size = file_size; | 1301 | mmap_size = file_size; |
1302 | session->one_mmap = true; | ||
1303 | } | ||
1301 | 1304 | ||
1302 | memset(mmaps, 0, sizeof(mmaps)); | 1305 | memset(mmaps, 0, sizeof(mmaps)); |
1303 | 1306 | ||
@@ -1319,6 +1322,10 @@ remap: | |||
1319 | mmaps[map_idx] = buf; | 1322 | mmaps[map_idx] = buf; |
1320 | map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); | 1323 | map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); |
1321 | file_pos = file_offset + head; | 1324 | file_pos = file_offset + head; |
1325 | if (session->one_mmap) { | ||
1326 | session->one_mmap_addr = buf; | ||
1327 | session->one_mmap_offset = file_offset; | ||
1328 | } | ||
1322 | 1329 | ||
1323 | more: | 1330 | more: |
1324 | event = fetch_mmaped_event(session, head, mmap_size, buf); | 1331 | event = fetch_mmaped_event(session, head, mmap_size, buf); |
@@ -1364,6 +1371,7 @@ out_err: | |||
1364 | ui_progress__finish(); | 1371 | ui_progress__finish(); |
1365 | perf_session__warn_about_errors(session, tool); | 1372 | perf_session__warn_about_errors(session, tool); |
1366 | perf_session_free_sample_buffers(session); | 1373 | perf_session_free_sample_buffers(session); |
1374 | session->one_mmap = false; | ||
1367 | return err; | 1375 | return err; |
1368 | } | 1376 | } |
1369 | 1377 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 3140f8ae6148..0321013bd9fd 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -36,6 +36,9 @@ struct perf_session { | |||
36 | struct trace_event tevent; | 36 | struct trace_event tevent; |
37 | struct events_stats stats; | 37 | struct events_stats stats; |
38 | bool repipe; | 38 | bool repipe; |
39 | bool one_mmap; | ||
40 | void *one_mmap_addr; | ||
41 | u64 one_mmap_offset; | ||
39 | struct ordered_samples ordered_samples; | 42 | struct ordered_samples ordered_samples; |
40 | struct perf_data_file *file; | 43 | struct perf_data_file *file; |
41 | }; | 44 | }; |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6864661a79dd..cef8f426356e 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym) | |||
49 | 49 | ||
50 | static inline int elf_sym__is_function(const GElf_Sym *sym) | 50 | static inline int elf_sym__is_function(const GElf_Sym *sym) |
51 | { | 51 | { |
52 | return elf_sym__type(sym) == STT_FUNC && | 52 | return (elf_sym__type(sym) == STT_FUNC || |
53 | elf_sym__type(sym) == STT_GNU_IFUNC) && | ||
53 | sym->st_name != 0 && | 54 | sym->st_name != 0 && |
54 | sym->st_shndx != SHN_UNDEF; | 55 | sym->st_shndx != SHN_UNDEF; |
55 | } | 56 | } |
@@ -598,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, | |||
598 | goto out_elf_end; | 599 | goto out_elf_end; |
599 | } | 600 | } |
600 | 601 | ||
602 | ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64); | ||
603 | |||
601 | ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", | 604 | ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", |
602 | NULL); | 605 | NULL); |
603 | if (ss->symshdr.sh_type != SHT_SYMTAB) | 606 | if (ss->symshdr.sh_type != SHT_SYMTAB) |
@@ -698,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
698 | bool remap_kernel = false, adjust_kernel_syms = false; | 701 | bool remap_kernel = false, adjust_kernel_syms = false; |
699 | 702 | ||
700 | dso->symtab_type = syms_ss->type; | 703 | dso->symtab_type = syms_ss->type; |
704 | dso->is_64_bit = syms_ss->is_64_bit; | ||
701 | dso->rel = syms_ss->ehdr.e_type == ET_REL; | 705 | dso->rel = syms_ss->ehdr.e_type == ET_REL; |
702 | 706 | ||
703 | /* | 707 | /* |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index bd15f490d04f..101f55d407d0 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused, | |||
288 | return 0; | 288 | return 0; |
289 | } | 289 | } |
290 | 290 | ||
291 | static int fd__is_64_bit(int fd) | ||
292 | { | ||
293 | u8 e_ident[EI_NIDENT]; | ||
294 | |||
295 | if (lseek(fd, 0, SEEK_SET)) | ||
296 | return -1; | ||
297 | |||
298 | if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) | ||
299 | return -1; | ||
300 | |||
301 | if (memcmp(e_ident, ELFMAG, SELFMAG) || | ||
302 | e_ident[EI_VERSION] != EV_CURRENT) | ||
303 | return -1; | ||
304 | |||
305 | return e_ident[EI_CLASS] == ELFCLASS64; | ||
306 | } | ||
307 | |||
291 | int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, | 308 | int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, |
292 | struct symsrc *ss, | 309 | struct symsrc *ss, |
293 | struct symsrc *runtime_ss __maybe_unused, | 310 | struct symsrc *runtime_ss __maybe_unused, |
@@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, | |||
295 | int kmodule __maybe_unused) | 312 | int kmodule __maybe_unused) |
296 | { | 313 | { |
297 | unsigned char *build_id[BUILD_ID_SIZE]; | 314 | unsigned char *build_id[BUILD_ID_SIZE]; |
315 | int ret; | ||
316 | |||
317 | ret = fd__is_64_bit(ss->fd); | ||
318 | if (ret >= 0) | ||
319 | dso->is_64_bit = ret; | ||
298 | 320 | ||
299 | if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { | 321 | if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { |
300 | dso__set_build_id(dso, build_id); | 322 | dso__set_build_id(dso, build_id); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 2e6a2e219eb9..eb06746b06b2 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -342,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols) | |||
342 | return NULL; | 342 | return NULL; |
343 | } | 343 | } |
344 | 344 | ||
345 | static struct symbol *symbols__next(struct symbol *sym) | ||
346 | { | ||
347 | struct rb_node *n = rb_next(&sym->rb_node); | ||
348 | |||
349 | if (n) | ||
350 | return rb_entry(n, struct symbol, rb_node); | ||
351 | |||
352 | return NULL; | ||
353 | } | ||
354 | |||
345 | struct symbol_name_rb_node { | 355 | struct symbol_name_rb_node { |
346 | struct rb_node rb_node; | 356 | struct rb_node rb_node; |
347 | struct symbol sym; | 357 | struct symbol sym; |
@@ -412,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso, | |||
412 | return symbols__find(&dso->symbols[type], addr); | 422 | return symbols__find(&dso->symbols[type], addr); |
413 | } | 423 | } |
414 | 424 | ||
415 | static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) | 425 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) |
416 | { | 426 | { |
417 | return symbols__first(&dso->symbols[type]); | 427 | return symbols__first(&dso->symbols[type]); |
418 | } | 428 | } |
419 | 429 | ||
430 | struct symbol *dso__next_symbol(struct symbol *sym) | ||
431 | { | ||
432 | return symbols__next(sym); | ||
433 | } | ||
434 | |||
420 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 435 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
421 | const char *name) | 436 | const char *name) |
422 | { | 437 | { |
@@ -1065,6 +1080,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1065 | &is_64_bit); | 1080 | &is_64_bit); |
1066 | if (err) | 1081 | if (err) |
1067 | goto out_err; | 1082 | goto out_err; |
1083 | dso->is_64_bit = is_64_bit; | ||
1068 | 1084 | ||
1069 | if (list_empty(&md.maps)) { | 1085 | if (list_empty(&md.maps)) { |
1070 | err = -EINVAL; | 1086 | err = -EINVAL; |
@@ -1663,6 +1679,7 @@ do_kallsyms: | |||
1663 | free(kallsyms_allocated_filename); | 1679 | free(kallsyms_allocated_filename); |
1664 | 1680 | ||
1665 | if (err > 0 && !dso__is_kcore(dso)) { | 1681 | if (err > 0 && !dso__is_kcore(dso)) { |
1682 | dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; | ||
1666 | dso__set_long_name(dso, "[kernel.kallsyms]", false); | 1683 | dso__set_long_name(dso, "[kernel.kallsyms]", false); |
1667 | map__fixup_start(map); | 1684 | map__fixup_start(map); |
1668 | map__fixup_end(map); | 1685 | map__fixup_end(map); |
@@ -1710,6 +1727,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1710 | if (err > 0) | 1727 | if (err > 0) |
1711 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 1728 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1712 | if (err > 0 && !dso__is_kcore(dso)) { | 1729 | if (err > 0 && !dso__is_kcore(dso)) { |
1730 | dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; | ||
1713 | machine__mmap_name(machine, path, sizeof(path)); | 1731 | machine__mmap_name(machine, path, sizeof(path)); |
1714 | dso__set_long_name(dso, strdup(path), true); | 1732 | dso__set_long_name(dso, strdup(path), true); |
1715 | map__fixup_start(map); | 1733 | map__fixup_start(map); |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index a81877b1dee0..ee2d3ccd3ad1 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -216,6 +216,7 @@ struct symsrc { | |||
216 | GElf_Shdr dynshdr; | 216 | GElf_Shdr dynshdr; |
217 | 217 | ||
218 | bool adjust_symbols; | 218 | bool adjust_symbols; |
219 | bool is_64_bit; | ||
219 | #endif | 220 | #endif |
220 | }; | 221 | }; |
221 | 222 | ||
@@ -239,6 +240,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | |||
239 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 240 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
240 | const char *name); | 241 | const char *name); |
241 | 242 | ||
243 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | ||
244 | struct symbol *dso__next_symbol(struct symbol *sym); | ||
245 | |||
242 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 246 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
243 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 247 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
244 | int modules__parse(const char *filename, void *arg, | 248 | int modules__parse(const char *filename, void *arg, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2fde0d5e40b5..9692c06a9e21 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine) | |||
13 | struct thread *leader; | 13 | struct thread *leader; |
14 | pid_t pid = thread->pid_; | 14 | pid_t pid = thread->pid_; |
15 | 15 | ||
16 | if (pid == thread->tid) { | 16 | if (pid == thread->tid || pid == -1) { |
17 | thread->mg = map_groups__new(); | 17 | thread->mg = map_groups__new(); |
18 | } else { | 18 | } else { |
19 | leader = machine__findnew_thread(machine, pid, pid); | 19 | leader = machine__findnew_thread(machine, pid, pid); |
@@ -60,8 +60,10 @@ void thread__delete(struct thread *thread) | |||
60 | { | 60 | { |
61 | struct comm *comm, *tmp; | 61 | struct comm *comm, *tmp; |
62 | 62 | ||
63 | map_groups__put(thread->mg); | 63 | if (thread->mg) { |
64 | thread->mg = NULL; | 64 | map_groups__put(thread->mg); |
65 | thread->mg = NULL; | ||
66 | } | ||
65 | list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { | 67 | list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { |
66 | list_del(&comm->list); | 68 | list_del(&comm->list); |
67 | comm__free(comm); | 69 | comm__free(comm); |
@@ -127,12 +129,12 @@ int thread__comm_len(struct thread *thread) | |||
127 | size_t thread__fprintf(struct thread *thread, FILE *fp) | 129 | size_t thread__fprintf(struct thread *thread, FILE *fp) |
128 | { | 130 | { |
129 | return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + | 131 | return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + |
130 | map_groups__fprintf(thread->mg, verbose, fp); | 132 | map_groups__fprintf(thread->mg, fp); |
131 | } | 133 | } |
132 | 134 | ||
133 | void thread__insert_map(struct thread *thread, struct map *map) | 135 | void thread__insert_map(struct thread *thread, struct map *map) |
134 | { | 136 | { |
135 | map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); | 137 | map_groups__fixup_overlappings(thread->mg, map, stderr); |
136 | map_groups__insert(thread->mg, map); | 138 | map_groups__insert(thread->mg, map); |
137 | } | 139 | } |
138 | 140 | ||
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index c3bba883f5c3..eb72716017ac 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "trace-event.h" | 40 | #include "trace-event.h" |
41 | #include <api/fs/debugfs.h> | 41 | #include <api/fs/debugfs.h> |
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | #include "debug.h" | ||
43 | 44 | ||
44 | #define VERSION "0.5" | 45 | #define VERSION "0.5" |
45 | 46 | ||
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index e113e180c48f..54d9e9b548a8 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <stdio.h> | 22 | #include <stdio.h> |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <string.h> | 24 | #include <string.h> |
25 | #include <getopt.h> | ||
26 | #include <stdarg.h> | 25 | #include <stdarg.h> |
27 | #include <sys/types.h> | 26 | #include <sys/types.h> |
28 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
@@ -36,6 +35,7 @@ | |||
36 | #include "../perf.h" | 35 | #include "../perf.h" |
37 | #include "util.h" | 36 | #include "util.h" |
38 | #include "trace-event.h" | 37 | #include "trace-event.h" |
38 | #include "debug.h" | ||
39 | 39 | ||
40 | static int input_fd; | 40 | static int input_fd; |
41 | 41 | ||
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c new file mode 100644 index 000000000000..ef4749836ce9 --- /dev/null +++ b/tools/perf/util/tsc.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <linux/types.h> | ||
3 | |||
4 | #include "tsc.h" | ||
5 | |||
6 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) | ||
7 | { | ||
8 | u64 t, quot, rem; | ||
9 | |||
10 | t = ns - tc->time_zero; | ||
11 | quot = t / tc->time_mult; | ||
12 | rem = t % tc->time_mult; | ||
13 | return (quot << tc->time_shift) + | ||
14 | (rem << tc->time_shift) / tc->time_mult; | ||
15 | } | ||
16 | |||
17 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) | ||
18 | { | ||
19 | u64 quot, rem; | ||
20 | |||
21 | quot = cyc >> tc->time_shift; | ||
22 | rem = cyc & ((1 << tc->time_shift) - 1); | ||
23 | return tc->time_zero + quot * tc->time_mult + | ||
24 | ((rem * tc->time_mult) >> tc->time_shift); | ||
25 | } | ||
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h new file mode 100644 index 000000000000..4eca84887c8a --- /dev/null +++ b/tools/perf/util/tsc.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef __PERF_TSC_H | ||
2 | #define __PERF_TSC_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | #include "../arch/x86/util/tsc.h" | ||
7 | |||
8 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | ||
9 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | ||
10 | |||
11 | #endif | ||
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 5ec80a575b50..7419768c38b1 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <elfutils/libdwfl.h> | 3 | #include <elfutils/libdwfl.h> |
4 | #include <inttypes.h> | 4 | #include <inttypes.h> |
5 | #include <errno.h> | 5 | #include <errno.h> |
6 | #include "debug.h" | ||
6 | #include "unwind.h" | 7 | #include "unwind.h" |
7 | #include "unwind-libdw.h" | 8 | #include "unwind-libdw.h" |
8 | #include "machine.h" | 9 | #include "machine.h" |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 25578b98f5c5..92b56db52471 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "unwind.h" | 30 | #include "unwind.h" |
31 | #include "symbol.h" | 31 | #include "symbol.h" |
32 | #include "util.h" | 32 | #include "util.h" |
33 | #include "debug.h" | ||
33 | 34 | ||
34 | extern int | 35 | extern int |
35 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 36 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index e4132aeeb780..e52e7461911b 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "../perf.h" | 1 | #include "../perf.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "debug.h" | ||
3 | #include <api/fs/fs.h> | 4 | #include <api/fs/fs.h> |
4 | #include <sys/mman.h> | 5 | #include <sys/mman.h> |
5 | #ifdef HAVE_BACKTRACE_SUPPORT | 6 | #ifdef HAVE_BACKTRACE_SUPPORT |
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 0ddb3b8a89ec..290582452da3 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "util.h" | 12 | #include "util.h" |
13 | #include "symbol.h" | 13 | #include "symbol.h" |
14 | #include "linux/string.h" | 14 | #include "linux/string.h" |
15 | #include "debug.h" | ||
15 | 16 | ||
16 | static bool vdso_found; | 17 | static bool vdso_found; |
17 | static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; | 18 | static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; |