diff options
Diffstat (limited to 'tools/perf')
80 files changed, 1187 insertions, 642 deletions
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt index fd77d81ea748..0294c57b1f5e 100644 --- a/tools/perf/Documentation/perf-buildid-cache.txt +++ b/tools/perf/Documentation/perf-buildid-cache.txt | |||
@@ -38,7 +38,7 @@ OPTIONS | |||
38 | --remove=:: | 38 | --remove=:: |
39 | Remove specified file from the cache. | 39 | Remove specified file from the cache. |
40 | -M:: | 40 | -M:: |
41 | --missing=:: | 41 | --missing=:: |
42 | List missing build ids in the cache for the specified file. | 42 | List missing build ids in the cache for the specified file. |
43 | -u:: | 43 | -u:: |
44 | --update:: | 44 | --update:: |
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index cbb4f743d921..3e2aec94f806 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
@@ -89,6 +89,19 @@ raw encoding of 0x1A8 can be used: | |||
89 | You should refer to the processor specific documentation for getting these | 89 | You should refer to the processor specific documentation for getting these |
90 | details. Some of them are referenced in the SEE ALSO section below. | 90 | details. Some of them are referenced in the SEE ALSO section below. |
91 | 91 | ||
92 | PARAMETERIZED EVENTS | ||
93 | -------------------- | ||
94 | |||
95 | Some pmu events listed by 'perf-list' will be displayed with '?' in them. For | ||
96 | example: | ||
97 | |||
98 | hv_gpci/dtbp_ptitc,phys_processor_idx=?/ | ||
99 | |||
100 | This means that when provided as an event, a value for '?' must | ||
101 | also be supplied. For example: | ||
102 | |||
103 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... | ||
104 | |||
92 | OPTIONS | 105 | OPTIONS |
93 | ------- | 106 | ------- |
94 | 107 | ||
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt index 1d78a4064da4..43310d8661fe 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt | |||
@@ -12,11 +12,12 @@ SYNOPSIS | |||
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | "perf mem -t <TYPE> record" runs a command and gathers memory operation data | 15 | "perf mem record" runs a command and gathers memory operation data |
16 | from it, into perf.data. Perf record options are accepted and are passed through. | 16 | from it, into perf.data. Perf record options are accepted and are passed through. |
17 | 17 | ||
18 | "perf mem -t <TYPE> report" displays the result. It invokes perf report with the | 18 | "perf mem report" displays the result. It invokes perf report with the |
19 | right set of options to display a memory access profile. | 19 | right set of options to display a memory access profile. By default, loads |
20 | and stores are sampled. Use the -t option to limit to loads or stores. | ||
20 | 21 | ||
21 | Note that on Intel systems the memory latency reported is the use-latency, | 22 | Note that on Intel systems the memory latency reported is the use-latency, |
22 | not the pure load (or store latency). Use latency includes any pipeline | 23 | not the pure load (or store latency). Use latency includes any pipeline |
@@ -29,7 +30,7 @@ OPTIONS | |||
29 | 30 | ||
30 | -t:: | 31 | -t:: |
31 | --type=:: | 32 | --type=:: |
32 | Select the memory operation type: load or store (default: load) | 33 | Select the memory operation type: load or store (default: load,store) |
33 | 34 | ||
34 | -D:: | 35 | -D:: |
35 | --dump-raw-samples=:: | 36 | --dump-raw-samples=:: |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index af9a54ece024..31e977459c51 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -33,12 +33,27 @@ OPTIONS | |||
33 | - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a | 33 | - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a |
34 | hexadecimal event descriptor. | 34 | hexadecimal event descriptor. |
35 | 35 | ||
36 | - a hardware breakpoint event in the form of '\mem:addr[:access]' | 36 | - a symbolically formed PMU event like 'pmu/param1=0x3,param2/' where |
37 | 'param1', 'param2', etc are defined as formats for the PMU in | ||
38 | /sys/bus/event_sources/devices/<pmu>/format/*. | ||
39 | |||
40 | - a symbolically formed event like 'pmu/config=M,config1=N,config3=K/' | ||
41 | |||
42 | where M, N, K are numbers (in decimal, hex, octal format). Acceptable | ||
43 | values for each of 'config', 'config1' and 'config2' are defined by | ||
44 | corresponding entries in /sys/bus/event_sources/devices/<pmu>/format/* | ||
45 | param1 and param2 are defined as formats for the PMU in: | ||
46 | /sys/bus/event_sources/devices/<pmu>/format/* | ||
47 | |||
48 | - a hardware breakpoint event in the form of '\mem:addr[/len][:access]' | ||
37 | where addr is the address in memory you want to break in. | 49 | where addr is the address in memory you want to break in. |
38 | Access is the memory access type (read, write, execute) it can | 50 | Access is the memory access type (read, write, execute) it can |
39 | be passed as follows: '\mem:addr[:[r][w][x]]'. | 51 | be passed as follows: '\mem:addr[:[r][w][x]]'. len is the range, |
52 | number of bytes from specified addr, which the breakpoint will cover. | ||
40 | If you want to profile read-write accesses in 0x1000, just set | 53 | If you want to profile read-write accesses in 0x1000, just set |
41 | 'mem:0x1000:rw'. | 54 | 'mem:0x1000:rw'. |
55 | If you want to profile write accesses in [0x1000~1008), just set | ||
56 | 'mem:0x1000/8:w'. | ||
42 | 57 | ||
43 | --filter=<filter>:: | 58 | --filter=<filter>:: |
44 | Event filter. | 59 | Event filter. |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 21494806c0ab..a21eec05bc42 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -125,46 +125,46 @@ OPTIONS | |||
125 | is equivalent to: | 125 | is equivalent to: |
126 | 126 | ||
127 | perf script -f trace:<fields> -f sw:<fields> -f hw:<fields> | 127 | perf script -f trace:<fields> -f sw:<fields> -f hw:<fields> |
128 | 128 | ||
129 | i.e., the specified fields apply to all event types if the type string | 129 | i.e., the specified fields apply to all event types if the type string |
130 | is not given. | 130 | is not given. |
131 | 131 | ||
132 | The arguments are processed in the order received. A later usage can | 132 | The arguments are processed in the order received. A later usage can |
133 | reset a prior request. e.g.: | 133 | reset a prior request. e.g.: |
134 | 134 | ||
135 | -f trace: -f comm,tid,time,ip,sym | 135 | -f trace: -f comm,tid,time,ip,sym |
136 | 136 | ||
137 | The first -f suppresses trace events (field list is ""), but then the | 137 | The first -f suppresses trace events (field list is ""), but then the |
138 | second invocation sets the fields to comm,tid,time,ip,sym. In this case a | 138 | second invocation sets the fields to comm,tid,time,ip,sym. In this case a |
139 | warning is given to the user: | 139 | warning is given to the user: |
140 | 140 | ||
141 | "Overriding previous field request for all events." | 141 | "Overriding previous field request for all events." |
142 | 142 | ||
143 | Alternatively, consider the order: | 143 | Alternatively, consider the order: |
144 | 144 | ||
145 | -f comm,tid,time,ip,sym -f trace: | 145 | -f comm,tid,time,ip,sym -f trace: |
146 | 146 | ||
147 | The first -f sets the fields for all events and the second -f | 147 | The first -f sets the fields for all events and the second -f |
148 | suppresses trace events. The user is given a warning message about | 148 | suppresses trace events. The user is given a warning message about |
149 | the override, and the result of the above is that only S/W and H/W | 149 | the override, and the result of the above is that only S/W and H/W |
150 | events are displayed with the given fields. | 150 | events are displayed with the given fields. |
151 | 151 | ||
152 | For the 'wildcard' option if a user selected field is invalid for an | 152 | For the 'wildcard' option if a user selected field is invalid for an |
153 | event type, a message is displayed to the user that the option is | 153 | event type, a message is displayed to the user that the option is |
154 | ignored for that type. For example: | 154 | ignored for that type. For example: |
155 | 155 | ||
156 | $ perf script -f comm,tid,trace | 156 | $ perf script -f comm,tid,trace |
157 | 'trace' not valid for hardware events. Ignoring. | 157 | 'trace' not valid for hardware events. Ignoring. |
158 | 'trace' not valid for software events. Ignoring. | 158 | 'trace' not valid for software events. Ignoring. |
159 | 159 | ||
160 | Alternatively, if the type is given an invalid field is specified it | 160 | Alternatively, if the type is given an invalid field is specified it |
161 | is an error. For example: | 161 | is an error. For example: |
162 | 162 | ||
163 | perf script -v -f sw:comm,tid,trace | 163 | perf script -v -f sw:comm,tid,trace |
164 | 'trace' not valid for software events. | 164 | 'trace' not valid for software events. |
165 | 165 | ||
166 | At this point usage is displayed, and perf-script exits. | 166 | At this point usage is displayed, and perf-script exits. |
167 | 167 | ||
168 | Finally, a user may not set fields to none for all event types. | 168 | Finally, a user may not set fields to none for all event types. |
169 | i.e., -f "" is not allowed. | 169 | i.e., -f "" is not allowed. |
170 | 170 | ||
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 29ee857c09c6..04e150d83e7d 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -25,10 +25,22 @@ OPTIONS | |||
25 | 25 | ||
26 | -e:: | 26 | -e:: |
27 | --event=:: | 27 | --event=:: |
28 | Select the PMU event. Selection can be a symbolic event name | 28 | Select the PMU event. Selection can be: |
29 | (use 'perf list' to list all events) or a raw PMU | 29 | |
30 | event (eventsel+umask) in the form of rNNN where NNN is a | 30 | - a symbolic event name (use 'perf list' to list all events) |
31 | hexadecimal event descriptor. | 31 | |
32 | - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a | ||
33 | hexadecimal event descriptor. | ||
34 | |||
35 | - a symbolically formed event like 'pmu/param1=0x3,param2/' where | ||
36 | param1 and param2 are defined as formats for the PMU in | ||
37 | /sys/bus/event_sources/devices/<pmu>/format/* | ||
38 | |||
39 | - a symbolically formed event like 'pmu/config=M,config1=N,config2=K/' | ||
40 | where M, N, K are numbers (in decimal, hex, octal format). | ||
41 | Acceptable values for each of 'config', 'config1' and 'config2' | ||
42 | parameters are defined by corresponding entries in | ||
43 | /sys/bus/event_sources/devices/<pmu>/format/* | ||
32 | 44 | ||
33 | -i:: | 45 | -i:: |
34 | --no-inherit:: | 46 | --no-inherit:: |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 83e2887f91a3..fbbfdc39271d 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -6,12 +6,15 @@ tools/lib/symbol/kallsyms.c | |||
6 | tools/lib/symbol/kallsyms.h | 6 | tools/lib/symbol/kallsyms.h |
7 | tools/lib/util/find_next_bit.c | 7 | tools/lib/util/find_next_bit.c |
8 | tools/include/asm/bug.h | 8 | tools/include/asm/bug.h |
9 | tools/include/asm-generic/bitops/arch_hweight.h | ||
9 | tools/include/asm-generic/bitops/atomic.h | 10 | tools/include/asm-generic/bitops/atomic.h |
11 | tools/include/asm-generic/bitops/const_hweight.h | ||
10 | tools/include/asm-generic/bitops/__ffs.h | 12 | tools/include/asm-generic/bitops/__ffs.h |
11 | tools/include/asm-generic/bitops/__fls.h | 13 | tools/include/asm-generic/bitops/__fls.h |
12 | tools/include/asm-generic/bitops/find.h | 14 | tools/include/asm-generic/bitops/find.h |
13 | tools/include/asm-generic/bitops/fls64.h | 15 | tools/include/asm-generic/bitops/fls64.h |
14 | tools/include/asm-generic/bitops/fls.h | 16 | tools/include/asm-generic/bitops/fls.h |
17 | tools/include/asm-generic/bitops/hweight.h | ||
15 | tools/include/asm-generic/bitops.h | 18 | tools/include/asm-generic/bitops.h |
16 | tools/include/linux/bitops.h | 19 | tools/include/linux/bitops.h |
17 | tools/include/linux/compiler.h | 20 | tools/include/linux/compiler.h |
@@ -19,6 +22,8 @@ tools/include/linux/export.h | |||
19 | tools/include/linux/hash.h | 22 | tools/include/linux/hash.h |
20 | tools/include/linux/log2.h | 23 | tools/include/linux/log2.h |
21 | tools/include/linux/types.h | 24 | tools/include/linux/types.h |
25 | include/asm-generic/bitops/arch_hweight.h | ||
26 | include/asm-generic/bitops/const_hweight.h | ||
22 | include/asm-generic/bitops/fls64.h | 27 | include/asm-generic/bitops/fls64.h |
23 | include/asm-generic/bitops/__fls.h | 28 | include/asm-generic/bitops/__fls.h |
24 | include/asm-generic/bitops/fls.h | 29 | include/asm-generic/bitops/fls.h |
@@ -29,6 +34,7 @@ include/linux/list.h | |||
29 | include/linux/hash.h | 34 | include/linux/hash.h |
30 | include/linux/stringify.h | 35 | include/linux/stringify.h |
31 | lib/find_next_bit.c | 36 | lib/find_next_bit.c |
37 | lib/hweight.c | ||
32 | lib/rbtree.c | 38 | lib/rbtree.c |
33 | include/linux/swab.h | 39 | include/linux/swab.h |
34 | arch/*/include/asm/unistd*.h | 40 | arch/*/include/asm/unistd*.h |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 67a03a825b3c..aa6a50447c32 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -232,12 +232,15 @@ LIB_H += ../include/linux/hash.h | |||
232 | LIB_H += ../../include/linux/stringify.h | 232 | LIB_H += ../../include/linux/stringify.h |
233 | LIB_H += util/include/linux/bitmap.h | 233 | LIB_H += util/include/linux/bitmap.h |
234 | LIB_H += ../include/linux/bitops.h | 234 | LIB_H += ../include/linux/bitops.h |
235 | LIB_H += ../include/asm-generic/bitops/arch_hweight.h | ||
235 | LIB_H += ../include/asm-generic/bitops/atomic.h | 236 | LIB_H += ../include/asm-generic/bitops/atomic.h |
237 | LIB_H += ../include/asm-generic/bitops/const_hweight.h | ||
236 | LIB_H += ../include/asm-generic/bitops/find.h | 238 | LIB_H += ../include/asm-generic/bitops/find.h |
237 | LIB_H += ../include/asm-generic/bitops/fls64.h | 239 | LIB_H += ../include/asm-generic/bitops/fls64.h |
238 | LIB_H += ../include/asm-generic/bitops/fls.h | 240 | LIB_H += ../include/asm-generic/bitops/fls.h |
239 | LIB_H += ../include/asm-generic/bitops/__ffs.h | 241 | LIB_H += ../include/asm-generic/bitops/__ffs.h |
240 | LIB_H += ../include/asm-generic/bitops/__fls.h | 242 | LIB_H += ../include/asm-generic/bitops/__fls.h |
243 | LIB_H += ../include/asm-generic/bitops/hweight.h | ||
241 | LIB_H += ../include/asm-generic/bitops.h | 244 | LIB_H += ../include/asm-generic/bitops.h |
242 | LIB_H += ../include/linux/compiler.h | 245 | LIB_H += ../include/linux/compiler.h |
243 | LIB_H += ../include/linux/log2.h | 246 | LIB_H += ../include/linux/log2.h |
@@ -255,7 +258,6 @@ LIB_H += util/include/linux/linkage.h | |||
255 | LIB_H += util/include/asm/asm-offsets.h | 258 | LIB_H += util/include/asm/asm-offsets.h |
256 | LIB_H += ../include/asm/bug.h | 259 | LIB_H += ../include/asm/bug.h |
257 | LIB_H += util/include/asm/byteorder.h | 260 | LIB_H += util/include/asm/byteorder.h |
258 | LIB_H += util/include/asm/hweight.h | ||
259 | LIB_H += util/include/asm/swab.h | 261 | LIB_H += util/include/asm/swab.h |
260 | LIB_H += util/include/asm/system.h | 262 | LIB_H += util/include/asm/system.h |
261 | LIB_H += util/include/asm/uaccess.h | 263 | LIB_H += util/include/asm/uaccess.h |
@@ -462,10 +464,12 @@ BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | |||
462 | # Benchmark modules | 464 | # Benchmark modules |
463 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o | 465 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o |
464 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o | 466 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o |
465 | ifeq ($(RAW_ARCH),x86_64) | 467 | ifeq ($(ARCH), x86) |
468 | ifeq ($(IS_64_BIT), 1) | ||
466 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o | 469 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o |
467 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o | 470 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o |
468 | endif | 471 | endif |
472 | endif | ||
469 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o | 473 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o |
470 | BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o | 474 | BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o |
471 | BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o | 475 | BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o |
@@ -743,6 +747,9 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS | |||
743 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 747 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
744 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 748 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
745 | 749 | ||
750 | $(OUTPUT)util/hweight.o: ../../lib/hweight.c $(OUTPUT)PERF-CFLAGS | ||
751 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | ||
752 | |||
746 | $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS | 753 | $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS |
747 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 754 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
748 | 755 | ||
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index 3bb50eac5542..0c370f81e002 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c | |||
@@ -103,7 +103,7 @@ static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc) | |||
103 | return NULL; | 103 | return NULL; |
104 | } | 104 | } |
105 | 105 | ||
106 | result = dwarf_cfi_addrframe(cfi, pc, &frame); | 106 | result = dwarf_cfi_addrframe(cfi, pc-bias, &frame); |
107 | if (result) { | 107 | if (result) { |
108 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); | 108 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); |
109 | return NULL; | 109 | return NULL; |
@@ -128,7 +128,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) | |||
128 | return NULL; | 128 | return NULL; |
129 | } | 129 | } |
130 | 130 | ||
131 | result = dwarf_cfi_addrframe(cfi, pc, &frame); | 131 | result = dwarf_cfi_addrframe(cfi, pc-bias, &frame); |
132 | if (result) { | 132 | if (result) { |
133 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); | 133 | pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); |
134 | return NULL; | 134 | return NULL; |
@@ -145,7 +145,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) | |||
145 | * yet used) | 145 | * yet used) |
146 | * -1 in case of errors | 146 | * -1 in case of errors |
147 | */ | 147 | */ |
148 | static int check_return_addr(struct dso *dso, Dwarf_Addr pc) | 148 | static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) |
149 | { | 149 | { |
150 | int rc = -1; | 150 | int rc = -1; |
151 | Dwfl *dwfl; | 151 | Dwfl *dwfl; |
@@ -155,6 +155,7 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr pc) | |||
155 | Dwarf_Addr start = pc; | 155 | Dwarf_Addr start = pc; |
156 | Dwarf_Addr end = pc; | 156 | Dwarf_Addr end = pc; |
157 | bool signalp; | 157 | bool signalp; |
158 | const char *exec_file = dso->long_name; | ||
158 | 159 | ||
159 | dwfl = dso->dwfl; | 160 | dwfl = dso->dwfl; |
160 | 161 | ||
@@ -165,8 +166,10 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr pc) | |||
165 | return -1; | 166 | return -1; |
166 | } | 167 | } |
167 | 168 | ||
168 | if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) { | 169 | mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1, |
169 | pr_debug("dwfl_report_offline() failed %s\n", | 170 | map_start, false); |
171 | if (!mod) { | ||
172 | pr_debug("dwfl_report_elf() failed %s\n", | ||
170 | dwarf_errmsg(-1)); | 173 | dwarf_errmsg(-1)); |
171 | /* | 174 | /* |
172 | * We normally cache the DWARF debug info and never | 175 | * We normally cache the DWARF debug info and never |
@@ -256,10 +259,10 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) | |||
256 | return skip_slot; | 259 | return skip_slot; |
257 | } | 260 | } |
258 | 261 | ||
259 | rc = check_return_addr(dso, ip); | 262 | rc = check_return_addr(dso, al.map->start, ip); |
260 | 263 | ||
261 | pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n", | 264 | pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n", |
262 | dso->long_name, chain->nr, ip, rc); | 265 | dso->long_name, al.sym->name, ip, rc); |
263 | 266 | ||
264 | if (rc == 0) { | 267 | if (rc == 0) { |
265 | /* | 268 | /* |
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h index 71f2844cf97f..7ed22ff1e1ac 100644 --- a/tools/perf/bench/futex.h +++ b/tools/perf/bench/futex.h | |||
@@ -68,4 +68,17 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak | |||
68 | val, opflags); | 68 | val, opflags); |
69 | } | 69 | } |
70 | 70 | ||
71 | #ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP | ||
72 | #include <pthread.h> | ||
73 | static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr, | ||
74 | size_t cpusetsize, | ||
75 | cpu_set_t *cpuset) | ||
76 | { | ||
77 | attr = attr; | ||
78 | cpusetsize = cpusetsize; | ||
79 | cpuset = cpuset; | ||
80 | return 0; | ||
81 | } | ||
82 | #endif | ||
83 | |||
71 | #endif /* _FUTEX_H */ | 84 | #endif /* _FUTEX_H */ |
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 07a8d7646a15..005cc283790c 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c | |||
@@ -19,12 +19,12 @@ | |||
19 | #include <stdlib.h> | 19 | #include <stdlib.h> |
20 | #include <signal.h> | 20 | #include <signal.h> |
21 | #include <sys/wait.h> | 21 | #include <sys/wait.h> |
22 | #include <linux/unistd.h> | ||
23 | #include <string.h> | 22 | #include <string.h> |
24 | #include <errno.h> | 23 | #include <errno.h> |
25 | #include <assert.h> | 24 | #include <assert.h> |
26 | #include <sys/time.h> | 25 | #include <sys/time.h> |
27 | #include <sys/types.h> | 26 | #include <sys/types.h> |
27 | #include <sys/syscall.h> | ||
28 | 28 | ||
29 | #include <pthread.h> | 29 | #include <pthread.h> |
30 | 30 | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e7417fe97a97..747f86103599 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -232,7 +232,7 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
232 | if (nr_samples > 0) { | 232 | if (nr_samples > 0) { |
233 | total_nr_samples += nr_samples; | 233 | total_nr_samples += nr_samples; |
234 | hists__collapse_resort(hists, NULL); | 234 | hists__collapse_resort(hists, NULL); |
235 | hists__output_resort(hists); | 235 | hists__output_resort(hists, NULL); |
236 | 236 | ||
237 | if (symbol_conf.event_group && | 237 | if (symbol_conf.event_group && |
238 | !perf_evsel__is_group_leader(pos)) | 238 | !perf_evsel__is_group_leader(pos)) |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 77d5cae54c6a..50e6b66aea1f 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -236,10 +236,10 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) | |||
236 | if (errno == ENOENT) | 236 | if (errno == ENOENT) |
237 | return false; | 237 | return false; |
238 | 238 | ||
239 | pr_warning("Problems with %s file, consider removing it from the cache\n", | 239 | pr_warning("Problems with %s file, consider removing it from the cache\n", |
240 | filename); | 240 | filename); |
241 | } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { | 241 | } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { |
242 | pr_warning("Problems with %s file, consider removing it from the cache\n", | 242 | pr_warning("Problems with %s file, consider removing it from the cache\n", |
243 | filename); | 243 | filename); |
244 | } | 244 | } |
245 | 245 | ||
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 1ce425d101a9..74aada554b12 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -390,6 +390,15 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) | |||
390 | } | 390 | } |
391 | } | 391 | } |
392 | 392 | ||
393 | static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt) | ||
394 | { | ||
395 | struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt); | ||
396 | void *ptr = dfmt - dfmt->idx; | ||
397 | struct data__file *d = container_of(ptr, struct data__file, fmt); | ||
398 | |||
399 | return d; | ||
400 | } | ||
401 | |||
393 | static struct hist_entry* | 402 | static struct hist_entry* |
394 | get_pair_data(struct hist_entry *he, struct data__file *d) | 403 | get_pair_data(struct hist_entry *he, struct data__file *d) |
395 | { | 404 | { |
@@ -407,8 +416,7 @@ get_pair_data(struct hist_entry *he, struct data__file *d) | |||
407 | static struct hist_entry* | 416 | static struct hist_entry* |
408 | get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt) | 417 | get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt) |
409 | { | 418 | { |
410 | void *ptr = dfmt - dfmt->idx; | 419 | struct data__file *d = fmt_to_data_file(&dfmt->fmt); |
411 | struct data__file *d = container_of(ptr, struct data__file, fmt); | ||
412 | 420 | ||
413 | return get_pair_data(he, d); | 421 | return get_pair_data(he, d); |
414 | } | 422 | } |
@@ -430,7 +438,7 @@ static void hists__baseline_only(struct hists *hists) | |||
430 | next = rb_next(&he->rb_node_in); | 438 | next = rb_next(&he->rb_node_in); |
431 | if (!hist_entry__next_pair(he)) { | 439 | if (!hist_entry__next_pair(he)) { |
432 | rb_erase(&he->rb_node_in, root); | 440 | rb_erase(&he->rb_node_in, root); |
433 | hist_entry__free(he); | 441 | hist_entry__delete(he); |
434 | } | 442 | } |
435 | } | 443 | } |
436 | } | 444 | } |
@@ -448,26 +456,30 @@ static void hists__precompute(struct hists *hists) | |||
448 | next = rb_first(root); | 456 | next = rb_first(root); |
449 | while (next != NULL) { | 457 | while (next != NULL) { |
450 | struct hist_entry *he, *pair; | 458 | struct hist_entry *he, *pair; |
459 | struct data__file *d; | ||
460 | int i; | ||
451 | 461 | ||
452 | he = rb_entry(next, struct hist_entry, rb_node_in); | 462 | he = rb_entry(next, struct hist_entry, rb_node_in); |
453 | next = rb_next(&he->rb_node_in); | 463 | next = rb_next(&he->rb_node_in); |
454 | 464 | ||
455 | pair = get_pair_data(he, &data__files[sort_compute]); | 465 | data__for_each_file_new(i, d) { |
456 | if (!pair) | 466 | pair = get_pair_data(he, d); |
457 | continue; | 467 | if (!pair) |
468 | continue; | ||
458 | 469 | ||
459 | switch (compute) { | 470 | switch (compute) { |
460 | case COMPUTE_DELTA: | 471 | case COMPUTE_DELTA: |
461 | compute_delta(he, pair); | 472 | compute_delta(he, pair); |
462 | break; | 473 | break; |
463 | case COMPUTE_RATIO: | 474 | case COMPUTE_RATIO: |
464 | compute_ratio(he, pair); | 475 | compute_ratio(he, pair); |
465 | break; | 476 | break; |
466 | case COMPUTE_WEIGHTED_DIFF: | 477 | case COMPUTE_WEIGHTED_DIFF: |
467 | compute_wdiff(he, pair); | 478 | compute_wdiff(he, pair); |
468 | break; | 479 | break; |
469 | default: | 480 | default: |
470 | BUG_ON(1); | 481 | BUG_ON(1); |
482 | } | ||
471 | } | 483 | } |
472 | } | 484 | } |
473 | } | 485 | } |
@@ -517,7 +529,7 @@ __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | |||
517 | 529 | ||
518 | static int64_t | 530 | static int64_t |
519 | hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | 531 | hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, |
520 | int c) | 532 | int c, int sort_idx) |
521 | { | 533 | { |
522 | bool pairs_left = hist_entry__has_pairs(left); | 534 | bool pairs_left = hist_entry__has_pairs(left); |
523 | bool pairs_right = hist_entry__has_pairs(right); | 535 | bool pairs_right = hist_entry__has_pairs(right); |
@@ -529,8 +541,8 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | |||
529 | if (!pairs_left || !pairs_right) | 541 | if (!pairs_left || !pairs_right) |
530 | return pairs_left ? -1 : 1; | 542 | return pairs_left ? -1 : 1; |
531 | 543 | ||
532 | p_left = get_pair_data(left, &data__files[sort_compute]); | 544 | p_left = get_pair_data(left, &data__files[sort_idx]); |
533 | p_right = get_pair_data(right, &data__files[sort_compute]); | 545 | p_right = get_pair_data(right, &data__files[sort_idx]); |
534 | 546 | ||
535 | if (!p_left && !p_right) | 547 | if (!p_left && !p_right) |
536 | return 0; | 548 | return 0; |
@@ -545,55 +557,103 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | |||
545 | return __hist_entry__cmp_compute(p_left, p_right, c); | 557 | return __hist_entry__cmp_compute(p_left, p_right, c); |
546 | } | 558 | } |
547 | 559 | ||
548 | static void insert_hist_entry_by_compute(struct rb_root *root, | 560 | static int64_t |
549 | struct hist_entry *he, | 561 | hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right, |
550 | int c) | 562 | int c, int sort_idx) |
551 | { | 563 | { |
552 | struct rb_node **p = &root->rb_node; | 564 | struct hist_entry *p_right, *p_left; |
553 | struct rb_node *parent = NULL; | 565 | |
554 | struct hist_entry *iter; | 566 | p_left = get_pair_data(left, &data__files[sort_idx]); |
555 | 567 | p_right = get_pair_data(right, &data__files[sort_idx]); | |
556 | while (*p != NULL) { | 568 | |
557 | parent = *p; | 569 | if (!p_left && !p_right) |
558 | iter = rb_entry(parent, struct hist_entry, rb_node); | 570 | return 0; |
559 | if (hist_entry__cmp_compute(he, iter, c) < 0) | 571 | |
560 | p = &(*p)->rb_left; | 572 | if (!p_left || !p_right) |
561 | else | 573 | return p_left ? -1 : 1; |
562 | p = &(*p)->rb_right; | 574 | |
575 | if (c != COMPUTE_DELTA) { | ||
576 | /* | ||
577 | * The delta can be computed without the baseline, but | ||
578 | * others are not. Put those entries which have no | ||
579 | * values below. | ||
580 | */ | ||
581 | if (left->dummy && right->dummy) | ||
582 | return 0; | ||
583 | |||
584 | if (left->dummy || right->dummy) | ||
585 | return left->dummy ? 1 : -1; | ||
563 | } | 586 | } |
564 | 587 | ||
565 | rb_link_node(&he->rb_node, parent, p); | 588 | return __hist_entry__cmp_compute(p_left, p_right, c); |
566 | rb_insert_color(&he->rb_node, root); | ||
567 | } | 589 | } |
568 | 590 | ||
569 | static void hists__compute_resort(struct hists *hists) | 591 | static int64_t |
592 | hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused, | ||
593 | struct hist_entry *left __maybe_unused, | ||
594 | struct hist_entry *right __maybe_unused) | ||
570 | { | 595 | { |
571 | struct rb_root *root; | 596 | return 0; |
572 | struct rb_node *next; | 597 | } |
573 | 598 | ||
574 | if (sort__need_collapse) | 599 | static int64_t |
575 | root = &hists->entries_collapsed; | 600 | hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused, |
576 | else | 601 | struct hist_entry *left, struct hist_entry *right) |
577 | root = hists->entries_in; | 602 | { |
603 | if (left->stat.period == right->stat.period) | ||
604 | return 0; | ||
605 | return left->stat.period > right->stat.period ? 1 : -1; | ||
606 | } | ||
578 | 607 | ||
579 | hists->entries = RB_ROOT; | 608 | static int64_t |
580 | next = rb_first(root); | 609 | hist_entry__cmp_delta(struct perf_hpp_fmt *fmt, |
610 | struct hist_entry *left, struct hist_entry *right) | ||
611 | { | ||
612 | struct data__file *d = fmt_to_data_file(fmt); | ||
581 | 613 | ||
582 | hists__reset_stats(hists); | 614 | return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx); |
583 | hists__reset_col_len(hists); | 615 | } |
584 | 616 | ||
585 | while (next != NULL) { | 617 | static int64_t |
586 | struct hist_entry *he; | 618 | hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt, |
619 | struct hist_entry *left, struct hist_entry *right) | ||
620 | { | ||
621 | struct data__file *d = fmt_to_data_file(fmt); | ||
587 | 622 | ||
588 | he = rb_entry(next, struct hist_entry, rb_node_in); | 623 | return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx); |
589 | next = rb_next(&he->rb_node_in); | 624 | } |
625 | |||
626 | static int64_t | ||
627 | hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt, | ||
628 | struct hist_entry *left, struct hist_entry *right) | ||
629 | { | ||
630 | struct data__file *d = fmt_to_data_file(fmt); | ||
590 | 631 | ||
591 | insert_hist_entry_by_compute(&hists->entries, he, compute); | 632 | return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx); |
592 | hists__inc_stats(hists, he); | 633 | } |
593 | 634 | ||
594 | if (!he->filtered) | 635 | static int64_t |
595 | hists__calc_col_len(hists, he); | 636 | hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused, |
596 | } | 637 | struct hist_entry *left, struct hist_entry *right) |
638 | { | ||
639 | return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA, | ||
640 | sort_compute); | ||
641 | } | ||
642 | |||
643 | static int64_t | ||
644 | hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused, | ||
645 | struct hist_entry *left, struct hist_entry *right) | ||
646 | { | ||
647 | return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO, | ||
648 | sort_compute); | ||
649 | } | ||
650 | |||
651 | static int64_t | ||
652 | hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused, | ||
653 | struct hist_entry *left, struct hist_entry *right) | ||
654 | { | ||
655 | return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF, | ||
656 | sort_compute); | ||
597 | } | 657 | } |
598 | 658 | ||
599 | static void hists__process(struct hists *hists) | 659 | static void hists__process(struct hists *hists) |
@@ -601,12 +661,8 @@ static void hists__process(struct hists *hists) | |||
601 | if (show_baseline_only) | 661 | if (show_baseline_only) |
602 | hists__baseline_only(hists); | 662 | hists__baseline_only(hists); |
603 | 663 | ||
604 | if (sort_compute) { | 664 | hists__precompute(hists); |
605 | hists__precompute(hists); | 665 | hists__output_resort(hists, NULL); |
606 | hists__compute_resort(hists); | ||
607 | } else { | ||
608 | hists__output_resort(hists); | ||
609 | } | ||
610 | 666 | ||
611 | hists__fprintf(hists, true, 0, 0, 0, stdout); | 667 | hists__fprintf(hists, true, 0, 0, 0, stdout); |
612 | } | 668 | } |
@@ -805,7 +861,7 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt, | |||
805 | char pfmt[20] = " "; | 861 | char pfmt[20] = " "; |
806 | 862 | ||
807 | if (!pair) | 863 | if (!pair) |
808 | goto dummy_print; | 864 | goto no_print; |
809 | 865 | ||
810 | switch (comparison_method) { | 866 | switch (comparison_method) { |
811 | case COMPUTE_DELTA: | 867 | case COMPUTE_DELTA: |
@@ -814,8 +870,6 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt, | |||
814 | else | 870 | else |
815 | diff = compute_delta(he, pair); | 871 | diff = compute_delta(he, pair); |
816 | 872 | ||
817 | if (fabs(diff) < 0.01) | ||
818 | goto dummy_print; | ||
819 | scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1); | 873 | scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1); |
820 | return percent_color_snprintf(hpp->buf, hpp->size, | 874 | return percent_color_snprintf(hpp->buf, hpp->size, |
821 | pfmt, diff); | 875 | pfmt, diff); |
@@ -847,6 +901,9 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt, | |||
847 | } | 901 | } |
848 | dummy_print: | 902 | dummy_print: |
849 | return scnprintf(hpp->buf, hpp->size, "%*s", | 903 | return scnprintf(hpp->buf, hpp->size, "%*s", |
904 | dfmt->header_width, "N/A"); | ||
905 | no_print: | ||
906 | return scnprintf(hpp->buf, hpp->size, "%*s", | ||
850 | dfmt->header_width, pfmt); | 907 | dfmt->header_width, pfmt); |
851 | } | 908 | } |
852 | 909 | ||
@@ -896,14 +953,15 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, | |||
896 | else | 953 | else |
897 | diff = compute_delta(he, pair); | 954 | diff = compute_delta(he, pair); |
898 | 955 | ||
899 | if (fabs(diff) >= 0.01) | 956 | scnprintf(buf, size, "%+4.2F%%", diff); |
900 | scnprintf(buf, size, "%+4.2F%%", diff); | ||
901 | break; | 957 | break; |
902 | 958 | ||
903 | case PERF_HPP_DIFF__RATIO: | 959 | case PERF_HPP_DIFF__RATIO: |
904 | /* No point for ratio number if we are dummy.. */ | 960 | /* No point for ratio number if we are dummy.. */ |
905 | if (he->dummy) | 961 | if (he->dummy) { |
962 | scnprintf(buf, size, "N/A"); | ||
906 | break; | 963 | break; |
964 | } | ||
907 | 965 | ||
908 | if (pair->diff.computed) | 966 | if (pair->diff.computed) |
909 | ratio = pair->diff.period_ratio; | 967 | ratio = pair->diff.period_ratio; |
@@ -916,8 +974,10 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, | |||
916 | 974 | ||
917 | case PERF_HPP_DIFF__WEIGHTED_DIFF: | 975 | case PERF_HPP_DIFF__WEIGHTED_DIFF: |
918 | /* No point for wdiff number if we are dummy.. */ | 976 | /* No point for wdiff number if we are dummy.. */ |
919 | if (he->dummy) | 977 | if (he->dummy) { |
978 | scnprintf(buf, size, "N/A"); | ||
920 | break; | 979 | break; |
980 | } | ||
921 | 981 | ||
922 | if (pair->diff.computed) | 982 | if (pair->diff.computed) |
923 | wdiff = pair->diff.wdiff; | 983 | wdiff = pair->diff.wdiff; |
@@ -1038,32 +1098,41 @@ static void data__hpp_register(struct data__file *d, int idx) | |||
1038 | fmt->header = hpp__header; | 1098 | fmt->header = hpp__header; |
1039 | fmt->width = hpp__width; | 1099 | fmt->width = hpp__width; |
1040 | fmt->entry = hpp__entry_global; | 1100 | fmt->entry = hpp__entry_global; |
1101 | fmt->cmp = hist_entry__cmp_nop; | ||
1102 | fmt->collapse = hist_entry__cmp_nop; | ||
1041 | 1103 | ||
1042 | /* TODO more colors */ | 1104 | /* TODO more colors */ |
1043 | switch (idx) { | 1105 | switch (idx) { |
1044 | case PERF_HPP_DIFF__BASELINE: | 1106 | case PERF_HPP_DIFF__BASELINE: |
1045 | fmt->color = hpp__color_baseline; | 1107 | fmt->color = hpp__color_baseline; |
1108 | fmt->sort = hist_entry__cmp_baseline; | ||
1046 | break; | 1109 | break; |
1047 | case PERF_HPP_DIFF__DELTA: | 1110 | case PERF_HPP_DIFF__DELTA: |
1048 | fmt->color = hpp__color_delta; | 1111 | fmt->color = hpp__color_delta; |
1112 | fmt->sort = hist_entry__cmp_delta; | ||
1049 | break; | 1113 | break; |
1050 | case PERF_HPP_DIFF__RATIO: | 1114 | case PERF_HPP_DIFF__RATIO: |
1051 | fmt->color = hpp__color_ratio; | 1115 | fmt->color = hpp__color_ratio; |
1116 | fmt->sort = hist_entry__cmp_ratio; | ||
1052 | break; | 1117 | break; |
1053 | case PERF_HPP_DIFF__WEIGHTED_DIFF: | 1118 | case PERF_HPP_DIFF__WEIGHTED_DIFF: |
1054 | fmt->color = hpp__color_wdiff; | 1119 | fmt->color = hpp__color_wdiff; |
1120 | fmt->sort = hist_entry__cmp_wdiff; | ||
1055 | break; | 1121 | break; |
1056 | default: | 1122 | default: |
1123 | fmt->sort = hist_entry__cmp_nop; | ||
1057 | break; | 1124 | break; |
1058 | } | 1125 | } |
1059 | 1126 | ||
1060 | init_header(d, dfmt); | 1127 | init_header(d, dfmt); |
1061 | perf_hpp__column_register(fmt); | 1128 | perf_hpp__column_register(fmt); |
1129 | perf_hpp__register_sort_field(fmt); | ||
1062 | } | 1130 | } |
1063 | 1131 | ||
1064 | static void ui_init(void) | 1132 | static int ui_init(void) |
1065 | { | 1133 | { |
1066 | struct data__file *d; | 1134 | struct data__file *d; |
1135 | struct perf_hpp_fmt *fmt; | ||
1067 | int i; | 1136 | int i; |
1068 | 1137 | ||
1069 | data__for_each_file(i, d) { | 1138 | data__for_each_file(i, d) { |
@@ -1093,6 +1162,46 @@ static void ui_init(void) | |||
1093 | data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD : | 1162 | data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD : |
1094 | PERF_HPP_DIFF__PERIOD_BASELINE); | 1163 | PERF_HPP_DIFF__PERIOD_BASELINE); |
1095 | } | 1164 | } |
1165 | |||
1166 | if (!sort_compute) | ||
1167 | return 0; | ||
1168 | |||
1169 | /* | ||
1170 | * Prepend an fmt to sort on columns at 'sort_compute' first. | ||
1171 | * This fmt is added only to the sort list but not to the | ||
1172 | * output fields list. | ||
1173 | * | ||
1174 | * Note that this column (data) can be compared twice - one | ||
1175 | * for this 'sort_compute' fmt and another for the normal | ||
1176 | * diff_hpp_fmt. But it shouldn't a problem as most entries | ||
1177 | * will be sorted out by first try or baseline and comparing | ||
1178 | * is not a costly operation. | ||
1179 | */ | ||
1180 | fmt = zalloc(sizeof(*fmt)); | ||
1181 | if (fmt == NULL) { | ||
1182 | pr_err("Memory allocation failed\n"); | ||
1183 | return -1; | ||
1184 | } | ||
1185 | |||
1186 | fmt->cmp = hist_entry__cmp_nop; | ||
1187 | fmt->collapse = hist_entry__cmp_nop; | ||
1188 | |||
1189 | switch (compute) { | ||
1190 | case COMPUTE_DELTA: | ||
1191 | fmt->sort = hist_entry__cmp_delta_idx; | ||
1192 | break; | ||
1193 | case COMPUTE_RATIO: | ||
1194 | fmt->sort = hist_entry__cmp_ratio_idx; | ||
1195 | break; | ||
1196 | case COMPUTE_WEIGHTED_DIFF: | ||
1197 | fmt->sort = hist_entry__cmp_wdiff_idx; | ||
1198 | break; | ||
1199 | default: | ||
1200 | BUG_ON(1); | ||
1201 | } | ||
1202 | |||
1203 | list_add(&fmt->sort_list, &perf_hpp__sort_list); | ||
1204 | return 0; | ||
1096 | } | 1205 | } |
1097 | 1206 | ||
1098 | static int data_init(int argc, const char **argv) | 1207 | static int data_init(int argc, const char **argv) |
@@ -1158,7 +1267,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1158 | if (data_init(argc, argv) < 0) | 1267 | if (data_init(argc, argv) < 0) |
1159 | return -1; | 1268 | return -1; |
1160 | 1269 | ||
1161 | ui_init(); | 1270 | if (ui_init() < 0) |
1271 | return -1; | ||
1162 | 1272 | ||
1163 | sort__mode = SORT_MODE__DIFF; | 1273 | sort__mode = SORT_MODE__DIFF; |
1164 | 1274 | ||
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 84df2deed988..a13641e066f5 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -343,6 +343,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
343 | int ret = -EINVAL; | 343 | int ret = -EINVAL; |
344 | struct perf_session *session = inject->session; | 344 | struct perf_session *session = inject->session; |
345 | struct perf_data_file *file_out = &inject->output; | 345 | struct perf_data_file *file_out = &inject->output; |
346 | int fd = perf_data_file__fd(file_out); | ||
346 | 347 | ||
347 | signal(SIGINT, sig_handler); | 348 | signal(SIGINT, sig_handler); |
348 | 349 | ||
@@ -376,7 +377,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
376 | } | 377 | } |
377 | 378 | ||
378 | if (!file_out->is_pipe) | 379 | if (!file_out->is_pipe) |
379 | lseek(file_out->fd, session->header.data_offset, SEEK_SET); | 380 | lseek(fd, session->header.data_offset, SEEK_SET); |
380 | 381 | ||
381 | ret = perf_session__process_events(session, &inject->tool); | 382 | ret = perf_session__process_events(session, &inject->tool); |
382 | 383 | ||
@@ -385,7 +386,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
385 | perf_header__set_feat(&session->header, | 386 | perf_header__set_feat(&session->header, |
386 | HEADER_BUILD_ID); | 387 | HEADER_BUILD_ID); |
387 | session->header.data_size = inject->bytes_written; | 388 | session->header.data_size = inject->bytes_written; |
388 | perf_session__write_header(session, session->evlist, file_out->fd, true); | 389 | perf_session__write_header(session, session->evlist, fd, true); |
389 | } | 390 | } |
390 | 391 | ||
391 | return ret; | 392 | return ret; |
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 011195e38f21..198f3c3aff95 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c | |||
@@ -19,7 +19,9 @@ | |||
19 | int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | 19 | int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) |
20 | { | 20 | { |
21 | int i; | 21 | int i; |
22 | const struct option list_options[] = { | 22 | bool raw_dump = false; |
23 | struct option list_options[] = { | ||
24 | OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), | ||
23 | OPT_END() | 25 | OPT_END() |
24 | }; | 26 | }; |
25 | const char * const list_usage[] = { | 27 | const char * const list_usage[] = { |
@@ -27,11 +29,18 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
27 | NULL | 29 | NULL |
28 | }; | 30 | }; |
29 | 31 | ||
32 | set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN); | ||
33 | |||
30 | argc = parse_options(argc, argv, list_options, list_usage, | 34 | argc = parse_options(argc, argv, list_options, list_usage, |
31 | PARSE_OPT_STOP_AT_NON_OPTION); | 35 | PARSE_OPT_STOP_AT_NON_OPTION); |
32 | 36 | ||
33 | setup_pager(); | 37 | setup_pager(); |
34 | 38 | ||
39 | if (raw_dump) { | ||
40 | print_events(NULL, true); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
35 | if (argc == 0) { | 44 | if (argc == 0) { |
36 | print_events(NULL, false); | 45 | print_events(NULL, false); |
37 | return 0; | 46 | return 0; |
@@ -53,8 +62,6 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
53 | print_hwcache_events(NULL, false); | 62 | print_hwcache_events(NULL, false); |
54 | else if (strcmp(argv[i], "pmu") == 0) | 63 | else if (strcmp(argv[i], "pmu") == 0) |
55 | print_pmu_events(NULL, false); | 64 | print_pmu_events(NULL, false); |
56 | else if (strcmp(argv[i], "--raw-dump") == 0) | ||
57 | print_events(NULL, true); | ||
58 | else { | 65 | else { |
59 | char *sep = strchr(argv[i], ':'), *s; | 66 | char *sep = strchr(argv[i], ':'), *s; |
60 | int sep_idx; | 67 | int sep_idx; |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 24db6ffe2957..9b5663950a4d 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -7,44 +7,47 @@ | |||
7 | #include "util/session.h" | 7 | #include "util/session.h" |
8 | #include "util/data.h" | 8 | #include "util/data.h" |
9 | 9 | ||
10 | #define MEM_OPERATION_LOAD "load" | 10 | #define MEM_OPERATION_LOAD 0x1 |
11 | #define MEM_OPERATION_STORE "store" | 11 | #define MEM_OPERATION_STORE 0x2 |
12 | |||
13 | static const char *mem_operation = MEM_OPERATION_LOAD; | ||
14 | 12 | ||
15 | struct perf_mem { | 13 | struct perf_mem { |
16 | struct perf_tool tool; | 14 | struct perf_tool tool; |
17 | char const *input_name; | 15 | char const *input_name; |
18 | bool hide_unresolved; | 16 | bool hide_unresolved; |
19 | bool dump_raw; | 17 | bool dump_raw; |
18 | int operation; | ||
20 | const char *cpu_list; | 19 | const char *cpu_list; |
21 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 20 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
22 | }; | 21 | }; |
23 | 22 | ||
24 | static int __cmd_record(int argc, const char **argv) | 23 | static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) |
25 | { | 24 | { |
26 | int rec_argc, i = 0, j; | 25 | int rec_argc, i = 0, j; |
27 | const char **rec_argv; | 26 | const char **rec_argv; |
28 | char event[64]; | ||
29 | int ret; | 27 | int ret; |
30 | 28 | ||
31 | rec_argc = argc + 4; | 29 | rec_argc = argc + 7; /* max number of arguments */ |
32 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 30 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
33 | if (!rec_argv) | 31 | if (!rec_argv) |
34 | return -1; | 32 | return -1; |
35 | 33 | ||
36 | rec_argv[i++] = strdup("record"); | 34 | rec_argv[i++] = "record"; |
37 | if (!strcmp(mem_operation, MEM_OPERATION_LOAD)) | ||
38 | rec_argv[i++] = strdup("-W"); | ||
39 | rec_argv[i++] = strdup("-d"); | ||
40 | rec_argv[i++] = strdup("-e"); | ||
41 | 35 | ||
42 | if (strcmp(mem_operation, MEM_OPERATION_LOAD)) | 36 | if (mem->operation & MEM_OPERATION_LOAD) |
43 | sprintf(event, "cpu/mem-stores/pp"); | 37 | rec_argv[i++] = "-W"; |
44 | else | 38 | |
45 | sprintf(event, "cpu/mem-loads/pp"); | 39 | rec_argv[i++] = "-d"; |
40 | |||
41 | if (mem->operation & MEM_OPERATION_LOAD) { | ||
42 | rec_argv[i++] = "-e"; | ||
43 | rec_argv[i++] = "cpu/mem-loads/pp"; | ||
44 | } | ||
45 | |||
46 | if (mem->operation & MEM_OPERATION_STORE) { | ||
47 | rec_argv[i++] = "-e"; | ||
48 | rec_argv[i++] = "cpu/mem-stores/pp"; | ||
49 | } | ||
46 | 50 | ||
47 | rec_argv[i++] = strdup(event); | ||
48 | for (j = 1; j < argc; j++, i++) | 51 | for (j = 1; j < argc; j++, i++) |
49 | rec_argv[i] = argv[j]; | 52 | rec_argv[i] = argv[j]; |
50 | 53 | ||
@@ -162,17 +165,17 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem) | |||
162 | if (!rep_argv) | 165 | if (!rep_argv) |
163 | return -1; | 166 | return -1; |
164 | 167 | ||
165 | rep_argv[i++] = strdup("report"); | 168 | rep_argv[i++] = "report"; |
166 | rep_argv[i++] = strdup("--mem-mode"); | 169 | rep_argv[i++] = "--mem-mode"; |
167 | rep_argv[i++] = strdup("-n"); /* display number of samples */ | 170 | rep_argv[i++] = "-n"; /* display number of samples */ |
168 | 171 | ||
169 | /* | 172 | /* |
170 | * there is no weight (cost) associated with stores, so don't print | 173 | * there is no weight (cost) associated with stores, so don't print |
171 | * the column | 174 | * the column |
172 | */ | 175 | */ |
173 | if (strcmp(mem_operation, MEM_OPERATION_LOAD)) | 176 | if (!(mem->operation & MEM_OPERATION_LOAD)) |
174 | rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr," | 177 | rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," |
175 | "dso_daddr,tlb,locked"); | 178 | "dso_daddr,tlb,locked"; |
176 | 179 | ||
177 | for (j = 1; j < argc; j++, i++) | 180 | for (j = 1; j < argc; j++, i++) |
178 | rep_argv[i] = argv[j]; | 181 | rep_argv[i] = argv[j]; |
@@ -182,6 +185,75 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem) | |||
182 | return ret; | 185 | return ret; |
183 | } | 186 | } |
184 | 187 | ||
188 | struct mem_mode { | ||
189 | const char *name; | ||
190 | int mode; | ||
191 | }; | ||
192 | |||
193 | #define MEM_OPT(n, m) \ | ||
194 | { .name = n, .mode = (m) } | ||
195 | |||
196 | #define MEM_END { .name = NULL } | ||
197 | |||
198 | static const struct mem_mode mem_modes[]={ | ||
199 | MEM_OPT("load", MEM_OPERATION_LOAD), | ||
200 | MEM_OPT("store", MEM_OPERATION_STORE), | ||
201 | MEM_END | ||
202 | }; | ||
203 | |||
204 | static int | ||
205 | parse_mem_ops(const struct option *opt, const char *str, int unset) | ||
206 | { | ||
207 | int *mode = (int *)opt->value; | ||
208 | const struct mem_mode *m; | ||
209 | char *s, *os = NULL, *p; | ||
210 | int ret = -1; | ||
211 | |||
212 | if (unset) | ||
213 | return 0; | ||
214 | |||
215 | /* str may be NULL in case no arg is passed to -t */ | ||
216 | if (str) { | ||
217 | /* because str is read-only */ | ||
218 | s = os = strdup(str); | ||
219 | if (!s) | ||
220 | return -1; | ||
221 | |||
222 | /* reset mode */ | ||
223 | *mode = 0; | ||
224 | |||
225 | for (;;) { | ||
226 | p = strchr(s, ','); | ||
227 | if (p) | ||
228 | *p = '\0'; | ||
229 | |||
230 | for (m = mem_modes; m->name; m++) { | ||
231 | if (!strcasecmp(s, m->name)) | ||
232 | break; | ||
233 | } | ||
234 | if (!m->name) { | ||
235 | fprintf(stderr, "unknown sampling op %s," | ||
236 | " check man page\n", s); | ||
237 | goto error; | ||
238 | } | ||
239 | |||
240 | *mode |= m->mode; | ||
241 | |||
242 | if (!p) | ||
243 | break; | ||
244 | |||
245 | s = p + 1; | ||
246 | } | ||
247 | } | ||
248 | ret = 0; | ||
249 | |||
250 | if (*mode == 0) | ||
251 | *mode = MEM_OPERATION_LOAD; | ||
252 | error: | ||
253 | free(os); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
185 | int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | 257 | int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) |
186 | { | 258 | { |
187 | struct stat st; | 259 | struct stat st; |
@@ -197,10 +269,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
197 | .ordered_events = true, | 269 | .ordered_events = true, |
198 | }, | 270 | }, |
199 | .input_name = "perf.data", | 271 | .input_name = "perf.data", |
272 | /* | ||
273 | * default to both load an store sampling | ||
274 | */ | ||
275 | .operation = MEM_OPERATION_LOAD | MEM_OPERATION_STORE, | ||
200 | }; | 276 | }; |
201 | const struct option mem_options[] = { | 277 | const struct option mem_options[] = { |
202 | OPT_STRING('t', "type", &mem_operation, | 278 | OPT_CALLBACK('t', "type", &mem.operation, |
203 | "type", "memory operations(load/store)"), | 279 | "type", "memory operations(load,store) Default load,store", |
280 | parse_mem_ops), | ||
204 | OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw, | 281 | OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw, |
205 | "dump raw samples in ASCII"), | 282 | "dump raw samples in ASCII"), |
206 | OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved, | 283 | OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved, |
@@ -225,7 +302,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
225 | argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, | 302 | argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, |
226 | mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); | 303 | mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
227 | 304 | ||
228 | if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) | 305 | if (!argc || !(strncmp(argv[0], "rec", 3) || mem.operation)) |
229 | usage_with_options(mem_usage, mem_options); | 306 | usage_with_options(mem_usage, mem_options); |
230 | 307 | ||
231 | if (!mem.input_name || !strlen(mem.input_name)) { | 308 | if (!mem.input_name || !strlen(mem.input_name)) { |
@@ -236,7 +313,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
236 | } | 313 | } |
237 | 314 | ||
238 | if (!strncmp(argv[0], "rec", 3)) | 315 | if (!strncmp(argv[0], "rec", 3)) |
239 | return __cmd_record(argc, argv); | 316 | return __cmd_record(argc, argv, &mem); |
240 | else if (!strncmp(argv[0], "rep", 3)) | 317 | else if (!strncmp(argv[0], "rep", 3)) |
241 | return report_events(argc, argv, &mem); | 318 | return report_events(argc, argv, &mem); |
242 | else | 319 | else |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8648c6d3003d..404ab3434052 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -190,16 +190,30 @@ out: | |||
190 | return rc; | 190 | return rc; |
191 | } | 191 | } |
192 | 192 | ||
193 | static int process_sample_event(struct perf_tool *tool, | ||
194 | union perf_event *event, | ||
195 | struct perf_sample *sample, | ||
196 | struct perf_evsel *evsel, | ||
197 | struct machine *machine) | ||
198 | { | ||
199 | struct record *rec = container_of(tool, struct record, tool); | ||
200 | |||
201 | rec->samples++; | ||
202 | |||
203 | return build_id__mark_dso_hit(tool, event, sample, evsel, machine); | ||
204 | } | ||
205 | |||
193 | static int process_buildids(struct record *rec) | 206 | static int process_buildids(struct record *rec) |
194 | { | 207 | { |
195 | struct perf_data_file *file = &rec->file; | 208 | struct perf_data_file *file = &rec->file; |
196 | struct perf_session *session = rec->session; | 209 | struct perf_session *session = rec->session; |
197 | u64 start = session->header.data_offset; | ||
198 | 210 | ||
199 | u64 size = lseek(file->fd, 0, SEEK_CUR); | 211 | u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); |
200 | if (size == 0) | 212 | if (size == 0) |
201 | return 0; | 213 | return 0; |
202 | 214 | ||
215 | file->size = size; | ||
216 | |||
203 | /* | 217 | /* |
204 | * During this process, it'll load kernel map and replace the | 218 | * During this process, it'll load kernel map and replace the |
205 | * dso->long_name to a real pathname it found. In this case | 219 | * dso->long_name to a real pathname it found. In this case |
@@ -211,9 +225,7 @@ static int process_buildids(struct record *rec) | |||
211 | */ | 225 | */ |
212 | symbol_conf.ignore_vmlinux_buildid = true; | 226 | symbol_conf.ignore_vmlinux_buildid = true; |
213 | 227 | ||
214 | return __perf_session__process_events(session, start, | 228 | return perf_session__process_events(session, &rec->tool); |
215 | size - start, | ||
216 | size, &build_id__mark_dso_hit_ops); | ||
217 | } | 229 | } |
218 | 230 | ||
219 | static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | 231 | static void perf_event__synthesize_guest_os(struct machine *machine, void *data) |
@@ -322,6 +334,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
322 | struct perf_data_file *file = &rec->file; | 334 | struct perf_data_file *file = &rec->file; |
323 | struct perf_session *session; | 335 | struct perf_session *session; |
324 | bool disabled = false, draining = false; | 336 | bool disabled = false, draining = false; |
337 | int fd; | ||
325 | 338 | ||
326 | rec->progname = argv[0]; | 339 | rec->progname = argv[0]; |
327 | 340 | ||
@@ -336,6 +349,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
336 | return -1; | 349 | return -1; |
337 | } | 350 | } |
338 | 351 | ||
352 | fd = perf_data_file__fd(file); | ||
339 | rec->session = session; | 353 | rec->session = session; |
340 | 354 | ||
341 | record__init_features(rec); | 355 | record__init_features(rec); |
@@ -360,12 +374,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
360 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); | 374 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); |
361 | 375 | ||
362 | if (file->is_pipe) { | 376 | if (file->is_pipe) { |
363 | err = perf_header__write_pipe(file->fd); | 377 | err = perf_header__write_pipe(fd); |
364 | if (err < 0) | 378 | if (err < 0) |
365 | goto out_child; | 379 | goto out_child; |
366 | } else { | 380 | } else { |
367 | err = perf_session__write_header(session, rec->evlist, | 381 | err = perf_session__write_header(session, rec->evlist, fd, false); |
368 | file->fd, false); | ||
369 | if (err < 0) | 382 | if (err < 0) |
370 | goto out_child; | 383 | goto out_child; |
371 | } | 384 | } |
@@ -397,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
397 | * return this more properly and also | 410 | * return this more properly and also |
398 | * propagate errors that now are calling die() | 411 | * propagate errors that now are calling die() |
399 | */ | 412 | */ |
400 | err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, | 413 | err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist, |
401 | process_synthesized_event); | 414 | process_synthesized_event); |
402 | if (err <= 0) { | 415 | if (err <= 0) { |
403 | pr_err("Couldn't record tracing data.\n"); | 416 | pr_err("Couldn't record tracing data.\n"); |
@@ -504,19 +517,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
504 | goto out_child; | 517 | goto out_child; |
505 | } | 518 | } |
506 | 519 | ||
507 | if (!quiet) { | 520 | if (!quiet) |
508 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); | 521 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); |
509 | 522 | ||
510 | /* | ||
511 | * Approximate RIP event size: 24 bytes. | ||
512 | */ | ||
513 | fprintf(stderr, | ||
514 | "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", | ||
515 | (double)rec->bytes_written / 1024.0 / 1024.0, | ||
516 | file->path, | ||
517 | rec->bytes_written / 24); | ||
518 | } | ||
519 | |||
520 | out_child: | 523 | out_child: |
521 | if (forks) { | 524 | if (forks) { |
522 | int exit_status; | 525 | int exit_status; |
@@ -535,13 +538,29 @@ out_child: | |||
535 | } else | 538 | } else |
536 | status = err; | 539 | status = err; |
537 | 540 | ||
541 | /* this will be recalculated during process_buildids() */ | ||
542 | rec->samples = 0; | ||
543 | |||
538 | if (!err && !file->is_pipe) { | 544 | if (!err && !file->is_pipe) { |
539 | rec->session->header.data_size += rec->bytes_written; | 545 | rec->session->header.data_size += rec->bytes_written; |
540 | 546 | ||
541 | if (!rec->no_buildid) | 547 | if (!rec->no_buildid) |
542 | process_buildids(rec); | 548 | process_buildids(rec); |
543 | perf_session__write_header(rec->session, rec->evlist, | 549 | perf_session__write_header(rec->session, rec->evlist, fd, true); |
544 | file->fd, true); | 550 | } |
551 | |||
552 | if (!err && !quiet) { | ||
553 | char samples[128]; | ||
554 | |||
555 | if (rec->samples) | ||
556 | scnprintf(samples, sizeof(samples), | ||
557 | " (%" PRIu64 " samples)", rec->samples); | ||
558 | else | ||
559 | samples[0] = '\0'; | ||
560 | |||
561 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n", | ||
562 | perf_data_file__size(file) / 1024.0 / 1024.0, | ||
563 | file->path, samples); | ||
545 | } | 564 | } |
546 | 565 | ||
547 | out_delete_session: | 566 | out_delete_session: |
@@ -720,6 +739,13 @@ static struct record record = { | |||
720 | .default_per_cpu = true, | 739 | .default_per_cpu = true, |
721 | }, | 740 | }, |
722 | }, | 741 | }, |
742 | .tool = { | ||
743 | .sample = process_sample_event, | ||
744 | .fork = perf_event__process_fork, | ||
745 | .comm = perf_event__process_comm, | ||
746 | .mmap = perf_event__process_mmap, | ||
747 | .mmap2 = perf_event__process_mmap2, | ||
748 | }, | ||
723 | }; | 749 | }; |
724 | 750 | ||
725 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " | 751 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 39367609c707..2f91094e228b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -86,17 +86,6 @@ static int report__config(const char *var, const char *value, void *cb) | |||
86 | return perf_default_config(var, value, cb); | 86 | return perf_default_config(var, value, cb); |
87 | } | 87 | } |
88 | 88 | ||
89 | static void report__inc_stats(struct report *rep, struct hist_entry *he) | ||
90 | { | ||
91 | /* | ||
92 | * The @he is either of a newly created one or an existing one | ||
93 | * merging current sample. We only want to count a new one so | ||
94 | * checking ->nr_events being 1. | ||
95 | */ | ||
96 | if (he->stat.nr_events == 1) | ||
97 | rep->nr_entries++; | ||
98 | } | ||
99 | |||
100 | static int hist_iter__report_callback(struct hist_entry_iter *iter, | 89 | static int hist_iter__report_callback(struct hist_entry_iter *iter, |
101 | struct addr_location *al, bool single, | 90 | struct addr_location *al, bool single, |
102 | void *arg) | 91 | void *arg) |
@@ -108,8 +97,6 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, | |||
108 | struct mem_info *mi; | 97 | struct mem_info *mi; |
109 | struct branch_info *bi; | 98 | struct branch_info *bi; |
110 | 99 | ||
111 | report__inc_stats(rep, he); | ||
112 | |||
113 | if (!ui__has_annotation()) | 100 | if (!ui__has_annotation()) |
114 | return 0; | 101 | return 0; |
115 | 102 | ||
@@ -457,6 +444,19 @@ static void report__collapse_hists(struct report *rep) | |||
457 | ui_progress__finish(); | 444 | ui_progress__finish(); |
458 | } | 445 | } |
459 | 446 | ||
447 | static void report__output_resort(struct report *rep) | ||
448 | { | ||
449 | struct ui_progress prog; | ||
450 | struct perf_evsel *pos; | ||
451 | |||
452 | ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); | ||
453 | |||
454 | evlist__for_each(rep->session->evlist, pos) | ||
455 | hists__output_resort(evsel__hists(pos), &prog); | ||
456 | |||
457 | ui_progress__finish(); | ||
458 | } | ||
459 | |||
460 | static int __cmd_report(struct report *rep) | 460 | static int __cmd_report(struct report *rep) |
461 | { | 461 | { |
462 | int ret; | 462 | int ret; |
@@ -486,6 +486,9 @@ static int __cmd_report(struct report *rep) | |||
486 | 486 | ||
487 | report__warn_kptr_restrict(rep); | 487 | report__warn_kptr_restrict(rep); |
488 | 488 | ||
489 | evlist__for_each(session->evlist, pos) | ||
490 | rep->nr_entries += evsel__hists(pos)->nr_entries; | ||
491 | |||
489 | if (use_browser == 0) { | 492 | if (use_browser == 0) { |
490 | if (verbose > 3) | 493 | if (verbose > 3) |
491 | perf_session__fprintf(session, stdout); | 494 | perf_session__fprintf(session, stdout); |
@@ -505,13 +508,20 @@ static int __cmd_report(struct report *rep) | |||
505 | if (session_done()) | 508 | if (session_done()) |
506 | return 0; | 509 | return 0; |
507 | 510 | ||
511 | /* | ||
512 | * recalculate number of entries after collapsing since it | ||
513 | * might be changed during the collapse phase. | ||
514 | */ | ||
515 | rep->nr_entries = 0; | ||
516 | evlist__for_each(session->evlist, pos) | ||
517 | rep->nr_entries += evsel__hists(pos)->nr_entries; | ||
518 | |||
508 | if (rep->nr_entries == 0) { | 519 | if (rep->nr_entries == 0) { |
509 | ui__error("The %s file has no samples!\n", file->path); | 520 | ui__error("The %s file has no samples!\n", file->path); |
510 | return 0; | 521 | return 0; |
511 | } | 522 | } |
512 | 523 | ||
513 | evlist__for_each(session->evlist, pos) | 524 | report__output_resort(rep); |
514 | hists__output_resort(evsel__hists(pos)); | ||
515 | 525 | ||
516 | return report__browse_hists(rep); | 526 | return report__browse_hists(rep); |
517 | } | 527 | } |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 891086376381..e598e4e98170 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1730,7 +1730,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1730 | "detailed run - start a lot of events"), | 1730 | "detailed run - start a lot of events"), |
1731 | OPT_BOOLEAN('S', "sync", &sync_run, | 1731 | OPT_BOOLEAN('S', "sync", &sync_run, |
1732 | "call sync() before starting a run"), | 1732 | "call sync() before starting a run"), |
1733 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | 1733 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, |
1734 | "print large numbers with thousands\' separators", | 1734 | "print large numbers with thousands\' separators", |
1735 | stat__set_big_num), | 1735 | stat__set_big_num), |
1736 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | 1736 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0aa7747ff139..c4c7eac69de4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -66,7 +66,6 @@ | |||
66 | #include <sys/utsname.h> | 66 | #include <sys/utsname.h> |
67 | #include <sys/mman.h> | 67 | #include <sys/mman.h> |
68 | 68 | ||
69 | #include <linux/unistd.h> | ||
70 | #include <linux/types.h> | 69 | #include <linux/types.h> |
71 | 70 | ||
72 | static volatile int done; | 71 | static volatile int done; |
@@ -166,7 +165,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) | |||
166 | err ? "[unknown]" : uts.release, perf_version_string); | 165 | err ? "[unknown]" : uts.release, perf_version_string); |
167 | if (use_browser <= 0) | 166 | if (use_browser <= 0) |
168 | sleep(5); | 167 | sleep(5); |
169 | 168 | ||
170 | map->erange_warned = true; | 169 | map->erange_warned = true; |
171 | } | 170 | } |
172 | 171 | ||
@@ -285,7 +284,7 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
285 | } | 284 | } |
286 | 285 | ||
287 | hists__collapse_resort(hists, NULL); | 286 | hists__collapse_resort(hists, NULL); |
288 | hists__output_resort(hists); | 287 | hists__output_resort(hists, NULL); |
289 | 288 | ||
290 | hists__output_recalc_col_len(hists, top->print_entries - printed); | 289 | hists__output_recalc_col_len(hists, top->print_entries - printed); |
291 | putchar('\n'); | 290 | putchar('\n'); |
@@ -554,7 +553,7 @@ static void perf_top__sort_new_samples(void *arg) | |||
554 | } | 553 | } |
555 | 554 | ||
556 | hists__collapse_resort(hists, NULL); | 555 | hists__collapse_resort(hists, NULL); |
557 | hists__output_resort(hists); | 556 | hists__output_resort(hists, NULL); |
558 | } | 557 | } |
559 | 558 | ||
560 | static void *display_thread_tui(void *arg) | 559 | static void *display_thread_tui(void *arg) |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index badfabc6a01f..7e935f1083ec 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -929,66 +929,66 @@ static struct syscall_fmt { | |||
929 | .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, | 929 | .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, |
930 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, | 930 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, |
931 | { .name = "close", .errmsg = true, | 931 | { .name = "close", .errmsg = true, |
932 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, | 932 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, |
933 | { .name = "connect", .errmsg = true, }, | 933 | { .name = "connect", .errmsg = true, }, |
934 | { .name = "dup", .errmsg = true, | 934 | { .name = "dup", .errmsg = true, |
935 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 935 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
936 | { .name = "dup2", .errmsg = true, | 936 | { .name = "dup2", .errmsg = true, |
937 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 937 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
938 | { .name = "dup3", .errmsg = true, | 938 | { .name = "dup3", .errmsg = true, |
939 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 939 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
940 | { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), }, | 940 | { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), }, |
941 | { .name = "eventfd2", .errmsg = true, | 941 | { .name = "eventfd2", .errmsg = true, |
942 | .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, | 942 | .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, |
943 | { .name = "faccessat", .errmsg = true, | 943 | { .name = "faccessat", .errmsg = true, |
944 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 944 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
945 | { .name = "fadvise64", .errmsg = true, | 945 | { .name = "fadvise64", .errmsg = true, |
946 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 946 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
947 | { .name = "fallocate", .errmsg = true, | 947 | { .name = "fallocate", .errmsg = true, |
948 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 948 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
949 | { .name = "fchdir", .errmsg = true, | 949 | { .name = "fchdir", .errmsg = true, |
950 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 950 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
951 | { .name = "fchmod", .errmsg = true, | 951 | { .name = "fchmod", .errmsg = true, |
952 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 952 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
953 | { .name = "fchmodat", .errmsg = true, | 953 | { .name = "fchmodat", .errmsg = true, |
954 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 954 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
955 | { .name = "fchown", .errmsg = true, | 955 | { .name = "fchown", .errmsg = true, |
956 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 956 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
957 | { .name = "fchownat", .errmsg = true, | 957 | { .name = "fchownat", .errmsg = true, |
958 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 958 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
959 | { .name = "fcntl", .errmsg = true, | 959 | { .name = "fcntl", .errmsg = true, |
960 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 960 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
961 | [1] = SCA_STRARRAY, /* cmd */ }, | 961 | [1] = SCA_STRARRAY, /* cmd */ }, |
962 | .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, | 962 | .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, |
963 | { .name = "fdatasync", .errmsg = true, | 963 | { .name = "fdatasync", .errmsg = true, |
964 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 964 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
965 | { .name = "flock", .errmsg = true, | 965 | { .name = "flock", .errmsg = true, |
966 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 966 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
967 | [1] = SCA_FLOCK, /* cmd */ }, }, | 967 | [1] = SCA_FLOCK, /* cmd */ }, }, |
968 | { .name = "fsetxattr", .errmsg = true, | 968 | { .name = "fsetxattr", .errmsg = true, |
969 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 969 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
970 | { .name = "fstat", .errmsg = true, .alias = "newfstat", | 970 | { .name = "fstat", .errmsg = true, .alias = "newfstat", |
971 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 971 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
972 | { .name = "fstatat", .errmsg = true, .alias = "newfstatat", | 972 | { .name = "fstatat", .errmsg = true, .alias = "newfstatat", |
973 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 973 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
974 | { .name = "fstatfs", .errmsg = true, | 974 | { .name = "fstatfs", .errmsg = true, |
975 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 975 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
976 | { .name = "fsync", .errmsg = true, | 976 | { .name = "fsync", .errmsg = true, |
977 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 977 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
978 | { .name = "ftruncate", .errmsg = true, | 978 | { .name = "ftruncate", .errmsg = true, |
979 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 979 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
980 | { .name = "futex", .errmsg = true, | 980 | { .name = "futex", .errmsg = true, |
981 | .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, | 981 | .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, |
982 | { .name = "futimesat", .errmsg = true, | 982 | { .name = "futimesat", .errmsg = true, |
983 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 983 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
984 | { .name = "getdents", .errmsg = true, | 984 | { .name = "getdents", .errmsg = true, |
985 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 985 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
986 | { .name = "getdents64", .errmsg = true, | 986 | { .name = "getdents64", .errmsg = true, |
987 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 987 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
988 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 988 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
989 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 989 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
990 | { .name = "ioctl", .errmsg = true, | 990 | { .name = "ioctl", .errmsg = true, |
991 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 991 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
992 | #if defined(__i386__) || defined(__x86_64__) | 992 | #if defined(__i386__) || defined(__x86_64__) |
993 | /* | 993 | /* |
994 | * FIXME: Make this available to all arches. | 994 | * FIXME: Make this available to all arches. |
@@ -1002,7 +1002,7 @@ static struct syscall_fmt { | |||
1002 | { .name = "kill", .errmsg = true, | 1002 | { .name = "kill", .errmsg = true, |
1003 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, | 1003 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, |
1004 | { .name = "linkat", .errmsg = true, | 1004 | { .name = "linkat", .errmsg = true, |
1005 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 1005 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
1006 | { .name = "lseek", .errmsg = true, | 1006 | { .name = "lseek", .errmsg = true, |
1007 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 1007 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
1008 | [2] = SCA_STRARRAY, /* whence */ }, | 1008 | [2] = SCA_STRARRAY, /* whence */ }, |
@@ -1012,9 +1012,9 @@ static struct syscall_fmt { | |||
1012 | .arg_scnprintf = { [0] = SCA_HEX, /* start */ | 1012 | .arg_scnprintf = { [0] = SCA_HEX, /* start */ |
1013 | [2] = SCA_MADV_BHV, /* behavior */ }, }, | 1013 | [2] = SCA_MADV_BHV, /* behavior */ }, }, |
1014 | { .name = "mkdirat", .errmsg = true, | 1014 | { .name = "mkdirat", .errmsg = true, |
1015 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 1015 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
1016 | { .name = "mknodat", .errmsg = true, | 1016 | { .name = "mknodat", .errmsg = true, |
1017 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, | 1017 | .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, |
1018 | { .name = "mlock", .errmsg = true, | 1018 | { .name = "mlock", .errmsg = true, |
1019 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, | 1019 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, |
1020 | { .name = "mlockall", .errmsg = true, | 1020 | { .name = "mlockall", .errmsg = true, |
@@ -1036,9 +1036,9 @@ static struct syscall_fmt { | |||
1036 | { .name = "munmap", .errmsg = true, | 1036 | { .name = "munmap", .errmsg = true, |
1037 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, | 1037 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, |
1038 | { .name = "name_to_handle_at", .errmsg = true, | 1038 | { .name = "name_to_handle_at", .errmsg = true, |
1039 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 1039 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
1040 | { .name = "newfstatat", .errmsg = true, | 1040 | { .name = "newfstatat", .errmsg = true, |
1041 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 1041 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
1042 | { .name = "open", .errmsg = true, | 1042 | { .name = "open", .errmsg = true, |
1043 | .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, | 1043 | .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, |
1044 | { .name = "open_by_handle_at", .errmsg = true, | 1044 | { .name = "open_by_handle_at", .errmsg = true, |
@@ -1052,20 +1052,20 @@ static struct syscall_fmt { | |||
1052 | { .name = "poll", .errmsg = true, .timeout = true, }, | 1052 | { .name = "poll", .errmsg = true, .timeout = true, }, |
1053 | { .name = "ppoll", .errmsg = true, .timeout = true, }, | 1053 | { .name = "ppoll", .errmsg = true, .timeout = true, }, |
1054 | { .name = "pread", .errmsg = true, .alias = "pread64", | 1054 | { .name = "pread", .errmsg = true, .alias = "pread64", |
1055 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1055 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1056 | { .name = "preadv", .errmsg = true, .alias = "pread", | 1056 | { .name = "preadv", .errmsg = true, .alias = "pread", |
1057 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1057 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1058 | { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, | 1058 | { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, |
1059 | { .name = "pwrite", .errmsg = true, .alias = "pwrite64", | 1059 | { .name = "pwrite", .errmsg = true, .alias = "pwrite64", |
1060 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1060 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1061 | { .name = "pwritev", .errmsg = true, | 1061 | { .name = "pwritev", .errmsg = true, |
1062 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1062 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1063 | { .name = "read", .errmsg = true, | 1063 | { .name = "read", .errmsg = true, |
1064 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1064 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1065 | { .name = "readlinkat", .errmsg = true, | 1065 | { .name = "readlinkat", .errmsg = true, |
1066 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 1066 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
1067 | { .name = "readv", .errmsg = true, | 1067 | { .name = "readv", .errmsg = true, |
1068 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1068 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1069 | { .name = "recvfrom", .errmsg = true, | 1069 | { .name = "recvfrom", .errmsg = true, |
1070 | .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, | 1070 | .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, |
1071 | { .name = "recvmmsg", .errmsg = true, | 1071 | { .name = "recvmmsg", .errmsg = true, |
@@ -1073,7 +1073,7 @@ static struct syscall_fmt { | |||
1073 | { .name = "recvmsg", .errmsg = true, | 1073 | { .name = "recvmsg", .errmsg = true, |
1074 | .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, | 1074 | .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, |
1075 | { .name = "renameat", .errmsg = true, | 1075 | { .name = "renameat", .errmsg = true, |
1076 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 1076 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
1077 | { .name = "rt_sigaction", .errmsg = true, | 1077 | { .name = "rt_sigaction", .errmsg = true, |
1078 | .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, | 1078 | .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, |
1079 | { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, | 1079 | { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, |
@@ -1091,7 +1091,7 @@ static struct syscall_fmt { | |||
1091 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 1091 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
1092 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 1092 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
1093 | { .name = "shutdown", .errmsg = true, | 1093 | { .name = "shutdown", .errmsg = true, |
1094 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1094 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1095 | { .name = "socket", .errmsg = true, | 1095 | { .name = "socket", .errmsg = true, |
1096 | .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ | 1096 | .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ |
1097 | [1] = SCA_SK_TYPE, /* type */ }, | 1097 | [1] = SCA_SK_TYPE, /* type */ }, |
@@ -1102,7 +1102,7 @@ static struct syscall_fmt { | |||
1102 | .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, | 1102 | .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, |
1103 | { .name = "stat", .errmsg = true, .alias = "newstat", }, | 1103 | { .name = "stat", .errmsg = true, .alias = "newstat", }, |
1104 | { .name = "symlinkat", .errmsg = true, | 1104 | { .name = "symlinkat", .errmsg = true, |
1105 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, | 1105 | .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, |
1106 | { .name = "tgkill", .errmsg = true, | 1106 | { .name = "tgkill", .errmsg = true, |
1107 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, | 1107 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, |
1108 | { .name = "tkill", .errmsg = true, | 1108 | { .name = "tkill", .errmsg = true, |
@@ -1113,9 +1113,9 @@ static struct syscall_fmt { | |||
1113 | { .name = "utimensat", .errmsg = true, | 1113 | { .name = "utimensat", .errmsg = true, |
1114 | .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, | 1114 | .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, |
1115 | { .name = "write", .errmsg = true, | 1115 | { .name = "write", .errmsg = true, |
1116 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1116 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1117 | { .name = "writev", .errmsg = true, | 1117 | { .name = "writev", .errmsg = true, |
1118 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 1118 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1119 | }; | 1119 | }; |
1120 | 1120 | ||
1121 | static int syscall_fmt__cmp(const void *name, const void *fmtp) | 1121 | static int syscall_fmt__cmp(const void *name, const void *fmtp) |
@@ -1191,7 +1191,7 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) | |||
1191 | 1191 | ||
1192 | if (thread__priv(thread) == NULL) | 1192 | if (thread__priv(thread) == NULL) |
1193 | thread__set_priv(thread, thread_trace__new()); | 1193 | thread__set_priv(thread, thread_trace__new()); |
1194 | 1194 | ||
1195 | if (thread__priv(thread) == NULL) | 1195 | if (thread__priv(thread) == NULL) |
1196 | goto fail; | 1196 | goto fail; |
1197 | 1197 | ||
@@ -2056,23 +2056,24 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2056 | if (trace->trace_syscalls && | 2056 | if (trace->trace_syscalls && |
2057 | perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, | 2057 | perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, |
2058 | trace__sys_exit)) | 2058 | trace__sys_exit)) |
2059 | goto out_error_tp; | 2059 | goto out_error_raw_syscalls; |
2060 | 2060 | ||
2061 | if (trace->trace_syscalls) | 2061 | if (trace->trace_syscalls) |
2062 | perf_evlist__add_vfs_getname(evlist); | 2062 | perf_evlist__add_vfs_getname(evlist); |
2063 | 2063 | ||
2064 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && | 2064 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && |
2065 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) | 2065 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) { |
2066 | goto out_error_tp; | 2066 | goto out_error_mem; |
2067 | } | ||
2067 | 2068 | ||
2068 | if ((trace->trace_pgfaults & TRACE_PFMIN) && | 2069 | if ((trace->trace_pgfaults & TRACE_PFMIN) && |
2069 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) | 2070 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) |
2070 | goto out_error_tp; | 2071 | goto out_error_mem; |
2071 | 2072 | ||
2072 | if (trace->sched && | 2073 | if (trace->sched && |
2073 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", | 2074 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", |
2074 | trace__sched_stat_runtime)) | 2075 | trace__sched_stat_runtime)) |
2075 | goto out_error_tp; | 2076 | goto out_error_sched_stat_runtime; |
2076 | 2077 | ||
2077 | err = perf_evlist__create_maps(evlist, &trace->opts.target); | 2078 | err = perf_evlist__create_maps(evlist, &trace->opts.target); |
2078 | if (err < 0) { | 2079 | if (err < 0) { |
@@ -2202,8 +2203,12 @@ out: | |||
2202 | { | 2203 | { |
2203 | char errbuf[BUFSIZ]; | 2204 | char errbuf[BUFSIZ]; |
2204 | 2205 | ||
2205 | out_error_tp: | 2206 | out_error_sched_stat_runtime: |
2206 | perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf)); | 2207 | debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime"); |
2208 | goto out_error; | ||
2209 | |||
2210 | out_error_raw_syscalls: | ||
2211 | debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)"); | ||
2207 | goto out_error; | 2212 | goto out_error; |
2208 | 2213 | ||
2209 | out_error_mmap: | 2214 | out_error_mmap: |
@@ -2217,6 +2222,9 @@ out_error: | |||
2217 | fprintf(trace->output, "%s\n", errbuf); | 2222 | fprintf(trace->output, "%s\n", errbuf); |
2218 | goto out_delete_evlist; | 2223 | goto out_delete_evlist; |
2219 | } | 2224 | } |
2225 | out_error_mem: | ||
2226 | fprintf(trace->output, "Not enough memory to run!\n"); | ||
2227 | goto out_delete_evlist; | ||
2220 | } | 2228 | } |
2221 | 2229 | ||
2222 | static int trace__replay(struct trace *trace) | 2230 | static int trace__replay(struct trace *trace) |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 5d4b039fe1ed..cc224080b525 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -20,7 +20,7 @@ NO_PERF_REGS := 1 | |||
20 | 20 | ||
21 | # Additional ARCH settings for x86 | 21 | # Additional ARCH settings for x86 |
22 | ifeq ($(ARCH),x86) | 22 | ifeq ($(ARCH),x86) |
23 | ifeq (${IS_X86_64}, 1) | 23 | ifeq (${IS_64_BIT}, 1) |
24 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 24 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT |
25 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 25 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
26 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 26 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
@@ -198,6 +198,7 @@ CORE_FEATURE_TESTS = \ | |||
198 | libpython-version \ | 198 | libpython-version \ |
199 | libslang \ | 199 | libslang \ |
200 | libunwind \ | 200 | libunwind \ |
201 | pthread-attr-setaffinity-np \ | ||
201 | stackprotector-all \ | 202 | stackprotector-all \ |
202 | timerfd \ | 203 | timerfd \ |
203 | libdw-dwarf-unwind \ | 204 | libdw-dwarf-unwind \ |
@@ -226,6 +227,7 @@ VF_FEATURE_TESTS = \ | |||
226 | libelf-getphdrnum \ | 227 | libelf-getphdrnum \ |
227 | libelf-mmap \ | 228 | libelf-mmap \ |
228 | libpython-version \ | 229 | libpython-version \ |
230 | pthread-attr-setaffinity-np \ | ||
229 | stackprotector-all \ | 231 | stackprotector-all \ |
230 | timerfd \ | 232 | timerfd \ |
231 | libunwind-debug-frame \ | 233 | libunwind-debug-frame \ |
@@ -301,6 +303,10 @@ ifeq ($(feature-sync-compare-and-swap), 1) | |||
301 | CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT | 303 | CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT |
302 | endif | 304 | endif |
303 | 305 | ||
306 | ifeq ($(feature-pthread-attr-setaffinity-np), 1) | ||
307 | CFLAGS += -DHAVE_PTHREAD_ATTR_SETAFFINITY_NP | ||
308 | endif | ||
309 | |||
304 | ifndef NO_BIONIC | 310 | ifndef NO_BIONIC |
305 | $(call feature_check,bionic) | 311 | $(call feature_check,bionic) |
306 | ifeq ($(feature-bionic), 1) | 312 | ifeq ($(feature-bionic), 1) |
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch index 851cd0172a76..ff95a68741d1 100644 --- a/tools/perf/config/Makefile.arch +++ b/tools/perf/config/Makefile.arch | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 2 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
3 | 3 | ||
4 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | 4 | RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ |
5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | 5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ |
6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | 6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ |
7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | 7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ |
@@ -9,23 +9,23 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | |||
9 | -e s/tile.*/tile/ ) | 9 | -e s/tile.*/tile/ ) |
10 | 10 | ||
11 | # Additional ARCH settings for x86 | 11 | # Additional ARCH settings for x86 |
12 | ifeq ($(ARCH),i386) | 12 | ifeq ($(RAW_ARCH),i386) |
13 | override ARCH := x86 | 13 | ARCH ?= x86 |
14 | endif | 14 | endif |
15 | 15 | ||
16 | ifeq ($(ARCH),x86_64) | 16 | ifeq ($(RAW_ARCH),x86_64) |
17 | override ARCH := x86 | 17 | ARCH ?= x86 |
18 | IS_X86_64 := 0 | 18 | |
19 | ifeq (, $(findstring m32,$(CFLAGS))) | 19 | ifneq (, $(findstring m32,$(CFLAGS))) |
20 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | 20 | RAW_ARCH := x86_32 |
21 | RAW_ARCH := x86_64 | ||
22 | endif | 21 | endif |
23 | endif | 22 | endif |
24 | 23 | ||
25 | ifeq (${IS_X86_64}, 1) | 24 | ARCH ?= $(RAW_ARCH) |
25 | |||
26 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | ||
27 | ifeq ($(LP64), 1) | ||
26 | IS_64_BIT := 1 | 28 | IS_64_BIT := 1 |
27 | else ifeq ($(ARCH),x86) | ||
28 | IS_64_BIT := 0 | ||
29 | else | 29 | else |
30 | IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | 30 | IS_64_BIT := 0 |
31 | endif | 31 | endif |
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 53f19b5dbc37..42ac05aaf8ac 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -25,6 +25,7 @@ FILES= \ | |||
25 | test-libslang.bin \ | 25 | test-libslang.bin \ |
26 | test-libunwind.bin \ | 26 | test-libunwind.bin \ |
27 | test-libunwind-debug-frame.bin \ | 27 | test-libunwind-debug-frame.bin \ |
28 | test-pthread-attr-setaffinity-np.bin \ | ||
28 | test-stackprotector-all.bin \ | 29 | test-stackprotector-all.bin \ |
29 | test-timerfd.bin \ | 30 | test-timerfd.bin \ |
30 | test-libdw-dwarf-unwind.bin \ | 31 | test-libdw-dwarf-unwind.bin \ |
@@ -47,6 +48,9 @@ test-all.bin: | |||
47 | test-hello.bin: | 48 | test-hello.bin: |
48 | $(BUILD) | 49 | $(BUILD) |
49 | 50 | ||
51 | test-pthread-attr-setaffinity-np.bin: | ||
52 | $(BUILD) -Werror -lpthread | ||
53 | |||
50 | test-stackprotector-all.bin: | 54 | test-stackprotector-all.bin: |
51 | $(BUILD) -Werror -fstack-protector-all | 55 | $(BUILD) -Werror -fstack-protector-all |
52 | 56 | ||
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index 652e0098eba6..6d4d09323922 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c | |||
@@ -97,6 +97,10 @@ | |||
97 | # include "test-zlib.c" | 97 | # include "test-zlib.c" |
98 | #undef main | 98 | #undef main |
99 | 99 | ||
100 | #define main main_test_pthread_attr_setaffinity_np | ||
101 | # include "test-pthread_attr_setaffinity_np.c" | ||
102 | #undef main | ||
103 | |||
100 | int main(int argc, char *argv[]) | 104 | int main(int argc, char *argv[]) |
101 | { | 105 | { |
102 | main_test_libpython(); | 106 | main_test_libpython(); |
@@ -121,6 +125,7 @@ int main(int argc, char *argv[]) | |||
121 | main_test_libdw_dwarf_unwind(); | 125 | main_test_libdw_dwarf_unwind(); |
122 | main_test_sync_compare_and_swap(argc, argv); | 126 | main_test_sync_compare_and_swap(argc, argv); |
123 | main_test_zlib(); | 127 | main_test_zlib(); |
128 | main_test_pthread_attr_setaffinity_np(); | ||
124 | 129 | ||
125 | return 0; | 130 | return 0; |
126 | } | 131 | } |
diff --git a/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c new file mode 100644 index 000000000000..0a0d3ecb4e8a --- /dev/null +++ b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c | |||
@@ -0,0 +1,14 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <pthread.h> | ||
3 | |||
4 | int main(void) | ||
5 | { | ||
6 | int ret = 0; | ||
7 | pthread_attr_t thread_attr; | ||
8 | |||
9 | pthread_attr_init(&thread_attr); | ||
10 | /* don't care abt exact args, just the API itself in libpthread */ | ||
11 | ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL); | ||
12 | |||
13 | return ret; | ||
14 | } | ||
diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index a3b13d7dc1d4..6ef68165c9db 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h | |||
@@ -6,7 +6,6 @@ | |||
6 | #include <sys/syscall.h> | 6 | #include <sys/syscall.h> |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/perf_event.h> | 8 | #include <linux/perf_event.h> |
9 | #include <asm/unistd.h> | ||
10 | 9 | ||
11 | #if defined(__i386__) | 10 | #if defined(__i386__) |
12 | #define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") | 11 | #define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") |
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c index 790ceba6ad3f..28431d1bbcf5 100644 --- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c | |||
@@ -5,7 +5,10 @@ | |||
5 | * ANY CHANGES MADE HERE WILL BE LOST! | 5 | * ANY CHANGES MADE HERE WILL BE LOST! |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | #include <stdbool.h> | |
9 | #ifndef HAS_BOOL | ||
10 | # define HAS_BOOL 1 | ||
11 | #endif | ||
9 | #line 1 "Context.xs" | 12 | #line 1 "Context.xs" |
10 | /* | 13 | /* |
11 | * Context.xs. XS interfaces for perf script. | 14 | * Context.xs. XS interfaces for perf script. |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index c9b4b6269b51..1091bd47adfd 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
@@ -104,7 +104,6 @@ class Event(dict): | |||
104 | continue | 104 | continue |
105 | if not self.compare_data(self[t], other[t]): | 105 | if not self.compare_data(self[t], other[t]): |
106 | log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) | 106 | log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) |
107 | |||
108 | 107 | ||
109 | # Test file description needs to have following sections: | 108 | # Test file description needs to have following sections: |
110 | # [config] | 109 | # [config] |
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index ab28cca2cb97..0bf06bec68c7 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c | |||
@@ -11,6 +11,9 @@ | |||
11 | #include "thread.h" | 11 | #include "thread.h" |
12 | #include "callchain.h" | 12 | #include "callchain.h" |
13 | 13 | ||
14 | /* For bsearch. We try to unwind functions in shared object. */ | ||
15 | #include <stdlib.h> | ||
16 | |||
14 | static int mmap_handler(struct perf_tool *tool __maybe_unused, | 17 | static int mmap_handler(struct perf_tool *tool __maybe_unused, |
15 | union perf_event *event, | 18 | union perf_event *event, |
16 | struct perf_sample *sample __maybe_unused, | 19 | struct perf_sample *sample __maybe_unused, |
@@ -28,7 +31,7 @@ static int init_live_machine(struct machine *machine) | |||
28 | mmap_handler, machine, true); | 31 | mmap_handler, machine, true); |
29 | } | 32 | } |
30 | 33 | ||
31 | #define MAX_STACK 6 | 34 | #define MAX_STACK 8 |
32 | 35 | ||
33 | static int unwind_entry(struct unwind_entry *entry, void *arg) | 36 | static int unwind_entry(struct unwind_entry *entry, void *arg) |
34 | { | 37 | { |
@@ -37,6 +40,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
37 | static const char *funcs[MAX_STACK] = { | 40 | static const char *funcs[MAX_STACK] = { |
38 | "test__arch_unwind_sample", | 41 | "test__arch_unwind_sample", |
39 | "unwind_thread", | 42 | "unwind_thread", |
43 | "compare", | ||
44 | "bsearch", | ||
40 | "krava_3", | 45 | "krava_3", |
41 | "krava_2", | 46 | "krava_2", |
42 | "krava_1", | 47 | "krava_1", |
@@ -88,10 +93,37 @@ static int unwind_thread(struct thread *thread) | |||
88 | return err; | 93 | return err; |
89 | } | 94 | } |
90 | 95 | ||
96 | static int global_unwind_retval = -INT_MAX; | ||
97 | |||
98 | __attribute__ ((noinline)) | ||
99 | static int compare(void *p1, void *p2) | ||
100 | { | ||
101 | /* Any possible value should be 'thread' */ | ||
102 | struct thread *thread = *(struct thread **)p1; | ||
103 | |||
104 | if (global_unwind_retval == -INT_MAX) | ||
105 | global_unwind_retval = unwind_thread(thread); | ||
106 | |||
107 | return p1 - p2; | ||
108 | } | ||
109 | |||
91 | __attribute__ ((noinline)) | 110 | __attribute__ ((noinline)) |
92 | static int krava_3(struct thread *thread) | 111 | static int krava_3(struct thread *thread) |
93 | { | 112 | { |
94 | return unwind_thread(thread); | 113 | struct thread *array[2] = {thread, thread}; |
114 | void *fp = &bsearch; | ||
115 | /* | ||
116 | * make _bsearch a volatile function pointer to | ||
117 | * prevent potential optimization, which may expand | ||
118 | * bsearch and call compare directly from this function, | ||
119 | * instead of libc shared object. | ||
120 | */ | ||
121 | void *(*volatile _bsearch)(void *, void *, size_t, | ||
122 | size_t, int (*)(void *, void *)); | ||
123 | |||
124 | _bsearch = fp; | ||
125 | _bsearch(array, &thread, 2, sizeof(struct thread **), compare); | ||
126 | return global_unwind_retval; | ||
95 | } | 127 | } |
96 | 128 | ||
97 | __attribute__ ((noinline)) | 129 | __attribute__ ((noinline)) |
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 614d5c4978ab..18619966454c 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
@@ -140,7 +140,7 @@ static void del_hist_entries(struct hists *hists) | |||
140 | he = rb_entry(node, struct hist_entry, rb_node); | 140 | he = rb_entry(node, struct hist_entry, rb_node); |
141 | rb_erase(node, root_out); | 141 | rb_erase(node, root_out); |
142 | rb_erase(&he->rb_node_in, root_in); | 142 | rb_erase(&he->rb_node_in, root_in); |
143 | hist_entry__free(he); | 143 | hist_entry__delete(he); |
144 | } | 144 | } |
145 | } | 145 | } |
146 | 146 | ||
@@ -187,7 +187,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec | |||
187 | * function since TEST_ASSERT_VAL() returns in case of failure. | 187 | * function since TEST_ASSERT_VAL() returns in case of failure. |
188 | */ | 188 | */ |
189 | hists__collapse_resort(hists, NULL); | 189 | hists__collapse_resort(hists, NULL); |
190 | hists__output_resort(hists); | 190 | hists__output_resort(hists, NULL); |
191 | 191 | ||
192 | if (verbose > 2) { | 192 | if (verbose > 2) { |
193 | pr_info("use callchain: %d, cumulate callchain: %d\n", | 193 | pr_info("use callchain: %d, cumulate callchain: %d\n", |
@@ -454,12 +454,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) | |||
454 | * 30.00% 10.00% perf perf [.] cmd_record | 454 | * 30.00% 10.00% perf perf [.] cmd_record |
455 | * 20.00% 0.00% bash libc [.] malloc | 455 | * 20.00% 0.00% bash libc [.] malloc |
456 | * 10.00% 10.00% bash [kernel] [k] page_fault | 456 | * 10.00% 10.00% bash [kernel] [k] page_fault |
457 | * 10.00% 10.00% perf [kernel] [k] schedule | 457 | * 10.00% 10.00% bash bash [.] xmalloc |
458 | * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open | ||
459 | * 10.00% 10.00% perf [kernel] [k] page_fault | 458 | * 10.00% 10.00% perf [kernel] [k] page_fault |
460 | * 10.00% 10.00% perf libc [.] free | ||
461 | * 10.00% 10.00% perf libc [.] malloc | 459 | * 10.00% 10.00% perf libc [.] malloc |
462 | * 10.00% 10.00% bash bash [.] xmalloc | 460 | * 10.00% 10.00% perf [kernel] [k] schedule |
461 | * 10.00% 10.00% perf libc [.] free | ||
462 | * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open | ||
463 | */ | 463 | */ |
464 | struct result expected[] = { | 464 | struct result expected[] = { |
465 | { 7000, 2000, "perf", "perf", "main" }, | 465 | { 7000, 2000, "perf", "perf", "main" }, |
@@ -468,12 +468,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) | |||
468 | { 3000, 1000, "perf", "perf", "cmd_record" }, | 468 | { 3000, 1000, "perf", "perf", "cmd_record" }, |
469 | { 2000, 0, "bash", "libc", "malloc" }, | 469 | { 2000, 0, "bash", "libc", "malloc" }, |
470 | { 1000, 1000, "bash", "[kernel]", "page_fault" }, | 470 | { 1000, 1000, "bash", "[kernel]", "page_fault" }, |
471 | { 1000, 1000, "perf", "[kernel]", "schedule" }, | 471 | { 1000, 1000, "bash", "bash", "xmalloc" }, |
472 | { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" }, | ||
473 | { 1000, 1000, "perf", "[kernel]", "page_fault" }, | 472 | { 1000, 1000, "perf", "[kernel]", "page_fault" }, |
473 | { 1000, 1000, "perf", "[kernel]", "schedule" }, | ||
474 | { 1000, 1000, "perf", "libc", "free" }, | 474 | { 1000, 1000, "perf", "libc", "free" }, |
475 | { 1000, 1000, "perf", "libc", "malloc" }, | 475 | { 1000, 1000, "perf", "libc", "malloc" }, |
476 | { 1000, 1000, "bash", "bash", "xmalloc" }, | 476 | { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" }, |
477 | }; | 477 | }; |
478 | 478 | ||
479 | symbol_conf.use_callchain = false; | 479 | symbol_conf.use_callchain = false; |
@@ -537,10 +537,13 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
537 | * malloc | 537 | * malloc |
538 | * main | 538 | * main |
539 | * | 539 | * |
540 | * 10.00% 10.00% perf [kernel] [k] schedule | 540 | * 10.00% 10.00% bash bash [.] xmalloc |
541 | * | | 541 | * | |
542 | * --- schedule | 542 | * --- xmalloc |
543 | * run_command | 543 | * malloc |
544 | * xmalloc <--- NOTE: there's a cycle | ||
545 | * malloc | ||
546 | * xmalloc | ||
544 | * main | 547 | * main |
545 | * | 548 | * |
546 | * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open | 549 | * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open |
@@ -556,6 +559,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
556 | * run_command | 559 | * run_command |
557 | * main | 560 | * main |
558 | * | 561 | * |
562 | * 10.00% 10.00% perf [kernel] [k] schedule | ||
563 | * | | ||
564 | * --- schedule | ||
565 | * run_command | ||
566 | * main | ||
567 | * | ||
559 | * 10.00% 10.00% perf libc [.] free | 568 | * 10.00% 10.00% perf libc [.] free |
560 | * | | 569 | * | |
561 | * --- free | 570 | * --- free |
@@ -570,15 +579,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
570 | * run_command | 579 | * run_command |
571 | * main | 580 | * main |
572 | * | 581 | * |
573 | * 10.00% 10.00% bash bash [.] xmalloc | ||
574 | * | | ||
575 | * --- xmalloc | ||
576 | * malloc | ||
577 | * xmalloc <--- NOTE: there's a cycle | ||
578 | * malloc | ||
579 | * xmalloc | ||
580 | * main | ||
581 | * | ||
582 | */ | 582 | */ |
583 | struct result expected[] = { | 583 | struct result expected[] = { |
584 | { 7000, 2000, "perf", "perf", "main" }, | 584 | { 7000, 2000, "perf", "perf", "main" }, |
@@ -587,12 +587,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
587 | { 3000, 1000, "perf", "perf", "cmd_record" }, | 587 | { 3000, 1000, "perf", "perf", "cmd_record" }, |
588 | { 2000, 0, "bash", "libc", "malloc" }, | 588 | { 2000, 0, "bash", "libc", "malloc" }, |
589 | { 1000, 1000, "bash", "[kernel]", "page_fault" }, | 589 | { 1000, 1000, "bash", "[kernel]", "page_fault" }, |
590 | { 1000, 1000, "perf", "[kernel]", "schedule" }, | 590 | { 1000, 1000, "bash", "bash", "xmalloc" }, |
591 | { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" }, | 591 | { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" }, |
592 | { 1000, 1000, "perf", "[kernel]", "page_fault" }, | 592 | { 1000, 1000, "perf", "[kernel]", "page_fault" }, |
593 | { 1000, 1000, "perf", "[kernel]", "schedule" }, | ||
593 | { 1000, 1000, "perf", "libc", "free" }, | 594 | { 1000, 1000, "perf", "libc", "free" }, |
594 | { 1000, 1000, "perf", "libc", "malloc" }, | 595 | { 1000, 1000, "perf", "libc", "malloc" }, |
595 | { 1000, 1000, "bash", "bash", "xmalloc" }, | ||
596 | }; | 596 | }; |
597 | struct callchain_result expected_callchain[] = { | 597 | struct callchain_result expected_callchain[] = { |
598 | { | 598 | { |
@@ -622,9 +622,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
622 | { "bash", "main" }, }, | 622 | { "bash", "main" }, }, |
623 | }, | 623 | }, |
624 | { | 624 | { |
625 | 3, { { "[kernel]", "schedule" }, | 625 | 6, { { "bash", "xmalloc" }, |
626 | { "perf", "run_command" }, | 626 | { "libc", "malloc" }, |
627 | { "perf", "main" }, }, | 627 | { "bash", "xmalloc" }, |
628 | { "libc", "malloc" }, | ||
629 | { "bash", "xmalloc" }, | ||
630 | { "bash", "main" }, }, | ||
628 | }, | 631 | }, |
629 | { | 632 | { |
630 | 3, { { "[kernel]", "sys_perf_event_open" }, | 633 | 3, { { "[kernel]", "sys_perf_event_open" }, |
@@ -638,6 +641,11 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
638 | { "perf", "main" }, }, | 641 | { "perf", "main" }, }, |
639 | }, | 642 | }, |
640 | { | 643 | { |
644 | 3, { { "[kernel]", "schedule" }, | ||
645 | { "perf", "run_command" }, | ||
646 | { "perf", "main" }, }, | ||
647 | }, | ||
648 | { | ||
641 | 4, { { "libc", "free" }, | 649 | 4, { { "libc", "free" }, |
642 | { "perf", "cmd_record" }, | 650 | { "perf", "cmd_record" }, |
643 | { "perf", "run_command" }, | 651 | { "perf", "run_command" }, |
@@ -649,14 +657,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
649 | { "perf", "run_command" }, | 657 | { "perf", "run_command" }, |
650 | { "perf", "main" }, }, | 658 | { "perf", "main" }, }, |
651 | }, | 659 | }, |
652 | { | ||
653 | 6, { { "bash", "xmalloc" }, | ||
654 | { "libc", "malloc" }, | ||
655 | { "bash", "xmalloc" }, | ||
656 | { "libc", "malloc" }, | ||
657 | { "bash", "xmalloc" }, | ||
658 | { "bash", "main" }, }, | ||
659 | }, | ||
660 | }; | 660 | }; |
661 | 661 | ||
662 | symbol_conf.use_callchain = true; | 662 | symbol_conf.use_callchain = true; |
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 74f257a81265..59e53db7914c 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -138,7 +138,7 @@ int test__hists_filter(void) | |||
138 | struct hists *hists = evsel__hists(evsel); | 138 | struct hists *hists = evsel__hists(evsel); |
139 | 139 | ||
140 | hists__collapse_resort(hists, NULL); | 140 | hists__collapse_resort(hists, NULL); |
141 | hists__output_resort(hists); | 141 | hists__output_resort(hists, NULL); |
142 | 142 | ||
143 | if (verbose > 2) { | 143 | if (verbose > 2) { |
144 | pr_info("Normal histogram\n"); | 144 | pr_info("Normal histogram\n"); |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index a748f2be1222..b52c9faea224 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -106,7 +106,7 @@ static void del_hist_entries(struct hists *hists) | |||
106 | he = rb_entry(node, struct hist_entry, rb_node); | 106 | he = rb_entry(node, struct hist_entry, rb_node); |
107 | rb_erase(node, root_out); | 107 | rb_erase(node, root_out); |
108 | rb_erase(&he->rb_node_in, root_in); | 108 | rb_erase(&he->rb_node_in, root_in); |
109 | hist_entry__free(he); | 109 | hist_entry__delete(he); |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
@@ -152,7 +152,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) | |||
152 | goto out; | 152 | goto out; |
153 | 153 | ||
154 | hists__collapse_resort(hists, NULL); | 154 | hists__collapse_resort(hists, NULL); |
155 | hists__output_resort(hists); | 155 | hists__output_resort(hists, NULL); |
156 | 156 | ||
157 | if (verbose > 2) { | 157 | if (verbose > 2) { |
158 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); | 158 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); |
@@ -252,7 +252,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) | |||
252 | goto out; | 252 | goto out; |
253 | 253 | ||
254 | hists__collapse_resort(hists, NULL); | 254 | hists__collapse_resort(hists, NULL); |
255 | hists__output_resort(hists); | 255 | hists__output_resort(hists, NULL); |
256 | 256 | ||
257 | if (verbose > 2) { | 257 | if (verbose > 2) { |
258 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); | 258 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); |
@@ -306,7 +306,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) | |||
306 | goto out; | 306 | goto out; |
307 | 307 | ||
308 | hists__collapse_resort(hists, NULL); | 308 | hists__collapse_resort(hists, NULL); |
309 | hists__output_resort(hists); | 309 | hists__output_resort(hists, NULL); |
310 | 310 | ||
311 | if (verbose > 2) { | 311 | if (verbose > 2) { |
312 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); | 312 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); |
@@ -384,7 +384,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) | |||
384 | goto out; | 384 | goto out; |
385 | 385 | ||
386 | hists__collapse_resort(hists, NULL); | 386 | hists__collapse_resort(hists, NULL); |
387 | hists__output_resort(hists); | 387 | hists__output_resort(hists, NULL); |
388 | 388 | ||
389 | if (verbose > 2) { | 389 | if (verbose > 2) { |
390 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); | 390 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); |
@@ -487,7 +487,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine) | |||
487 | goto out; | 487 | goto out; |
488 | 488 | ||
489 | hists__collapse_resort(hists, NULL); | 489 | hists__collapse_resort(hists, NULL); |
490 | hists__output_resort(hists); | 490 | hists__output_resort(hists, NULL); |
491 | 491 | ||
492 | if (verbose > 2) { | 492 | if (verbose > 2) { |
493 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); | 493 | pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 69a71ff84e01..75709d2b17b4 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -222,7 +222,6 @@ tarpkg: | |||
222 | @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ | 222 | @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ |
223 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ | 223 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ |
224 | ( eval $$cmd ) >> $@ 2>&1 | 224 | ( eval $$cmd ) >> $@ 2>&1 |
225 | |||
226 | 225 | ||
227 | all: $(run) $(run_O) tarpkg | 226 | all: $(run) $(run_O) tarpkg |
228 | @echo OK | 227 | @echo OK |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7f2f51f93619..1cdab0ce00e2 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -1145,6 +1145,49 @@ static int test__pinned_group(struct perf_evlist *evlist) | |||
1145 | return 0; | 1145 | return 0; |
1146 | } | 1146 | } |
1147 | 1147 | ||
1148 | static int test__checkevent_breakpoint_len(struct perf_evlist *evlist) | ||
1149 | { | ||
1150 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
1151 | |||
1152 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
1153 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
1154 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
1155 | TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == | ||
1156 | evsel->attr.bp_type); | ||
1157 | TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 == | ||
1158 | evsel->attr.bp_len); | ||
1159 | |||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | static int test__checkevent_breakpoint_len_w(struct perf_evlist *evlist) | ||
1164 | { | ||
1165 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
1166 | |||
1167 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
1168 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
1169 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
1170 | TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W == | ||
1171 | evsel->attr.bp_type); | ||
1172 | TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 == | ||
1173 | evsel->attr.bp_len); | ||
1174 | |||
1175 | return 0; | ||
1176 | } | ||
1177 | |||
1178 | static int | ||
1179 | test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) | ||
1180 | { | ||
1181 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
1182 | |||
1183 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
1184 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
1185 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
1186 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
1187 | |||
1188 | return test__checkevent_breakpoint_rw(evlist); | ||
1189 | } | ||
1190 | |||
1148 | static int count_tracepoints(void) | 1191 | static int count_tracepoints(void) |
1149 | { | 1192 | { |
1150 | char events_path[PATH_MAX]; | 1193 | char events_path[PATH_MAX]; |
@@ -1420,6 +1463,21 @@ static struct evlist_test test__events[] = { | |||
1420 | .check = test__pinned_group, | 1463 | .check = test__pinned_group, |
1421 | .id = 41, | 1464 | .id = 41, |
1422 | }, | 1465 | }, |
1466 | { | ||
1467 | .name = "mem:0/1", | ||
1468 | .check = test__checkevent_breakpoint_len, | ||
1469 | .id = 42, | ||
1470 | }, | ||
1471 | { | ||
1472 | .name = "mem:0/2:w", | ||
1473 | .check = test__checkevent_breakpoint_len_w, | ||
1474 | .id = 43, | ||
1475 | }, | ||
1476 | { | ||
1477 | .name = "mem:0/4:rw:u", | ||
1478 | .check = test__checkevent_breakpoint_len_rw_modifier, | ||
1479 | .id = 44 | ||
1480 | }, | ||
1423 | #if defined(__s390x__) | 1481 | #if defined(__s390x__) |
1424 | { | 1482 | { |
1425 | .name = "kvm-s390:kvm_s390_create_vm", | 1483 | .name = "kvm-s390:kvm_s390_create_vm", |
@@ -1471,7 +1529,7 @@ static int test_event(struct evlist_test *e) | |||
1471 | } else { | 1529 | } else { |
1472 | ret = e->check(evlist); | 1530 | ret = e->check(evlist); |
1473 | } | 1531 | } |
1474 | 1532 | ||
1475 | perf_evlist__delete(evlist); | 1533 | perf_evlist__delete(evlist); |
1476 | 1534 | ||
1477 | return ret; | 1535 | return ret; |
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 4908c648a597..30c02181e78b 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c | |||
@@ -110,7 +110,7 @@ static bool samples_same(const struct perf_sample *s1, | |||
110 | 110 | ||
111 | if (type & PERF_SAMPLE_STACK_USER) { | 111 | if (type & PERF_SAMPLE_STACK_USER) { |
112 | COMP(user_stack.size); | 112 | COMP(user_stack.size); |
113 | if (memcmp(s1->user_stack.data, s1->user_stack.data, | 113 | if (memcmp(s1->user_stack.data, s2->user_stack.data, |
114 | s1->user_stack.size)) { | 114 | s1->user_stack.size)) { |
115 | pr_debug("Samples differ at 'user_stack'\n"); | 115 | pr_debug("Samples differ at 'user_stack'\n"); |
116 | return false; | 116 | return false; |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 1e0a2fd80115..9d32e3c0cfee 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -517,7 +517,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) | |||
517 | } | 517 | } |
518 | 518 | ||
519 | annotate_browser__set_top(browser, dl, idx); | 519 | annotate_browser__set_top(browser, dl, idx); |
520 | 520 | ||
521 | return true; | 521 | return true; |
522 | } | 522 | } |
523 | 523 | ||
@@ -867,7 +867,6 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser | |||
867 | 867 | ||
868 | ++browser->nr_jumps; | 868 | ++browser->nr_jumps; |
869 | } | 869 | } |
870 | |||
871 | } | 870 | } |
872 | 871 | ||
873 | static inline int width_jumps(int n) | 872 | static inline int width_jumps(int n) |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e6bb04b5b09b..788506eef567 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -550,7 +550,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
550 | bool need_percent; | 550 | bool need_percent; |
551 | 551 | ||
552 | node = rb_first(root); | 552 | node = rb_first(root); |
553 | need_percent = !!rb_next(node); | 553 | need_percent = node && rb_next(node); |
554 | 554 | ||
555 | while (node) { | 555 | while (node) { |
556 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | 556 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index dc0d095f318c..25d608394d74 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -204,6 +204,9 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, | |||
204 | if (ret) | 204 | if (ret) |
205 | return ret; | 205 | return ret; |
206 | 206 | ||
207 | if (a->thread != b->thread || !symbol_conf.use_callchain) | ||
208 | return 0; | ||
209 | |||
207 | ret = b->callchain->max_depth - a->callchain->max_depth; | 210 | ret = b->callchain->max_depth - a->callchain->max_depth; |
208 | } | 211 | } |
209 | return ret; | 212 | return ret; |
@@ -282,7 +285,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ | |||
282 | } | 285 | } |
283 | 286 | ||
284 | #define __HPP_SORT_FN(_type, _field) \ | 287 | #define __HPP_SORT_FN(_type, _field) \ |
285 | static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ | 288 | static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
289 | struct hist_entry *a, struct hist_entry *b) \ | ||
286 | { \ | 290 | { \ |
287 | return __hpp__sort(a, b, he_get_##_field); \ | 291 | return __hpp__sort(a, b, he_get_##_field); \ |
288 | } | 292 | } |
@@ -309,7 +313,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ | |||
309 | } | 313 | } |
310 | 314 | ||
311 | #define __HPP_SORT_ACC_FN(_type, _field) \ | 315 | #define __HPP_SORT_ACC_FN(_type, _field) \ |
312 | static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ | 316 | static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
317 | struct hist_entry *a, struct hist_entry *b) \ | ||
313 | { \ | 318 | { \ |
314 | return __hpp__sort_acc(a, b, he_get_acc_##_field); \ | 319 | return __hpp__sort_acc(a, b, he_get_acc_##_field); \ |
315 | } | 320 | } |
@@ -328,7 +333,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ | |||
328 | } | 333 | } |
329 | 334 | ||
330 | #define __HPP_SORT_RAW_FN(_type, _field) \ | 335 | #define __HPP_SORT_RAW_FN(_type, _field) \ |
331 | static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ | 336 | static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
337 | struct hist_entry *a, struct hist_entry *b) \ | ||
332 | { \ | 338 | { \ |
333 | return __hpp__sort(a, b, he_get_raw_##_field); \ | 339 | return __hpp__sort(a, b, he_get_raw_##_field); \ |
334 | } | 340 | } |
@@ -358,7 +364,8 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period) | |||
358 | HPP_RAW_FNS(samples, nr_events) | 364 | HPP_RAW_FNS(samples, nr_events) |
359 | HPP_RAW_FNS(period, period) | 365 | HPP_RAW_FNS(period, period) |
360 | 366 | ||
361 | static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, | 367 | static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, |
368 | struct hist_entry *a __maybe_unused, | ||
362 | struct hist_entry *b __maybe_unused) | 369 | struct hist_entry *b __maybe_unused) |
363 | { | 370 | { |
364 | return 0; | 371 | return 0; |
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h index f34f89eb607c..717d39d3052b 100644 --- a/tools/perf/ui/progress.h +++ b/tools/perf/ui/progress.h | |||
@@ -4,12 +4,12 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | void ui_progress__finish(void); | 6 | void ui_progress__finish(void); |
7 | 7 | ||
8 | struct ui_progress { | 8 | struct ui_progress { |
9 | const char *title; | 9 | const char *title; |
10 | u64 curr, next, step, total; | 10 | u64 curr, next, step, total; |
11 | }; | 11 | }; |
12 | 12 | ||
13 | void ui_progress__init(struct ui_progress *p, u64 total, const char *title); | 13 | void ui_progress__init(struct ui_progress *p, u64 total, const char *title); |
14 | void ui_progress__update(struct ui_progress *p, u64 adv); | 14 | void ui_progress__update(struct ui_progress *p, u64 adv); |
15 | 15 | ||
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 1c8b9afd5d6e..88f5143a5981 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "../libslang.h" | 9 | #include "../libslang.h" |
10 | 10 | ||
11 | char ui_helpline__last_msg[1024]; | 11 | char ui_helpline__last_msg[1024]; |
12 | bool tui_helpline__set; | ||
12 | 13 | ||
13 | static void tui_helpline__pop(void) | 14 | static void tui_helpline__pop(void) |
14 | { | 15 | { |
@@ -35,6 +36,8 @@ static int tui_helpline__show(const char *format, va_list ap) | |||
35 | sizeof(ui_helpline__last_msg) - backlog, format, ap); | 36 | sizeof(ui_helpline__last_msg) - backlog, format, ap); |
36 | backlog += ret; | 37 | backlog += ret; |
37 | 38 | ||
39 | tui_helpline__set = true; | ||
40 | |||
38 | if (ui_helpline__last_msg[backlog - 1] == '\n') { | 41 | if (ui_helpline__last_msg[backlog - 1] == '\n') { |
39 | ui_helpline__puts(ui_helpline__last_msg); | 42 | ui_helpline__puts(ui_helpline__last_msg); |
40 | SLsmg_refresh(); | 43 | SLsmg_refresh(); |
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 2f612562978c..b77e1d771363 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c | |||
@@ -1,5 +1,8 @@ | |||
1 | #include <signal.h> | 1 | #include <signal.h> |
2 | #include <stdbool.h> | 2 | #include <stdbool.h> |
3 | #ifdef HAVE_BACKTRACE_SUPPORT | ||
4 | #include <execinfo.h> | ||
5 | #endif | ||
3 | 6 | ||
4 | #include "../../util/cache.h" | 7 | #include "../../util/cache.h" |
5 | #include "../../util/debug.h" | 8 | #include "../../util/debug.h" |
@@ -14,6 +17,7 @@ | |||
14 | static volatile int ui__need_resize; | 17 | static volatile int ui__need_resize; |
15 | 18 | ||
16 | extern struct perf_error_ops perf_tui_eops; | 19 | extern struct perf_error_ops perf_tui_eops; |
20 | extern bool tui_helpline__set; | ||
17 | 21 | ||
18 | extern void hist_browser__init_hpp(void); | 22 | extern void hist_browser__init_hpp(void); |
19 | 23 | ||
@@ -88,6 +92,25 @@ int ui__getch(int delay_secs) | |||
88 | return SLkp_getkey(); | 92 | return SLkp_getkey(); |
89 | } | 93 | } |
90 | 94 | ||
95 | #ifdef HAVE_BACKTRACE_SUPPORT | ||
96 | static void ui__signal_backtrace(int sig) | ||
97 | { | ||
98 | void *stackdump[32]; | ||
99 | size_t size; | ||
100 | |||
101 | ui__exit(false); | ||
102 | psignal(sig, "perf"); | ||
103 | |||
104 | printf("-------- backtrace --------\n"); | ||
105 | size = backtrace(stackdump, ARRAY_SIZE(stackdump)); | ||
106 | backtrace_symbols_fd(stackdump, size, STDOUT_FILENO); | ||
107 | |||
108 | exit(0); | ||
109 | } | ||
110 | #else | ||
111 | # define ui__signal_backtrace ui__signal | ||
112 | #endif | ||
113 | |||
91 | static void ui__signal(int sig) | 114 | static void ui__signal(int sig) |
92 | { | 115 | { |
93 | ui__exit(false); | 116 | ui__exit(false); |
@@ -122,8 +145,8 @@ int ui__init(void) | |||
122 | ui_browser__init(); | 145 | ui_browser__init(); |
123 | tui_progress__init(); | 146 | tui_progress__init(); |
124 | 147 | ||
125 | signal(SIGSEGV, ui__signal); | 148 | signal(SIGSEGV, ui__signal_backtrace); |
126 | signal(SIGFPE, ui__signal); | 149 | signal(SIGFPE, ui__signal_backtrace); |
127 | signal(SIGINT, ui__signal); | 150 | signal(SIGINT, ui__signal); |
128 | signal(SIGQUIT, ui__signal); | 151 | signal(SIGQUIT, ui__signal); |
129 | signal(SIGTERM, ui__signal); | 152 | signal(SIGTERM, ui__signal); |
@@ -137,7 +160,7 @@ out: | |||
137 | 160 | ||
138 | void ui__exit(bool wait_for_ok) | 161 | void ui__exit(bool wait_for_ok) |
139 | { | 162 | { |
140 | if (wait_for_ok) | 163 | if (wait_for_ok && tui_helpline__set) |
141 | ui__question_window("Fatal Error", | 164 | ui__question_window("Fatal Error", |
142 | ui_helpline__last_msg, | 165 | ui_helpline__last_msg, |
143 | "Press any key...", 0); | 166 | "Press any key...", 0); |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 79999ceaf2be..61bf9128e1f2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -177,14 +177,17 @@ static int lock__parse(struct ins_operands *ops) | |||
177 | goto out_free_ops; | 177 | goto out_free_ops; |
178 | 178 | ||
179 | ops->locked.ins = ins__find(name); | 179 | ops->locked.ins = ins__find(name); |
180 | free(name); | ||
181 | |||
180 | if (ops->locked.ins == NULL) | 182 | if (ops->locked.ins == NULL) |
181 | goto out_free_ops; | 183 | goto out_free_ops; |
182 | 184 | ||
183 | if (!ops->locked.ins->ops) | 185 | if (!ops->locked.ins->ops) |
184 | return 0; | 186 | return 0; |
185 | 187 | ||
186 | if (ops->locked.ins->ops->parse) | 188 | if (ops->locked.ins->ops->parse && |
187 | ops->locked.ins->ops->parse(ops->locked.ops); | 189 | ops->locked.ins->ops->parse(ops->locked.ops) < 0) |
190 | goto out_free_ops; | ||
188 | 191 | ||
189 | return 0; | 192 | return 0; |
190 | 193 | ||
@@ -208,6 +211,13 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | |||
208 | 211 | ||
209 | static void lock__delete(struct ins_operands *ops) | 212 | static void lock__delete(struct ins_operands *ops) |
210 | { | 213 | { |
214 | struct ins *ins = ops->locked.ins; | ||
215 | |||
216 | if (ins && ins->ops->free) | ||
217 | ins->ops->free(ops->locked.ops); | ||
218 | else | ||
219 | ins__delete(ops->locked.ops); | ||
220 | |||
211 | zfree(&ops->locked.ops); | 221 | zfree(&ops->locked.ops); |
212 | zfree(&ops->target.raw); | 222 | zfree(&ops->target.raw); |
213 | zfree(&ops->target.name); | 223 | zfree(&ops->target.name); |
@@ -229,7 +239,7 @@ static int mov__parse(struct ins_operands *ops) | |||
229 | *s = '\0'; | 239 | *s = '\0'; |
230 | ops->source.raw = strdup(ops->raw); | 240 | ops->source.raw = strdup(ops->raw); |
231 | *s = ','; | 241 | *s = ','; |
232 | 242 | ||
233 | if (ops->source.raw == NULL) | 243 | if (ops->source.raw == NULL) |
234 | return -1; | 244 | return -1; |
235 | 245 | ||
@@ -531,8 +541,8 @@ static void disasm_line__init_ins(struct disasm_line *dl) | |||
531 | if (!dl->ins->ops) | 541 | if (!dl->ins->ops) |
532 | return; | 542 | return; |
533 | 543 | ||
534 | if (dl->ins->ops->parse) | 544 | if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0) |
535 | dl->ins->ops->parse(&dl->ops); | 545 | dl->ins = NULL; |
536 | } | 546 | } |
537 | 547 | ||
538 | static int disasm_line__parse(char *line, char **namep, char **rawp) | 548 | static int disasm_line__parse(char *line, char **namep, char **rawp) |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0784a9420528..cadbdc90a5cb 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -116,11 +116,6 @@ struct annotation { | |||
116 | struct annotated_source *src; | 116 | struct annotated_source *src; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | struct sannotation { | ||
120 | struct annotation annotation; | ||
121 | struct symbol symbol; | ||
122 | }; | ||
123 | |||
124 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) | 119 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) |
125 | { | 120 | { |
126 | return (((void *)¬es->src->histograms) + | 121 | return (((void *)¬es->src->histograms) + |
@@ -129,8 +124,7 @@ static inline struct sym_hist *annotation__histogram(struct annotation *notes, i | |||
129 | 124 | ||
130 | static inline struct annotation *symbol__annotation(struct symbol *sym) | 125 | static inline struct annotation *symbol__annotation(struct symbol *sym) |
131 | { | 126 | { |
132 | struct sannotation *a = container_of(sym, struct sannotation, symbol); | 127 | return (void *)sym - symbol_conf.priv_size; |
133 | return &a->annotation; | ||
134 | } | 128 | } |
135 | 129 | ||
136 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); | 130 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 5cf9e1b5989d..d04d770d90f6 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -71,7 +71,9 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2 | |||
71 | extern char *perf_pathdup(const char *fmt, ...) | 71 | extern char *perf_pathdup(const char *fmt, ...) |
72 | __attribute__((format (printf, 1, 2))); | 72 | __attribute__((format (printf, 1, 2))); |
73 | 73 | ||
74 | #ifndef __UCLIBC__ | ||
74 | /* Matches the libc/libbsd function attribute so we declare this unconditionally: */ | 75 | /* Matches the libc/libbsd function attribute so we declare this unconditionally: */ |
75 | extern size_t strlcpy(char *dest, const char *src, size_t size); | 76 | extern size_t strlcpy(char *dest, const char *src, size_t size); |
77 | #endif | ||
76 | 78 | ||
77 | #endif /* __PERF_CACHE_H */ | 79 | #endif /* __PERF_CACHE_H */ |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 64b377e591e4..14e7a123d43b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -841,3 +841,33 @@ char *callchain_list__sym_name(struct callchain_list *cl, | |||
841 | 841 | ||
842 | return bf; | 842 | return bf; |
843 | } | 843 | } |
844 | |||
845 | static void free_callchain_node(struct callchain_node *node) | ||
846 | { | ||
847 | struct callchain_list *list, *tmp; | ||
848 | struct callchain_node *child; | ||
849 | struct rb_node *n; | ||
850 | |||
851 | list_for_each_entry_safe(list, tmp, &node->val, list) { | ||
852 | list_del(&list->list); | ||
853 | free(list); | ||
854 | } | ||
855 | |||
856 | n = rb_first(&node->rb_root_in); | ||
857 | while (n) { | ||
858 | child = container_of(n, struct callchain_node, rb_node_in); | ||
859 | n = rb_next(n); | ||
860 | rb_erase(&child->rb_node_in, &node->rb_root_in); | ||
861 | |||
862 | free_callchain_node(child); | ||
863 | free(child); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | void free_callchain(struct callchain_root *root) | ||
868 | { | ||
869 | if (!symbol_conf.use_callchain) | ||
870 | return; | ||
871 | |||
872 | free_callchain_node(&root->node); | ||
873 | } | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index dbc08cf5f970..c0ec1acc38e4 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -198,4 +198,6 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused, | |||
198 | char *callchain_list__sym_name(struct callchain_list *cl, | 198 | char *callchain_list__sym_name(struct callchain_list *cl, |
199 | char *bf, size_t bfsize, bool show_dso); | 199 | char *bf, size_t bfsize, bool show_dso); |
200 | 200 | ||
201 | void free_callchain(struct callchain_root *root); | ||
202 | |||
201 | #endif /* __PERF_CALLCHAIN_H */ | 203 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index f4654183d391..55355b3d4f85 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -5,132 +5,6 @@ | |||
5 | 5 | ||
6 | int perf_use_color_default = -1; | 6 | int perf_use_color_default = -1; |
7 | 7 | ||
8 | static int parse_color(const char *name, int len) | ||
9 | { | ||
10 | static const char * const color_names[] = { | ||
11 | "normal", "black", "red", "green", "yellow", | ||
12 | "blue", "magenta", "cyan", "white" | ||
13 | }; | ||
14 | char *end; | ||
15 | int i; | ||
16 | |||
17 | for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) { | ||
18 | const char *str = color_names[i]; | ||
19 | if (!strncasecmp(name, str, len) && !str[len]) | ||
20 | return i - 1; | ||
21 | } | ||
22 | i = strtol(name, &end, 10); | ||
23 | if (end - name == len && i >= -1 && i <= 255) | ||
24 | return i; | ||
25 | return -2; | ||
26 | } | ||
27 | |||
28 | static int parse_attr(const char *name, int len) | ||
29 | { | ||
30 | static const int attr_values[] = { 1, 2, 4, 5, 7 }; | ||
31 | static const char * const attr_names[] = { | ||
32 | "bold", "dim", "ul", "blink", "reverse" | ||
33 | }; | ||
34 | unsigned int i; | ||
35 | |||
36 | for (i = 0; i < ARRAY_SIZE(attr_names); i++) { | ||
37 | const char *str = attr_names[i]; | ||
38 | if (!strncasecmp(name, str, len) && !str[len]) | ||
39 | return attr_values[i]; | ||
40 | } | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | void color_parse(const char *value, const char *var, char *dst) | ||
45 | { | ||
46 | color_parse_mem(value, strlen(value), var, dst); | ||
47 | } | ||
48 | |||
49 | void color_parse_mem(const char *value, int value_len, const char *var, | ||
50 | char *dst) | ||
51 | { | ||
52 | const char *ptr = value; | ||
53 | int len = value_len; | ||
54 | int attr = -1; | ||
55 | int fg = -2; | ||
56 | int bg = -2; | ||
57 | |||
58 | if (!strncasecmp(value, "reset", len)) { | ||
59 | strcpy(dst, PERF_COLOR_RESET); | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | /* [fg [bg]] [attr] */ | ||
64 | while (len > 0) { | ||
65 | const char *word = ptr; | ||
66 | int val, wordlen = 0; | ||
67 | |||
68 | while (len > 0 && !isspace(word[wordlen])) { | ||
69 | wordlen++; | ||
70 | len--; | ||
71 | } | ||
72 | |||
73 | ptr = word + wordlen; | ||
74 | while (len > 0 && isspace(*ptr)) { | ||
75 | ptr++; | ||
76 | len--; | ||
77 | } | ||
78 | |||
79 | val = parse_color(word, wordlen); | ||
80 | if (val >= -1) { | ||
81 | if (fg == -2) { | ||
82 | fg = val; | ||
83 | continue; | ||
84 | } | ||
85 | if (bg == -2) { | ||
86 | bg = val; | ||
87 | continue; | ||
88 | } | ||
89 | goto bad; | ||
90 | } | ||
91 | val = parse_attr(word, wordlen); | ||
92 | if (val < 0 || attr != -1) | ||
93 | goto bad; | ||
94 | attr = val; | ||
95 | } | ||
96 | |||
97 | if (attr >= 0 || fg >= 0 || bg >= 0) { | ||
98 | int sep = 0; | ||
99 | |||
100 | *dst++ = '\033'; | ||
101 | *dst++ = '['; | ||
102 | if (attr >= 0) { | ||
103 | *dst++ = '0' + attr; | ||
104 | sep++; | ||
105 | } | ||
106 | if (fg >= 0) { | ||
107 | if (sep++) | ||
108 | *dst++ = ';'; | ||
109 | if (fg < 8) { | ||
110 | *dst++ = '3'; | ||
111 | *dst++ = '0' + fg; | ||
112 | } else { | ||
113 | dst += sprintf(dst, "38;5;%d", fg); | ||
114 | } | ||
115 | } | ||
116 | if (bg >= 0) { | ||
117 | if (sep++) | ||
118 | *dst++ = ';'; | ||
119 | if (bg < 8) { | ||
120 | *dst++ = '4'; | ||
121 | *dst++ = '0' + bg; | ||
122 | } else { | ||
123 | dst += sprintf(dst, "48;5;%d", bg); | ||
124 | } | ||
125 | } | ||
126 | *dst++ = 'm'; | ||
127 | } | ||
128 | *dst = 0; | ||
129 | return; | ||
130 | bad: | ||
131 | die("bad color value '%.*s' for variable '%s'", value_len, value, var); | ||
132 | } | ||
133 | |||
134 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) | 8 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) |
135 | { | 9 | { |
136 | if (value) { | 10 | if (value) { |
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 0a594b8a0c26..38146f922c54 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h | |||
@@ -30,8 +30,6 @@ extern int perf_use_color_default; | |||
30 | int perf_color_default_config(const char *var, const char *value, void *cb); | 30 | int perf_color_default_config(const char *var, const char *value, void *cb); |
31 | 31 | ||
32 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); | 32 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); |
33 | void color_parse(const char *value, const char *var, char *dst); | ||
34 | void color_parse_mem(const char *value, int len, const char *var, char *dst); | ||
35 | int color_vsnprintf(char *bf, size_t size, const char *color, | 33 | int color_vsnprintf(char *bf, size_t size, const char *color, |
36 | const char *fmt, va_list args); | 34 | const char *fmt, va_list args); |
37 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); | 35 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 45be944d450a..c2f7d3b90966 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -532,12 +532,8 @@ dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size) | |||
532 | break; | 532 | break; |
533 | 533 | ||
534 | cache_offset = offset & DSO__DATA_CACHE_MASK; | 534 | cache_offset = offset & DSO__DATA_CACHE_MASK; |
535 | ret = -EINVAL; | ||
536 | 535 | ||
537 | if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET)) | 536 | ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset); |
538 | break; | ||
539 | |||
540 | ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE); | ||
541 | if (ret <= 0) | 537 | if (ret <= 0) |
542 | break; | 538 | break; |
543 | 539 | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 3782c82c6e44..ced92841ff97 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -139,6 +139,7 @@ struct dso { | |||
139 | u32 status_seen; | 139 | u32 status_seen; |
140 | size_t file_size; | 140 | size_t file_size; |
141 | struct list_head open_entry; | 141 | struct list_head open_entry; |
142 | u64 frame_offset; | ||
142 | } data; | 143 | } data; |
143 | 144 | ||
144 | union { /* Tool specific area */ | 145 | union { /* Tool specific area */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index cbab1fb77b1d..28b8ce86bf12 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1436,33 +1436,6 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) | |||
1436 | return printed + fprintf(fp, "\n"); | 1436 | return printed + fprintf(fp, "\n"); |
1437 | } | 1437 | } |
1438 | 1438 | ||
1439 | int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused, | ||
1440 | int err, char *buf, size_t size) | ||
1441 | { | ||
1442 | char sbuf[128]; | ||
1443 | |||
1444 | switch (err) { | ||
1445 | case ENOENT: | ||
1446 | scnprintf(buf, size, "%s", | ||
1447 | "Error:\tUnable to find debugfs\n" | ||
1448 | "Hint:\tWas your kernel was compiled with debugfs support?\n" | ||
1449 | "Hint:\tIs the debugfs filesystem mounted?\n" | ||
1450 | "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); | ||
1451 | break; | ||
1452 | case EACCES: | ||
1453 | scnprintf(buf, size, | ||
1454 | "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n" | ||
1455 | "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", | ||
1456 | debugfs_mountpoint, debugfs_mountpoint); | ||
1457 | break; | ||
1458 | default: | ||
1459 | scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); | ||
1460 | break; | ||
1461 | } | ||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | 1439 | int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, |
1467 | int err, char *buf, size_t size) | 1440 | int err, char *buf, size_t size) |
1468 | { | 1441 | { |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 0ba93f67ab94..c94a9e03ecf1 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -183,7 +183,6 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) | |||
183 | 183 | ||
184 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); | 184 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); |
185 | 185 | ||
186 | int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size); | ||
187 | int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size); | 186 | int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size); |
188 | int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size); | 187 | int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size); |
189 | 188 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1e90c8557ede..ea51a90e20a0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -709,6 +709,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
709 | if (opts->sample_weight) | 709 | if (opts->sample_weight) |
710 | perf_evsel__set_sample_bit(evsel, WEIGHT); | 710 | perf_evsel__set_sample_bit(evsel, WEIGHT); |
711 | 711 | ||
712 | attr->task = track; | ||
712 | attr->mmap = track; | 713 | attr->mmap = track; |
713 | attr->mmap2 = track && !perf_missing_features.mmap2; | 714 | attr->mmap2 = track && !perf_missing_features.mmap2; |
714 | attr->comm = track; | 715 | attr->comm = track; |
@@ -797,6 +798,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
797 | 798 | ||
798 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 799 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
799 | { | 800 | { |
801 | if (ncpus == 0 || nthreads == 0) | ||
802 | return 0; | ||
803 | |||
800 | if (evsel->system_wide) | 804 | if (evsel->system_wide) |
801 | nthreads = 1; | 805 | nthreads = 1; |
802 | 806 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b20e40c74468..1f407f7352a7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2237,6 +2237,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2237 | * - unique number to identify actual perf.data files | 2237 | * - unique number to identify actual perf.data files |
2238 | * - encode endianness of file | 2238 | * - encode endianness of file |
2239 | */ | 2239 | */ |
2240 | ph->version = PERF_HEADER_VERSION_2; | ||
2240 | 2241 | ||
2241 | /* check magic number with one endianness */ | 2242 | /* check magic number with one endianness */ |
2242 | if (magic == __perf_magic2) | 2243 | if (magic == __perf_magic2) |
@@ -2247,7 +2248,6 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2247 | return -1; | 2248 | return -1; |
2248 | 2249 | ||
2249 | ph->needs_swap = true; | 2250 | ph->needs_swap = true; |
2250 | ph->version = PERF_HEADER_VERSION_2; | ||
2251 | 2251 | ||
2252 | return 0; | 2252 | return 0; |
2253 | } | 2253 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6e88b9e395df..70b48a65064c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include "evlist.h" | 6 | #include "evlist.h" |
7 | #include "evsel.h" | 7 | #include "evsel.h" |
8 | #include "annotate.h" | 8 | #include "annotate.h" |
9 | #include "ui/progress.h" | ||
9 | #include <math.h> | 10 | #include <math.h> |
10 | 11 | ||
11 | static bool hists__filter_entry_by_dso(struct hists *hists, | 12 | static bool hists__filter_entry_by_dso(struct hists *hists, |
@@ -240,6 +241,20 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
240 | return he->stat.period == 0; | 241 | return he->stat.period == 0; |
241 | } | 242 | } |
242 | 243 | ||
244 | static void hists__delete_entry(struct hists *hists, struct hist_entry *he) | ||
245 | { | ||
246 | rb_erase(&he->rb_node, &hists->entries); | ||
247 | |||
248 | if (sort__need_collapse) | ||
249 | rb_erase(&he->rb_node_in, &hists->entries_collapsed); | ||
250 | |||
251 | --hists->nr_entries; | ||
252 | if (!he->filtered) | ||
253 | --hists->nr_non_filtered_entries; | ||
254 | |||
255 | hist_entry__delete(he); | ||
256 | } | ||
257 | |||
243 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | 258 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) |
244 | { | 259 | { |
245 | struct rb_node *next = rb_first(&hists->entries); | 260 | struct rb_node *next = rb_first(&hists->entries); |
@@ -257,16 +272,7 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | |||
257 | (zap_kernel && n->level != '.') || | 272 | (zap_kernel && n->level != '.') || |
258 | hists__decay_entry(hists, n)) && | 273 | hists__decay_entry(hists, n)) && |
259 | !n->used) { | 274 | !n->used) { |
260 | rb_erase(&n->rb_node, &hists->entries); | 275 | hists__delete_entry(hists, n); |
261 | |||
262 | if (sort__need_collapse) | ||
263 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | ||
264 | |||
265 | --hists->nr_entries; | ||
266 | if (!n->filtered) | ||
267 | --hists->nr_non_filtered_entries; | ||
268 | |||
269 | hist_entry__free(n); | ||
270 | } | 276 | } |
271 | } | 277 | } |
272 | } | 278 | } |
@@ -280,16 +286,7 @@ void hists__delete_entries(struct hists *hists) | |||
280 | n = rb_entry(next, struct hist_entry, rb_node); | 286 | n = rb_entry(next, struct hist_entry, rb_node); |
281 | next = rb_next(&n->rb_node); | 287 | next = rb_next(&n->rb_node); |
282 | 288 | ||
283 | rb_erase(&n->rb_node, &hists->entries); | 289 | hists__delete_entry(hists, n); |
284 | |||
285 | if (sort__need_collapse) | ||
286 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | ||
287 | |||
288 | --hists->nr_entries; | ||
289 | if (!n->filtered) | ||
290 | --hists->nr_non_filtered_entries; | ||
291 | |||
292 | hist_entry__free(n); | ||
293 | } | 290 | } |
294 | } | 291 | } |
295 | 292 | ||
@@ -303,7 +300,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
303 | size_t callchain_size = 0; | 300 | size_t callchain_size = 0; |
304 | struct hist_entry *he; | 301 | struct hist_entry *he; |
305 | 302 | ||
306 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) | 303 | if (symbol_conf.use_callchain) |
307 | callchain_size = sizeof(struct callchain_root); | 304 | callchain_size = sizeof(struct callchain_root); |
308 | 305 | ||
309 | he = zalloc(sizeof(*he) + callchain_size); | 306 | he = zalloc(sizeof(*he) + callchain_size); |
@@ -432,6 +429,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
432 | if (!he) | 429 | if (!he) |
433 | return NULL; | 430 | return NULL; |
434 | 431 | ||
432 | hists->nr_entries++; | ||
433 | |||
435 | rb_link_node(&he->rb_node_in, parent, p); | 434 | rb_link_node(&he->rb_node_in, parent, p); |
436 | rb_insert_color(&he->rb_node_in, hists->entries_in); | 435 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
437 | out: | 436 | out: |
@@ -736,7 +735,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, | |||
736 | iter->he = he; | 735 | iter->he = he; |
737 | he_cache[iter->curr++] = he; | 736 | he_cache[iter->curr++] = he; |
738 | 737 | ||
739 | callchain_append(he->callchain, &callchain_cursor, sample->period); | 738 | hist_entry__append_callchain(he, sample); |
740 | 739 | ||
741 | /* | 740 | /* |
742 | * We need to re-initialize the cursor since callchain_append() | 741 | * We need to re-initialize the cursor since callchain_append() |
@@ -809,7 +808,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
809 | iter->he = he; | 808 | iter->he = he; |
810 | he_cache[iter->curr++] = he; | 809 | he_cache[iter->curr++] = he; |
811 | 810 | ||
812 | callchain_append(he->callchain, &cursor, sample->period); | 811 | if (symbol_conf.use_callchain) |
812 | callchain_append(he->callchain, &cursor, sample->period); | ||
813 | return 0; | 813 | return 0; |
814 | } | 814 | } |
815 | 815 | ||
@@ -913,7 +913,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) | |||
913 | if (perf_hpp__should_skip(fmt)) | 913 | if (perf_hpp__should_skip(fmt)) |
914 | continue; | 914 | continue; |
915 | 915 | ||
916 | cmp = fmt->cmp(left, right); | 916 | cmp = fmt->cmp(fmt, left, right); |
917 | if (cmp) | 917 | if (cmp) |
918 | break; | 918 | break; |
919 | } | 919 | } |
@@ -931,7 +931,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
931 | if (perf_hpp__should_skip(fmt)) | 931 | if (perf_hpp__should_skip(fmt)) |
932 | continue; | 932 | continue; |
933 | 933 | ||
934 | cmp = fmt->collapse(left, right); | 934 | cmp = fmt->collapse(fmt, left, right); |
935 | if (cmp) | 935 | if (cmp) |
936 | break; | 936 | break; |
937 | } | 937 | } |
@@ -939,12 +939,13 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
939 | return cmp; | 939 | return cmp; |
940 | } | 940 | } |
941 | 941 | ||
942 | void hist_entry__free(struct hist_entry *he) | 942 | void hist_entry__delete(struct hist_entry *he) |
943 | { | 943 | { |
944 | zfree(&he->branch_info); | 944 | zfree(&he->branch_info); |
945 | zfree(&he->mem_info); | 945 | zfree(&he->mem_info); |
946 | zfree(&he->stat_acc); | 946 | zfree(&he->stat_acc); |
947 | free_srcline(he->srcline); | 947 | free_srcline(he->srcline); |
948 | free_callchain(he->callchain); | ||
948 | free(he); | 949 | free(he); |
949 | } | 950 | } |
950 | 951 | ||
@@ -978,7 +979,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
978 | iter->callchain, | 979 | iter->callchain, |
979 | he->callchain); | 980 | he->callchain); |
980 | } | 981 | } |
981 | hist_entry__free(he); | 982 | hist_entry__delete(he); |
982 | return false; | 983 | return false; |
983 | } | 984 | } |
984 | 985 | ||
@@ -987,6 +988,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
987 | else | 988 | else |
988 | p = &(*p)->rb_right; | 989 | p = &(*p)->rb_right; |
989 | } | 990 | } |
991 | hists->nr_entries++; | ||
990 | 992 | ||
991 | rb_link_node(&he->rb_node_in, parent, p); | 993 | rb_link_node(&he->rb_node_in, parent, p); |
992 | rb_insert_color(&he->rb_node_in, root); | 994 | rb_insert_color(&he->rb_node_in, root); |
@@ -1024,7 +1026,10 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) | |||
1024 | if (!sort__need_collapse) | 1026 | if (!sort__need_collapse) |
1025 | return; | 1027 | return; |
1026 | 1028 | ||
1029 | hists->nr_entries = 0; | ||
1030 | |||
1027 | root = hists__get_rotate_entries_in(hists); | 1031 | root = hists__get_rotate_entries_in(hists); |
1032 | |||
1028 | next = rb_first(root); | 1033 | next = rb_first(root); |
1029 | 1034 | ||
1030 | while (next) { | 1035 | while (next) { |
@@ -1056,7 +1061,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) | |||
1056 | if (perf_hpp__should_skip(fmt)) | 1061 | if (perf_hpp__should_skip(fmt)) |
1057 | continue; | 1062 | continue; |
1058 | 1063 | ||
1059 | cmp = fmt->sort(a, b); | 1064 | cmp = fmt->sort(fmt, a, b); |
1060 | if (cmp) | 1065 | if (cmp) |
1061 | break; | 1066 | break; |
1062 | } | 1067 | } |
@@ -1119,7 +1124,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
1119 | rb_insert_color(&he->rb_node, entries); | 1124 | rb_insert_color(&he->rb_node, entries); |
1120 | } | 1125 | } |
1121 | 1126 | ||
1122 | void hists__output_resort(struct hists *hists) | 1127 | void hists__output_resort(struct hists *hists, struct ui_progress *prog) |
1123 | { | 1128 | { |
1124 | struct rb_root *root; | 1129 | struct rb_root *root; |
1125 | struct rb_node *next; | 1130 | struct rb_node *next; |
@@ -1148,6 +1153,9 @@ void hists__output_resort(struct hists *hists) | |||
1148 | 1153 | ||
1149 | if (!n->filtered) | 1154 | if (!n->filtered) |
1150 | hists__calc_col_len(hists, n); | 1155 | hists__calc_col_len(hists, n); |
1156 | |||
1157 | if (prog) | ||
1158 | ui_progress__update(prog, 1); | ||
1151 | } | 1159 | } |
1152 | } | 1160 | } |
1153 | 1161 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index d0ef9a19a744..2b690d028907 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -119,9 +119,9 @@ int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); | |||
119 | int hist_entry__transaction_len(void); | 119 | int hist_entry__transaction_len(void); |
120 | int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, | 120 | int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, |
121 | struct hists *hists); | 121 | struct hists *hists); |
122 | void hist_entry__free(struct hist_entry *); | 122 | void hist_entry__delete(struct hist_entry *he); |
123 | 123 | ||
124 | void hists__output_resort(struct hists *hists); | 124 | void hists__output_resort(struct hists *hists, struct ui_progress *prog); |
125 | void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); | 125 | void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); |
126 | 126 | ||
127 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); | 127 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); |
@@ -195,9 +195,12 @@ struct perf_hpp_fmt { | |||
195 | struct hist_entry *he); | 195 | struct hist_entry *he); |
196 | int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 196 | int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
197 | struct hist_entry *he); | 197 | struct hist_entry *he); |
198 | int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b); | 198 | int64_t (*cmp)(struct perf_hpp_fmt *fmt, |
199 | int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b); | 199 | struct hist_entry *a, struct hist_entry *b); |
200 | int64_t (*sort)(struct hist_entry *a, struct hist_entry *b); | 200 | int64_t (*collapse)(struct perf_hpp_fmt *fmt, |
201 | struct hist_entry *a, struct hist_entry *b); | ||
202 | int64_t (*sort)(struct perf_hpp_fmt *fmt, | ||
203 | struct hist_entry *a, struct hist_entry *b); | ||
201 | 204 | ||
202 | struct list_head list; | 205 | struct list_head list; |
203 | struct list_head sort_list; | 206 | struct list_head sort_list; |
diff --git a/tools/perf/util/hweight.c b/tools/perf/util/hweight.c deleted file mode 100644 index 5c1d0d099f0d..000000000000 --- a/tools/perf/util/hweight.c +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | #include <linux/bitops.h> | ||
2 | |||
3 | /** | ||
4 | * hweightN - returns the hamming weight of a N-bit word | ||
5 | * @x: the word to weigh | ||
6 | * | ||
7 | * The Hamming Weight of a number is the total number of bits set in it. | ||
8 | */ | ||
9 | |||
10 | unsigned int hweight32(unsigned int w) | ||
11 | { | ||
12 | unsigned int res = w - ((w >> 1) & 0x55555555); | ||
13 | res = (res & 0x33333333) + ((res >> 2) & 0x33333333); | ||
14 | res = (res + (res >> 4)) & 0x0F0F0F0F; | ||
15 | res = res + (res >> 8); | ||
16 | return (res + (res >> 16)) & 0x000000FF; | ||
17 | } | ||
18 | |||
19 | unsigned long hweight64(__u64 w) | ||
20 | { | ||
21 | #if BITS_PER_LONG == 32 | ||
22 | return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); | ||
23 | #elif BITS_PER_LONG == 64 | ||
24 | __u64 res = w - ((w >> 1) & 0x5555555555555555ul); | ||
25 | res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); | ||
26 | res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; | ||
27 | res = res + (res >> 8); | ||
28 | res = res + (res >> 16); | ||
29 | return (res + (res >> 32)) & 0x00000000000000FFul; | ||
30 | #endif | ||
31 | } | ||
diff --git a/tools/perf/util/include/asm/hweight.h b/tools/perf/util/include/asm/hweight.h deleted file mode 100644 index 36cf26d434a5..000000000000 --- a/tools/perf/util/include/asm/hweight.h +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #ifndef PERF_HWEIGHT_H | ||
2 | #define PERF_HWEIGHT_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | unsigned int hweight32(unsigned int w); | ||
6 | unsigned long hweight64(__u64 w); | ||
7 | |||
8 | #endif /* PERF_HWEIGHT_H */ | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 94de3e48b490..1bca3a9f2b16 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -389,7 +389,6 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
389 | if (th != NULL) { | 389 | if (th != NULL) { |
390 | rb_link_node(&th->rb_node, parent, p); | 390 | rb_link_node(&th->rb_node, parent, p); |
391 | rb_insert_color(&th->rb_node, &machine->threads); | 391 | rb_insert_color(&th->rb_node, &machine->threads); |
392 | machine->last_match = th; | ||
393 | 392 | ||
394 | /* | 393 | /* |
395 | * We have to initialize map_groups separately | 394 | * We have to initialize map_groups separately |
@@ -400,9 +399,12 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
400 | * leader and that would screwed the rb tree. | 399 | * leader and that would screwed the rb tree. |
401 | */ | 400 | */ |
402 | if (thread__init_map_groups(th, machine)) { | 401 | if (thread__init_map_groups(th, machine)) { |
402 | rb_erase(&th->rb_node, &machine->threads); | ||
403 | thread__delete(th); | 403 | thread__delete(th); |
404 | return NULL; | 404 | return NULL; |
405 | } | 405 | } |
406 | |||
407 | machine->last_match = th; | ||
406 | } | 408 | } |
407 | 409 | ||
408 | return th; | 410 | return th; |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 6951a9d42339..0e42438b1e59 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -116,6 +116,22 @@ struct thread; | |||
116 | #define map__for_each_symbol(map, pos, n) \ | 116 | #define map__for_each_symbol(map, pos, n) \ |
117 | dso__for_each_symbol(map->dso, pos, n, map->type) | 117 | dso__for_each_symbol(map->dso, pos, n, map->type) |
118 | 118 | ||
119 | /* map__for_each_symbol_with_name - iterate over the symbols in the given map | ||
120 | * that have the given name | ||
121 | * | ||
122 | * @map: the 'struct map *' in which symbols itereated | ||
123 | * @sym_name: the symbol name | ||
124 | * @pos: the 'struct symbol *' to use as a loop cursor | ||
125 | * @filter: to use when loading the DSO | ||
126 | */ | ||
127 | #define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \ | ||
128 | for (pos = map__find_symbol_by_name(map, sym_name, filter); \ | ||
129 | pos && strcmp(pos->name, sym_name) == 0; \ | ||
130 | pos = symbol__next_by_name(pos)) | ||
131 | |||
132 | #define map__for_each_symbol_by_name(map, sym_name, pos) \ | ||
133 | __map__for_each_symbol_by_name(map, sym_name, (pos), NULL) | ||
134 | |||
119 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | 135 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
120 | 136 | ||
121 | void map__init(struct map *map, enum map_type type, | 137 | void map__init(struct map *map, enum map_type type, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 77b43fe43d55..7f8ec6ce2823 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -526,7 +526,7 @@ do { \ | |||
526 | } | 526 | } |
527 | 527 | ||
528 | int parse_events_add_breakpoint(struct list_head *list, int *idx, | 528 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
529 | void *ptr, char *type) | 529 | void *ptr, char *type, u64 len) |
530 | { | 530 | { |
531 | struct perf_event_attr attr; | 531 | struct perf_event_attr attr; |
532 | 532 | ||
@@ -536,14 +536,15 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, | |||
536 | if (parse_breakpoint_type(type, &attr)) | 536 | if (parse_breakpoint_type(type, &attr)) |
537 | return -EINVAL; | 537 | return -EINVAL; |
538 | 538 | ||
539 | /* | 539 | /* Provide some defaults if len is not specified */ |
540 | * We should find a nice way to override the access length | 540 | if (!len) { |
541 | * Provide some defaults for now | 541 | if (attr.bp_type == HW_BREAKPOINT_X) |
542 | */ | 542 | len = sizeof(long); |
543 | if (attr.bp_type == HW_BREAKPOINT_X) | 543 | else |
544 | attr.bp_len = sizeof(long); | 544 | len = HW_BREAKPOINT_LEN_4; |
545 | else | 545 | } |
546 | attr.bp_len = HW_BREAKPOINT_LEN_4; | 546 | |
547 | attr.bp_len = len; | ||
547 | 548 | ||
548 | attr.type = PERF_TYPE_BREAKPOINT; | 549 | attr.type = PERF_TYPE_BREAKPOINT; |
549 | attr.sample_period = 1; | 550 | attr.sample_period = 1; |
@@ -1121,7 +1122,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | |||
1121 | return; | 1122 | return; |
1122 | 1123 | ||
1123 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 1124 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
1124 | if (subsys_glob != NULL && | 1125 | if (subsys_glob != NULL && |
1125 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | 1126 | !strglobmatch(sys_dirent.d_name, subsys_glob)) |
1126 | continue; | 1127 | continue; |
1127 | 1128 | ||
@@ -1132,7 +1133,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | |||
1132 | continue; | 1133 | continue; |
1133 | 1134 | ||
1134 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 1135 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
1135 | if (event_glob != NULL && | 1136 | if (event_glob != NULL && |
1136 | !strglobmatch(evt_dirent.d_name, event_glob)) | 1137 | !strglobmatch(evt_dirent.d_name, event_glob)) |
1137 | continue; | 1138 | continue; |
1138 | 1139 | ||
@@ -1305,7 +1306,7 @@ static void print_symbol_events(const char *event_glob, unsigned type, | |||
1305 | 1306 | ||
1306 | for (i = 0; i < max; i++, syms++) { | 1307 | for (i = 0; i < max; i++, syms++) { |
1307 | 1308 | ||
1308 | if (event_glob != NULL && | 1309 | if (event_glob != NULL && |
1309 | !(strglobmatch(syms->symbol, event_glob) || | 1310 | !(strglobmatch(syms->symbol, event_glob) || |
1310 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | 1311 | (syms->alias && strglobmatch(syms->alias, event_glob)))) |
1311 | continue; | 1312 | continue; |
@@ -1366,7 +1367,7 @@ void print_events(const char *event_glob, bool name_only) | |||
1366 | printf("\n"); | 1367 | printf("\n"); |
1367 | 1368 | ||
1368 | printf(" %-50s [%s]\n", | 1369 | printf(" %-50s [%s]\n", |
1369 | "mem:<addr>[:access]", | 1370 | "mem:<addr>[/len][:access]", |
1370 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); | 1371 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); |
1371 | printf("\n"); | 1372 | printf("\n"); |
1372 | } | 1373 | } |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index db2cf78ff0f3..ff6e1fa4111e 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -71,6 +71,7 @@ struct parse_events_term { | |||
71 | int type_val; | 71 | int type_val; |
72 | int type_term; | 72 | int type_term; |
73 | struct list_head list; | 73 | struct list_head list; |
74 | bool used; | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | struct parse_events_evlist { | 77 | struct parse_events_evlist { |
@@ -104,7 +105,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx, | |||
104 | int parse_events_add_cache(struct list_head *list, int *idx, | 105 | int parse_events_add_cache(struct list_head *list, int *idx, |
105 | char *type, char *op_result1, char *op_result2); | 106 | char *type, char *op_result1, char *op_result2); |
106 | int parse_events_add_breakpoint(struct list_head *list, int *idx, | 107 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
107 | void *ptr, char *type); | 108 | void *ptr, char *type, u64 len); |
108 | int parse_events_add_pmu(struct list_head *list, int *idx, | 109 | int parse_events_add_pmu(struct list_head *list, int *idx, |
109 | char *pmu , struct list_head *head_config); | 110 | char *pmu , struct list_head *head_config); |
110 | enum perf_pmu_event_symbol_type | 111 | enum perf_pmu_event_symbol_type |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 906630bbf8eb..94eacb6c1ef7 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -159,6 +159,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE | |||
159 | <mem>{ | 159 | <mem>{ |
160 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } | 160 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } |
161 | : { return ':'; } | 161 | : { return ':'; } |
162 | "/" { return '/'; } | ||
162 | {num_dec} { return value(yyscanner, 10); } | 163 | {num_dec} { return value(yyscanner, 10); } |
163 | {num_hex} { return value(yyscanner, 16); } | 164 | {num_hex} { return value(yyscanner, 16); } |
164 | /* | 165 | /* |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 93c4c9fbc922..72def077dbbf 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -326,6 +326,28 @@ PE_NAME_CACHE_TYPE | |||
326 | } | 326 | } |
327 | 327 | ||
328 | event_legacy_mem: | 328 | event_legacy_mem: |
329 | PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc | ||
330 | { | ||
331 | struct parse_events_evlist *data = _data; | ||
332 | struct list_head *list; | ||
333 | |||
334 | ALLOC_LIST(list); | ||
335 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | ||
336 | (void *) $2, $6, $4)); | ||
337 | $$ = list; | ||
338 | } | ||
339 | | | ||
340 | PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc | ||
341 | { | ||
342 | struct parse_events_evlist *data = _data; | ||
343 | struct list_head *list; | ||
344 | |||
345 | ALLOC_LIST(list); | ||
346 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | ||
347 | (void *) $2, NULL, $4)); | ||
348 | $$ = list; | ||
349 | } | ||
350 | | | ||
329 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 351 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
330 | { | 352 | { |
331 | struct parse_events_evlist *data = _data; | 353 | struct parse_events_evlist *data = _data; |
@@ -333,7 +355,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | |||
333 | 355 | ||
334 | ALLOC_LIST(list); | 356 | ALLOC_LIST(list); |
335 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | 357 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, |
336 | (void *) $2, $4)); | 358 | (void *) $2, $4, 0)); |
337 | $$ = list; | 359 | $$ = list; |
338 | } | 360 | } |
339 | | | 361 | | |
@@ -344,7 +366,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc | |||
344 | 366 | ||
345 | ALLOC_LIST(list); | 367 | ALLOC_LIST(list); |
346 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | 368 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, |
347 | (void *) $2, NULL)); | 369 | (void *) $2, NULL, 0)); |
348 | $$ = list; | 370 | $$ = list; |
349 | } | 371 | } |
350 | 372 | ||
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index f62dee7bd924..4a015f77e2b5 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -46,7 +46,7 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
46 | return opterror(opt, "is not usable", flags); | 46 | return opterror(opt, "is not usable", flags); |
47 | 47 | ||
48 | if (opt->flags & PARSE_OPT_EXCLUSIVE) { | 48 | if (opt->flags & PARSE_OPT_EXCLUSIVE) { |
49 | if (p->excl_opt) { | 49 | if (p->excl_opt && p->excl_opt != opt) { |
50 | char msg[128]; | 50 | char msg[128]; |
51 | 51 | ||
52 | if (((flags & OPT_SHORT) && p->excl_opt->short_name) || | 52 | if (((flags & OPT_SHORT) && p->excl_opt->short_name) || |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 5c9c4947cfb4..48411674da0f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -551,31 +551,68 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, | |||
551 | } | 551 | } |
552 | 552 | ||
553 | /* | 553 | /* |
554 | * Term is a string term, and might be a param-term. Try to look up it's value | ||
555 | * in the remaining terms. | ||
556 | * - We have a term like "base-or-format-term=param-term", | ||
557 | * - We need to find the value supplied for "param-term" (with param-term named | ||
558 | * in a config string) later on in the term list. | ||
559 | */ | ||
560 | static int pmu_resolve_param_term(struct parse_events_term *term, | ||
561 | struct list_head *head_terms, | ||
562 | __u64 *value) | ||
563 | { | ||
564 | struct parse_events_term *t; | ||
565 | |||
566 | list_for_each_entry(t, head_terms, list) { | ||
567 | if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { | ||
568 | if (!strcmp(t->config, term->config)) { | ||
569 | t->used = true; | ||
570 | *value = t->val.num; | ||
571 | return 0; | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | |||
576 | if (verbose) | ||
577 | printf("Required parameter '%s' not specified\n", term->config); | ||
578 | |||
579 | return -1; | ||
580 | } | ||
581 | |||
582 | /* | ||
554 | * Setup one of config[12] attr members based on the | 583 | * Setup one of config[12] attr members based on the |
555 | * user input data - term parameter. | 584 | * user input data - term parameter. |
556 | */ | 585 | */ |
557 | static int pmu_config_term(struct list_head *formats, | 586 | static int pmu_config_term(struct list_head *formats, |
558 | struct perf_event_attr *attr, | 587 | struct perf_event_attr *attr, |
559 | struct parse_events_term *term, | 588 | struct parse_events_term *term, |
589 | struct list_head *head_terms, | ||
560 | bool zero) | 590 | bool zero) |
561 | { | 591 | { |
562 | struct perf_pmu_format *format; | 592 | struct perf_pmu_format *format; |
563 | __u64 *vp; | 593 | __u64 *vp; |
594 | __u64 val; | ||
595 | |||
596 | /* | ||
597 | * If this is a parameter we've already used for parameterized-eval, | ||
598 | * skip it in normal eval. | ||
599 | */ | ||
600 | if (term->used) | ||
601 | return 0; | ||
564 | 602 | ||
565 | /* | 603 | /* |
566 | * Support only for hardcoded and numnerial terms. | ||
567 | * Hardcoded terms should be already in, so nothing | 604 | * Hardcoded terms should be already in, so nothing |
568 | * to be done for them. | 605 | * to be done for them. |
569 | */ | 606 | */ |
570 | if (parse_events__is_hardcoded_term(term)) | 607 | if (parse_events__is_hardcoded_term(term)) |
571 | return 0; | 608 | return 0; |
572 | 609 | ||
573 | if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) | ||
574 | return -EINVAL; | ||
575 | |||
576 | format = pmu_find_format(formats, term->config); | 610 | format = pmu_find_format(formats, term->config); |
577 | if (!format) | 611 | if (!format) { |
612 | if (verbose) | ||
613 | printf("Invalid event/parameter '%s'\n", term->config); | ||
578 | return -EINVAL; | 614 | return -EINVAL; |
615 | } | ||
579 | 616 | ||
580 | switch (format->value) { | 617 | switch (format->value) { |
581 | case PERF_PMU_FORMAT_VALUE_CONFIG: | 618 | case PERF_PMU_FORMAT_VALUE_CONFIG: |
@@ -592,11 +629,25 @@ static int pmu_config_term(struct list_head *formats, | |||
592 | } | 629 | } |
593 | 630 | ||
594 | /* | 631 | /* |
595 | * XXX If we ever decide to go with string values for | 632 | * Either directly use a numeric term, or try to translate string terms |
596 | * non-hardcoded terms, here's the place to translate | 633 | * using event parameters. |
597 | * them into value. | ||
598 | */ | 634 | */ |
599 | pmu_format_value(format->bits, term->val.num, vp, zero); | 635 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) |
636 | val = term->val.num; | ||
637 | else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { | ||
638 | if (strcmp(term->val.str, "?")) { | ||
639 | if (verbose) | ||
640 | pr_info("Invalid sysfs entry %s=%s\n", | ||
641 | term->config, term->val.str); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | |||
645 | if (pmu_resolve_param_term(term, head_terms, &val)) | ||
646 | return -EINVAL; | ||
647 | } else | ||
648 | return -EINVAL; | ||
649 | |||
650 | pmu_format_value(format->bits, val, vp, zero); | ||
600 | return 0; | 651 | return 0; |
601 | } | 652 | } |
602 | 653 | ||
@@ -607,9 +658,10 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
607 | { | 658 | { |
608 | struct parse_events_term *term; | 659 | struct parse_events_term *term; |
609 | 660 | ||
610 | list_for_each_entry(term, head_terms, list) | 661 | list_for_each_entry(term, head_terms, list) { |
611 | if (pmu_config_term(formats, attr, term, zero)) | 662 | if (pmu_config_term(formats, attr, term, head_terms, zero)) |
612 | return -EINVAL; | 663 | return -EINVAL; |
664 | } | ||
613 | 665 | ||
614 | return 0; | 666 | return 0; |
615 | } | 667 | } |
@@ -767,10 +819,36 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) | |||
767 | set_bit(b, bits); | 819 | set_bit(b, bits); |
768 | } | 820 | } |
769 | 821 | ||
822 | static int sub_non_neg(int a, int b) | ||
823 | { | ||
824 | if (b > a) | ||
825 | return 0; | ||
826 | return a - b; | ||
827 | } | ||
828 | |||
770 | static char *format_alias(char *buf, int len, struct perf_pmu *pmu, | 829 | static char *format_alias(char *buf, int len, struct perf_pmu *pmu, |
771 | struct perf_pmu_alias *alias) | 830 | struct perf_pmu_alias *alias) |
772 | { | 831 | { |
773 | snprintf(buf, len, "%s/%s/", pmu->name, alias->name); | 832 | struct parse_events_term *term; |
833 | int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); | ||
834 | |||
835 | list_for_each_entry(term, &alias->terms, list) { | ||
836 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) | ||
837 | used += snprintf(buf + used, sub_non_neg(len, used), | ||
838 | ",%s=%s", term->config, | ||
839 | term->val.str); | ||
840 | } | ||
841 | |||
842 | if (sub_non_neg(len, used) > 0) { | ||
843 | buf[used] = '/'; | ||
844 | used++; | ||
845 | } | ||
846 | if (sub_non_neg(len, used) > 0) { | ||
847 | buf[used] = '\0'; | ||
848 | used++; | ||
849 | } else | ||
850 | buf[len - 1] = '\0'; | ||
851 | |||
774 | return buf; | 852 | return buf; |
775 | } | 853 | } |
776 | 854 | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 28eb1417cb2a..919937eb0be2 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -446,7 +446,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, | |||
446 | } | 446 | } |
447 | 447 | ||
448 | for (i = 0; i < ntevs; i++) { | 448 | for (i = 0; i < ntevs; i++) { |
449 | if (tevs[i].point.address) { | 449 | if (tevs[i].point.address && !tevs[i].point.retprobe) { |
450 | tmp = strdup(reloc_sym->name); | 450 | tmp = strdup(reloc_sym->name); |
451 | if (!tmp) | 451 | if (!tmp) |
452 | return -ENOMEM; | 452 | return -ENOMEM; |
@@ -495,9 +495,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
495 | } | 495 | } |
496 | 496 | ||
497 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 497 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
498 | pr_warning("Probe point '%s' not found.\n", | 498 | pr_warning("Probe point '%s' not found in debuginfo.\n", |
499 | synthesize_perf_probe_point(&pev->point)); | 499 | synthesize_perf_probe_point(&pev->point)); |
500 | return -ENOENT; | 500 | if (need_dwarf) |
501 | return -ENOENT; | ||
502 | return 0; | ||
501 | } | 503 | } |
502 | /* Error path : ntevs < 0 */ | 504 | /* Error path : ntevs < 0 */ |
503 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); | 505 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); |
@@ -2050,9 +2052,11 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev) | |||
2050 | pr_debug("Writing event: %s\n", buf); | 2052 | pr_debug("Writing event: %s\n", buf); |
2051 | if (!probe_event_dry_run) { | 2053 | if (!probe_event_dry_run) { |
2052 | ret = write(fd, buf, strlen(buf)); | 2054 | ret = write(fd, buf, strlen(buf)); |
2053 | if (ret <= 0) | 2055 | if (ret <= 0) { |
2056 | ret = -errno; | ||
2054 | pr_warning("Failed to write event: %s\n", | 2057 | pr_warning("Failed to write event: %s\n", |
2055 | strerror_r(errno, sbuf, sizeof(sbuf))); | 2058 | strerror_r(errno, sbuf, sizeof(sbuf))); |
2059 | } | ||
2056 | } | 2060 | } |
2057 | free(buf); | 2061 | free(buf); |
2058 | return ret; | 2062 | return ret; |
@@ -2189,18 +2193,17 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2189 | return ret; | 2193 | return ret; |
2190 | } | 2194 | } |
2191 | 2195 | ||
2192 | static char *looking_function_name; | 2196 | static int find_probe_functions(struct map *map, char *name) |
2193 | static int num_matched_functions; | ||
2194 | |||
2195 | static int probe_function_filter(struct map *map __maybe_unused, | ||
2196 | struct symbol *sym) | ||
2197 | { | 2197 | { |
2198 | if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && | 2198 | int found = 0; |
2199 | strcmp(looking_function_name, sym->name) == 0) { | 2199 | struct symbol *sym; |
2200 | num_matched_functions++; | 2200 | |
2201 | return 0; | 2201 | map__for_each_symbol_by_name(map, name, sym) { |
2202 | if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) | ||
2203 | found++; | ||
2202 | } | 2204 | } |
2203 | return 1; | 2205 | |
2206 | return found; | ||
2204 | } | 2207 | } |
2205 | 2208 | ||
2206 | #define strdup_or_goto(str, label) \ | 2209 | #define strdup_or_goto(str, label) \ |
@@ -2218,10 +2221,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2218 | struct kmap *kmap = NULL; | 2221 | struct kmap *kmap = NULL; |
2219 | struct ref_reloc_sym *reloc_sym = NULL; | 2222 | struct ref_reloc_sym *reloc_sym = NULL; |
2220 | struct symbol *sym; | 2223 | struct symbol *sym; |
2221 | struct rb_node *nd; | ||
2222 | struct probe_trace_event *tev; | 2224 | struct probe_trace_event *tev; |
2223 | struct perf_probe_point *pp = &pev->point; | 2225 | struct perf_probe_point *pp = &pev->point; |
2224 | struct probe_trace_point *tp; | 2226 | struct probe_trace_point *tp; |
2227 | int num_matched_functions; | ||
2225 | int ret, i; | 2228 | int ret, i; |
2226 | 2229 | ||
2227 | /* Init maps of given executable or kernel */ | 2230 | /* Init maps of given executable or kernel */ |
@@ -2238,10 +2241,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2238 | * Load matched symbols: Since the different local symbols may have | 2241 | * Load matched symbols: Since the different local symbols may have |
2239 | * same name but different addresses, this lists all the symbols. | 2242 | * same name but different addresses, this lists all the symbols. |
2240 | */ | 2243 | */ |
2241 | num_matched_functions = 0; | 2244 | num_matched_functions = find_probe_functions(map, pp->function); |
2242 | looking_function_name = pp->function; | 2245 | if (num_matched_functions == 0) { |
2243 | ret = map__load(map, probe_function_filter); | ||
2244 | if (ret || num_matched_functions == 0) { | ||
2245 | pr_err("Failed to find symbol %s in %s\n", pp->function, | 2246 | pr_err("Failed to find symbol %s in %s\n", pp->function, |
2246 | target ? : "kernel"); | 2247 | target ? : "kernel"); |
2247 | ret = -ENOENT; | 2248 | ret = -ENOENT; |
@@ -2253,7 +2254,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2253 | goto out; | 2254 | goto out; |
2254 | } | 2255 | } |
2255 | 2256 | ||
2256 | if (!pev->uprobes) { | 2257 | if (!pev->uprobes && !pp->retprobe) { |
2257 | kmap = map__kmap(map); | 2258 | kmap = map__kmap(map); |
2258 | reloc_sym = kmap->ref_reloc_sym; | 2259 | reloc_sym = kmap->ref_reloc_sym; |
2259 | if (!reloc_sym) { | 2260 | if (!reloc_sym) { |
@@ -2271,7 +2272,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2271 | } | 2272 | } |
2272 | 2273 | ||
2273 | ret = 0; | 2274 | ret = 0; |
2274 | map__for_each_symbol(map, sym, nd) { | 2275 | |
2276 | map__for_each_symbol_by_name(map, pp->function, sym) { | ||
2275 | tev = (*tevs) + ret; | 2277 | tev = (*tevs) + ret; |
2276 | tp = &tev->point; | 2278 | tp = &tev->point; |
2277 | if (ret == num_matched_functions) { | 2279 | if (ret == num_matched_functions) { |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c7918f83b300..b5247d777f0e 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -989,8 +989,24 @@ static int debuginfo__find_probes(struct debuginfo *dbg, | |||
989 | int ret = 0; | 989 | int ret = 0; |
990 | 990 | ||
991 | #if _ELFUTILS_PREREQ(0, 142) | 991 | #if _ELFUTILS_PREREQ(0, 142) |
992 | Elf *elf; | ||
993 | GElf_Ehdr ehdr; | ||
994 | GElf_Shdr shdr; | ||
995 | |||
992 | /* Get the call frame information from this dwarf */ | 996 | /* Get the call frame information from this dwarf */ |
993 | pf->cfi = dwarf_getcfi_elf(dwarf_getelf(dbg->dbg)); | 997 | elf = dwarf_getelf(dbg->dbg); |
998 | if (elf == NULL) | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
1002 | return -EINVAL; | ||
1003 | |||
1004 | if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && | ||
1005 | shdr.sh_type == SHT_PROGBITS) { | ||
1006 | pf->cfi = dwarf_getcfi_elf(elf); | ||
1007 | } else { | ||
1008 | pf->cfi = dwarf_getcfi(dbg->dbg); | ||
1009 | } | ||
994 | #endif | 1010 | #endif |
995 | 1011 | ||
996 | off = 0; | 1012 | off = 0; |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 16a475a7d492..6c6a6953fa93 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -10,7 +10,7 @@ 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 | util/hweight.c | 13 | ../../lib/hweight.c |
14 | util/thread_map.c | 14 | util/thread_map.c |
15 | util/util.c | 15 | util/util.c |
16 | util/xyarray.c | 16 | util/xyarray.c |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 3dda85ca50c1..d906d0ad5d40 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -768,7 +768,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, | |||
768 | Py_DECREF(file); | 768 | Py_DECREF(file); |
769 | goto free_list; | 769 | goto free_list; |
770 | } | 770 | } |
771 | 771 | ||
772 | Py_DECREF(file); | 772 | Py_DECREF(file); |
773 | } | 773 | } |
774 | 774 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index d808a328f4dc..0c815a40a6e8 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -89,7 +89,7 @@ static void handler_call_die(const char *handler_name) | |||
89 | 89 | ||
90 | /* | 90 | /* |
91 | * Insert val into into the dictionary and decrement the reference counter. | 91 | * Insert val into into the dictionary and decrement the reference counter. |
92 | * This is necessary for dictionaries since PyDict_SetItemString() does not | 92 | * This is necessary for dictionaries since PyDict_SetItemString() does not |
93 | * steal a reference, as opposed to PyTuple_SetItem(). | 93 | * steal a reference, as opposed to PyTuple_SetItem(). |
94 | */ | 94 | */ |
95 | static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val) | 95 | static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val) |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 5f0e05a76c05..0baf75f12b7c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -274,7 +274,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
274 | if (tool->id_index == NULL) | 274 | if (tool->id_index == NULL) |
275 | tool->id_index = process_id_index_stub; | 275 | tool->id_index = process_id_index_stub; |
276 | } | 276 | } |
277 | 277 | ||
278 | static void swap_sample_id_all(union perf_event *event, void *data) | 278 | static void swap_sample_id_all(union perf_event *event, void *data) |
279 | { | 279 | { |
280 | void *end = (void *) event + event->header.size; | 280 | void *end = (void *) event + event->header.size; |
@@ -1251,9 +1251,9 @@ fetch_mmaped_event(struct perf_session *session, | |||
1251 | #define NUM_MMAPS 128 | 1251 | #define NUM_MMAPS 128 |
1252 | #endif | 1252 | #endif |
1253 | 1253 | ||
1254 | int __perf_session__process_events(struct perf_session *session, | 1254 | static int __perf_session__process_events(struct perf_session *session, |
1255 | u64 data_offset, u64 data_size, | 1255 | u64 data_offset, u64 data_size, |
1256 | u64 file_size, struct perf_tool *tool) | 1256 | u64 file_size, struct perf_tool *tool) |
1257 | { | 1257 | { |
1258 | int fd = perf_data_file__fd(session->file); | 1258 | int fd = perf_data_file__fd(session->file); |
1259 | u64 head, page_offset, file_offset, file_pos, size; | 1259 | u64 head, page_offset, file_offset, file_pos, size; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index dc26ebf60fe4..6d663dc76404 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -49,9 +49,6 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset, | |||
49 | union perf_event **event_ptr, | 49 | union perf_event **event_ptr, |
50 | struct perf_sample *sample); | 50 | struct perf_sample *sample); |
51 | 51 | ||
52 | int __perf_session__process_events(struct perf_session *session, | ||
53 | u64 data_offset, u64 data_size, u64 size, | ||
54 | struct perf_tool *tool); | ||
55 | int perf_session__process_events(struct perf_session *session, | 52 | int perf_session__process_events(struct perf_session *session, |
56 | struct perf_tool *tool); | 53 | struct perf_tool *tool); |
57 | 54 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 9139dda9f9a3..7a39c1ed8d37 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1304,6 +1304,37 @@ static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
1304 | return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); | 1304 | return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); |
1305 | } | 1305 | } |
1306 | 1306 | ||
1307 | static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt, | ||
1308 | struct hist_entry *a, struct hist_entry *b) | ||
1309 | { | ||
1310 | struct hpp_sort_entry *hse; | ||
1311 | |||
1312 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | ||
1313 | return hse->se->se_cmp(a, b); | ||
1314 | } | ||
1315 | |||
1316 | static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt, | ||
1317 | struct hist_entry *a, struct hist_entry *b) | ||
1318 | { | ||
1319 | struct hpp_sort_entry *hse; | ||
1320 | int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *); | ||
1321 | |||
1322 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | ||
1323 | collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp; | ||
1324 | return collapse_fn(a, b); | ||
1325 | } | ||
1326 | |||
1327 | static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt, | ||
1328 | struct hist_entry *a, struct hist_entry *b) | ||
1329 | { | ||
1330 | struct hpp_sort_entry *hse; | ||
1331 | int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *); | ||
1332 | |||
1333 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | ||
1334 | sort_fn = hse->se->se_sort ?: hse->se->se_cmp; | ||
1335 | return sort_fn(a, b); | ||
1336 | } | ||
1337 | |||
1307 | static struct hpp_sort_entry * | 1338 | static struct hpp_sort_entry * |
1308 | __sort_dimension__alloc_hpp(struct sort_dimension *sd) | 1339 | __sort_dimension__alloc_hpp(struct sort_dimension *sd) |
1309 | { | 1340 | { |
@@ -1322,9 +1353,9 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) | |||
1322 | hse->hpp.entry = __sort__hpp_entry; | 1353 | hse->hpp.entry = __sort__hpp_entry; |
1323 | hse->hpp.color = NULL; | 1354 | hse->hpp.color = NULL; |
1324 | 1355 | ||
1325 | hse->hpp.cmp = sd->entry->se_cmp; | 1356 | hse->hpp.cmp = __sort__hpp_cmp; |
1326 | hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp; | 1357 | hse->hpp.collapse = __sort__hpp_collapse; |
1327 | hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse; | 1358 | hse->hpp.sort = __sort__hpp_sort; |
1328 | 1359 | ||
1329 | INIT_LIST_HEAD(&hse->hpp.list); | 1360 | INIT_LIST_HEAD(&hse->hpp.list); |
1330 | INIT_LIST_HEAD(&hse->hpp.sort_list); | 1361 | INIT_LIST_HEAD(&hse->hpp.sort_list); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 06fcd1bf98b6..b24f9d8727a8 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -574,13 +574,16 @@ static int decompress_kmodule(struct dso *dso, const char *name, | |||
574 | const char *ext = strrchr(name, '.'); | 574 | const char *ext = strrchr(name, '.'); |
575 | char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; | 575 | char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; |
576 | 576 | ||
577 | if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && | 577 | if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && |
578 | type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) || | 578 | type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP && |
579 | type != dso->symtab_type) | 579 | type != DSO_BINARY_TYPE__BUILD_ID_CACHE) |
580 | return -1; | 580 | return -1; |
581 | 581 | ||
582 | if (!ext || !is_supported_compression(ext + 1)) | 582 | if (!ext || !is_supported_compression(ext + 1)) { |
583 | return -1; | 583 | ext = strrchr(dso->name, '.'); |
584 | if (!ext || !is_supported_compression(ext + 1)) | ||
585 | return -1; | ||
586 | } | ||
584 | 587 | ||
585 | fd = mkstemp(tmpbuf); | 588 | fd = mkstemp(tmpbuf); |
586 | if (fd < 0) | 589 | if (fd < 0) |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c24c5b83156c..a69066865a55 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -396,6 +396,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
396 | const char *name) | 396 | const char *name) |
397 | { | 397 | { |
398 | struct rb_node *n; | 398 | struct rb_node *n; |
399 | struct symbol_name_rb_node *s; | ||
399 | 400 | ||
400 | if (symbols == NULL) | 401 | if (symbols == NULL) |
401 | return NULL; | 402 | return NULL; |
@@ -403,7 +404,6 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
403 | n = symbols->rb_node; | 404 | n = symbols->rb_node; |
404 | 405 | ||
405 | while (n) { | 406 | while (n) { |
406 | struct symbol_name_rb_node *s; | ||
407 | int cmp; | 407 | int cmp; |
408 | 408 | ||
409 | s = rb_entry(n, struct symbol_name_rb_node, rb_node); | 409 | s = rb_entry(n, struct symbol_name_rb_node, rb_node); |
@@ -414,10 +414,24 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
414 | else if (cmp > 0) | 414 | else if (cmp > 0) |
415 | n = n->rb_right; | 415 | n = n->rb_right; |
416 | else | 416 | else |
417 | return &s->sym; | 417 | break; |
418 | } | 418 | } |
419 | 419 | ||
420 | return NULL; | 420 | if (n == NULL) |
421 | return NULL; | ||
422 | |||
423 | /* return first symbol that has same name (if any) */ | ||
424 | for (n = rb_prev(n); n; n = rb_prev(n)) { | ||
425 | struct symbol_name_rb_node *tmp; | ||
426 | |||
427 | tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); | ||
428 | if (strcmp(tmp->sym.name, s->sym.name)) | ||
429 | break; | ||
430 | |||
431 | s = tmp; | ||
432 | } | ||
433 | |||
434 | return &s->sym; | ||
421 | } | 435 | } |
422 | 436 | ||
423 | struct symbol *dso__find_symbol(struct dso *dso, | 437 | struct symbol *dso__find_symbol(struct dso *dso, |
@@ -436,6 +450,17 @@ struct symbol *dso__next_symbol(struct symbol *sym) | |||
436 | return symbols__next(sym); | 450 | return symbols__next(sym); |
437 | } | 451 | } |
438 | 452 | ||
453 | struct symbol *symbol__next_by_name(struct symbol *sym) | ||
454 | { | ||
455 | struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); | ||
456 | struct rb_node *n = rb_next(&s->rb_node); | ||
457 | |||
458 | return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * Teturns first symbol that matched with @name. | ||
463 | */ | ||
439 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 464 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
440 | const char *name) | 465 | const char *name) |
441 | { | 466 | { |
@@ -660,7 +685,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, | |||
660 | struct machine *machine = kmaps->machine; | 685 | struct machine *machine = kmaps->machine; |
661 | struct map *curr_map = map; | 686 | struct map *curr_map = map; |
662 | struct symbol *pos; | 687 | struct symbol *pos; |
663 | int count = 0, moved = 0; | 688 | int count = 0, moved = 0; |
664 | struct rb_root *root = &dso->symbols[map->type]; | 689 | struct rb_root *root = &dso->symbols[map->type]; |
665 | struct rb_node *next = rb_first(root); | 690 | struct rb_node *next = rb_first(root); |
666 | int kernel_range = 0; | 691 | int kernel_range = 0; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 9d602e9c6f59..1650dcb3a67b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -231,6 +231,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | |||
231 | u64 addr); | 231 | u64 addr); |
232 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 232 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
233 | const char *name); | 233 | const char *name); |
234 | struct symbol *symbol__next_by_name(struct symbol *sym); | ||
234 | 235 | ||
235 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | 236 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); |
236 | struct symbol *dso__next_symbol(struct symbol *sym); | 237 | struct symbol *dso__next_symbol(struct symbol *sym); |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 371219a6daf1..e3c40a520a25 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -185,6 +185,28 @@ static u64 elf_section_offset(int fd, const char *name) | |||
185 | return offset; | 185 | return offset; |
186 | } | 186 | } |
187 | 187 | ||
188 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | ||
189 | static int elf_is_exec(int fd, const char *name) | ||
190 | { | ||
191 | Elf *elf; | ||
192 | GElf_Ehdr ehdr; | ||
193 | int retval = 0; | ||
194 | |||
195 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
196 | if (elf == NULL) | ||
197 | return 0; | ||
198 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
199 | goto out; | ||
200 | |||
201 | retval = (ehdr.e_type == ET_EXEC); | ||
202 | |||
203 | out: | ||
204 | elf_end(elf); | ||
205 | pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); | ||
206 | return retval; | ||
207 | } | ||
208 | #endif | ||
209 | |||
188 | struct table_entry { | 210 | struct table_entry { |
189 | u32 start_ip_offset; | 211 | u32 start_ip_offset; |
190 | u32 fde_offset; | 212 | u32 fde_offset; |
@@ -244,14 +266,17 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | |||
244 | u64 *fde_count) | 266 | u64 *fde_count) |
245 | { | 267 | { |
246 | int ret = -EINVAL, fd; | 268 | int ret = -EINVAL, fd; |
247 | u64 offset; | 269 | u64 offset = dso->data.frame_offset; |
248 | 270 | ||
249 | fd = dso__data_fd(dso, machine); | 271 | if (offset == 0) { |
250 | if (fd < 0) | 272 | fd = dso__data_fd(dso, machine); |
251 | return -EINVAL; | 273 | if (fd < 0) |
274 | return -EINVAL; | ||
252 | 275 | ||
253 | /* Check the .eh_frame section for unwinding info */ | 276 | /* Check the .eh_frame section for unwinding info */ |
254 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 277 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
278 | dso->data.frame_offset = offset; | ||
279 | } | ||
255 | 280 | ||
256 | if (offset) | 281 | if (offset) |
257 | ret = unwind_spec_ehframe(dso, machine, offset, | 282 | ret = unwind_spec_ehframe(dso, machine, offset, |
@@ -265,14 +290,20 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | |||
265 | static int read_unwind_spec_debug_frame(struct dso *dso, | 290 | static int read_unwind_spec_debug_frame(struct dso *dso, |
266 | struct machine *machine, u64 *offset) | 291 | struct machine *machine, u64 *offset) |
267 | { | 292 | { |
268 | int fd = dso__data_fd(dso, machine); | 293 | int fd; |
294 | u64 ofs = dso->data.frame_offset; | ||
269 | 295 | ||
270 | if (fd < 0) | 296 | if (ofs == 0) { |
271 | return -EINVAL; | 297 | fd = dso__data_fd(dso, machine); |
298 | if (fd < 0) | ||
299 | return -EINVAL; | ||
272 | 300 | ||
273 | /* Check the .debug_frame section for unwinding info */ | 301 | /* Check the .debug_frame section for unwinding info */ |
274 | *offset = elf_section_offset(fd, ".debug_frame"); | 302 | ofs = elf_section_offset(fd, ".debug_frame"); |
303 | dso->data.frame_offset = ofs; | ||
304 | } | ||
275 | 305 | ||
306 | *offset = ofs; | ||
276 | if (*offset) | 307 | if (*offset) |
277 | return 0; | 308 | return 0; |
278 | 309 | ||
@@ -322,8 +353,12 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
322 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | 353 | #ifndef NO_LIBUNWIND_DEBUG_FRAME |
323 | /* Check the .debug_frame section for unwinding info */ | 354 | /* Check the .debug_frame section for unwinding info */ |
324 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 355 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
356 | int fd = dso__data_fd(map->dso, ui->machine); | ||
357 | int is_exec = elf_is_exec(fd, map->dso->name); | ||
358 | unw_word_t base = is_exec ? 0 : map->start; | ||
359 | |||
325 | memset(&di, 0, sizeof(di)); | 360 | memset(&di, 0, sizeof(di)); |
326 | if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | 361 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, |
327 | map->start, map->end)) | 362 | map->start, map->end)) |
328 | return dwarf_search_unwind_table(as, ip, &di, pi, | 363 | return dwarf_search_unwind_table(as, ip, &di, pi, |
329 | need_unwind_info, arg); | 364 | need_unwind_info, arg); |