diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-01-09 11:17:33 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-09 11:17:33 -0500 |
commit | 3eb9ede23bdd96e9ba60e2b4d4d17a7c35d58448 (patch) | |
tree | 2bed2ab8e7fa6e6202154992433bb24ecdb9a24d | |
parent | 9cc2617de5b9222abb39cd02e90d57dfea99c6d7 (diff) | |
parent | 775d8a1b0d75211cc6123915c6b5b688f2002478 (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:
New features:
- Allow using trace events fields as sort order keys, making 'perf evlist --trace_fields'
show those, and then the user can select a subset and use like:
perf top -e sched:sched_switch -s prev_comm,next_comm
That works as well in 'perf report' when handling files containing
tracepoints.
The default when just tracepoint events are found in a perf.data file is to
format it like ftrace, using the libtraceevent formatters, plugins, etc (Namhyung Kim)
- Add support in 'perf script' to process 'perf stat record' generated files,
culminating in a python perf script that calculates CPI (Cycles per
Instruction) (Jiri Olsa)
- Show random perf tool tips in the 'perf report' bottom line (Namhyung Kim)
- perf report now defaults to --group if the perf.data file has grouped events, try it with:
# perf record -e '{cycles,instructions}' -a sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.093 MB perf.data (1247 samples) ]
# perf report
# Samples: 1K of event 'anon group { cycles, instructions }'
# Event count (approx.): 1955219195
#
# Overhead Command Shared Object Symbol
2.86% 0.22% swapper [kernel.kallsyms] [k] intel_idle
1.05% 0.33% firefox libxul.so [.] js::SetObjectElement
1.05% 0.00% kworker/0:3 [kernel.kallsyms] [k] gen6_ring_get_seqno
0.88% 0.17% chrome chrome [.] 0x0000000000ee27ab
0.65% 0.86% firefox libxul.so [.] js::ValueToId<(js::AllowGC)1>
0.64% 0.23% JS Helper libxul.so [.] js::SplayTree<js::jit::LiveRange*, js::jit::LiveRange>::splay
0.62% 1.27% firefox libxul.so [.] js::GetIterator
0.61% 1.74% firefox libxul.so [.] js::NativeSetProperty
0.61% 0.31% firefox libxul.so [.] js::SetPropertyByDefining
User visible fixes:
- Coect data mmaps so that the DWARF unwinder can handle usecases needing them,
like softice (Jiri Olsa)
- Decay callchains in fractal mode, fixing up cases where 'perf top -g' would
show entries with more than 100% (Namhyung Kim)
Infrastructure changes:
- Sync tools/lib with the lib/ in the kernel sources for find_bit.c and
move bitmap.[ch] from tools/perf/util/ to tools/lib/ (Arnaldo Carvalho de Melo)
- No need to set attr.sample_freq in some 'perf test' entries that only
want to deal with PERF_RECORD_ meta-events, improve a bit error output
for CQM test (Arnaldo Carvalho de Melo)
- Fix python binding build, adding some missing object files now required
due to cpumap using find_bit stuff (Arnaldo Carvalho de Melo)
- tools/build improvemnts (Jiri Olsa)
- Add more files to cscope/ctags databases (Jiri Olsa)
- Do not show 'trace' in 'perf help' if it is not compiled in (Jiri Olsa)
- Make perf_evlist__open() open evsels with their cpus and threads,
like perf record does, making them consistent (Adrian Hunter)
- Fix pmu snapshot initialization bug (Stephane Eranian)
- Add missing headers in perf's MANIFEST (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
65 files changed, 1556 insertions, 347 deletions
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 6c0519de765d..02db3cdff20f 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature | |||
@@ -122,13 +122,31 @@ define feature_print_text_code | |||
122 | MSG = $(shell printf '...%30s: %s' $(1) $(2)) | 122 | MSG = $(shell printf '...%30s: %s' $(1) $(2)) |
123 | endef | 123 | endef |
124 | 124 | ||
125 | # | ||
126 | # generates feature value assignment for name, like: | ||
127 | # $(call feature_assign,dwarf) == feature-dwarf=1 | ||
128 | # | ||
129 | feature_assign = feature-$(1)=$(feature-$(1)) | ||
130 | |||
125 | FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER) | 131 | FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER) |
126 | FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat)))) | 132 | FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME)) |
127 | FEATURE_DUMP_FILE := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME)) | ||
128 | 133 | ||
129 | ifeq ($(dwarf-post-unwind),1) | 134 | feature_dump_check = $(eval $(feature_dump_check_code)) |
130 | FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text)) | 135 | define feature_dump_check_code |
131 | endif | 136 | ifeq ($(findstring $(1),$(FEATURE_DUMP)),) |
137 | $(2) := 1 | ||
138 | endif | ||
139 | endef | ||
140 | |||
141 | # | ||
142 | # First check if any test from FEATURE_DISPLAY | ||
143 | # and set feature_display := 1 if it does | ||
144 | $(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display)) | ||
145 | |||
146 | # | ||
147 | # Now also check if any other test changed, | ||
148 | # so we force FEATURE-DUMP generation | ||
149 | $(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed)) | ||
132 | 150 | ||
133 | # The $(feature_display) controls the default detection message | 151 | # The $(feature_display) controls the default detection message |
134 | # output. It's set if: | 152 | # output. It's set if: |
@@ -137,13 +155,13 @@ endif | |||
137 | # - one of the $(FEATURE_DISPLAY) is not detected | 155 | # - one of the $(FEATURE_DISPLAY) is not detected |
138 | # - VF is enabled | 156 | # - VF is enabled |
139 | 157 | ||
140 | ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)") | 158 | ifeq ($(feature_dump_changed),1) |
141 | $(shell echo "$(FEATURE_DUMP)" > $(FEATURE_DUMP_FILENAME)) | 159 | $(shell rm -f $(FEATURE_DUMP_FILENAME)) |
142 | feature_display := 1 | 160 | $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME))) |
143 | endif | 161 | endif |
144 | 162 | ||
145 | feature_display_check = $(eval $(feature_check_display_code)) | 163 | feature_display_check = $(eval $(feature_check_display_code)) |
146 | define feature_display_check_code | 164 | define feature_check_display_code |
147 | ifneq ($(feature-$(1)), 1) | 165 | ifneq ($(feature-$(1)), 1) |
148 | feature_display := 1 | 166 | feature_display := 1 |
149 | endif | 167 | endif |
@@ -160,11 +178,6 @@ ifeq ($(feature_display),1) | |||
160 | $(info ) | 178 | $(info ) |
161 | $(info Auto-detecting system features:) | 179 | $(info Auto-detecting system features:) |
162 | $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),)) | 180 | $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),)) |
163 | |||
164 | ifeq ($(dwarf-post-unwind),1) | ||
165 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) | ||
166 | endif | ||
167 | |||
168 | ifneq ($(feature_verbose),1) | 181 | ifneq ($(feature_verbose),1) |
169 | $(info ) | 182 | $(info ) |
170 | endif | 183 | endif |
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/include/linux/bitmap.h index 40bd21488032..28f5493da491 100644 --- a/tools/perf/util/include/linux/bitmap.h +++ b/tools/include/linux/bitmap.h | |||
@@ -11,6 +11,8 @@ int __bitmap_weight(const unsigned long *bitmap, int bits); | |||
11 | void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, | 11 | void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, |
12 | const unsigned long *bitmap2, int bits); | 12 | const unsigned long *bitmap2, int bits); |
13 | 13 | ||
14 | #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) | ||
15 | |||
14 | #define BITMAP_LAST_WORD_MASK(nbits) \ | 16 | #define BITMAP_LAST_WORD_MASK(nbits) \ |
15 | ( \ | 17 | ( \ |
16 | ((nbits) % BITS_PER_LONG) ? \ | 18 | ((nbits) % BITS_PER_LONG) ? \ |
diff --git a/tools/perf/util/bitmap.c b/tools/lib/bitmap.c index 0a1adc1111fd..0a1adc1111fd 100644 --- a/tools/perf/util/bitmap.c +++ b/tools/lib/bitmap.c | |||
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 636e3ddb93a1..919b71780710 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -80,7 +80,11 @@ endif | |||
80 | endif | 80 | endif |
81 | 81 | ||
82 | ifeq ($(check_feat),1) | 82 | ifeq ($(check_feat),1) |
83 | ifeq ($(FEATURES_DUMP),) | ||
83 | include $(srctree)/tools/build/Makefile.feature | 84 | include $(srctree)/tools/build/Makefile.feature |
85 | else | ||
86 | include $(FEATURES_DUMP) | ||
87 | endif | ||
84 | endif | 88 | endif |
85 | 89 | ||
86 | export prefix libdir src obj | 90 | export prefix libdir src obj |
diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c new file mode 100644 index 000000000000..9122a9e80046 --- /dev/null +++ b/tools/lib/find_bit.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* bit search implementation | ||
2 | * | ||
3 | * Copied from lib/find_bit.c to tools/lib/find_bit.c | ||
4 | * | ||
5 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
6 | * Written by David Howells (dhowells@redhat.com) | ||
7 | * | ||
8 | * Copyright (C) 2008 IBM Corporation | ||
9 | * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au> | ||
10 | * (Inspired by David Howell's find_next_bit implementation) | ||
11 | * | ||
12 | * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease | ||
13 | * size and improve performance, 2015. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | */ | ||
20 | |||
21 | #include <linux/bitops.h> | ||
22 | #include <linux/bitmap.h> | ||
23 | #include <linux/kernel.h> | ||
24 | |||
25 | #if !defined(find_next_bit) | ||
26 | |||
27 | /* | ||
28 | * This is a common helper function for find_next_bit and | ||
29 | * find_next_zero_bit. The difference is the "invert" argument, which | ||
30 | * is XORed with each fetched word before searching it for one bits. | ||
31 | */ | ||
32 | static unsigned long _find_next_bit(const unsigned long *addr, | ||
33 | unsigned long nbits, unsigned long start, unsigned long invert) | ||
34 | { | ||
35 | unsigned long tmp; | ||
36 | |||
37 | if (!nbits || start >= nbits) | ||
38 | return nbits; | ||
39 | |||
40 | tmp = addr[start / BITS_PER_LONG] ^ invert; | ||
41 | |||
42 | /* Handle 1st word. */ | ||
43 | tmp &= BITMAP_FIRST_WORD_MASK(start); | ||
44 | start = round_down(start, BITS_PER_LONG); | ||
45 | |||
46 | while (!tmp) { | ||
47 | start += BITS_PER_LONG; | ||
48 | if (start >= nbits) | ||
49 | return nbits; | ||
50 | |||
51 | tmp = addr[start / BITS_PER_LONG] ^ invert; | ||
52 | } | ||
53 | |||
54 | return min(start + __ffs(tmp), nbits); | ||
55 | } | ||
56 | #endif | ||
57 | |||
58 | #ifndef find_next_bit | ||
59 | /* | ||
60 | * Find the next set bit in a memory region. | ||
61 | */ | ||
62 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | ||
63 | unsigned long offset) | ||
64 | { | ||
65 | return _find_next_bit(addr, size, offset, 0UL); | ||
66 | } | ||
67 | #endif | ||
68 | |||
69 | #ifndef find_first_bit | ||
70 | /* | ||
71 | * Find the first set bit in a memory region. | ||
72 | */ | ||
73 | unsigned long find_first_bit(const unsigned long *addr, unsigned long size) | ||
74 | { | ||
75 | unsigned long idx; | ||
76 | |||
77 | for (idx = 0; idx * BITS_PER_LONG < size; idx++) { | ||
78 | if (addr[idx]) | ||
79 | return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); | ||
80 | } | ||
81 | |||
82 | return size; | ||
83 | } | ||
84 | #endif | ||
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 68276f35e323..ea69ce35e902 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -4735,73 +4735,80 @@ static int is_printable_array(char *p, unsigned int len) | |||
4735 | return 1; | 4735 | return 1; |
4736 | } | 4736 | } |
4737 | 4737 | ||
4738 | static void print_event_fields(struct trace_seq *s, void *data, | 4738 | void pevent_print_field(struct trace_seq *s, void *data, |
4739 | int size __maybe_unused, | 4739 | struct format_field *field) |
4740 | struct event_format *event) | ||
4741 | { | 4740 | { |
4742 | struct format_field *field; | ||
4743 | unsigned long long val; | 4741 | unsigned long long val; |
4744 | unsigned int offset, len, i; | 4742 | unsigned int offset, len, i; |
4745 | 4743 | struct pevent *pevent = field->event->pevent; | |
4746 | field = event->format.fields; | 4744 | |
4747 | while (field) { | 4745 | if (field->flags & FIELD_IS_ARRAY) { |
4748 | trace_seq_printf(s, " %s=", field->name); | 4746 | offset = field->offset; |
4749 | if (field->flags & FIELD_IS_ARRAY) { | 4747 | len = field->size; |
4750 | offset = field->offset; | 4748 | if (field->flags & FIELD_IS_DYNAMIC) { |
4751 | len = field->size; | 4749 | val = pevent_read_number(pevent, data + offset, len); |
4752 | if (field->flags & FIELD_IS_DYNAMIC) { | 4750 | offset = val; |
4753 | val = pevent_read_number(event->pevent, data + offset, len); | 4751 | len = offset >> 16; |
4754 | offset = val; | 4752 | offset &= 0xffff; |
4755 | len = offset >> 16; | 4753 | } |
4756 | offset &= 0xffff; | 4754 | if (field->flags & FIELD_IS_STRING && |
4757 | } | 4755 | is_printable_array(data + offset, len)) { |
4758 | if (field->flags & FIELD_IS_STRING && | 4756 | trace_seq_printf(s, "%s", (char *)data + offset); |
4759 | is_printable_array(data + offset, len)) { | ||
4760 | trace_seq_printf(s, "%s", (char *)data + offset); | ||
4761 | } else { | ||
4762 | trace_seq_puts(s, "ARRAY["); | ||
4763 | for (i = 0; i < len; i++) { | ||
4764 | if (i) | ||
4765 | trace_seq_puts(s, ", "); | ||
4766 | trace_seq_printf(s, "%02x", | ||
4767 | *((unsigned char *)data + offset + i)); | ||
4768 | } | ||
4769 | trace_seq_putc(s, ']'); | ||
4770 | field->flags &= ~FIELD_IS_STRING; | ||
4771 | } | ||
4772 | } else { | 4757 | } else { |
4773 | val = pevent_read_number(event->pevent, data + field->offset, | 4758 | trace_seq_puts(s, "ARRAY["); |
4774 | field->size); | 4759 | for (i = 0; i < len; i++) { |
4775 | if (field->flags & FIELD_IS_POINTER) { | 4760 | if (i) |
4776 | trace_seq_printf(s, "0x%llx", val); | 4761 | trace_seq_puts(s, ", "); |
4777 | } else if (field->flags & FIELD_IS_SIGNED) { | 4762 | trace_seq_printf(s, "%02x", |
4778 | switch (field->size) { | 4763 | *((unsigned char *)data + offset + i)); |
4779 | case 4: | 4764 | } |
4780 | /* | 4765 | trace_seq_putc(s, ']'); |
4781 | * If field is long then print it in hex. | 4766 | field->flags &= ~FIELD_IS_STRING; |
4782 | * A long usually stores pointers. | 4767 | } |
4783 | */ | 4768 | } else { |
4784 | if (field->flags & FIELD_IS_LONG) | 4769 | val = pevent_read_number(pevent, data + field->offset, |
4785 | trace_seq_printf(s, "0x%x", (int)val); | 4770 | field->size); |
4786 | else | 4771 | if (field->flags & FIELD_IS_POINTER) { |
4787 | trace_seq_printf(s, "%d", (int)val); | 4772 | trace_seq_printf(s, "0x%llx", val); |
4788 | break; | 4773 | } else if (field->flags & FIELD_IS_SIGNED) { |
4789 | case 2: | 4774 | switch (field->size) { |
4790 | trace_seq_printf(s, "%2d", (short)val); | 4775 | case 4: |
4791 | break; | 4776 | /* |
4792 | case 1: | 4777 | * If field is long then print it in hex. |
4793 | trace_seq_printf(s, "%1d", (char)val); | 4778 | * A long usually stores pointers. |
4794 | break; | 4779 | */ |
4795 | default: | ||
4796 | trace_seq_printf(s, "%lld", val); | ||
4797 | } | ||
4798 | } else { | ||
4799 | if (field->flags & FIELD_IS_LONG) | 4780 | if (field->flags & FIELD_IS_LONG) |
4800 | trace_seq_printf(s, "0x%llx", val); | 4781 | trace_seq_printf(s, "0x%x", (int)val); |
4801 | else | 4782 | else |
4802 | trace_seq_printf(s, "%llu", val); | 4783 | trace_seq_printf(s, "%d", (int)val); |
4784 | break; | ||
4785 | case 2: | ||
4786 | trace_seq_printf(s, "%2d", (short)val); | ||
4787 | break; | ||
4788 | case 1: | ||
4789 | trace_seq_printf(s, "%1d", (char)val); | ||
4790 | break; | ||
4791 | default: | ||
4792 | trace_seq_printf(s, "%lld", val); | ||
4803 | } | 4793 | } |
4794 | } else { | ||
4795 | if (field->flags & FIELD_IS_LONG) | ||
4796 | trace_seq_printf(s, "0x%llx", val); | ||
4797 | else | ||
4798 | trace_seq_printf(s, "%llu", val); | ||
4804 | } | 4799 | } |
4800 | } | ||
4801 | } | ||
4802 | |||
4803 | void pevent_print_fields(struct trace_seq *s, void *data, | ||
4804 | int size __maybe_unused, struct event_format *event) | ||
4805 | { | ||
4806 | struct format_field *field; | ||
4807 | |||
4808 | field = event->format.fields; | ||
4809 | while (field) { | ||
4810 | trace_seq_printf(s, " %s=", field->name); | ||
4811 | pevent_print_field(s, data, field); | ||
4805 | field = field->next; | 4812 | field = field->next; |
4806 | } | 4813 | } |
4807 | } | 4814 | } |
@@ -4827,7 +4834,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
4827 | 4834 | ||
4828 | if (event->flags & EVENT_FL_FAILED) { | 4835 | if (event->flags & EVENT_FL_FAILED) { |
4829 | trace_seq_printf(s, "[FAILED TO PARSE]"); | 4836 | trace_seq_printf(s, "[FAILED TO PARSE]"); |
4830 | print_event_fields(s, data, size, event); | 4837 | pevent_print_fields(s, data, size, event); |
4831 | return; | 4838 | return; |
4832 | } | 4839 | } |
4833 | 4840 | ||
@@ -5301,7 +5308,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, | |||
5301 | int print_pretty = 1; | 5308 | int print_pretty = 1; |
5302 | 5309 | ||
5303 | if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) | 5310 | if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) |
5304 | print_event_fields(s, record->data, record->size, event); | 5311 | pevent_print_fields(s, record->data, record->size, event); |
5305 | else { | 5312 | else { |
5306 | 5313 | ||
5307 | if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) | 5314 | if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 6fc83c7edbe9..706d9bc24066 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -705,6 +705,10 @@ struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *com | |||
705 | struct cmdline *next); | 705 | struct cmdline *next); |
706 | int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); | 706 | int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); |
707 | 707 | ||
708 | void pevent_print_field(struct trace_seq *s, void *data, | ||
709 | struct format_field *field); | ||
710 | void pevent_print_fields(struct trace_seq *s, void *data, | ||
711 | int size __maybe_unused, struct event_format *event); | ||
708 | void pevent_event_info(struct trace_seq *s, struct event_format *event, | 712 | void pevent_event_info(struct trace_seq *s, struct event_format *event, |
709 | struct pevent_record *record); | 713 | struct pevent_record *record); |
710 | int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, | 714 | int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, |
diff --git a/tools/lib/util/find_next_bit.c b/tools/lib/util/find_next_bit.c deleted file mode 100644 index 41b44f65a79e..000000000000 --- a/tools/lib/util/find_next_bit.c +++ /dev/null | |||
@@ -1,89 +0,0 @@ | |||
1 | /* find_next_bit.c: fallback find next bit implementation | ||
2 | * | ||
3 | * Copied from lib/find_next_bit.c to tools/lib/next_bit.c | ||
4 | * | ||
5 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
6 | * Written by David Howells (dhowells@redhat.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/bitops.h> | ||
15 | #include <asm/types.h> | ||
16 | #include <asm/byteorder.h> | ||
17 | |||
18 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | ||
19 | |||
20 | #ifndef find_next_bit | ||
21 | /* | ||
22 | * Find the next set bit in a memory region. | ||
23 | */ | ||
24 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | ||
25 | unsigned long offset) | ||
26 | { | ||
27 | const unsigned long *p = addr + BITOP_WORD(offset); | ||
28 | unsigned long result = offset & ~(BITS_PER_LONG-1); | ||
29 | unsigned long tmp; | ||
30 | |||
31 | if (offset >= size) | ||
32 | return size; | ||
33 | size -= result; | ||
34 | offset %= BITS_PER_LONG; | ||
35 | if (offset) { | ||
36 | tmp = *(p++); | ||
37 | tmp &= (~0UL << offset); | ||
38 | if (size < BITS_PER_LONG) | ||
39 | goto found_first; | ||
40 | if (tmp) | ||
41 | goto found_middle; | ||
42 | size -= BITS_PER_LONG; | ||
43 | result += BITS_PER_LONG; | ||
44 | } | ||
45 | while (size & ~(BITS_PER_LONG-1)) { | ||
46 | if ((tmp = *(p++))) | ||
47 | goto found_middle; | ||
48 | result += BITS_PER_LONG; | ||
49 | size -= BITS_PER_LONG; | ||
50 | } | ||
51 | if (!size) | ||
52 | return result; | ||
53 | tmp = *p; | ||
54 | |||
55 | found_first: | ||
56 | tmp &= (~0UL >> (BITS_PER_LONG - size)); | ||
57 | if (tmp == 0UL) /* Are any bits set? */ | ||
58 | return result + size; /* Nope. */ | ||
59 | found_middle: | ||
60 | return result + __ffs(tmp); | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | #ifndef find_first_bit | ||
65 | /* | ||
66 | * Find the first set bit in a memory region. | ||
67 | */ | ||
68 | unsigned long find_first_bit(const unsigned long *addr, unsigned long size) | ||
69 | { | ||
70 | const unsigned long *p = addr; | ||
71 | unsigned long result = 0; | ||
72 | unsigned long tmp; | ||
73 | |||
74 | while (size & ~(BITS_PER_LONG-1)) { | ||
75 | if ((tmp = *(p++))) | ||
76 | goto found; | ||
77 | result += BITS_PER_LONG; | ||
78 | size -= BITS_PER_LONG; | ||
79 | } | ||
80 | if (!size) | ||
81 | return result; | ||
82 | |||
83 | tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); | ||
84 | if (tmp == 0UL) /* Are any bits set? */ | ||
85 | return result + size; /* Nope. */ | ||
86 | found: | ||
87 | return result + __ffs(tmp); | ||
88 | } | ||
89 | #endif | ||
diff --git a/tools/perf/Build b/tools/perf/Build index 00c4b8c3d8ca..6b67e6f4179f 100644 --- a/tools/perf/Build +++ b/tools/perf/Build | |||
@@ -41,6 +41,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \ | |||
41 | -DPREFIX="BUILD_STR($(prefix_SQ))" \ | 41 | -DPREFIX="BUILD_STR($(prefix_SQ))" \ |
42 | -include $(OUTPUT)PERF-VERSION-FILE | 42 | -include $(OUTPUT)PERF-VERSION-FILE |
43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" | 43 | CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" |
44 | CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" | ||
44 | 45 | ||
45 | libperf-y += util/ | 46 | libperf-y += util/ |
46 | libperf-y += arch/ | 47 | libperf-y += arch/ |
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 1ceb3700ffbb..6f7200fb85cf 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt | |||
@@ -32,6 +32,9 @@ OPTIONS | |||
32 | --group:: | 32 | --group:: |
33 | Show event group information. | 33 | Show event group information. |
34 | 34 | ||
35 | --trace-fields:: | ||
36 | Show tracepoint field names. | ||
37 | |||
35 | SEE ALSO | 38 | SEE ALSO |
36 | -------- | 39 | -------- |
37 | linkperf:perf-record[1], linkperf:perf-list[1], | 40 | linkperf:perf-record[1], linkperf:perf-list[1], |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index dab99ed2b339..8a301f6afb37 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -117,6 +117,30 @@ OPTIONS | |||
117 | And default sort keys are changed to comm, dso_from, symbol_from, dso_to | 117 | And default sort keys are changed to comm, dso_from, symbol_from, dso_to |
118 | and symbol_to, see '--branch-stack'. | 118 | and symbol_to, see '--branch-stack'. |
119 | 119 | ||
120 | If the data file has tracepoint event(s), following (dynamic) sort keys | ||
121 | are also available: | ||
122 | trace, trace_fields, [<event>.]<field>[/raw] | ||
123 | |||
124 | - trace: pretty printed trace output in a single column | ||
125 | - trace_fields: fields in tracepoints in separate columns | ||
126 | - <field name>: optional event and field name for a specific field | ||
127 | |||
128 | The last form consists of event and field names. If event name is | ||
129 | omitted, it searches all events for matching field name. The matched | ||
130 | field will be shown only for the event has the field. The event name | ||
131 | supports substring match so user doesn't need to specify full subsystem | ||
132 | and event name everytime. For example, 'sched:sched_switch' event can | ||
133 | be shortened to 'switch' as long as it's not ambiguous. Also event can | ||
134 | be specified by its index (starting from 1) preceded by the '%'. | ||
135 | So '%1' is the first event, '%2' is the second, and so on. | ||
136 | |||
137 | The field name can have '/raw' suffix which disables pretty printing | ||
138 | and shows raw field value like hex numbers. The --raw-trace option | ||
139 | has the same effect for all dynamic sort keys. | ||
140 | |||
141 | The default sort keys are changed to 'trace' if all events in the data | ||
142 | file are tracepoint. | ||
143 | |||
120 | -F:: | 144 | -F:: |
121 | --fields=:: | 145 | --fields=:: |
122 | Specify output field - multiple keys can be specified in CSV format. | 146 | Specify output field - multiple keys can be specified in CSV format. |
@@ -371,6 +395,9 @@ include::itrace.txt[] | |||
371 | --socket-filter:: | 395 | --socket-filter:: |
372 | Only report the samples on the processor socket that match with this filter | 396 | Only report the samples on the processor socket that match with this filter |
373 | 397 | ||
398 | --raw-trace:: | ||
399 | When displaying traceevent output, do not use print fmt or plugins. | ||
400 | |||
374 | include::callchain-overhead-calculation.txt[] | 401 | include::callchain-overhead-calculation.txt[] |
375 | 402 | ||
376 | SEE ALSO | 403 | SEE ALSO |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 556cec09bf50..b0e60e17db38 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -230,6 +230,9 @@ Default is to monitor all CPUS. | |||
230 | The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k | 230 | The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k |
231 | Note that this feature may not be available on all processors. | 231 | Note that this feature may not be available on all processors. |
232 | 232 | ||
233 | --raw-trace:: | ||
234 | When displaying traceevent output, do not use print fmt or plugins. | ||
235 | |||
233 | INTERACTIVE PROMPTING KEYS | 236 | INTERACTIVE PROMPTING KEYS |
234 | -------------------------- | 237 | -------------------------- |
235 | 238 | ||
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt new file mode 100644 index 000000000000..a1c10e360db5 --- /dev/null +++ b/tools/perf/Documentation/tips.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | For a higher level overview, try: perf report --sort comm,dso | ||
2 | Sample related events with: perf record -e '{cycles,instructions}:S' | ||
3 | Compare performance results with: perf diff [<old file> <new file>] | ||
4 | Boolean options have negative forms, e.g.: perf report --no-children | ||
5 | Customize output of perf script with: perf script -F event,ip,sym | ||
6 | Generate a script for your data: perf script -g <lang> | ||
7 | Save output of perf stat using: perf stat record <target workload> | ||
8 | Create an archive with symtabs to analyse on other machine: perf archive | ||
9 | Search options using a keyword: perf report -h <keyword> | ||
10 | Use parent filter to see specific call path: perf report -p <regex> | ||
11 | List events using substring match: perf list <keyword> | ||
12 | To see list of saved events and attributes: perf evlist -v | ||
13 | Use --symfs <dir> if your symbol files are in non-standard locations | ||
14 | To see callchains in a more compact form: perf report -g folded | ||
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index ce3932ee4893..ddf922f93aa1 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -1,6 +1,7 @@ | |||
1 | tools/perf | 1 | tools/perf |
2 | tools/arch/alpha/include/asm/barrier.h | 2 | tools/arch/alpha/include/asm/barrier.h |
3 | tools/arch/arm/include/asm/barrier.h | 3 | tools/arch/arm/include/asm/barrier.h |
4 | tools/arch/arm64/include/asm/barrier.h | ||
4 | tools/arch/ia64/include/asm/barrier.h | 5 | tools/arch/ia64/include/asm/barrier.h |
5 | tools/arch/mips/include/asm/barrier.h | 6 | tools/arch/mips/include/asm/barrier.h |
6 | tools/arch/powerpc/include/asm/barrier.h | 7 | tools/arch/powerpc/include/asm/barrier.h |
@@ -26,10 +27,11 @@ tools/lib/rbtree.c | |||
26 | tools/lib/string.c | 27 | tools/lib/string.c |
27 | tools/lib/symbol/kallsyms.c | 28 | tools/lib/symbol/kallsyms.c |
28 | tools/lib/symbol/kallsyms.h | 29 | tools/lib/symbol/kallsyms.h |
29 | tools/lib/util/find_next_bit.c | 30 | tools/lib/find_bit.c |
30 | tools/include/asm/atomic.h | 31 | tools/include/asm/atomic.h |
31 | tools/include/asm/barrier.h | 32 | tools/include/asm/barrier.h |
32 | tools/include/asm/bug.h | 33 | tools/include/asm/bug.h |
34 | tools/include/asm-generic/atomic-gcc.h | ||
33 | tools/include/asm-generic/barrier.h | 35 | tools/include/asm-generic/barrier.h |
34 | tools/include/asm-generic/bitops/arch_hweight.h | 36 | tools/include/asm-generic/bitops/arch_hweight.h |
35 | tools/include/asm-generic/bitops/atomic.h | 37 | tools/include/asm-generic/bitops/atomic.h |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 569fcf022531..0a22407e1d7d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -436,7 +436,7 @@ $(LIBAPI)-clean: | |||
436 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null | 436 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
437 | 437 | ||
438 | $(LIBBPF): fixdep FORCE | 438 | $(LIBBPF): fixdep FORCE |
439 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a | 439 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(realpath $(OUTPUT)FEATURE-DUMP) |
440 | 440 | ||
441 | $(LIBBPF)-clean: | 441 | $(LIBBPF)-clean: |
442 | $(call QUIET_CLEAN, libbpf) | 442 | $(call QUIET_CLEAN, libbpf) |
@@ -488,7 +488,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html | |||
488 | $(DOC_TARGETS): | 488 | $(DOC_TARGETS): |
489 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) | 489 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) |
490 | 490 | ||
491 | TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf | 491 | TAG_FOLDERS= . ../lib ../include |
492 | TAG_FILES= ../../include/uapi/linux/perf_event.h | 492 | TAG_FILES= ../../include/uapi/linux/perf_event.h |
493 | 493 | ||
494 | TAGS: | 494 | TAGS: |
@@ -567,6 +567,9 @@ endif | |||
567 | $(call QUIET_INSTALL, perf_completion-script) \ | 567 | $(call QUIET_INSTALL, perf_completion-script) \ |
568 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ | 568 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ |
569 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' | 569 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' |
570 | $(call QUIET_INSTALL, perf-tip) \ | ||
571 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \ | ||
572 | $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)' | ||
570 | 573 | ||
571 | install-tests: all install-gtk | 574 | install-tests: all install-gtk |
572 | $(call QUIET_INSTALL, tests) \ | 575 | $(call QUIET_INSTALL, tests) \ |
diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c index 94e0cb7462f9..3e89ba825f6b 100644 --- a/tools/perf/arch/x86/tests/intel-cqm.c +++ b/tools/perf/arch/x86/tests/intel-cqm.c | |||
@@ -54,7 +54,7 @@ int test__intel_cqm_count_nmi_context(int subtest __maybe_unused) | |||
54 | 54 | ||
55 | ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); | 55 | ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); |
56 | if (ret) { | 56 | if (ret) { |
57 | pr_debug("parse_events failed\n"); | 57 | pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n"); |
58 | err = TEST_SKIP; | 58 | err = TEST_SKIP; |
59 | goto out; | 59 | goto out; |
60 | } | 60 | } |
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index a289aa8a083a..9d29ee283ac5 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c | |||
@@ -41,7 +41,6 @@ int test__perf_time_to_tsc(int subtest __maybe_unused) | |||
41 | .mmap_pages = UINT_MAX, | 41 | .mmap_pages = UINT_MAX, |
42 | .user_freq = UINT_MAX, | 42 | .user_freq = UINT_MAX, |
43 | .user_interval = ULLONG_MAX, | 43 | .user_interval = ULLONG_MAX, |
44 | .freq = 4000, | ||
45 | .target = { | 44 | .target = { |
46 | .uses_mmap = true, | 45 | .uses_mmap = true, |
47 | }, | 46 | }, |
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index 9b94ce520917..8d8150f1cf9b 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c | |||
@@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr) | |||
327 | 327 | ||
328 | evlist__for_each(btsr->evlist, evsel) { | 328 | evlist__for_each(btsr->evlist, evsel) { |
329 | if (evsel->attr.type == btsr->intel_bts_pmu->type) | 329 | if (evsel->attr.type == btsr->intel_bts_pmu->type) |
330 | return perf_evlist__disable_event(btsr->evlist, evsel); | 330 | return perf_evsel__disable(evsel); |
331 | } | 331 | } |
332 | return -EINVAL; | 332 | return -EINVAL; |
333 | } | 333 | } |
@@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr) | |||
340 | 340 | ||
341 | evlist__for_each(btsr->evlist, evsel) { | 341 | evlist__for_each(btsr->evlist, evsel) { |
342 | if (evsel->attr.type == btsr->intel_bts_pmu->type) | 342 | if (evsel->attr.type == btsr->intel_bts_pmu->type) |
343 | return perf_evlist__enable_event(btsr->evlist, evsel); | 343 | return perf_evsel__enable(evsel); |
344 | } | 344 | } |
345 | return -EINVAL; | 345 | return -EINVAL; |
346 | } | 346 | } |
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index b64d46285ebb..f05daacc9e78 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c | |||
@@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr) | |||
725 | 725 | ||
726 | evlist__for_each(ptr->evlist, evsel) { | 726 | evlist__for_each(ptr->evlist, evsel) { |
727 | if (evsel->attr.type == ptr->intel_pt_pmu->type) | 727 | if (evsel->attr.type == ptr->intel_pt_pmu->type) |
728 | return perf_evlist__disable_event(ptr->evlist, evsel); | 728 | return perf_evsel__disable(evsel); |
729 | } | 729 | } |
730 | return -EINVAL; | 730 | return -EINVAL; |
731 | } | 731 | } |
@@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr) | |||
738 | 738 | ||
739 | evlist__for_each(ptr->evlist, evsel) { | 739 | evlist__for_each(ptr->evlist, evsel) { |
740 | if (evsel->attr.type == ptr->intel_pt_pmu->type) | 740 | if (evsel->attr.type == ptr->intel_pt_pmu->type) |
741 | return perf_evlist__enable_event(ptr->evlist, evsel); | 741 | return perf_evsel__enable(evsel); |
742 | } | 742 | } |
743 | return -EINVAL; | 743 | return -EINVAL; |
744 | } | 744 | } |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e18f1b995ffd..cc5c1267c738 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -47,7 +47,7 @@ struct perf_annotate { | |||
47 | }; | 47 | }; |
48 | 48 | ||
49 | static int perf_evsel__add_sample(struct perf_evsel *evsel, | 49 | static int perf_evsel__add_sample(struct perf_evsel *evsel, |
50 | struct perf_sample *sample __maybe_unused, | 50 | struct perf_sample *sample, |
51 | struct addr_location *al, | 51 | struct addr_location *al, |
52 | struct perf_annotate *ann) | 52 | struct perf_annotate *ann) |
53 | { | 53 | { |
@@ -72,7 +72,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
75 | he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true); | 75 | sample->period = 1; |
76 | sample->weight = 1; | ||
77 | |||
78 | he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); | ||
76 | if (he == NULL) | 79 | if (he == NULL) |
77 | return -ENOMEM; | 80 | return -ENOMEM; |
78 | 81 | ||
@@ -367,7 +370,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
367 | if (ret < 0) | 370 | if (ret < 0) |
368 | goto out_delete; | 371 | goto out_delete; |
369 | 372 | ||
370 | if (setup_sorting() < 0) | 373 | if (setup_sorting(NULL) < 0) |
371 | usage_with_options(annotate_usage, options); | 374 | usage_with_options(annotate_usage, options); |
372 | 375 | ||
373 | if (annotate.use_stdio) | 376 | if (annotate.use_stdio) |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 0b180a885ba3..36ccc2b8827f 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -311,11 +311,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, | |||
311 | } | 311 | } |
312 | 312 | ||
313 | static int hists__add_entry(struct hists *hists, | 313 | static int hists__add_entry(struct hists *hists, |
314 | struct addr_location *al, u64 period, | 314 | struct addr_location *al, |
315 | u64 weight, u64 transaction) | 315 | struct perf_sample *sample) |
316 | { | 316 | { |
317 | if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, | 317 | if (__hists__add_entry(hists, al, NULL, NULL, NULL, |
318 | transaction, true) != NULL) | 318 | sample, true) != NULL) |
319 | return 0; | 319 | return 0; |
320 | return -ENOMEM; | 320 | return -ENOMEM; |
321 | } | 321 | } |
@@ -336,8 +336,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, | |||
336 | return -1; | 336 | return -1; |
337 | } | 337 | } |
338 | 338 | ||
339 | if (hists__add_entry(hists, &al, sample->period, | 339 | if (hists__add_entry(hists, &al, sample)) { |
340 | sample->weight, sample->transaction)) { | ||
341 | pr_warning("problem incrementing symbol period, skipping event\n"); | 340 | pr_warning("problem incrementing symbol period, skipping event\n"); |
342 | goto out_put; | 341 | goto out_put; |
343 | } | 342 | } |
@@ -1208,7 +1207,7 @@ static int ui_init(void) | |||
1208 | BUG_ON(1); | 1207 | BUG_ON(1); |
1209 | } | 1208 | } |
1210 | 1209 | ||
1211 | list_add(&fmt->sort_list, &perf_hpp__sort_list); | 1210 | perf_hpp__register_sort_field(fmt); |
1212 | return 0; | 1211 | return 0; |
1213 | } | 1212 | } |
1214 | 1213 | ||
@@ -1280,7 +1279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1280 | 1279 | ||
1281 | sort__mode = SORT_MODE__DIFF; | 1280 | sort__mode = SORT_MODE__DIFF; |
1282 | 1281 | ||
1283 | if (setup_sorting() < 0) | 1282 | if (setup_sorting(NULL) < 0) |
1284 | usage_with_options(diff_usage, options); | 1283 | usage_with_options(diff_usage, options); |
1285 | 1284 | ||
1286 | setup_pager(); | 1285 | setup_pager(); |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 08a7d36a2cf8..8a31f511e1a0 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -26,14 +26,22 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
26 | .mode = PERF_DATA_MODE_READ, | 26 | .mode = PERF_DATA_MODE_READ, |
27 | .force = details->force, | 27 | .force = details->force, |
28 | }; | 28 | }; |
29 | bool has_tracepoint = false; | ||
29 | 30 | ||
30 | session = perf_session__new(&file, 0, NULL); | 31 | session = perf_session__new(&file, 0, NULL); |
31 | if (session == NULL) | 32 | if (session == NULL) |
32 | return -1; | 33 | return -1; |
33 | 34 | ||
34 | evlist__for_each(session->evlist, pos) | 35 | evlist__for_each(session->evlist, pos) { |
35 | perf_evsel__fprintf(pos, details, stdout); | 36 | perf_evsel__fprintf(pos, details, stdout); |
36 | 37 | ||
38 | if (pos->attr.type == PERF_TYPE_TRACEPOINT) | ||
39 | has_tracepoint = true; | ||
40 | } | ||
41 | |||
42 | if (has_tracepoint && !details->trace_fields) | ||
43 | printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n"); | ||
44 | |||
37 | perf_session__delete(session); | 45 | perf_session__delete(session); |
38 | return 0; | 46 | return 0; |
39 | } | 47 | } |
@@ -49,6 +57,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | |||
49 | OPT_BOOLEAN('g', "group", &details.event_group, | 57 | OPT_BOOLEAN('g', "group", &details.event_group, |
50 | "Show event group information"), | 58 | "Show event group information"), |
51 | OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"), | 59 | OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"), |
60 | OPT_BOOLEAN(0, "trace-fields", &details.trace_fields, "Show tracepoint fields"), | ||
52 | OPT_END() | 61 | OPT_END() |
53 | }; | 62 | }; |
54 | const char * const evlist_usage[] = { | 63 | const char * const evlist_usage[] = { |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9c5cdc2c4471..dc4e0adf5c5b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -815,8 +815,12 @@ int record_parse_callchain_opt(const struct option *opt, | |||
815 | } | 815 | } |
816 | 816 | ||
817 | ret = parse_callchain_record_opt(arg, &callchain_param); | 817 | ret = parse_callchain_record_opt(arg, &callchain_param); |
818 | if (!ret) | 818 | if (!ret) { |
819 | /* Enable data address sampling for DWARF unwind. */ | ||
820 | if (callchain_param.record_mode == CALLCHAIN_DWARF) | ||
821 | record->sample_address = true; | ||
819 | callchain_debug(); | 822 | callchain_debug(); |
823 | } | ||
820 | 824 | ||
821 | return ret; | 825 | return ret; |
822 | } | 826 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2a7330b99b82..d5a42ee12529 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -433,7 +433,7 @@ static int report__browse_hists(struct report *rep) | |||
433 | int ret; | 433 | int ret; |
434 | struct perf_session *session = rep->session; | 434 | struct perf_session *session = rep->session; |
435 | struct perf_evlist *evlist = session->evlist; | 435 | struct perf_evlist *evlist = session->evlist; |
436 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | 436 | const char *help = perf_tip(TIPDIR); |
437 | 437 | ||
438 | switch (use_browser) { | 438 | switch (use_browser) { |
439 | case 1: | 439 | case 1: |
@@ -788,6 +788,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
788 | "Show callgraph from reference event"), | 788 | "Show callgraph from reference event"), |
789 | OPT_INTEGER(0, "socket-filter", &report.socket_filter, | 789 | OPT_INTEGER(0, "socket-filter", &report.socket_filter, |
790 | "only show processor socket that match with this filter"), | 790 | "only show processor socket that match with this filter"), |
791 | OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, | ||
792 | "Show raw trace event output (do not use print fmt or plugins)"), | ||
791 | OPT_END() | 793 | OPT_END() |
792 | }; | 794 | }; |
793 | struct perf_data_file file = { | 795 | struct perf_data_file file = { |
@@ -897,7 +899,7 @@ repeat: | |||
897 | symbol_conf.cumulate_callchain = false; | 899 | symbol_conf.cumulate_callchain = false; |
898 | } | 900 | } |
899 | 901 | ||
900 | if (setup_sorting() < 0) { | 902 | if (setup_sorting(session->evlist) < 0) { |
901 | if (sort_order) | 903 | if (sort_order) |
902 | parse_options_usage(report_usage, options, "s", 1); | 904 | parse_options_usage(report_usage, options, "s", 1); |
903 | if (field_order) | 905 | if (field_order) |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index bcc3542d9df5..c691214d820f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -18,7 +18,11 @@ | |||
18 | #include "util/sort.h" | 18 | #include "util/sort.h" |
19 | #include "util/data.h" | 19 | #include "util/data.h" |
20 | #include "util/auxtrace.h" | 20 | #include "util/auxtrace.h" |
21 | #include "util/cpumap.h" | ||
22 | #include "util/thread_map.h" | ||
23 | #include "util/stat.h" | ||
21 | #include <linux/bitmap.h> | 24 | #include <linux/bitmap.h> |
25 | #include "asm/bug.h" | ||
22 | 26 | ||
23 | static char const *script_name; | 27 | static char const *script_name; |
24 | static char const *generate_script_lang; | 28 | static char const *generate_script_lang; |
@@ -32,6 +36,7 @@ static bool print_flags; | |||
32 | static bool nanosecs; | 36 | static bool nanosecs; |
33 | static const char *cpu_list; | 37 | static const char *cpu_list; |
34 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 38 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
39 | static struct perf_stat_config stat_config; | ||
35 | 40 | ||
36 | unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; | 41 | unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; |
37 | 42 | ||
@@ -216,6 +221,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
216 | struct perf_event_attr *attr = &evsel->attr; | 221 | struct perf_event_attr *attr = &evsel->attr; |
217 | bool allow_user_set; | 222 | bool allow_user_set; |
218 | 223 | ||
224 | if (perf_header__has_feat(&session->header, HEADER_STAT)) | ||
225 | return 0; | ||
226 | |||
219 | allow_user_set = perf_header__has_feat(&session->header, | 227 | allow_user_set = perf_header__has_feat(&session->header, |
220 | HEADER_AUXTRACE); | 228 | HEADER_AUXTRACE); |
221 | 229 | ||
@@ -606,9 +614,27 @@ struct perf_script { | |||
606 | bool show_task_events; | 614 | bool show_task_events; |
607 | bool show_mmap_events; | 615 | bool show_mmap_events; |
608 | bool show_switch_events; | 616 | bool show_switch_events; |
617 | bool allocated; | ||
618 | struct cpu_map *cpus; | ||
619 | struct thread_map *threads; | ||
620 | int name_width; | ||
609 | }; | 621 | }; |
610 | 622 | ||
611 | static void process_event(struct perf_script *script __maybe_unused, union perf_event *event, | 623 | static int perf_evlist__max_name_len(struct perf_evlist *evlist) |
624 | { | ||
625 | struct perf_evsel *evsel; | ||
626 | int max = 0; | ||
627 | |||
628 | evlist__for_each(evlist, evsel) { | ||
629 | int len = strlen(perf_evsel__name(evsel)); | ||
630 | |||
631 | max = MAX(len, max); | ||
632 | } | ||
633 | |||
634 | return max; | ||
635 | } | ||
636 | |||
637 | static void process_event(struct perf_script *script, union perf_event *event, | ||
612 | struct perf_sample *sample, struct perf_evsel *evsel, | 638 | struct perf_sample *sample, struct perf_evsel *evsel, |
613 | struct addr_location *al) | 639 | struct addr_location *al) |
614 | { | 640 | { |
@@ -625,7 +651,12 @@ static void process_event(struct perf_script *script __maybe_unused, union perf_ | |||
625 | 651 | ||
626 | if (PRINT_FIELD(EVNAME)) { | 652 | if (PRINT_FIELD(EVNAME)) { |
627 | const char *evname = perf_evsel__name(evsel); | 653 | const char *evname = perf_evsel__name(evsel); |
628 | printf("%s: ", evname ? evname : "[unknown]"); | 654 | |
655 | if (!script->name_width) | ||
656 | script->name_width = perf_evlist__max_name_len(script->session->evlist); | ||
657 | |||
658 | printf("%*s: ", script->name_width, | ||
659 | evname ? evname : "[unknown]"); | ||
629 | } | 660 | } |
630 | 661 | ||
631 | if (print_flags) | 662 | if (print_flags) |
@@ -666,6 +697,54 @@ static void process_event(struct perf_script *script __maybe_unused, union perf_ | |||
666 | 697 | ||
667 | static struct scripting_ops *scripting_ops; | 698 | static struct scripting_ops *scripting_ops; |
668 | 699 | ||
700 | static void __process_stat(struct perf_evsel *counter, u64 tstamp) | ||
701 | { | ||
702 | int nthreads = thread_map__nr(counter->threads); | ||
703 | int ncpus = perf_evsel__nr_cpus(counter); | ||
704 | int cpu, thread; | ||
705 | static int header_printed; | ||
706 | |||
707 | if (counter->system_wide) | ||
708 | nthreads = 1; | ||
709 | |||
710 | if (!header_printed) { | ||
711 | printf("%3s %8s %15s %15s %15s %15s %s\n", | ||
712 | "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT"); | ||
713 | header_printed = 1; | ||
714 | } | ||
715 | |||
716 | for (thread = 0; thread < nthreads; thread++) { | ||
717 | for (cpu = 0; cpu < ncpus; cpu++) { | ||
718 | struct perf_counts_values *counts; | ||
719 | |||
720 | counts = perf_counts(counter->counts, cpu, thread); | ||
721 | |||
722 | printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n", | ||
723 | counter->cpus->map[cpu], | ||
724 | thread_map__pid(counter->threads, thread), | ||
725 | counts->val, | ||
726 | counts->ena, | ||
727 | counts->run, | ||
728 | tstamp, | ||
729 | perf_evsel__name(counter)); | ||
730 | } | ||
731 | } | ||
732 | } | ||
733 | |||
734 | static void process_stat(struct perf_evsel *counter, u64 tstamp) | ||
735 | { | ||
736 | if (scripting_ops && scripting_ops->process_stat) | ||
737 | scripting_ops->process_stat(&stat_config, counter, tstamp); | ||
738 | else | ||
739 | __process_stat(counter, tstamp); | ||
740 | } | ||
741 | |||
742 | static void process_stat_interval(u64 tstamp) | ||
743 | { | ||
744 | if (scripting_ops && scripting_ops->process_stat_interval) | ||
745 | scripting_ops->process_stat_interval(tstamp); | ||
746 | } | ||
747 | |||
669 | static void setup_scripting(void) | 748 | static void setup_scripting(void) |
670 | { | 749 | { |
671 | setup_perl_scripting(); | 750 | setup_perl_scripting(); |
@@ -1682,6 +1761,87 @@ static void script__setup_sample_type(struct perf_script *script) | |||
1682 | } | 1761 | } |
1683 | } | 1762 | } |
1684 | 1763 | ||
1764 | static int process_stat_round_event(struct perf_tool *tool __maybe_unused, | ||
1765 | union perf_event *event, | ||
1766 | struct perf_session *session) | ||
1767 | { | ||
1768 | struct stat_round_event *round = &event->stat_round; | ||
1769 | struct perf_evsel *counter; | ||
1770 | |||
1771 | evlist__for_each(session->evlist, counter) { | ||
1772 | perf_stat_process_counter(&stat_config, counter); | ||
1773 | process_stat(counter, round->time); | ||
1774 | } | ||
1775 | |||
1776 | process_stat_interval(round->time); | ||
1777 | return 0; | ||
1778 | } | ||
1779 | |||
1780 | static int process_stat_config_event(struct perf_tool *tool __maybe_unused, | ||
1781 | union perf_event *event, | ||
1782 | struct perf_session *session __maybe_unused) | ||
1783 | { | ||
1784 | perf_event__read_stat_config(&stat_config, &event->stat_config); | ||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | static int set_maps(struct perf_script *script) | ||
1789 | { | ||
1790 | struct perf_evlist *evlist = script->session->evlist; | ||
1791 | |||
1792 | if (!script->cpus || !script->threads) | ||
1793 | return 0; | ||
1794 | |||
1795 | if (WARN_ONCE(script->allocated, "stats double allocation\n")) | ||
1796 | return -EINVAL; | ||
1797 | |||
1798 | perf_evlist__set_maps(evlist, script->cpus, script->threads); | ||
1799 | |||
1800 | if (perf_evlist__alloc_stats(evlist, true)) | ||
1801 | return -ENOMEM; | ||
1802 | |||
1803 | script->allocated = true; | ||
1804 | return 0; | ||
1805 | } | ||
1806 | |||
1807 | static | ||
1808 | int process_thread_map_event(struct perf_tool *tool, | ||
1809 | union perf_event *event, | ||
1810 | struct perf_session *session __maybe_unused) | ||
1811 | { | ||
1812 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
1813 | |||
1814 | if (script->threads) { | ||
1815 | pr_warning("Extra thread map event, ignoring.\n"); | ||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | script->threads = thread_map__new_event(&event->thread_map); | ||
1820 | if (!script->threads) | ||
1821 | return -ENOMEM; | ||
1822 | |||
1823 | return set_maps(script); | ||
1824 | } | ||
1825 | |||
1826 | static | ||
1827 | int process_cpu_map_event(struct perf_tool *tool __maybe_unused, | ||
1828 | union perf_event *event, | ||
1829 | struct perf_session *session __maybe_unused) | ||
1830 | { | ||
1831 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
1832 | |||
1833 | if (script->cpus) { | ||
1834 | pr_warning("Extra cpu map event, ignoring.\n"); | ||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1838 | script->cpus = cpu_map__new_data(&event->cpu_map.data); | ||
1839 | if (!script->cpus) | ||
1840 | return -ENOMEM; | ||
1841 | |||
1842 | return set_maps(script); | ||
1843 | } | ||
1844 | |||
1685 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | 1845 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) |
1686 | { | 1846 | { |
1687 | bool show_full_info = false; | 1847 | bool show_full_info = false; |
@@ -1710,6 +1870,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1710 | .auxtrace_info = perf_event__process_auxtrace_info, | 1870 | .auxtrace_info = perf_event__process_auxtrace_info, |
1711 | .auxtrace = perf_event__process_auxtrace, | 1871 | .auxtrace = perf_event__process_auxtrace, |
1712 | .auxtrace_error = perf_event__process_auxtrace_error, | 1872 | .auxtrace_error = perf_event__process_auxtrace_error, |
1873 | .stat = perf_event__process_stat_event, | ||
1874 | .stat_round = process_stat_round_event, | ||
1875 | .stat_config = process_stat_config_event, | ||
1876 | .thread_map = process_thread_map_event, | ||
1877 | .cpu_map = process_cpu_map_event, | ||
1713 | .ordered_events = true, | 1878 | .ordered_events = true, |
1714 | .ordering_requires_timestamps = true, | 1879 | .ordering_requires_timestamps = true, |
1715 | }, | 1880 | }, |
@@ -2063,6 +2228,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2063 | flush_scripting(); | 2228 | flush_scripting(); |
2064 | 2229 | ||
2065 | out_delete: | 2230 | out_delete: |
2231 | perf_evlist__free_stats(session->evlist); | ||
2066 | perf_session__delete(session); | 2232 | perf_session__delete(session); |
2067 | 2233 | ||
2068 | if (script_started) | 2234 | if (script_started) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9805e03ab163..7f568244662b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -184,11 +184,18 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
184 | * like tracepoints. Clear it up for counting. | 184 | * like tracepoints. Clear it up for counting. |
185 | */ | 185 | */ |
186 | attr->sample_period = 0; | 186 | attr->sample_period = 0; |
187 | |||
187 | /* | 188 | /* |
188 | * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless | 189 | * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless |
189 | * while avoiding that older tools show confusing messages. | 190 | * while avoiding that older tools show confusing messages. |
191 | * | ||
192 | * However for pipe sessions we need to keep it zero, | ||
193 | * because script's perf_evsel__check_attr is triggered | ||
194 | * by attr->sample_type != 0, and we can't run it on | ||
195 | * stat sessions. | ||
190 | */ | 196 | */ |
191 | attr->sample_type = PERF_SAMPLE_IDENTIFIER; | 197 | if (!(STAT_RECORD && perf_stat.file.is_pipe)) |
198 | attr->sample_type = PERF_SAMPLE_IDENTIFIER; | ||
192 | 199 | ||
193 | /* | 200 | /* |
194 | * Disabling all counters initially, they will be enabled | 201 | * Disabling all counters initially, they will be enabled |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 9ebd67a42ede..bf01cbb0ef23 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -1210,6 +1210,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1210 | OPT_CALLBACK('j', "branch-filter", &opts->branch_stack, | 1210 | OPT_CALLBACK('j', "branch-filter", &opts->branch_stack, |
1211 | "branch filter mask", "branch stack filter modes", | 1211 | "branch filter mask", "branch stack filter modes", |
1212 | parse_branch_stack), | 1212 | parse_branch_stack), |
1213 | OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, | ||
1214 | "Show raw trace event output (do not use print fmt or plugins)"), | ||
1213 | OPT_END() | 1215 | OPT_END() |
1214 | }; | 1216 | }; |
1215 | const char * const top_usage[] = { | 1217 | const char * const top_usage[] = { |
@@ -1231,11 +1233,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1231 | if (argc) | 1233 | if (argc) |
1232 | usage_with_options(top_usage, options); | 1234 | usage_with_options(top_usage, options); |
1233 | 1235 | ||
1236 | if (!top.evlist->nr_entries && | ||
1237 | perf_evlist__add_default(top.evlist) < 0) { | ||
1238 | pr_err("Not enough memory for event selector list\n"); | ||
1239 | goto out_delete_evlist; | ||
1240 | } | ||
1241 | |||
1234 | sort__mode = SORT_MODE__TOP; | 1242 | sort__mode = SORT_MODE__TOP; |
1235 | /* display thread wants entries to be collapsed in a different tree */ | 1243 | /* display thread wants entries to be collapsed in a different tree */ |
1236 | sort__need_collapse = 1; | 1244 | sort__need_collapse = 1; |
1237 | 1245 | ||
1238 | if (setup_sorting() < 0) { | 1246 | if (setup_sorting(top.evlist) < 0) { |
1239 | if (sort_order) | 1247 | if (sort_order) |
1240 | parse_options_usage(top_usage, options, "s", 1); | 1248 | parse_options_usage(top_usage, options, "s", 1); |
1241 | if (field_order) | 1249 | if (field_order) |
@@ -1277,12 +1285,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1277 | goto out_delete_evlist; | 1285 | goto out_delete_evlist; |
1278 | } | 1286 | } |
1279 | 1287 | ||
1280 | if (!top.evlist->nr_entries && | ||
1281 | perf_evlist__add_default(top.evlist) < 0) { | ||
1282 | ui__error("Not enough memory for event selector list\n"); | ||
1283 | goto out_delete_evlist; | ||
1284 | } | ||
1285 | |||
1286 | symbol_conf.nr_events = top.evlist->nr_entries; | 1288 | symbol_conf.nr_events = top.evlist->nr_entries; |
1287 | 1289 | ||
1288 | if (top.delay_secs < 1) | 1290 | if (top.delay_secs < 1) |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index acc3ea7d90b7..ab5cbaa170d0 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
@@ -26,4 +26,4 @@ perf-stat mainporcelain common | |||
26 | perf-test mainporcelain common | 26 | perf-test mainporcelain common |
27 | perf-timechart mainporcelain common | 27 | perf-timechart mainporcelain common |
28 | perf-top mainporcelain common | 28 | perf-top mainporcelain common |
29 | perf-trace mainporcelain common | 29 | perf-trace mainporcelain audit |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index a5524179d26e..254d06e39bea 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -691,6 +691,7 @@ sharedir = $(prefix)/share | |||
691 | template_dir = share/perf-core/templates | 691 | template_dir = share/perf-core/templates |
692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups | 692 | STRACE_GROUPS_DIR = share/perf-core/strace/groups |
693 | htmldir = share/doc/perf-doc | 693 | htmldir = share/doc/perf-doc |
694 | tipdir = share/doc/perf-tip | ||
694 | ifeq ($(prefix),/usr) | 695 | ifeq ($(prefix),/usr) |
695 | sysconfdir = /etc | 696 | sysconfdir = /etc |
696 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig | 697 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig |
@@ -717,6 +718,7 @@ infodir_SQ = $(subst ','\'',$(infodir)) | |||
717 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) | 718 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) |
718 | template_dir_SQ = $(subst ','\'',$(template_dir)) | 719 | template_dir_SQ = $(subst ','\'',$(template_dir)) |
719 | htmldir_SQ = $(subst ','\'',$(htmldir)) | 720 | htmldir_SQ = $(subst ','\'',$(htmldir)) |
721 | tipdir_SQ = $(subst ','\'',$(tipdir)) | ||
720 | prefix_SQ = $(subst ','\'',$(prefix)) | 722 | prefix_SQ = $(subst ','\'',$(prefix)) |
721 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | 723 | sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) |
722 | libdir_SQ = $(subst ','\'',$(libdir)) | 724 | libdir_SQ = $(subst ','\'',$(libdir)) |
@@ -724,12 +726,15 @@ libdir_SQ = $(subst ','\'',$(libdir)) | |||
724 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) | 726 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) |
725 | perfexec_instdir = $(perfexecdir) | 727 | perfexec_instdir = $(perfexecdir) |
726 | STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR) | 728 | STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR) |
729 | tip_instdir = $(tipdir) | ||
727 | else | 730 | else |
728 | perfexec_instdir = $(prefix)/$(perfexecdir) | 731 | perfexec_instdir = $(prefix)/$(perfexecdir) |
729 | STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR) | 732 | STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR) |
733 | tip_instdir = $(prefix)/$(tipdir) | ||
730 | endif | 734 | endif |
731 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 735 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
732 | STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR)) | 736 | STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR)) |
737 | tip_instdir_SQ = $(subst ','\'',$(tip_instdir)) | ||
733 | 738 | ||
734 | # If we install to $(HOME) we keep the traceevent default: | 739 | # If we install to $(HOME) we keep the traceevent default: |
735 | # $(HOME)/.traceevent/plugins | 740 | # $(HOME)/.traceevent/plugins |
@@ -751,6 +756,10 @@ ifeq ($(VF),1) | |||
751 | $(call print_var,sysconfdir) | 756 | $(call print_var,sysconfdir) |
752 | $(call print_var,LIBUNWIND_DIR) | 757 | $(call print_var,LIBUNWIND_DIR) |
753 | $(call print_var,LIBDW_DIR) | 758 | $(call print_var,LIBDW_DIR) |
759 | |||
760 | ifeq ($(dwarf-post-unwind),1) | ||
761 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) | ||
762 | endif | ||
754 | $(info ) | 763 | $(info ) |
755 | endif | 764 | endif |
756 | 765 | ||
@@ -766,6 +775,7 @@ $(call detected_var,ETC_PERFCONFIG_SQ) | |||
766 | $(call detected_var,STRACE_GROUPS_DIR_SQ) | 775 | $(call detected_var,STRACE_GROUPS_DIR_SQ) |
767 | $(call detected_var,prefix_SQ) | 776 | $(call detected_var,prefix_SQ) |
768 | $(call detected_var,perfexecdir_SQ) | 777 | $(call detected_var,perfexecdir_SQ) |
778 | $(call detected_var,tipdir_SQ) | ||
769 | $(call detected_var,LIBDIR) | 779 | $(call detected_var,LIBDIR) |
770 | $(call detected_var,GTK_CFLAGS) | 780 | $(call detected_var,GTK_CFLAGS) |
771 | $(call detected_var,PERL_EMBED_CCOPTS) | 781 | $(call detected_var,PERL_EMBED_CCOPTS) |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index cb1d2499c45c..a929618b8eb6 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include "util/debug.h" | 19 | #include "util/debug.h" |
20 | #include <api/fs/tracing_path.h> | 20 | #include <api/fs/tracing_path.h> |
21 | #include <pthread.h> | 21 | #include <pthread.h> |
22 | #include <stdlib.h> | ||
23 | #include <time.h> | ||
22 | 24 | ||
23 | const char perf_usage_string[] = | 25 | const char perf_usage_string[] = |
24 | "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; | 26 | "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; |
@@ -542,6 +544,8 @@ int main(int argc, const char **argv) | |||
542 | if (!cmd) | 544 | if (!cmd) |
543 | cmd = "perf-help"; | 545 | cmd = "perf-help"; |
544 | 546 | ||
547 | srandom(time(NULL)); | ||
548 | |||
545 | /* get debugfs/tracefs mount point from /proc/mounts */ | 549 | /* get debugfs/tracefs mount point from /proc/mounts */ |
546 | tracing_path_mount(); | 550 | tracing_path_mount(); |
547 | 551 | ||
diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py new file mode 100644 index 000000000000..8b60f343dd07 --- /dev/null +++ b/tools/perf/scripts/python/stat-cpi.py | |||
@@ -0,0 +1,77 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | data = {} | ||
4 | times = [] | ||
5 | threads = [] | ||
6 | cpus = [] | ||
7 | |||
8 | def get_key(time, event, cpu, thread): | ||
9 | return "%d-%s-%d-%d" % (time, event, cpu, thread) | ||
10 | |||
11 | def store_key(time, cpu, thread): | ||
12 | if (time not in times): | ||
13 | times.append(time) | ||
14 | |||
15 | if (cpu not in cpus): | ||
16 | cpus.append(cpu) | ||
17 | |||
18 | if (thread not in threads): | ||
19 | threads.append(thread) | ||
20 | |||
21 | def store(time, event, cpu, thread, val, ena, run): | ||
22 | #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \ | ||
23 | # (event, cpu, thread, time, val, ena, run) | ||
24 | |||
25 | store_key(time, cpu, thread) | ||
26 | key = get_key(time, event, cpu, thread) | ||
27 | data[key] = [ val, ena, run] | ||
28 | |||
29 | def get(time, event, cpu, thread): | ||
30 | key = get_key(time, event, cpu, thread) | ||
31 | return data[key][0] | ||
32 | |||
33 | def stat__cycles_k(cpu, thread, time, val, ena, run): | ||
34 | store(time, "cycles", cpu, thread, val, ena, run); | ||
35 | |||
36 | def stat__instructions_k(cpu, thread, time, val, ena, run): | ||
37 | store(time, "instructions", cpu, thread, val, ena, run); | ||
38 | |||
39 | def stat__cycles_u(cpu, thread, time, val, ena, run): | ||
40 | store(time, "cycles", cpu, thread, val, ena, run); | ||
41 | |||
42 | def stat__instructions_u(cpu, thread, time, val, ena, run): | ||
43 | store(time, "instructions", cpu, thread, val, ena, run); | ||
44 | |||
45 | def stat__cycles(cpu, thread, time, val, ena, run): | ||
46 | store(time, "cycles", cpu, thread, val, ena, run); | ||
47 | |||
48 | def stat__instructions(cpu, thread, time, val, ena, run): | ||
49 | store(time, "instructions", cpu, thread, val, ena, run); | ||
50 | |||
51 | def stat__interval(time): | ||
52 | for cpu in cpus: | ||
53 | for thread in threads: | ||
54 | cyc = get(time, "cycles", cpu, thread) | ||
55 | ins = get(time, "instructions", cpu, thread) | ||
56 | cpi = 0 | ||
57 | |||
58 | if ins != 0: | ||
59 | cpi = cyc/float(ins) | ||
60 | |||
61 | print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins) | ||
62 | |||
63 | def trace_end(): | ||
64 | pass | ||
65 | # XXX trace_end callback could be used as an alternative place | ||
66 | # to compute same values as in the script above: | ||
67 | # | ||
68 | # for time in times: | ||
69 | # for cpu in cpus: | ||
70 | # for thread in threads: | ||
71 | # cyc = get(time, "cycles", cpu, thread) | ||
72 | # ins = get(time, "instructions", cpu, thread) | ||
73 | # | ||
74 | # if ins != 0: | ||
75 | # cpi = cyc/float(ins) | ||
76 | # | ||
77 | # print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi) | ||
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 8292948bc5f9..e36089212061 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
@@ -281,7 +281,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) | |||
281 | symbol_conf.cumulate_callchain = false; | 281 | symbol_conf.cumulate_callchain = false; |
282 | perf_evsel__reset_sample_bit(evsel, CALLCHAIN); | 282 | perf_evsel__reset_sample_bit(evsel, CALLCHAIN); |
283 | 283 | ||
284 | setup_sorting(); | 284 | setup_sorting(NULL); |
285 | callchain_register_param(&callchain_param); | 285 | callchain_register_param(&callchain_param); |
286 | 286 | ||
287 | err = add_hist_entries(hists, machine); | 287 | err = add_hist_entries(hists, machine); |
@@ -428,7 +428,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) | |||
428 | symbol_conf.cumulate_callchain = false; | 428 | symbol_conf.cumulate_callchain = false; |
429 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); | 429 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); |
430 | 430 | ||
431 | setup_sorting(); | 431 | setup_sorting(NULL); |
432 | callchain_register_param(&callchain_param); | 432 | callchain_register_param(&callchain_param); |
433 | 433 | ||
434 | err = add_hist_entries(hists, machine); | 434 | err = add_hist_entries(hists, machine); |
@@ -486,7 +486,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) | |||
486 | symbol_conf.cumulate_callchain = true; | 486 | symbol_conf.cumulate_callchain = true; |
487 | perf_evsel__reset_sample_bit(evsel, CALLCHAIN); | 487 | perf_evsel__reset_sample_bit(evsel, CALLCHAIN); |
488 | 488 | ||
489 | setup_sorting(); | 489 | setup_sorting(NULL); |
490 | callchain_register_param(&callchain_param); | 490 | callchain_register_param(&callchain_param); |
491 | 491 | ||
492 | err = add_hist_entries(hists, machine); | 492 | err = add_hist_entries(hists, machine); |
@@ -670,7 +670,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
670 | symbol_conf.cumulate_callchain = true; | 670 | symbol_conf.cumulate_callchain = true; |
671 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); | 671 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); |
672 | 672 | ||
673 | setup_sorting(); | 673 | setup_sorting(NULL); |
674 | callchain_register_param(&callchain_param); | 674 | callchain_register_param(&callchain_param); |
675 | 675 | ||
676 | err = add_hist_entries(hists, machine); | 676 | err = add_hist_entries(hists, machine); |
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index ccb5b4921f25..2a784befd9ce 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -122,7 +122,7 @@ int test__hists_filter(int subtest __maybe_unused) | |||
122 | goto out; | 122 | goto out; |
123 | 123 | ||
124 | /* default sort order (comm,dso,sym) will be used */ | 124 | /* default sort order (comm,dso,sym) will be used */ |
125 | if (setup_sorting() < 0) | 125 | if (setup_sorting(NULL) < 0) |
126 | goto out; | 126 | goto out; |
127 | 127 | ||
128 | machines__init(&machines); | 128 | machines__init(&machines); |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 6243e2b2a245..c764d69ac6ef 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | |||
64 | struct perf_evsel *evsel; | 64 | struct perf_evsel *evsel; |
65 | struct addr_location al; | 65 | struct addr_location al; |
66 | struct hist_entry *he; | 66 | struct hist_entry *he; |
67 | struct perf_sample sample = { .period = 1, }; | 67 | struct perf_sample sample = { .period = 1, .weight = 1, }; |
68 | size_t i = 0, k; | 68 | size_t i = 0, k; |
69 | 69 | ||
70 | /* | 70 | /* |
@@ -90,7 +90,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | |||
90 | goto out; | 90 | goto out; |
91 | 91 | ||
92 | he = __hists__add_entry(hists, &al, NULL, | 92 | he = __hists__add_entry(hists, &al, NULL, |
93 | NULL, NULL, 1, 1, 0, true); | 93 | NULL, NULL, &sample, true); |
94 | if (he == NULL) { | 94 | if (he == NULL) { |
95 | addr_location__put(&al); | 95 | addr_location__put(&al); |
96 | goto out; | 96 | goto out; |
@@ -116,7 +116,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | |||
116 | goto out; | 116 | goto out; |
117 | 117 | ||
118 | he = __hists__add_entry(hists, &al, NULL, | 118 | he = __hists__add_entry(hists, &al, NULL, |
119 | NULL, NULL, 1, 1, 0, true); | 119 | NULL, NULL, &sample, true); |
120 | if (he == NULL) { | 120 | if (he == NULL) { |
121 | addr_location__put(&al); | 121 | addr_location__put(&al); |
122 | goto out; | 122 | goto out; |
@@ -294,7 +294,7 @@ int test__hists_link(int subtest __maybe_unused) | |||
294 | goto out; | 294 | goto out; |
295 | 295 | ||
296 | /* default sort order (comm,dso,sym) will be used */ | 296 | /* default sort order (comm,dso,sym) will be used */ |
297 | if (setup_sorting() < 0) | 297 | if (setup_sorting(NULL) < 0) |
298 | goto out; | 298 | goto out; |
299 | 299 | ||
300 | machines__init(&machines); | 300 | machines__init(&machines); |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 248beec1d917..ebe6cd485b5d 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -134,7 +134,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) | |||
134 | field_order = NULL; | 134 | field_order = NULL; |
135 | sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */ | 135 | sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */ |
136 | 136 | ||
137 | setup_sorting(); | 137 | setup_sorting(NULL); |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * expected output: | 140 | * expected output: |
@@ -236,7 +236,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) | |||
236 | field_order = "overhead,cpu"; | 236 | field_order = "overhead,cpu"; |
237 | sort_order = "pid"; | 237 | sort_order = "pid"; |
238 | 238 | ||
239 | setup_sorting(); | 239 | setup_sorting(NULL); |
240 | 240 | ||
241 | /* | 241 | /* |
242 | * expected output: | 242 | * expected output: |
@@ -292,7 +292,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) | |||
292 | field_order = "comm,overhead,dso"; | 292 | field_order = "comm,overhead,dso"; |
293 | sort_order = NULL; | 293 | sort_order = NULL; |
294 | 294 | ||
295 | setup_sorting(); | 295 | setup_sorting(NULL); |
296 | 296 | ||
297 | /* | 297 | /* |
298 | * expected output: | 298 | * expected output: |
@@ -366,7 +366,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
366 | field_order = "dso,sym,comm,overhead,dso"; | 366 | field_order = "dso,sym,comm,overhead,dso"; |
367 | sort_order = "sym"; | 367 | sort_order = "sym"; |
368 | 368 | ||
369 | setup_sorting(); | 369 | setup_sorting(NULL); |
370 | 370 | ||
371 | /* | 371 | /* |
372 | * expected output: | 372 | * expected output: |
@@ -468,7 +468,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine) | |||
468 | field_order = "cpu,pid,comm,dso,sym"; | 468 | field_order = "cpu,pid,comm,dso,sym"; |
469 | sort_order = "dso,pid"; | 469 | sort_order = "dso,pid"; |
470 | 470 | ||
471 | setup_sorting(); | 471 | setup_sorting(NULL); |
472 | 472 | ||
473 | /* | 473 | /* |
474 | * expected output: | 474 | * expected output: |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index a337a6da1f39..ddb78fae064a 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
@@ -55,7 +55,6 @@ int test__keep_tracking(int subtest __maybe_unused) | |||
55 | .mmap_pages = UINT_MAX, | 55 | .mmap_pages = UINT_MAX, |
56 | .user_freq = UINT_MAX, | 56 | .user_freq = UINT_MAX, |
57 | .user_interval = ULLONG_MAX, | 57 | .user_interval = ULLONG_MAX, |
58 | .freq = 4000, | ||
59 | .target = { | 58 | .target = { |
60 | .uses_mmap = true, | 59 | .uses_mmap = true, |
61 | }, | 60 | }, |
@@ -124,7 +123,7 @@ int test__keep_tracking(int subtest __maybe_unused) | |||
124 | 123 | ||
125 | evsel = perf_evlist__last(evlist); | 124 | evsel = perf_evlist__last(evlist); |
126 | 125 | ||
127 | CHECK__(perf_evlist__disable_event(evlist, evsel)); | 126 | CHECK__(perf_evsel__disable(evsel)); |
128 | 127 | ||
129 | comm = "Test COMM 2"; | 128 | comm = "Test COMM 2"; |
130 | CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); | 129 | CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 9d5f0b57c4c1..1cc78cefe399 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -40,12 +40,11 @@ int test__PERF_RECORD(int subtest __maybe_unused) | |||
40 | .uses_mmap = true, | 40 | .uses_mmap = true, |
41 | }, | 41 | }, |
42 | .no_buffering = true, | 42 | .no_buffering = true, |
43 | .freq = 10, | ||
44 | .mmap_pages = 256, | 43 | .mmap_pages = 256, |
45 | }; | 44 | }; |
46 | cpu_set_t cpu_mask; | 45 | cpu_set_t cpu_mask; |
47 | size_t cpu_mask_size = sizeof(cpu_mask); | 46 | size_t cpu_mask_size = sizeof(cpu_mask); |
48 | struct perf_evlist *evlist = perf_evlist__new_default(); | 47 | struct perf_evlist *evlist = perf_evlist__new_dummy(); |
49 | struct perf_evsel *evsel; | 48 | struct perf_evsel *evsel; |
50 | struct perf_sample sample; | 49 | struct perf_sample sample; |
51 | const char *cmd = "sleep"; | 50 | const char *cmd = "sleep"; |
@@ -61,6 +60,9 @@ int test__PERF_RECORD(int subtest __maybe_unused) | |||
61 | int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; | 60 | int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; |
62 | char sbuf[STRERR_BUFSIZE]; | 61 | char sbuf[STRERR_BUFSIZE]; |
63 | 62 | ||
63 | if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */ | ||
64 | evlist = perf_evlist__new_default(); | ||
65 | |||
64 | if (evlist == NULL || argv == NULL) { | 66 | if (evlist == NULL || argv == NULL) { |
65 | pr_debug("Not enough memory to create evlist\n"); | 67 | pr_debug("Not enough memory to create evlist\n"); |
66 | goto out; | 68 | goto out; |
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index dfbd8d69ce89..ebd80168d51e 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c | |||
@@ -455,7 +455,7 @@ int test__switch_tracking(int subtest __maybe_unused) | |||
455 | 455 | ||
456 | perf_evlist__enable(evlist); | 456 | perf_evlist__enable(evlist); |
457 | 457 | ||
458 | err = perf_evlist__disable_event(evlist, cpu_clocks_evsel); | 458 | err = perf_evsel__disable(cpu_clocks_evsel); |
459 | if (err) { | 459 | if (err) { |
460 | pr_debug("perf_evlist__disable_event failed!\n"); | 460 | pr_debug("perf_evlist__disable_event failed!\n"); |
461 | goto out_err; | 461 | goto out_err; |
@@ -474,7 +474,7 @@ int test__switch_tracking(int subtest __maybe_unused) | |||
474 | goto out_err; | 474 | goto out_err; |
475 | } | 475 | } |
476 | 476 | ||
477 | err = perf_evlist__disable_event(evlist, cycles_evsel); | 477 | err = perf_evsel__disable(cycles_evsel); |
478 | if (err) { | 478 | if (err) { |
479 | pr_debug("perf_evlist__disable_event failed!\n"); | 479 | pr_debug("perf_evlist__disable_event failed!\n"); |
480 | goto out_err; | 480 | goto out_err; |
@@ -500,7 +500,7 @@ int test__switch_tracking(int subtest __maybe_unused) | |||
500 | goto out_err; | 500 | goto out_err; |
501 | } | 501 | } |
502 | 502 | ||
503 | err = perf_evlist__enable_event(evlist, cycles_evsel); | 503 | err = perf_evsel__enable(cycles_evsel); |
504 | if (err) { | 504 | if (err) { |
505 | pr_debug("perf_evlist__disable_event failed!\n"); | 505 | pr_debug("perf_evlist__disable_event failed!\n"); |
506 | goto out_err; | 506 | goto out_err; |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ec331969b7d7..901d481e6cea 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1041,7 +1041,8 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
1041 | hist_browser__gotorc(browser, row, 0); | 1041 | hist_browser__gotorc(browser, row, 0); |
1042 | 1042 | ||
1043 | perf_hpp__for_each_format(fmt) { | 1043 | perf_hpp__for_each_format(fmt) { |
1044 | if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) | 1044 | if (perf_hpp__should_skip(fmt, entry->hists) || |
1045 | column++ < browser->b.horiz_scroll) | ||
1045 | continue; | 1046 | continue; |
1046 | 1047 | ||
1047 | if (current_entry && browser->b.navkeypressed) { | 1048 | if (current_entry && browser->b.navkeypressed) { |
@@ -1144,7 +1145,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char * | |||
1144 | } | 1145 | } |
1145 | 1146 | ||
1146 | perf_hpp__for_each_format(fmt) { | 1147 | perf_hpp__for_each_format(fmt) { |
1147 | if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) | 1148 | if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) |
1148 | continue; | 1149 | continue; |
1149 | 1150 | ||
1150 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1151 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); |
@@ -1414,7 +1415,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
1414 | printed += fprintf(fp, "%c ", folded_sign); | 1415 | printed += fprintf(fp, "%c ", folded_sign); |
1415 | 1416 | ||
1416 | perf_hpp__for_each_format(fmt) { | 1417 | perf_hpp__for_each_format(fmt) { |
1417 | if (perf_hpp__should_skip(fmt)) | 1418 | if (perf_hpp__should_skip(fmt, he->hists)) |
1418 | continue; | 1419 | continue; |
1419 | 1420 | ||
1420 | if (!first) { | 1421 | if (!first) { |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 467717276ab6..0f8dcfdfb10f 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -318,7 +318,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
318 | col_idx = 0; | 318 | col_idx = 0; |
319 | 319 | ||
320 | perf_hpp__for_each_format(fmt) { | 320 | perf_hpp__for_each_format(fmt) { |
321 | if (perf_hpp__should_skip(fmt)) | 321 | if (perf_hpp__should_skip(fmt, hists)) |
322 | continue; | 322 | continue; |
323 | 323 | ||
324 | /* | 324 | /* |
@@ -368,7 +368,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
368 | col_idx = 0; | 368 | col_idx = 0; |
369 | 369 | ||
370 | perf_hpp__for_each_format(fmt) { | 370 | perf_hpp__for_each_format(fmt) { |
371 | if (perf_hpp__should_skip(fmt)) | 371 | if (perf_hpp__should_skip(fmt, h->hists)) |
372 | continue; | 372 | continue; |
373 | 373 | ||
374 | if (fmt->color) | 374 | if (fmt->color) |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 5029ba2b55af..bf2a66e254ea 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -443,7 +443,6 @@ LIST_HEAD(perf_hpp__sort_list); | |||
443 | 443 | ||
444 | void perf_hpp__init(void) | 444 | void perf_hpp__init(void) |
445 | { | 445 | { |
446 | struct list_head *list; | ||
447 | int i; | 446 | int i; |
448 | 447 | ||
449 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 448 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { |
@@ -484,17 +483,6 @@ void perf_hpp__init(void) | |||
484 | 483 | ||
485 | if (symbol_conf.show_total_period) | 484 | if (symbol_conf.show_total_period) |
486 | hpp_dimension__add_output(PERF_HPP__PERIOD); | 485 | hpp_dimension__add_output(PERF_HPP__PERIOD); |
487 | |||
488 | /* prepend overhead field for backward compatiblity. */ | ||
489 | list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; | ||
490 | if (list_empty(list)) | ||
491 | list_add(list, &perf_hpp__sort_list); | ||
492 | |||
493 | if (symbol_conf.cumulate_callchain) { | ||
494 | list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list; | ||
495 | if (list_empty(list)) | ||
496 | list_add(list, &perf_hpp__sort_list); | ||
497 | } | ||
498 | } | 486 | } |
499 | 487 | ||
500 | void perf_hpp__column_register(struct perf_hpp_fmt *format) | 488 | void perf_hpp__column_register(struct perf_hpp_fmt *format) |
@@ -619,7 +607,7 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
619 | struct perf_hpp dummy_hpp; | 607 | struct perf_hpp dummy_hpp; |
620 | 608 | ||
621 | perf_hpp__for_each_format(fmt) { | 609 | perf_hpp__for_each_format(fmt) { |
622 | if (perf_hpp__should_skip(fmt)) | 610 | if (perf_hpp__should_skip(fmt, hists)) |
623 | continue; | 611 | continue; |
624 | 612 | ||
625 | if (first) | 613 | if (first) |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 7ebc661be267..387110d50b00 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -385,7 +385,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) | |||
385 | return 0; | 385 | return 0; |
386 | 386 | ||
387 | perf_hpp__for_each_format(fmt) { | 387 | perf_hpp__for_each_format(fmt) { |
388 | if (perf_hpp__should_skip(fmt)) | 388 | if (perf_hpp__should_skip(fmt, he->hists)) |
389 | continue; | 389 | continue; |
390 | 390 | ||
391 | /* | 391 | /* |
@@ -464,7 +464,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
464 | fprintf(fp, "# "); | 464 | fprintf(fp, "# "); |
465 | 465 | ||
466 | perf_hpp__for_each_format(fmt) { | 466 | perf_hpp__for_each_format(fmt) { |
467 | if (perf_hpp__should_skip(fmt)) | 467 | if (perf_hpp__should_skip(fmt, hists)) |
468 | continue; | 468 | continue; |
469 | 469 | ||
470 | if (!first) | 470 | if (!first) |
@@ -490,7 +490,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
490 | perf_hpp__for_each_format(fmt) { | 490 | perf_hpp__for_each_format(fmt) { |
491 | unsigned int i; | 491 | unsigned int i; |
492 | 492 | ||
493 | if (perf_hpp__should_skip(fmt)) | 493 | if (perf_hpp__should_skip(fmt, hists)) |
494 | continue; | 494 | continue; |
495 | 495 | ||
496 | if (!first) | 496 | if (!first) |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 94b1099f2c22..5eec53a3f4ac 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -9,7 +9,7 @@ libperf-y += env.o | |||
9 | libperf-y += event.o | 9 | libperf-y += event.o |
10 | libperf-y += evlist.o | 10 | libperf-y += evlist.o |
11 | libperf-y += evsel.o | 11 | libperf-y += evsel.o |
12 | libperf-y += find_next_bit.o | 12 | libperf-y += find_bit.o |
13 | libperf-y += kallsyms.o | 13 | libperf-y += kallsyms.o |
14 | libperf-y += levenshtein.o | 14 | libperf-y += levenshtein.o |
15 | libperf-y += llvm-utils.o | 15 | libperf-y += llvm-utils.o |
@@ -132,7 +132,8 @@ CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w | |||
132 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c | 132 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c |
133 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | 133 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c |
134 | 134 | ||
135 | CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 135 | CFLAGS_bitmap.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
136 | CFLAGS_find_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | ||
136 | CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 137 | CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
137 | CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 138 | CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
138 | CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 139 | CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
@@ -142,7 +143,11 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE | |||
142 | $(call rule_mkdir) | 143 | $(call rule_mkdir) |
143 | $(call if_changed_dep,cc_o_c) | 144 | $(call if_changed_dep,cc_o_c) |
144 | 145 | ||
145 | $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE | 146 | $(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE |
147 | $(call rule_mkdir) | ||
148 | $(call if_changed_dep,cc_o_c) | ||
149 | |||
150 | $(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE | ||
146 | $(call rule_mkdir) | 151 | $(call rule_mkdir) |
147 | $(call if_changed_dep,cc_o_c) | 152 | $(call if_changed_dep,cc_o_c) |
148 | 153 | ||
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 564377d2bebf..53c43eb9489e 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -925,6 +925,34 @@ void free_callchain(struct callchain_root *root) | |||
925 | free_callchain_node(&root->node); | 925 | free_callchain_node(&root->node); |
926 | } | 926 | } |
927 | 927 | ||
928 | static u64 decay_callchain_node(struct callchain_node *node) | ||
929 | { | ||
930 | struct callchain_node *child; | ||
931 | struct rb_node *n; | ||
932 | u64 child_hits = 0; | ||
933 | |||
934 | n = rb_first(&node->rb_root_in); | ||
935 | while (n) { | ||
936 | child = container_of(n, struct callchain_node, rb_node_in); | ||
937 | |||
938 | child_hits += decay_callchain_node(child); | ||
939 | n = rb_next(n); | ||
940 | } | ||
941 | |||
942 | node->hit = (node->hit * 7) / 8; | ||
943 | node->children_hit = child_hits; | ||
944 | |||
945 | return node->hit; | ||
946 | } | ||
947 | |||
948 | void decay_callchain(struct callchain_root *root) | ||
949 | { | ||
950 | if (!symbol_conf.use_callchain) | ||
951 | return; | ||
952 | |||
953 | decay_callchain_node(&root->node); | ||
954 | } | ||
955 | |||
928 | int callchain_node__make_parent_list(struct callchain_node *node) | 956 | int callchain_node__make_parent_list(struct callchain_node *node) |
929 | { | 957 | { |
930 | struct callchain_node *parent = node->parent; | 958 | struct callchain_node *parent = node->parent; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 8ac8f043004c..18dd22269764 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -253,6 +253,7 @@ int callchain_node__fprintf_value(struct callchain_node *node, | |||
253 | FILE *fp, u64 total); | 253 | FILE *fp, u64 total); |
254 | 254 | ||
255 | void free_callchain(struct callchain_root *root); | 255 | void free_callchain(struct callchain_root *root); |
256 | void decay_callchain(struct callchain_root *root); | ||
256 | int callchain_node__make_parent_list(struct callchain_node *node); | 257 | int callchain_node__make_parent_list(struct callchain_node *node); |
257 | 258 | ||
258 | #endif /* __PERF_CALLCHAIN_H */ | 259 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index a0717b93d8f5..fa935093a599 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -188,8 +188,17 @@ static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) | |||
188 | if (map) { | 188 | if (map) { |
189 | unsigned i; | 189 | unsigned i; |
190 | 190 | ||
191 | for (i = 0; i < cpus->nr; i++) | 191 | for (i = 0; i < cpus->nr; i++) { |
192 | map->map[i] = (int)cpus->cpu[i]; | 192 | /* |
193 | * Special treatment for -1, which is not real cpu number, | ||
194 | * and we need to use (int) -1 to initialize map[i], | ||
195 | * otherwise it would become 65535. | ||
196 | */ | ||
197 | if (cpus->cpu[i] == (u16) -1) | ||
198 | map->map[i] = -1; | ||
199 | else | ||
200 | map->map[i] = (int) cpus->cpu[i]; | ||
201 | } | ||
193 | } | 202 | } |
194 | 203 | ||
195 | return map; | 204 | return map; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b9eac0daa0b9..d81f13de2476 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -68,6 +68,18 @@ struct perf_evlist *perf_evlist__new_default(void) | |||
68 | return evlist; | 68 | return evlist; |
69 | } | 69 | } |
70 | 70 | ||
71 | struct perf_evlist *perf_evlist__new_dummy(void) | ||
72 | { | ||
73 | struct perf_evlist *evlist = perf_evlist__new(); | ||
74 | |||
75 | if (evlist && perf_evlist__add_dummy(evlist)) { | ||
76 | perf_evlist__delete(evlist); | ||
77 | evlist = NULL; | ||
78 | } | ||
79 | |||
80 | return evlist; | ||
81 | } | ||
82 | |||
71 | /** | 83 | /** |
72 | * perf_evlist__set_id_pos - set the positions of event ids. | 84 | * perf_evlist__set_id_pos - set the positions of event ids. |
73 | * @evlist: selected event list | 85 | * @evlist: selected event list |
@@ -248,6 +260,22 @@ error: | |||
248 | return -ENOMEM; | 260 | return -ENOMEM; |
249 | } | 261 | } |
250 | 262 | ||
263 | int perf_evlist__add_dummy(struct perf_evlist *evlist) | ||
264 | { | ||
265 | struct perf_event_attr attr = { | ||
266 | .type = PERF_TYPE_SOFTWARE, | ||
267 | .config = PERF_COUNT_SW_DUMMY, | ||
268 | .size = sizeof(attr), /* to capture ABI version */ | ||
269 | }; | ||
270 | struct perf_evsel *evsel = perf_evsel__new(&attr); | ||
271 | |||
272 | if (evsel == NULL) | ||
273 | return -ENOMEM; | ||
274 | |||
275 | perf_evlist__add(evlist, evsel); | ||
276 | return 0; | ||
277 | } | ||
278 | |||
251 | static int perf_evlist__add_attrs(struct perf_evlist *evlist, | 279 | static int perf_evlist__add_attrs(struct perf_evlist *evlist, |
252 | struct perf_event_attr *attrs, size_t nr_attrs) | 280 | struct perf_event_attr *attrs, size_t nr_attrs) |
253 | { | 281 | { |
@@ -365,48 +393,6 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist) | |||
365 | (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); | 393 | (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); |
366 | } | 394 | } |
367 | 395 | ||
368 | int perf_evlist__disable_event(struct perf_evlist *evlist, | ||
369 | struct perf_evsel *evsel) | ||
370 | { | ||
371 | int cpu, thread, err; | ||
372 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
373 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
374 | |||
375 | if (!evsel->fd) | ||
376 | return 0; | ||
377 | |||
378 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
379 | for (thread = 0; thread < nr_threads; thread++) { | ||
380 | err = ioctl(FD(evsel, cpu, thread), | ||
381 | PERF_EVENT_IOC_DISABLE, 0); | ||
382 | if (err) | ||
383 | return err; | ||
384 | } | ||
385 | } | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | int perf_evlist__enable_event(struct perf_evlist *evlist, | ||
390 | struct perf_evsel *evsel) | ||
391 | { | ||
392 | int cpu, thread, err; | ||
393 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
394 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
395 | |||
396 | if (!evsel->fd) | ||
397 | return -EINVAL; | ||
398 | |||
399 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
400 | for (thread = 0; thread < nr_threads; thread++) { | ||
401 | err = ioctl(FD(evsel, cpu, thread), | ||
402 | PERF_EVENT_IOC_ENABLE, 0); | ||
403 | if (err) | ||
404 | return err; | ||
405 | } | ||
406 | } | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, | 396 | static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, |
411 | struct perf_evsel *evsel, int cpu) | 397 | struct perf_evsel *evsel, int cpu) |
412 | { | 398 | { |
@@ -1470,7 +1456,7 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
1470 | perf_evlist__update_id_pos(evlist); | 1456 | perf_evlist__update_id_pos(evlist); |
1471 | 1457 | ||
1472 | evlist__for_each(evlist, evsel) { | 1458 | evlist__for_each(evlist, evsel) { |
1473 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 1459 | err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); |
1474 | if (err < 0) | 1460 | if (err < 0) |
1475 | goto out_err; | 1461 | goto out_err; |
1476 | } | 1462 | } |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 139a50038097..7c4d9a206776 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -67,6 +67,7 @@ struct perf_evsel_str_handler { | |||
67 | 67 | ||
68 | struct perf_evlist *perf_evlist__new(void); | 68 | struct perf_evlist *perf_evlist__new(void); |
69 | struct perf_evlist *perf_evlist__new_default(void); | 69 | struct perf_evlist *perf_evlist__new_default(void); |
70 | struct perf_evlist *perf_evlist__new_dummy(void); | ||
70 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | 71 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, |
71 | struct thread_map *threads); | 72 | struct thread_map *threads); |
72 | void perf_evlist__exit(struct perf_evlist *evlist); | 73 | void perf_evlist__exit(struct perf_evlist *evlist); |
@@ -81,6 +82,8 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | |||
81 | #define perf_evlist__add_default_attrs(evlist, array) \ | 82 | #define perf_evlist__add_default_attrs(evlist, array) \ |
82 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) | 83 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) |
83 | 84 | ||
85 | int perf_evlist__add_dummy(struct perf_evlist *evlist); | ||
86 | |||
84 | int perf_evlist__add_newtp(struct perf_evlist *evlist, | 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
85 | const char *sys, const char *name, void *handler); | 88 | const char *sys, const char *name, void *handler); |
86 | 89 | ||
@@ -152,10 +155,6 @@ void perf_evlist__disable(struct perf_evlist *evlist); | |||
152 | void perf_evlist__enable(struct perf_evlist *evlist); | 155 | void perf_evlist__enable(struct perf_evlist *evlist); |
153 | void perf_evlist__toggle_enable(struct perf_evlist *evlist); | 156 | void perf_evlist__toggle_enable(struct perf_evlist *evlist); |
154 | 157 | ||
155 | int perf_evlist__disable_event(struct perf_evlist *evlist, | ||
156 | struct perf_evsel *evsel); | ||
157 | int perf_evlist__enable_event(struct perf_evlist *evlist, | ||
158 | struct perf_evsel *evsel); | ||
159 | int perf_evlist__enable_event_idx(struct perf_evlist *evlist, | 158 | int perf_evlist__enable_event_idx(struct perf_evlist *evlist, |
160 | struct perf_evsel *evsel, int idx); | 159 | struct perf_evsel *evsel, int idx); |
161 | 160 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 544e4400de13..cdbaf9b51e42 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -2298,6 +2298,29 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
2298 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | 2298 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, |
2299 | term, (u64)evsel->attr.sample_freq); | 2299 | term, (u64)evsel->attr.sample_freq); |
2300 | } | 2300 | } |
2301 | |||
2302 | if (details->trace_fields) { | ||
2303 | struct format_field *field; | ||
2304 | |||
2305 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
2306 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | ||
2307 | goto out; | ||
2308 | } | ||
2309 | |||
2310 | field = evsel->tp_format->format.fields; | ||
2311 | if (field == NULL) { | ||
2312 | printed += comma_fprintf(fp, &first, " (no trace field)"); | ||
2313 | goto out; | ||
2314 | } | ||
2315 | |||
2316 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | ||
2317 | |||
2318 | field = field->next; | ||
2319 | while (field) { | ||
2320 | printed += comma_fprintf(fp, &first, "%s", field->name); | ||
2321 | field = field->next; | ||
2322 | } | ||
2323 | } | ||
2301 | out: | 2324 | out: |
2302 | fputc('\n', fp); | 2325 | fputc('\n', fp); |
2303 | return ++printed; | 2326 | return ++printed; |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 5ded1fc0341e..8e75434bd01c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -369,6 +369,7 @@ struct perf_attr_details { | |||
369 | bool verbose; | 369 | bool verbose; |
370 | bool event_group; | 370 | bool event_group; |
371 | bool force; | 371 | bool force; |
372 | bool trace_fields; | ||
372 | }; | 373 | }; |
373 | 374 | ||
374 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 375 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh index 36a885d2cd22..0ac2037c970c 100755 --- a/tools/perf/util/generate-cmdlist.sh +++ b/tools/perf/util/generate-cmdlist.sh | |||
@@ -36,4 +36,19 @@ do | |||
36 | }' "Documentation/perf-$cmd.txt" | 36 | }' "Documentation/perf-$cmd.txt" |
37 | done | 37 | done |
38 | echo "#endif /* HAVE_LIBELF_SUPPORT */" | 38 | echo "#endif /* HAVE_LIBELF_SUPPORT */" |
39 | |||
40 | echo "#ifdef HAVE_LIBAUDIT_SUPPORT" | ||
41 | sed -n -e 's/^perf-\([^ ]*\)[ ].* audit*/\1/p' command-list.txt | | ||
42 | sort | | ||
43 | while read cmd | ||
44 | do | ||
45 | sed -n ' | ||
46 | /^NAME/,/perf-'"$cmd"'/H | ||
47 | ${ | ||
48 | x | ||
49 | s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/ | ||
50 | p | ||
51 | }' "Documentation/perf-$cmd.txt" | ||
52 | done | ||
53 | echo "#endif /* HAVE_LIBELF_SUPPORT */" | ||
39 | echo "};" | 54 | echo "};" |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 56e97f5af598..c226303e3da0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -254,6 +254,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
254 | he_stat__decay(&he->stat); | 254 | he_stat__decay(&he->stat); |
255 | if (symbol_conf.cumulate_callchain) | 255 | if (symbol_conf.cumulate_callchain) |
256 | he_stat__decay(he->stat_acc); | 256 | he_stat__decay(he->stat_acc); |
257 | decay_callchain(he->callchain); | ||
257 | 258 | ||
258 | diff = prev_period - he->stat.period; | 259 | diff = prev_period - he->stat.period; |
259 | 260 | ||
@@ -369,6 +370,25 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
369 | if (symbol_conf.use_callchain) | 370 | if (symbol_conf.use_callchain) |
370 | callchain_init(he->callchain); | 371 | callchain_init(he->callchain); |
371 | 372 | ||
373 | if (he->raw_data) { | ||
374 | he->raw_data = memdup(he->raw_data, he->raw_size); | ||
375 | |||
376 | if (he->raw_data == NULL) { | ||
377 | map__put(he->ms.map); | ||
378 | if (he->branch_info) { | ||
379 | map__put(he->branch_info->from.map); | ||
380 | map__put(he->branch_info->to.map); | ||
381 | free(he->branch_info); | ||
382 | } | ||
383 | if (he->mem_info) { | ||
384 | map__put(he->mem_info->iaddr.map); | ||
385 | map__put(he->mem_info->daddr.map); | ||
386 | } | ||
387 | free(he->stat_acc); | ||
388 | free(he); | ||
389 | return NULL; | ||
390 | } | ||
391 | } | ||
372 | INIT_LIST_HEAD(&he->pairs.node); | 392 | INIT_LIST_HEAD(&he->pairs.node); |
373 | thread__get(he->thread); | 393 | thread__get(he->thread); |
374 | } | 394 | } |
@@ -461,7 +481,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
461 | struct symbol *sym_parent, | 481 | struct symbol *sym_parent, |
462 | struct branch_info *bi, | 482 | struct branch_info *bi, |
463 | struct mem_info *mi, | 483 | struct mem_info *mi, |
464 | u64 period, u64 weight, u64 transaction, | 484 | struct perf_sample *sample, |
465 | bool sample_self) | 485 | bool sample_self) |
466 | { | 486 | { |
467 | struct hist_entry entry = { | 487 | struct hist_entry entry = { |
@@ -478,15 +498,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
478 | .level = al->level, | 498 | .level = al->level, |
479 | .stat = { | 499 | .stat = { |
480 | .nr_events = 1, | 500 | .nr_events = 1, |
481 | .period = period, | 501 | .period = sample->period, |
482 | .weight = weight, | 502 | .weight = sample->weight, |
483 | }, | 503 | }, |
484 | .parent = sym_parent, | 504 | .parent = sym_parent, |
485 | .filtered = symbol__parent_filter(sym_parent) | al->filtered, | 505 | .filtered = symbol__parent_filter(sym_parent) | al->filtered, |
486 | .hists = hists, | 506 | .hists = hists, |
487 | .branch_info = bi, | 507 | .branch_info = bi, |
488 | .mem_info = mi, | 508 | .mem_info = mi, |
489 | .transaction = transaction, | 509 | .transaction = sample->transaction, |
510 | .raw_data = sample->raw_data, | ||
511 | .raw_size = sample->raw_size, | ||
490 | }; | 512 | }; |
491 | 513 | ||
492 | return hists__findnew_entry(hists, &entry, al, sample_self); | 514 | return hists__findnew_entry(hists, &entry, al, sample_self); |
@@ -526,12 +548,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al | |||
526 | u64 cost; | 548 | u64 cost; |
527 | struct mem_info *mi = iter->priv; | 549 | struct mem_info *mi = iter->priv; |
528 | struct hists *hists = evsel__hists(iter->evsel); | 550 | struct hists *hists = evsel__hists(iter->evsel); |
551 | struct perf_sample *sample = iter->sample; | ||
529 | struct hist_entry *he; | 552 | struct hist_entry *he; |
530 | 553 | ||
531 | if (mi == NULL) | 554 | if (mi == NULL) |
532 | return -EINVAL; | 555 | return -EINVAL; |
533 | 556 | ||
534 | cost = iter->sample->weight; | 557 | cost = sample->weight; |
535 | if (!cost) | 558 | if (!cost) |
536 | cost = 1; | 559 | cost = 1; |
537 | 560 | ||
@@ -542,8 +565,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al | |||
542 | * and this is indirectly achieved by passing period=weight here | 565 | * and this is indirectly achieved by passing period=weight here |
543 | * and the he_stat__add_period() function. | 566 | * and the he_stat__add_period() function. |
544 | */ | 567 | */ |
568 | sample->period = cost; | ||
569 | |||
545 | he = __hists__add_entry(hists, al, iter->parent, NULL, mi, | 570 | he = __hists__add_entry(hists, al, iter->parent, NULL, mi, |
546 | cost, cost, 0, true); | 571 | sample, true); |
547 | if (!he) | 572 | if (!he) |
548 | return -ENOMEM; | 573 | return -ENOMEM; |
549 | 574 | ||
@@ -630,6 +655,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a | |||
630 | struct branch_info *bi; | 655 | struct branch_info *bi; |
631 | struct perf_evsel *evsel = iter->evsel; | 656 | struct perf_evsel *evsel = iter->evsel; |
632 | struct hists *hists = evsel__hists(evsel); | 657 | struct hists *hists = evsel__hists(evsel); |
658 | struct perf_sample *sample = iter->sample; | ||
633 | struct hist_entry *he = NULL; | 659 | struct hist_entry *he = NULL; |
634 | int i = iter->curr; | 660 | int i = iter->curr; |
635 | int err = 0; | 661 | int err = 0; |
@@ -643,9 +669,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a | |||
643 | * The report shows the percentage of total branches captured | 669 | * The report shows the percentage of total branches captured |
644 | * and not events sampled. Thus we use a pseudo period of 1. | 670 | * and not events sampled. Thus we use a pseudo period of 1. |
645 | */ | 671 | */ |
672 | sample->period = 1; | ||
673 | sample->weight = bi->flags.cycles ? bi->flags.cycles : 1; | ||
674 | |||
646 | he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, | 675 | he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, |
647 | 1, bi->flags.cycles ? bi->flags.cycles : 1, | 676 | sample, true); |
648 | 0, true); | ||
649 | if (he == NULL) | 677 | if (he == NULL) |
650 | return -ENOMEM; | 678 | return -ENOMEM; |
651 | 679 | ||
@@ -682,8 +710,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location | |||
682 | struct hist_entry *he; | 710 | struct hist_entry *he; |
683 | 711 | ||
684 | he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, | 712 | he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, |
685 | sample->period, sample->weight, | 713 | sample, true); |
686 | sample->transaction, true); | ||
687 | if (he == NULL) | 714 | if (he == NULL) |
688 | return -ENOMEM; | 715 | return -ENOMEM; |
689 | 716 | ||
@@ -744,8 +771,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, | |||
744 | int err = 0; | 771 | int err = 0; |
745 | 772 | ||
746 | he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, | 773 | he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, |
747 | sample->period, sample->weight, | 774 | sample, true); |
748 | sample->transaction, true); | ||
749 | if (he == NULL) | 775 | if (he == NULL) |
750 | return -ENOMEM; | 776 | return -ENOMEM; |
751 | 777 | ||
@@ -797,6 +823,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
797 | .sym = al->sym, | 823 | .sym = al->sym, |
798 | }, | 824 | }, |
799 | .parent = iter->parent, | 825 | .parent = iter->parent, |
826 | .raw_data = sample->raw_data, | ||
827 | .raw_size = sample->raw_size, | ||
800 | }; | 828 | }; |
801 | int i; | 829 | int i; |
802 | struct callchain_cursor cursor; | 830 | struct callchain_cursor cursor; |
@@ -818,8 +846,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
818 | } | 846 | } |
819 | 847 | ||
820 | he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, | 848 | he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, |
821 | sample->period, sample->weight, | 849 | sample, false); |
822 | sample->transaction, false); | ||
823 | if (he == NULL) | 850 | if (he == NULL) |
824 | return -ENOMEM; | 851 | return -ENOMEM; |
825 | 852 | ||
@@ -971,6 +998,8 @@ void hist_entry__delete(struct hist_entry *he) | |||
971 | if (he->srcfile && he->srcfile[0]) | 998 | if (he->srcfile && he->srcfile[0]) |
972 | free(he->srcfile); | 999 | free(he->srcfile); |
973 | free_callchain(he->callchain); | 1000 | free_callchain(he->callchain); |
1001 | free(he->trace_output); | ||
1002 | free(he->raw_data); | ||
974 | free(he); | 1003 | free(he); |
975 | } | 1004 | } |
976 | 1005 | ||
@@ -978,9 +1007,8 @@ void hist_entry__delete(struct hist_entry *he) | |||
978 | * collapse the histogram | 1007 | * collapse the histogram |
979 | */ | 1008 | */ |
980 | 1009 | ||
981 | static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | 1010 | bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, |
982 | struct rb_root *root, | 1011 | struct rb_root *root, struct hist_entry *he) |
983 | struct hist_entry *he) | ||
984 | { | 1012 | { |
985 | struct rb_node **p = &root->rb_node; | 1013 | struct rb_node **p = &root->rb_node; |
986 | struct rb_node *parent = NULL; | 1014 | struct rb_node *parent = NULL; |
@@ -1020,7 +1048,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
1020 | return true; | 1048 | return true; |
1021 | } | 1049 | } |
1022 | 1050 | ||
1023 | static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) | 1051 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists) |
1024 | { | 1052 | { |
1025 | struct rb_root *root; | 1053 | struct rb_root *root; |
1026 | 1054 | ||
@@ -1084,7 +1112,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) | |||
1084 | int64_t cmp = 0; | 1112 | int64_t cmp = 0; |
1085 | 1113 | ||
1086 | perf_hpp__for_each_sort_list(fmt) { | 1114 | perf_hpp__for_each_sort_list(fmt) { |
1087 | if (perf_hpp__should_skip(fmt)) | 1115 | if (perf_hpp__should_skip(fmt, a->hists)) |
1088 | continue; | 1116 | continue; |
1089 | 1117 | ||
1090 | cmp = fmt->sort(fmt, a, b); | 1118 | cmp = fmt->sort(fmt, a, b); |
@@ -1555,10 +1583,8 @@ int perf_hist_config(const char *var, const char *value) | |||
1555 | return 0; | 1583 | return 0; |
1556 | } | 1584 | } |
1557 | 1585 | ||
1558 | static int hists_evsel__init(struct perf_evsel *evsel) | 1586 | int __hists__init(struct hists *hists) |
1559 | { | 1587 | { |
1560 | struct hists *hists = evsel__hists(evsel); | ||
1561 | |||
1562 | memset(hists, 0, sizeof(*hists)); | 1588 | memset(hists, 0, sizeof(*hists)); |
1563 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; | 1589 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; |
1564 | hists->entries_in = &hists->entries_in_array[0]; | 1590 | hists->entries_in = &hists->entries_in_array[0]; |
@@ -1598,6 +1624,14 @@ static void hists_evsel__exit(struct perf_evsel *evsel) | |||
1598 | hists__delete_all_entries(hists); | 1624 | hists__delete_all_entries(hists); |
1599 | } | 1625 | } |
1600 | 1626 | ||
1627 | static int hists_evsel__init(struct perf_evsel *evsel) | ||
1628 | { | ||
1629 | struct hists *hists = evsel__hists(evsel); | ||
1630 | |||
1631 | __hists__init(hists); | ||
1632 | return 0; | ||
1633 | } | ||
1634 | |||
1601 | /* | 1635 | /* |
1602 | * XXX We probably need a hists_evsel__exit() to free the hist_entries | 1636 | * XXX We probably need a hists_evsel__exit() to free the hist_entries |
1603 | * stored in the rbtree... | 1637 | * stored in the rbtree... |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a48a2078d288..d4ec4822a103 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -52,6 +52,7 @@ enum hist_column { | |||
52 | HISTC_MEM_IADDR_SYMBOL, | 52 | HISTC_MEM_IADDR_SYMBOL, |
53 | HISTC_TRANSACTION, | 53 | HISTC_TRANSACTION, |
54 | HISTC_CYCLES, | 54 | HISTC_CYCLES, |
55 | HISTC_TRACE, | ||
55 | HISTC_NR_COLS, /* Last entry */ | 56 | HISTC_NR_COLS, /* Last entry */ |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -114,8 +115,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
114 | struct addr_location *al, | 115 | struct addr_location *al, |
115 | struct symbol *parent, | 116 | struct symbol *parent, |
116 | struct branch_info *bi, | 117 | struct branch_info *bi, |
117 | struct mem_info *mi, u64 period, | 118 | struct mem_info *mi, |
118 | u64 weight, u64 transaction, | 119 | struct perf_sample *sample, |
119 | bool sample_self); | 120 | bool sample_self); |
120 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 121 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
121 | int max_stack_depth, void *arg); | 122 | int max_stack_depth, void *arg); |
@@ -184,6 +185,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel) | |||
184 | } | 185 | } |
185 | 186 | ||
186 | int hists__init(void); | 187 | int hists__init(void); |
188 | int __hists__init(struct hists *hists); | ||
189 | |||
190 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists); | ||
191 | bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | ||
192 | struct rb_root *root, struct hist_entry *he); | ||
187 | 193 | ||
188 | struct perf_hpp { | 194 | struct perf_hpp { |
189 | char *buf; | 195 | char *buf; |
@@ -261,10 +267,20 @@ void perf_hpp__append_sort_keys(void); | |||
261 | 267 | ||
262 | bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); | 268 | bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); |
263 | bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); | 269 | bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); |
270 | bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format); | ||
271 | bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists); | ||
264 | 272 | ||
265 | static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) | 273 | static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format, |
274 | struct hists *hists) | ||
266 | { | 275 | { |
267 | return format->elide; | 276 | if (format->elide) |
277 | return true; | ||
278 | |||
279 | if (perf_hpp__is_dynamic_entry(format) && | ||
280 | !perf_hpp__defined_dynamic_entry(format, hists)) | ||
281 | return true; | ||
282 | |||
283 | return false; | ||
268 | } | 284 | } |
269 | 285 | ||
270 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); | 286 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index e4b173dec4b9..b597bcc8fc78 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -220,6 +220,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | |||
220 | alias->scale = 1.0; | 220 | alias->scale = 1.0; |
221 | alias->unit[0] = '\0'; | 221 | alias->unit[0] = '\0'; |
222 | alias->per_pkg = false; | 222 | alias->per_pkg = false; |
223 | alias->snapshot = false; | ||
223 | 224 | ||
224 | ret = parse_events_terms(&alias->terms, val); | 225 | ret = parse_events_terms(&alias->terms, val); |
225 | if (ret) { | 226 | if (ret) { |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 51be28b1bca2..8162ba0e2e57 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -10,6 +10,8 @@ util/ctype.c | |||
10 | util/evlist.c | 10 | util/evlist.c |
11 | util/evsel.c | 11 | util/evsel.c |
12 | util/cpumap.c | 12 | util/cpumap.c |
13 | ../lib/bitmap.c | ||
14 | ../lib/find_bit.c | ||
13 | ../lib/hweight.c | 15 | ../lib/hweight.c |
14 | util/thread_map.c | 16 | util/thread_map.c |
15 | util/util.c | 17 | util/util.c |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index a8e825fca42a..d72fafc1c800 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -41,6 +41,9 @@ | |||
41 | #include "../thread-stack.h" | 41 | #include "../thread-stack.h" |
42 | #include "../trace-event.h" | 42 | #include "../trace-event.h" |
43 | #include "../machine.h" | 43 | #include "../machine.h" |
44 | #include "thread_map.h" | ||
45 | #include "cpumap.h" | ||
46 | #include "stat.h" | ||
44 | 47 | ||
45 | PyMODINIT_FUNC initperf_trace_context(void); | 48 | PyMODINIT_FUNC initperf_trace_context(void); |
46 | 49 | ||
@@ -859,6 +862,104 @@ static void python_process_event(union perf_event *event, | |||
859 | } | 862 | } |
860 | } | 863 | } |
861 | 864 | ||
865 | static void get_handler_name(char *str, size_t size, | ||
866 | struct perf_evsel *evsel) | ||
867 | { | ||
868 | char *p = str; | ||
869 | |||
870 | scnprintf(str, size, "stat__%s", perf_evsel__name(evsel)); | ||
871 | |||
872 | while ((p = strchr(p, ':'))) { | ||
873 | *p = '_'; | ||
874 | p++; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | static void | ||
879 | process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp, | ||
880 | struct perf_counts_values *count) | ||
881 | { | ||
882 | PyObject *handler, *t; | ||
883 | static char handler_name[256]; | ||
884 | int n = 0; | ||
885 | |||
886 | t = PyTuple_New(MAX_FIELDS); | ||
887 | if (!t) | ||
888 | Py_FatalError("couldn't create Python tuple"); | ||
889 | |||
890 | get_handler_name(handler_name, sizeof(handler_name), | ||
891 | counter); | ||
892 | |||
893 | handler = get_handler(handler_name); | ||
894 | if (!handler) { | ||
895 | pr_debug("can't find python handler %s\n", handler_name); | ||
896 | return; | ||
897 | } | ||
898 | |||
899 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | ||
900 | PyTuple_SetItem(t, n++, PyInt_FromLong(thread)); | ||
901 | |||
902 | tuple_set_u64(t, n++, tstamp); | ||
903 | tuple_set_u64(t, n++, count->val); | ||
904 | tuple_set_u64(t, n++, count->ena); | ||
905 | tuple_set_u64(t, n++, count->run); | ||
906 | |||
907 | if (_PyTuple_Resize(&t, n) == -1) | ||
908 | Py_FatalError("error resizing Python tuple"); | ||
909 | |||
910 | call_object(handler, t, handler_name); | ||
911 | |||
912 | Py_DECREF(t); | ||
913 | } | ||
914 | |||
915 | static void python_process_stat(struct perf_stat_config *config, | ||
916 | struct perf_evsel *counter, u64 tstamp) | ||
917 | { | ||
918 | struct thread_map *threads = counter->threads; | ||
919 | struct cpu_map *cpus = counter->cpus; | ||
920 | int cpu, thread; | ||
921 | |||
922 | if (config->aggr_mode == AGGR_GLOBAL) { | ||
923 | process_stat(counter, -1, -1, tstamp, | ||
924 | &counter->counts->aggr); | ||
925 | return; | ||
926 | } | ||
927 | |||
928 | for (thread = 0; thread < threads->nr; thread++) { | ||
929 | for (cpu = 0; cpu < cpus->nr; cpu++) { | ||
930 | process_stat(counter, cpus->map[cpu], | ||
931 | thread_map__pid(threads, thread), tstamp, | ||
932 | perf_counts(counter->counts, cpu, thread)); | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | |||
937 | static void python_process_stat_interval(u64 tstamp) | ||
938 | { | ||
939 | PyObject *handler, *t; | ||
940 | static const char handler_name[] = "stat__interval"; | ||
941 | int n = 0; | ||
942 | |||
943 | t = PyTuple_New(MAX_FIELDS); | ||
944 | if (!t) | ||
945 | Py_FatalError("couldn't create Python tuple"); | ||
946 | |||
947 | handler = get_handler(handler_name); | ||
948 | if (!handler) { | ||
949 | pr_debug("can't find python handler %s\n", handler_name); | ||
950 | return; | ||
951 | } | ||
952 | |||
953 | tuple_set_u64(t, n++, tstamp); | ||
954 | |||
955 | if (_PyTuple_Resize(&t, n) == -1) | ||
956 | Py_FatalError("error resizing Python tuple"); | ||
957 | |||
958 | call_object(handler, t, handler_name); | ||
959 | |||
960 | Py_DECREF(t); | ||
961 | } | ||
962 | |||
862 | static int run_start_sub(void) | 963 | static int run_start_sub(void) |
863 | { | 964 | { |
864 | main_module = PyImport_AddModule("__main__"); | 965 | main_module = PyImport_AddModule("__main__"); |
@@ -1201,10 +1302,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1201 | } | 1302 | } |
1202 | 1303 | ||
1203 | struct scripting_ops python_scripting_ops = { | 1304 | struct scripting_ops python_scripting_ops = { |
1204 | .name = "Python", | 1305 | .name = "Python", |
1205 | .start_script = python_start_script, | 1306 | .start_script = python_start_script, |
1206 | .flush_script = python_flush_script, | 1307 | .flush_script = python_flush_script, |
1207 | .stop_script = python_stop_script, | 1308 | .stop_script = python_stop_script, |
1208 | .process_event = python_process_event, | 1309 | .process_event = python_process_event, |
1209 | .generate_script = python_generate_script, | 1310 | .process_stat = python_process_stat, |
1311 | .process_stat_interval = python_process_stat_interval, | ||
1312 | .generate_script = python_generate_script, | ||
1210 | }; | 1313 | }; |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 2d8ccd4d9e1b..ec722346e6ff 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -4,6 +4,8 @@ | |||
4 | #include "comm.h" | 4 | #include "comm.h" |
5 | #include "symbol.h" | 5 | #include "symbol.h" |
6 | #include "evsel.h" | 6 | #include "evsel.h" |
7 | #include "evlist.h" | ||
8 | #include <traceevent/event-parse.h> | ||
7 | 9 | ||
8 | regex_t parent_regex; | 10 | regex_t parent_regex; |
9 | const char default_parent_pattern[] = "^sys_|^do_page_fault"; | 11 | const char default_parent_pattern[] = "^sys_|^do_page_fault"; |
@@ -13,6 +15,7 @@ const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy | |||
13 | const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; | 15 | const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; |
14 | const char default_top_sort_order[] = "dso,symbol"; | 16 | const char default_top_sort_order[] = "dso,symbol"; |
15 | const char default_diff_sort_order[] = "dso,symbol"; | 17 | const char default_diff_sort_order[] = "dso,symbol"; |
18 | const char default_tracepoint_sort_order[] = "trace"; | ||
16 | const char *sort_order; | 19 | const char *sort_order; |
17 | const char *field_order; | 20 | const char *field_order; |
18 | regex_t ignore_callees_regex; | 21 | regex_t ignore_callees_regex; |
@@ -443,6 +446,70 @@ struct sort_entry sort_socket = { | |||
443 | .se_width_idx = HISTC_SOCKET, | 446 | .se_width_idx = HISTC_SOCKET, |
444 | }; | 447 | }; |
445 | 448 | ||
449 | /* --sort trace */ | ||
450 | |||
451 | static char *get_trace_output(struct hist_entry *he) | ||
452 | { | ||
453 | struct trace_seq seq; | ||
454 | struct perf_evsel *evsel; | ||
455 | struct pevent_record rec = { | ||
456 | .data = he->raw_data, | ||
457 | .size = he->raw_size, | ||
458 | }; | ||
459 | |||
460 | evsel = hists_to_evsel(he->hists); | ||
461 | |||
462 | trace_seq_init(&seq); | ||
463 | if (symbol_conf.raw_trace) { | ||
464 | pevent_print_fields(&seq, he->raw_data, he->raw_size, | ||
465 | evsel->tp_format); | ||
466 | } else { | ||
467 | pevent_event_info(&seq, evsel->tp_format, &rec); | ||
468 | } | ||
469 | return seq.buffer; | ||
470 | } | ||
471 | |||
472 | static int64_t | ||
473 | sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) | ||
474 | { | ||
475 | struct perf_evsel *evsel; | ||
476 | |||
477 | evsel = hists_to_evsel(left->hists); | ||
478 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | ||
479 | return 0; | ||
480 | |||
481 | if (left->trace_output == NULL) | ||
482 | left->trace_output = get_trace_output(left); | ||
483 | if (right->trace_output == NULL) | ||
484 | right->trace_output = get_trace_output(right); | ||
485 | |||
486 | hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output)); | ||
487 | hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output)); | ||
488 | |||
489 | return strcmp(right->trace_output, left->trace_output); | ||
490 | } | ||
491 | |||
492 | static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, | ||
493 | size_t size, unsigned int width) | ||
494 | { | ||
495 | struct perf_evsel *evsel; | ||
496 | |||
497 | evsel = hists_to_evsel(he->hists); | ||
498 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | ||
499 | return scnprintf(bf, size, "%-*.*s", width, width, "N/A"); | ||
500 | |||
501 | if (he->trace_output == NULL) | ||
502 | he->trace_output = get_trace_output(he); | ||
503 | return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output); | ||
504 | } | ||
505 | |||
506 | struct sort_entry sort_trace = { | ||
507 | .se_header = "Trace output", | ||
508 | .se_cmp = sort__trace_cmp, | ||
509 | .se_snprintf = hist_entry__trace_snprintf, | ||
510 | .se_width_idx = HISTC_TRACE, | ||
511 | }; | ||
512 | |||
446 | /* sort keys for branch stacks */ | 513 | /* sort keys for branch stacks */ |
447 | 514 | ||
448 | static int64_t | 515 | static int64_t |
@@ -1312,6 +1379,7 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
1312 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), | 1379 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), |
1313 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), | 1380 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), |
1314 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), | 1381 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), |
1382 | DIM(SORT_TRACE, "trace", sort_trace), | ||
1315 | }; | 1383 | }; |
1316 | 1384 | ||
1317 | #undef DIM | 1385 | #undef DIM |
@@ -1529,6 +1597,455 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) | |||
1529 | return 0; | 1597 | return 0; |
1530 | } | 1598 | } |
1531 | 1599 | ||
1600 | struct hpp_dynamic_entry { | ||
1601 | struct perf_hpp_fmt hpp; | ||
1602 | struct perf_evsel *evsel; | ||
1603 | struct format_field *field; | ||
1604 | unsigned dynamic_len; | ||
1605 | bool raw_trace; | ||
1606 | }; | ||
1607 | |||
1608 | static int hde_width(struct hpp_dynamic_entry *hde) | ||
1609 | { | ||
1610 | if (!hde->hpp.len) { | ||
1611 | int len = hde->dynamic_len; | ||
1612 | int namelen = strlen(hde->field->name); | ||
1613 | int fieldlen = hde->field->size; | ||
1614 | |||
1615 | if (namelen > len) | ||
1616 | len = namelen; | ||
1617 | |||
1618 | if (!(hde->field->flags & FIELD_IS_STRING)) { | ||
1619 | /* length for print hex numbers */ | ||
1620 | fieldlen = hde->field->size * 2 + 2; | ||
1621 | } | ||
1622 | if (fieldlen > len) | ||
1623 | len = fieldlen; | ||
1624 | |||
1625 | hde->hpp.len = len; | ||
1626 | } | ||
1627 | return hde->hpp.len; | ||
1628 | } | ||
1629 | |||
1630 | static void update_dynamic_len(struct hpp_dynamic_entry *hde, | ||
1631 | struct hist_entry *he) | ||
1632 | { | ||
1633 | char *str, *pos; | ||
1634 | struct format_field *field = hde->field; | ||
1635 | size_t namelen; | ||
1636 | bool last = false; | ||
1637 | |||
1638 | if (hde->raw_trace) | ||
1639 | return; | ||
1640 | |||
1641 | /* parse pretty print result and update max length */ | ||
1642 | if (!he->trace_output) | ||
1643 | he->trace_output = get_trace_output(he); | ||
1644 | |||
1645 | namelen = strlen(field->name); | ||
1646 | str = he->trace_output; | ||
1647 | |||
1648 | while (str) { | ||
1649 | pos = strchr(str, ' '); | ||
1650 | if (pos == NULL) { | ||
1651 | last = true; | ||
1652 | pos = str + strlen(str); | ||
1653 | } | ||
1654 | |||
1655 | if (!strncmp(str, field->name, namelen)) { | ||
1656 | size_t len; | ||
1657 | |||
1658 | str += namelen + 1; | ||
1659 | len = pos - str; | ||
1660 | |||
1661 | if (len > hde->dynamic_len) | ||
1662 | hde->dynamic_len = len; | ||
1663 | break; | ||
1664 | } | ||
1665 | |||
1666 | if (last) | ||
1667 | str = NULL; | ||
1668 | else | ||
1669 | str = pos + 1; | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | ||
1674 | struct perf_evsel *evsel __maybe_unused) | ||
1675 | { | ||
1676 | struct hpp_dynamic_entry *hde; | ||
1677 | size_t len = fmt->user_len; | ||
1678 | |||
1679 | hde = container_of(fmt, struct hpp_dynamic_entry, hpp); | ||
1680 | |||
1681 | if (!len) | ||
1682 | len = hde_width(hde); | ||
1683 | |||
1684 | return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name); | ||
1685 | } | ||
1686 | |||
1687 | static int __sort__hde_width(struct perf_hpp_fmt *fmt, | ||
1688 | struct perf_hpp *hpp __maybe_unused, | ||
1689 | struct perf_evsel *evsel __maybe_unused) | ||
1690 | { | ||
1691 | struct hpp_dynamic_entry *hde; | ||
1692 | size_t len = fmt->user_len; | ||
1693 | |||
1694 | hde = container_of(fmt, struct hpp_dynamic_entry, hpp); | ||
1695 | |||
1696 | if (!len) | ||
1697 | len = hde_width(hde); | ||
1698 | |||
1699 | return len; | ||
1700 | } | ||
1701 | |||
1702 | bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists) | ||
1703 | { | ||
1704 | struct hpp_dynamic_entry *hde; | ||
1705 | |||
1706 | hde = container_of(fmt, struct hpp_dynamic_entry, hpp); | ||
1707 | |||
1708 | return hists_to_evsel(hists) == hde->evsel; | ||
1709 | } | ||
1710 | |||
1711 | static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | ||
1712 | struct hist_entry *he) | ||
1713 | { | ||
1714 | struct hpp_dynamic_entry *hde; | ||
1715 | size_t len = fmt->user_len; | ||
1716 | char *str, *pos; | ||
1717 | struct format_field *field; | ||
1718 | size_t namelen; | ||
1719 | bool last = false; | ||
1720 | int ret; | ||
1721 | |||
1722 | hde = container_of(fmt, struct hpp_dynamic_entry, hpp); | ||
1723 | |||
1724 | if (!len) | ||
1725 | len = hde_width(hde); | ||
1726 | |||
1727 | if (hde->raw_trace) | ||
1728 | goto raw_field; | ||
1729 | |||
1730 | field = hde->field; | ||
1731 | namelen = strlen(field->name); | ||
1732 | str = he->trace_output; | ||
1733 | |||
1734 | while (str) { | ||
1735 | pos = strchr(str, ' '); | ||
1736 | if (pos == NULL) { | ||
1737 | last = true; | ||
1738 | pos = str + strlen(str); | ||
1739 | } | ||
1740 | |||
1741 | if (!strncmp(str, field->name, namelen)) { | ||
1742 | str += namelen + 1; | ||
1743 | str = strndup(str, pos - str); | ||
1744 | |||
1745 | if (str == NULL) | ||
1746 | return scnprintf(hpp->buf, hpp->size, | ||
1747 | "%*.*s", len, len, "ERROR"); | ||
1748 | break; | ||
1749 | } | ||
1750 | |||
1751 | if (last) | ||
1752 | str = NULL; | ||
1753 | else | ||
1754 | str = pos + 1; | ||
1755 | } | ||
1756 | |||
1757 | if (str == NULL) { | ||
1758 | struct trace_seq seq; | ||
1759 | raw_field: | ||
1760 | trace_seq_init(&seq); | ||
1761 | pevent_print_field(&seq, he->raw_data, hde->field); | ||
1762 | str = seq.buffer; | ||
1763 | } | ||
1764 | |||
1765 | ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str); | ||
1766 | free(str); | ||
1767 | return ret; | ||
1768 | } | ||
1769 | |||
1770 | static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, | ||
1771 | struct hist_entry *a, struct hist_entry *b) | ||
1772 | { | ||
1773 | struct hpp_dynamic_entry *hde; | ||
1774 | struct format_field *field; | ||
1775 | unsigned offset, size; | ||
1776 | |||
1777 | hde = container_of(fmt, struct hpp_dynamic_entry, hpp); | ||
1778 | |||
1779 | field = hde->field; | ||
1780 | if (field->flags & FIELD_IS_DYNAMIC) { | ||
1781 | unsigned long long dyn; | ||
1782 | |||
1783 | pevent_read_number_field(field, a->raw_data, &dyn); | ||
1784 | offset = dyn & 0xffff; | ||
1785 | size = (dyn >> 16) & 0xffff; | ||
1786 | |||
1787 | /* record max width for output */ | ||
1788 | if (size > hde->dynamic_len) | ||
1789 | hde->dynamic_len = size; | ||
1790 | } else { | ||
1791 | offset = field->offset; | ||
1792 | size = field->size; | ||
1793 | |||
1794 | update_dynamic_len(hde, a); | ||
1795 | update_dynamic_len(hde, b); | ||
1796 | } | ||
1797 | |||
1798 | return memcmp(a->raw_data + offset, b->raw_data + offset, size); | ||
1799 | } | ||
1800 | |||
1801 | bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt) | ||
1802 | { | ||
1803 | return fmt->cmp == __sort__hde_cmp; | ||
1804 | } | ||
1805 | |||
1806 | static struct hpp_dynamic_entry * | ||
1807 | __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field) | ||
1808 | { | ||
1809 | struct hpp_dynamic_entry *hde; | ||
1810 | |||
1811 | hde = malloc(sizeof(*hde)); | ||
1812 | if (hde == NULL) { | ||
1813 | pr_debug("Memory allocation failed\n"); | ||
1814 | return NULL; | ||
1815 | } | ||
1816 | |||
1817 | hde->evsel = evsel; | ||
1818 | hde->field = field; | ||
1819 | hde->dynamic_len = 0; | ||
1820 | |||
1821 | hde->hpp.name = field->name; | ||
1822 | hde->hpp.header = __sort__hde_header; | ||
1823 | hde->hpp.width = __sort__hde_width; | ||
1824 | hde->hpp.entry = __sort__hde_entry; | ||
1825 | hde->hpp.color = NULL; | ||
1826 | |||
1827 | hde->hpp.cmp = __sort__hde_cmp; | ||
1828 | hde->hpp.collapse = __sort__hde_cmp; | ||
1829 | hde->hpp.sort = __sort__hde_cmp; | ||
1830 | |||
1831 | INIT_LIST_HEAD(&hde->hpp.list); | ||
1832 | INIT_LIST_HEAD(&hde->hpp.sort_list); | ||
1833 | hde->hpp.elide = false; | ||
1834 | hde->hpp.len = 0; | ||
1835 | hde->hpp.user_len = 0; | ||
1836 | |||
1837 | return hde; | ||
1838 | } | ||
1839 | |||
1840 | static int parse_field_name(char *str, char **event, char **field, char **opt) | ||
1841 | { | ||
1842 | char *event_name, *field_name, *opt_name; | ||
1843 | |||
1844 | event_name = str; | ||
1845 | field_name = strchr(str, '.'); | ||
1846 | |||
1847 | if (field_name) { | ||
1848 | *field_name++ = '\0'; | ||
1849 | } else { | ||
1850 | event_name = NULL; | ||
1851 | field_name = str; | ||
1852 | } | ||
1853 | |||
1854 | opt_name = strchr(field_name, '/'); | ||
1855 | if (opt_name) | ||
1856 | *opt_name++ = '\0'; | ||
1857 | |||
1858 | *event = event_name; | ||
1859 | *field = field_name; | ||
1860 | *opt = opt_name; | ||
1861 | |||
1862 | return 0; | ||
1863 | } | ||
1864 | |||
1865 | /* find match evsel using a given event name. The event name can be: | ||
1866 | * 1. '%' + event index (e.g. '%1' for first event) | ||
1867 | * 2. full event name (e.g. sched:sched_switch) | ||
1868 | * 3. partial event name (should not contain ':') | ||
1869 | */ | ||
1870 | static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name) | ||
1871 | { | ||
1872 | struct perf_evsel *evsel = NULL; | ||
1873 | struct perf_evsel *pos; | ||
1874 | bool full_name; | ||
1875 | |||
1876 | /* case 1 */ | ||
1877 | if (event_name[0] == '%') { | ||
1878 | int nr = strtol(event_name+1, NULL, 0); | ||
1879 | |||
1880 | if (nr > evlist->nr_entries) | ||
1881 | return NULL; | ||
1882 | |||
1883 | evsel = perf_evlist__first(evlist); | ||
1884 | while (--nr > 0) | ||
1885 | evsel = perf_evsel__next(evsel); | ||
1886 | |||
1887 | return evsel; | ||
1888 | } | ||
1889 | |||
1890 | full_name = !!strchr(event_name, ':'); | ||
1891 | evlist__for_each(evlist, pos) { | ||
1892 | /* case 2 */ | ||
1893 | if (full_name && !strcmp(pos->name, event_name)) | ||
1894 | return pos; | ||
1895 | /* case 3 */ | ||
1896 | if (!full_name && strstr(pos->name, event_name)) { | ||
1897 | if (evsel) { | ||
1898 | pr_debug("'%s' event is ambiguous: it can be %s or %s\n", | ||
1899 | event_name, evsel->name, pos->name); | ||
1900 | return NULL; | ||
1901 | } | ||
1902 | evsel = pos; | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | return evsel; | ||
1907 | } | ||
1908 | |||
1909 | static int __dynamic_dimension__add(struct perf_evsel *evsel, | ||
1910 | struct format_field *field, | ||
1911 | bool raw_trace) | ||
1912 | { | ||
1913 | struct hpp_dynamic_entry *hde; | ||
1914 | |||
1915 | hde = __alloc_dynamic_entry(evsel, field); | ||
1916 | if (hde == NULL) | ||
1917 | return -ENOMEM; | ||
1918 | |||
1919 | hde->raw_trace = raw_trace; | ||
1920 | |||
1921 | perf_hpp__register_sort_field(&hde->hpp); | ||
1922 | return 0; | ||
1923 | } | ||
1924 | |||
1925 | static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace) | ||
1926 | { | ||
1927 | int ret; | ||
1928 | struct format_field *field; | ||
1929 | |||
1930 | field = evsel->tp_format->format.fields; | ||
1931 | while (field) { | ||
1932 | ret = __dynamic_dimension__add(evsel, field, raw_trace); | ||
1933 | if (ret < 0) | ||
1934 | return ret; | ||
1935 | |||
1936 | field = field->next; | ||
1937 | } | ||
1938 | return 0; | ||
1939 | } | ||
1940 | |||
1941 | static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace) | ||
1942 | { | ||
1943 | int ret; | ||
1944 | struct perf_evsel *evsel; | ||
1945 | |||
1946 | evlist__for_each(evlist, evsel) { | ||
1947 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | ||
1948 | continue; | ||
1949 | |||
1950 | ret = add_evsel_fields(evsel, raw_trace); | ||
1951 | if (ret < 0) | ||
1952 | return ret; | ||
1953 | } | ||
1954 | return 0; | ||
1955 | } | ||
1956 | |||
1957 | static int add_all_matching_fields(struct perf_evlist *evlist, | ||
1958 | char *field_name, bool raw_trace) | ||
1959 | { | ||
1960 | int ret = -ESRCH; | ||
1961 | struct perf_evsel *evsel; | ||
1962 | struct format_field *field; | ||
1963 | |||
1964 | evlist__for_each(evlist, evsel) { | ||
1965 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | ||
1966 | continue; | ||
1967 | |||
1968 | field = pevent_find_any_field(evsel->tp_format, field_name); | ||
1969 | if (field == NULL) | ||
1970 | continue; | ||
1971 | |||
1972 | ret = __dynamic_dimension__add(evsel, field, raw_trace); | ||
1973 | if (ret < 0) | ||
1974 | break; | ||
1975 | } | ||
1976 | return ret; | ||
1977 | } | ||
1978 | |||
1979 | static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok) | ||
1980 | { | ||
1981 | char *str, *event_name, *field_name, *opt_name; | ||
1982 | struct perf_evsel *evsel; | ||
1983 | struct format_field *field; | ||
1984 | bool raw_trace = symbol_conf.raw_trace; | ||
1985 | int ret = 0; | ||
1986 | |||
1987 | if (evlist == NULL) | ||
1988 | return -ENOENT; | ||
1989 | |||
1990 | str = strdup(tok); | ||
1991 | if (str == NULL) | ||
1992 | return -ENOMEM; | ||
1993 | |||
1994 | if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) { | ||
1995 | ret = -EINVAL; | ||
1996 | goto out; | ||
1997 | } | ||
1998 | |||
1999 | if (opt_name) { | ||
2000 | if (strcmp(opt_name, "raw")) { | ||
2001 | pr_debug("unsupported field option %s\n", opt_name); | ||
2002 | ret = -EINVAL; | ||
2003 | goto out; | ||
2004 | } | ||
2005 | raw_trace = true; | ||
2006 | } | ||
2007 | |||
2008 | if (!strcmp(field_name, "trace_fields")) { | ||
2009 | ret = add_all_dynamic_fields(evlist, raw_trace); | ||
2010 | goto out; | ||
2011 | } | ||
2012 | |||
2013 | if (event_name == NULL) { | ||
2014 | ret = add_all_matching_fields(evlist, field_name, raw_trace); | ||
2015 | goto out; | ||
2016 | } | ||
2017 | |||
2018 | evsel = find_evsel(evlist, event_name); | ||
2019 | if (evsel == NULL) { | ||
2020 | pr_debug("Cannot find event: %s\n", event_name); | ||
2021 | ret = -ENOENT; | ||
2022 | goto out; | ||
2023 | } | ||
2024 | |||
2025 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
2026 | pr_debug("%s is not a tracepoint event\n", event_name); | ||
2027 | ret = -EINVAL; | ||
2028 | goto out; | ||
2029 | } | ||
2030 | |||
2031 | if (!strcmp(field_name, "*")) { | ||
2032 | ret = add_evsel_fields(evsel, raw_trace); | ||
2033 | } else { | ||
2034 | field = pevent_find_any_field(evsel->tp_format, field_name); | ||
2035 | if (field == NULL) { | ||
2036 | pr_debug("Cannot find event field for %s.%s\n", | ||
2037 | event_name, field_name); | ||
2038 | return -ENOENT; | ||
2039 | } | ||
2040 | |||
2041 | ret = __dynamic_dimension__add(evsel, field, raw_trace); | ||
2042 | } | ||
2043 | |||
2044 | out: | ||
2045 | free(str); | ||
2046 | return ret; | ||
2047 | } | ||
2048 | |||
1532 | static int __sort_dimension__add(struct sort_dimension *sd) | 2049 | static int __sort_dimension__add(struct sort_dimension *sd) |
1533 | { | 2050 | { |
1534 | if (sd->taken) | 2051 | if (sd->taken) |
@@ -1583,7 +2100,8 @@ int hpp_dimension__add_output(unsigned col) | |||
1583 | return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); | 2100 | return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); |
1584 | } | 2101 | } |
1585 | 2102 | ||
1586 | int sort_dimension__add(const char *tok) | 2103 | static int sort_dimension__add(const char *tok, |
2104 | struct perf_evlist *evlist __maybe_unused) | ||
1587 | { | 2105 | { |
1588 | unsigned int i; | 2106 | unsigned int i; |
1589 | 2107 | ||
@@ -1664,10 +2182,13 @@ int sort_dimension__add(const char *tok) | |||
1664 | return 0; | 2182 | return 0; |
1665 | } | 2183 | } |
1666 | 2184 | ||
2185 | if (!add_dynamic_entry(evlist, tok)) | ||
2186 | return 0; | ||
2187 | |||
1667 | return -ESRCH; | 2188 | return -ESRCH; |
1668 | } | 2189 | } |
1669 | 2190 | ||
1670 | static const char *get_default_sort_order(void) | 2191 | static const char *get_default_sort_order(struct perf_evlist *evlist) |
1671 | { | 2192 | { |
1672 | const char *default_sort_orders[] = { | 2193 | const char *default_sort_orders[] = { |
1673 | default_sort_order, | 2194 | default_sort_order, |
@@ -1675,14 +2196,33 @@ static const char *get_default_sort_order(void) | |||
1675 | default_mem_sort_order, | 2196 | default_mem_sort_order, |
1676 | default_top_sort_order, | 2197 | default_top_sort_order, |
1677 | default_diff_sort_order, | 2198 | default_diff_sort_order, |
2199 | default_tracepoint_sort_order, | ||
1678 | }; | 2200 | }; |
2201 | bool use_trace = true; | ||
2202 | struct perf_evsel *evsel; | ||
1679 | 2203 | ||
1680 | BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); | 2204 | BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); |
1681 | 2205 | ||
2206 | if (evlist == NULL) | ||
2207 | goto out_no_evlist; | ||
2208 | |||
2209 | evlist__for_each(evlist, evsel) { | ||
2210 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
2211 | use_trace = false; | ||
2212 | break; | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | if (use_trace) { | ||
2217 | sort__mode = SORT_MODE__TRACEPOINT; | ||
2218 | if (symbol_conf.raw_trace) | ||
2219 | return "trace_fields"; | ||
2220 | } | ||
2221 | out_no_evlist: | ||
1682 | return default_sort_orders[sort__mode]; | 2222 | return default_sort_orders[sort__mode]; |
1683 | } | 2223 | } |
1684 | 2224 | ||
1685 | static int setup_sort_order(void) | 2225 | static int setup_sort_order(struct perf_evlist *evlist) |
1686 | { | 2226 | { |
1687 | char *new_sort_order; | 2227 | char *new_sort_order; |
1688 | 2228 | ||
@@ -1703,7 +2243,7 @@ static int setup_sort_order(void) | |||
1703 | * because it's checked over the rest of the code. | 2243 | * because it's checked over the rest of the code. |
1704 | */ | 2244 | */ |
1705 | if (asprintf(&new_sort_order, "%s,%s", | 2245 | if (asprintf(&new_sort_order, "%s,%s", |
1706 | get_default_sort_order(), sort_order + 1) < 0) { | 2246 | get_default_sort_order(evlist), sort_order + 1) < 0) { |
1707 | error("Not enough memory to set up --sort"); | 2247 | error("Not enough memory to set up --sort"); |
1708 | return -ENOMEM; | 2248 | return -ENOMEM; |
1709 | } | 2249 | } |
@@ -1712,13 +2252,41 @@ static int setup_sort_order(void) | |||
1712 | return 0; | 2252 | return 0; |
1713 | } | 2253 | } |
1714 | 2254 | ||
1715 | static int __setup_sorting(void) | 2255 | /* |
2256 | * Adds 'pre,' prefix into 'str' is 'pre' is | ||
2257 | * not already part of 'str'. | ||
2258 | */ | ||
2259 | static char *prefix_if_not_in(const char *pre, char *str) | ||
2260 | { | ||
2261 | char *n; | ||
2262 | |||
2263 | if (!str || strstr(str, pre)) | ||
2264 | return str; | ||
2265 | |||
2266 | if (asprintf(&n, "%s,%s", pre, str) < 0) | ||
2267 | return NULL; | ||
2268 | |||
2269 | free(str); | ||
2270 | return n; | ||
2271 | } | ||
2272 | |||
2273 | static char *setup_overhead(char *keys) | ||
2274 | { | ||
2275 | keys = prefix_if_not_in("overhead", keys); | ||
2276 | |||
2277 | if (symbol_conf.cumulate_callchain) | ||
2278 | keys = prefix_if_not_in("overhead_children", keys); | ||
2279 | |||
2280 | return keys; | ||
2281 | } | ||
2282 | |||
2283 | static int __setup_sorting(struct perf_evlist *evlist) | ||
1716 | { | 2284 | { |
1717 | char *tmp, *tok, *str; | 2285 | char *tmp, *tok, *str; |
1718 | const char *sort_keys; | 2286 | const char *sort_keys; |
1719 | int ret = 0; | 2287 | int ret = 0; |
1720 | 2288 | ||
1721 | ret = setup_sort_order(); | 2289 | ret = setup_sort_order(evlist); |
1722 | if (ret) | 2290 | if (ret) |
1723 | return ret; | 2291 | return ret; |
1724 | 2292 | ||
@@ -1732,7 +2300,7 @@ static int __setup_sorting(void) | |||
1732 | return 0; | 2300 | return 0; |
1733 | } | 2301 | } |
1734 | 2302 | ||
1735 | sort_keys = get_default_sort_order(); | 2303 | sort_keys = get_default_sort_order(evlist); |
1736 | } | 2304 | } |
1737 | 2305 | ||
1738 | str = strdup(sort_keys); | 2306 | str = strdup(sort_keys); |
@@ -1741,9 +2309,20 @@ static int __setup_sorting(void) | |||
1741 | return -ENOMEM; | 2309 | return -ENOMEM; |
1742 | } | 2310 | } |
1743 | 2311 | ||
2312 | /* | ||
2313 | * Prepend overhead fields for backward compatibility. | ||
2314 | */ | ||
2315 | if (!is_strict_order(field_order)) { | ||
2316 | str = setup_overhead(str); | ||
2317 | if (str == NULL) { | ||
2318 | error("Not enough memory to setup overhead keys"); | ||
2319 | return -ENOMEM; | ||
2320 | } | ||
2321 | } | ||
2322 | |||
1744 | for (tok = strtok_r(str, ", ", &tmp); | 2323 | for (tok = strtok_r(str, ", ", &tmp); |
1745 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 2324 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
1746 | ret = sort_dimension__add(tok); | 2325 | ret = sort_dimension__add(tok, evlist); |
1747 | if (ret == -EINVAL) { | 2326 | if (ret == -EINVAL) { |
1748 | error("Invalid --sort key: `%s'", tok); | 2327 | error("Invalid --sort key: `%s'", tok); |
1749 | break; | 2328 | break; |
@@ -1954,16 +2533,16 @@ out: | |||
1954 | return ret; | 2533 | return ret; |
1955 | } | 2534 | } |
1956 | 2535 | ||
1957 | int setup_sorting(void) | 2536 | int setup_sorting(struct perf_evlist *evlist) |
1958 | { | 2537 | { |
1959 | int err; | 2538 | int err; |
1960 | 2539 | ||
1961 | err = __setup_sorting(); | 2540 | err = __setup_sorting(evlist); |
1962 | if (err < 0) | 2541 | if (err < 0) |
1963 | return err; | 2542 | return err; |
1964 | 2543 | ||
1965 | if (parent_pattern != default_parent_pattern) { | 2544 | if (parent_pattern != default_parent_pattern) { |
1966 | err = sort_dimension__add("parent"); | 2545 | err = sort_dimension__add("parent", evlist); |
1967 | if (err < 0) | 2546 | if (err < 0) |
1968 | return err; | 2547 | return err; |
1969 | } | 2548 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 86f05e7a5566..687bbb124428 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -122,6 +122,9 @@ struct hist_entry { | |||
122 | struct branch_info *branch_info; | 122 | struct branch_info *branch_info; |
123 | struct hists *hists; | 123 | struct hists *hists; |
124 | struct mem_info *mem_info; | 124 | struct mem_info *mem_info; |
125 | void *raw_data; | ||
126 | u32 raw_size; | ||
127 | void *trace_output; | ||
125 | struct callchain_root callchain[0]; /* must be last member */ | 128 | struct callchain_root callchain[0]; /* must be last member */ |
126 | }; | 129 | }; |
127 | 130 | ||
@@ -164,6 +167,7 @@ enum sort_mode { | |||
164 | SORT_MODE__MEMORY, | 167 | SORT_MODE__MEMORY, |
165 | SORT_MODE__TOP, | 168 | SORT_MODE__TOP, |
166 | SORT_MODE__DIFF, | 169 | SORT_MODE__DIFF, |
170 | SORT_MODE__TRACEPOINT, | ||
167 | }; | 171 | }; |
168 | 172 | ||
169 | enum sort_type { | 173 | enum sort_type { |
@@ -180,6 +184,7 @@ enum sort_type { | |||
180 | SORT_LOCAL_WEIGHT, | 184 | SORT_LOCAL_WEIGHT, |
181 | SORT_GLOBAL_WEIGHT, | 185 | SORT_GLOBAL_WEIGHT, |
182 | SORT_TRANSACTION, | 186 | SORT_TRANSACTION, |
187 | SORT_TRACE, | ||
183 | 188 | ||
184 | /* branch stack specific sort keys */ | 189 | /* branch stack specific sort keys */ |
185 | __SORT_BRANCH_STACK, | 190 | __SORT_BRANCH_STACK, |
@@ -209,8 +214,6 @@ enum sort_type { | |||
209 | */ | 214 | */ |
210 | 215 | ||
211 | struct sort_entry { | 216 | struct sort_entry { |
212 | struct list_head list; | ||
213 | |||
214 | const char *se_header; | 217 | const char *se_header; |
215 | 218 | ||
216 | int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); | 219 | int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); |
@@ -224,10 +227,11 @@ struct sort_entry { | |||
224 | extern struct sort_entry sort_thread; | 227 | extern struct sort_entry sort_thread; |
225 | extern struct list_head hist_entry__sort_list; | 228 | extern struct list_head hist_entry__sort_list; |
226 | 229 | ||
227 | int setup_sorting(void); | 230 | struct perf_evlist; |
231 | struct pevent; | ||
232 | int setup_sorting(struct perf_evlist *evlist); | ||
228 | int setup_output_field(void); | 233 | int setup_output_field(void); |
229 | void reset_output_field(void); | 234 | void reset_output_field(void); |
230 | extern int sort_dimension__add(const char *); | ||
231 | void sort__setup_elide(FILE *fp); | 235 | void sort__setup_elide(FILE *fp); |
232 | void perf_hpp__set_elide(int idx, bool elide); | 236 | void perf_hpp__set_elide(int idx, bool elide); |
233 | 237 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index d51abd2e7865..3b2de6eb3376 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -39,6 +39,7 @@ struct symbol_conf symbol_conf = { | |||
39 | .cumulate_callchain = true, | 39 | .cumulate_callchain = true, |
40 | .show_hist_headers = true, | 40 | .show_hist_headers = true, |
41 | .symfs = "", | 41 | .symfs = "", |
42 | .event_group = true, | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | static enum dso_binary_type binary_type_symtab[] = { | 45 | static enum dso_binary_type binary_type_symtab[] = { |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 857f707ac12b..ccd1caa40e11 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -109,7 +109,8 @@ struct symbol_conf { | |||
109 | branch_callstack, | 109 | branch_callstack, |
110 | has_filter, | 110 | has_filter, |
111 | show_ref_callgraph, | 111 | show_ref_callgraph, |
112 | hide_unresolved; | 112 | hide_unresolved, |
113 | raw_trace; | ||
113 | const char *vmlinux_name, | 114 | const char *vmlinux_name, |
114 | *kallsyms_name, | 115 | *kallsyms_name, |
115 | *source_prefix, | 116 | *source_prefix, |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b85ee55cca0c..bce5b1dac268 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -65,6 +65,7 @@ int tracing_data_put(struct tracing_data *tdata); | |||
65 | struct addr_location; | 65 | struct addr_location; |
66 | 66 | ||
67 | struct perf_session; | 67 | struct perf_session; |
68 | struct perf_stat_config; | ||
68 | 69 | ||
69 | struct scripting_ops { | 70 | struct scripting_ops { |
70 | const char *name; | 71 | const char *name; |
@@ -75,6 +76,9 @@ struct scripting_ops { | |||
75 | struct perf_sample *sample, | 76 | struct perf_sample *sample, |
76 | struct perf_evsel *evsel, | 77 | struct perf_evsel *evsel, |
77 | struct addr_location *al); | 78 | struct addr_location *al); |
79 | void (*process_stat)(struct perf_stat_config *config, | ||
80 | struct perf_evsel *evsel, u64 tstamp); | ||
81 | void (*process_stat_interval)(u64 tstamp); | ||
78 | int (*generate_script) (struct pevent *pevent, const char *outfile); | 82 | int (*generate_script) (struct pevent *pevent, const char *outfile); |
79 | }; | 83 | }; |
80 | 84 | ||
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index db8142ba7cb9..cf5e250bc78e 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c | |||
@@ -96,6 +96,16 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr, | |||
96 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | 96 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, |
97 | MAP__FUNCTION, addr, &al); | 97 | MAP__FUNCTION, addr, &al); |
98 | if (!al.map) { | 98 | if (!al.map) { |
99 | /* | ||
100 | * We've seen cases (softice) where DWARF unwinder went | ||
101 | * through non executable mmaps, which we need to lookup | ||
102 | * in MAP__VARIABLE tree. | ||
103 | */ | ||
104 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | ||
105 | MAP__VARIABLE, addr, &al); | ||
106 | } | ||
107 | |||
108 | if (!al.map) { | ||
99 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); | 109 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); |
100 | return -1; | 110 | return -1; |
101 | } | 111 | } |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 3c258a0e4092..ee7e372297e5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -319,6 +319,15 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui) | |||
319 | 319 | ||
320 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | 320 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, |
321 | MAP__FUNCTION, ip, &al); | 321 | MAP__FUNCTION, ip, &al); |
322 | if (!al.map) { | ||
323 | /* | ||
324 | * We've seen cases (softice) where DWARF unwinder went | ||
325 | * through non executable mmaps, which we need to lookup | ||
326 | * in MAP__VARIABLE tree. | ||
327 | */ | ||
328 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | ||
329 | MAP__VARIABLE, ip, &al); | ||
330 | } | ||
322 | return al.map; | 331 | return al.map; |
323 | } | 332 | } |
324 | 333 | ||
@@ -416,20 +425,19 @@ get_proc_name(unw_addr_space_t __maybe_unused as, | |||
416 | static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, | 425 | static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, |
417 | unw_word_t *data) | 426 | unw_word_t *data) |
418 | { | 427 | { |
419 | struct addr_location al; | 428 | struct map *map; |
420 | ssize_t size; | 429 | ssize_t size; |
421 | 430 | ||
422 | thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, | 431 | map = find_map(addr, ui); |
423 | MAP__FUNCTION, addr, &al); | 432 | if (!map) { |
424 | if (!al.map) { | ||
425 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); | 433 | pr_debug("unwind: no map for %lx\n", (unsigned long)addr); |
426 | return -1; | 434 | return -1; |
427 | } | 435 | } |
428 | 436 | ||
429 | if (!al.map->dso) | 437 | if (!map->dso) |
430 | return -1; | 438 | return -1; |
431 | 439 | ||
432 | size = dso__data_read_addr(al.map->dso, al.map, ui->machine, | 440 | size = dso__data_read_addr(map->dso, map, ui->machine, |
433 | addr, (u8 *) data, sizeof(*data)); | 441 | addr, (u8 *) data, sizeof(*data)); |
434 | 442 | ||
435 | return !(size == sizeof(*data)); | 443 | return !(size == sizeof(*data)); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index aff0cfd83662..88b8f8d21f58 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include "callchain.h" | 18 | #include "callchain.h" |
19 | #include "strlist.h" | ||
20 | #include <subcmd/exec-cmd.h> | ||
19 | 21 | ||
20 | struct callchain_param callchain_param = { | 22 | struct callchain_param callchain_param = { |
21 | .mode = CHAIN_GRAPH_ABS, | 23 | .mode = CHAIN_GRAPH_ABS, |
@@ -663,3 +665,28 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
663 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | 665 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
664 | return 0; | 666 | return 0; |
665 | } | 667 | } |
668 | |||
669 | const char *perf_tip(const char *dirpath) | ||
670 | { | ||
671 | struct strlist *tips; | ||
672 | struct str_node *node; | ||
673 | char *tip = NULL; | ||
674 | struct strlist_config conf = { | ||
675 | .dirname = system_path(dirpath) , | ||
676 | }; | ||
677 | |||
678 | tips = strlist__new("tips.txt", &conf); | ||
679 | if (tips == NULL || strlist__nr_entries(tips) == 1) { | ||
680 | tip = (char *)"Cannot find tips.txt file"; | ||
681 | goto out; | ||
682 | } | ||
683 | |||
684 | node = strlist__entry(tips, random() % strlist__nr_entries(tips)); | ||
685 | if (asprintf(&tip, "Tip: %s", node->s) < 0) | ||
686 | tip = (char *)"Tip: get more memory! ;-)"; | ||
687 | |||
688 | out: | ||
689 | strlist__delete(tips); | ||
690 | |||
691 | return tip; | ||
692 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 4b519c59bdc3..fe915e616f9b 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -342,4 +342,6 @@ int fetch_kernel_version(unsigned int *puint, | |||
342 | #define KVER_FMT "%d.%d.%d" | 342 | #define KVER_FMT "%d.%d.%d" |
343 | #define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) | 343 | #define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) |
344 | 344 | ||
345 | const char *perf_tip(const char *dirpath); | ||
346 | |||
345 | #endif /* GIT_COMPAT_UTIL_H */ | 347 | #endif /* GIT_COMPAT_UTIL_H */ |