aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 11:03:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 11:03:38 -0400
commit7115e3fcf45514db7525a05365b10454ff7f345e (patch)
tree17450e6337d559cc35dae6a7a73abab01ac63f00 /tools
parent1f6e05171bb5cc32a4d6437ab2269fc21d169ca7 (diff)
parentc752d04066a36ae30b29795f3fa3f536292c1f8c (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (121 commits) perf symbols: Increase symbol KSYM_NAME_LEN size perf hists browser: Refuse 'a' hotkey on non symbolic views perf ui browser: Use libslang to read keys perf tools: Fix tracing info recording perf hists browser: Elide DSO column when it is set to just one DSO, ditto for threads perf hists: Don't consider filtered entries when calculating column widths perf hists: Don't decay total_period for filtered entries perf hists browser: Honour symbol_conf.show_{nr_samples,total_period} perf hists browser: Do not exit on tab key with single event perf annotate browser: Don't change selection line when returning from callq perf tools: handle endianness of feature bitmap perf tools: Add prelink suggestion to dso update message perf script: Fix unknown feature comment perf hists browser: Apply the dso and thread filters when merging new batches perf hists: Move the dso and thread filters from hist_browser perf ui browser: Honour the xterm colors perf top tui: Give color hints just on the percentage, like on --stdio perf ui browser: Make the colors configurable and change the defaults perf tui: Remove unneeded call to newtCls on startup perf hists: Don't format the percentage on hist_entry__snprintf ... Fix up conflicts in arch/x86/kernel/kprobes.c manually. Ingo's tree did the insane "add volatile to const array", which just doesn't make sense ("volatile const"?). But we could remove the const *and* make the array volatile to make doubly sure that gcc doesn't optimize it away.. Also fix up kernel/trace/ring_buffer.c non-data-conflicts manually: the reader_lock has been turned into a raw lock by the core locking merge, and there was a new user of it introduced in this perf core merge. Make sure that new use also uses the raw accessor functions.
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-annotate.txt13
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt20
-rw-r--r--tools/perf/Documentation/perf-sched.txt6
-rw-r--r--tools/perf/Documentation/perf-script.txt7
-rw-r--r--tools/perf/Documentation/perf-stat.txt16
-rw-r--r--tools/perf/Documentation/perf-top.txt48
-rw-r--r--tools/perf/Documentation/perfconfig.example20
-rw-r--r--tools/perf/Makefile5
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/header.c36
-rw-r--r--tools/perf/arch/x86/Makefile1
-rw-r--r--tools/perf/arch/x86/util/header.c59
-rw-r--r--tools/perf/builtin-annotate.c25
-rw-r--r--tools/perf/builtin-buildid-list.c52
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-record.c34
-rw-r--r--tools/perf/builtin-report.c28
-rw-r--r--tools/perf/builtin-script.c6
-rw-r--r--tools/perf/builtin-stat.c190
-rw-r--r--tools/perf/builtin-top.c495
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.c24
-rw-r--r--tools/perf/perf.h13
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-record2
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-report4
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py72
-rw-r--r--tools/perf/util/annotate.c11
-rw-r--r--tools/perf/util/annotate.h9
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/evlist.c6
-rw-r--r--tools/perf/util/evlist.h4
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/header.c1231
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/hist.c447
-rw-r--r--tools/perf/util/hist.h61
-rw-r--r--tools/perf/util/map.c102
-rw-r--r--tools/perf/util/map.h42
-rw-r--r--tools/perf/util/probe-event.c4
-rw-r--r--tools/perf/util/session.c19
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/sort.c4
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/symbol.c3
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h39
-rw-r--r--tools/perf/util/trace-event-info.c112
-rw-r--r--tools/perf/util/trace-event.h13
-rw-r--r--tools/perf/util/ui/browser.c386
-rw-r--r--tools/perf/util/ui/browser.h12
-rw-r--r--tools/perf/util/ui/browsers/annotate.c201
-rw-r--r--tools/perf/util/ui/browsers/hists.c297
-rw-r--r--tools/perf/util/ui/browsers/map.c6
-rw-r--r--tools/perf/util/ui/browsers/top.c212
-rw-r--r--tools/perf/util/ui/helpline.h3
-rw-r--r--tools/perf/util/ui/keysyms.h25
-rw-r--r--tools/perf/util/ui/libslang.h2
-rw-r--r--tools/perf/util/ui/setup.c38
60 files changed, 3447 insertions, 1209 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 85c5f026930d..fe6762ed56bd 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -72,6 +72,19 @@ OPTIONS
72 CPUs are specified with -: 0-2. Default is to report samples on all 72 CPUs are specified with -: 0-2. Default is to report samples on all
73 CPUs. 73 CPUs.
74 74
75--asm-raw::
76 Show raw instruction encoding of assembly instructions.
77
78--source::
79 Interleave source code with assembly code. Enabled by default,
80 disable with --no-source.
81
82--symfs=<directory>::
83 Look for files with symbols relative to this directory.
84
85-M::
86--disassembler-style=:: Set disassembler style for objdump.
87
75SEE ALSO 88SEE ALSO
76-------- 89--------
77linkperf:perf-record[1], linkperf:perf-report[1] 90linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 5eaac6f26d51..cc22325ffd1b 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -16,6 +16,9 @@ This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by 16tools can be used to fetch packages with matching symbol tables for use by
17perf report. 17perf report.
18 18
19It can also be used to show the build id of the running kernel or in an ELF
20file using -i/--input.
21
19OPTIONS 22OPTIONS
20------- 23-------
21-H:: 24-H::
@@ -27,6 +30,9 @@ OPTIONS
27-f:: 30-f::
28--force:: 31--force::
29 Don't do ownership validation. 32 Don't do ownership validation.
33-k::
34--kernel::
35 Show running kernel build id.
30-v:: 36-v::
31--verbose:: 37--verbose::
32 Be more verbose. 38 Be more verbose.
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 04253c07d19a..212f24d672e1 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -134,6 +134,24 @@ OPTIONS
134 CPUs are specified with -: 0-2. Default is to report samples on all 134 CPUs are specified with -: 0-2. Default is to report samples on all
135 CPUs. 135 CPUs.
136 136
137-M::
138--disassembler-style=:: Set disassembler style for objdump.
139
140--source::
141 Interleave source code with assembly code. Enabled by default,
142 disable with --no-source.
143
144--asm-raw::
145 Show raw instruction encoding of assembly instructions.
146
147--show-total-period:: Show a column with the sum of periods.
148
149-I::
150--show-info::
151 Display extended information about the perf.data file. This adds
152 information which may be very large and thus may clutter the display.
153 It currently includes: cpu and numa topology of the host system.
154
137SEE ALSO 155SEE ALSO
138-------- 156--------
139linkperf:perf-stat[1] 157linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 46822d5fde1c..5b212b57f70b 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|map|replay|trace} 11'perf sched' {record|latency|map|replay|script}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,8 +20,8 @@ There are five variants of perf sched:
20 'perf sched latency' to report the per task scheduling latencies 20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload. 21 and other scheduling properties of the workload.
22 22
23 'perf sched trace' to see a detailed trace of the workload that 23 'perf sched script' to see a detailed trace of the workload that
24 was recorded. 24 was recorded (aliased to 'perf script' for now).
25 25
26 'perf sched replay' to simulate the workload that was recorded 26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads 27 via perf sched record. (this is done by starting up mockup threads
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index db017867d9e8..dec87ecb530e 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -188,6 +188,13 @@ OPTIONS
188 CPUs are specified with -: 0-2. Default is to report samples on all 188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs. 189 CPUs.
190 190
191-I::
192--show-info::
193 Display extended information about the perf.data file. This adds
194 information which may be very large and thus may clutter the display.
195 It currently includes: cpu and numa topology of the host system.
196 It can only be used with the perf script report mode.
197
191SEE ALSO 198SEE ALSO
192-------- 199--------
193linkperf:perf-record[1], linkperf:perf-script-perl[1], 200linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 918cc38ee6d1..8966b9ab2014 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -94,6 +94,22 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
94corresponding events, i.e., they always refer to events defined earlier on the command 94corresponding events, i.e., they always refer to events defined earlier on the command
95line. 95line.
96 96
97-o file::
98--output file::
99Print the output into the designated file.
100
101--append::
102Append to the output file designated with the -o option. Ignored if -o is not specified.
103
104--log-fd::
105
106Log output to fd, instead of stderr. Complementary to --output, and mutually exclusive
107with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd
110
111
112
97EXAMPLES 113EXAMPLES
98-------- 114--------
99 115
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index f6eb1cdafb77..b1a5bbbfebef 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -106,6 +106,51 @@ Default is to monitor all CPUS.
106--zero:: 106--zero::
107 Zero history across display updates. 107 Zero history across display updates.
108 108
109-s::
110--sort::
111 Sort by key(s): pid, comm, dso, symbol, parent
112
113-n::
114--show-nr-samples::
115 Show a column with the number of samples.
116
117--show-total-period::
118 Show a column with the sum of periods.
119
120--dsos::
121 Only consider symbols in these dsos.
122
123--comms::
124 Only consider symbols in these comms.
125
126--symbols::
127 Only consider these symbols.
128
129-M::
130--disassembler-style=:: Set disassembler style for objdump.
131
132--source::
133 Interleave source code with assembly code. Enabled by default,
134 disable with --no-source.
135
136--asm-raw::
137 Show raw instruction encoding of assembly instructions.
138
139-G [type,min,order]::
140--call-graph::
141 Display call chains using type, min percent threshold and order.
142 type can be either:
143 - flat: single column, linear exposure of call chains.
144 - graph: use a graph tree, displaying absolute overhead rates.
145 - fractal: like graph, but displays relative rates. Each branch of
146 the tree is considered as a new profiled object.
147
148 order can be either:
149 - callee: callee based call graph.
150 - caller: inverted caller based call graph.
151
152 Default: fractal,0.5,callee.
153
109INTERACTIVE PROMPTING KEYS 154INTERACTIVE PROMPTING KEYS
110-------------------------- 155--------------------------
111 156
@@ -130,9 +175,6 @@ INTERACTIVE PROMPTING KEYS
130[S]:: 175[S]::
131 Stop annotation, return to full profile display. 176 Stop annotation, return to full profile display.
132 177
133[w]::
134 Toggle between weighted sum and individual count[E]r profile.
135
136[z]:: 178[z]::
137 Toggle event count zeroing across display updates. 179 Toggle event count zeroing across display updates.
138 180
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
new file mode 100644
index 000000000000..d1448668f4d4
--- /dev/null
+++ b/tools/perf/Documentation/perfconfig.example
@@ -0,0 +1,20 @@
1[colors]
2
3 # These were the old defaults
4 top = red, lightgray
5 medium = green, lightgray
6 normal = black, lightgray
7 selected = lightgray, magenta
8 code = blue, lightgray
9
10[tui]
11
12 # Defaults if linked with libslang
13 report = on
14 annotate = on
15 top = on
16
17[buildid]
18
19 # Default, disable using /dev/null
20 dir = /root/.debug
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index e9d5c271db69..b98e3075646b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -466,13 +466,13 @@ else
466 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 466 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
467 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 467 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
468 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 468 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
469 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
470 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 469 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
471 LIB_OBJS += $(OUTPUT)util/ui/progress.o 470 LIB_OBJS += $(OUTPUT)util/ui/progress.o
472 LIB_OBJS += $(OUTPUT)util/ui/util.o 471 LIB_OBJS += $(OUTPUT)util/ui/util.o
473 LIB_H += util/ui/browser.h 472 LIB_H += util/ui/browser.h
474 LIB_H += util/ui/browsers/map.h 473 LIB_H += util/ui/browsers/map.h
475 LIB_H += util/ui/helpline.h 474 LIB_H += util/ui/helpline.h
475 LIB_H += util/ui/keysyms.h
476 LIB_H += util/ui/libslang.h 476 LIB_H += util/ui/libslang.h
477 LIB_H += util/ui/progress.h 477 LIB_H += util/ui/progress.h
478 LIB_H += util/ui/util.h 478 LIB_H += util/ui/util.h
@@ -729,9 +729,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
729$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 729$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
731 731
732$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
734
735$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 732$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
736 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
737 734
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
new file mode 100644
index 000000000000..eba80c292945
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -0,0 +1,36 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15
16#define SPRN_PVR 0x11F /* Processor Version Register */
17#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
18#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
19
20int
21get_cpuid(char *buffer, size_t sz)
22{
23 unsigned long pvr;
24 int nb;
25
26 pvr = mfspr(SPRN_PVR);
27
28 nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
29
30 /* look for end marker to ensure the entire data fit */
31 if (strchr(buffer, '$')) {
32 buffer[nb-1] = '\0';
33 return 0;
34 }
35 return -1;
36}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
new file mode 100644
index 000000000000..f94006068d2b
--- /dev/null
+++ b/tools/perf/arch/x86/util/header.c
@@ -0,0 +1,59 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9static inline void
10cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
11 unsigned int *d)
12{
13 __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
14 "movl %%ebx, %%esi\n\t.byte 0x5b"
15 : "=a" (*a),
16 "=S" (*b),
17 "=c" (*c),
18 "=d" (*d)
19 : "a" (op));
20}
21
22int
23get_cpuid(char *buffer, size_t sz)
24{
25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1;
27 int nb;
28 char vendor[16];
29
30 cpuid(0, &lvl, &b, &c, &d);
31 strncpy(&vendor[0], (char *)(&b), 4);
32 strncpy(&vendor[4], (char *)(&d), 4);
33 strncpy(&vendor[8], (char *)(&c), 4);
34 vendor[12] = '\0';
35
36 if (lvl >= 1) {
37 cpuid(1, &a, &b, &c, &d);
38
39 family = (a >> 8) & 0xf; /* bits 11 - 8 */
40 model = (a >> 4) & 0xf; /* Bits 7 - 4 */
41 step = a & 0xf;
42
43 /* extended family */
44 if (family == 0xf)
45 family += (a >> 20) & 0xff;
46
47 /* extended model */
48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4;
50 }
51 nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
52
53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) {
55 buffer[nb-1] = '\0';
56 return 0;
57 }
58 return -1;
59}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 555aefd7fe01..46b4c24f338e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -114,10 +114,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
114 print_line, full_paths, 0, 0); 114 print_line, full_paths, 0, 0);
115} 115}
116 116
117static void hists__find_annotations(struct hists *self, int evidx) 117static void hists__find_annotations(struct hists *self, int evidx,
118 int nr_events)
118{ 119{
119 struct rb_node *nd = rb_first(&self->entries), *next; 120 struct rb_node *nd = rb_first(&self->entries), *next;
120 int key = KEY_RIGHT; 121 int key = K_RIGHT;
121 122
122 while (nd) { 123 while (nd) {
123 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 124 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
@@ -129,7 +130,7 @@ static void hists__find_annotations(struct hists *self, int evidx)
129 notes = symbol__annotation(he->ms.sym); 130 notes = symbol__annotation(he->ms.sym);
130 if (notes->src == NULL) { 131 if (notes->src == NULL) {
131find_next: 132find_next:
132 if (key == KEY_LEFT) 133 if (key == K_LEFT)
133 nd = rb_prev(nd); 134 nd = rb_prev(nd);
134 else 135 else
135 nd = rb_next(nd); 136 nd = rb_next(nd);
@@ -137,12 +138,13 @@ find_next:
137 } 138 }
138 139
139 if (use_browser > 0) { 140 if (use_browser > 0) {
140 key = hist_entry__tui_annotate(he, evidx); 141 key = hist_entry__tui_annotate(he, evidx, nr_events,
142 NULL, NULL, 0);
141 switch (key) { 143 switch (key) {
142 case KEY_RIGHT: 144 case K_RIGHT:
143 next = rb_next(nd); 145 next = rb_next(nd);
144 break; 146 break;
145 case KEY_LEFT: 147 case K_LEFT:
146 next = rb_prev(nd); 148 next = rb_prev(nd);
147 break; 149 break;
148 default: 150 default:
@@ -215,7 +217,8 @@ static int __cmd_annotate(void)
215 total_nr_samples += nr_samples; 217 total_nr_samples += nr_samples;
216 hists__collapse_resort(hists); 218 hists__collapse_resort(hists);
217 hists__output_resort(hists); 219 hists__output_resort(hists);
218 hists__find_annotations(hists, pos->idx); 220 hists__find_annotations(hists, pos->idx,
221 session->evlist->nr_entries);
219 } 222 }
220 } 223 }
221 224
@@ -267,6 +270,14 @@ static const struct option options[] = {
267 OPT_BOOLEAN('P', "full-paths", &full_paths, 270 OPT_BOOLEAN('P', "full-paths", &full_paths,
268 "Don't shorten the displayed pathnames"), 271 "Don't shorten the displayed pathnames"),
269 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 272 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
274 "Look for files with symbols relative to this directory"),
275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
276 "Interleave source code with assembly code (default)"),
277 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
278 "Display raw encoding of assembly instructions (default)"),
279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
280 "Specify disassembler style (e.g. -M intel for intel syntax)"),
270 OPT_END() 281 OPT_END()
271}; 282};
272 283
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 5af32ae9031e..cb690a65bf02 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * builtin-buildid-list.c 2 * builtin-buildid-list.c
3 * 3 *
4 * Builtin buildid-list command: list buildids in perf.data 4 * Builtin buildid-list command: list buildids in perf.data, in the running
5 * kernel and in ELF files.
5 * 6 *
6 * Copyright (C) 2009, Red Hat Inc. 7 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> 8 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
@@ -15,8 +16,11 @@
15#include "util/session.h" 16#include "util/session.h"
16#include "util/symbol.h" 17#include "util/symbol.h"
17 18
19#include <libelf.h>
20
18static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
19static bool force; 22static bool force;
23static bool show_kernel;
20static bool with_hits; 24static bool with_hits;
21 25
22static const char * const buildid_list_usage[] = { 26static const char * const buildid_list_usage[] = {
@@ -29,12 +33,13 @@ static const struct option options[] = {
29 OPT_STRING('i', "input", &input_name, "file", 33 OPT_STRING('i', "input", &input_name, "file",
30 "input file name"), 34 "input file name"),
31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 35 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
36 OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
32 OPT_INCR('v', "verbose", &verbose, 37 OPT_INCR('v', "verbose", &verbose,
33 "be more verbose"), 38 "be more verbose"),
34 OPT_END() 39 OPT_END()
35}; 40};
36 41
37static int __cmd_buildid_list(void) 42static int perf_session__list_build_ids(void)
38{ 43{
39 struct perf_session *session; 44 struct perf_session *session;
40 45
@@ -52,6 +57,49 @@ static int __cmd_buildid_list(void)
52 return 0; 57 return 0;
53} 58}
54 59
60static int sysfs__fprintf_build_id(FILE *fp)
61{
62 u8 kallsyms_build_id[BUILD_ID_SIZE];
63 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
64
65 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
66 sizeof(kallsyms_build_id)) != 0)
67 return -1;
68
69 build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
70 sbuild_id);
71 fprintf(fp, "%s\n", sbuild_id);
72 return 0;
73}
74
75static int filename__fprintf_build_id(const char *name, FILE *fp)
76{
77 u8 build_id[BUILD_ID_SIZE];
78 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
79
80 if (filename__read_build_id(name, build_id,
81 sizeof(build_id)) != sizeof(build_id))
82 return 0;
83
84 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
85 return fprintf(fp, "%s\n", sbuild_id);
86}
87
88static int __cmd_buildid_list(void)
89{
90 if (show_kernel)
91 return sysfs__fprintf_build_id(stdout);
92
93 elf_version(EV_CURRENT);
94 /*
95 * See if this is an ELF file first:
96 */
97 if (filename__fprintf_build_id(input_name, stdout))
98 return 0;
99
100 return perf_session__list_build_ids();
101}
102
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 103int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
56{ 104{
57 argc = parse_options(argc, argv, options, buildid_list_usage, 0); 105 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e8219990f8b8..b39f3a1ee7dc 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -162,7 +162,7 @@ static int __cmd_diff(void)
162 162
163 hists__match(&session[0]->hists, &session[1]->hists); 163 hists__match(&session[0]->hists, &session[1]->hists);
164 hists__fprintf(&session[1]->hists, &session[0]->hists, 164 hists__fprintf(&session[1]->hists, &session[0]->hists,
165 show_displacement, stdout); 165 show_displacement, true, 0, 0, stdout);
166out_delete: 166out_delete:
167 for (i = 0; i < 2; ++i) 167 for (i = 0; i < 2; ++i)
168 perf_session__delete(session[i]); 168 perf_session__delete(session[i]);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f4c3fbee4bad..f82480fa7f27 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -73,6 +73,7 @@ static off_t post_processing_offset;
73 73
74static struct perf_session *session; 74static struct perf_session *session;
75static const char *cpu_list; 75static const char *cpu_list;
76static const char *progname;
76 77
77static void advance_output(size_t size) 78static void advance_output(size_t size)
78{ 79{
@@ -137,17 +138,29 @@ static void mmap_read(struct perf_mmap *md)
137 138
138static volatile int done = 0; 139static volatile int done = 0;
139static volatile int signr = -1; 140static volatile int signr = -1;
141static volatile int child_finished = 0;
140 142
141static void sig_handler(int sig) 143static void sig_handler(int sig)
142{ 144{
145 if (sig == SIGCHLD)
146 child_finished = 1;
147
143 done = 1; 148 done = 1;
144 signr = sig; 149 signr = sig;
145} 150}
146 151
147static void sig_atexit(void) 152static void sig_atexit(void)
148{ 153{
149 if (child_pid > 0) 154 int status;
150 kill(child_pid, SIGTERM); 155
156 if (child_pid > 0) {
157 if (!child_finished)
158 kill(child_pid, SIGTERM);
159
160 wait(&status);
161 if (WIFSIGNALED(status))
162 psignal(WTERMSIG(status), progname);
163 }
151 164
152 if (signr == -1 || signr == SIGUSR1) 165 if (signr == -1 || signr == SIGUSR1)
153 return; 166 return;
@@ -446,6 +459,8 @@ static int __cmd_record(int argc, const char **argv)
446 char buf; 459 char buf;
447 struct machine *machine; 460 struct machine *machine;
448 461
462 progname = argv[0];
463
449 page_size = sysconf(_SC_PAGE_SIZE); 464 page_size = sysconf(_SC_PAGE_SIZE);
450 465
451 atexit(sig_atexit); 466 atexit(sig_atexit);
@@ -514,6 +529,19 @@ static int __cmd_record(int argc, const char **argv)
514 if (have_tracepoints(&evsel_list->entries)) 529 if (have_tracepoints(&evsel_list->entries))
515 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 530 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
516 531
532 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
533 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
534 perf_header__set_feat(&session->header, HEADER_ARCH);
535 perf_header__set_feat(&session->header, HEADER_CPUDESC);
536 perf_header__set_feat(&session->header, HEADER_NRCPUS);
537 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
538 perf_header__set_feat(&session->header, HEADER_CMDLINE);
539 perf_header__set_feat(&session->header, HEADER_VERSION);
540 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
541 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
542 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
543 perf_header__set_feat(&session->header, HEADER_CPUID);
544
517 /* 512 kiB: default amount of unprivileged mlocked memory */ 545 /* 512 kiB: default amount of unprivileged mlocked memory */
518 if (mmap_pages == UINT_MAX) 546 if (mmap_pages == UINT_MAX)
519 mmap_pages = (512 * 1024) / page_size; 547 mmap_pages = (512 * 1024) / page_size;
@@ -785,6 +813,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
785 int err = -ENOMEM; 813 int err = -ENOMEM;
786 struct perf_evsel *pos; 814 struct perf_evsel *pos;
787 815
816 perf_header__set_cmdline(argc, argv);
817
788 evsel_list = perf_evlist__new(NULL, NULL); 818 evsel_list = perf_evlist__new(NULL, NULL);
789 if (evsel_list == NULL) 819 if (evsel_list == NULL)
790 return -ENOMEM; 820 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d7ff277bdb78..4d7c8340c326 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -40,6 +40,7 @@ static char const *input_name = "perf.data";
40static bool force, use_tui, use_stdio; 40static bool force, use_tui, use_stdio;
41static bool hide_unresolved; 41static bool hide_unresolved;
42static bool dont_use_callchains; 42static bool dont_use_callchains;
43static bool show_full_info;
43 44
44static bool show_threads; 45static bool show_threads;
45static struct perf_read_values show_threads_values; 46static struct perf_read_values show_threads_values;
@@ -229,13 +230,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
229 230
230 list_for_each_entry(pos, &evlist->entries, node) { 231 list_for_each_entry(pos, &evlist->entries, node) {
231 struct hists *hists = &pos->hists; 232 struct hists *hists = &pos->hists;
232 const char *evname = NULL; 233 const char *evname = event_name(pos);
233
234 if (rb_first(&hists->entries) != rb_last(&hists->entries))
235 evname = event_name(pos);
236 234
237 hists__fprintf_nr_sample_events(hists, evname, stdout); 235 hists__fprintf_nr_sample_events(hists, evname, stdout);
238 hists__fprintf(hists, NULL, false, stdout); 236 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
239 fprintf(stdout, "\n\n"); 237 fprintf(stdout, "\n\n");
240 } 238 }
241 239
@@ -276,6 +274,9 @@ static int __cmd_report(void)
276 goto out_delete; 274 goto out_delete;
277 } 275 }
278 276
277 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info);
279
279 if (show_threads) 280 if (show_threads)
280 perf_read_values_init(&show_threads_values); 281 perf_read_values_init(&show_threads_values);
281 282
@@ -330,9 +331,10 @@ static int __cmd_report(void)
330 goto out_delete; 331 goto out_delete;
331 } 332 }
332 333
333 if (use_browser > 0) 334 if (use_browser > 0) {
334 perf_evlist__tui_browse_hists(session->evlist, help); 335 perf_evlist__tui_browse_hists(session->evlist, help,
335 else 336 NULL, NULL, 0);
337 } else
336 perf_evlist__tty_browse_hists(session->evlist, help); 338 perf_evlist__tty_browse_hists(session->evlist, help);
337 339
338out_delete: 340out_delete:
@@ -487,6 +489,16 @@ static const struct option options[] = {
487 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
488 "Look for files with symbols relative to this directory"), 490 "Look for files with symbols relative to this directory"),
489 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 491 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
492 OPT_BOOLEAN('I', "show-info", &show_full_info,
493 "Display extended information about perf.data file"),
494 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
495 "Interleave source code with assembly code (default)"),
496 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
497 "Display raw encoding of assembly instructions (default)"),
498 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
499 "Specify disassembler style (e.g. -M intel for intel syntax)"),
500 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
501 "Show a column with the sum of periods"),
490 OPT_END() 502 OPT_END()
491}; 503};
492 504
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 09024ec2ab2e..2f62a2952269 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -22,6 +22,7 @@ static u64 last_timestamp;
22static u64 nr_unordered; 22static u64 nr_unordered;
23extern const struct option record_options[]; 23extern const struct option record_options[];
24static bool no_callchain; 24static bool no_callchain;
25static bool show_full_info;
25static const char *cpu_list; 26static const char *cpu_list;
26static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 27static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
27 28
@@ -1083,7 +1084,8 @@ static const struct option options[] = {
1083 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", 1084 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
1084 parse_output_fields), 1085 parse_output_fields),
1085 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 1086 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1086 1087 OPT_BOOLEAN('I', "show-info", &show_full_info,
1088 "display extended information from perf.data file"),
1087 OPT_END() 1089 OPT_END()
1088}; 1090};
1089 1091
@@ -1268,6 +1270,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1268 return -1; 1270 return -1;
1269 } 1271 }
1270 1272
1273 perf_session__fprintf_info(session, stdout, show_full_info);
1274
1271 if (!no_callchain) 1275 if (!no_callchain)
1272 symbol_conf.use_callchain = true; 1276 symbol_conf.use_callchain = true;
1273 else 1277 else
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5deb17d9e795..7ce65f52415e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -194,6 +194,9 @@ static const char *cpu_list;
194static const char *csv_sep = NULL; 194static const char *csv_sep = NULL;
195static bool csv_output = false; 195static bool csv_output = false;
196static bool group = false; 196static bool group = false;
197static const char *output_name = NULL;
198static FILE *output = NULL;
199static int output_fd;
197 200
198static volatile int done = 0; 201static volatile int done = 0;
199 202
@@ -251,8 +254,13 @@ static double avg_stats(struct stats *stats)
251 */ 254 */
252static double stddev_stats(struct stats *stats) 255static double stddev_stats(struct stats *stats)
253{ 256{
254 double variance = stats->M2 / (stats->n - 1); 257 double variance, variance_mean;
255 double variance_mean = variance / stats->n; 258
259 if (!stats->n)
260 return 0.0;
261
262 variance = stats->M2 / (stats->n - 1);
263 variance_mean = variance / stats->n;
256 264
257 return sqrt(variance_mean); 265 return sqrt(variance_mean);
258} 266}
@@ -352,7 +360,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
352 update_stats(&ps->res_stats[i], count[i]); 360 update_stats(&ps->res_stats[i], count[i]);
353 361
354 if (verbose) { 362 if (verbose) {
355 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 363 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
356 event_name(counter), count[0], count[1], count[2]); 364 event_name(counter), count[0], count[1], count[2]);
357 } 365 }
358 366
@@ -487,6 +495,8 @@ static int run_perf_stat(int argc __used, const char **argv)
487 if (forks) { 495 if (forks) {
488 close(go_pipe[1]); 496 close(go_pipe[1]);
489 wait(&status); 497 wait(&status);
498 if (WIFSIGNALED(status))
499 psignal(WTERMSIG(status), argv[0]);
490 } else { 500 } else {
491 while(!done) sleep(1); 501 while(!done) sleep(1);
492 } 502 }
@@ -519,9 +529,9 @@ static void print_noise_pct(double total, double avg)
519 pct = 100.0*total/avg; 529 pct = 100.0*total/avg;
520 530
521 if (csv_output) 531 if (csv_output)
522 fprintf(stderr, "%s%.2f%%", csv_sep, pct); 532 fprintf(output, "%s%.2f%%", csv_sep, pct);
523 else 533 else if (pct)
524 fprintf(stderr, " ( +-%6.2f%% )", pct); 534 fprintf(output, " ( +-%6.2f%% )", pct);
525} 535}
526 536
527static void print_noise(struct perf_evsel *evsel, double avg) 537static void print_noise(struct perf_evsel *evsel, double avg)
@@ -546,16 +556,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
546 csv_output ? 0 : -4, 556 csv_output ? 0 : -4,
547 evsel_list->cpus->map[cpu], csv_sep); 557 evsel_list->cpus->map[cpu], csv_sep);
548 558
549 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 559 fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
550 560
551 if (evsel->cgrp) 561 if (evsel->cgrp)
552 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 562 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
553 563
554 if (csv_output) 564 if (csv_output)
555 return; 565 return;
556 566
557 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 567 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
558 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); 568 fprintf(output, " # %8.3f CPUs utilized ",
569 avg / avg_stats(&walltime_nsecs_stats));
559} 570}
560 571
561static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 572static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -576,9 +587,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
576 else if (ratio > 10.0) 587 else if (ratio > 10.0)
577 color = PERF_COLOR_YELLOW; 588 color = PERF_COLOR_YELLOW;
578 589
579 fprintf(stderr, " # "); 590 fprintf(output, " # ");
580 color_fprintf(stderr, color, "%6.2f%%", ratio); 591 color_fprintf(output, color, "%6.2f%%", ratio);
581 fprintf(stderr, " frontend cycles idle "); 592 fprintf(output, " frontend cycles idle ");
582} 593}
583 594
584static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) 595static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -599,9 +610,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
599 else if (ratio > 20.0) 610 else if (ratio > 20.0)
600 color = PERF_COLOR_YELLOW; 611 color = PERF_COLOR_YELLOW;
601 612
602 fprintf(stderr, " # "); 613 fprintf(output, " # ");
603 color_fprintf(stderr, color, "%6.2f%%", ratio); 614 color_fprintf(output, color, "%6.2f%%", ratio);
604 fprintf(stderr, " backend cycles idle "); 615 fprintf(output, " backend cycles idle ");
605} 616}
606 617
607static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) 618static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -622,9 +633,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
622 else if (ratio > 5.0) 633 else if (ratio > 5.0)
623 color = PERF_COLOR_YELLOW; 634 color = PERF_COLOR_YELLOW;
624 635
625 fprintf(stderr, " # "); 636 fprintf(output, " # ");
626 color_fprintf(stderr, color, "%6.2f%%", ratio); 637 color_fprintf(output, color, "%6.2f%%", ratio);
627 fprintf(stderr, " of all branches "); 638 fprintf(output, " of all branches ");
628} 639}
629 640
630static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 641static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -645,9 +656,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
645 else if (ratio > 5.0) 656 else if (ratio > 5.0)
646 color = PERF_COLOR_YELLOW; 657 color = PERF_COLOR_YELLOW;
647 658
648 fprintf(stderr, " # "); 659 fprintf(output, " # ");
649 color_fprintf(stderr, color, "%6.2f%%", ratio); 660 color_fprintf(output, color, "%6.2f%%", ratio);
650 fprintf(stderr, " of all L1-dcache hits "); 661 fprintf(output, " of all L1-dcache hits ");
651} 662}
652 663
653static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 664static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -668,9 +679,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
668 else if (ratio > 5.0) 679 else if (ratio > 5.0)
669 color = PERF_COLOR_YELLOW; 680 color = PERF_COLOR_YELLOW;
670 681
671 fprintf(stderr, " # "); 682 fprintf(output, " # ");
672 color_fprintf(stderr, color, "%6.2f%%", ratio); 683 color_fprintf(output, color, "%6.2f%%", ratio);
673 fprintf(stderr, " of all L1-icache hits "); 684 fprintf(output, " of all L1-icache hits ");
674} 685}
675 686
676static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 687static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -691,9 +702,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
691 else if (ratio > 5.0) 702 else if (ratio > 5.0)
692 color = PERF_COLOR_YELLOW; 703 color = PERF_COLOR_YELLOW;
693 704
694 fprintf(stderr, " # "); 705 fprintf(output, " # ");
695 color_fprintf(stderr, color, "%6.2f%%", ratio); 706 color_fprintf(output, color, "%6.2f%%", ratio);
696 fprintf(stderr, " of all dTLB cache hits "); 707 fprintf(output, " of all dTLB cache hits ");
697} 708}
698 709
699static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 710static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -714,9 +725,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
714 else if (ratio > 5.0) 725 else if (ratio > 5.0)
715 color = PERF_COLOR_YELLOW; 726 color = PERF_COLOR_YELLOW;
716 727
717 fprintf(stderr, " # "); 728 fprintf(output, " # ");
718 color_fprintf(stderr, color, "%6.2f%%", ratio); 729 color_fprintf(output, color, "%6.2f%%", ratio);
719 fprintf(stderr, " of all iTLB cache hits "); 730 fprintf(output, " of all iTLB cache hits ");
720} 731}
721 732
722static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 733static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -737,9 +748,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
737 else if (ratio > 5.0) 748 else if (ratio > 5.0)
738 color = PERF_COLOR_YELLOW; 749 color = PERF_COLOR_YELLOW;
739 750
740 fprintf(stderr, " # "); 751 fprintf(output, " # ");
741 color_fprintf(stderr, color, "%6.2f%%", ratio); 752 color_fprintf(output, color, "%6.2f%%", ratio);
742 fprintf(stderr, " of all LL-cache hits "); 753 fprintf(output, " of all LL-cache hits ");
743} 754}
744 755
745static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 756static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -762,10 +773,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
762 else 773 else
763 cpu = 0; 774 cpu = 0;
764 775
765 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 776 fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
766 777
767 if (evsel->cgrp) 778 if (evsel->cgrp)
768 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 779 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
769 780
770 if (csv_output) 781 if (csv_output)
771 return; 782 return;
@@ -776,14 +787,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
776 if (total) 787 if (total)
777 ratio = avg / total; 788 ratio = avg / total;
778 789
779 fprintf(stderr, " # %5.2f insns per cycle ", ratio); 790 fprintf(output, " # %5.2f insns per cycle ", ratio);
780 791
781 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 792 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
782 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 793 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
783 794
784 if (total && avg) { 795 if (total && avg) {
785 ratio = total / avg; 796 ratio = total / avg;
786 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); 797 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio);
787 } 798 }
788 799
789 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 800 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -831,7 +842,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
831 if (total) 842 if (total)
832 ratio = avg * 100 / total; 843 ratio = avg * 100 / total;
833 844
834 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); 845 fprintf(output, " # %8.3f %% of all cache refs ", ratio);
835 846
836 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 847 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
837 print_stalled_cycles_frontend(cpu, evsel, avg); 848 print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -843,16 +854,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
843 if (total) 854 if (total)
844 ratio = 1.0 * avg / total; 855 ratio = 1.0 * avg / total;
845 856
846 fprintf(stderr, " # %8.3f GHz ", ratio); 857 fprintf(output, " # %8.3f GHz ", ratio);
847 } else if (runtime_nsecs_stats[cpu].n != 0) { 858 } else if (runtime_nsecs_stats[cpu].n != 0) {
848 total = avg_stats(&runtime_nsecs_stats[cpu]); 859 total = avg_stats(&runtime_nsecs_stats[cpu]);
849 860
850 if (total) 861 if (total)
851 ratio = 1000.0 * avg / total; 862 ratio = 1000.0 * avg / total;
852 863
853 fprintf(stderr, " # %8.3f M/sec ", ratio); 864 fprintf(output, " # %8.3f M/sec ", ratio);
854 } else { 865 } else {
855 fprintf(stderr, " "); 866 fprintf(output, " ");
856 } 867 }
857} 868}
858 869
@@ -867,7 +878,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
867 int scaled = counter->counts->scaled; 878 int scaled = counter->counts->scaled;
868 879
869 if (scaled == -1) { 880 if (scaled == -1) {
870 fprintf(stderr, "%*s%s%*s", 881 fprintf(output, "%*s%s%*s",
871 csv_output ? 0 : 18, 882 csv_output ? 0 : 18,
872 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 883 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
873 csv_sep, 884 csv_sep,
@@ -875,9 +886,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
875 event_name(counter)); 886 event_name(counter));
876 887
877 if (counter->cgrp) 888 if (counter->cgrp)
878 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 889 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
879 890
880 fputc('\n', stderr); 891 fputc('\n', output);
881 return; 892 return;
882 } 893 }
883 894
@@ -889,7 +900,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
889 print_noise(counter, avg); 900 print_noise(counter, avg);
890 901
891 if (csv_output) { 902 if (csv_output) {
892 fputc('\n', stderr); 903 fputc('\n', output);
893 return; 904 return;
894 } 905 }
895 906
@@ -899,9 +910,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
899 avg_enabled = avg_stats(&ps->res_stats[1]); 910 avg_enabled = avg_stats(&ps->res_stats[1]);
900 avg_running = avg_stats(&ps->res_stats[2]); 911 avg_running = avg_stats(&ps->res_stats[2]);
901 912
902 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); 913 fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled);
903 } 914 }
904 fprintf(stderr, "\n"); 915 fprintf(output, "\n");
905} 916}
906 917
907/* 918/*
@@ -918,7 +929,7 @@ static void print_counter(struct perf_evsel *counter)
918 ena = counter->counts->cpu[cpu].ena; 929 ena = counter->counts->cpu[cpu].ena;
919 run = counter->counts->cpu[cpu].run; 930 run = counter->counts->cpu[cpu].run;
920 if (run == 0 || ena == 0) { 931 if (run == 0 || ena == 0) {
921 fprintf(stderr, "CPU%*d%s%*s%s%*s", 932 fprintf(output, "CPU%*d%s%*s%s%*s",
922 csv_output ? 0 : -4, 933 csv_output ? 0 : -4,
923 evsel_list->cpus->map[cpu], csv_sep, 934 evsel_list->cpus->map[cpu], csv_sep,
924 csv_output ? 0 : 18, 935 csv_output ? 0 : 18,
@@ -928,9 +939,10 @@ static void print_counter(struct perf_evsel *counter)
928 event_name(counter)); 939 event_name(counter));
929 940
930 if (counter->cgrp) 941 if (counter->cgrp)
931 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 942 fprintf(output, "%s%s",
943 csv_sep, counter->cgrp->name);
932 944
933 fputc('\n', stderr); 945 fputc('\n', output);
934 continue; 946 continue;
935 } 947 }
936 948
@@ -943,9 +955,10 @@ static void print_counter(struct perf_evsel *counter)
943 print_noise(counter, 1.0); 955 print_noise(counter, 1.0);
944 956
945 if (run != ena) 957 if (run != ena)
946 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); 958 fprintf(output, " (%.2f%%)",
959 100.0 * run / ena);
947 } 960 }
948 fputc('\n', stderr); 961 fputc('\n', output);
949 } 962 }
950} 963}
951 964
@@ -957,21 +970,21 @@ static void print_stat(int argc, const char **argv)
957 fflush(stdout); 970 fflush(stdout);
958 971
959 if (!csv_output) { 972 if (!csv_output) {
960 fprintf(stderr, "\n"); 973 fprintf(output, "\n");
961 fprintf(stderr, " Performance counter stats for "); 974 fprintf(output, " Performance counter stats for ");
962 if(target_pid == -1 && target_tid == -1) { 975 if(target_pid == -1 && target_tid == -1) {
963 fprintf(stderr, "\'%s", argv[0]); 976 fprintf(output, "\'%s", argv[0]);
964 for (i = 1; i < argc; i++) 977 for (i = 1; i < argc; i++)
965 fprintf(stderr, " %s", argv[i]); 978 fprintf(output, " %s", argv[i]);
966 } else if (target_pid != -1) 979 } else if (target_pid != -1)
967 fprintf(stderr, "process id \'%d", target_pid); 980 fprintf(output, "process id \'%d", target_pid);
968 else 981 else
969 fprintf(stderr, "thread id \'%d", target_tid); 982 fprintf(output, "thread id \'%d", target_tid);
970 983
971 fprintf(stderr, "\'"); 984 fprintf(output, "\'");
972 if (run_count > 1) 985 if (run_count > 1)
973 fprintf(stderr, " (%d runs)", run_count); 986 fprintf(output, " (%d runs)", run_count);
974 fprintf(stderr, ":\n\n"); 987 fprintf(output, ":\n\n");
975 } 988 }
976 989
977 if (no_aggr) { 990 if (no_aggr) {
@@ -984,15 +997,15 @@ static void print_stat(int argc, const char **argv)
984 997
985 if (!csv_output) { 998 if (!csv_output) {
986 if (!null_run) 999 if (!null_run)
987 fprintf(stderr, "\n"); 1000 fprintf(output, "\n");
988 fprintf(stderr, " %17.9f seconds time elapsed", 1001 fprintf(output, " %17.9f seconds time elapsed",
989 avg_stats(&walltime_nsecs_stats)/1e9); 1002 avg_stats(&walltime_nsecs_stats)/1e9);
990 if (run_count > 1) { 1003 if (run_count > 1) {
991 fprintf(stderr, " "); 1004 fprintf(output, " ");
992 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 1005 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
993 avg_stats(&walltime_nsecs_stats)); 1006 avg_stats(&walltime_nsecs_stats));
994 } 1007 }
995 fprintf(stderr, "\n\n"); 1008 fprintf(output, "\n\n");
996 } 1009 }
997} 1010}
998 1011
@@ -1030,6 +1043,8 @@ static int stat__set_big_num(const struct option *opt __used,
1030 return 0; 1043 return 0;
1031} 1044}
1032 1045
1046static bool append_file;
1047
1033static const struct option options[] = { 1048static const struct option options[] = {
1034 OPT_CALLBACK('e', "event", &evsel_list, "event", 1049 OPT_CALLBACK('e', "event", &evsel_list, "event",
1035 "event selector. use 'perf list' to list available events", 1050 "event selector. use 'perf list' to list available events",
@@ -1070,6 +1085,11 @@ static const struct option options[] = {
1070 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1085 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1071 "monitor event in cgroup name only", 1086 "monitor event in cgroup name only",
1072 parse_cgroups), 1087 parse_cgroups),
1088 OPT_STRING('o', "output", &output_name, "file",
1089 "output file name"),
1090 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1091 OPT_INTEGER(0, "log-fd", &output_fd,
1092 "log output to fd, instead of stderr"),
1073 OPT_END() 1093 OPT_END()
1074}; 1094};
1075 1095
@@ -1141,6 +1161,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1141{ 1161{
1142 struct perf_evsel *pos; 1162 struct perf_evsel *pos;
1143 int status = -ENOMEM; 1163 int status = -ENOMEM;
1164 const char *mode;
1144 1165
1145 setlocale(LC_ALL, ""); 1166 setlocale(LC_ALL, "");
1146 1167
@@ -1151,16 +1172,46 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1151 argc = parse_options(argc, argv, options, stat_usage, 1172 argc = parse_options(argc, argv, options, stat_usage,
1152 PARSE_OPT_STOP_AT_NON_OPTION); 1173 PARSE_OPT_STOP_AT_NON_OPTION);
1153 1174
1154 if (csv_sep) 1175 output = stderr;
1176 if (output_name && strcmp(output_name, "-"))
1177 output = NULL;
1178
1179 if (output_name && output_fd) {
1180 fprintf(stderr, "cannot use both --output and --log-fd\n");
1181 usage_with_options(stat_usage, options);
1182 }
1183 if (!output) {
1184 struct timespec tm;
1185 mode = append_file ? "a" : "w";
1186
1187 output = fopen(output_name, mode);
1188 if (!output) {
1189 perror("failed to create output file");
1190 exit(-1);
1191 }
1192 clock_gettime(CLOCK_REALTIME, &tm);
1193 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1194 } else if (output_fd != 2) {
1195 mode = append_file ? "a" : "w";
1196 output = fdopen(output_fd, mode);
1197 if (!output) {
1198 perror("Failed opening logfd");
1199 return -errno;
1200 }
1201 }
1202
1203 if (csv_sep) {
1155 csv_output = true; 1204 csv_output = true;
1156 else 1205 if (!strcmp(csv_sep, "\\t"))
1206 csv_sep = "\t";
1207 } else
1157 csv_sep = DEFAULT_SEPARATOR; 1208 csv_sep = DEFAULT_SEPARATOR;
1158 1209
1159 /* 1210 /*
1160 * let the spreadsheet do the pretty-printing 1211 * let the spreadsheet do the pretty-printing
1161 */ 1212 */
1162 if (csv_output) { 1213 if (csv_output) {
1163 /* User explicitely passed -B? */ 1214 /* User explicitly passed -B? */
1164 if (big_num_opt == 1) { 1215 if (big_num_opt == 1) {
1165 fprintf(stderr, "-B option not supported with -x\n"); 1216 fprintf(stderr, "-B option not supported with -x\n");
1166 usage_with_options(stat_usage, options); 1217 usage_with_options(stat_usage, options);
@@ -1226,7 +1277,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1226 status = 0; 1277 status = 0;
1227 for (run_idx = 0; run_idx < run_count; run_idx++) { 1278 for (run_idx = 0; run_idx < run_count; run_idx++) {
1228 if (run_count != 1 && verbose) 1279 if (run_count != 1 && verbose)
1229 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1280 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1281 run_idx + 1);
1230 1282
1231 if (sync_run) 1283 if (sync_run)
1232 sync(); 1284 sync();
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index d28013b7d61c..7a871714d44e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -5,6 +5,7 @@
5 * any workload, CPU or specific PID. 5 * any workload, CPU or specific PID.
6 * 6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
8 * 9 *
9 * Improvements and fixes by: 10 * Improvements and fixes by:
10 * 11 *
@@ -36,6 +37,7 @@
36#include "util/parse-events.h" 37#include "util/parse-events.h"
37#include "util/cpumap.h" 38#include "util/cpumap.h"
38#include "util/xyarray.h" 39#include "util/xyarray.h"
40#include "util/sort.h"
39 41
40#include "util/debug.h" 42#include "util/debug.h"
41 43
@@ -65,12 +67,8 @@
65static struct perf_top top = { 67static struct perf_top top = {
66 .count_filter = 5, 68 .count_filter = 5,
67 .delay_secs = 2, 69 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1, 70 .target_pid = -1,
70 .target_tid = -1, 71 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */ 72 .freq = 1000, /* 1 KHz */
75}; 73};
76 74
@@ -78,6 +76,12 @@ static bool system_wide = false;
78 76
79static bool use_tui, use_stdio; 77static bool use_tui, use_stdio;
80 78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
81static int default_interval = 0; 85static int default_interval = 0;
82 86
83static bool kptr_restrict_warned; 87static bool kptr_restrict_warned;
@@ -85,7 +89,6 @@ static bool vmlinux_warned;
85static bool inherit = false; 89static bool inherit = false;
86static int realtime_prio = 0; 90static int realtime_prio = 0;
87static bool group = false; 91static bool group = false;
88static unsigned int page_size;
89static unsigned int mmap_pages = 128; 92static unsigned int mmap_pages = 128;
90 93
91static bool dump_symtab = false; 94static bool dump_symtab = false;
@@ -93,7 +96,6 @@ static bool dump_symtab = false;
93static struct winsize winsize; 96static struct winsize winsize;
94 97
95static const char *sym_filter = NULL; 98static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 99static int sym_pcnt_filter = 5;
98 100
99/* 101/*
@@ -136,18 +138,18 @@ static void sig_winch_handler(int sig __used)
136 update_print_entries(&winsize); 138 update_print_entries(&winsize);
137} 139}
138 140
139static int parse_source(struct sym_entry *syme) 141static int parse_source(struct hist_entry *he)
140{ 142{
141 struct symbol *sym; 143 struct symbol *sym;
142 struct annotation *notes; 144 struct annotation *notes;
143 struct map *map; 145 struct map *map;
144 int err = -1; 146 int err = -1;
145 147
146 if (!syme) 148 if (!he || !he->ms.sym)
147 return -1; 149 return -1;
148 150
149 sym = sym_entry__symbol(syme); 151 sym = he->ms.sym;
150 map = syme->map; 152 map = he->ms.map;
151 153
152 /* 154 /*
153 * We can't annotate with just /proc/kallsyms 155 * We can't annotate with just /proc/kallsyms
@@ -175,53 +177,62 @@ static int parse_source(struct sym_entry *syme)
175 return err; 177 return err;
176 } 178 }
177 179
178 err = symbol__annotate(sym, syme->map, 0); 180 err = symbol__annotate(sym, map, 0);
179 if (err == 0) { 181 if (err == 0) {
180out_assign: 182out_assign:
181 top.sym_filter_entry = syme; 183 top.sym_filter_entry = he;
182 } 184 }
183 185
184 pthread_mutex_unlock(&notes->lock); 186 pthread_mutex_unlock(&notes->lock);
185 return err; 187 return err;
186} 188}
187 189
188static void __zero_source_counters(struct sym_entry *syme) 190static void __zero_source_counters(struct hist_entry *he)
189{ 191{
190 struct symbol *sym = sym_entry__symbol(syme); 192 struct symbol *sym = he->ms.sym;
191 symbol__annotate_zero_histograms(sym); 193 symbol__annotate_zero_histograms(sym);
192} 194}
193 195
194static void record_precise_ip(struct sym_entry *syme, struct map *map, 196static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
195 int counter, u64 ip)
196{ 197{
197 struct annotation *notes; 198 struct annotation *notes;
198 struct symbol *sym; 199 struct symbol *sym;
199 200
200 if (syme != top.sym_filter_entry) 201 if (he == NULL || he->ms.sym == NULL ||
202 (he != top.sym_filter_entry && use_browser != 1))
201 return; 203 return;
202 204
203 sym = sym_entry__symbol(syme); 205 sym = he->ms.sym;
204 notes = symbol__annotation(sym); 206 notes = symbol__annotation(sym);
205 207
206 if (pthread_mutex_trylock(&notes->lock)) 208 if (pthread_mutex_trylock(&notes->lock))
207 return; 209 return;
208 210
209 ip = map->map_ip(map, ip); 211 if (notes->src == NULL &&
210 symbol__inc_addr_samples(sym, map, counter, ip); 212 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
213 pthread_mutex_unlock(&notes->lock);
214 pr_err("Not enough memory for annotating '%s' symbol!\n",
215 sym->name);
216 sleep(1);
217 return;
218 }
219
220 ip = he->ms.map->map_ip(he->ms.map, ip);
221 symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
211 222
212 pthread_mutex_unlock(&notes->lock); 223 pthread_mutex_unlock(&notes->lock);
213} 224}
214 225
215static void show_details(struct sym_entry *syme) 226static void show_details(struct hist_entry *he)
216{ 227{
217 struct annotation *notes; 228 struct annotation *notes;
218 struct symbol *symbol; 229 struct symbol *symbol;
219 int more; 230 int more;
220 231
221 if (!syme) 232 if (!he)
222 return; 233 return;
223 234
224 symbol = sym_entry__symbol(syme); 235 symbol = he->ms.sym;
225 notes = symbol__annotation(symbol); 236 notes = symbol__annotation(symbol);
226 237
227 pthread_mutex_lock(&notes->lock); 238 pthread_mutex_lock(&notes->lock);
@@ -232,7 +243,7 @@ static void show_details(struct sym_entry *syme)
232 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 243 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
233 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 244 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
234 245
235 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, 246 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
236 0, sym_pcnt_filter, top.print_entries, 4); 247 0, sym_pcnt_filter, top.print_entries, 4);
237 if (top.zero) 248 if (top.zero)
238 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 249 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
@@ -246,21 +257,28 @@ out_unlock:
246 257
247static const char CONSOLE_CLEAR[] = ""; 258static const char CONSOLE_CLEAR[] = "";
248 259
249static void __list_insert_active_sym(struct sym_entry *syme) 260static struct hist_entry *
261 perf_session__add_hist_entry(struct perf_session *session,
262 struct addr_location *al,
263 struct perf_sample *sample,
264 struct perf_evsel *evsel)
250{ 265{
251 list_add(&syme->node, &top.active_symbols); 266 struct hist_entry *he;
267
268 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
269 if (he == NULL)
270 return NULL;
271
272 session->hists.stats.total_period += sample->period;
273 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
274 return he;
252} 275}
253 276
254static void print_sym_table(struct perf_session *session) 277static void print_sym_table(void)
255{ 278{
256 char bf[160]; 279 char bf[160];
257 int printed = 0; 280 int printed = 0;
258 struct rb_node *nd;
259 struct sym_entry *syme;
260 struct rb_root tmp = RB_ROOT;
261 const int win_width = winsize.ws_col - 1; 281 const int win_width = winsize.ws_col - 1;
262 int sym_width, dso_width, dso_short_width;
263 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
264 282
265 puts(CONSOLE_CLEAR); 283 puts(CONSOLE_CLEAR);
266 284
@@ -271,10 +289,12 @@ static void print_sym_table(struct perf_session *session)
271 289
272 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 290 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
273 291
274 if (session->hists.stats.total_lost != 0) { 292 if (top.total_lost_warned != top.session->hists.stats.total_lost) {
293 top.total_lost_warned = top.session->hists.stats.total_lost;
275 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 294 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
276 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 295 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
277 session->hists.stats.total_lost); 296 top.total_lost_warned);
297 ++printed;
278 } 298 }
279 299
280 if (top.sym_filter_entry) { 300 if (top.sym_filter_entry) {
@@ -282,58 +302,15 @@ static void print_sym_table(struct perf_session *session)
282 return; 302 return;
283 } 303 }
284 304
285 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 305 hists__collapse_resort_threaded(&top.sym_evsel->hists);
286 &sym_width); 306 hists__output_resort_threaded(&top.sym_evsel->hists);
287 307 hists__decay_entries_threaded(&top.sym_evsel->hists,
288 if (sym_width + dso_width > winsize.ws_col - 29) { 308 top.hide_user_symbols,
289 dso_width = dso_short_width; 309 top.hide_kernel_symbols);
290 if (sym_width + dso_width > winsize.ws_col - 29) 310 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3);
291 sym_width = winsize.ws_col - dso_width - 29;
292 }
293 putchar('\n'); 311 putchar('\n');
294 if (top.evlist->nr_entries == 1) 312 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
295 printf(" samples pcnt"); 313 winsize.ws_row - 4 - printed, win_width, stdout);
296 else
297 printf(" weight samples pcnt");
298
299 if (verbose)
300 printf(" RIP ");
301 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
302 printf(" %s _______ _____",
303 top.evlist->nr_entries == 1 ? " " : "______");
304 if (verbose)
305 printf(" ________________");
306 printf(" %-*.*s", sym_width, sym_width, graph_line);
307 printf(" %-*.*s", dso_width, dso_width, graph_line);
308 puts("\n");
309
310 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
311 struct symbol *sym;
312 double pcnt;
313
314 syme = rb_entry(nd, struct sym_entry, rb_node);
315 sym = sym_entry__symbol(syme);
316 if (++printed > top.print_entries ||
317 (int)syme->snap_count < top.count_filter)
318 continue;
319
320 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
321 sum_ksamples));
322
323 if (top.evlist->nr_entries == 1 || !top.display_weighted)
324 printf("%20.2f ", syme->weight);
325 else
326 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
327
328 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
329 if (verbose)
330 printf(" %016" PRIx64, sym->start);
331 printf(" %-*.*s", sym_width, sym_width, sym->name);
332 printf(" %-*.*s\n", dso_width, dso_width,
333 dso_width >= syme->map->dso->long_name_len ?
334 syme->map->dso->long_name :
335 syme->map->dso->short_name);
336 }
337} 314}
338 315
339static void prompt_integer(int *target, const char *msg) 316static void prompt_integer(int *target, const char *msg)
@@ -371,10 +348,11 @@ static void prompt_percent(int *target, const char *msg)
371 *target = tmp; 348 *target = tmp;
372} 349}
373 350
374static void prompt_symbol(struct sym_entry **target, const char *msg) 351static void prompt_symbol(struct hist_entry **target, const char *msg)
375{ 352{
376 char *buf = malloc(0), *p; 353 char *buf = malloc(0), *p;
377 struct sym_entry *syme = *target, *n, *found = NULL; 354 struct hist_entry *syme = *target, *n, *found = NULL;
355 struct rb_node *next;
378 size_t dummy = 0; 356 size_t dummy = 0;
379 357
380 /* zero counters of active symbol */ 358 /* zero counters of active symbol */
@@ -391,17 +369,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
391 if (p) 369 if (p)
392 *p = 0; 370 *p = 0;
393 371
394 pthread_mutex_lock(&top.active_symbols_lock); 372 next = rb_first(&top.sym_evsel->hists.entries);
395 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 373 while (next) {
396 pthread_mutex_unlock(&top.active_symbols_lock); 374 n = rb_entry(next, struct hist_entry, rb_node);
397 375 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
398 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 376 found = n;
399 struct symbol *sym = sym_entry__symbol(syme);
400
401 if (!strcmp(buf, sym->name)) {
402 found = syme;
403 break; 377 break;
404 } 378 }
379 next = rb_next(&n->rb_node);
405 } 380 }
406 381
407 if (!found) { 382 if (!found) {
@@ -420,7 +395,7 @@ static void print_mapped_keys(void)
420 char *name = NULL; 395 char *name = NULL;
421 396
422 if (top.sym_filter_entry) { 397 if (top.sym_filter_entry) {
423 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 398 struct symbol *sym = top.sym_filter_entry->ms.sym;
424 name = sym->name; 399 name = sym->name;
425 } 400 }
426 401
@@ -437,9 +412,6 @@ static void print_mapped_keys(void)
437 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 412 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
438 fprintf(stdout, "\t[S] stop annotation.\n"); 413 fprintf(stdout, "\t[S] stop annotation.\n");
439 414
440 if (top.evlist->nr_entries > 1)
441 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
442
443 fprintf(stdout, 415 fprintf(stdout,
444 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 416 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
445 top.hide_kernel_symbols ? "yes" : "no"); 417 top.hide_kernel_symbols ? "yes" : "no");
@@ -466,7 +438,6 @@ static int key_mapped(int c)
466 case 'S': 438 case 'S':
467 return 1; 439 return 1;
468 case 'E': 440 case 'E':
469 case 'w':
470 return top.evlist->nr_entries > 1 ? 1 : 0; 441 return top.evlist->nr_entries > 1 ? 1 : 0;
471 default: 442 default:
472 break; 443 break;
@@ -475,7 +446,7 @@ static int key_mapped(int c)
475 return 0; 446 return 0;
476} 447}
477 448
478static void handle_keypress(struct perf_session *session, int c) 449static void handle_keypress(int c)
479{ 450{
480 if (!key_mapped(c)) { 451 if (!key_mapped(c)) {
481 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 452 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -551,7 +522,7 @@ static void handle_keypress(struct perf_session *session, int c)
551 case 'Q': 522 case 'Q':
552 printf("exiting.\n"); 523 printf("exiting.\n");
553 if (dump_symtab) 524 if (dump_symtab)
554 perf_session__fprintf_dsos(session, stderr); 525 perf_session__fprintf_dsos(top.session, stderr);
555 exit(0); 526 exit(0);
556 case 's': 527 case 's':
557 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 528 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
@@ -560,7 +531,7 @@ static void handle_keypress(struct perf_session *session, int c)
560 if (!top.sym_filter_entry) 531 if (!top.sym_filter_entry)
561 break; 532 break;
562 else { 533 else {
563 struct sym_entry *syme = top.sym_filter_entry; 534 struct hist_entry *syme = top.sym_filter_entry;
564 535
565 top.sym_filter_entry = NULL; 536 top.sym_filter_entry = NULL;
566 __zero_source_counters(syme); 537 __zero_source_counters(syme);
@@ -569,9 +540,6 @@ static void handle_keypress(struct perf_session *session, int c)
569 case 'U': 540 case 'U':
570 top.hide_user_symbols = !top.hide_user_symbols; 541 top.hide_user_symbols = !top.hide_user_symbols;
571 break; 542 break;
572 case 'w':
573 top.display_weighted = ~top.display_weighted;
574 break;
575 case 'z': 543 case 'z':
576 top.zero = !top.zero; 544 top.zero = !top.zero;
577 break; 545 break;
@@ -580,19 +548,31 @@ static void handle_keypress(struct perf_session *session, int c)
580 } 548 }
581} 549}
582 550
551static void perf_top__sort_new_samples(void *arg)
552{
553 struct perf_top *t = arg;
554 perf_top__reset_sample_counters(t);
555
556 if (t->evlist->selected != NULL)
557 t->sym_evsel = t->evlist->selected;
558
559 hists__collapse_resort_threaded(&t->sym_evsel->hists);
560 hists__output_resort_threaded(&t->sym_evsel->hists);
561 hists__decay_entries_threaded(&t->sym_evsel->hists,
562 top.hide_user_symbols,
563 top.hide_kernel_symbols);
564 hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3);
565}
566
583static void *display_thread_tui(void *arg __used) 567static void *display_thread_tui(void *arg __used)
584{ 568{
585 int err = 0; 569 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
586 pthread_mutex_lock(&top.active_symbols_lock); 570
587 while (list_empty(&top.active_symbols)) { 571 perf_top__sort_new_samples(&top);
588 err = pthread_cond_wait(&top.active_symbols_cond, 572 perf_evlist__tui_browse_hists(top.evlist, help,
589 &top.active_symbols_lock); 573 perf_top__sort_new_samples,
590 if (err) 574 &top, top.delay_secs);
591 break; 575
592 }
593 pthread_mutex_unlock(&top.active_symbols_lock);
594 if (!err)
595 perf_top__tui_browser(&top);
596 exit_browser(0); 576 exit_browser(0);
597 exit(0); 577 exit(0);
598 return NULL; 578 return NULL;
@@ -603,7 +583,6 @@ static void *display_thread(void *arg __used)
603 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 583 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
604 struct termios tc, save; 584 struct termios tc, save;
605 int delay_msecs, c; 585 int delay_msecs, c;
606 struct perf_session *session = (struct perf_session *) arg;
607 586
608 tcgetattr(0, &save); 587 tcgetattr(0, &save);
609 tc = save; 588 tc = save;
@@ -611,20 +590,35 @@ static void *display_thread(void *arg __used)
611 tc.c_cc[VMIN] = 0; 590 tc.c_cc[VMIN] = 0;
612 tc.c_cc[VTIME] = 0; 591 tc.c_cc[VTIME] = 0;
613 592
593 pthread__unblock_sigwinch();
614repeat: 594repeat:
615 delay_msecs = top.delay_secs * 1000; 595 delay_msecs = top.delay_secs * 1000;
616 tcsetattr(0, TCSANOW, &tc); 596 tcsetattr(0, TCSANOW, &tc);
617 /* trash return*/ 597 /* trash return*/
618 getc(stdin); 598 getc(stdin);
619 599
620 do { 600 while (1) {
621 print_sym_table(session); 601 print_sym_table();
622 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 602 /*
623 603 * Either timeout expired or we got an EINTR due to SIGWINCH,
604 * refresh screen in both cases.
605 */
606 switch (poll(&stdin_poll, 1, delay_msecs)) {
607 case 0:
608 continue;
609 case -1:
610 if (errno == EINTR)
611 continue;
612 /* Fall trhu */
613 default:
614 goto process_hotkey;
615 }
616 }
617process_hotkey:
624 c = getc(stdin); 618 c = getc(stdin);
625 tcsetattr(0, TCSAFLUSH, &save); 619 tcsetattr(0, TCSAFLUSH, &save);
626 620
627 handle_keypress(session, c); 621 handle_keypress(c);
628 goto repeat; 622 goto repeat;
629 623
630 return NULL; 624 return NULL;
@@ -645,9 +639,8 @@ static const char *skip_symbols[] = {
645 NULL 639 NULL
646}; 640};
647 641
648static int symbol_filter(struct map *map, struct symbol *sym) 642static int symbol_filter(struct map *map __used, struct symbol *sym)
649{ 643{
650 struct sym_entry *syme;
651 const char *name = sym->name; 644 const char *name = sym->name;
652 int i; 645 int i;
653 646
@@ -667,16 +660,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
667 strstr(name, "_text_end")) 660 strstr(name, "_text_end"))
668 return 1; 661 return 1;
669 662
670 syme = symbol__priv(sym);
671 syme->map = map;
672 symbol__annotate_init(map, sym);
673
674 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
675 /* schedule initial sym_filter_entry setup */
676 sym_filter_entry_sched = syme;
677 sym_filter = NULL;
678 }
679
680 for (i = 0; skip_symbols[i]; i++) { 663 for (i = 0; skip_symbols[i]; i++) {
681 if (!strcmp(skip_symbols[i], name)) { 664 if (!strcmp(skip_symbols[i], name)) {
682 sym->ignore = true; 665 sym->ignore = true;
@@ -691,10 +674,11 @@ static void perf_event__process_sample(const union perf_event *event,
691 struct perf_sample *sample, 674 struct perf_sample *sample,
692 struct perf_session *session) 675 struct perf_session *session)
693{ 676{
677 struct symbol *parent = NULL;
694 u64 ip = event->ip.ip; 678 u64 ip = event->ip.ip;
695 struct sym_entry *syme;
696 struct addr_location al; 679 struct addr_location al;
697 struct machine *machine; 680 struct machine *machine;
681 int err;
698 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 682 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
699 683
700 ++top.samples; 684 ++top.samples;
@@ -783,46 +767,41 @@ static void perf_event__process_sample(const union perf_event *event,
783 sleep(5); 767 sleep(5);
784 vmlinux_warned = true; 768 vmlinux_warned = true;
785 } 769 }
786
787 return;
788 }
789
790 /* let's see, whether we need to install initial sym_filter_entry */
791 if (sym_filter_entry_sched) {
792 top.sym_filter_entry = sym_filter_entry_sched;
793 sym_filter_entry_sched = NULL;
794 if (parse_source(top.sym_filter_entry) < 0) {
795 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
796
797 pr_err("Can't annotate %s", sym->name);
798 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
799 pr_err(": No vmlinux file was found in the path:\n");
800 machine__fprintf_vmlinux_path(machine, stderr);
801 } else
802 pr_err(".\n");
803 exit(1);
804 }
805 } 770 }
806 771
807 syme = symbol__priv(al.sym); 772 if (al.sym == NULL || !al.sym->ignore) {
808 if (!al.sym->ignore) {
809 struct perf_evsel *evsel; 773 struct perf_evsel *evsel;
774 struct hist_entry *he;
810 775
811 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 776 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
812 assert(evsel != NULL); 777 assert(evsel != NULL);
813 syme->count[evsel->idx]++; 778
814 record_precise_ip(syme, al.map, evsel->idx, ip); 779 if ((sort__has_parent || symbol_conf.use_callchain) &&
815 pthread_mutex_lock(&top.active_symbols_lock); 780 sample->callchain) {
816 if (list_empty(&syme->node) || !syme->node.next) { 781 err = perf_session__resolve_callchain(session, al.thread,
817 static bool first = true; 782 sample->callchain, &parent);
818 __list_insert_active_sym(syme); 783 if (err)
819 if (first) { 784 return;
820 pthread_cond_broadcast(&top.active_symbols_cond);
821 first = false;
822 }
823 } 785 }
824 pthread_mutex_unlock(&top.active_symbols_lock); 786
787 he = perf_session__add_hist_entry(session, &al, sample, evsel);
788 if (he == NULL) {
789 pr_err("Problem incrementing symbol period, skipping event\n");
790 return;
791 }
792
793 if (symbol_conf.use_callchain) {
794 err = callchain_append(he->callchain, &session->callchain_cursor,
795 sample->period);
796 if (err)
797 return;
798 }
799
800 if (sort_has_symbols)
801 record_precise_ip(he, evsel->idx, ip);
825 } 802 }
803
804 return;
826} 805}
827 806
828static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 807static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
@@ -873,7 +852,11 @@ static void start_counters(struct perf_evlist *evlist)
873 attr->read_format |= PERF_FORMAT_ID; 852 attr->read_format |= PERF_FORMAT_ID;
874 } 853 }
875 854
855 if (symbol_conf.use_callchain)
856 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
857
876 attr->mmap = 1; 858 attr->mmap = 1;
859 attr->comm = 1;
877 attr->inherit = inherit; 860 attr->inherit = inherit;
878try_again: 861try_again:
879 if (perf_evsel__open(counter, top.evlist->cpus, 862 if (perf_evsel__open(counter, top.evlist->cpus,
@@ -928,35 +911,56 @@ out_err:
928 exit(0); 911 exit(0);
929} 912}
930 913
914static int setup_sample_type(void)
915{
916 if (!sort_has_symbols) {
917 if (symbol_conf.use_callchain) {
918 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
919 return -EINVAL;
920 }
921 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
922 if (callchain_register_param(&callchain_param) < 0) {
923 ui__warning("Can't register callchain params.\n");
924 return -EINVAL;
925 }
926 }
927
928 return 0;
929}
930
931static int __cmd_top(void) 931static int __cmd_top(void)
932{ 932{
933 pthread_t thread; 933 pthread_t thread;
934 int ret __used; 934 int ret;
935 /* 935 /*
936 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 936 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
937 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 937 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
938 */ 938 */
939 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 939 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
940 if (session == NULL) 940 if (top.session == NULL)
941 return -ENOMEM; 941 return -ENOMEM;
942 942
943 ret = setup_sample_type();
944 if (ret)
945 goto out_delete;
946
943 if (top.target_tid != -1) 947 if (top.target_tid != -1)
944 perf_event__synthesize_thread_map(top.evlist->threads, 948 perf_event__synthesize_thread_map(top.evlist->threads,
945 perf_event__process, session); 949 perf_event__process, top.session);
946 else 950 else
947 perf_event__synthesize_threads(perf_event__process, session); 951 perf_event__synthesize_threads(perf_event__process, top.session);
948 952
949 start_counters(top.evlist); 953 start_counters(top.evlist);
950 session->evlist = top.evlist; 954 top.session->evlist = top.evlist;
951 perf_session__update_sample_type(session); 955 perf_session__update_sample_type(top.session);
952 956
953 /* Wait for a minimal set of events before starting the snapshot */ 957 /* Wait for a minimal set of events before starting the snapshot */
954 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 958 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
955 959
956 perf_session__mmap_read(session); 960 perf_session__mmap_read(top.session);
957 961
958 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 962 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
959 display_thread), session)) { 963 display_thread), NULL)) {
960 printf("Could not create display thread.\n"); 964 printf("Could not create display thread.\n");
961 exit(-1); 965 exit(-1);
962 } 966 }
@@ -974,12 +978,96 @@ static int __cmd_top(void)
974 while (1) { 978 while (1) {
975 u64 hits = top.samples; 979 u64 hits = top.samples;
976 980
977 perf_session__mmap_read(session); 981 perf_session__mmap_read(top.session);
978 982
979 if (hits == top.samples) 983 if (hits == top.samples)
980 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 984 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
981 } 985 }
982 986
987out_delete:
988 perf_session__delete(top.session);
989 top.session = NULL;
990
991 return 0;
992}
993
994static int
995parse_callchain_opt(const struct option *opt __used, const char *arg,
996 int unset)
997{
998 char *tok, *tok2;
999 char *endptr;
1000
1001 /*
1002 * --no-call-graph
1003 */
1004 if (unset) {
1005 dont_use_callchains = true;
1006 return 0;
1007 }
1008
1009 symbol_conf.use_callchain = true;
1010
1011 if (!arg)
1012 return 0;
1013
1014 tok = strtok((char *)arg, ",");
1015 if (!tok)
1016 return -1;
1017
1018 /* get the output mode */
1019 if (!strncmp(tok, "graph", strlen(arg)))
1020 callchain_param.mode = CHAIN_GRAPH_ABS;
1021
1022 else if (!strncmp(tok, "flat", strlen(arg)))
1023 callchain_param.mode = CHAIN_FLAT;
1024
1025 else if (!strncmp(tok, "fractal", strlen(arg)))
1026 callchain_param.mode = CHAIN_GRAPH_REL;
1027
1028 else if (!strncmp(tok, "none", strlen(arg))) {
1029 callchain_param.mode = CHAIN_NONE;
1030 symbol_conf.use_callchain = false;
1031
1032 return 0;
1033 }
1034
1035 else
1036 return -1;
1037
1038 /* get the min percentage */
1039 tok = strtok(NULL, ",");
1040 if (!tok)
1041 goto setup;
1042
1043 callchain_param.min_percent = strtod(tok, &endptr);
1044 if (tok == endptr)
1045 return -1;
1046
1047 /* get the print limit */
1048 tok2 = strtok(NULL, ",");
1049 if (!tok2)
1050 goto setup;
1051
1052 if (tok2[0] != 'c') {
1053 callchain_param.print_limit = strtod(tok2, &endptr);
1054 tok2 = strtok(NULL, ",");
1055 if (!tok2)
1056 goto setup;
1057 }
1058
1059 /* get the call chain order */
1060 if (!strcmp(tok2, "caller"))
1061 callchain_param.order = ORDER_CALLER;
1062 else if (!strcmp(tok2, "callee"))
1063 callchain_param.order = ORDER_CALLEE;
1064 else
1065 return -1;
1066setup:
1067 if (callchain_register_param(&callchain_param) < 0) {
1068 fprintf(stderr, "Can't register callchain params\n");
1069 return -1;
1070 }
983 return 0; 1071 return 0;
984} 1072}
985 1073
@@ -1019,7 +1107,7 @@ static const struct option options[] = {
1019 "put the counters into a counter group"), 1107 "put the counters into a counter group"),
1020 OPT_BOOLEAN('i', "inherit", &inherit, 1108 OPT_BOOLEAN('i', "inherit", &inherit,
1021 "child tasks inherit counters"), 1109 "child tasks inherit counters"),
1022 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1110 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1023 "symbol to annotate"), 1111 "symbol to annotate"),
1024 OPT_BOOLEAN('z', "zero", &top.zero, 1112 OPT_BOOLEAN('z', "zero", &top.zero,
1025 "zero history across updates"), 1113 "zero history across updates"),
@@ -1033,6 +1121,28 @@ static const struct option options[] = {
1033 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1121 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1034 OPT_INCR('v', "verbose", &verbose, 1122 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 1123 "be more verbose (show counter open errors, etc)"),
1124 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1125 "sort by key(s): pid, comm, dso, symbol, parent"),
1126 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1127 "Show a column with the number of samples"),
1128 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1129 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1130 "Default: fractal,0.5,callee", &parse_callchain_opt,
1131 callchain_default_opt),
1132 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1133 "Show a column with the sum of periods"),
1134 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1135 "only consider symbols in these dsos"),
1136 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1137 "only consider symbols in these comms"),
1138 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1139 "only consider these symbols"),
1140 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1141 "Interleave source code with assembly code (default)"),
1142 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1143 "Display raw encoding of assembly instructions (default)"),
1144 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1145 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1036 OPT_END() 1146 OPT_END()
1037}; 1147};
1038 1148
@@ -1045,18 +1155,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1045 if (top.evlist == NULL) 1155 if (top.evlist == NULL)
1046 return -ENOMEM; 1156 return -ENOMEM;
1047 1157
1048 page_size = sysconf(_SC_PAGE_SIZE); 1158 symbol_conf.exclude_other = false;
1049 1159
1050 argc = parse_options(argc, argv, options, top_usage, 0); 1160 argc = parse_options(argc, argv, options, top_usage, 0);
1051 if (argc) 1161 if (argc)
1052 usage_with_options(top_usage, options); 1162 usage_with_options(top_usage, options);
1053 1163
1054 /* 1164 if (sort_order == default_sort_order)
1055 * XXX For now start disabled, only using TUI if explicitely asked for. 1165 sort_order = "dso,symbol";
1056 * Change that when handle_keys equivalent gets written, live annotation 1166
1057 * done, etc. 1167 setup_sorting(top_usage, options);
1058 */
1059 use_browser = 0;
1060 1168
1061 if (use_stdio) 1169 if (use_stdio)
1062 use_browser = 0; 1170 use_browser = 0;
@@ -1119,13 +1227,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1119 1227
1120 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1228 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1121 1229
1122 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1230 symbol_conf.priv_size = sizeof(struct annotation);
1123 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1124 1231
1125 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1232 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1126 if (symbol__init() < 0) 1233 if (symbol__init() < 0)
1127 return -1; 1234 return -1;
1128 1235
1236 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1237 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1238 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1239
1240 /*
1241 * Avoid annotation data structures overhead when symbols aren't on the
1242 * sort list.
1243 */
1244 sort_has_symbols = sort_sym.list.next != NULL;
1245
1129 get_term_dimensions(&winsize); 1246 get_term_dimensions(&winsize);
1130 if (top.print_entries == 0) { 1247 if (top.print_entries == 0) {
1131 update_print_entries(&winsize); 1248 update_print_entries(&winsize);
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 4702e2443a8e..b382bd551aac 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -4,7 +4,6 @@
4#include "util/util.h" 4#include "util/util.h"
5#include "util/strbuf.h" 5#include "util/strbuf.h"
6 6
7extern const char perf_version_string[];
8extern const char perf_usage_string[]; 7extern const char perf_usage_string[];
9extern const char perf_more_info_string[]; 8extern const char perf_more_info_string[];
10 9
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index ec635b7cc8ea..73d0cac8b67e 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void)
427 debugfs_mntpt[0] = '\0'; 427 debugfs_mntpt[0] = '\0';
428} 428}
429 429
430static void pthread__block_sigwinch(void)
431{
432 sigset_t set;
433
434 sigemptyset(&set);
435 sigaddset(&set, SIGWINCH);
436 pthread_sigmask(SIG_BLOCK, &set, NULL);
437}
438
439void pthread__unblock_sigwinch(void)
440{
441 sigset_t set;
442
443 sigemptyset(&set);
444 sigaddset(&set, SIGWINCH);
445 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
446}
447
430int main(int argc, const char **argv) 448int main(int argc, const char **argv)
431{ 449{
432 const char *cmd; 450 const char *cmd;
@@ -480,6 +498,12 @@ int main(int argc, const char **argv)
480 * time. 498 * time.
481 */ 499 */
482 setup_path(); 500 setup_path();
501 /*
502 * Block SIGWINCH notifications so that the thread that wants it can
503 * unblock and get syscalls like select interrupted instead of waiting
504 * forever while the signal goes to some other non interested thread.
505 */
506 pthread__block_sigwinch();
483 507
484 while (1) { 508 while (1) {
485 static int done_help; 509 static int done_help;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index a5fc660c1f12..914c895510f7 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -9,18 +9,21 @@ void get_term_dimensions(struct winsize *ws);
9#include "../../arch/x86/include/asm/unistd.h" 9#include "../../arch/x86/include/asm/unistd.h"
10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
11#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 11#define cpu_relax() asm volatile("rep; nop" ::: "memory");
12#define CPUINFO_PROC "model name"
12#endif 13#endif
13 14
14#if defined(__x86_64__) 15#if defined(__x86_64__)
15#include "../../arch/x86/include/asm/unistd.h" 16#include "../../arch/x86/include/asm/unistd.h"
16#define rmb() asm volatile("lfence" ::: "memory") 17#define rmb() asm volatile("lfence" ::: "memory")
17#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 18#define cpu_relax() asm volatile("rep; nop" ::: "memory");
19#define CPUINFO_PROC "model name"
18#endif 20#endif
19 21
20#ifdef __powerpc__ 22#ifdef __powerpc__
21#include "../../arch/powerpc/include/asm/unistd.h" 23#include "../../arch/powerpc/include/asm/unistd.h"
22#define rmb() asm volatile ("sync" ::: "memory") 24#define rmb() asm volatile ("sync" ::: "memory")
23#define cpu_relax() asm volatile ("" ::: "memory"); 25#define cpu_relax() asm volatile ("" ::: "memory");
26#define CPUINFO_PROC "cpu"
24#endif 27#endif
25 28
26#ifdef __s390__ 29#ifdef __s390__
@@ -37,30 +40,35 @@ void get_term_dimensions(struct winsize *ws);
37# define rmb() asm volatile("" ::: "memory") 40# define rmb() asm volatile("" ::: "memory")
38#endif 41#endif
39#define cpu_relax() asm volatile("" ::: "memory") 42#define cpu_relax() asm volatile("" ::: "memory")
43#define CPUINFO_PROC "cpu type"
40#endif 44#endif
41 45
42#ifdef __hppa__ 46#ifdef __hppa__
43#include "../../arch/parisc/include/asm/unistd.h" 47#include "../../arch/parisc/include/asm/unistd.h"
44#define rmb() asm volatile("" ::: "memory") 48#define rmb() asm volatile("" ::: "memory")
45#define cpu_relax() asm volatile("" ::: "memory"); 49#define cpu_relax() asm volatile("" ::: "memory");
50#define CPUINFO_PROC "cpu"
46#endif 51#endif
47 52
48#ifdef __sparc__ 53#ifdef __sparc__
49#include "../../arch/sparc/include/asm/unistd.h" 54#include "../../arch/sparc/include/asm/unistd.h"
50#define rmb() asm volatile("":::"memory") 55#define rmb() asm volatile("":::"memory")
51#define cpu_relax() asm volatile("":::"memory") 56#define cpu_relax() asm volatile("":::"memory")
57#define CPUINFO_PROC "cpu"
52#endif 58#endif
53 59
54#ifdef __alpha__ 60#ifdef __alpha__
55#include "../../arch/alpha/include/asm/unistd.h" 61#include "../../arch/alpha/include/asm/unistd.h"
56#define rmb() asm volatile("mb" ::: "memory") 62#define rmb() asm volatile("mb" ::: "memory")
57#define cpu_relax() asm volatile("" ::: "memory") 63#define cpu_relax() asm volatile("" ::: "memory")
64#define CPUINFO_PROC "cpu model"
58#endif 65#endif
59 66
60#ifdef __ia64__ 67#ifdef __ia64__
61#include "../../arch/ia64/include/asm/unistd.h" 68#include "../../arch/ia64/include/asm/unistd.h"
62#define rmb() asm volatile ("mf" ::: "memory") 69#define rmb() asm volatile ("mf" ::: "memory")
63#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 70#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
71#define CPUINFO_PROC "model name"
64#endif 72#endif
65 73
66#ifdef __arm__ 74#ifdef __arm__
@@ -71,6 +79,7 @@ void get_term_dimensions(struct winsize *ws);
71 */ 79 */
72#define rmb() ((void(*)(void))0xffff0fa0)() 80#define rmb() ((void(*)(void))0xffff0fa0)()
73#define cpu_relax() asm volatile("":::"memory") 81#define cpu_relax() asm volatile("":::"memory")
82#define CPUINFO_PROC "Processor"
74#endif 83#endif
75 84
76#ifdef __mips__ 85#ifdef __mips__
@@ -83,6 +92,7 @@ void get_term_dimensions(struct winsize *ws);
83 : /* no input */ \ 92 : /* no input */ \
84 : "memory") 93 : "memory")
85#define cpu_relax() asm volatile("" ::: "memory") 94#define cpu_relax() asm volatile("" ::: "memory")
95#define CPUINFO_PROC "cpu model"
86#endif 96#endif
87 97
88#include <time.h> 98#include <time.h>
@@ -171,5 +181,8 @@ struct ip_callchain {
171}; 181};
172 182
173extern bool perf_host, perf_guest; 183extern bool perf_host, perf_guest;
184extern const char perf_version_string[];
185
186void pthread__unblock_sigwinch(void);
174 187
175#endif 188#endif
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-record b/tools/perf/scripts/python/bin/net_dropmonitor-record
new file mode 100755
index 000000000000..423fb81dadae
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e skb:kfree_skb $@
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-report b/tools/perf/scripts/python/bin/net_dropmonitor-report
new file mode 100755
index 000000000000..8d698f5a06aa
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: display a table of dropped frames
3
4perf script -s "$PERF_EXEC_PATH"/scripts/python/net_dropmonitor.py $@
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
new file mode 100755
index 000000000000..a4ffc9500023
--- /dev/null
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -0,0 +1,72 @@
1# Monitor the system for dropped packets and proudce a report of drop locations and counts
2
3import os
4import sys
5
6sys.path.append(os.environ['PERF_EXEC_PATH'] + \
7 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
8
9from perf_trace_context import *
10from Core import *
11from Util import *
12
13drop_log = {}
14kallsyms = []
15
16def get_kallsyms_table():
17 global kallsyms
18 try:
19 f = open("/proc/kallsyms", "r")
20 linecount = 0
21 for line in f:
22 linecount = linecount+1
23 f.seek(0)
24 except:
25 return
26
27
28 j = 0
29 for line in f:
30 loc = int(line.split()[0], 16)
31 name = line.split()[2]
32 j = j +1
33 if ((j % 100) == 0):
34 print "\r" + str(j) + "/" + str(linecount),
35 kallsyms.append({ 'loc': loc, 'name' : name})
36
37 print "\r" + str(j) + "/" + str(linecount)
38 kallsyms.sort()
39 return
40
41def get_sym(sloc):
42 loc = int(sloc)
43 for i in kallsyms:
44 if (i['loc'] >= loc):
45 return (i['name'], i['loc']-loc)
46 return (None, 0)
47
48def print_drop_table():
49 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
50 for i in drop_log.keys():
51 (sym, off) = get_sym(i)
52 if sym == None:
53 sym = i
54 print "%25s %25s %25s" % (sym, off, drop_log[i])
55
56
57def trace_begin():
58 print "Starting trace (Ctrl-C to dump results)"
59
60def trace_end():
61 print "Gathering kallsyms data"
62 get_kallsyms_table()
63 print_drop_table()
64
65# called from perf, when it finds a correspoinding event
66def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
67 skbaddr, protocol, location):
68 slocation = str(location)
69 try:
70 drop_log[slocation] = drop_log[slocation] + 1
71 except:
72 drop_log[slocation] = 1
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e01af2b1a469..bc8f4773d4d8 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -16,6 +16,8 @@
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char *disassembler_style;
20
19int symbol__annotate_init(struct map *map __used, struct symbol *sym) 21int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20{ 22{
21 struct annotation *notes = symbol__annotation(sym); 23 struct annotation *notes = symbol__annotation(sym);
@@ -323,10 +325,15 @@ fallback:
323 dso, dso->long_name, sym, sym->name); 325 dso, dso->long_name, sym, sym->name);
324 326
325 snprintf(command, sizeof(command), 327 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64 328 "objdump %s%s --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", 329 " --stop-address=0x%016" PRIx64
330 " -d %s %s -C %s|grep -v %s|expand",
331 disassembler_style ? "-M " : "",
332 disassembler_style ? disassembler_style : "",
328 map__rip_2objdump(map, sym->start), 333 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end), 334 map__rip_2objdump(map, sym->end),
335 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
336 symbol_conf.annotate_src ? "-S" : "",
330 symfs_filename, filename); 337 symfs_filename, filename);
331 338
332 pr_debug("Executing: %s\n", command); 339 pr_debug("Executing: %s\n", command);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c2c286896801..d9072523d342 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -91,13 +91,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
91#ifdef NO_NEWT_SUPPORT 91#ifdef NO_NEWT_SUPPORT
92static inline int symbol__tui_annotate(struct symbol *sym __used, 92static inline int symbol__tui_annotate(struct symbol *sym __used,
93 struct map *map __used, 93 struct map *map __used,
94 int evidx __used, int refresh __used) 94 int evidx __used,
95 void(*timer)(void *arg) __used,
96 void *arg __used, int delay_secs __used)
95{ 97{
96 return 0; 98 return 0;
97} 99}
98#else 100#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh); 102 int nr_events, void(*timer)(void *arg), void *arg,
103 int delay_secs);
101#endif 104#endif
102 105
106extern const char *disassembler_style;
107
103#endif /* __PERF_ANNOTATE_H */ 108#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e191eb9a667f..521c38a79190 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
200 * Auto-detect: 200 * Auto-detect:
201 */ 201 */
202 if (perf_use_color_default < 0) { 202 if (perf_use_color_default < 0) {
203 if (isatty(1) || pager_in_use()) 203 if (isatty(fileno(fp)) || pager_in_use())
204 perf_use_color_default = 1; 204 perf_use_color_default = 1;
205 else 205 else
206 perf_use_color_default = 0; 206 perf_use_color_default = 0;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 72e9f4886b6d..2f6bc89027da 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -533,3 +533,9 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
533 first = list_entry(evlist->entries.next, struct perf_evsel, node); 533 first = list_entry(evlist->entries.next, struct perf_evsel, node);
534 return first->attr.sample_id_all; 534 return first->attr.sample_id_all;
535} 535}
536
537void perf_evlist__set_selected(struct perf_evlist *evlist,
538 struct perf_evsel *evsel)
539{
540 evlist->selected = evsel;
541}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index f34915002745..6be71fc57794 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -25,6 +25,7 @@ struct perf_evlist {
25 struct pollfd *pollfd; 25 struct pollfd *pollfd;
26 struct thread_map *threads; 26 struct thread_map *threads;
27 struct cpu_map *cpus; 27 struct cpu_map *cpus;
28 struct perf_evsel *selected;
28}; 29};
29 30
30struct perf_evsel; 31struct perf_evsel;
@@ -56,6 +57,9 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
56void perf_evlist__disable(struct perf_evlist *evlist); 57void perf_evlist__disable(struct perf_evlist *evlist);
57void perf_evlist__enable(struct perf_evlist *evlist); 58void perf_evlist__enable(struct perf_evlist *evlist);
58 59
60void perf_evlist__set_selected(struct perf_evlist *evlist,
61 struct perf_evsel *evsel);
62
59static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 63static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
60 struct cpu_map *cpus, 64 struct cpu_map *cpus,
61 struct thread_map *threads) 65 struct thread_map *threads)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e389815078d3..b46f6e4bff3c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -39,6 +39,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
39 evsel->idx = idx; 39 evsel->idx = idx;
40 evsel->attr = *attr; 40 evsel->attr = *attr;
41 INIT_LIST_HEAD(&evsel->node); 41 INIT_LIST_HEAD(&evsel->node);
42 hists__init(&evsel->hists);
42} 43}
43 44
44struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 45struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b6c1ad123ca9..76c0b2c49eb8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -7,6 +7,7 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <sys/utsname.h>
10 11
11#include "evlist.h" 12#include "evlist.h"
12#include "evsel.h" 13#include "evsel.h"
@@ -17,12 +18,19 @@
17#include "session.h" 18#include "session.h"
18#include "symbol.h" 19#include "symbol.h"
19#include "debug.h" 20#include "debug.h"
21#include "cpumap.h"
20 22
21static bool no_buildid_cache = false; 23static bool no_buildid_cache = false;
22 24
23static int event_count; 25static int event_count;
24static struct perf_trace_event_type *events; 26static struct perf_trace_event_type *events;
25 27
28static u32 header_argc;
29static const char **header_argv;
30
31static int dsos__write_buildid_table(struct perf_header *header, int fd);
32static int perf_session__cache_build_ids(struct perf_session *session);
33
26int perf_header__push_event(u64 id, const char *name) 34int perf_header__push_event(u64 id, const char *name)
27{ 35{
28 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
@@ -110,6 +118,1020 @@ static int write_padded(int fd, const void *bf, size_t count,
110 return err; 118 return err;
111} 119}
112 120
121static int do_write_string(int fd, const char *str)
122{
123 u32 len, olen;
124 int ret;
125
126 olen = strlen(str) + 1;
127 len = ALIGN(olen, NAME_ALIGN);
128
129 /* write len, incl. \0 */
130 ret = do_write(fd, &len, sizeof(len));
131 if (ret < 0)
132 return ret;
133
134 return write_padded(fd, str, olen, len);
135}
136
137static char *do_read_string(int fd, struct perf_header *ph)
138{
139 ssize_t sz, ret;
140 u32 len;
141 char *buf;
142
143 sz = read(fd, &len, sizeof(len));
144 if (sz < (ssize_t)sizeof(len))
145 return NULL;
146
147 if (ph->needs_swap)
148 len = bswap_32(len);
149
150 buf = malloc(len);
151 if (!buf)
152 return NULL;
153
154 ret = read(fd, buf, len);
155 if (ret == (ssize_t)len) {
156 /*
157 * strings are padded by zeroes
158 * thus the actual strlen of buf
159 * may be less than len
160 */
161 return buf;
162 }
163
164 free(buf);
165 return NULL;
166}
167
168int
169perf_header__set_cmdline(int argc, const char **argv)
170{
171 int i;
172
173 header_argc = (u32)argc;
174
175 /* do not include NULL termination */
176 header_argv = calloc(argc, sizeof(char *));
177 if (!header_argv)
178 return -ENOMEM;
179
180 /*
181 * must copy argv contents because it gets moved
182 * around during option parsing
183 */
184 for (i = 0; i < argc ; i++)
185 header_argv[i] = argv[i];
186
187 return 0;
188}
189
190static int write_trace_info(int fd, struct perf_header *h __used,
191 struct perf_evlist *evlist)
192{
193 return read_tracing_data(fd, &evlist->entries);
194}
195
196
197static int write_build_id(int fd, struct perf_header *h,
198 struct perf_evlist *evlist __used)
199{
200 struct perf_session *session;
201 int err;
202
203 session = container_of(h, struct perf_session, header);
204
205 err = dsos__write_buildid_table(h, fd);
206 if (err < 0) {
207 pr_debug("failed to write buildid table\n");
208 return err;
209 }
210 if (!no_buildid_cache)
211 perf_session__cache_build_ids(session);
212
213 return 0;
214}
215
216static int write_hostname(int fd, struct perf_header *h __used,
217 struct perf_evlist *evlist __used)
218{
219 struct utsname uts;
220 int ret;
221
222 ret = uname(&uts);
223 if (ret < 0)
224 return -1;
225
226 return do_write_string(fd, uts.nodename);
227}
228
229static int write_osrelease(int fd, struct perf_header *h __used,
230 struct perf_evlist *evlist __used)
231{
232 struct utsname uts;
233 int ret;
234
235 ret = uname(&uts);
236 if (ret < 0)
237 return -1;
238
239 return do_write_string(fd, uts.release);
240}
241
242static int write_arch(int fd, struct perf_header *h __used,
243 struct perf_evlist *evlist __used)
244{
245 struct utsname uts;
246 int ret;
247
248 ret = uname(&uts);
249 if (ret < 0)
250 return -1;
251
252 return do_write_string(fd, uts.machine);
253}
254
255static int write_version(int fd, struct perf_header *h __used,
256 struct perf_evlist *evlist __used)
257{
258 return do_write_string(fd, perf_version_string);
259}
260
261static int write_cpudesc(int fd, struct perf_header *h __used,
262 struct perf_evlist *evlist __used)
263{
264#ifndef CPUINFO_PROC
265#define CPUINFO_PROC NULL
266#endif
267 FILE *file;
268 char *buf = NULL;
269 char *s, *p;
270 const char *search = CPUINFO_PROC;
271 size_t len = 0;
272 int ret = -1;
273
274 if (!search)
275 return -1;
276
277 file = fopen("/proc/cpuinfo", "r");
278 if (!file)
279 return -1;
280
281 while (getline(&buf, &len, file) > 0) {
282 ret = strncmp(buf, search, strlen(search));
283 if (!ret)
284 break;
285 }
286
287 if (ret)
288 goto done;
289
290 s = buf;
291
292 p = strchr(buf, ':');
293 if (p && *(p+1) == ' ' && *(p+2))
294 s = p + 2;
295 p = strchr(s, '\n');
296 if (p)
297 *p = '\0';
298
299 /* squash extra space characters (branding string) */
300 p = s;
301 while (*p) {
302 if (isspace(*p)) {
303 char *r = p + 1;
304 char *q = r;
305 *p = ' ';
306 while (*q && isspace(*q))
307 q++;
308 if (q != (p+1))
309 while ((*r++ = *q++));
310 }
311 p++;
312 }
313 ret = do_write_string(fd, s);
314done:
315 free(buf);
316 fclose(file);
317 return ret;
318}
319
320static int write_nrcpus(int fd, struct perf_header *h __used,
321 struct perf_evlist *evlist __used)
322{
323 long nr;
324 u32 nrc, nra;
325 int ret;
326
327 nr = sysconf(_SC_NPROCESSORS_CONF);
328 if (nr < 0)
329 return -1;
330
331 nrc = (u32)(nr & UINT_MAX);
332
333 nr = sysconf(_SC_NPROCESSORS_ONLN);
334 if (nr < 0)
335 return -1;
336
337 nra = (u32)(nr & UINT_MAX);
338
339 ret = do_write(fd, &nrc, sizeof(nrc));
340 if (ret < 0)
341 return ret;
342
343 return do_write(fd, &nra, sizeof(nra));
344}
345
346static int write_event_desc(int fd, struct perf_header *h __used,
347 struct perf_evlist *evlist)
348{
349 struct perf_evsel *attr;
350 u32 nre = 0, nri, sz;
351 int ret;
352
353 list_for_each_entry(attr, &evlist->entries, node)
354 nre++;
355
356 /*
357 * write number of events
358 */
359 ret = do_write(fd, &nre, sizeof(nre));
360 if (ret < 0)
361 return ret;
362
363 /*
364 * size of perf_event_attr struct
365 */
366 sz = (u32)sizeof(attr->attr);
367 ret = do_write(fd, &sz, sizeof(sz));
368 if (ret < 0)
369 return ret;
370
371 list_for_each_entry(attr, &evlist->entries, node) {
372
373 ret = do_write(fd, &attr->attr, sz);
374 if (ret < 0)
375 return ret;
376 /*
377 * write number of unique id per event
378 * there is one id per instance of an event
379 *
380 * copy into an nri to be independent of the
381 * type of ids,
382 */
383 nri = attr->ids;
384 ret = do_write(fd, &nri, sizeof(nri));
385 if (ret < 0)
386 return ret;
387
388 /*
389 * write event string as passed on cmdline
390 */
391 ret = do_write_string(fd, attr->name);
392 if (ret < 0)
393 return ret;
394 /*
395 * write unique ids for this event
396 */
397 ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
398 if (ret < 0)
399 return ret;
400 }
401 return 0;
402}
403
404static int write_cmdline(int fd, struct perf_header *h __used,
405 struct perf_evlist *evlist __used)
406{
407 char buf[MAXPATHLEN];
408 char proc[32];
409 u32 i, n;
410 int ret;
411
412 /*
413 * actual atual path to perf binary
414 */
415 sprintf(proc, "/proc/%d/exe", getpid());
416 ret = readlink(proc, buf, sizeof(buf));
417 if (ret <= 0)
418 return -1;
419
420 /* readlink() does not add null termination */
421 buf[ret] = '\0';
422
423 /* account for binary path */
424 n = header_argc + 1;
425
426 ret = do_write(fd, &n, sizeof(n));
427 if (ret < 0)
428 return ret;
429
430 ret = do_write_string(fd, buf);
431 if (ret < 0)
432 return ret;
433
434 for (i = 0 ; i < header_argc; i++) {
435 ret = do_write_string(fd, header_argv[i]);
436 if (ret < 0)
437 return ret;
438 }
439 return 0;
440}
441
442#define CORE_SIB_FMT \
443 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list"
444#define THRD_SIB_FMT \
445 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
446
447struct cpu_topo {
448 u32 core_sib;
449 u32 thread_sib;
450 char **core_siblings;
451 char **thread_siblings;
452};
453
454static int build_cpu_topo(struct cpu_topo *tp, int cpu)
455{
456 FILE *fp;
457 char filename[MAXPATHLEN];
458 char *buf = NULL, *p;
459 size_t len = 0;
460 u32 i = 0;
461 int ret = -1;
462
463 sprintf(filename, CORE_SIB_FMT, cpu);
464 fp = fopen(filename, "r");
465 if (!fp)
466 return -1;
467
468 if (getline(&buf, &len, fp) <= 0)
469 goto done;
470
471 fclose(fp);
472
473 p = strchr(buf, '\n');
474 if (p)
475 *p = '\0';
476
477 for (i = 0; i < tp->core_sib; i++) {
478 if (!strcmp(buf, tp->core_siblings[i]))
479 break;
480 }
481 if (i == tp->core_sib) {
482 tp->core_siblings[i] = buf;
483 tp->core_sib++;
484 buf = NULL;
485 len = 0;
486 }
487
488 sprintf(filename, THRD_SIB_FMT, cpu);
489 fp = fopen(filename, "r");
490 if (!fp)
491 goto done;
492
493 if (getline(&buf, &len, fp) <= 0)
494 goto done;
495
496 p = strchr(buf, '\n');
497 if (p)
498 *p = '\0';
499
500 for (i = 0; i < tp->thread_sib; i++) {
501 if (!strcmp(buf, tp->thread_siblings[i]))
502 break;
503 }
504 if (i == tp->thread_sib) {
505 tp->thread_siblings[i] = buf;
506 tp->thread_sib++;
507 buf = NULL;
508 }
509 ret = 0;
510done:
511 if(fp)
512 fclose(fp);
513 free(buf);
514 return ret;
515}
516
517static void free_cpu_topo(struct cpu_topo *tp)
518{
519 u32 i;
520
521 if (!tp)
522 return;
523
524 for (i = 0 ; i < tp->core_sib; i++)
525 free(tp->core_siblings[i]);
526
527 for (i = 0 ; i < tp->thread_sib; i++)
528 free(tp->thread_siblings[i]);
529
530 free(tp);
531}
532
533static struct cpu_topo *build_cpu_topology(void)
534{
535 struct cpu_topo *tp;
536 void *addr;
537 u32 nr, i;
538 size_t sz;
539 long ncpus;
540 int ret = -1;
541
542 ncpus = sysconf(_SC_NPROCESSORS_CONF);
543 if (ncpus < 0)
544 return NULL;
545
546 nr = (u32)(ncpus & UINT_MAX);
547
548 sz = nr * sizeof(char *);
549
550 addr = calloc(1, sizeof(*tp) + 2 * sz);
551 if (!addr)
552 return NULL;
553
554 tp = addr;
555
556 addr += sizeof(*tp);
557 tp->core_siblings = addr;
558 addr += sz;
559 tp->thread_siblings = addr;
560
561 for (i = 0; i < nr; i++) {
562 ret = build_cpu_topo(tp, i);
563 if (ret < 0)
564 break;
565 }
566 if (ret) {
567 free_cpu_topo(tp);
568 tp = NULL;
569 }
570 return tp;
571}
572
573static int write_cpu_topology(int fd, struct perf_header *h __used,
574 struct perf_evlist *evlist __used)
575{
576 struct cpu_topo *tp;
577 u32 i;
578 int ret;
579
580 tp = build_cpu_topology();
581 if (!tp)
582 return -1;
583
584 ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib));
585 if (ret < 0)
586 goto done;
587
588 for (i = 0; i < tp->core_sib; i++) {
589 ret = do_write_string(fd, tp->core_siblings[i]);
590 if (ret < 0)
591 goto done;
592 }
593 ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib));
594 if (ret < 0)
595 goto done;
596
597 for (i = 0; i < tp->thread_sib; i++) {
598 ret = do_write_string(fd, tp->thread_siblings[i]);
599 if (ret < 0)
600 break;
601 }
602done:
603 free_cpu_topo(tp);
604 return ret;
605}
606
607
608
609static int write_total_mem(int fd, struct perf_header *h __used,
610 struct perf_evlist *evlist __used)
611{
612 char *buf = NULL;
613 FILE *fp;
614 size_t len = 0;
615 int ret = -1, n;
616 uint64_t mem;
617
618 fp = fopen("/proc/meminfo", "r");
619 if (!fp)
620 return -1;
621
622 while (getline(&buf, &len, fp) > 0) {
623 ret = strncmp(buf, "MemTotal:", 9);
624 if (!ret)
625 break;
626 }
627 if (!ret) {
628 n = sscanf(buf, "%*s %"PRIu64, &mem);
629 if (n == 1)
630 ret = do_write(fd, &mem, sizeof(mem));
631 }
632 free(buf);
633 fclose(fp);
634 return ret;
635}
636
637static int write_topo_node(int fd, int node)
638{
639 char str[MAXPATHLEN];
640 char field[32];
641 char *buf = NULL, *p;
642 size_t len = 0;
643 FILE *fp;
644 u64 mem_total, mem_free, mem;
645 int ret = -1;
646
647 sprintf(str, "/sys/devices/system/node/node%d/meminfo", node);
648 fp = fopen(str, "r");
649 if (!fp)
650 return -1;
651
652 while (getline(&buf, &len, fp) > 0) {
653 /* skip over invalid lines */
654 if (!strchr(buf, ':'))
655 continue;
656 if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2)
657 goto done;
658 if (!strcmp(field, "MemTotal:"))
659 mem_total = mem;
660 if (!strcmp(field, "MemFree:"))
661 mem_free = mem;
662 }
663
664 fclose(fp);
665
666 ret = do_write(fd, &mem_total, sizeof(u64));
667 if (ret)
668 goto done;
669
670 ret = do_write(fd, &mem_free, sizeof(u64));
671 if (ret)
672 goto done;
673
674 ret = -1;
675 sprintf(str, "/sys/devices/system/node/node%d/cpulist", node);
676
677 fp = fopen(str, "r");
678 if (!fp)
679 goto done;
680
681 if (getline(&buf, &len, fp) <= 0)
682 goto done;
683
684 p = strchr(buf, '\n');
685 if (p)
686 *p = '\0';
687
688 ret = do_write_string(fd, buf);
689done:
690 free(buf);
691 fclose(fp);
692 return ret;
693}
694
695static int write_numa_topology(int fd, struct perf_header *h __used,
696 struct perf_evlist *evlist __used)
697{
698 char *buf = NULL;
699 size_t len = 0;
700 FILE *fp;
701 struct cpu_map *node_map = NULL;
702 char *c;
703 u32 nr, i, j;
704 int ret = -1;
705
706 fp = fopen("/sys/devices/system/node/online", "r");
707 if (!fp)
708 return -1;
709
710 if (getline(&buf, &len, fp) <= 0)
711 goto done;
712
713 c = strchr(buf, '\n');
714 if (c)
715 *c = '\0';
716
717 node_map = cpu_map__new(buf);
718 if (!node_map)
719 goto done;
720
721 nr = (u32)node_map->nr;
722
723 ret = do_write(fd, &nr, sizeof(nr));
724 if (ret < 0)
725 goto done;
726
727 for (i = 0; i < nr; i++) {
728 j = (u32)node_map->map[i];
729 ret = do_write(fd, &j, sizeof(j));
730 if (ret < 0)
731 break;
732
733 ret = write_topo_node(fd, i);
734 if (ret < 0)
735 break;
736 }
737done:
738 free(buf);
739 fclose(fp);
740 free(node_map);
741 return ret;
742}
743
744/*
745 * default get_cpuid(): nothing gets recorded
746 * actual implementation must be in arch/$(ARCH)/util/header.c
747 */
748int __attribute__((weak)) get_cpuid(char *buffer __used, size_t sz __used)
749{
750 return -1;
751}
752
753static int write_cpuid(int fd, struct perf_header *h __used,
754 struct perf_evlist *evlist __used)
755{
756 char buffer[64];
757 int ret;
758
759 ret = get_cpuid(buffer, sizeof(buffer));
760 if (!ret)
761 goto write_it;
762
763 return -1;
764write_it:
765 return do_write_string(fd, buffer);
766}
767
768static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
769{
770 char *str = do_read_string(fd, ph);
771 fprintf(fp, "# hostname : %s\n", str);
772 free(str);
773}
774
775static void print_osrelease(struct perf_header *ph, int fd, FILE *fp)
776{
777 char *str = do_read_string(fd, ph);
778 fprintf(fp, "# os release : %s\n", str);
779 free(str);
780}
781
782static void print_arch(struct perf_header *ph, int fd, FILE *fp)
783{
784 char *str = do_read_string(fd, ph);
785 fprintf(fp, "# arch : %s\n", str);
786 free(str);
787}
788
789static void print_cpudesc(struct perf_header *ph, int fd, FILE *fp)
790{
791 char *str = do_read_string(fd, ph);
792 fprintf(fp, "# cpudesc : %s\n", str);
793 free(str);
794}
795
796static void print_nrcpus(struct perf_header *ph, int fd, FILE *fp)
797{
798 ssize_t ret;
799 u32 nr;
800
801 ret = read(fd, &nr, sizeof(nr));
802 if (ret != (ssize_t)sizeof(nr))
803 nr = -1; /* interpreted as error */
804
805 if (ph->needs_swap)
806 nr = bswap_32(nr);
807
808 fprintf(fp, "# nrcpus online : %u\n", nr);
809
810 ret = read(fd, &nr, sizeof(nr));
811 if (ret != (ssize_t)sizeof(nr))
812 nr = -1; /* interpreted as error */
813
814 if (ph->needs_swap)
815 nr = bswap_32(nr);
816
817 fprintf(fp, "# nrcpus avail : %u\n", nr);
818}
819
820static void print_version(struct perf_header *ph, int fd, FILE *fp)
821{
822 char *str = do_read_string(fd, ph);
823 fprintf(fp, "# perf version : %s\n", str);
824 free(str);
825}
826
827static void print_cmdline(struct perf_header *ph, int fd, FILE *fp)
828{
829 ssize_t ret;
830 char *str;
831 u32 nr, i;
832
833 ret = read(fd, &nr, sizeof(nr));
834 if (ret != (ssize_t)sizeof(nr))
835 return;
836
837 if (ph->needs_swap)
838 nr = bswap_32(nr);
839
840 fprintf(fp, "# cmdline : ");
841
842 for (i = 0; i < nr; i++) {
843 str = do_read_string(fd, ph);
844 fprintf(fp, "%s ", str);
845 free(str);
846 }
847 fputc('\n', fp);
848}
849
850static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
851{
852 ssize_t ret;
853 u32 nr, i;
854 char *str;
855
856 ret = read(fd, &nr, sizeof(nr));
857 if (ret != (ssize_t)sizeof(nr))
858 return;
859
860 if (ph->needs_swap)
861 nr = bswap_32(nr);
862
863 for (i = 0; i < nr; i++) {
864 str = do_read_string(fd, ph);
865 fprintf(fp, "# sibling cores : %s\n", str);
866 free(str);
867 }
868
869 ret = read(fd, &nr, sizeof(nr));
870 if (ret != (ssize_t)sizeof(nr))
871 return;
872
873 if (ph->needs_swap)
874 nr = bswap_32(nr);
875
876 for (i = 0; i < nr; i++) {
877 str = do_read_string(fd, ph);
878 fprintf(fp, "# sibling threads : %s\n", str);
879 free(str);
880 }
881}
882
883static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
884{
885 struct perf_event_attr attr;
886 uint64_t id;
887 void *buf = NULL;
888 char *str;
889 u32 nre, sz, nr, i, j, msz;
890 int ret;
891
892 /* number of events */
893 ret = read(fd, &nre, sizeof(nre));
894 if (ret != (ssize_t)sizeof(nre))
895 goto error;
896
897 if (ph->needs_swap)
898 nre = bswap_32(nre);
899
900 ret = read(fd, &sz, sizeof(sz));
901 if (ret != (ssize_t)sizeof(sz))
902 goto error;
903
904 if (ph->needs_swap)
905 sz = bswap_32(sz);
906
907 /*
908 * ensure it is at least to our ABI rev
909 */
910 if (sz < (u32)sizeof(attr))
911 goto error;
912
913 memset(&attr, 0, sizeof(attr));
914
915 /* read entire region to sync up to next field */
916 buf = malloc(sz);
917 if (!buf)
918 goto error;
919
920 msz = sizeof(attr);
921 if (sz < msz)
922 msz = sz;
923
924 for (i = 0 ; i < nre; i++) {
925
926 ret = read(fd, buf, sz);
927 if (ret != (ssize_t)sz)
928 goto error;
929
930 if (ph->needs_swap)
931 perf_event__attr_swap(buf);
932
933 memcpy(&attr, buf, msz);
934
935 ret = read(fd, &nr, sizeof(nr));
936 if (ret != (ssize_t)sizeof(nr))
937 goto error;
938
939 if (ph->needs_swap)
940 nr = bswap_32(nr);
941
942 str = do_read_string(fd, ph);
943 fprintf(fp, "# event : name = %s, ", str);
944 free(str);
945
946 fprintf(fp, "type = %d, config = 0x%"PRIx64
947 ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
948 attr.type,
949 (u64)attr.config,
950 (u64)attr.config1,
951 (u64)attr.config2);
952
953 fprintf(fp, ", excl_usr = %d, excl_kern = %d",
954 attr.exclude_user,
955 attr.exclude_kernel);
956
957 if (nr)
958 fprintf(fp, ", id = {");
959
960 for (j = 0 ; j < nr; j++) {
961 ret = read(fd, &id, sizeof(id));
962 if (ret != (ssize_t)sizeof(id))
963 goto error;
964
965 if (ph->needs_swap)
966 id = bswap_64(id);
967
968 if (j)
969 fputc(',', fp);
970
971 fprintf(fp, " %"PRIu64, id);
972 }
973 if (nr && j == nr)
974 fprintf(fp, " }");
975 fputc('\n', fp);
976 }
977 free(buf);
978 return;
979error:
980 fprintf(fp, "# event desc: not available or unable to read\n");
981}
982
983static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)
984{
985 uint64_t mem;
986 ssize_t ret;
987
988 ret = read(fd, &mem, sizeof(mem));
989 if (ret != sizeof(mem))
990 goto error;
991
992 if (h->needs_swap)
993 mem = bswap_64(mem);
994
995 fprintf(fp, "# total memory : %"PRIu64" kB\n", mem);
996 return;
997error:
998 fprintf(fp, "# total memory : unknown\n");
999}
1000
1001static void print_numa_topology(struct perf_header *h __used, int fd, FILE *fp)
1002{
1003 ssize_t ret;
1004 u32 nr, c, i;
1005 char *str;
1006 uint64_t mem_total, mem_free;
1007
1008 /* nr nodes */
1009 ret = read(fd, &nr, sizeof(nr));
1010 if (ret != (ssize_t)sizeof(nr))
1011 goto error;
1012
1013 if (h->needs_swap)
1014 nr = bswap_32(nr);
1015
1016 for (i = 0; i < nr; i++) {
1017
1018 /* node number */
1019 ret = read(fd, &c, sizeof(c));
1020 if (ret != (ssize_t)sizeof(c))
1021 goto error;
1022
1023 if (h->needs_swap)
1024 c = bswap_32(c);
1025
1026 ret = read(fd, &mem_total, sizeof(u64));
1027 if (ret != sizeof(u64))
1028 goto error;
1029
1030 ret = read(fd, &mem_free, sizeof(u64));
1031 if (ret != sizeof(u64))
1032 goto error;
1033
1034 if (h->needs_swap) {
1035 mem_total = bswap_64(mem_total);
1036 mem_free = bswap_64(mem_free);
1037 }
1038
1039 fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB,"
1040 " free = %"PRIu64" kB\n",
1041 c,
1042 mem_total,
1043 mem_free);
1044
1045 str = do_read_string(fd, h);
1046 fprintf(fp, "# node%u cpu list : %s\n", c, str);
1047 free(str);
1048 }
1049 return;
1050error:
1051 fprintf(fp, "# numa topology : not available\n");
1052}
1053
1054static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
1055{
1056 char *str = do_read_string(fd, ph);
1057 fprintf(fp, "# cpuid : %s\n", str);
1058 free(str);
1059}
1060
1061struct feature_ops {
1062 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1063 void (*print)(struct perf_header *h, int fd, FILE *fp);
1064 const char *name;
1065 bool full_only;
1066};
1067
1068#define FEAT_OPA(n, w, p) \
1069 [n] = { .name = #n, .write = w, .print = p }
1070#define FEAT_OPF(n, w, p) \
1071 [n] = { .name = #n, .write = w, .print = p, .full_only = true }
1072
1073static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1074 FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL),
1075 FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL),
1076 FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname),
1077 FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease),
1078 FEAT_OPA(HEADER_VERSION, write_version, print_version),
1079 FEAT_OPA(HEADER_ARCH, write_arch, print_arch),
1080 FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus),
1081 FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc),
1082 FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid),
1083 FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem),
1084 FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc),
1085 FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline),
1086 FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology),
1087 FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology),
1088};
1089
1090struct header_print_data {
1091 FILE *fp;
1092 bool full; /* extended list of headers */
1093};
1094
1095static int perf_file_section__fprintf_info(struct perf_file_section *section,
1096 struct perf_header *ph,
1097 int feat, int fd, void *data)
1098{
1099 struct header_print_data *hd = data;
1100
1101 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
1102 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
1103 "%d, continuing...\n", section->offset, feat);
1104 return 0;
1105 }
1106 if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) {
1107 pr_warning("unknown feature %d\n", feat);
1108 return -1;
1109 }
1110 if (!feat_ops[feat].print)
1111 return 0;
1112
1113 if (!feat_ops[feat].full_only || hd->full)
1114 feat_ops[feat].print(ph, fd, hd->fp);
1115 else
1116 fprintf(hd->fp, "# %s info available, use -I to display\n",
1117 feat_ops[feat].name);
1118
1119 return 0;
1120}
1121
1122int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
1123{
1124 struct header_print_data hd;
1125 struct perf_header *header = &session->header;
1126 int fd = session->fd;
1127 hd.fp = fp;
1128 hd.full = full;
1129
1130 perf_header__process_sections(header, fd, &hd,
1131 perf_file_section__fprintf_info);
1132 return 0;
1133}
1134
113#define dsos__for_each_with_build_id(pos, head) \ 1135#define dsos__for_each_with_build_id(pos, head) \
114 list_for_each_entry(pos, head, node) \ 1136 list_for_each_entry(pos, head, node) \
115 if (!pos->has_build_id) \ 1137 if (!pos->has_build_id) \
@@ -267,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
267 if (access(linkname, F_OK)) 1289 if (access(linkname, F_OK))
268 goto out_free; 1290 goto out_free;
269 1291
270 if (readlink(linkname, filename, size) < 0) 1292 if (readlink(linkname, filename, size - 1) < 0)
271 goto out_free; 1293 goto out_free;
272 1294
273 if (unlink(linkname)) 1295 if (unlink(linkname))
@@ -356,15 +1378,41 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
356 return ret; 1378 return ret;
357} 1379}
358 1380
1381static int do_write_feat(int fd, struct perf_header *h, int type,
1382 struct perf_file_section **p,
1383 struct perf_evlist *evlist)
1384{
1385 int err;
1386 int ret = 0;
1387
1388 if (perf_header__has_feat(h, type)) {
1389
1390 (*p)->offset = lseek(fd, 0, SEEK_CUR);
1391
1392 err = feat_ops[type].write(fd, h, evlist);
1393 if (err < 0) {
1394 pr_debug("failed to write feature %d\n", type);
1395
1396 /* undo anything written */
1397 lseek(fd, (*p)->offset, SEEK_SET);
1398
1399 return -1;
1400 }
1401 (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset;
1402 (*p)++;
1403 }
1404 return ret;
1405}
1406
359static int perf_header__adds_write(struct perf_header *header, 1407static int perf_header__adds_write(struct perf_header *header,
360 struct perf_evlist *evlist, int fd) 1408 struct perf_evlist *evlist, int fd)
361{ 1409{
362 int nr_sections; 1410 int nr_sections;
363 struct perf_session *session; 1411 struct perf_session *session;
364 struct perf_file_section *feat_sec; 1412 struct perf_file_section *feat_sec, *p;
365 int sec_size; 1413 int sec_size;
366 u64 sec_start; 1414 u64 sec_start;
367 int idx = 0, err; 1415 int err;
368 1416
369 session = container_of(header, struct perf_session, header); 1417 session = container_of(header, struct perf_session, header);
370 1418
@@ -376,7 +1424,7 @@ static int perf_header__adds_write(struct perf_header *header,
376 if (!nr_sections) 1424 if (!nr_sections)
377 return 0; 1425 return 0;
378 1426
379 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 1427 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections);
380 if (feat_sec == NULL) 1428 if (feat_sec == NULL)
381 return -ENOMEM; 1429 return -ENOMEM;
382 1430
@@ -385,36 +1433,69 @@ static int perf_header__adds_write(struct perf_header *header,
385 sec_start = header->data_offset + header->data_size; 1433 sec_start = header->data_offset + header->data_size;
386 lseek(fd, sec_start + sec_size, SEEK_SET); 1434 lseek(fd, sec_start + sec_size, SEEK_SET);
387 1435
388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { 1436 err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist);
389 struct perf_file_section *trace_sec; 1437 if (err)
390 1438 goto out_free;
391 trace_sec = &feat_sec[idx++];
392 1439
393 /* Write trace info */ 1440 err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist);
394 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 1441 if (err) {
395 read_tracing_data(fd, &evlist->entries); 1442 perf_header__clear_feat(header, HEADER_BUILD_ID);
396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 1443 goto out_free;
397 } 1444 }
398 1445
399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) { 1446 err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist);
400 struct perf_file_section *buildid_sec; 1447 if (err)
1448 perf_header__clear_feat(header, HEADER_HOSTNAME);
401 1449
402 buildid_sec = &feat_sec[idx++]; 1450 err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist);
1451 if (err)
1452 perf_header__clear_feat(header, HEADER_OSRELEASE);
403 1453
404 /* Write build-ids */ 1454 err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist);
405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 1455 if (err)
406 err = dsos__write_buildid_table(header, fd); 1456 perf_header__clear_feat(header, HEADER_VERSION);
407 if (err < 0) { 1457
408 pr_debug("failed to write buildid table\n"); 1458 err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist);
409 goto out_free; 1459 if (err)
410 } 1460 perf_header__clear_feat(header, HEADER_ARCH);
411 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - 1461
412 buildid_sec->offset; 1462 err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist);
413 if (!no_buildid_cache) 1463 if (err)
414 perf_session__cache_build_ids(session); 1464 perf_header__clear_feat(header, HEADER_NRCPUS);
415 } 1465
1466 err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist);
1467 if (err)
1468 perf_header__clear_feat(header, HEADER_CPUDESC);
1469
1470 err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist);
1471 if (err)
1472 perf_header__clear_feat(header, HEADER_CPUID);
1473
1474 err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist);
1475 if (err)
1476 perf_header__clear_feat(header, HEADER_TOTAL_MEM);
1477
1478 err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist);
1479 if (err)
1480 perf_header__clear_feat(header, HEADER_CMDLINE);
1481
1482 err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist);
1483 if (err)
1484 perf_header__clear_feat(header, HEADER_EVENT_DESC);
1485
1486 err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist);
1487 if (err)
1488 perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY);
1489
1490 err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist);
1491 if (err)
1492 perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY);
416 1493
417 lseek(fd, sec_start, SEEK_SET); 1494 lseek(fd, sec_start, SEEK_SET);
1495 /*
1496 * may write more than needed due to dropped feature, but
1497 * this is okay, reader will skip the mising entries
1498 */
418 err = do_write(fd, feat_sec, sec_size); 1499 err = do_write(fd, feat_sec, sec_size);
419 if (err < 0) 1500 if (err < 0)
420 pr_debug("failed to write feature section\n"); 1501 pr_debug("failed to write feature section\n");
@@ -554,9 +1635,10 @@ static int perf_header__getbuffer64(struct perf_header *header,
554} 1635}
555 1636
556int perf_header__process_sections(struct perf_header *header, int fd, 1637int perf_header__process_sections(struct perf_header *header, int fd,
1638 void *data,
557 int (*process)(struct perf_file_section *section, 1639 int (*process)(struct perf_file_section *section,
558 struct perf_header *ph, 1640 struct perf_header *ph,
559 int feat, int fd)) 1641 int feat, int fd, void *data))
560{ 1642{
561 struct perf_file_section *feat_sec; 1643 struct perf_file_section *feat_sec;
562 int nr_sections; 1644 int nr_sections;
@@ -584,7 +1666,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
584 if (perf_header__has_feat(header, feat)) { 1666 if (perf_header__has_feat(header, feat)) {
585 struct perf_file_section *sec = &feat_sec[idx++]; 1667 struct perf_file_section *sec = &feat_sec[idx++];
586 1668
587 err = process(sec, header, feat, fd); 1669 err = process(sec, header, feat, fd, data);
588 if (err < 0) 1670 if (err < 0)
589 break; 1671 break;
590 } 1672 }
@@ -621,21 +1703,41 @@ int perf_file_header__read(struct perf_file_header *header,
621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 1703 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
622 else 1704 else
623 return -1; 1705 return -1;
1706 } else if (ph->needs_swap) {
1707 unsigned int i;
1708 /*
1709 * feature bitmap is declared as an array of unsigned longs --
1710 * not good since its size can differ between the host that
1711 * generated the data file and the host analyzing the file.
1712 *
1713 * We need to handle endianness, but we don't know the size of
1714 * the unsigned long where the file was generated. Take a best
1715 * guess at determining it: try 64-bit swap first (ie., file
1716 * created on a 64-bit host), and check if the hostname feature
1717 * bit is set (this feature bit is forced on as of fbe96f2).
1718 * If the bit is not, undo the 64-bit swap and try a 32-bit
1719 * swap. If the hostname bit is still not set (e.g., older data
1720 * file), punt and fallback to the original behavior --
1721 * clearing all feature bits and setting buildid.
1722 */
1723 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i)
1724 header->adds_features[i] = bswap_64(header->adds_features[i]);
1725
1726 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1727 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) {
1728 header->adds_features[i] = bswap_64(header->adds_features[i]);
1729 header->adds_features[i] = bswap_32(header->adds_features[i]);
1730 }
1731 }
1732
1733 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1734 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
1735 set_bit(HEADER_BUILD_ID, header->adds_features);
1736 }
624 } 1737 }
625 1738
626 memcpy(&ph->adds_features, &header->adds_features, 1739 memcpy(&ph->adds_features, &header->adds_features,
627 sizeof(ph->adds_features)); 1740 sizeof(ph->adds_features));
628 /*
629 * FIXME: hack that assumes that if we need swap the perf.data file
630 * may be coming from an arch with a different word-size, ergo different
631 * DEFINE_BITMAP format, investigate more later, but for now its mostly
632 * safe to assume that we have a build-id section. Trace files probably
633 * have several other issues in this realm anyway...
634 */
635 if (ph->needs_swap) {
636 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
637 perf_header__set_feat(ph, HEADER_BUILD_ID);
638 }
639 1741
640 ph->event_offset = header->event_types.offset; 1742 ph->event_offset = header->event_types.offset;
641 ph->event_size = header->event_types.size; 1743 ph->event_size = header->event_types.size;
@@ -796,7 +1898,7 @@ out:
796 1898
797static int perf_file_section__process(struct perf_file_section *section, 1899static int perf_file_section__process(struct perf_file_section *section,
798 struct perf_header *ph, 1900 struct perf_header *ph,
799 int feat, int fd) 1901 int feat, int fd, void *data __used)
800{ 1902{
801 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 1903 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
802 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 1904 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -813,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section,
813 if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) 1915 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
814 pr_debug("Failed to read buildids, continuing...\n"); 1916 pr_debug("Failed to read buildids, continuing...\n");
815 break; 1917 break;
1918
1919 case HEADER_HOSTNAME:
1920 case HEADER_OSRELEASE:
1921 case HEADER_VERSION:
1922 case HEADER_ARCH:
1923 case HEADER_NRCPUS:
1924 case HEADER_CPUDESC:
1925 case HEADER_CPUID:
1926 case HEADER_TOTAL_MEM:
1927 case HEADER_CMDLINE:
1928 case HEADER_EVENT_DESC:
1929 case HEADER_CPU_TOPOLOGY:
1930 case HEADER_NUMA_TOPOLOGY:
1931 break;
1932
816 default: 1933 default:
817 pr_debug("unknown feature %d, continuing...\n", feat); 1934 pr_debug("unknown feature %d, continuing...\n", feat);
818 } 1935 }
@@ -935,7 +2052,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
935 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 2052 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
936 } 2053 }
937 2054
938 perf_header__process_sections(header, fd, perf_file_section__process); 2055 perf_header__process_sections(header, fd, NULL,
2056 perf_file_section__process);
939 2057
940 lseek(fd, header->data_offset, SEEK_SET); 2058 lseek(fd, header->data_offset, SEEK_SET);
941 2059
@@ -1100,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1100 struct perf_session *session __unused) 2218 struct perf_session *session __unused)
1101{ 2219{
1102 union perf_event ev; 2220 union perf_event ev;
2221 struct tracing_data *tdata;
1103 ssize_t size = 0, aligned_size = 0, padding; 2222 ssize_t size = 0, aligned_size = 0, padding;
1104 int err __used = 0; 2223 int err __used = 0;
1105 2224
2225 /*
2226 * We are going to store the size of the data followed
2227 * by the data contents. Since the fd descriptor is a pipe,
2228 * we cannot seek back to store the size of the data once
2229 * we know it. Instead we:
2230 *
2231 * - write the tracing data to the temp file
2232 * - get/write the data size to pipe
2233 * - write the tracing data from the temp file
2234 * to the pipe
2235 */
2236 tdata = tracing_data_get(&evlist->entries, fd, true);
2237 if (!tdata)
2238 return -1;
2239
1106 memset(&ev, 0, sizeof(ev)); 2240 memset(&ev, 0, sizeof(ev));
1107 2241
1108 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2242 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1109 size = read_tracing_data_size(fd, &evlist->entries); 2243 size = tdata->size;
1110 if (size <= 0)
1111 return size;
1112 aligned_size = ALIGN(size, sizeof(u64)); 2244 aligned_size = ALIGN(size, sizeof(u64));
1113 padding = aligned_size - size; 2245 padding = aligned_size - size;
1114 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2246 ev.tracing_data.header.size = sizeof(ev.tracing_data);
@@ -1116,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1116 2248
1117 process(&ev, NULL, session); 2249 process(&ev, NULL, session);
1118 2250
1119 err = read_tracing_data(fd, &evlist->entries); 2251 /*
2252 * The put function will copy all the tracing data
2253 * stored in temp file to the pipe.
2254 */
2255 tracing_data_put(tdata);
2256
1120 write_padded(fd, NULL, 0, padding); 2257 write_padded(fd, NULL, 0, padding);
1121 2258
1122 return aligned_size; 2259 return aligned_size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 1886256768a1..3d5a742f4a2a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,6 +12,20 @@
12enum { 12enum {
13 HEADER_TRACE_INFO = 1, 13 HEADER_TRACE_INFO = 1,
14 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
15
16 HEADER_HOSTNAME,
17 HEADER_OSRELEASE,
18 HEADER_VERSION,
19 HEADER_ARCH,
20 HEADER_NRCPUS,
21 HEADER_CPUDESC,
22 HEADER_CPUID,
23 HEADER_TOTAL_MEM,
24 HEADER_CMDLINE,
25 HEADER_EVENT_DESC,
26 HEADER_CPU_TOPOLOGY,
27 HEADER_NUMA_TOPOLOGY,
28
15 HEADER_LAST_FEATURE, 29 HEADER_LAST_FEATURE,
16}; 30};
17 31
@@ -68,10 +82,15 @@ void perf_header__set_feat(struct perf_header *header, int feat);
68void perf_header__clear_feat(struct perf_header *header, int feat); 82void perf_header__clear_feat(struct perf_header *header, int feat);
69bool perf_header__has_feat(const struct perf_header *header, int feat); 83bool perf_header__has_feat(const struct perf_header *header, int feat);
70 84
85int perf_header__set_cmdline(int argc, const char **argv);
86
71int perf_header__process_sections(struct perf_header *header, int fd, 87int perf_header__process_sections(struct perf_header *header, int fd,
88 void *data,
72 int (*process)(struct perf_file_section *section, 89 int (*process)(struct perf_file_section *section,
73 struct perf_header *ph, 90 struct perf_header *ph,
74 int feat, int fd)); 91 int feat, int fd, void *data));
92
93int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
75 94
76int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 95int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
77 const char *name, bool is_kallsyms); 96 const char *name, bool is_kallsyms);
@@ -104,4 +123,10 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
104 struct perf_session *session); 123 struct perf_session *session);
105int perf_event__process_build_id(union perf_event *event, 124int perf_event__process_build_id(union perf_event *event,
106 struct perf_session *session); 125 struct perf_session *session);
126
127/*
128 * arch specific callback
129 */
130int get_cpuid(char *buffer, size_t sz);
131
107#endif /* __PERF_HEADER_H */ 132#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 677e1da6bb3e..f6a993963a1e 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -6,6 +6,11 @@
6#include "sort.h" 6#include "sort.h"
7#include <math.h> 7#include <math.h>
8 8
9static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he);
13
9enum hist_filter { 14enum hist_filter {
10 HIST_FILTER__DSO, 15 HIST_FILTER__DSO,
11 HIST_FILTER__THREAD, 16 HIST_FILTER__THREAD,
@@ -18,56 +23,56 @@ struct callchain_param callchain_param = {
18 .order = ORDER_CALLEE 23 .order = ORDER_CALLEE
19}; 24};
20 25
21u16 hists__col_len(struct hists *self, enum hist_column col) 26u16 hists__col_len(struct hists *hists, enum hist_column col)
22{ 27{
23 return self->col_len[col]; 28 return hists->col_len[col];
24} 29}
25 30
26void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) 31void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
27{ 32{
28 self->col_len[col] = len; 33 hists->col_len[col] = len;
29} 34}
30 35
31bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) 36bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
32{ 37{
33 if (len > hists__col_len(self, col)) { 38 if (len > hists__col_len(hists, col)) {
34 hists__set_col_len(self, col, len); 39 hists__set_col_len(hists, col, len);
35 return true; 40 return true;
36 } 41 }
37 return false; 42 return false;
38} 43}
39 44
40static void hists__reset_col_len(struct hists *self) 45static void hists__reset_col_len(struct hists *hists)
41{ 46{
42 enum hist_column col; 47 enum hist_column col;
43 48
44 for (col = 0; col < HISTC_NR_COLS; ++col) 49 for (col = 0; col < HISTC_NR_COLS; ++col)
45 hists__set_col_len(self, col, 0); 50 hists__set_col_len(hists, col, 0);
46} 51}
47 52
48static void hists__calc_col_len(struct hists *self, struct hist_entry *h) 53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
49{ 54{
50 u16 len; 55 u16 len;
51 56
52 if (h->ms.sym) 57 if (h->ms.sym)
53 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
54 else { 59 else {
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56 61
57 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width && 62 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 63 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list) 64 !symbol_conf.dso_list)
60 hists__set_col_len(self, HISTC_DSO, 65 hists__set_col_len(hists, HISTC_DSO,
61 unresolved_col_width); 66 unresolved_col_width);
62 } 67 }
63 68
64 len = thread__comm_len(h->thread); 69 len = thread__comm_len(h->thread);
65 if (hists__new_col_len(self, HISTC_COMM, len)) 70 if (hists__new_col_len(hists, HISTC_COMM, len))
66 hists__set_col_len(self, HISTC_THREAD, len + 6); 71 hists__set_col_len(hists, HISTC_THREAD, len + 6);
67 72
68 if (h->ms.map) { 73 if (h->ms.map) {
69 len = dso__name_len(h->ms.map->dso); 74 len = dso__name_len(h->ms.map->dso);
70 hists__new_col_len(self, HISTC_DSO, len); 75 hists__new_col_len(hists, HISTC_DSO, len);
71 } 76 }
72} 77}
73 78
@@ -92,6 +97,67 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
92 } 97 }
93} 98}
94 99
100static void hist_entry__decay(struct hist_entry *he)
101{
102 he->period = (he->period * 7) / 8;
103 he->nr_events = (he->nr_events * 7) / 8;
104}
105
106static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
107{
108 u64 prev_period = he->period;
109
110 if (prev_period == 0)
111 return true;
112
113 hist_entry__decay(he);
114
115 if (!he->filtered)
116 hists->stats.total_period -= prev_period - he->period;
117
118 return he->period == 0;
119}
120
121static void __hists__decay_entries(struct hists *hists, bool zap_user,
122 bool zap_kernel, bool threaded)
123{
124 struct rb_node *next = rb_first(&hists->entries);
125 struct hist_entry *n;
126
127 while (next) {
128 n = rb_entry(next, struct hist_entry, rb_node);
129 next = rb_next(&n->rb_node);
130 /*
131 * We may be annotating this, for instance, so keep it here in
132 * case some it gets new samples, we'll eventually free it when
133 * the user stops browsing and it agains gets fully decayed.
134 */
135 if (((zap_user && n->level == '.') ||
136 (zap_kernel && n->level != '.') ||
137 hists__decay_entry(hists, n)) &&
138 !n->used) {
139 rb_erase(&n->rb_node, &hists->entries);
140
141 if (sort__need_collapse || threaded)
142 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
143
144 hist_entry__free(n);
145 --hists->nr_entries;
146 }
147 }
148}
149
150void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
151{
152 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
153}
154
155void hists__decay_entries_threaded(struct hists *hists,
156 bool zap_user, bool zap_kernel)
157{
158 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
159}
160
95/* 161/*
96 * histogram, sorted on item, collects periods 162 * histogram, sorted on item, collects periods
97 */ 163 */
@@ -113,11 +179,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
113 return self; 179 return self;
114} 180}
115 181
116static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) 182static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
117{ 183{
118 if (!h->filtered) { 184 if (!h->filtered) {
119 hists__calc_col_len(self, h); 185 hists__calc_col_len(hists, h);
120 ++self->nr_entries; 186 ++hists->nr_entries;
187 hists->stats.total_period += h->period;
121 } 188 }
122} 189}
123 190
@@ -128,11 +195,11 @@ static u8 symbol__parent_filter(const struct symbol *parent)
128 return 0; 195 return 0;
129} 196}
130 197
131struct hist_entry *__hists__add_entry(struct hists *self, 198struct hist_entry *__hists__add_entry(struct hists *hists,
132 struct addr_location *al, 199 struct addr_location *al,
133 struct symbol *sym_parent, u64 period) 200 struct symbol *sym_parent, u64 period)
134{ 201{
135 struct rb_node **p = &self->entries.rb_node; 202 struct rb_node **p;
136 struct rb_node *parent = NULL; 203 struct rb_node *parent = NULL;
137 struct hist_entry *he; 204 struct hist_entry *he;
138 struct hist_entry entry = { 205 struct hist_entry entry = {
@@ -150,9 +217,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
150 }; 217 };
151 int cmp; 218 int cmp;
152 219
220 pthread_mutex_lock(&hists->lock);
221
222 p = &hists->entries_in->rb_node;
223
153 while (*p != NULL) { 224 while (*p != NULL) {
154 parent = *p; 225 parent = *p;
155 he = rb_entry(parent, struct hist_entry, rb_node); 226 he = rb_entry(parent, struct hist_entry, rb_node_in);
156 227
157 cmp = hist_entry__cmp(&entry, he); 228 cmp = hist_entry__cmp(&entry, he);
158 229
@@ -170,12 +241,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
170 241
171 he = hist_entry__new(&entry); 242 he = hist_entry__new(&entry);
172 if (!he) 243 if (!he)
173 return NULL; 244 goto out_unlock;
174 rb_link_node(&he->rb_node, parent, p); 245
175 rb_insert_color(&he->rb_node, &self->entries); 246 rb_link_node(&he->rb_node_in, parent, p);
176 hists__inc_nr_entries(self, he); 247 rb_insert_color(&he->rb_node_in, hists->entries_in);
177out: 248out:
178 hist_entry__add_cpumode_period(he, al->cpumode, period); 249 hist_entry__add_cpumode_period(he, al->cpumode, period);
250out_unlock:
251 pthread_mutex_unlock(&hists->lock);
179 return he; 252 return he;
180} 253}
181 254
@@ -222,7 +295,7 @@ void hist_entry__free(struct hist_entry *he)
222 * collapse the histogram 295 * collapse the histogram
223 */ 296 */
224 297
225static bool hists__collapse_insert_entry(struct hists *self, 298static bool hists__collapse_insert_entry(struct hists *hists,
226 struct rb_root *root, 299 struct rb_root *root,
227 struct hist_entry *he) 300 struct hist_entry *he)
228{ 301{
@@ -233,15 +306,16 @@ static bool hists__collapse_insert_entry(struct hists *self,
233 306
234 while (*p != NULL) { 307 while (*p != NULL) {
235 parent = *p; 308 parent = *p;
236 iter = rb_entry(parent, struct hist_entry, rb_node); 309 iter = rb_entry(parent, struct hist_entry, rb_node_in);
237 310
238 cmp = hist_entry__collapse(iter, he); 311 cmp = hist_entry__collapse(iter, he);
239 312
240 if (!cmp) { 313 if (!cmp) {
241 iter->period += he->period; 314 iter->period += he->period;
315 iter->nr_events += he->nr_events;
242 if (symbol_conf.use_callchain) { 316 if (symbol_conf.use_callchain) {
243 callchain_cursor_reset(&self->callchain_cursor); 317 callchain_cursor_reset(&hists->callchain_cursor);
244 callchain_merge(&self->callchain_cursor, iter->callchain, 318 callchain_merge(&hists->callchain_cursor, iter->callchain,
245 he->callchain); 319 he->callchain);
246 } 320 }
247 hist_entry__free(he); 321 hist_entry__free(he);
@@ -254,35 +328,70 @@ static bool hists__collapse_insert_entry(struct hists *self,
254 p = &(*p)->rb_right; 328 p = &(*p)->rb_right;
255 } 329 }
256 330
257 rb_link_node(&he->rb_node, parent, p); 331 rb_link_node(&he->rb_node_in, parent, p);
258 rb_insert_color(&he->rb_node, root); 332 rb_insert_color(&he->rb_node_in, root);
259 return true; 333 return true;
260} 334}
261 335
262void hists__collapse_resort(struct hists *self) 336static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
337{
338 struct rb_root *root;
339
340 pthread_mutex_lock(&hists->lock);
341
342 root = hists->entries_in;
343 if (++hists->entries_in > &hists->entries_in_array[1])
344 hists->entries_in = &hists->entries_in_array[0];
345
346 pthread_mutex_unlock(&hists->lock);
347
348 return root;
349}
350
351static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
352{
353 hists__filter_entry_by_dso(hists, he);
354 hists__filter_entry_by_thread(hists, he);
355}
356
357static void __hists__collapse_resort(struct hists *hists, bool threaded)
263{ 358{
264 struct rb_root tmp; 359 struct rb_root *root;
265 struct rb_node *next; 360 struct rb_node *next;
266 struct hist_entry *n; 361 struct hist_entry *n;
267 362
268 if (!sort__need_collapse) 363 if (!sort__need_collapse && !threaded)
269 return; 364 return;
270 365
271 tmp = RB_ROOT; 366 root = hists__get_rotate_entries_in(hists);
272 next = rb_first(&self->entries); 367 next = rb_first(root);
273 self->nr_entries = 0; 368 hists->stats.total_period = 0;
274 hists__reset_col_len(self);
275 369
276 while (next) { 370 while (next) {
277 n = rb_entry(next, struct hist_entry, rb_node); 371 n = rb_entry(next, struct hist_entry, rb_node_in);
278 next = rb_next(&n->rb_node); 372 next = rb_next(&n->rb_node_in);
279 373
280 rb_erase(&n->rb_node, &self->entries); 374 rb_erase(&n->rb_node_in, root);
281 if (hists__collapse_insert_entry(self, &tmp, n)) 375 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
282 hists__inc_nr_entries(self, n); 376 /*
377 * If it wasn't combined with one of the entries already
378 * collapsed, we need to apply the filters that may have
379 * been set by, say, the hist_browser.
380 */
381 hists__apply_filters(hists, n);
382 hists__inc_nr_entries(hists, n);
383 }
283 } 384 }
385}
284 386
285 self->entries = tmp; 387void hists__collapse_resort(struct hists *hists)
388{
389 return __hists__collapse_resort(hists, false);
390}
391
392void hists__collapse_resort_threaded(struct hists *hists)
393{
394 return __hists__collapse_resort(hists, true);
286} 395}
287 396
288/* 397/*
@@ -315,31 +424,43 @@ static void __hists__insert_output_entry(struct rb_root *entries,
315 rb_insert_color(&he->rb_node, entries); 424 rb_insert_color(&he->rb_node, entries);
316} 425}
317 426
318void hists__output_resort(struct hists *self) 427static void __hists__output_resort(struct hists *hists, bool threaded)
319{ 428{
320 struct rb_root tmp; 429 struct rb_root *root;
321 struct rb_node *next; 430 struct rb_node *next;
322 struct hist_entry *n; 431 struct hist_entry *n;
323 u64 min_callchain_hits; 432 u64 min_callchain_hits;
324 433
325 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); 434 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
435
436 if (sort__need_collapse || threaded)
437 root = &hists->entries_collapsed;
438 else
439 root = hists->entries_in;
326 440
327 tmp = RB_ROOT; 441 next = rb_first(root);
328 next = rb_first(&self->entries); 442 hists->entries = RB_ROOT;
329 443
330 self->nr_entries = 0; 444 hists->nr_entries = 0;
331 hists__reset_col_len(self); 445 hists__reset_col_len(hists);
332 446
333 while (next) { 447 while (next) {
334 n = rb_entry(next, struct hist_entry, rb_node); 448 n = rb_entry(next, struct hist_entry, rb_node_in);
335 next = rb_next(&n->rb_node); 449 next = rb_next(&n->rb_node_in);
336 450
337 rb_erase(&n->rb_node, &self->entries); 451 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
338 __hists__insert_output_entry(&tmp, n, min_callchain_hits); 452 hists__inc_nr_entries(hists, n);
339 hists__inc_nr_entries(self, n);
340 } 453 }
454}
341 455
342 self->entries = tmp; 456void hists__output_resort(struct hists *hists)
457{
458 return __hists__output_resort(hists, false);
459}
460
461void hists__output_resort_threaded(struct hists *hists)
462{
463 return __hists__output_resort(hists, true);
343} 464}
344 465
345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 466static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -594,12 +715,27 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
594 return ret; 715 return ret;
595} 716}
596 717
597int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 718void hists__output_recalc_col_len(struct hists *hists, int max_rows)
598 struct hists *hists, struct hists *pair_hists, 719{
599 bool show_displacement, long displacement, 720 struct rb_node *next = rb_first(&hists->entries);
600 bool color, u64 session_total) 721 struct hist_entry *n;
722 int row = 0;
723
724 hists__reset_col_len(hists);
725
726 while (next && row++ < max_rows) {
727 n = rb_entry(next, struct hist_entry, rb_node);
728 if (!n->filtered)
729 hists__calc_col_len(hists, n);
730 next = rb_next(&n->rb_node);
731 }
732}
733
734static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
735 size_t size, struct hists *pair_hists,
736 bool show_displacement, long displacement,
737 bool color, u64 session_total)
601{ 738{
602 struct sort_entry *se;
603 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 739 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
604 u64 nr_events; 740 u64 nr_events;
605 const char *sep = symbol_conf.field_sep; 741 const char *sep = symbol_conf.field_sep;
@@ -664,6 +800,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
664 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 800 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 } 801 }
666 802
803 if (symbol_conf.show_total_period) {
804 if (sep)
805 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
806 else
807 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
808 }
809
667 if (pair_hists) { 810 if (pair_hists) {
668 char bf[32]; 811 char bf[32];
669 double old_percent = 0, new_percent = 0, diff; 812 double old_percent = 0, new_percent = 0, diff;
@@ -698,26 +841,42 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
698 } 841 }
699 } 842 }
700 843
844 return ret;
845}
846
847int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
848 struct hists *hists)
849{
850 const char *sep = symbol_conf.field_sep;
851 struct sort_entry *se;
852 int ret = 0;
853
701 list_for_each_entry(se, &hist_entry__sort_list, list) { 854 list_for_each_entry(se, &hist_entry__sort_list, list) {
702 if (se->elide) 855 if (se->elide)
703 continue; 856 continue;
704 857
705 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 858 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
706 ret += se->se_snprintf(self, s + ret, size - ret, 859 ret += se->se_snprintf(he, s + ret, size - ret,
707 hists__col_len(hists, se->se_width_idx)); 860 hists__col_len(hists, se->se_width_idx));
708 } 861 }
709 862
710 return ret; 863 return ret;
711} 864}
712 865
713int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 866int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
714 struct hists *pair_hists, bool show_displacement, 867 struct hists *pair_hists, bool show_displacement,
715 long displacement, FILE *fp, u64 session_total) 868 long displacement, FILE *fp, u64 session_total)
716{ 869{
717 char bf[512]; 870 char bf[512];
718 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, 871 int ret;
719 show_displacement, displacement, 872
720 true, session_total); 873 if (size == 0 || size > sizeof(bf))
874 size = sizeof(bf);
875
876 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
877 show_displacement, displacement,
878 true, session_total);
879 hist_entry__snprintf(he, bf + ret, size - ret, hists);
721 return fprintf(fp, "%s\n", bf); 880 return fprintf(fp, "%s\n", bf);
722} 881}
723 882
@@ -738,8 +897,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
738 left_margin); 897 left_margin);
739} 898}
740 899
741size_t hists__fprintf(struct hists *self, struct hists *pair, 900size_t hists__fprintf(struct hists *hists, struct hists *pair,
742 bool show_displacement, FILE *fp) 901 bool show_displacement, bool show_header, int max_rows,
902 int max_cols, FILE *fp)
743{ 903{
744 struct sort_entry *se; 904 struct sort_entry *se;
745 struct rb_node *nd; 905 struct rb_node *nd;
@@ -749,9 +909,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
749 unsigned int width; 909 unsigned int width;
750 const char *sep = symbol_conf.field_sep; 910 const char *sep = symbol_conf.field_sep;
751 const char *col_width = symbol_conf.col_width_list_str; 911 const char *col_width = symbol_conf.col_width_list_str;
912 int nr_rows = 0;
752 913
753 init_rem_hits(); 914 init_rem_hits();
754 915
916 if (!show_header)
917 goto print_entries;
918
755 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 919 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
756 920
757 if (symbol_conf.show_nr_samples) { 921 if (symbol_conf.show_nr_samples) {
@@ -761,6 +925,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
761 fputs(" Samples ", fp); 925 fputs(" Samples ", fp);
762 } 926 }
763 927
928 if (symbol_conf.show_total_period) {
929 if (sep)
930 ret += fprintf(fp, "%cPeriod", *sep);
931 else
932 ret += fprintf(fp, " Period ");
933 }
934
764 if (symbol_conf.show_cpu_utilization) { 935 if (symbol_conf.show_cpu_utilization) {
765 if (sep) { 936 if (sep) {
766 ret += fprintf(fp, "%csys", *sep); 937 ret += fprintf(fp, "%csys", *sep);
@@ -803,18 +974,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
803 width = strlen(se->se_header); 974 width = strlen(se->se_header);
804 if (symbol_conf.col_width_list_str) { 975 if (symbol_conf.col_width_list_str) {
805 if (col_width) { 976 if (col_width) {
806 hists__set_col_len(self, se->se_width_idx, 977 hists__set_col_len(hists, se->se_width_idx,
807 atoi(col_width)); 978 atoi(col_width));
808 col_width = strchr(col_width, ','); 979 col_width = strchr(col_width, ',');
809 if (col_width) 980 if (col_width)
810 ++col_width; 981 ++col_width;
811 } 982 }
812 } 983 }
813 if (!hists__new_col_len(self, se->se_width_idx, width)) 984 if (!hists__new_col_len(hists, se->se_width_idx, width))
814 width = hists__col_len(self, se->se_width_idx); 985 width = hists__col_len(hists, se->se_width_idx);
815 fprintf(fp, " %*s", width, se->se_header); 986 fprintf(fp, " %*s", width, se->se_header);
816 } 987 }
988
817 fprintf(fp, "\n"); 989 fprintf(fp, "\n");
990 if (max_rows && ++nr_rows >= max_rows)
991 goto out;
818 992
819 if (sep) 993 if (sep)
820 goto print_entries; 994 goto print_entries;
@@ -822,6 +996,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
822 fprintf(fp, "# ........"); 996 fprintf(fp, "# ........");
823 if (symbol_conf.show_nr_samples) 997 if (symbol_conf.show_nr_samples)
824 fprintf(fp, " .........."); 998 fprintf(fp, " ..........");
999 if (symbol_conf.show_total_period)
1000 fprintf(fp, " ............");
825 if (pair) { 1001 if (pair) {
826 fprintf(fp, " .........."); 1002 fprintf(fp, " ..........");
827 if (show_displacement) 1003 if (show_displacement)
@@ -834,17 +1010,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
834 continue; 1010 continue;
835 1011
836 fprintf(fp, " "); 1012 fprintf(fp, " ");
837 width = hists__col_len(self, se->se_width_idx); 1013 width = hists__col_len(hists, se->se_width_idx);
838 if (width == 0) 1014 if (width == 0)
839 width = strlen(se->se_header); 1015 width = strlen(se->se_header);
840 for (i = 0; i < width; i++) 1016 for (i = 0; i < width; i++)
841 fprintf(fp, "."); 1017 fprintf(fp, ".");
842 } 1018 }
843 1019
844 fprintf(fp, "\n#\n"); 1020 fprintf(fp, "\n");
1021 if (max_rows && ++nr_rows >= max_rows)
1022 goto out;
1023
1024 fprintf(fp, "#\n");
1025 if (max_rows && ++nr_rows >= max_rows)
1026 goto out;
845 1027
846print_entries: 1028print_entries:
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1029 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1030 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
849 1031
850 if (h->filtered) 1032 if (h->filtered)
@@ -858,19 +1040,22 @@ print_entries:
858 displacement = 0; 1040 displacement = 0;
859 ++position; 1041 ++position;
860 } 1042 }
861 ret += hist_entry__fprintf(h, self, pair, show_displacement, 1043 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
862 displacement, fp, self->stats.total_period); 1044 displacement, fp, hists->stats.total_period);
863 1045
864 if (symbol_conf.use_callchain) 1046 if (symbol_conf.use_callchain)
865 ret += hist_entry__fprintf_callchain(h, self, fp, 1047 ret += hist_entry__fprintf_callchain(h, hists, fp,
866 self->stats.total_period); 1048 hists->stats.total_period);
1049 if (max_rows && ++nr_rows >= max_rows)
1050 goto out;
1051
867 if (h->ms.map == NULL && verbose > 1) { 1052 if (h->ms.map == NULL && verbose > 1) {
868 __map_groups__fprintf_maps(&h->thread->mg, 1053 __map_groups__fprintf_maps(&h->thread->mg,
869 MAP__FUNCTION, verbose, fp); 1054 MAP__FUNCTION, verbose, fp);
870 fprintf(fp, "%.10s end\n", graph_dotted_line); 1055 fprintf(fp, "%.10s end\n", graph_dotted_line);
871 } 1056 }
872 } 1057 }
873 1058out:
874 free(rem_sq_bracket); 1059 free(rem_sq_bracket);
875 1060
876 return ret; 1061 return ret;
@@ -879,7 +1064,7 @@ print_entries:
879/* 1064/*
880 * See hists__fprintf to match the column widths 1065 * See hists__fprintf to match the column widths
881 */ 1066 */
882unsigned int hists__sort_list_width(struct hists *self) 1067unsigned int hists__sort_list_width(struct hists *hists)
883{ 1068{
884 struct sort_entry *se; 1069 struct sort_entry *se;
885 int ret = 9; /* total % */ 1070 int ret = 9; /* total % */
@@ -896,9 +1081,12 @@ unsigned int hists__sort_list_width(struct hists *self)
896 if (symbol_conf.show_nr_samples) 1081 if (symbol_conf.show_nr_samples)
897 ret += 11; 1082 ret += 11;
898 1083
1084 if (symbol_conf.show_total_period)
1085 ret += 13;
1086
899 list_for_each_entry(se, &hist_entry__sort_list, list) 1087 list_for_each_entry(se, &hist_entry__sort_list, list)
900 if (!se->elide) 1088 if (!se->elide)
901 ret += 2 + hists__col_len(self, se->se_width_idx); 1089 ret += 2 + hists__col_len(hists, se->se_width_idx);
902 1090
903 if (verbose) /* Addr + origin */ 1091 if (verbose) /* Addr + origin */
904 ret += 3 + BITS_PER_LONG / 4; 1092 ret += 3 + BITS_PER_LONG / 4;
@@ -906,63 +1094,84 @@ unsigned int hists__sort_list_width(struct hists *self)
906 return ret; 1094 return ret;
907} 1095}
908 1096
909static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 1097static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
910 enum hist_filter filter) 1098 enum hist_filter filter)
911{ 1099{
912 h->filtered &= ~(1 << filter); 1100 h->filtered &= ~(1 << filter);
913 if (h->filtered) 1101 if (h->filtered)
914 return; 1102 return;
915 1103
916 ++self->nr_entries; 1104 ++hists->nr_entries;
917 if (h->ms.unfolded) 1105 if (h->ms.unfolded)
918 self->nr_entries += h->nr_rows; 1106 hists->nr_entries += h->nr_rows;
919 h->row_offset = 0; 1107 h->row_offset = 0;
920 self->stats.total_period += h->period; 1108 hists->stats.total_period += h->period;
921 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1109 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
922 1110
923 hists__calc_col_len(self, h); 1111 hists__calc_col_len(hists, h);
924} 1112}
925 1113
926void hists__filter_by_dso(struct hists *self, const struct dso *dso) 1114
1115static bool hists__filter_entry_by_dso(struct hists *hists,
1116 struct hist_entry *he)
1117{
1118 if (hists->dso_filter != NULL &&
1119 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1120 he->filtered |= (1 << HIST_FILTER__DSO);
1121 return true;
1122 }
1123
1124 return false;
1125}
1126
1127void hists__filter_by_dso(struct hists *hists)
927{ 1128{
928 struct rb_node *nd; 1129 struct rb_node *nd;
929 1130
930 self->nr_entries = self->stats.total_period = 0; 1131 hists->nr_entries = hists->stats.total_period = 0;
931 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1132 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
932 hists__reset_col_len(self); 1133 hists__reset_col_len(hists);
933 1134
934 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1135 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1136 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
936 1137
937 if (symbol_conf.exclude_other && !h->parent) 1138 if (symbol_conf.exclude_other && !h->parent)
938 continue; 1139 continue;
939 1140
940 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { 1141 if (hists__filter_entry_by_dso(hists, h))
941 h->filtered |= (1 << HIST_FILTER__DSO);
942 continue; 1142 continue;
943 }
944 1143
945 hists__remove_entry_filter(self, h, HIST_FILTER__DSO); 1144 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
946 } 1145 }
947} 1146}
948 1147
949void hists__filter_by_thread(struct hists *self, const struct thread *thread) 1148static bool hists__filter_entry_by_thread(struct hists *hists,
1149 struct hist_entry *he)
1150{
1151 if (hists->thread_filter != NULL &&
1152 he->thread != hists->thread_filter) {
1153 he->filtered |= (1 << HIST_FILTER__THREAD);
1154 return true;
1155 }
1156
1157 return false;
1158}
1159
1160void hists__filter_by_thread(struct hists *hists)
950{ 1161{
951 struct rb_node *nd; 1162 struct rb_node *nd;
952 1163
953 self->nr_entries = self->stats.total_period = 0; 1164 hists->nr_entries = hists->stats.total_period = 0;
954 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1165 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
955 hists__reset_col_len(self); 1166 hists__reset_col_len(hists);
956 1167
957 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1168 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1169 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
959 1170
960 if (thread != NULL && h->thread != thread) { 1171 if (hists__filter_entry_by_thread(hists, h))
961 h->filtered |= (1 << HIST_FILTER__THREAD);
962 continue; 1172 continue;
963 }
964 1173
965 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); 1174 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
966 } 1175 }
967} 1176}
968 1177
@@ -976,13 +1185,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
976 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1185 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
977} 1186}
978 1187
979void hists__inc_nr_events(struct hists *self, u32 type) 1188void hists__inc_nr_events(struct hists *hists, u32 type)
980{ 1189{
981 ++self->stats.nr_events[0]; 1190 ++hists->stats.nr_events[0];
982 ++self->stats.nr_events[type]; 1191 ++hists->stats.nr_events[type];
983} 1192}
984 1193
985size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) 1194size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
986{ 1195{
987 int i; 1196 int i;
988 size_t ret = 0; 1197 size_t ret = 0;
@@ -990,7 +1199,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1199 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
991 const char *name; 1200 const char *name;
992 1201
993 if (self->stats.nr_events[i] == 0) 1202 if (hists->stats.nr_events[i] == 0)
994 continue; 1203 continue;
995 1204
996 name = perf_event__name(i); 1205 name = perf_event__name(i);
@@ -998,8 +1207,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
998 continue; 1207 continue;
999 1208
1000 ret += fprintf(fp, "%16s events: %10d\n", name, 1209 ret += fprintf(fp, "%16s events: %10d\n", name,
1001 self->stats.nr_events[i]); 1210 hists->stats.nr_events[i]);
1002 } 1211 }
1003 1212
1004 return ret; 1213 return ret;
1005} 1214}
1215
1216void hists__init(struct hists *hists)
1217{
1218 memset(hists, 0, sizeof(*hists));
1219 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1220 hists->entries_in = &hists->entries_in_array[0];
1221 hists->entries_collapsed = RB_ROOT;
1222 hists->entries = RB_ROOT;
1223 pthread_mutex_init(&hists->lock, NULL);
1224}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3beb97c4d822..ff93ddc91c5c 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -2,6 +2,7 @@
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h>
5#include "callchain.h" 6#include "callchain.h"
6 7
7extern struct callchain_param callchain_param; 8extern struct callchain_param callchain_param;
@@ -42,9 +43,18 @@ enum hist_column {
42 HISTC_NR_COLS, /* Last entry */ 43 HISTC_NR_COLS, /* Last entry */
43}; 44};
44 45
46struct thread;
47struct dso;
48
45struct hists { 49struct hists {
50 struct rb_root entries_in_array[2];
51 struct rb_root *entries_in;
46 struct rb_root entries; 52 struct rb_root entries;
53 struct rb_root entries_collapsed;
47 u64 nr_entries; 54 u64 nr_entries;
55 const struct thread *thread_filter;
56 const struct dso *dso_filter;
57 pthread_mutex_t lock;
48 struct events_stats stats; 58 struct events_stats stats;
49 u64 event_stream; 59 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 60 u16 col_len[HISTC_NR_COLS];
@@ -52,34 +62,42 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 62 struct callchain_cursor callchain_cursor;
53}; 63};
54 64
65void hists__init(struct hists *hists);
66
55struct hist_entry *__hists__add_entry(struct hists *self, 67struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 68 struct addr_location *al,
57 struct symbol *parent, u64 period); 69 struct symbol *parent, u64 period);
58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 70extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 71extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 72int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
61 struct hists *pair_hists, bool show_displacement, 73 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total); 74 long displacement, FILE *fp, u64 session_total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 75int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists, 76 struct hists *hists);
65 bool show_displacement, long displacement,
66 bool color, u64 total);
67void hist_entry__free(struct hist_entry *); 77void hist_entry__free(struct hist_entry *);
68 78
69void hists__output_resort(struct hists *self); 79void hists__output_resort(struct hists *self);
80void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 81void hists__collapse_resort(struct hists *self);
82void hists__collapse_resort_threaded(struct hists *hists);
83
84void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
85void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
86 bool zap_kernel);
87void hists__output_recalc_col_len(struct hists *hists, int max_rows);
71 88
72void hists__inc_nr_events(struct hists *self, u32 type); 89void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 90size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
74 91
75size_t hists__fprintf(struct hists *self, struct hists *pair, 92size_t hists__fprintf(struct hists *self, struct hists *pair,
76 bool show_displacement, FILE *fp); 93 bool show_displacement, bool show_header,
94 int max_rows, int max_cols, FILE *fp);
77 95
78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 96int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
79int hist_entry__annotate(struct hist_entry *self, size_t privsize); 97int hist_entry__annotate(struct hist_entry *self, size_t privsize);
80 98
81void hists__filter_by_dso(struct hists *self, const struct dso *dso); 99void hists__filter_by_dso(struct hists *hists);
82void hists__filter_by_thread(struct hists *self, const struct thread *thread); 100void hists__filter_by_thread(struct hists *hists);
83 101
84u16 hists__col_len(struct hists *self, enum hist_column col); 102u16 hists__col_len(struct hists *self, enum hist_column col);
85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 103void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -90,26 +108,33 @@ struct perf_evlist;
90#ifdef NO_NEWT_SUPPORT 108#ifdef NO_NEWT_SUPPORT
91static inline 109static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, 110int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used) 111 const char *help __used,
112 void(*timer)(void *arg) __used,
113 void *arg __used,
114 int refresh __used)
94{ 115{
95 return 0; 116 return 0;
96} 117}
97 118
98static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 119static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used) 120 int evidx __used,
121 int nr_events __used,
122 void(*timer)(void *arg) __used,
123 void *arg __used,
124 int delay_secs __used)
100{ 125{
101 return 0; 126 return 0;
102} 127}
103#define KEY_LEFT -1 128#define K_LEFT -1
104#define KEY_RIGHT -2 129#define K_RIGHT -2
105#else 130#else
106#include <newt.h> 131#include "ui/keysyms.h"
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx); 132int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
108 133 void(*timer)(void *arg), void *arg, int delay_secs);
109#define KEY_LEFT NEWT_KEY_LEFT
110#define KEY_RIGHT NEWT_KEY_RIGHT
111 134
112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); 135int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
136 void(*timer)(void *arg), void *arg,
137 int refresh);
113#endif 138#endif
114 139
115unsigned int hists__sort_list_width(struct hists *self); 140unsigned int hists__sort_list_width(struct hists *self);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a16ecab5229d..78284b13e808 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -18,6 +18,13 @@ static inline int is_anon_memory(const char *filename)
18 return strcmp(filename, "//anon") == 0; 18 return strcmp(filename, "//anon") == 0;
19} 19}
20 20
21static inline int is_no_dso_memory(const char *filename)
22{
23 return !strcmp(filename, "[stack]") ||
24 !strcmp(filename, "[vdso]") ||
25 !strcmp(filename, "[heap]");
26}
27
21void map__init(struct map *self, enum map_type type, 28void map__init(struct map *self, enum map_type type,
22 u64 start, u64 end, u64 pgoff, struct dso *dso) 29 u64 start, u64 end, u64 pgoff, struct dso *dso)
23{ 30{
@@ -42,9 +49,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
42 if (self != NULL) { 49 if (self != NULL) {
43 char newfilename[PATH_MAX]; 50 char newfilename[PATH_MAX];
44 struct dso *dso; 51 struct dso *dso;
45 int anon; 52 int anon, no_dso;
46 53
47 anon = is_anon_memory(filename); 54 anon = is_anon_memory(filename);
55 no_dso = is_no_dso_memory(filename);
48 56
49 if (anon) { 57 if (anon) {
50 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 58 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
@@ -57,12 +65,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
57 65
58 map__init(self, type, start, start + len, pgoff, dso); 66 map__init(self, type, start, start + len, pgoff, dso);
59 67
60 if (anon) { 68 if (anon || no_dso) {
61set_identity:
62 self->map_ip = self->unmap_ip = identity__map_ip; 69 self->map_ip = self->unmap_ip = identity__map_ip;
63 } else if (strcmp(filename, "[vdso]") == 0) { 70
64 dso__set_loaded(dso, self->type); 71 /*
65 goto set_identity; 72 * Set memory without DSO as loaded. All map__find_*
73 * functions still return NULL, and we avoid the
74 * unnecessary map__load warning.
75 */
76 if (no_dso)
77 dso__set_loaded(dso, self->type);
66 } 78 }
67 } 79 }
68 return self; 80 return self;
@@ -127,8 +139,8 @@ int map__load(struct map *self, symbol_filter_t filter)
127 139
128 if (len > sizeof(DSO__DELETED) && 140 if (len > sizeof(DSO__DELETED) &&
129 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 141 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
130 pr_warning("%.*s was updated, restart the long " 142 pr_warning("%.*s was updated (is prelink enabled?). "
131 "running apps that use it!\n", 143 "Restart the long running apps that use it!\n",
132 (int)real_len, name); 144 (int)real_len, name);
133 } else { 145 } else {
134 pr_warning("no symbols found in %s, maybe install " 146 pr_warning("no symbols found in %s, maybe install "
@@ -220,55 +232,55 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
220 return ip; 232 return ip;
221} 233}
222 234
223void map_groups__init(struct map_groups *self) 235void map_groups__init(struct map_groups *mg)
224{ 236{
225 int i; 237 int i;
226 for (i = 0; i < MAP__NR_TYPES; ++i) { 238 for (i = 0; i < MAP__NR_TYPES; ++i) {
227 self->maps[i] = RB_ROOT; 239 mg->maps[i] = RB_ROOT;
228 INIT_LIST_HEAD(&self->removed_maps[i]); 240 INIT_LIST_HEAD(&mg->removed_maps[i]);
229 } 241 }
230 self->machine = NULL; 242 mg->machine = NULL;
231} 243}
232 244
233static void maps__delete(struct rb_root *self) 245static void maps__delete(struct rb_root *maps)
234{ 246{
235 struct rb_node *next = rb_first(self); 247 struct rb_node *next = rb_first(maps);
236 248
237 while (next) { 249 while (next) {
238 struct map *pos = rb_entry(next, struct map, rb_node); 250 struct map *pos = rb_entry(next, struct map, rb_node);
239 251
240 next = rb_next(&pos->rb_node); 252 next = rb_next(&pos->rb_node);
241 rb_erase(&pos->rb_node, self); 253 rb_erase(&pos->rb_node, maps);
242 map__delete(pos); 254 map__delete(pos);
243 } 255 }
244} 256}
245 257
246static void maps__delete_removed(struct list_head *self) 258static void maps__delete_removed(struct list_head *maps)
247{ 259{
248 struct map *pos, *n; 260 struct map *pos, *n;
249 261
250 list_for_each_entry_safe(pos, n, self, node) { 262 list_for_each_entry_safe(pos, n, maps, node) {
251 list_del(&pos->node); 263 list_del(&pos->node);
252 map__delete(pos); 264 map__delete(pos);
253 } 265 }
254} 266}
255 267
256void map_groups__exit(struct map_groups *self) 268void map_groups__exit(struct map_groups *mg)
257{ 269{
258 int i; 270 int i;
259 271
260 for (i = 0; i < MAP__NR_TYPES; ++i) { 272 for (i = 0; i < MAP__NR_TYPES; ++i) {
261 maps__delete(&self->maps[i]); 273 maps__delete(&mg->maps[i]);
262 maps__delete_removed(&self->removed_maps[i]); 274 maps__delete_removed(&mg->removed_maps[i]);
263 } 275 }
264} 276}
265 277
266void map_groups__flush(struct map_groups *self) 278void map_groups__flush(struct map_groups *mg)
267{ 279{
268 int type; 280 int type;
269 281
270 for (type = 0; type < MAP__NR_TYPES; type++) { 282 for (type = 0; type < MAP__NR_TYPES; type++) {
271 struct rb_root *root = &self->maps[type]; 283 struct rb_root *root = &mg->maps[type];
272 struct rb_node *next = rb_first(root); 284 struct rb_node *next = rb_first(root);
273 285
274 while (next) { 286 while (next) {
@@ -280,17 +292,17 @@ void map_groups__flush(struct map_groups *self)
280 * instance in some hist_entry instances, so 292 * instance in some hist_entry instances, so
281 * just move them to a separate list. 293 * just move them to a separate list.
282 */ 294 */
283 list_add_tail(&pos->node, &self->removed_maps[pos->type]); 295 list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
284 } 296 }
285 } 297 }
286} 298}
287 299
288struct symbol *map_groups__find_symbol(struct map_groups *self, 300struct symbol *map_groups__find_symbol(struct map_groups *mg,
289 enum map_type type, u64 addr, 301 enum map_type type, u64 addr,
290 struct map **mapp, 302 struct map **mapp,
291 symbol_filter_t filter) 303 symbol_filter_t filter)
292{ 304{
293 struct map *map = map_groups__find(self, type, addr); 305 struct map *map = map_groups__find(mg, type, addr);
294 306
295 if (map != NULL) { 307 if (map != NULL) {
296 if (mapp != NULL) 308 if (mapp != NULL)
@@ -301,7 +313,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *self,
301 return NULL; 313 return NULL;
302} 314}
303 315
304struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 316struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
305 enum map_type type, 317 enum map_type type,
306 const char *name, 318 const char *name,
307 struct map **mapp, 319 struct map **mapp,
@@ -309,7 +321,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
309{ 321{
310 struct rb_node *nd; 322 struct rb_node *nd;
311 323
312 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 324 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
313 struct map *pos = rb_entry(nd, struct map, rb_node); 325 struct map *pos = rb_entry(nd, struct map, rb_node);
314 struct symbol *sym = map__find_symbol_by_name(pos, name, filter); 326 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
315 327
@@ -323,13 +335,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
323 return NULL; 335 return NULL;
324} 336}
325 337
326size_t __map_groups__fprintf_maps(struct map_groups *self, 338size_t __map_groups__fprintf_maps(struct map_groups *mg,
327 enum map_type type, int verbose, FILE *fp) 339 enum map_type type, int verbose, FILE *fp)
328{ 340{
329 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 341 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
330 struct rb_node *nd; 342 struct rb_node *nd;
331 343
332 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 344 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
333 struct map *pos = rb_entry(nd, struct map, rb_node); 345 struct map *pos = rb_entry(nd, struct map, rb_node);
334 printed += fprintf(fp, "Map:"); 346 printed += fprintf(fp, "Map:");
335 printed += map__fprintf(pos, fp); 347 printed += map__fprintf(pos, fp);
@@ -342,22 +354,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *self,
342 return printed; 354 return printed;
343} 355}
344 356
345size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp) 357size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
346{ 358{
347 size_t printed = 0, i; 359 size_t printed = 0, i;
348 for (i = 0; i < MAP__NR_TYPES; ++i) 360 for (i = 0; i < MAP__NR_TYPES; ++i)
349 printed += __map_groups__fprintf_maps(self, i, verbose, fp); 361 printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
350 return printed; 362 return printed;
351} 363}
352 364
353static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, 365static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
354 enum map_type type, 366 enum map_type type,
355 int verbose, FILE *fp) 367 int verbose, FILE *fp)
356{ 368{
357 struct map *pos; 369 struct map *pos;
358 size_t printed = 0; 370 size_t printed = 0;
359 371
360 list_for_each_entry(pos, &self->removed_maps[type], node) { 372 list_for_each_entry(pos, &mg->removed_maps[type], node) {
361 printed += fprintf(fp, "Map:"); 373 printed += fprintf(fp, "Map:");
362 printed += map__fprintf(pos, fp); 374 printed += map__fprintf(pos, fp);
363 if (verbose > 1) { 375 if (verbose > 1) {
@@ -368,26 +380,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
368 return printed; 380 return printed;
369} 381}
370 382
371static size_t map_groups__fprintf_removed_maps(struct map_groups *self, 383static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
372 int verbose, FILE *fp) 384 int verbose, FILE *fp)
373{ 385{
374 size_t printed = 0, i; 386 size_t printed = 0, i;
375 for (i = 0; i < MAP__NR_TYPES; ++i) 387 for (i = 0; i < MAP__NR_TYPES; ++i)
376 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp); 388 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
377 return printed; 389 return printed;
378} 390}
379 391
380size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp) 392size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
381{ 393{
382 size_t printed = map_groups__fprintf_maps(self, verbose, fp); 394 size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
383 printed += fprintf(fp, "Removed maps:\n"); 395 printed += fprintf(fp, "Removed maps:\n");
384 return printed + map_groups__fprintf_removed_maps(self, verbose, fp); 396 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
385} 397}
386 398
387int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 399int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
388 int verbose, FILE *fp) 400 int verbose, FILE *fp)
389{ 401{
390 struct rb_root *root = &self->maps[map->type]; 402 struct rb_root *root = &mg->maps[map->type];
391 struct rb_node *next = rb_first(root); 403 struct rb_node *next = rb_first(root);
392 int err = 0; 404 int err = 0;
393 405
@@ -418,7 +430,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
418 } 430 }
419 431
420 before->end = map->start - 1; 432 before->end = map->start - 1;
421 map_groups__insert(self, before); 433 map_groups__insert(mg, before);
422 if (verbose >= 2) 434 if (verbose >= 2)
423 map__fprintf(before, fp); 435 map__fprintf(before, fp);
424 } 436 }
@@ -432,7 +444,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
432 } 444 }
433 445
434 after->start = map->end + 1; 446 after->start = map->end + 1;
435 map_groups__insert(self, after); 447 map_groups__insert(mg, after);
436 if (verbose >= 2) 448 if (verbose >= 2)
437 map__fprintf(after, fp); 449 map__fprintf(after, fp);
438 } 450 }
@@ -441,7 +453,7 @@ move_map:
441 * If we have references, just move them to a separate list. 453 * If we have references, just move them to a separate list.
442 */ 454 */
443 if (pos->referenced) 455 if (pos->referenced)
444 list_add_tail(&pos->node, &self->removed_maps[map->type]); 456 list_add_tail(&pos->node, &mg->removed_maps[map->type]);
445 else 457 else
446 map__delete(pos); 458 map__delete(pos);
447 459
@@ -455,7 +467,7 @@ move_map:
455/* 467/*
456 * XXX This should not really _copy_ te maps, but refcount them. 468 * XXX This should not really _copy_ te maps, but refcount them.
457 */ 469 */
458int map_groups__clone(struct map_groups *self, 470int map_groups__clone(struct map_groups *mg,
459 struct map_groups *parent, enum map_type type) 471 struct map_groups *parent, enum map_type type)
460{ 472{
461 struct rb_node *nd; 473 struct rb_node *nd;
@@ -464,7 +476,7 @@ int map_groups__clone(struct map_groups *self,
464 struct map *new = map__clone(map); 476 struct map *new = map__clone(map);
465 if (new == NULL) 477 if (new == NULL)
466 return -ENOMEM; 478 return -ENOMEM;
467 map_groups__insert(self, new); 479 map_groups__insert(mg, new);
468 } 480 }
469 return 0; 481 return 0;
470} 482}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b397c0383728..890d85545d0f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -123,17 +123,17 @@ void map__fixup_end(struct map *self);
123 123
124void map__reloc_vmlinux(struct map *self); 124void map__reloc_vmlinux(struct map *self);
125 125
126size_t __map_groups__fprintf_maps(struct map_groups *self, 126size_t __map_groups__fprintf_maps(struct map_groups *mg,
127 enum map_type type, int verbose, FILE *fp); 127 enum map_type type, int verbose, FILE *fp);
128void maps__insert(struct rb_root *maps, struct map *map); 128void maps__insert(struct rb_root *maps, struct map *map);
129void maps__remove(struct rb_root *self, struct map *map); 129void maps__remove(struct rb_root *maps, struct map *map);
130struct map *maps__find(struct rb_root *maps, u64 addr); 130struct map *maps__find(struct rb_root *maps, u64 addr);
131void map_groups__init(struct map_groups *self); 131void map_groups__init(struct map_groups *mg);
132void map_groups__exit(struct map_groups *self); 132void map_groups__exit(struct map_groups *mg);
133int map_groups__clone(struct map_groups *self, 133int map_groups__clone(struct map_groups *mg,
134 struct map_groups *parent, enum map_type type); 134 struct map_groups *parent, enum map_type type);
135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 135size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
136size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); 136size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
137 137
138typedef void (*machine__process_t)(struct machine *self, void *data); 138typedef void (*machine__process_t)(struct machine *self, void *data);
139 139
@@ -162,29 +162,29 @@ static inline bool machine__is_host(struct machine *self)
162 return self ? self->pid == HOST_KERNEL_ID : false; 162 return self ? self->pid == HOST_KERNEL_ID : false;
163} 163}
164 164
165static inline void map_groups__insert(struct map_groups *self, struct map *map) 165static inline void map_groups__insert(struct map_groups *mg, struct map *map)
166{ 166{
167 maps__insert(&self->maps[map->type], map); 167 maps__insert(&mg->maps[map->type], map);
168 map->groups = self; 168 map->groups = mg;
169} 169}
170 170
171static inline void map_groups__remove(struct map_groups *self, struct map *map) 171static inline void map_groups__remove(struct map_groups *mg, struct map *map)
172{ 172{
173 maps__remove(&self->maps[map->type], map); 173 maps__remove(&mg->maps[map->type], map);
174} 174}
175 175
176static inline struct map *map_groups__find(struct map_groups *self, 176static inline struct map *map_groups__find(struct map_groups *mg,
177 enum map_type type, u64 addr) 177 enum map_type type, u64 addr)
178{ 178{
179 return maps__find(&self->maps[type], addr); 179 return maps__find(&mg->maps[type], addr);
180} 180}
181 181
182struct symbol *map_groups__find_symbol(struct map_groups *self, 182struct symbol *map_groups__find_symbol(struct map_groups *mg,
183 enum map_type type, u64 addr, 183 enum map_type type, u64 addr,
184 struct map **mapp, 184 struct map **mapp,
185 symbol_filter_t filter); 185 symbol_filter_t filter);
186 186
187struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 187struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
188 enum map_type type, 188 enum map_type type,
189 const char *name, 189 const char *name,
190 struct map **mapp, 190 struct map **mapp,
@@ -208,11 +208,11 @@ struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
208} 208}
209 209
210static inline 210static inline
211struct symbol *map_groups__find_function_by_name(struct map_groups *self, 211struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
212 const char *name, struct map **mapp, 212 const char *name, struct map **mapp,
213 symbol_filter_t filter) 213 symbol_filter_t filter)
214{ 214{
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline 218static inline
@@ -225,13 +225,13 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *self,
225 filter); 225 filter);
226} 226}
227 227
228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
229 int verbose, FILE *fp); 229 int verbose, FILE *fp);
230 230
231struct map *map_groups__find_by_name(struct map_groups *self, 231struct map *map_groups__find_by_name(struct map_groups *mg,
232 enum map_type type, const char *name); 232 enum map_type type, const char *name);
233struct map *machine__new_module(struct machine *self, u64 start, const char *filename); 233struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
234 234
235void map_groups__flush(struct map_groups *self); 235void map_groups__flush(struct map_groups *mg);
236 236
237#endif /* __PERF_MAP_H */ 237#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1c7bfa5fe0a8..eb25900e2211 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1956,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1956 1956
1957 pr_debug("Writing event: %s\n", buf); 1957 pr_debug("Writing event: %s\n", buf);
1958 ret = write(fd, buf, strlen(buf)); 1958 ret = write(fd, buf, strlen(buf));
1959 if (ret < 0) 1959 if (ret < 0) {
1960 ret = -errno;
1960 goto error; 1961 goto error;
1962 }
1961 1963
1962 printf("Remove event: %s\n", ent->s); 1964 printf("Remove event: %s\n", ent->s);
1963 return 0; 1965 return 0;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 72458d9da5b1..20e011c99a94 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1326,3 +1326,22 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1326 1326
1327 return 0; 1327 return 0;
1328} 1328}
1329
1330void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1331 bool full)
1332{
1333 struct stat st;
1334 int ret;
1335
1336 if (session == NULL || fp == NULL)
1337 return;
1338
1339 ret = fstat(session->fd, &st);
1340 if (ret == -1)
1341 return;
1342
1343 fprintf(fp, "# ========\n");
1344 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
1345 perf_header__fprintf_info(session, fp, full);
1346 fprintf(fp, "# ========\n#\n");
1347}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 974d0cbee5e9..514b06d41f05 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -177,4 +177,5 @@ void perf_session__print_ip(union perf_event *event,
177int perf_session__cpu_bitmap(struct perf_session *session, 177int perf_session__cpu_bitmap(struct perf_session *session,
178 const char *cpu_list, unsigned long *cpu_bitmap); 178 const char *cpu_list, unsigned long *cpu_bitmap);
179 179
180void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
180#endif /* __PERF_SESSION_H */ 181#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 1ee8f1e40f18..16da30d8d765 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -177,7 +177,9 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
177 BITS_PER_LONG / 4, self->ip, o); 177 BITS_PER_LONG / 4, self->ip, o);
178 } 178 }
179 179
180 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); 180 if (!sort_dso.elide)
181 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
182
181 if (self->ms.sym) 183 if (self->ms.sym)
182 ret += repsep_snprintf(bf + ret, size - ret, "%s", 184 ret += repsep_snprintf(bf + ret, size - ret, "%s",
183 self->ms.sym->name); 185 self->ms.sym->name);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 77d0388ad415..3f67ae395752 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension;
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding 45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */ 46 */
47struct hist_entry { 47struct hist_entry {
48 struct rb_node rb_node_in;
48 struct rb_node rb_node; 49 struct rb_node rb_node;
49 u64 period; 50 u64 period;
50 u64 period_sys; 51 u64 period_sys;
@@ -63,6 +64,7 @@ struct hist_entry {
63 64
64 bool init_have_children; 65 bool init_have_children;
65 char level; 66 char level;
67 bool used;
66 u8 filtered; 68 u8 filtered;
67 struct symbol *parent; 69 struct symbol *parent;
68 union { 70 union {
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 40eeaf07725b..632b50c7bc26 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -24,7 +24,7 @@
24#include <sys/utsname.h> 24#include <sys/utsname.h>
25 25
26#ifndef KSYM_NAME_LEN 26#ifndef KSYM_NAME_LEN
27#define KSYM_NAME_LEN 128 27#define KSYM_NAME_LEN 256
28#endif 28#endif
29 29
30#ifndef NT_GNU_BUILD_ID 30#ifndef NT_GNU_BUILD_ID
@@ -46,6 +46,7 @@ struct symbol_conf symbol_conf = {
46 .exclude_other = true, 46 .exclude_other = true,
47 .use_modules = true, 47 .use_modules = true,
48 .try_vmlinux_path = true, 48 .try_vmlinux_path = true,
49 .annotate_src = true,
49 .symfs = "", 50 .symfs = "",
50}; 51};
51 52
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 4f377d92e75a..29f8d742e92f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -72,11 +72,14 @@ struct symbol_conf {
72 use_modules, 72 use_modules,
73 sort_by_name, 73 sort_by_name,
74 show_nr_samples, 74 show_nr_samples,
75 show_total_period,
75 use_callchain, 76 use_callchain,
76 exclude_other, 77 exclude_other,
77 show_cpu_utilization, 78 show_cpu_utilization,
78 initialized, 79 initialized,
79 kptr_restrict; 80 kptr_restrict,
81 annotate_asm_raw,
82 annotate_src;
80 const char *vmlinux_name, 83 const char *vmlinux_name,
81 *kallsyms_name, 84 *kallsyms_name,
82 *source_prefix, 85 *source_prefix,
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index a11f60735a18..500471dffa4f 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -15,52 +15,6 @@
15#include "top.h" 15#include "top.h"
16#include <inttypes.h> 16#include <inttypes.h>
17 17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
64#define SNPRINTF(buf, size, fmt, args...) \ 18#define SNPRINTF(buf, size, fmt, args...) \
65({ \ 19({ \
66 size_t r = snprintf(buf, size, fmt, ## args); \ 20 size_t r = snprintf(buf, size, fmt, ## args); \
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
69 23
70size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
71{ 25{
72 struct perf_evsel *counter;
73 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
74 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
75 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
104 esamples_percent); 57 esamples_percent);
105 } 58 }
106 59
107 if (top->evlist->nr_entries == 1 || !top->display_weighted) { 60 if (top->evlist->nr_entries == 1) {
108 struct perf_evsel *first; 61 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node); 62 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 63 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
112 top->freq ? "Hz" : ""); 65 top->freq ? "Hz" : "");
113 } 66 }
114 67
115 if (!top->display_weighted) { 68 ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
136 69
137 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
138 71
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
166 top->exact_samples = top->guest_kernel_samples = 99 top->exact_samples = top->guest_kernel_samples =
167 top->guest_us_samples = 0; 100 top->guest_us_samples = 0;
168} 101}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index bfbf95bcc603..01d1057f3074 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -4,26 +4,10 @@
4#include "types.h" 4#include "types.h"
5#include "../perf.h" 5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <pthread.h>
8#include <linux/list.h>
9#include <linux/rbtree.h>
10 7
11struct perf_evlist; 8struct perf_evlist;
12struct perf_evsel; 9struct perf_evsel;
13 10struct perf_session;
14struct sym_entry {
15 struct rb_node rb_node;
16 struct list_head node;
17 unsigned long snap_count;
18 double weight;
19 struct map *map;
20 unsigned long count[0];
21};
22
23static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
24{
25 return ((void *)self) + symbol_conf.priv_size;
26}
27 11
28struct perf_top { 12struct perf_top {
29 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
@@ -31,34 +15,21 @@ struct perf_top {
31 * Symbols will be added here in perf_event__process_sample and will 15 * Symbols will be added here in perf_event__process_sample and will
32 * get out after decayed. 16 * get out after decayed.
33 */ 17 */
34 struct list_head active_symbols;
35 pthread_mutex_t active_symbols_lock;
36 pthread_cond_t active_symbols_cond;
37 u64 samples; 18 u64 samples;
38 u64 kernel_samples, us_samples; 19 u64 kernel_samples, us_samples;
39 u64 exact_samples; 20 u64 exact_samples;
40 u64 guest_us_samples, guest_kernel_samples; 21 u64 guest_us_samples, guest_kernel_samples;
22 u64 total_lost_warned;
41 int print_entries, count_filter, delay_secs; 23 int print_entries, count_filter, delay_secs;
42 int display_weighted, freq, rb_entries; 24 int freq;
43 pid_t target_pid, target_tid; 25 pid_t target_pid, target_tid;
44 bool hide_kernel_symbols, hide_user_symbols, zero; 26 bool hide_kernel_symbols, hide_user_symbols, zero;
45 const char *cpu_list; 27 const char *cpu_list;
46 struct sym_entry *sym_filter_entry; 28 struct hist_entry *sym_filter_entry;
47 struct perf_evsel *sym_evsel; 29 struct perf_evsel *sym_evsel;
30 struct perf_session *session;
48}; 31};
49 32
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 33size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top); 34void perf_top__reset_sample_counters(struct perf_top *top);
52float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
53void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
54 int *dso_width, int *dso_short_width, int *sym_width);
55
56#ifdef NO_NEWT_SUPPORT
57static inline int perf_top__tui_browser(struct perf_top *top __used)
58{
59 return 0;
60}
61#else
62int perf_top__tui_browser(struct perf_top *top);
63#endif
64#endif /* __PERF_TOP_H */ 35#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3403f814ad72..2d530cf74f43 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -196,7 +196,8 @@ static void record_file(const char *file, size_t hdr_sz)
196 die("Can't read '%s'", file); 196 die("Can't read '%s'", file);
197 197
198 /* put in zeros for file size, then fill true size later */ 198 /* put in zeros for file size, then fill true size later */
199 write_or_die(&size, hdr_sz); 199 if (hdr_sz)
200 write_or_die(&size, hdr_sz);
200 201
201 do { 202 do {
202 r = read(fd, buf, BUFSIZ); 203 r = read(fd, buf, BUFSIZ);
@@ -212,7 +213,7 @@ static void record_file(const char *file, size_t hdr_sz)
212 if (bigendian()) 213 if (bigendian())
213 sizep += sizeof(u64) - hdr_sz; 214 sizep += sizeof(u64) - hdr_sz;
214 215
215 if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 216 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
216 die("writing to %s", output_file); 217 die("writing to %s", output_file);
217} 218}
218 219
@@ -428,6 +429,19 @@ get_tracepoints_path(struct list_head *pattrs)
428 return nr_tracepoints > 0 ? path.next : NULL; 429 return nr_tracepoints > 0 ? path.next : NULL;
429} 430}
430 431
432static void
433put_tracepoints_path(struct tracepoint_path *tps)
434{
435 while (tps) {
436 struct tracepoint_path *t = tps;
437
438 tps = tps->next;
439 free(t->name);
440 free(t->system);
441 free(t);
442 }
443}
444
431bool have_tracepoints(struct list_head *pattrs) 445bool have_tracepoints(struct list_head *pattrs)
432{ 446{
433 struct perf_evsel *pos; 447 struct perf_evsel *pos;
@@ -439,19 +453,11 @@ bool have_tracepoints(struct list_head *pattrs)
439 return false; 453 return false;
440} 454}
441 455
442int read_tracing_data(int fd, struct list_head *pattrs) 456static void tracing_data_header(void)
443{ 457{
444 char buf[BUFSIZ]; 458 char buf[20];
445 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
446
447 /*
448 * What? No tracepoints? No sense writing anything here, bail out.
449 */
450 if (tps == NULL)
451 return -1;
452
453 output_fd = fd;
454 459
460 /* just guessing this is someone's birthday.. ;) */
455 buf[0] = 23; 461 buf[0] = 23;
456 buf[1] = 8; 462 buf[1] = 8;
457 buf[2] = 68; 463 buf[2] = 68;
@@ -476,28 +482,86 @@ int read_tracing_data(int fd, struct list_head *pattrs)
476 /* save page_size */ 482 /* save page_size */
477 page_size = sysconf(_SC_PAGESIZE); 483 page_size = sysconf(_SC_PAGESIZE);
478 write_or_die(&page_size, 4); 484 write_or_die(&page_size, 4);
485}
486
487struct tracing_data *tracing_data_get(struct list_head *pattrs,
488 int fd, bool temp)
489{
490 struct tracepoint_path *tps;
491 struct tracing_data *tdata;
492
493 output_fd = fd;
494
495 tps = get_tracepoints_path(pattrs);
496 if (!tps)
497 return NULL;
479 498
499 tdata = malloc_or_die(sizeof(*tdata));
500 tdata->temp = temp;
501 tdata->size = 0;
502
503 if (temp) {
504 int temp_fd;
505
506 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
507 "/tmp/perf-XXXXXX");
508 if (!mkstemp(tdata->temp_file))
509 die("Can't make temp file");
510
511 temp_fd = open(tdata->temp_file, O_RDWR);
512 if (temp_fd < 0)
513 die("Can't read '%s'", tdata->temp_file);
514
515 /*
516 * Set the temp file the default output, so all the
517 * tracing data are stored into it.
518 */
519 output_fd = temp_fd;
520 }
521
522 tracing_data_header();
480 read_header_files(); 523 read_header_files();
481 read_ftrace_files(tps); 524 read_ftrace_files(tps);
482 read_event_files(tps); 525 read_event_files(tps);
483 read_proc_kallsyms(); 526 read_proc_kallsyms();
484 read_ftrace_printk(); 527 read_ftrace_printk();
485 528
486 return 0; 529 /*
530 * All tracing data are stored by now, we can restore
531 * the default output file in case we used temp file.
532 */
533 if (temp) {
534 tdata->size = lseek(output_fd, 0, SEEK_CUR);
535 close(output_fd);
536 output_fd = fd;
537 }
538
539 put_tracepoints_path(tps);
540 return tdata;
487} 541}
488 542
489ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 543void tracing_data_put(struct tracing_data *tdata)
490{ 544{
491 ssize_t size; 545 if (tdata->temp) {
492 int err = 0; 546 record_file(tdata->temp_file, 0);
547 unlink(tdata->temp_file);
548 }
493 549
494 calc_data_size = 1; 550 free(tdata);
495 err = read_tracing_data(fd, pattrs); 551}
496 size = calc_data_size - 1;
497 calc_data_size = 0;
498 552
499 if (err < 0) 553int read_tracing_data(int fd, struct list_head *pattrs)
500 return err; 554{
555 struct tracing_data *tdata;
501 556
502 return size; 557 /*
558 * We work over the real file, so we can write data
559 * directly, no temp file is needed.
560 */
561 tdata = tracing_data_get(pattrs, fd, false);
562 if (!tdata)
563 return -ENOMEM;
564
565 tracing_data_put(tdata);
566 return 0;
503} 567}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index f674dda3363b..a84100817649 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -263,7 +263,18 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
264 264
265int read_tracing_data(int fd, struct list_head *pattrs); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs); 266
267struct tracing_data {
268 /* size is only valid if temp is 'true' */
269 ssize_t size;
270 bool temp;
271 char temp_file[50];
272};
273
274struct tracing_data *tracing_data_get(struct list_head *pattrs,
275 int fd, bool temp);
276void tracing_data_put(struct tracing_data *tdata);
277
267 278
268/* taken from kernel/trace/trace.h */ 279/* taken from kernel/trace/trace.h */
269enum trace_flag_type { 280enum trace_flag_type {
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 611219f80680..5359f371d30a 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,8 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
1#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
2#include "ui.h" 6#include "ui.h"
3#include <linux/compiler.h> 7#include <linux/compiler.h>
4#include <linux/list.h> 8#include <linux/list.h>
@@ -7,13 +11,13 @@
7#include <sys/ttydefaults.h> 11#include <sys/ttydefaults.h>
8#include "browser.h" 12#include "browser.h"
9#include "helpline.h" 13#include "helpline.h"
14#include "keysyms.h"
10#include "../color.h" 15#include "../color.h"
11#include "../util.h"
12#include <stdio.h>
13 16
14static int ui_browser__percent_color(double percent, bool current) 17static int ui_browser__percent_color(struct ui_browser *browser,
18 double percent, bool current)
15{ 19{
16 if (current) 20 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
17 return HE_COLORSET_SELECTED; 21 return HE_COLORSET_SELECTED;
18 if (percent >= MIN_RED) 22 if (percent >= MIN_RED)
19 return HE_COLORSET_TOP; 23 return HE_COLORSET_TOP;
@@ -30,7 +34,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color)
30void ui_browser__set_percent_color(struct ui_browser *self, 34void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current) 35 double percent, bool current)
32{ 36{
33 int color = ui_browser__percent_color(percent, current); 37 int color = ui_browser__percent_color(self, percent, current);
34 ui_browser__set_color(self, color); 38 ui_browser__set_color(self, color);
35} 39}
36 40
@@ -39,31 +43,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x)
39 SLsmg_gotorc(self->y + y, self->x + x); 43 SLsmg_gotorc(self->y + y, self->x + x);
40} 44}
41 45
46static struct list_head *
47ui_browser__list_head_filter_entries(struct ui_browser *browser,
48 struct list_head *pos)
49{
50 do {
51 if (!browser->filter || !browser->filter(browser, pos))
52 return pos;
53 pos = pos->next;
54 } while (pos != browser->entries);
55
56 return NULL;
57}
58
59static struct list_head *
60ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
61 struct list_head *pos)
62{
63 do {
64 if (!browser->filter || !browser->filter(browser, pos))
65 return pos;
66 pos = pos->prev;
67 } while (pos != browser->entries);
68
69 return NULL;
70}
71
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 72void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
43{ 73{
44 struct list_head *head = self->entries; 74 struct list_head *head = self->entries;
45 struct list_head *pos; 75 struct list_head *pos;
46 76
77 if (self->nr_entries == 0)
78 return;
79
47 switch (whence) { 80 switch (whence) {
48 case SEEK_SET: 81 case SEEK_SET:
49 pos = head->next; 82 pos = ui_browser__list_head_filter_entries(self, head->next);
50 break; 83 break;
51 case SEEK_CUR: 84 case SEEK_CUR:
52 pos = self->top; 85 pos = self->top;
53 break; 86 break;
54 case SEEK_END: 87 case SEEK_END:
55 pos = head->prev; 88 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
56 break; 89 break;
57 default: 90 default:
58 return; 91 return;
59 } 92 }
60 93
94 assert(pos != NULL);
95
61 if (offset > 0) { 96 if (offset > 0) {
62 while (offset-- != 0) 97 while (offset-- != 0)
63 pos = pos->next; 98 pos = ui_browser__list_head_filter_entries(self, pos->next);
64 } else { 99 } else {
65 while (offset++ != 0) 100 while (offset++ != 0)
66 pos = pos->prev; 101 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
67 } 102 }
68 103
69 self->top = pos; 104 self->top = pos;
@@ -127,11 +162,8 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
127 162
128void ui_browser__refresh_dimensions(struct ui_browser *self) 163void ui_browser__refresh_dimensions(struct ui_browser *self)
129{ 164{
130 int cols, rows; 165 self->width = SLtt_Screen_Cols - 1;
131 newtGetScreenSize(&cols, &rows); 166 self->height = SLtt_Screen_Rows - 2;
132
133 self->width = cols - 1;
134 self->height = rows - 2;
135 self->y = 1; 167 self->y = 1;
136 self->x = 0; 168 self->x = 0;
137} 169}
@@ -142,26 +174,11 @@ void ui_browser__reset_index(struct ui_browser *self)
142 self->seek(self, 0, SEEK_SET); 174 self->seek(self, 0, SEEK_SET);
143} 175}
144 176
145void ui_browser__add_exit_key(struct ui_browser *self, int key)
146{
147 newtFormAddHotKey(self->form, key);
148}
149
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
151{
152 int i = 0;
153
154 while (keys[i] && i < 64) {
155 ui_browser__add_exit_key(self, keys[i]);
156 ++i;
157 }
158}
159
160void __ui_browser__show_title(struct ui_browser *browser, const char *title) 177void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{ 178{
162 SLsmg_gotorc(0, 0); 179 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 180 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width); 181 slsmg_write_nstring(title, browser->width + 1);
165} 182}
166 183
167void ui_browser__show_title(struct ui_browser *browser, const char *title) 184void ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -174,78 +191,189 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
174int ui_browser__show(struct ui_browser *self, const char *title, 191int ui_browser__show(struct ui_browser *self, const char *title,
175 const char *helpline, ...) 192 const char *helpline, ...)
176{ 193{
194 int err;
177 va_list ap; 195 va_list ap;
178 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
179 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
180 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
181
182 if (self->form != NULL)
183 newtFormDestroy(self->form);
184 196
185 ui_browser__refresh_dimensions(self); 197 ui_browser__refresh_dimensions(self);
186 self->form = newtForm(NULL, NULL, 0);
187 if (self->form == NULL)
188 return -1;
189
190 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
191 HE_COLORSET_NORMAL,
192 HE_COLORSET_SELECTED);
193 if (self->sb == NULL)
194 return -1;
195 198
196 pthread_mutex_lock(&ui__lock); 199 pthread_mutex_lock(&ui__lock);
197 __ui_browser__show_title(self, title); 200 __ui_browser__show_title(self, title);
198 201
199 ui_browser__add_exit_keys(self, keys); 202 self->title = title;
200 newtFormAddComponent(self->form, self->sb); 203 free(self->helpline);
204 self->helpline = NULL;
201 205
202 va_start(ap, helpline); 206 va_start(ap, helpline);
203 ui_helpline__vpush(helpline, ap); 207 err = vasprintf(&self->helpline, helpline, ap);
204 va_end(ap); 208 va_end(ap);
209 if (err > 0)
210 ui_helpline__push(self->helpline);
205 pthread_mutex_unlock(&ui__lock); 211 pthread_mutex_unlock(&ui__lock);
206 return 0; 212 return err ? 0 : -1;
207} 213}
208 214
209void ui_browser__hide(struct ui_browser *self) 215void ui_browser__hide(struct ui_browser *browser __used)
210{ 216{
211 pthread_mutex_lock(&ui__lock); 217 pthread_mutex_lock(&ui__lock);
212 newtFormDestroy(self->form);
213 self->form = NULL;
214 ui_helpline__pop(); 218 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock); 219 pthread_mutex_unlock(&ui__lock);
216} 220}
217 221
218int ui_browser__refresh(struct ui_browser *self) 222static void ui_browser__scrollbar_set(struct ui_browser *browser)
223{
224 int height = browser->height, h = 0, pct = 0,
225 col = browser->width,
226 row = browser->y - 1;
227
228 if (browser->nr_entries > 1) {
229 pct = ((browser->index * (browser->height - 1)) /
230 (browser->nr_entries - 1));
231 }
232
233 while (h < height) {
234 ui_browser__gotorc(browser, row++, col);
235 SLsmg_set_char_set(1);
236 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR);
237 SLsmg_set_char_set(0);
238 ++h;
239 }
240}
241
242static int __ui_browser__refresh(struct ui_browser *browser)
219{ 243{
220 int row; 244 int row;
245 int width = browser->width;
246
247 row = browser->refresh(browser);
248 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
249
250 if (!browser->use_navkeypressed || browser->navkeypressed)
251 ui_browser__scrollbar_set(browser);
252 else
253 width += 1;
221 254
255 SLsmg_fill_region(browser->y + row, browser->x,
256 browser->height - row, width, ' ');
257
258 return 0;
259}
260
261int ui_browser__refresh(struct ui_browser *browser)
262{
222 pthread_mutex_lock(&ui__lock); 263 pthread_mutex_lock(&ui__lock);
223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 264 __ui_browser__refresh(browser);
224 row = self->refresh(self);
225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
226 SLsmg_fill_region(self->y + row, self->x,
227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock); 265 pthread_mutex_unlock(&ui__lock);
229 266
230 return 0; 267 return 0;
231} 268}
232 269
233int ui_browser__run(struct ui_browser *self) 270/*
271 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
272 * forget about any reference to any entry in the underlying data structure,
273 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
274 * after an output_resort and hist decay.
275 */
276void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
234{ 277{
235 struct newtExitStruct es; 278 off_t offset = nr_entries - browser->nr_entries;
279
280 browser->nr_entries = nr_entries;
236 281
237 if (ui_browser__refresh(self) < 0) 282 if (offset < 0) {
238 return -1; 283 if (browser->top_idx < (u64)-offset)
284 offset = -browser->top_idx;
285
286 browser->index += offset;
287 browser->top_idx += offset;
288 }
289
290 browser->top = NULL;
291 browser->seek(browser, browser->top_idx, SEEK_SET);
292}
293
294static int ui__getch(int delay_secs)
295{
296 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
297 fd_set read_set;
298 int err, key;
299
300 FD_ZERO(&read_set);
301 FD_SET(0, &read_set);
302
303 if (delay_secs) {
304 timeout.tv_sec = delay_secs;
305 timeout.tv_usec = 0;
306 }
307
308 err = select(1, &read_set, NULL, NULL, ptimeout);
309
310 if (err == 0)
311 return K_TIMER;
312
313 if (err == -1) {
314 if (errno == EINTR)
315 return K_RESIZE;
316 return K_ERROR;
317 }
318
319 key = SLang_getkey();
320 if (key != K_ESC)
321 return key;
322
323 FD_ZERO(&read_set);
324 FD_SET(0, &read_set);
325 timeout.tv_sec = 0;
326 timeout.tv_usec = 20;
327 err = select(1, &read_set, NULL, NULL, &timeout);
328 if (err == 0)
329 return K_ESC;
330
331 SLang_ungetkey(key);
332 return SLkp_getkey();
333}
334
335int ui_browser__run(struct ui_browser *self, int delay_secs)
336{
337 int err, key;
338
339 pthread__unblock_sigwinch();
239 340
240 while (1) { 341 while (1) {
241 off_t offset; 342 off_t offset;
242 343
243 newtFormRun(self->form, &es); 344 pthread_mutex_lock(&ui__lock);
244 345 err = __ui_browser__refresh(self);
245 if (es.reason != NEWT_EXIT_HOTKEY) 346 SLsmg_refresh();
347 pthread_mutex_unlock(&ui__lock);
348 if (err < 0)
246 break; 349 break;
247 switch (es.u.key) { 350
248 case NEWT_KEY_DOWN: 351 key = ui__getch(delay_secs);
352
353 if (key == K_RESIZE) {
354 pthread_mutex_lock(&ui__lock);
355 SLtt_get_screen_size();
356 SLsmg_reinit_smg();
357 pthread_mutex_unlock(&ui__lock);
358 ui_browser__refresh_dimensions(self);
359 __ui_browser__show_title(self, self->title);
360 ui_helpline__puts(self->helpline);
361 continue;
362 }
363
364 if (self->use_navkeypressed && !self->navkeypressed) {
365 if (key == K_DOWN || key == K_UP ||
366 key == K_PGDN || key == K_PGUP ||
367 key == K_HOME || key == K_END ||
368 key == ' ') {
369 self->navkeypressed = true;
370 continue;
371 } else
372 return key;
373 }
374
375 switch (key) {
376 case K_DOWN:
249 if (self->index == self->nr_entries - 1) 377 if (self->index == self->nr_entries - 1)
250 break; 378 break;
251 ++self->index; 379 ++self->index;
@@ -254,7 +382,7 @@ int ui_browser__run(struct ui_browser *self)
254 self->seek(self, +1, SEEK_CUR); 382 self->seek(self, +1, SEEK_CUR);
255 } 383 }
256 break; 384 break;
257 case NEWT_KEY_UP: 385 case K_UP:
258 if (self->index == 0) 386 if (self->index == 0)
259 break; 387 break;
260 --self->index; 388 --self->index;
@@ -263,7 +391,7 @@ int ui_browser__run(struct ui_browser *self)
263 self->seek(self, -1, SEEK_CUR); 391 self->seek(self, -1, SEEK_CUR);
264 } 392 }
265 break; 393 break;
266 case NEWT_KEY_PGDN: 394 case K_PGDN:
267 case ' ': 395 case ' ':
268 if (self->top_idx + self->height > self->nr_entries - 1) 396 if (self->top_idx + self->height > self->nr_entries - 1)
269 break; 397 break;
@@ -275,7 +403,7 @@ int ui_browser__run(struct ui_browser *self)
275 self->top_idx += offset; 403 self->top_idx += offset;
276 self->seek(self, +offset, SEEK_CUR); 404 self->seek(self, +offset, SEEK_CUR);
277 break; 405 break;
278 case NEWT_KEY_PGUP: 406 case K_PGUP:
279 if (self->top_idx == 0) 407 if (self->top_idx == 0)
280 break; 408 break;
281 409
@@ -288,10 +416,10 @@ int ui_browser__run(struct ui_browser *self)
288 self->top_idx -= offset; 416 self->top_idx -= offset;
289 self->seek(self, -offset, SEEK_CUR); 417 self->seek(self, -offset, SEEK_CUR);
290 break; 418 break;
291 case NEWT_KEY_HOME: 419 case K_HOME:
292 ui_browser__reset_index(self); 420 ui_browser__reset_index(self);
293 break; 421 break;
294 case NEWT_KEY_END: 422 case K_END:
295 offset = self->height - 1; 423 offset = self->height - 1;
296 if (offset >= self->nr_entries) 424 if (offset >= self->nr_entries)
297 offset = self->nr_entries - 1; 425 offset = self->nr_entries - 1;
@@ -301,10 +429,8 @@ int ui_browser__run(struct ui_browser *self)
301 self->seek(self, -offset, SEEK_END); 429 self->seek(self, -offset, SEEK_END);
302 break; 430 break;
303 default: 431 default:
304 return es.u.key; 432 return key;
305 } 433 }
306 if (ui_browser__refresh(self) < 0)
307 return -1;
308 } 434 }
309 return -1; 435 return -1;
310} 436}
@@ -316,41 +442,105 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
316 int row = 0; 442 int row = 0;
317 443
318 if (self->top == NULL || self->top == self->entries) 444 if (self->top == NULL || self->top == self->entries)
319 self->top = head->next; 445 self->top = ui_browser__list_head_filter_entries(self, head->next);
320 446
321 pos = self->top; 447 pos = self->top;
322 448
323 list_for_each_from(pos, head) { 449 list_for_each_from(pos, head) {
324 ui_browser__gotorc(self, row, 0); 450 if (!self->filter || !self->filter(self, pos)) {
325 self->write(self, pos, row); 451 ui_browser__gotorc(self, row, 0);
326 if (++row == self->height) 452 self->write(self, pos, row);
327 break; 453 if (++row == self->height)
454 break;
455 }
328 } 456 }
329 457
330 return row; 458 return row;
331} 459}
332 460
333static struct newtPercentTreeColors { 461static struct ui_browser__colorset {
334 const char *topColorFg, *topColorBg; 462 const char *name, *fg, *bg;
335 const char *mediumColorFg, *mediumColorBg; 463 int colorset;
336 const char *normalColorFg, *normalColorBg; 464} ui_browser__colorsets[] = {
337 const char *selColorFg, *selColorBg; 465 {
338 const char *codeColorFg, *codeColorBg; 466 .colorset = HE_COLORSET_TOP,
339} defaultPercentTreeColors = { 467 .name = "top",
340 "red", "lightgray", 468 .fg = "red",
341 "green", "lightgray", 469 .bg = "default",
342 "black", "lightgray", 470 },
343 "lightgray", "magenta", 471 {
344 "blue", "lightgray", 472 .colorset = HE_COLORSET_MEDIUM,
473 .name = "medium",
474 .fg = "green",
475 .bg = "default",
476 },
477 {
478 .colorset = HE_COLORSET_NORMAL,
479 .name = "normal",
480 .fg = "default",
481 .bg = "default",
482 },
483 {
484 .colorset = HE_COLORSET_SELECTED,
485 .name = "selected",
486 .fg = "black",
487 .bg = "lightgray",
488 },
489 {
490 .colorset = HE_COLORSET_CODE,
491 .name = "code",
492 .fg = "blue",
493 .bg = "default",
494 },
495 {
496 .name = NULL,
497 }
345}; 498};
346 499
500
501static int ui_browser__color_config(const char *var, const char *value,
502 void *data __used)
503{
504 char *fg = NULL, *bg;
505 int i;
506
507 /* same dir for all commands */
508 if (prefixcmp(var, "colors.") != 0)
509 return 0;
510
511 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
512 const char *name = var + 7;
513
514 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
515 continue;
516
517 fg = strdup(value);
518 if (fg == NULL)
519 break;
520
521 bg = strchr(fg, ',');
522 if (bg == NULL)
523 break;
524
525 *bg = '\0';
526 while (isspace(*++bg));
527 ui_browser__colorsets[i].bg = bg;
528 ui_browser__colorsets[i].fg = fg;
529 return 0;
530 }
531
532 free(fg);
533 return -1;
534}
535
347void ui_browser__init(void) 536void ui_browser__init(void)
348{ 537{
349 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 538 int i = 0;
350 539
351 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 540 perf_config(ui_browser__color_config, NULL);
352 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 541
353 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); 542 while (ui_browser__colorsets[i].name) {
354 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); 543 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
355 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg); 544 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
545 }
356} 546}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index fc63dda10910..a2c707d33c5e 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -2,7 +2,6 @@
2#define _PERF_UI_BROWSER_H_ 1 2#define _PERF_UI_BROWSER_H_ 1
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <newt.h>
6#include <sys/types.h> 5#include <sys/types.h>
7#include "../types.h" 6#include "../types.h"
8 7
@@ -13,15 +12,19 @@
13#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
14 13
15struct ui_browser { 14struct ui_browser {
16 newtComponent form, sb;
17 u64 index, top_idx; 15 u64 index, top_idx;
18 void *top, *entries; 16 void *top, *entries;
19 u16 y, x, width, height; 17 u16 y, x, width, height;
20 void *priv; 18 void *priv;
19 const char *title;
20 char *helpline;
21 unsigned int (*refresh)(struct ui_browser *self); 21 unsigned int (*refresh)(struct ui_browser *self);
22 void (*write)(struct ui_browser *self, void *entry, int row); 22 void (*write)(struct ui_browser *self, void *entry, int row);
23 void (*seek)(struct ui_browser *self, off_t offset, int whence); 23 void (*seek)(struct ui_browser *self, off_t offset, int whence);
24 bool (*filter)(struct ui_browser *self, void *entry);
24 u32 nr_entries; 25 u32 nr_entries;
26 bool navkeypressed;
27 bool use_navkeypressed;
25}; 28};
26 29
27void ui_browser__set_color(struct ui_browser *self, int color); 30void ui_browser__set_color(struct ui_browser *self, int color);
@@ -32,15 +35,14 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
32void ui_browser__reset_index(struct ui_browser *self); 35void ui_browser__reset_index(struct ui_browser *self);
33 36
34void ui_browser__gotorc(struct ui_browser *self, int y, int x); 37void ui_browser__gotorc(struct ui_browser *self, int y, int x);
35void ui_browser__add_exit_key(struct ui_browser *self, int key);
36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title); 38void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title); 39void ui_browser__show_title(struct ui_browser *browser, const char *title);
39int ui_browser__show(struct ui_browser *self, const char *title, 40int ui_browser__show(struct ui_browser *self, const char *title,
40 const char *helpline, ...); 41 const char *helpline, ...);
41void ui_browser__hide(struct ui_browser *self); 42void ui_browser__hide(struct ui_browser *self);
42int ui_browser__refresh(struct ui_browser *self); 43int ui_browser__refresh(struct ui_browser *self);
43int ui_browser__run(struct ui_browser *self); 44int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
44 46
45void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 47void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
46unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 48unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0229723aceb3..4e0cb7fea7d9 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -6,6 +6,7 @@
6#include "../../sort.h" 6#include "../../sort.h"
7#include "../../symbol.h" 7#include "../../symbol.h"
8#include <pthread.h> 8#include <pthread.h>
9#include <newt.h>
9 10
10static void ui__error_window(const char *fmt, ...) 11static void ui__error_window(const char *fmt, ...)
11{ 12{
@@ -20,12 +21,17 @@ struct annotate_browser {
20 struct ui_browser b; 21 struct ui_browser b;
21 struct rb_root entries; 22 struct rb_root entries;
22 struct rb_node *curr_hot; 23 struct rb_node *curr_hot;
24 struct objdump_line *selection;
25 int nr_asm_entries;
26 int nr_entries;
27 bool hide_src_code;
23}; 28};
24 29
25struct objdump_line_rb_node { 30struct objdump_line_rb_node {
26 struct rb_node rb_node; 31 struct rb_node rb_node;
27 double percent; 32 double percent;
28 u32 idx; 33 u32 idx;
34 int idx_asm;
29}; 35};
30 36
31static inline 37static inline
@@ -34,9 +40,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
34 return (struct objdump_line_rb_node *)(self + 1); 40 return (struct objdump_line_rb_node *)(self + 1);
35} 41}
36 42
43static bool objdump_line__filter(struct ui_browser *browser, void *entry)
44{
45 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
46
47 if (ab->hide_src_code) {
48 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
49 return ol->offset == -1;
50 }
51
52 return false;
53}
54
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 55static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 56{
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 57 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
58 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 59 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 60 int width = self->width;
42 61
@@ -51,6 +70,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
51 70
52 SLsmg_write_char(':'); 71 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8); 72 slsmg_write_nstring(" ", 8);
73
74 /* The scroll bar isn't being used */
75 if (!self->navkeypressed)
76 width += 1;
77
54 if (!*ol->line) 78 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18); 79 slsmg_write_nstring(" ", width - 18);
56 else 80 else
@@ -58,6 +82,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 82
59 if (!current_entry) 83 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 84 ui_browser__set_color(self, HE_COLORSET_CODE);
85 else
86 ab->selection = ol;
61} 87}
62 88
63static double objdump_line__calc_percent(struct objdump_line *self, 89static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +167,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 167static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 168 int evidx)
143{ 169{
144 struct symbol *sym = browser->b.priv; 170 struct map_symbol *ms = browser->b.priv;
171 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 172 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 173 struct objdump_line *pos;
147 174
@@ -163,25 +190,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
163 browser->curr_hot = rb_last(&browser->entries); 190 browser->curr_hot = rb_last(&browser->entries);
164} 191}
165 192
193static bool annotate_browser__toggle_source(struct annotate_browser *browser)
194{
195 struct objdump_line *ol;
196 struct objdump_line_rb_node *olrb;
197 off_t offset = browser->b.index - browser->b.top_idx;
198
199 browser->b.seek(&browser->b, offset, SEEK_CUR);
200 ol = list_entry(browser->b.top, struct objdump_line, node);
201 olrb = objdump_line__rb(ol);
202
203 if (browser->hide_src_code) {
204 if (olrb->idx_asm < offset)
205 offset = olrb->idx;
206
207 browser->b.nr_entries = browser->nr_entries;
208 browser->hide_src_code = false;
209 browser->b.seek(&browser->b, -offset, SEEK_CUR);
210 browser->b.top_idx = olrb->idx - offset;
211 browser->b.index = olrb->idx;
212 } else {
213 if (olrb->idx_asm < 0) {
214 ui_helpline__puts("Only available for assembly lines.");
215 browser->b.seek(&browser->b, -offset, SEEK_CUR);
216 return false;
217 }
218
219 if (olrb->idx_asm < offset)
220 offset = olrb->idx_asm;
221
222 browser->b.nr_entries = browser->nr_asm_entries;
223 browser->hide_src_code = true;
224 browser->b.seek(&browser->b, -offset, SEEK_CUR);
225 browser->b.top_idx = olrb->idx_asm - offset;
226 browser->b.index = olrb->idx_asm;
227 }
228
229 return true;
230}
231
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 232static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 233 int nr_events, void(*timer)(void *arg),
234 void *arg, int delay_secs)
168{ 235{
169 struct rb_node *nd = NULL; 236 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 237 struct map_symbol *ms = self->b.priv;
171 /* 238 struct symbol *sym = ms->sym;
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 239 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
173 * examining the exit key for this function. 240 "H: Hottest, -> Line action, S -> Toggle source "
174 */ 241 "code view";
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key; 242 int key;
178 243
179 if (ui_browser__show(&self->b, sym->name, 244 if (ui_browser__show(&self->b, sym->name, help) < 0)
180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
182 return -1; 245 return -1;
183 246
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx); 247 annotate_browser__calc_percent(self, evidx);
186 248
187 if (self->curr_hot) 249 if (self->curr_hot)
@@ -189,13 +251,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 251
190 nd = self->curr_hot; 252 nd = self->curr_hot;
191 253
192 if (refresh != 0)
193 newtFormSetTimer(self->b.form, refresh);
194
195 while (1) { 254 while (1) {
196 key = ui_browser__run(&self->b); 255 key = ui_browser__run(&self->b, delay_secs);
197 256
198 if (refresh != 0) { 257 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 258 annotate_browser__calc_percent(self, evidx);
200 /* 259 /*
201 * Current line focus got out of the list of most active 260 * Current line focus got out of the list of most active
@@ -207,15 +266,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
207 } 266 }
208 267
209 switch (key) { 268 switch (key) {
210 case -1: 269 case K_TIMER:
211 /* 270 if (timer != NULL)
212 * FIXME we need to check if it was 271 timer(arg);
213 * es.reason == NEWT_EXIT_TIMER 272
214 */ 273 if (delay_secs != 0)
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 274 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 275 continue;
218 case NEWT_KEY_TAB: 276 case K_TAB:
219 if (nd != NULL) { 277 if (nd != NULL) {
220 nd = rb_prev(nd); 278 nd = rb_prev(nd);
221 if (nd == NULL) 279 if (nd == NULL)
@@ -223,7 +281,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
223 } else 281 } else
224 nd = self->curr_hot; 282 nd = self->curr_hot;
225 break; 283 break;
226 case NEWT_KEY_UNTAB: 284 case K_UNTAB:
227 if (nd != NULL) 285 if (nd != NULL)
228 nd = rb_next(nd); 286 nd = rb_next(nd);
229 if (nd == NULL) 287 if (nd == NULL)
@@ -234,8 +292,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 292 case 'H':
235 nd = self->curr_hot; 293 nd = self->curr_hot;
236 break; 294 break;
237 default: 295 case 'S':
296 if (annotate_browser__toggle_source(self))
297 ui_helpline__puts(help);
298 continue;
299 case K_ENTER:
300 case K_RIGHT:
301 if (self->selection == NULL) {
302 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
303 continue;
304 }
305
306 if (self->selection->offset == -1) {
307 ui_helpline__puts("Actions are only available for assembly lines.");
308 continue;
309 } else {
310 char *s = strstr(self->selection->line, "callq ");
311 struct annotation *notes;
312 struct symbol *target;
313 u64 ip;
314
315 if (s == NULL) {
316 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
317 continue;
318 }
319
320 s = strchr(s, ' ');
321 if (s++ == NULL) {
322 ui_helpline__puts("Invallid callq instruction.");
323 continue;
324 }
325
326 ip = strtoull(s, NULL, 16);
327 ip = ms->map->map_ip(ms->map, ip);
328 target = map__find_symbol(ms->map, ip, NULL);
329 if (target == NULL) {
330 ui_helpline__puts("The called function was not found.");
331 continue;
332 }
333
334 notes = symbol__annotation(target);
335 pthread_mutex_lock(&notes->lock);
336
337 if (notes->src == NULL &&
338 symbol__alloc_hist(target, nr_events) < 0) {
339 pthread_mutex_unlock(&notes->lock);
340 ui__warning("Not enough memory for annotating '%s' symbol!\n",
341 target->name);
342 continue;
343 }
344
345 pthread_mutex_unlock(&notes->lock);
346 symbol__tui_annotate(target, ms->map, evidx, nr_events,
347 timer, arg, delay_secs);
348 }
349 continue;
350 case K_LEFT:
351 case K_ESC:
352 case 'q':
353 case CTRL('c'):
238 goto out; 354 goto out;
355 default:
356 continue;
239 } 357 }
240 358
241 if (nd != NULL) 359 if (nd != NULL)
@@ -246,22 +364,31 @@ out:
246 return key; 364 return key;
247} 365}
248 366
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 367int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
368 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 369{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 370 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
371 timer, arg, delay_secs);
252} 372}
253 373
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 374int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 375 int nr_events, void(*timer)(void *arg), void *arg,
376 int delay_secs)
256{ 377{
257 struct objdump_line *pos, *n; 378 struct objdump_line *pos, *n;
258 struct annotation *notes; 379 struct annotation *notes;
380 struct map_symbol ms = {
381 .map = map,
382 .sym = sym,
383 };
259 struct annotate_browser browser = { 384 struct annotate_browser browser = {
260 .b = { 385 .b = {
261 .refresh = ui_browser__list_head_refresh, 386 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 387 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 388 .write = annotate_browser__write,
264 .priv = sym, 389 .filter = objdump_line__filter,
390 .priv = &ms,
391 .use_navkeypressed = true,
265 }, 392 },
266 }; 393 };
267 int ret; 394 int ret;
@@ -288,12 +415,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
288 if (browser.b.width < line_len) 415 if (browser.b.width < line_len)
289 browser.b.width = line_len; 416 browser.b.width = line_len;
290 rbpos = objdump_line__rb(pos); 417 rbpos = objdump_line__rb(pos);
291 rbpos->idx = browser.b.nr_entries++; 418 rbpos->idx = browser.nr_entries++;
419 if (pos->offset != -1)
420 rbpos->idx_asm = browser.nr_asm_entries++;
421 else
422 rbpos->idx_asm = -1;
292 } 423 }
293 424
425 browser.b.nr_entries = browser.nr_entries;
294 browser.b.entries = &notes->src->source, 426 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 427 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 428 ret = annotate_browser__run(&browser, evidx, nr_events,
429 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 430 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 431 list_del(&pos->node);
299 objdump_line__free(pos); 432 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..4663dcb2a19b 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -24,8 +24,12 @@ struct hist_browser {
24 struct hists *hists; 24 struct hists *hists;
25 struct hist_entry *he_selection; 25 struct hist_entry *he_selection;
26 struct map_symbol *selection; 26 struct map_symbol *selection;
27 bool has_symbols;
27}; 28};
28 29
30static int hists__browser_title(struct hists *self, char *bf, size_t size,
31 const char *ev_name);
32
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 33static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 34{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 35 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +294,34 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 294 ui_browser__reset_index(&self->b);
291} 295}
292 296
293static int hist_browser__run(struct hist_browser *self, const char *title) 297static int hist_browser__run(struct hist_browser *self, const char *ev_name,
298 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 299{
295 int key; 300 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 301 char title[160];
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
299 302
300 self->b.entries = &self->hists->entries; 303 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 304 self->b.nr_entries = self->hists->nr_entries;
302 305
303 hist_browser__refresh_dimensions(self); 306 hist_browser__refresh_dimensions(self);
307 hists__browser_title(self->hists, title, sizeof(title), ev_name);
304 308
305 if (ui_browser__show(&self->b, title, 309 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 310 "Press '?' for help on key bindings") < 0)
307 return -1; 311 return -1;
308 312
309 ui_browser__add_exit_keys(&self->b, exit_keys);
310
311 while (1) { 313 while (1) {
312 key = ui_browser__run(&self->b); 314 key = ui_browser__run(&self->b, delay_secs);
313 315
314 switch (key) { 316 switch (key) {
317 case -1:
318 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
319 timer(arg);
320 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
321 hists__browser_title(self->hists, title, sizeof(title),
322 ev_name);
323 ui_browser__show_title(&self->b, title);
324 continue;
315 case 'D': { /* Debug */ 325 case 'D': { /* Debug */
316 static int seq; 326 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 327 struct hist_entry *h = rb_entry(self->b.top,
@@ -334,7 +344,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
334 /* Expand the whole world. */ 344 /* Expand the whole world. */
335 hist_browser__set_folding(self, true); 345 hist_browser__set_folding(self, true);
336 break; 346 break;
337 case NEWT_KEY_ENTER: 347 case K_ENTER:
338 if (hist_browser__toggle_fold(self)) 348 if (hist_browser__toggle_fold(self))
339 break; 349 break;
340 /* fall thru */ 350 /* fall thru */
@@ -532,7 +542,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
532 char s[256]; 542 char s[256];
533 double percent; 543 double percent;
534 int printed = 0; 544 int printed = 0;
535 int color, width = self->b.width; 545 int width = self->b.width - 6; /* The percentage */
536 char folded_sign = ' '; 546 char folded_sign = ' ';
537 bool current_entry = ui_browser__is_current_entry(&self->b, row); 547 bool current_entry = ui_browser__is_current_entry(&self->b, row);
538 off_t row_offset = entry->row_offset; 548 off_t row_offset = entry->row_offset;
@@ -548,26 +558,35 @@ static int hist_browser__show_entry(struct hist_browser *self,
548 } 558 }
549 559
550 if (row_offset == 0) { 560 if (row_offset == 0) {
551 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, 561 hist_entry__snprintf(entry, s, sizeof(s), self->hists);
552 0, false, self->hists->stats.total_period);
553 percent = (entry->period * 100.0) / self->hists->stats.total_period; 562 percent = (entry->period * 100.0) / self->hists->stats.total_period;
554 563
555 color = HE_COLORSET_SELECTED; 564 ui_browser__set_percent_color(&self->b, percent, current_entry);
556 if (!current_entry) {
557 if (percent >= MIN_RED)
558 color = HE_COLORSET_TOP;
559 else if (percent >= MIN_GREEN)
560 color = HE_COLORSET_MEDIUM;
561 else
562 color = HE_COLORSET_NORMAL;
563 }
564
565 ui_browser__set_color(&self->b, color);
566 ui_browser__gotorc(&self->b, row, 0); 565 ui_browser__gotorc(&self->b, row, 0);
567 if (symbol_conf.use_callchain) { 566 if (symbol_conf.use_callchain) {
568 slsmg_printf("%c ", folded_sign); 567 slsmg_printf("%c ", folded_sign);
569 width -= 2; 568 width -= 2;
570 } 569 }
570
571 slsmg_printf(" %5.2f%%", percent);
572
573 /* The scroll bar isn't being used */
574 if (!self->b.navkeypressed)
575 width += 1;
576
577 if (!current_entry || !self->b.navkeypressed)
578 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
579
580 if (symbol_conf.show_nr_samples) {
581 slsmg_printf(" %11u", entry->nr_events);
582 width -= 12;
583 }
584
585 if (symbol_conf.show_total_period) {
586 slsmg_printf(" %12" PRIu64, entry->period);
587 width -= 13;
588 }
589
571 slsmg_write_nstring(s, width); 590 slsmg_write_nstring(s, width);
572 ++row; 591 ++row;
573 ++printed; 592 ++printed;
@@ -585,14 +604,23 @@ static int hist_browser__show_entry(struct hist_browser *self,
585 return printed; 604 return printed;
586} 605}
587 606
607static void ui_browser__hists_init_top(struct ui_browser *browser)
608{
609 if (browser->top == NULL) {
610 struct hist_browser *hb;
611
612 hb = container_of(browser, struct hist_browser, b);
613 browser->top = rb_first(&hb->hists->entries);
614 }
615}
616
588static unsigned int hist_browser__refresh(struct ui_browser *self) 617static unsigned int hist_browser__refresh(struct ui_browser *self)
589{ 618{
590 unsigned row = 0; 619 unsigned row = 0;
591 struct rb_node *nd; 620 struct rb_node *nd;
592 struct hist_browser *hb = container_of(self, struct hist_browser, b); 621 struct hist_browser *hb = container_of(self, struct hist_browser, b);
593 622
594 if (self->top == NULL) 623 ui_browser__hists_init_top(self);
595 self->top = rb_first(&hb->hists->entries);
596 624
597 for (nd = self->top; nd; nd = rb_next(nd)) { 625 for (nd = self->top; nd; nd = rb_next(nd)) {
598 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 626 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -644,6 +672,8 @@ static void ui_browser__hists_seek(struct ui_browser *self,
644 if (self->nr_entries == 0) 672 if (self->nr_entries == 0)
645 return; 673 return;
646 674
675 ui_browser__hists_init_top(self);
676
647 switch (whence) { 677 switch (whence) {
648 case SEEK_SET: 678 case SEEK_SET:
649 nd = hists__filter_entries(rb_first(self->entries)); 679 nd = hists__filter_entries(rb_first(self->entries));
@@ -761,6 +791,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 791 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 792 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 793 self->b.seek = ui_browser__hists_seek;
794 self->b.use_navkeypressed = true,
795 self->has_symbols = sort_sym.list.next != NULL;
764 } 796 }
765 797
766 return self; 798 return self;
@@ -782,11 +814,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
782} 814}
783 815
784static int hists__browser_title(struct hists *self, char *bf, size_t size, 816static int hists__browser_title(struct hists *self, char *bf, size_t size,
785 const char *ev_name, const struct dso *dso, 817 const char *ev_name)
786 const struct thread *thread)
787{ 818{
788 char unit; 819 char unit;
789 int printed; 820 int printed;
821 const struct dso *dso = self->dso_filter;
822 const struct thread *thread = self->thread_filter;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 823 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791 824
792 nr_events = convert_unit(nr_events, &unit); 825 nr_events = convert_unit(nr_events, &unit);
@@ -803,16 +836,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
803 return printed; 836 return printed;
804} 837}
805 838
806static int perf_evsel__hists_browse(struct perf_evsel *evsel, 839static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
807 const char *helpline, const char *ev_name, 840 const char *helpline, const char *ev_name,
808 bool left_exits) 841 bool left_exits,
842 void(*timer)(void *arg), void *arg,
843 int delay_secs)
809{ 844{
810 struct hists *self = &evsel->hists; 845 struct hists *self = &evsel->hists;
811 struct hist_browser *browser = hist_browser__new(self); 846 struct hist_browser *browser = hist_browser__new(self);
812 struct pstack *fstack; 847 struct pstack *fstack;
813 const struct thread *thread_filter = NULL;
814 const struct dso *dso_filter = NULL;
815 char msg[160];
816 int key = -1; 848 int key = -1;
817 849
818 if (browser == NULL) 850 if (browser == NULL)
@@ -824,8 +856,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
824 856
825 ui_helpline__push(helpline); 857 ui_helpline__push(helpline);
826 858
827 hists__browser_title(self, msg, sizeof(msg), ev_name,
828 dso_filter, thread_filter);
829 while (1) { 859 while (1) {
830 const struct thread *thread = NULL; 860 const struct thread *thread = NULL;
831 const struct dso *dso = NULL; 861 const struct dso *dso = NULL;
@@ -834,7 +864,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
834 annotate = -2, zoom_dso = -2, zoom_thread = -2, 864 annotate = -2, zoom_dso = -2, zoom_thread = -2,
835 browse_map = -2; 865 browse_map = -2;
836 866
837 key = hist_browser__run(browser, msg); 867 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
838 868
839 if (browser->he_selection != NULL) { 869 if (browser->he_selection != NULL) {
840 thread = hist_browser__selected_thread(browser); 870 thread = hist_browser__selected_thread(browser);
@@ -842,14 +872,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
842 } 872 }
843 873
844 switch (key) { 874 switch (key) {
845 case NEWT_KEY_TAB: 875 case K_TAB:
846 case NEWT_KEY_UNTAB: 876 case K_UNTAB:
877 if (nr_events == 1)
878 continue;
847 /* 879 /*
848 * Exit the browser, let hists__browser_tree 880 * Exit the browser, let hists__browser_tree
849 * go to the next or previous 881 * go to the next or previous
850 */ 882 */
851 goto out_free_stack; 883 goto out_free_stack;
852 case 'a': 884 case 'a':
885 if (!browser->has_symbols) {
886 ui__warning(
887 "Annotation is only available for symbolic views, "
888 "include \"sym\" in --sort to use it.");
889 continue;
890 }
891
853 if (browser->selection == NULL || 892 if (browser->selection == NULL ||
854 browser->selection->sym == NULL || 893 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned) 894 browser->selection->map->dso->annotate_warned)
@@ -859,25 +898,29 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
859 goto zoom_dso; 898 goto zoom_dso;
860 case 't': 899 case 't':
861 goto zoom_thread; 900 goto zoom_thread;
862 case NEWT_KEY_F1: 901 case K_F1:
863 case 'h': 902 case 'h':
864 case '?': 903 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 904 ui__help_window("h/?/F1 Show this window\n"
866 "<- Zoom out\n" 905 "UP/DOWN/PGUP\n"
867 "a Annotate current symbol\n" 906 "PGDN/SPACE Navigate\n"
868 "h/?/F1 Show this window\n" 907 "q/ESC/CTRL+C Exit browser\n\n"
869 "C Collapse all callchains\n" 908 "For multiple event sessions:\n\n"
870 "E Expand all callchains\n" 909 "TAB/UNTAB Switch events\n\n"
871 "d Zoom into current DSO\n" 910 "For symbolic views (--sort has sym):\n\n"
872 "t Zoom into current Thread\n" 911 "-> Zoom into DSO/Threads & Annotate current symbol\n"
873 "TAB/UNTAB Switch events\n" 912 "<- Zoom out\n"
874 "q/CTRL+C Exit browser"); 913 "a Annotate current symbol\n"
914 "C Collapse all callchains\n"
915 "E Expand all callchains\n"
916 "d Zoom into current DSO\n"
917 "t Zoom into current Thread\n");
875 continue; 918 continue;
876 case NEWT_KEY_ENTER: 919 case K_ENTER:
877 case NEWT_KEY_RIGHT: 920 case K_RIGHT:
878 /* menu */ 921 /* menu */
879 break; 922 break;
880 case NEWT_KEY_LEFT: { 923 case K_LEFT: {
881 const void *top; 924 const void *top;
882 925
883 if (pstack__empty(fstack)) { 926 if (pstack__empty(fstack)) {
@@ -889,21 +932,27 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 932 continue;
890 } 933 }
891 top = pstack__pop(fstack); 934 top = pstack__pop(fstack);
892 if (top == &dso_filter) 935 if (top == &browser->hists->dso_filter)
893 goto zoom_out_dso; 936 goto zoom_out_dso;
894 if (top == &thread_filter) 937 if (top == &browser->hists->thread_filter)
895 goto zoom_out_thread; 938 goto zoom_out_thread;
896 continue; 939 continue;
897 } 940 }
898 case NEWT_KEY_ESCAPE: 941 case K_ESC:
899 if (!left_exits && 942 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?")) 943 !ui__dialog_yesno("Do you really want to exit?"))
901 continue; 944 continue;
902 /* Fall thru */ 945 /* Fall thru */
903 default: 946 case 'q':
947 case CTRL('c'):
904 goto out_free_stack; 948 goto out_free_stack;
949 default:
950 continue;
905 } 951 }
906 952
953 if (!browser->has_symbols)
954 goto add_exit_option;
955
907 if (browser->selection != NULL && 956 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 957 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 958 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +962,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 962
914 if (thread != NULL && 963 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 964 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 965 (browser->hists->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 966 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 967 thread->pid) > 0)
919 zoom_thread = nr_options++; 968 zoom_thread = nr_options++;
920 969
921 if (dso != NULL && 970 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 971 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 972 (browser->hists->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 973 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 974 zoom_dso = nr_options++;
926 975
@@ -928,7 +977,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 977 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 978 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 979 browse_map = nr_options++;
931 980add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 981 options[nr_options++] = (char *)"Exit";
933 982
934 choice = ui__popup_menu(nr_options, options); 983 choice = ui__popup_menu(nr_options, options);
@@ -948,46 +997,52 @@ do_annotate:
948 he = hist_browser__selected_entry(browser); 997 he = hist_browser__selected_entry(browser);
949 if (he == NULL) 998 if (he == NULL)
950 continue; 999 continue;
951 1000 /*
952 hist_entry__tui_annotate(he, evsel->idx); 1001 * Don't let this be freed, say, by hists__decay_entry.
1002 */
1003 he->used = true;
1004 hist_entry__tui_annotate(he, evsel->idx, nr_events,
1005 timer, arg, delay_secs);
1006 he->used = false;
1007 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
953 } else if (choice == browse_map) 1008 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 1009 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 1010 else if (choice == zoom_dso) {
956zoom_dso: 1011zoom_dso:
957 if (dso_filter) { 1012 if (browser->hists->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 1013 pstack__remove(fstack, &browser->hists->dso_filter);
959zoom_out_dso: 1014zoom_out_dso:
960 ui_helpline__pop(); 1015 ui_helpline__pop();
961 dso_filter = NULL; 1016 browser->hists->dso_filter = NULL;
1017 sort_dso.elide = false;
962 } else { 1018 } else {
963 if (dso == NULL) 1019 if (dso == NULL)
964 continue; 1020 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1021 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1022 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1023 browser->hists->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1024 sort_dso.elide = true;
1025 pstack__push(fstack, &browser->hists->dso_filter);
969 } 1026 }
970 hists__filter_by_dso(self, dso_filter); 1027 hists__filter_by_dso(self);
971 hists__browser_title(self, msg, sizeof(msg), ev_name,
972 dso_filter, thread_filter);
973 hist_browser__reset(browser); 1028 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1029 } else if (choice == zoom_thread) {
975zoom_thread: 1030zoom_thread:
976 if (thread_filter) { 1031 if (browser->hists->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1032 pstack__remove(fstack, &browser->hists->thread_filter);
978zoom_out_thread: 1033zoom_out_thread:
979 ui_helpline__pop(); 1034 ui_helpline__pop();
980 thread_filter = NULL; 1035 browser->hists->thread_filter = NULL;
1036 sort_thread.elide = false;
981 } else { 1037 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1038 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1039 thread->comm_set ? thread->comm : "",
984 thread->pid); 1040 thread->pid);
985 thread_filter = thread; 1041 browser->hists->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1042 sort_thread.elide = true;
1043 pstack__push(fstack, &browser->hists->thread_filter);
987 } 1044 }
988 hists__filter_by_thread(self, thread_filter); 1045 hists__filter_by_thread(self);
989 hists__browser_title(self, msg, sizeof(msg), ev_name,
990 dso_filter, thread_filter);
991 hist_browser__reset(browser); 1046 hist_browser__reset(browser);
992 } 1047 }
993 } 1048 }
@@ -1026,9 +1081,10 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1026 menu->selection = evsel; 1081 menu->selection = evsel;
1027} 1082}
1028 1083
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1084static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1085 int nr_events, const char *help,
1086 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1087{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv; 1088 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1089 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1090 const char *ev_name, *title = "Available samples";
@@ -1038,50 +1094,65 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1094 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1095 return -1;
1040 1096
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) { 1097 while (1) {
1044 key = ui_browser__run(&menu->b); 1098 key = ui_browser__run(&menu->b, delay_secs);
1045 1099
1046 switch (key) { 1100 switch (key) {
1047 case NEWT_KEY_RIGHT: 1101 case K_TIMER:
1048 case NEWT_KEY_ENTER: 1102 timer(arg);
1103 continue;
1104 case K_RIGHT:
1105 case K_ENTER:
1049 if (!menu->selection) 1106 if (!menu->selection)
1050 continue; 1107 continue;
1051 pos = menu->selection; 1108 pos = menu->selection;
1052browse_hists: 1109browse_hists:
1110 perf_evlist__set_selected(evlist, pos);
1111 /*
1112 * Give the calling tool a chance to populate the non
1113 * default evsel resorted hists tree.
1114 */
1115 if (timer)
1116 timer(arg);
1053 ev_name = event_name(pos); 1117 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1118 key = perf_evsel__hists_browse(pos, nr_events, help,
1119 ev_name, true, timer,
1120 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1121 ui_browser__show_title(&menu->b, title);
1056 break; 1122 switch (key) {
1057 case NEWT_KEY_LEFT: 1123 case K_TAB:
1124 if (pos->node.next == &evlist->entries)
1125 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1126 else
1127 pos = list_entry(pos->node.next, struct perf_evsel, node);
1128 goto browse_hists;
1129 case K_UNTAB:
1130 if (pos->node.prev == &evlist->entries)
1131 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1132 else
1133 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1134 goto browse_hists;
1135 case K_ESC:
1136 if (!ui__dialog_yesno("Do you really want to exit?"))
1137 continue;
1138 /* Fall thru */
1139 case 'q':
1140 case CTRL('c'):
1141 goto out;
1142 default:
1143 continue;
1144 }
1145 case K_LEFT:
1058 continue; 1146 continue;
1059 case NEWT_KEY_ESCAPE: 1147 case K_ESC:
1060 if (!ui__dialog_yesno("Do you really want to exit?")) 1148 if (!ui__dialog_yesno("Do you really want to exit?"))
1061 continue; 1149 continue;
1062 /* Fall thru */ 1150 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q': 1151 case 'q':
1081 case CTRL('c'): 1152 case CTRL('c'):
1082 goto out; 1153 goto out;
1083 default: 1154 default:
1084 break; 1155 continue;
1085 } 1156 }
1086 } 1157 }
1087 1158
@@ -1091,7 +1162,9 @@ out:
1091} 1162}
1092 1163
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1164static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1165 const char *help,
1166 void(*timer)(void *arg), void *arg,
1167 int delay_secs)
1095{ 1168{
1096 struct perf_evsel *pos; 1169 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1170 struct perf_evsel_menu menu = {
@@ -1121,18 +1194,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1194 pos->name = strdup(ev_name);
1122 } 1195 }
1123 1196
1124 return perf_evsel_menu__run(&menu, help); 1197 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1198 arg, delay_secs);
1125} 1199}
1126 1200
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1201int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1202 void(*timer)(void *arg), void *arg,
1203 int delay_secs)
1128{ 1204{
1129 1205
1130 if (evlist->nr_entries == 1) { 1206 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1207 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1208 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1209 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1210 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1211 ev_name, false, timer, arg,
1212 delay_secs);
1135 } 1213 }
1136 1214
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1215 return __perf_evlist__tui_browse_hists(evlist, help,
1216 timer, arg, delay_secs);
1138} 1217}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 8462bffe20bc..6905bcc8be2d 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
3#include <inttypes.h> 4#include <inttypes.h>
4#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
5#include <ctype.h> 6#include <ctype.h>
@@ -108,11 +109,8 @@ static int map_browser__run(struct map_browser *self)
108 verbose ? "" : "restart with -v to use") < 0) 109 verbose ? "" : "restart with -v to use") < 0)
109 return -1; 110 return -1;
110 111
111 if (verbose)
112 ui_browser__add_exit_key(&self->b, '/');
113
114 while (1) { 112 while (1) {
115 key = ui_browser__run(&self->b); 113 key = ui_browser__run(&self->b, 0);
116 114
117 if (verbose && key == '/') 115 if (verbose && key == '/')
118 map_browser__search(self); 116 map_browser__search(self);
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index 88403cf8396a..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,212 +0,0 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 return perf_top_browser__run(&browser);
212}
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
index ab6028d0c401..fdcbc0270acd 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/util/ui/helpline.h
@@ -1,6 +1,9 @@
1#ifndef _PERF_UI_HELPLINE_H_ 1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1 2#define _PERF_UI_HELPLINE_H_ 1
3 3
4#include <stdio.h>
5#include <stdarg.h>
6
4void ui_helpline__init(void); 7void ui_helpline__init(void);
5void ui_helpline__pop(void); 8void ui_helpline__pop(void);
6void ui_helpline__push(const char *msg); 9void ui_helpline__push(const char *msg);
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
new file mode 100644
index 000000000000..3458b1985761
--- /dev/null
+++ b/tools/perf/util/ui/keysyms.h
@@ -0,0 +1,25 @@
1#ifndef _PERF_KEYSYMS_H_
2#define _PERF_KEYSYMS_H_ 1
3
4#include "libslang.h"
5
6#define K_DOWN SL_KEY_DOWN
7#define K_END SL_KEY_END
8#define K_ENTER '\r'
9#define K_ESC 033
10#define K_F1 SL_KEY_F(1)
11#define K_HOME SL_KEY_HOME
12#define K_LEFT SL_KEY_LEFT
13#define K_PGDN SL_KEY_NPAGE
14#define K_PGUP SL_KEY_PPAGE
15#define K_RIGHT SL_KEY_RIGHT
16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP
19
20/* Not really keys */
21#define K_TIMER -1
22#define K_ERROR -2
23#define K_RESIZE -3
24
25#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 2b63e1c9b181..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -24,4 +24,6 @@
24#define sltt_set_color SLtt_set_color 24#define sltt_set_color SLtt_set_color
25#endif 25#endif
26 26
27#define SL_KEY_UNTAB 0x1000
28
27#endif /* _PERF_UI_SLANG_H_ */ 29#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index ee46d671db59..1e6ba06980c4 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -7,6 +7,7 @@
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h" 9#include "ui.h"
10#include "libslang.h"
10 11
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 12pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
12 13
@@ -17,6 +18,33 @@ static void newt_suspend(void *d __used)
17 newtResume(); 18 newtResume();
18} 19}
19 20
21static int ui__init(void)
22{
23 int err = SLkp_init();
24
25 if (err < 0)
26 goto out;
27
28 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
29out:
30 return err;
31}
32
33static void ui__exit(void)
34{
35 SLtt_set_cursor_visibility(1);
36 SLsmg_refresh();
37 SLsmg_reset_smg();
38 SLang_reset_tty();
39}
40
41static void ui__signal(int sig)
42{
43 ui__exit();
44 psignal(sig, "perf");
45 exit(0);
46}
47
20void setup_browser(bool fallback_to_pager) 48void setup_browser(bool fallback_to_pager)
21{ 49{
22 if (!isatty(1) || !use_browser || dump_trace) { 50 if (!isatty(1) || !use_browser || dump_trace) {
@@ -28,10 +56,16 @@ void setup_browser(bool fallback_to_pager)
28 56
29 use_browser = 1; 57 use_browser = 1;
30 newtInit(); 58 newtInit();
31 newtCls(); 59 ui__init();
32 newtSetSuspendCallback(newt_suspend, NULL); 60 newtSetSuspendCallback(newt_suspend, NULL);
33 ui_helpline__init(); 61 ui_helpline__init();
34 ui_browser__init(); 62 ui_browser__init();
63
64 signal(SIGSEGV, ui__signal);
65 signal(SIGFPE, ui__signal);
66 signal(SIGINT, ui__signal);
67 signal(SIGQUIT, ui__signal);
68 signal(SIGTERM, ui__signal);
35} 69}
36 70
37void exit_browser(bool wait_for_ok) 71void exit_browser(bool wait_for_ok)
@@ -41,6 +75,6 @@ void exit_browser(bool wait_for_ok)
41 char title[] = "Fatal Error", ok[] = "Ok"; 75 char title[] = "Fatal Error", ok[] = "Ok";
42 newtWinMessage(title, ok, ui_helpline__last_msg); 76 newtWinMessage(title, ok, ui_helpline__last_msg);
43 } 77 }
44 newtFinished(); 78 ui__exit();
45 } 79 }
46} 80}