aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-10-10 01:10:05 -0400
committerIngo Molnar <mingo@elte.hu>2011-10-10 01:10:05 -0400
commit7588badafcd762034aa962ec86b82cacd4f42f74 (patch)
tree3fbfeb46f771e73e4269d655c24212b488916f6a
parentd48b0e173715f678698d3678fefd40f2893ce798 (diff)
parent64c6f0c7f8db449e05ee16e35a7083df69addd1d (diff)
Merge branch 'perf/core' of git://github.com/acmel/linux into perf/core
-rw-r--r--tools/perf/Documentation/perf-annotate.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt17
-rw-r--r--tools/perf/Documentation/perf-script.txt7
-rw-r--r--tools/perf/Documentation/perf-top.txt48
-rw-r--r--tools/perf/Makefile4
-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.c13
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-record.c15
-rw-r--r--tools/perf/builtin-report.c21
-rw-r--r--tools/perf/builtin-script.c6
-rw-r--r--tools/perf/builtin-top.c437
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.h11
-rw-r--r--tools/perf/util/annotate.h7
-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.c1145
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/hist.c340
-rw-r--r--tools/perf/util/hist.h33
-rw-r--r--tools/perf/util/session.c19
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/symbol.c1
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h36
-rw-r--r--tools/perf/util/ui/browsers/annotate.c99
-rw-r--r--tools/perf/util/ui/browsers/hists.c146
-rw-r--r--tools/perf/util/ui/browsers/top.c236
35 files changed, 2124 insertions, 804 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 0102d83600db..fe6762ed56bd 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -73,8 +73,7 @@ OPTIONS
73 CPUs. 73 CPUs.
74 74
75--asm-raw:: 75--asm-raw::
76 Show raw instruction encoding of assembly instructions. They 76 Show raw instruction encoding of assembly instructions.
77 are displayed by default, disable with --no-asm-raw.
78 77
79--source:: 78--source::
80 Interleave source code with assembly code. Enabled by default, 79 Interleave source code with assembly code. Enabled by default,
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 6349b6c0e3ec..212f24d672e1 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -137,6 +137,21 @@ OPTIONS
137-M:: 137-M::
138--disassembler-style=:: Set disassembler style for objdump. 138--disassembler-style=:: Set disassembler style for objdump.
139 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
140SEE ALSO 155SEE ALSO
141-------- 156--------
142linkperf:perf-stat[1] 157linkperf:perf-stat[1], linkperf:perf-annotate[1]
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-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/Makefile b/tools/perf/Makefile
index e9d5c271db69..37fe93019bc6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -466,7 +466,6 @@ 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
@@ -729,9 +728,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 728$(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 $< 729 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
731 730
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 731$(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 $< 732 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
737 733
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 cf68819f7453..3ea764a78053 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -114,7 +114,8 @@ 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 = KEY_RIGHT;
@@ -137,7 +138,8 @@ 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 KEY_RIGHT:
143 next = rb_next(nd); 145 next = rb_next(nd);
@@ -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
@@ -269,9 +272,9 @@ static const struct option options[] = {
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"),
270 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
271 "Look for files with symbols relative to this directory"), 274 "Look for files with symbols relative to this directory"),
272 OPT_BOOLEAN('0', "source", &symbol_conf.annotate_src, 275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
273 "Interleave source code with assembly code (default)"), 276 "Interleave source code with assembly code (default)"),
274 OPT_BOOLEAN('0', "asm-raw", &symbol_conf.annotate_asm_raw, 277 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
275 "Display raw encoding of assembly instructions (default)"), 278 "Display raw encoding of assembly instructions (default)"),
276 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
277 "Specify disassembler style (e.g. -M intel for intel syntax)"), 280 "Specify disassembler style (e.g. -M intel for intel syntax)"),
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 dd6467872f60..f82480fa7f27 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -529,6 +529,19 @@ static int __cmd_record(int argc, const char **argv)
529 if (have_tracepoints(&evsel_list->entries)) 529 if (have_tracepoints(&evsel_list->entries))
530 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 530 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
531 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
532 /* 512 kiB: default amount of unprivileged mlocked memory */ 545 /* 512 kiB: default amount of unprivileged mlocked memory */
533 if (mmap_pages == UINT_MAX) 546 if (mmap_pages == UINT_MAX)
534 mmap_pages = (512 * 1024) / page_size; 547 mmap_pages = (512 * 1024) / page_size;
@@ -800,6 +813,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
800 int err = -ENOMEM; 813 int err = -ENOMEM;
801 struct perf_evsel *pos; 814 struct perf_evsel *pos;
802 815
816 perf_header__set_cmdline(argc, argv);
817
803 evsel_list = perf_evlist__new(NULL, NULL); 818 evsel_list = perf_evlist__new(NULL, NULL);
804 if (evsel_list == NULL) 819 if (evsel_list == NULL)
805 return -ENOMEM; 820 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3d58334909a5..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;
@@ -232,7 +233,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
232 const char *evname = event_name(pos); 233 const char *evname = event_name(pos);
233 234
234 hists__fprintf_nr_sample_events(hists, evname, stdout); 235 hists__fprintf_nr_sample_events(hists, evname, stdout);
235 hists__fprintf(hists, NULL, false, stdout); 236 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
236 fprintf(stdout, "\n\n"); 237 fprintf(stdout, "\n\n");
237 } 238 }
238 239
@@ -273,6 +274,9 @@ static int __cmd_report(void)
273 goto out_delete; 274 goto out_delete;
274 } 275 }
275 276
277 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info);
279
276 if (show_threads) 280 if (show_threads)
277 perf_read_values_init(&show_threads_values); 281 perf_read_values_init(&show_threads_values);
278 282
@@ -327,9 +331,10 @@ static int __cmd_report(void)
327 goto out_delete; 331 goto out_delete;
328 } 332 }
329 333
330 if (use_browser > 0) 334 if (use_browser > 0) {
331 perf_evlist__tui_browse_hists(session->evlist, help); 335 perf_evlist__tui_browse_hists(session->evlist, help,
332 else 336 NULL, NULL, 0);
337 } else
333 perf_evlist__tty_browse_hists(session->evlist, help); 338 perf_evlist__tty_browse_hists(session->evlist, help);
334 339
335out_delete: 340out_delete:
@@ -484,8 +489,16 @@ static const struct option options[] = {
484 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
485 "Look for files with symbols relative to this directory"), 490 "Look for files with symbols relative to this directory"),
486 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)"),
487 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 498 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
488 "Specify disassembler style (e.g. -M intel for intel syntax)"), 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"),
489 OPT_END() 502 OPT_END()
490}; 503};
491 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-top.c b/tools/perf/builtin-top.c
index 5ede7d7c9239..c5aebf6eb746 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(void) 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
@@ -276,6 +294,7 @@ static void print_sym_table(void)
276 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 294 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
277 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 295 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
278 top.total_lost_warned); 296 top.total_lost_warned);
297 ++printed;
279 } 298 }
280 299
281 if (top.sym_filter_entry) { 300 if (top.sym_filter_entry) {
@@ -283,58 +302,13 @@ static void print_sym_table(void)
283 return; 302 return;
284 } 303 }
285 304
286 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 305 hists__collapse_resort_threaded(&top.sym_evsel->hists);
287 &sym_width); 306 hists__output_resort_threaded(&top.sym_evsel->hists);
288 307 hists__decay_entries(&top.sym_evsel->hists);
289 if (sym_width + dso_width > winsize.ws_col - 29) { 308 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3);
290 dso_width = dso_short_width;
291 if (sym_width + dso_width > winsize.ws_col - 29)
292 sym_width = winsize.ws_col - dso_width - 29;
293 }
294 putchar('\n'); 309 putchar('\n');
295 if (top.evlist->nr_entries == 1) 310 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
296 printf(" samples pcnt"); 311 winsize.ws_row - 4 - printed, win_width, stdout);
297 else
298 printf(" weight samples pcnt");
299
300 if (verbose)
301 printf(" RIP ");
302 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
303 printf(" %s _______ _____",
304 top.evlist->nr_entries == 1 ? " " : "______");
305 if (verbose)
306 printf(" ________________");
307 printf(" %-*.*s", sym_width, sym_width, graph_line);
308 printf(" %-*.*s", dso_width, dso_width, graph_line);
309 puts("\n");
310
311 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
312 struct symbol *sym;
313 double pcnt;
314
315 syme = rb_entry(nd, struct sym_entry, rb_node);
316 sym = sym_entry__symbol(syme);
317 if (++printed > top.print_entries ||
318 (int)syme->snap_count < top.count_filter)
319 continue;
320
321 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
322 sum_ksamples));
323
324 if (top.evlist->nr_entries == 1 || !top.display_weighted)
325 printf("%20.2f ", syme->weight);
326 else
327 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
328
329 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
330 if (verbose)
331 printf(" %016" PRIx64, sym->start);
332 printf(" %-*.*s", sym_width, sym_width, sym->name);
333 printf(" %-*.*s\n", dso_width, dso_width,
334 dso_width >= syme->map->dso->long_name_len ?
335 syme->map->dso->long_name :
336 syme->map->dso->short_name);
337 }
338} 312}
339 313
340static void prompt_integer(int *target, const char *msg) 314static void prompt_integer(int *target, const char *msg)
@@ -372,10 +346,11 @@ static void prompt_percent(int *target, const char *msg)
372 *target = tmp; 346 *target = tmp;
373} 347}
374 348
375static void prompt_symbol(struct sym_entry **target, const char *msg) 349static void prompt_symbol(struct hist_entry **target, const char *msg)
376{ 350{
377 char *buf = malloc(0), *p; 351 char *buf = malloc(0), *p;
378 struct sym_entry *syme = *target, *n, *found = NULL; 352 struct hist_entry *syme = *target, *n, *found = NULL;
353 struct rb_node *next;
379 size_t dummy = 0; 354 size_t dummy = 0;
380 355
381 /* zero counters of active symbol */ 356 /* zero counters of active symbol */
@@ -392,17 +367,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
392 if (p) 367 if (p)
393 *p = 0; 368 *p = 0;
394 369
395 pthread_mutex_lock(&top.active_symbols_lock); 370 next = rb_first(&top.sym_evsel->hists.entries);
396 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 371 while (next) {
397 pthread_mutex_unlock(&top.active_symbols_lock); 372 n = rb_entry(next, struct hist_entry, rb_node);
398 373 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
399 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 374 found = n;
400 struct symbol *sym = sym_entry__symbol(syme);
401
402 if (!strcmp(buf, sym->name)) {
403 found = syme;
404 break; 375 break;
405 } 376 }
377 next = rb_next(&n->rb_node);
406 } 378 }
407 379
408 if (!found) { 380 if (!found) {
@@ -421,7 +393,7 @@ static void print_mapped_keys(void)
421 char *name = NULL; 393 char *name = NULL;
422 394
423 if (top.sym_filter_entry) { 395 if (top.sym_filter_entry) {
424 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 396 struct symbol *sym = top.sym_filter_entry->ms.sym;
425 name = sym->name; 397 name = sym->name;
426 } 398 }
427 399
@@ -438,9 +410,6 @@ static void print_mapped_keys(void)
438 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 410 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
439 fprintf(stdout, "\t[S] stop annotation.\n"); 411 fprintf(stdout, "\t[S] stop annotation.\n");
440 412
441 if (top.evlist->nr_entries > 1)
442 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
443
444 fprintf(stdout, 413 fprintf(stdout,
445 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 414 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
446 top.hide_kernel_symbols ? "yes" : "no"); 415 top.hide_kernel_symbols ? "yes" : "no");
@@ -467,8 +436,6 @@ static int key_mapped(int c)
467 case 'S': 436 case 'S':
468 return 1; 437 return 1;
469 case 'E': 438 case 'E':
470 case 'w':
471 return top.evlist->nr_entries > 1 ? 1 : 0;
472 default: 439 default:
473 break; 440 break;
474 } 441 }
@@ -561,7 +528,7 @@ static void handle_keypress(int c)
561 if (!top.sym_filter_entry) 528 if (!top.sym_filter_entry)
562 break; 529 break;
563 else { 530 else {
564 struct sym_entry *syme = top.sym_filter_entry; 531 struct hist_entry *syme = top.sym_filter_entry;
565 532
566 top.sym_filter_entry = NULL; 533 top.sym_filter_entry = NULL;
567 __zero_source_counters(syme); 534 __zero_source_counters(syme);
@@ -570,9 +537,6 @@ static void handle_keypress(int c)
570 case 'U': 537 case 'U':
571 top.hide_user_symbols = !top.hide_user_symbols; 538 top.hide_user_symbols = !top.hide_user_symbols;
572 break; 539 break;
573 case 'w':
574 top.display_weighted = ~top.display_weighted;
575 break;
576 case 'z': 540 case 'z':
577 top.zero = !top.zero; 541 top.zero = !top.zero;
578 break; 542 break;
@@ -581,19 +545,29 @@ static void handle_keypress(int c)
581 } 545 }
582} 546}
583 547
548static void perf_top__sort_new_samples(void *arg)
549{
550 struct perf_top *t = arg;
551 perf_top__reset_sample_counters(t);
552
553 if (t->evlist->selected != NULL)
554 t->sym_evsel = t->evlist->selected;
555
556 hists__collapse_resort_threaded(&t->sym_evsel->hists);
557 hists__output_resort_threaded(&t->sym_evsel->hists);
558 hists__decay_entries(&t->sym_evsel->hists);
559 hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3);
560}
561
584static void *display_thread_tui(void *arg __used) 562static void *display_thread_tui(void *arg __used)
585{ 563{
586 int err = 0; 564 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
587 pthread_mutex_lock(&top.active_symbols_lock); 565
588 while (list_empty(&top.active_symbols)) { 566 perf_top__sort_new_samples(&top);
589 err = pthread_cond_wait(&top.active_symbols_cond, 567 perf_evlist__tui_browse_hists(top.evlist, help,
590 &top.active_symbols_lock); 568 perf_top__sort_new_samples,
591 if (err) 569 &top, top.delay_secs);
592 break; 570
593 }
594 pthread_mutex_unlock(&top.active_symbols_lock);
595 if (!err)
596 perf_top__tui_browser(&top);
597 exit_browser(0); 571 exit_browser(0);
598 exit(0); 572 exit(0);
599 return NULL; 573 return NULL;
@@ -645,9 +619,8 @@ static const char *skip_symbols[] = {
645 NULL 619 NULL
646}; 620};
647 621
648static int symbol_filter(struct map *map, struct symbol *sym) 622static int symbol_filter(struct map *map __used, struct symbol *sym)
649{ 623{
650 struct sym_entry *syme;
651 const char *name = sym->name; 624 const char *name = sym->name;
652 int i; 625 int i;
653 626
@@ -667,16 +640,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
667 strstr(name, "_text_end")) 640 strstr(name, "_text_end"))
668 return 1; 641 return 1;
669 642
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++) { 643 for (i = 0; skip_symbols[i]; i++) {
681 if (!strcmp(skip_symbols[i], name)) { 644 if (!strcmp(skip_symbols[i], name)) {
682 sym->ignore = true; 645 sym->ignore = true;
@@ -691,10 +654,11 @@ static void perf_event__process_sample(const union perf_event *event,
691 struct perf_sample *sample, 654 struct perf_sample *sample,
692 struct perf_session *session) 655 struct perf_session *session)
693{ 656{
657 struct symbol *parent = NULL;
694 u64 ip = event->ip.ip; 658 u64 ip = event->ip.ip;
695 struct sym_entry *syme;
696 struct addr_location al; 659 struct addr_location al;
697 struct machine *machine; 660 struct machine *machine;
661 int err;
698 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 662 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
699 663
700 ++top.samples; 664 ++top.samples;
@@ -783,46 +747,41 @@ static void perf_event__process_sample(const union perf_event *event,
783 sleep(5); 747 sleep(5);
784 vmlinux_warned = true; 748 vmlinux_warned = true;
785 } 749 }
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 } 750 }
806 751
807 syme = symbol__priv(al.sym); 752 if (al.sym == NULL || !al.sym->ignore) {
808 if (!al.sym->ignore) {
809 struct perf_evsel *evsel; 753 struct perf_evsel *evsel;
754 struct hist_entry *he;
810 755
811 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 756 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
812 assert(evsel != NULL); 757 assert(evsel != NULL);
813 syme->count[evsel->idx]++; 758
814 record_precise_ip(syme, al.map, evsel->idx, ip); 759 if ((sort__has_parent || symbol_conf.use_callchain) &&
815 pthread_mutex_lock(&top.active_symbols_lock); 760 sample->callchain) {
816 if (list_empty(&syme->node) || !syme->node.next) { 761 err = perf_session__resolve_callchain(session, al.thread,
817 static bool first = true; 762 sample->callchain, &parent);
818 __list_insert_active_sym(syme); 763 if (err)
819 if (first) { 764 return;
820 pthread_cond_broadcast(&top.active_symbols_cond);
821 first = false;
822 }
823 } 765 }
824 pthread_mutex_unlock(&top.active_symbols_lock); 766
767 he = perf_session__add_hist_entry(session, &al, sample, evsel);
768 if (he == NULL) {
769 pr_err("Problem incrementing symbol period, skipping event\n");
770 return;
771 }
772
773 if (symbol_conf.use_callchain) {
774 err = callchain_append(he->callchain, &session->callchain_cursor,
775 sample->period);
776 if (err)
777 return;
778 }
779
780 if (sort_has_symbols)
781 record_precise_ip(he, evsel->idx, ip);
825 } 782 }
783
784 return;
826} 785}
827 786
828static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 787static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
@@ -873,7 +832,11 @@ static void start_counters(struct perf_evlist *evlist)
873 attr->read_format |= PERF_FORMAT_ID; 832 attr->read_format |= PERF_FORMAT_ID;
874 } 833 }
875 834
835 if (symbol_conf.use_callchain)
836 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
837
876 attr->mmap = 1; 838 attr->mmap = 1;
839 attr->comm = 1;
877 attr->inherit = inherit; 840 attr->inherit = inherit;
878try_again: 841try_again:
879 if (perf_evsel__open(counter, top.evlist->cpus, 842 if (perf_evsel__open(counter, top.evlist->cpus,
@@ -928,10 +891,27 @@ out_err:
928 exit(0); 891 exit(0);
929} 892}
930 893
894static int setup_sample_type(void)
895{
896 if (!sort_has_symbols) {
897 if (symbol_conf.use_callchain) {
898 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
899 return -EINVAL;
900 }
901 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
902 if (callchain_register_param(&callchain_param) < 0) {
903 ui__warning("Can't register callchain params.\n");
904 return -EINVAL;
905 }
906 }
907
908 return 0;
909}
910
931static int __cmd_top(void) 911static int __cmd_top(void)
932{ 912{
933 pthread_t thread; 913 pthread_t thread;
934 int ret __used; 914 int ret;
935 /* 915 /*
936 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 916 * 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. 917 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -940,6 +920,10 @@ static int __cmd_top(void)
940 if (top.session == NULL) 920 if (top.session == NULL)
941 return -ENOMEM; 921 return -ENOMEM;
942 922
923 ret = setup_sample_type();
924 if (ret)
925 goto out_delete;
926
943 if (top.target_tid != -1) 927 if (top.target_tid != -1)
944 perf_event__synthesize_thread_map(top.evlist->threads, 928 perf_event__synthesize_thread_map(top.evlist->threads,
945 perf_event__process, top.session); 929 perf_event__process, top.session);
@@ -980,6 +964,90 @@ static int __cmd_top(void)
980 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 964 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
981 } 965 }
982 966
967out_delete:
968 perf_session__delete(top.session);
969 top.session = NULL;
970
971 return 0;
972}
973
974static int
975parse_callchain_opt(const struct option *opt __used, const char *arg,
976 int unset)
977{
978 char *tok, *tok2;
979 char *endptr;
980
981 /*
982 * --no-call-graph
983 */
984 if (unset) {
985 dont_use_callchains = true;
986 return 0;
987 }
988
989 symbol_conf.use_callchain = true;
990
991 if (!arg)
992 return 0;
993
994 tok = strtok((char *)arg, ",");
995 if (!tok)
996 return -1;
997
998 /* get the output mode */
999 if (!strncmp(tok, "graph", strlen(arg)))
1000 callchain_param.mode = CHAIN_GRAPH_ABS;
1001
1002 else if (!strncmp(tok, "flat", strlen(arg)))
1003 callchain_param.mode = CHAIN_FLAT;
1004
1005 else if (!strncmp(tok, "fractal", strlen(arg)))
1006 callchain_param.mode = CHAIN_GRAPH_REL;
1007
1008 else if (!strncmp(tok, "none", strlen(arg))) {
1009 callchain_param.mode = CHAIN_NONE;
1010 symbol_conf.use_callchain = false;
1011
1012 return 0;
1013 }
1014
1015 else
1016 return -1;
1017
1018 /* get the min percentage */
1019 tok = strtok(NULL, ",");
1020 if (!tok)
1021 goto setup;
1022
1023 callchain_param.min_percent = strtod(tok, &endptr);
1024 if (tok == endptr)
1025 return -1;
1026
1027 /* get the print limit */
1028 tok2 = strtok(NULL, ",");
1029 if (!tok2)
1030 goto setup;
1031
1032 if (tok2[0] != 'c') {
1033 callchain_param.print_limit = strtod(tok2, &endptr);
1034 tok2 = strtok(NULL, ",");
1035 if (!tok2)
1036 goto setup;
1037 }
1038
1039 /* get the call chain order */
1040 if (!strcmp(tok2, "caller"))
1041 callchain_param.order = ORDER_CALLER;
1042 else if (!strcmp(tok2, "callee"))
1043 callchain_param.order = ORDER_CALLEE;
1044 else
1045 return -1;
1046setup:
1047 if (callchain_register_param(&callchain_param) < 0) {
1048 fprintf(stderr, "Can't register callchain params\n");
1049 return -1;
1050 }
983 return 0; 1051 return 0;
984} 1052}
985 1053
@@ -1019,7 +1087,7 @@ static const struct option options[] = {
1019 "put the counters into a counter group"), 1087 "put the counters into a counter group"),
1020 OPT_BOOLEAN('i', "inherit", &inherit, 1088 OPT_BOOLEAN('i', "inherit", &inherit,
1021 "child tasks inherit counters"), 1089 "child tasks inherit counters"),
1022 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1090 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1023 "symbol to annotate"), 1091 "symbol to annotate"),
1024 OPT_BOOLEAN('z', "zero", &top.zero, 1092 OPT_BOOLEAN('z', "zero", &top.zero,
1025 "zero history across updates"), 1093 "zero history across updates"),
@@ -1033,6 +1101,28 @@ static const struct option options[] = {
1033 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1101 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1034 OPT_INCR('v', "verbose", &verbose, 1102 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 1103 "be more verbose (show counter open errors, etc)"),
1104 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1105 "sort by key(s): pid, comm, dso, symbol, parent"),
1106 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1107 "Show a column with the number of samples"),
1108 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1109 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1110 "Default: fractal,0.5,callee", &parse_callchain_opt,
1111 callchain_default_opt),
1112 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1113 "Show a column with the sum of periods"),
1114 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1115 "only consider symbols in these dsos"),
1116 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1117 "only consider symbols in these comms"),
1118 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1119 "only consider these symbols"),
1120 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1121 "Interleave source code with assembly code (default)"),
1122 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1123 "Display raw encoding of assembly instructions (default)"),
1124 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1125 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1036 OPT_END() 1126 OPT_END()
1037}; 1127};
1038 1128
@@ -1045,18 +1135,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1045 if (top.evlist == NULL) 1135 if (top.evlist == NULL)
1046 return -ENOMEM; 1136 return -ENOMEM;
1047 1137
1048 page_size = sysconf(_SC_PAGE_SIZE); 1138 symbol_conf.exclude_other = false;
1049 1139
1050 argc = parse_options(argc, argv, options, top_usage, 0); 1140 argc = parse_options(argc, argv, options, top_usage, 0);
1051 if (argc) 1141 if (argc)
1052 usage_with_options(top_usage, options); 1142 usage_with_options(top_usage, options);
1053 1143
1054 /* 1144 if (sort_order == default_sort_order)
1055 * XXX For now start disabled, only using TUI if explicitely asked for. 1145 sort_order = "dso,symbol";
1056 * Change that when handle_keys equivalent gets written, live annotation 1146
1057 * done, etc. 1147 setup_sorting(top_usage, options);
1058 */
1059 use_browser = 0;
1060 1148
1061 if (use_stdio) 1149 if (use_stdio)
1062 use_browser = 0; 1150 use_browser = 0;
@@ -1119,13 +1207,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1119 1207
1120 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1208 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1121 1209
1122 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1210 symbol_conf.priv_size = sizeof(struct annotation);
1123 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1124 1211
1125 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1212 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1126 if (symbol__init() < 0) 1213 if (symbol__init() < 0)
1127 return -1; 1214 return -1;
1128 1215
1216 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1217 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1218 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1219
1220 /*
1221 * Avoid annotation data structures overhead when symbols aren't on the
1222 * sort list.
1223 */
1224 sort_has_symbols = sort_sym.list.next != NULL;
1225
1129 get_term_dimensions(&winsize); 1226 get_term_dimensions(&winsize);
1130 if (top.print_entries == 0) { 1227 if (top.print_entries == 0) {
1131 update_print_entries(&winsize); 1228 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.h b/tools/perf/perf.h
index a5fc660c1f12..08b0b5e82a44 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,6 @@ 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[];
174 185
175#endif 186#endif
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 6ede1286ee71..d9072523d342 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -91,13 +91,16 @@ 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
103extern const char *disassembler_style; 106extern const char *disassembler_style;
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..f2ceb0f7d669 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) \
@@ -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 }
@@ -796,7 +1878,7 @@ out:
796 1878
797static int perf_file_section__process(struct perf_file_section *section, 1879static int perf_file_section__process(struct perf_file_section *section,
798 struct perf_header *ph, 1880 struct perf_header *ph,
799 int feat, int fd) 1881 int feat, int fd, void *data __used)
800{ 1882{
801 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 1883 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
802 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 1884 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -935,7 +2017,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); 2017 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
936 } 2018 }
937 2019
938 perf_header__process_sections(header, fd, perf_file_section__process); 2020 perf_header__process_sections(header, fd, NULL,
2021 perf_file_section__process);
939 2022
940 lseek(fd, header->data_offset, SEEK_SET); 2023 lseek(fd, header->data_offset, SEEK_SET);
941 2024
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..50c8fece1681 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -18,56 +18,56 @@ struct callchain_param callchain_param = {
18 .order = ORDER_CALLEE 18 .order = ORDER_CALLEE
19}; 19};
20 20
21u16 hists__col_len(struct hists *self, enum hist_column col) 21u16 hists__col_len(struct hists *hists, enum hist_column col)
22{ 22{
23 return self->col_len[col]; 23 return hists->col_len[col];
24} 24}
25 25
26void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) 26void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
27{ 27{
28 self->col_len[col] = len; 28 hists->col_len[col] = len;
29} 29}
30 30
31bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) 31bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
32{ 32{
33 if (len > hists__col_len(self, col)) { 33 if (len > hists__col_len(hists, col)) {
34 hists__set_col_len(self, col, len); 34 hists__set_col_len(hists, col, len);
35 return true; 35 return true;
36 } 36 }
37 return false; 37 return false;
38} 38}
39 39
40static void hists__reset_col_len(struct hists *self) 40static void hists__reset_col_len(struct hists *hists)
41{ 41{
42 enum hist_column col; 42 enum hist_column col;
43 43
44 for (col = 0; col < HISTC_NR_COLS; ++col) 44 for (col = 0; col < HISTC_NR_COLS; ++col)
45 hists__set_col_len(self, col, 0); 45 hists__set_col_len(hists, col, 0);
46} 46}
47 47
48static void hists__calc_col_len(struct hists *self, struct hist_entry *h) 48static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
49{ 49{
50 u16 len; 50 u16 len;
51 51
52 if (h->ms.sym) 52 if (h->ms.sym)
53 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 53 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
54 else { 54 else {
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56 56
57 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width && 57 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list) 59 !symbol_conf.dso_list)
60 hists__set_col_len(self, HISTC_DSO, 60 hists__set_col_len(hists, HISTC_DSO,
61 unresolved_col_width); 61 unresolved_col_width);
62 } 62 }
63 63
64 len = thread__comm_len(h->thread); 64 len = thread__comm_len(h->thread);
65 if (hists__new_col_len(self, HISTC_COMM, len)) 65 if (hists__new_col_len(hists, HISTC_COMM, len))
66 hists__set_col_len(self, HISTC_THREAD, len + 6); 66 hists__set_col_len(hists, HISTC_THREAD, len + 6);
67 67
68 if (h->ms.map) { 68 if (h->ms.map) {
69 len = dso__name_len(h->ms.map->dso); 69 len = dso__name_len(h->ms.map->dso);
70 hists__new_col_len(self, HISTC_DSO, len); 70 hists__new_col_len(hists, HISTC_DSO, len);
71 } 71 }
72} 72}
73 73
@@ -92,6 +92,41 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
92 } 92 }
93} 93}
94 94
95static void hist_entry__decay(struct hist_entry *he)
96{
97 he->period = (he->period * 7) / 8;
98 he->nr_events = (he->nr_events * 7) / 8;
99}
100
101static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
102{
103 hists->stats.total_period -= he->period;
104 hist_entry__decay(he);
105 hists->stats.total_period += he->period;
106 return he->period == 0;
107}
108
109void hists__decay_entries(struct hists *hists)
110{
111 struct rb_node *next = rb_first(&hists->entries);
112 struct hist_entry *n;
113
114 while (next) {
115 n = rb_entry(next, struct hist_entry, rb_node);
116 next = rb_next(&n->rb_node);
117
118 if (hists__decay_entry(hists, n)) {
119 rb_erase(&n->rb_node, &hists->entries);
120
121 if (sort__need_collapse)
122 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
123
124 hist_entry__free(n);
125 --hists->nr_entries;
126 }
127 }
128}
129
95/* 130/*
96 * histogram, sorted on item, collects periods 131 * histogram, sorted on item, collects periods
97 */ 132 */
@@ -113,11 +148,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
113 return self; 148 return self;
114} 149}
115 150
116static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) 151static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
117{ 152{
118 if (!h->filtered) { 153 if (!h->filtered) {
119 hists__calc_col_len(self, h); 154 hists__calc_col_len(hists, h);
120 ++self->nr_entries; 155 ++hists->nr_entries;
156 hists->stats.total_period += h->period;
121 } 157 }
122} 158}
123 159
@@ -128,11 +164,11 @@ static u8 symbol__parent_filter(const struct symbol *parent)
128 return 0; 164 return 0;
129} 165}
130 166
131struct hist_entry *__hists__add_entry(struct hists *self, 167struct hist_entry *__hists__add_entry(struct hists *hists,
132 struct addr_location *al, 168 struct addr_location *al,
133 struct symbol *sym_parent, u64 period) 169 struct symbol *sym_parent, u64 period)
134{ 170{
135 struct rb_node **p = &self->entries.rb_node; 171 struct rb_node **p;
136 struct rb_node *parent = NULL; 172 struct rb_node *parent = NULL;
137 struct hist_entry *he; 173 struct hist_entry *he;
138 struct hist_entry entry = { 174 struct hist_entry entry = {
@@ -150,9 +186,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
150 }; 186 };
151 int cmp; 187 int cmp;
152 188
189 pthread_mutex_lock(&hists->lock);
190
191 p = &hists->entries_in->rb_node;
192
153 while (*p != NULL) { 193 while (*p != NULL) {
154 parent = *p; 194 parent = *p;
155 he = rb_entry(parent, struct hist_entry, rb_node); 195 he = rb_entry(parent, struct hist_entry, rb_node_in);
156 196
157 cmp = hist_entry__cmp(&entry, he); 197 cmp = hist_entry__cmp(&entry, he);
158 198
@@ -170,12 +210,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
170 210
171 he = hist_entry__new(&entry); 211 he = hist_entry__new(&entry);
172 if (!he) 212 if (!he)
173 return NULL; 213 goto out_unlock;
174 rb_link_node(&he->rb_node, parent, p); 214
175 rb_insert_color(&he->rb_node, &self->entries); 215 rb_link_node(&he->rb_node_in, parent, p);
176 hists__inc_nr_entries(self, he); 216 rb_insert_color(&he->rb_node_in, hists->entries_in);
177out: 217out:
178 hist_entry__add_cpumode_period(he, al->cpumode, period); 218 hist_entry__add_cpumode_period(he, al->cpumode, period);
219out_unlock:
220 pthread_mutex_unlock(&hists->lock);
179 return he; 221 return he;
180} 222}
181 223
@@ -222,7 +264,7 @@ void hist_entry__free(struct hist_entry *he)
222 * collapse the histogram 264 * collapse the histogram
223 */ 265 */
224 266
225static bool hists__collapse_insert_entry(struct hists *self, 267static bool hists__collapse_insert_entry(struct hists *hists,
226 struct rb_root *root, 268 struct rb_root *root,
227 struct hist_entry *he) 269 struct hist_entry *he)
228{ 270{
@@ -233,15 +275,16 @@ static bool hists__collapse_insert_entry(struct hists *self,
233 275
234 while (*p != NULL) { 276 while (*p != NULL) {
235 parent = *p; 277 parent = *p;
236 iter = rb_entry(parent, struct hist_entry, rb_node); 278 iter = rb_entry(parent, struct hist_entry, rb_node_in);
237 279
238 cmp = hist_entry__collapse(iter, he); 280 cmp = hist_entry__collapse(iter, he);
239 281
240 if (!cmp) { 282 if (!cmp) {
241 iter->period += he->period; 283 iter->period += he->period;
284 iter->nr_events += he->nr_events;
242 if (symbol_conf.use_callchain) { 285 if (symbol_conf.use_callchain) {
243 callchain_cursor_reset(&self->callchain_cursor); 286 callchain_cursor_reset(&hists->callchain_cursor);
244 callchain_merge(&self->callchain_cursor, iter->callchain, 287 callchain_merge(&hists->callchain_cursor, iter->callchain,
245 he->callchain); 288 he->callchain);
246 } 289 }
247 hist_entry__free(he); 290 hist_entry__free(he);
@@ -254,35 +297,57 @@ static bool hists__collapse_insert_entry(struct hists *self,
254 p = &(*p)->rb_right; 297 p = &(*p)->rb_right;
255 } 298 }
256 299
257 rb_link_node(&he->rb_node, parent, p); 300 rb_link_node(&he->rb_node_in, parent, p);
258 rb_insert_color(&he->rb_node, root); 301 rb_insert_color(&he->rb_node_in, root);
259 return true; 302 return true;
260} 303}
261 304
262void hists__collapse_resort(struct hists *self) 305static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
306{
307 struct rb_root *root;
308
309 pthread_mutex_lock(&hists->lock);
310
311 root = hists->entries_in;
312 if (++hists->entries_in > &hists->entries_in_array[1])
313 hists->entries_in = &hists->entries_in_array[0];
314
315 pthread_mutex_unlock(&hists->lock);
316
317 return root;
318}
319
320static void __hists__collapse_resort(struct hists *hists, bool threaded)
263{ 321{
264 struct rb_root tmp; 322 struct rb_root *root;
265 struct rb_node *next; 323 struct rb_node *next;
266 struct hist_entry *n; 324 struct hist_entry *n;
267 325
268 if (!sort__need_collapse) 326 if (!sort__need_collapse && !threaded)
269 return; 327 return;
270 328
271 tmp = RB_ROOT; 329 root = hists__get_rotate_entries_in(hists);
272 next = rb_first(&self->entries); 330 next = rb_first(root);
273 self->nr_entries = 0; 331 hists->stats.total_period = 0;
274 hists__reset_col_len(self);
275 332
276 while (next) { 333 while (next) {
277 n = rb_entry(next, struct hist_entry, rb_node); 334 n = rb_entry(next, struct hist_entry, rb_node_in);
278 next = rb_next(&n->rb_node); 335 next = rb_next(&n->rb_node_in);
279 336
280 rb_erase(&n->rb_node, &self->entries); 337 rb_erase(&n->rb_node_in, root);
281 if (hists__collapse_insert_entry(self, &tmp, n)) 338 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
282 hists__inc_nr_entries(self, n); 339 hists__inc_nr_entries(hists, n);
283 } 340 }
341}
284 342
285 self->entries = tmp; 343void hists__collapse_resort(struct hists *hists)
344{
345 return __hists__collapse_resort(hists, false);
346}
347
348void hists__collapse_resort_threaded(struct hists *hists)
349{
350 return __hists__collapse_resort(hists, true);
286} 351}
287 352
288/* 353/*
@@ -315,31 +380,43 @@ static void __hists__insert_output_entry(struct rb_root *entries,
315 rb_insert_color(&he->rb_node, entries); 380 rb_insert_color(&he->rb_node, entries);
316} 381}
317 382
318void hists__output_resort(struct hists *self) 383static void __hists__output_resort(struct hists *hists, bool threaded)
319{ 384{
320 struct rb_root tmp; 385 struct rb_root *root;
321 struct rb_node *next; 386 struct rb_node *next;
322 struct hist_entry *n; 387 struct hist_entry *n;
323 u64 min_callchain_hits; 388 u64 min_callchain_hits;
324 389
325 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); 390 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
391
392 if (sort__need_collapse || threaded)
393 root = &hists->entries_collapsed;
394 else
395 root = hists->entries_in;
326 396
327 tmp = RB_ROOT; 397 next = rb_first(root);
328 next = rb_first(&self->entries); 398 hists->entries = RB_ROOT;
329 399
330 self->nr_entries = 0; 400 hists->nr_entries = 0;
331 hists__reset_col_len(self); 401 hists__reset_col_len(hists);
332 402
333 while (next) { 403 while (next) {
334 n = rb_entry(next, struct hist_entry, rb_node); 404 n = rb_entry(next, struct hist_entry, rb_node_in);
335 next = rb_next(&n->rb_node); 405 next = rb_next(&n->rb_node_in);
336 406
337 rb_erase(&n->rb_node, &self->entries); 407 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
338 __hists__insert_output_entry(&tmp, n, min_callchain_hits); 408 hists__inc_nr_entries(hists, n);
339 hists__inc_nr_entries(self, n);
340 } 409 }
410}
411
412void hists__output_resort(struct hists *hists)
413{
414 return __hists__output_resort(hists, false);
415}
341 416
342 self->entries = tmp; 417void hists__output_resort_threaded(struct hists *hists)
418{
419 return __hists__output_resort(hists, true);
343} 420}
344 421
345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 422static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -594,6 +671,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
594 return ret; 671 return ret;
595} 672}
596 673
674void hists__output_recalc_col_len(struct hists *hists, int max_rows)
675{
676 struct rb_node *next = rb_first(&hists->entries);
677 struct hist_entry *n;
678 int row = 0;
679
680 hists__reset_col_len(hists);
681
682 while (next && row++ < max_rows) {
683 n = rb_entry(next, struct hist_entry, rb_node);
684 hists__calc_col_len(hists, n);
685 next = rb_next(&n->rb_node);
686 }
687}
688
597int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 689int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
598 struct hists *hists, struct hists *pair_hists, 690 struct hists *hists, struct hists *pair_hists,
599 bool show_displacement, long displacement, 691 bool show_displacement, long displacement,
@@ -664,6 +756,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); 756 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 } 757 }
666 758
759 if (symbol_conf.show_total_period) {
760 if (sep)
761 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
762 else
763 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
764 }
765
667 if (pair_hists) { 766 if (pair_hists) {
668 char bf[32]; 767 char bf[32];
669 double old_percent = 0, new_percent = 0, diff; 768 double old_percent = 0, new_percent = 0, diff;
@@ -710,12 +809,16 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
710 return ret; 809 return ret;
711} 810}
712 811
713int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 812int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
714 struct hists *pair_hists, bool show_displacement, 813 struct hists *pair_hists, bool show_displacement,
715 long displacement, FILE *fp, u64 session_total) 814 long displacement, FILE *fp, u64 session_total)
716{ 815{
717 char bf[512]; 816 char bf[512];
718 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, 817
818 if (size == 0 || size > sizeof(bf))
819 size = sizeof(bf);
820
821 hist_entry__snprintf(he, bf, size, hists, pair_hists,
719 show_displacement, displacement, 822 show_displacement, displacement,
720 true, session_total); 823 true, session_total);
721 return fprintf(fp, "%s\n", bf); 824 return fprintf(fp, "%s\n", bf);
@@ -738,8 +841,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
738 left_margin); 841 left_margin);
739} 842}
740 843
741size_t hists__fprintf(struct hists *self, struct hists *pair, 844size_t hists__fprintf(struct hists *hists, struct hists *pair,
742 bool show_displacement, FILE *fp) 845 bool show_displacement, bool show_header, int max_rows,
846 int max_cols, FILE *fp)
743{ 847{
744 struct sort_entry *se; 848 struct sort_entry *se;
745 struct rb_node *nd; 849 struct rb_node *nd;
@@ -749,9 +853,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
749 unsigned int width; 853 unsigned int width;
750 const char *sep = symbol_conf.field_sep; 854 const char *sep = symbol_conf.field_sep;
751 const char *col_width = symbol_conf.col_width_list_str; 855 const char *col_width = symbol_conf.col_width_list_str;
856 int nr_rows = 0;
752 857
753 init_rem_hits(); 858 init_rem_hits();
754 859
860 if (!show_header)
861 goto print_entries;
862
755 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 863 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
756 864
757 if (symbol_conf.show_nr_samples) { 865 if (symbol_conf.show_nr_samples) {
@@ -761,6 +869,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
761 fputs(" Samples ", fp); 869 fputs(" Samples ", fp);
762 } 870 }
763 871
872 if (symbol_conf.show_total_period) {
873 if (sep)
874 ret += fprintf(fp, "%cPeriod", *sep);
875 else
876 ret += fprintf(fp, " Period ");
877 }
878
764 if (symbol_conf.show_cpu_utilization) { 879 if (symbol_conf.show_cpu_utilization) {
765 if (sep) { 880 if (sep) {
766 ret += fprintf(fp, "%csys", *sep); 881 ret += fprintf(fp, "%csys", *sep);
@@ -803,18 +918,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
803 width = strlen(se->se_header); 918 width = strlen(se->se_header);
804 if (symbol_conf.col_width_list_str) { 919 if (symbol_conf.col_width_list_str) {
805 if (col_width) { 920 if (col_width) {
806 hists__set_col_len(self, se->se_width_idx, 921 hists__set_col_len(hists, se->se_width_idx,
807 atoi(col_width)); 922 atoi(col_width));
808 col_width = strchr(col_width, ','); 923 col_width = strchr(col_width, ',');
809 if (col_width) 924 if (col_width)
810 ++col_width; 925 ++col_width;
811 } 926 }
812 } 927 }
813 if (!hists__new_col_len(self, se->se_width_idx, width)) 928 if (!hists__new_col_len(hists, se->se_width_idx, width))
814 width = hists__col_len(self, se->se_width_idx); 929 width = hists__col_len(hists, se->se_width_idx);
815 fprintf(fp, " %*s", width, se->se_header); 930 fprintf(fp, " %*s", width, se->se_header);
816 } 931 }
932
817 fprintf(fp, "\n"); 933 fprintf(fp, "\n");
934 if (max_rows && ++nr_rows >= max_rows)
935 goto out;
818 936
819 if (sep) 937 if (sep)
820 goto print_entries; 938 goto print_entries;
@@ -822,6 +940,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
822 fprintf(fp, "# ........"); 940 fprintf(fp, "# ........");
823 if (symbol_conf.show_nr_samples) 941 if (symbol_conf.show_nr_samples)
824 fprintf(fp, " .........."); 942 fprintf(fp, " ..........");
943 if (symbol_conf.show_total_period)
944 fprintf(fp, " ............");
825 if (pair) { 945 if (pair) {
826 fprintf(fp, " .........."); 946 fprintf(fp, " ..........");
827 if (show_displacement) 947 if (show_displacement)
@@ -834,17 +954,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
834 continue; 954 continue;
835 955
836 fprintf(fp, " "); 956 fprintf(fp, " ");
837 width = hists__col_len(self, se->se_width_idx); 957 width = hists__col_len(hists, se->se_width_idx);
838 if (width == 0) 958 if (width == 0)
839 width = strlen(se->se_header); 959 width = strlen(se->se_header);
840 for (i = 0; i < width; i++) 960 for (i = 0; i < width; i++)
841 fprintf(fp, "."); 961 fprintf(fp, ".");
842 } 962 }
843 963
844 fprintf(fp, "\n#\n"); 964 fprintf(fp, "\n");
965 if (max_rows && ++nr_rows >= max_rows)
966 goto out;
967
968 fprintf(fp, "#\n");
969 if (max_rows && ++nr_rows >= max_rows)
970 goto out;
845 971
846print_entries: 972print_entries:
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 973 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 974 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
849 975
850 if (h->filtered) 976 if (h->filtered)
@@ -858,19 +984,22 @@ print_entries:
858 displacement = 0; 984 displacement = 0;
859 ++position; 985 ++position;
860 } 986 }
861 ret += hist_entry__fprintf(h, self, pair, show_displacement, 987 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
862 displacement, fp, self->stats.total_period); 988 displacement, fp, hists->stats.total_period);
863 989
864 if (symbol_conf.use_callchain) 990 if (symbol_conf.use_callchain)
865 ret += hist_entry__fprintf_callchain(h, self, fp, 991 ret += hist_entry__fprintf_callchain(h, hists, fp,
866 self->stats.total_period); 992 hists->stats.total_period);
993 if (max_rows && ++nr_rows >= max_rows)
994 goto out;
995
867 if (h->ms.map == NULL && verbose > 1) { 996 if (h->ms.map == NULL && verbose > 1) {
868 __map_groups__fprintf_maps(&h->thread->mg, 997 __map_groups__fprintf_maps(&h->thread->mg,
869 MAP__FUNCTION, verbose, fp); 998 MAP__FUNCTION, verbose, fp);
870 fprintf(fp, "%.10s end\n", graph_dotted_line); 999 fprintf(fp, "%.10s end\n", graph_dotted_line);
871 } 1000 }
872 } 1001 }
873 1002out:
874 free(rem_sq_bracket); 1003 free(rem_sq_bracket);
875 1004
876 return ret; 1005 return ret;
@@ -879,7 +1008,7 @@ print_entries:
879/* 1008/*
880 * See hists__fprintf to match the column widths 1009 * See hists__fprintf to match the column widths
881 */ 1010 */
882unsigned int hists__sort_list_width(struct hists *self) 1011unsigned int hists__sort_list_width(struct hists *hists)
883{ 1012{
884 struct sort_entry *se; 1013 struct sort_entry *se;
885 int ret = 9; /* total % */ 1014 int ret = 9; /* total % */
@@ -896,9 +1025,12 @@ unsigned int hists__sort_list_width(struct hists *self)
896 if (symbol_conf.show_nr_samples) 1025 if (symbol_conf.show_nr_samples)
897 ret += 11; 1026 ret += 11;
898 1027
1028 if (symbol_conf.show_total_period)
1029 ret += 13;
1030
899 list_for_each_entry(se, &hist_entry__sort_list, list) 1031 list_for_each_entry(se, &hist_entry__sort_list, list)
900 if (!se->elide) 1032 if (!se->elide)
901 ret += 2 + hists__col_len(self, se->se_width_idx); 1033 ret += 2 + hists__col_len(hists, se->se_width_idx);
902 1034
903 if (verbose) /* Addr + origin */ 1035 if (verbose) /* Addr + origin */
904 ret += 3 + BITS_PER_LONG / 4; 1036 ret += 3 + BITS_PER_LONG / 4;
@@ -906,32 +1038,32 @@ unsigned int hists__sort_list_width(struct hists *self)
906 return ret; 1038 return ret;
907} 1039}
908 1040
909static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 1041static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
910 enum hist_filter filter) 1042 enum hist_filter filter)
911{ 1043{
912 h->filtered &= ~(1 << filter); 1044 h->filtered &= ~(1 << filter);
913 if (h->filtered) 1045 if (h->filtered)
914 return; 1046 return;
915 1047
916 ++self->nr_entries; 1048 ++hists->nr_entries;
917 if (h->ms.unfolded) 1049 if (h->ms.unfolded)
918 self->nr_entries += h->nr_rows; 1050 hists->nr_entries += h->nr_rows;
919 h->row_offset = 0; 1051 h->row_offset = 0;
920 self->stats.total_period += h->period; 1052 hists->stats.total_period += h->period;
921 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1053 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
922 1054
923 hists__calc_col_len(self, h); 1055 hists__calc_col_len(hists, h);
924} 1056}
925 1057
926void hists__filter_by_dso(struct hists *self, const struct dso *dso) 1058void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
927{ 1059{
928 struct rb_node *nd; 1060 struct rb_node *nd;
929 1061
930 self->nr_entries = self->stats.total_period = 0; 1062 hists->nr_entries = hists->stats.total_period = 0;
931 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1063 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
932 hists__reset_col_len(self); 1064 hists__reset_col_len(hists);
933 1065
934 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1066 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1067 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
936 1068
937 if (symbol_conf.exclude_other && !h->parent) 1069 if (symbol_conf.exclude_other && !h->parent)
@@ -942,19 +1074,19 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
942 continue; 1074 continue;
943 } 1075 }
944 1076
945 hists__remove_entry_filter(self, h, HIST_FILTER__DSO); 1077 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
946 } 1078 }
947} 1079}
948 1080
949void hists__filter_by_thread(struct hists *self, const struct thread *thread) 1081void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
950{ 1082{
951 struct rb_node *nd; 1083 struct rb_node *nd;
952 1084
953 self->nr_entries = self->stats.total_period = 0; 1085 hists->nr_entries = hists->stats.total_period = 0;
954 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1086 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
955 hists__reset_col_len(self); 1087 hists__reset_col_len(hists);
956 1088
957 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1089 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1090 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
959 1091
960 if (thread != NULL && h->thread != thread) { 1092 if (thread != NULL && h->thread != thread) {
@@ -962,7 +1094,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
962 continue; 1094 continue;
963 } 1095 }
964 1096
965 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); 1097 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
966 } 1098 }
967} 1099}
968 1100
@@ -976,13 +1108,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
976 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1108 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
977} 1109}
978 1110
979void hists__inc_nr_events(struct hists *self, u32 type) 1111void hists__inc_nr_events(struct hists *hists, u32 type)
980{ 1112{
981 ++self->stats.nr_events[0]; 1113 ++hists->stats.nr_events[0];
982 ++self->stats.nr_events[type]; 1114 ++hists->stats.nr_events[type];
983} 1115}
984 1116
985size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) 1117size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
986{ 1118{
987 int i; 1119 int i;
988 size_t ret = 0; 1120 size_t ret = 0;
@@ -990,7 +1122,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1122 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
991 const char *name; 1123 const char *name;
992 1124
993 if (self->stats.nr_events[i] == 0) 1125 if (hists->stats.nr_events[i] == 0)
994 continue; 1126 continue;
995 1127
996 name = perf_event__name(i); 1128 name = perf_event__name(i);
@@ -998,8 +1130,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
998 continue; 1130 continue;
999 1131
1000 ret += fprintf(fp, "%16s events: %10d\n", name, 1132 ret += fprintf(fp, "%16s events: %10d\n", name,
1001 self->stats.nr_events[i]); 1133 hists->stats.nr_events[i]);
1002 } 1134 }
1003 1135
1004 return ret; 1136 return ret;
1005} 1137}
1138
1139void hists__init(struct hists *hists)
1140{
1141 memset(hists, 0, sizeof(*hists));
1142 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1143 hists->entries_in = &hists->entries_in_array[0];
1144 hists->entries_collapsed = RB_ROOT;
1145 hists->entries = RB_ROOT;
1146 pthread_mutex_init(&hists->lock, NULL);
1147}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3beb97c4d822..7ea1e560e008 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;
@@ -43,8 +44,12 @@ enum hist_column {
43}; 44};
44 45
45struct hists { 46struct hists {
47 struct rb_root entries_in_array[2];
48 struct rb_root *entries_in;
46 struct rb_root entries; 49 struct rb_root entries;
50 struct rb_root entries_collapsed;
47 u64 nr_entries; 51 u64 nr_entries;
52 pthread_mutex_t lock;
48 struct events_stats stats; 53 struct events_stats stats;
49 u64 event_stream; 54 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 55 u16 col_len[HISTC_NR_COLS];
@@ -52,14 +57,16 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 57 struct callchain_cursor callchain_cursor;
53}; 58};
54 59
60void hists__init(struct hists *hists);
61
55struct hist_entry *__hists__add_entry(struct hists *self, 62struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 63 struct addr_location *al,
57 struct symbol *parent, u64 period); 64 struct symbol *parent, u64 period);
58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 65extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 66extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 67int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
61 struct hists *pair_hists, bool show_displacement, 68 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total); 69 long displacement, FILE *fp, u64 session_total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 70int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists, 71 struct hists *hists, struct hists *pair_hists,
65 bool show_displacement, long displacement, 72 bool show_displacement, long displacement,
@@ -67,13 +74,19 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
67void hist_entry__free(struct hist_entry *); 74void hist_entry__free(struct hist_entry *);
68 75
69void hists__output_resort(struct hists *self); 76void hists__output_resort(struct hists *self);
77void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 78void hists__collapse_resort(struct hists *self);
79void hists__collapse_resort_threaded(struct hists *hists);
80
81void hists__decay_entries(struct hists *hists);
82void hists__output_recalc_col_len(struct hists *hists, int max_rows);
71 83
72void hists__inc_nr_events(struct hists *self, u32 type); 84void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 85size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
74 86
75size_t hists__fprintf(struct hists *self, struct hists *pair, 87size_t hists__fprintf(struct hists *self, struct hists *pair,
76 bool show_displacement, FILE *fp); 88 bool show_displacement, bool show_header,
89 int max_rows, int max_cols, FILE *fp);
77 90
78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 91int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
79int hist_entry__annotate(struct hist_entry *self, size_t privsize); 92int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -90,13 +103,16 @@ struct perf_evlist;
90#ifdef NO_NEWT_SUPPORT 103#ifdef NO_NEWT_SUPPORT
91static inline 104static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, 105int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used) 106 const char *help __used, void(*timer)(void *arg) __used, void *arg,
107 int refresh __used)
94{ 108{
95 return 0; 109 return 0;
96} 110}
97 111
98static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 112static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used) 113 int evidx __used, int nr_events __used,
114 void(*timer)(void *arg) __used,
115 void *arg __used, int delay_secs __used);
100{ 116{
101 return 0; 117 return 0;
102} 118}
@@ -104,12 +120,15 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
104#define KEY_RIGHT -2 120#define KEY_RIGHT -2
105#else 121#else
106#include <newt.h> 122#include <newt.h>
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx); 123int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
124 void(*timer)(void *arg), void *arg, int delay_secs);
108 125
109#define KEY_LEFT NEWT_KEY_LEFT 126#define KEY_LEFT NEWT_KEY_LEFT
110#define KEY_RIGHT NEWT_KEY_RIGHT 127#define KEY_RIGHT NEWT_KEY_RIGHT
111 128
112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); 129int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
130 void(*timer)(void *arg), void *arg,
131 int refresh);
113#endif 132#endif
114 133
115unsigned int hists__sort_list_width(struct hists *self); 134unsigned int hists__sort_list_width(struct hists *self);
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.h b/tools/perf/util/sort.h
index 77d0388ad415..03851e301721 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;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 077df15ee705..3f09a23f71b4 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -46,7 +46,6 @@ 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_asm_raw = true,
50 .annotate_src = true, 49 .annotate_src = true,
51 .symfs = "", 50 .symfs = "",
52}; 51};
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 7733f0b3cd41..29f8d742e92f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -72,6 +72,7 @@ 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,
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 b07b0410463c..01d1057f3074 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -4,64 +4,32 @@
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;
13struct perf_session; 10struct perf_session;
14 11
15struct sym_entry {
16 struct rb_node rb_node;
17 struct list_head node;
18 unsigned long snap_count;
19 double weight;
20 struct map *map;
21 unsigned long count[0];
22};
23
24static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
25{
26 return ((void *)self) + symbol_conf.priv_size;
27}
28
29struct perf_top { 12struct perf_top {
30 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
31 /* 14 /*
32 * 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
33 * get out after decayed. 16 * get out after decayed.
34 */ 17 */
35 struct list_head active_symbols;
36 pthread_mutex_t active_symbols_lock;
37 pthread_cond_t active_symbols_cond;
38 u64 samples; 18 u64 samples;
39 u64 kernel_samples, us_samples; 19 u64 kernel_samples, us_samples;
40 u64 exact_samples; 20 u64 exact_samples;
41 u64 guest_us_samples, guest_kernel_samples; 21 u64 guest_us_samples, guest_kernel_samples;
42 u64 total_lost_warned; 22 u64 total_lost_warned;
43 int print_entries, count_filter, delay_secs; 23 int print_entries, count_filter, delay_secs;
44 int display_weighted, freq, rb_entries; 24 int freq;
45 pid_t target_pid, target_tid; 25 pid_t target_pid, target_tid;
46 bool hide_kernel_symbols, hide_user_symbols, zero; 26 bool hide_kernel_symbols, hide_user_symbols, zero;
47 const char *cpu_list; 27 const char *cpu_list;
48 struct sym_entry *sym_filter_entry; 28 struct hist_entry *sym_filter_entry;
49 struct perf_evsel *sym_evsel; 29 struct perf_evsel *sym_evsel;
50 struct perf_session *session; 30 struct perf_session *session;
51}; 31};
52 32
53size_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);
54void perf_top__reset_sample_counters(struct perf_top *top); 34void perf_top__reset_sample_counters(struct perf_top *top);
55float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
56void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
57 int *dso_width, int *dso_short_width, int *sym_width);
58
59#ifdef NO_NEWT_SUPPORT
60static inline int perf_top__tui_browser(struct perf_top *top __used)
61{
62 return 0;
63}
64#else
65int perf_top__tui_browser(struct perf_top *top);
66#endif
67#endif /* __PERF_TOP_H */ 35#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0229723aceb3..674b55e686fd 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -20,6 +20,7 @@ struct annotate_browser {
20 struct ui_browser b; 20 struct ui_browser b;
21 struct rb_root entries; 21 struct rb_root entries;
22 struct rb_node *curr_hot; 22 struct rb_node *curr_hot;
23 struct objdump_line *selection;
23}; 24};
24 25
25struct objdump_line_rb_node { 26struct objdump_line_rb_node {
@@ -36,6 +37,7 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
36 37
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 38static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 39{
40 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 41 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 42 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 43 int width = self->width;
@@ -58,6 +60,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 60
59 if (!current_entry) 61 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 62 ui_browser__set_color(self, HE_COLORSET_CODE);
63 else
64 ab->selection = ol;
61} 65}
62 66
63static double objdump_line__calc_percent(struct objdump_line *self, 67static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +145,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 145static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 146 int evidx)
143{ 147{
144 struct symbol *sym = browser->b.priv; 148 struct map_symbol *ms = browser->b.priv;
149 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 150 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 151 struct objdump_line *pos;
147 152
@@ -164,21 +169,23 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
164} 169}
165 170
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 171static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 172 int nr_events, void(*timer)(void *arg),
173 void *arg, int delay_secs)
168{ 174{
169 struct rb_node *nd = NULL; 175 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 176 struct map_symbol *ms = self->b.priv;
177 struct symbol *sym = ms->sym;
171 /* 178 /*
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 179 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
173 * examining the exit key for this function. 180 * examining the exit key for this function.
174 */ 181 */
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, 182 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 }; 183 NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 };
177 int key; 184 int key;
178 185
179 if (ui_browser__show(&self->b, sym->name, 186 if (ui_browser__show(&self->b, sym->name,
180 "<-, -> or ESC: exit, TAB/shift+TAB: " 187 "<- or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0) 188 "cycle hottest lines, H: Hottest, -> Line action") < 0)
182 return -1; 189 return -1;
183 190
184 ui_browser__add_exit_keys(&self->b, exit_keys); 191 ui_browser__add_exit_keys(&self->b, exit_keys);
@@ -189,13 +196,13 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 196
190 nd = self->curr_hot; 197 nd = self->curr_hot;
191 198
192 if (refresh != 0) 199 if (delay_secs != 0)
193 newtFormSetTimer(self->b.form, refresh); 200 newtFormSetTimer(self->b.form, delay_secs * 1000);
194 201
195 while (1) { 202 while (1) {
196 key = ui_browser__run(&self->b); 203 key = ui_browser__run(&self->b);
197 204
198 if (refresh != 0) { 205 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 206 annotate_browser__calc_percent(self, evidx);
200 /* 207 /*
201 * Current line focus got out of the list of most active 208 * Current line focus got out of the list of most active
@@ -212,7 +219,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
212 * FIXME we need to check if it was 219 * FIXME we need to check if it was
213 * es.reason == NEWT_EXIT_TIMER 220 * es.reason == NEWT_EXIT_TIMER
214 */ 221 */
215 if (refresh != 0) 222 if (timer != NULL)
223 timer(arg);
224
225 if (delay_secs != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 226 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 227 continue;
218 case NEWT_KEY_TAB: 228 case NEWT_KEY_TAB:
@@ -234,6 +244,57 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 244 case 'H':
235 nd = self->curr_hot; 245 nd = self->curr_hot;
236 break; 246 break;
247 case NEWT_KEY_ENTER:
248 case NEWT_KEY_RIGHT:
249 if (self->selection == NULL) {
250 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
251 continue;
252 }
253
254 if (self->selection->offset == -1) {
255 ui_helpline__puts("Actions are only available for assembly lines.");
256 continue;
257 } else {
258 char *s = strstr(self->selection->line, "callq ");
259 struct annotation *notes;
260 struct symbol *target;
261 u64 ip;
262
263 if (s == NULL) {
264 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
265 continue;
266 }
267
268 s = strchr(s, ' ');
269 if (s++ == NULL) {
270 ui_helpline__puts("Invallid callq instruction.");
271 continue;
272 }
273
274 ip = strtoull(s, NULL, 16);
275 ip = ms->map->map_ip(ms->map, ip);
276 target = map__find_symbol(ms->map, ip, NULL);
277 if (target == NULL) {
278 ui_helpline__puts("The called function was not found.");
279 continue;
280 }
281
282 notes = symbol__annotation(target);
283 pthread_mutex_lock(&notes->lock);
284
285 if (notes->src == NULL &&
286 symbol__alloc_hist(target, nr_events) < 0) {
287 pthread_mutex_unlock(&notes->lock);
288 ui__warning("Not enough memory for annotating '%s' symbol!\n",
289 target->name);
290 continue;
291 }
292
293 pthread_mutex_unlock(&notes->lock);
294 symbol__tui_annotate(target, ms->map, evidx, nr_events,
295 timer, arg, delay_secs);
296 }
297 break;
237 default: 298 default:
238 goto out; 299 goto out;
239 } 300 }
@@ -246,22 +307,29 @@ out:
246 return key; 307 return key;
247} 308}
248 309
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 310int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
311 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 312{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 313 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
314 timer, arg, delay_secs);
252} 315}
253 316
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 317int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 318 int nr_events, void(*timer)(void *arg), void *arg,
319 int delay_secs)
256{ 320{
257 struct objdump_line *pos, *n; 321 struct objdump_line *pos, *n;
258 struct annotation *notes; 322 struct annotation *notes;
323 struct map_symbol ms = {
324 .map = map,
325 .sym = sym,
326 };
259 struct annotate_browser browser = { 327 struct annotate_browser browser = {
260 .b = { 328 .b = {
261 .refresh = ui_browser__list_head_refresh, 329 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 330 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 331 .write = annotate_browser__write,
264 .priv = sym, 332 .priv = &ms,
265 }, 333 },
266 }; 334 };
267 int ret; 335 int ret;
@@ -293,7 +361,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
293 361
294 browser.b.entries = &notes->src->source, 362 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 363 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 364 ret = annotate_browser__run(&browser, evidx, nr_events,
365 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 366 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 367 list_del(&pos->node);
299 objdump_line__free(pos); 368 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..e64d9527f14e 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -24,8 +24,15 @@ 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 const struct thread *thread_filter;
28 const struct dso *dso_filter;
29 bool has_symbols;
27}; 30};
28 31
32static int hists__browser_title(struct hists *self, char *bf, size_t size,
33 const char *ev_name, const struct dso *dso,
34 const struct thread *thread);
35
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 36static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 37{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 38 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +297,53 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 297 ui_browser__reset_index(&self->b);
291} 298}
292 299
293static int hist_browser__run(struct hist_browser *self, const char *title) 300static int hist_browser__run(struct hist_browser *self, const char *ev_name,
301 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 302{
295 int key; 303 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 304 int delay_msecs = delay_secs * 1000;
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 305 char title[160];
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, }; 306 int sym_exit_keys[] = { 'a', 'h', 'C', 'd', 'E', 't', 0, };
307 int exit_keys[] = { '?', 'h', 'D', NEWT_KEY_LEFT, NEWT_KEY_RIGHT,
308 NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, };
299 309
300 self->b.entries = &self->hists->entries; 310 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 311 self->b.nr_entries = self->hists->nr_entries;
302 312
303 hist_browser__refresh_dimensions(self); 313 hist_browser__refresh_dimensions(self);
314 hists__browser_title(self->hists, title, sizeof(title), ev_name,
315 self->dso_filter, self->thread_filter);
304 316
305 if (ui_browser__show(&self->b, title, 317 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 318 "Press '?' for help on key bindings") < 0)
307 return -1; 319 return -1;
308 320
321 if (timer != NULL)
322 newtFormSetTimer(self->b.form, delay_msecs);
323
309 ui_browser__add_exit_keys(&self->b, exit_keys); 324 ui_browser__add_exit_keys(&self->b, exit_keys);
325 if (self->has_symbols)
326 ui_browser__add_exit_keys(&self->b, sym_exit_keys);
310 327
311 while (1) { 328 while (1) {
312 key = ui_browser__run(&self->b); 329 key = ui_browser__run(&self->b);
313 330
314 switch (key) { 331 switch (key) {
332 case -1:
333 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
334 timer(arg);
335 /*
336 * The timer may have changed the number of entries.
337 * XXX: Find better way to keep this in synch, probably
338 * removing this timer function altogether and just sync
339 * using the hists->lock...
340 */
341 self->b.nr_entries = self->hists->nr_entries;
342 hists__browser_title(self->hists, title, sizeof(title),
343 ev_name, self->dso_filter,
344 self->thread_filter);
345 ui_browser__show_title(&self->b, title);
346 continue;
315 case 'D': { /* Debug */ 347 case 'D': { /* Debug */
316 static int seq; 348 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 349 struct hist_entry *h = rb_entry(self->b.top,
@@ -761,6 +793,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 793 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 794 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 795 self->b.seek = ui_browser__hists_seek;
796 self->has_symbols = sort_sym.list.next != NULL;
764 } 797 }
765 798
766 return self; 799 return self;
@@ -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);
@@ -862,16 +892,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
862 case NEWT_KEY_F1: 892 case NEWT_KEY_F1:
863 case 'h': 893 case 'h':
864 case '?': 894 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 895 ui__help_window("h/?/F1 Show this window\n"
896 "TAB/UNTAB Switch events\n"
897 "q/CTRL+C Exit browser\n\n"
898 "For symbolic views (--sort has sym):\n\n"
899 "-> Zoom into DSO/Threads & Annotate current symbol\n"
866 "<- Zoom out\n" 900 "<- Zoom out\n"
867 "a Annotate current symbol\n" 901 "a Annotate current symbol\n"
868 "h/?/F1 Show this window\n"
869 "C Collapse all callchains\n" 902 "C Collapse all callchains\n"
870 "E Expand all callchains\n" 903 "E Expand all callchains\n"
871 "d Zoom into current DSO\n" 904 "d Zoom into current DSO\n"
872 "t Zoom into current Thread\n" 905 "t Zoom into current Thread\n");
873 "TAB/UNTAB Switch events\n"
874 "q/CTRL+C Exit browser");
875 continue; 906 continue;
876 case NEWT_KEY_ENTER: 907 case NEWT_KEY_ENTER:
877 case NEWT_KEY_RIGHT: 908 case NEWT_KEY_RIGHT:
@@ -889,9 +920,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 920 continue;
890 } 921 }
891 top = pstack__pop(fstack); 922 top = pstack__pop(fstack);
892 if (top == &dso_filter) 923 if (top == &browser->dso_filter)
893 goto zoom_out_dso; 924 goto zoom_out_dso;
894 if (top == &thread_filter) 925 if (top == &browser->thread_filter)
895 goto zoom_out_thread; 926 goto zoom_out_thread;
896 continue; 927 continue;
897 } 928 }
@@ -904,6 +935,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
904 goto out_free_stack; 935 goto out_free_stack;
905 } 936 }
906 937
938 if (!browser->has_symbols)
939 goto add_exit_option;
940
907 if (browser->selection != NULL && 941 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 942 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 943 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +947,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 947
914 if (thread != NULL && 948 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 949 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 950 (browser->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 951 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 952 thread->pid) > 0)
919 zoom_thread = nr_options++; 953 zoom_thread = nr_options++;
920 954
921 if (dso != NULL && 955 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 956 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 957 (browser->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 958 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 959 zoom_dso = nr_options++;
926 960
@@ -928,7 +962,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 962 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 963 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 964 browse_map = nr_options++;
931 965add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 966 options[nr_options++] = (char *)"Exit";
933 967
934 choice = ui__popup_menu(nr_options, options); 968 choice = ui__popup_menu(nr_options, options);
@@ -949,45 +983,42 @@ do_annotate:
949 if (he == NULL) 983 if (he == NULL)
950 continue; 984 continue;
951 985
952 hist_entry__tui_annotate(he, evsel->idx); 986 hist_entry__tui_annotate(he, evsel->idx, nr_events,
987 timer, arg, delay_secs);
953 } else if (choice == browse_map) 988 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 989 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 990 else if (choice == zoom_dso) {
956zoom_dso: 991zoom_dso:
957 if (dso_filter) { 992 if (browser->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 993 pstack__remove(fstack, &browser->dso_filter);
959zoom_out_dso: 994zoom_out_dso:
960 ui_helpline__pop(); 995 ui_helpline__pop();
961 dso_filter = NULL; 996 browser->dso_filter = NULL;
962 } else { 997 } else {
963 if (dso == NULL) 998 if (dso == NULL)
964 continue; 999 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1000 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1001 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1002 browser->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1003 pstack__push(fstack, &browser->dso_filter);
969 } 1004 }
970 hists__filter_by_dso(self, dso_filter); 1005 hists__filter_by_dso(self, browser->dso_filter);
971 hists__browser_title(self, msg, sizeof(msg), ev_name,
972 dso_filter, thread_filter);
973 hist_browser__reset(browser); 1006 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1007 } else if (choice == zoom_thread) {
975zoom_thread: 1008zoom_thread:
976 if (thread_filter) { 1009 if (browser->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1010 pstack__remove(fstack, &browser->thread_filter);
978zoom_out_thread: 1011zoom_out_thread:
979 ui_helpline__pop(); 1012 ui_helpline__pop();
980 thread_filter = NULL; 1013 browser->thread_filter = NULL;
981 } else { 1014 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1015 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1016 thread->comm_set ? thread->comm : "",
984 thread->pid); 1017 thread->pid);
985 thread_filter = thread; 1018 browser->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1019 pstack__push(fstack, &browser->thread_filter);
987 } 1020 }
988 hists__filter_by_thread(self, thread_filter); 1021 hists__filter_by_thread(self, browser->thread_filter);
989 hists__browser_title(self, msg, sizeof(msg), ev_name,
990 dso_filter, thread_filter);
991 hist_browser__reset(browser); 1022 hist_browser__reset(browser);
992 } 1023 }
993 } 1024 }
@@ -1026,9 +1057,12 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1026 menu->selection = evsel; 1057 menu->selection = evsel;
1027} 1058}
1028 1059
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1060static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1061 int nr_events, const char *help,
1062 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1063{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; 1064 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1065 int delay_msecs = delay_secs * 1000;
1032 struct perf_evlist *evlist = menu->b.priv; 1066 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1067 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1068 const char *ev_name, *title = "Available samples";
@@ -1038,20 +1072,30 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1072 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1073 return -1;
1040 1074
1075 if (timer != NULL)
1076 newtFormSetTimer(menu->b.form, delay_msecs);
1077
1041 ui_browser__add_exit_keys(&menu->b, exit_keys); 1078 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042 1079
1043 while (1) { 1080 while (1) {
1044 key = ui_browser__run(&menu->b); 1081 key = ui_browser__run(&menu->b);
1045 1082
1046 switch (key) { 1083 switch (key) {
1084 case -1:
1085 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
1086 timer(arg);
1087 continue;
1047 case NEWT_KEY_RIGHT: 1088 case NEWT_KEY_RIGHT:
1048 case NEWT_KEY_ENTER: 1089 case NEWT_KEY_ENTER:
1049 if (!menu->selection) 1090 if (!menu->selection)
1050 continue; 1091 continue;
1051 pos = menu->selection; 1092 pos = menu->selection;
1093 perf_evlist__set_selected(evlist, pos);
1052browse_hists: 1094browse_hists:
1053 ev_name = event_name(pos); 1095 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1096 key = perf_evsel__hists_browse(pos, nr_events, help,
1097 ev_name, true, timer,
1098 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1099 ui_browser__show_title(&menu->b, title);
1056 break; 1100 break;
1057 case NEWT_KEY_LEFT: 1101 case NEWT_KEY_LEFT:
@@ -1070,12 +1114,14 @@ browse_hists:
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node); 1114 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else 1115 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node); 1116 pos = list_entry(pos->node.next, struct perf_evsel, node);
1117 perf_evlist__set_selected(evlist, pos);
1073 goto browse_hists; 1118 goto browse_hists;
1074 case NEWT_KEY_UNTAB: 1119 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries) 1120 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node); 1121 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else 1122 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node); 1123 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1124 perf_evlist__set_selected(evlist, pos);
1079 goto browse_hists; 1125 goto browse_hists;
1080 case 'q': 1126 case 'q':
1081 case CTRL('c'): 1127 case CTRL('c'):
@@ -1091,7 +1137,9 @@ out:
1091} 1137}
1092 1138
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1139static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1140 const char *help,
1141 void(*timer)(void *arg), void *arg,
1142 int delay_secs)
1095{ 1143{
1096 struct perf_evsel *pos; 1144 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1145 struct perf_evsel_menu menu = {
@@ -1121,18 +1169,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1169 pos->name = strdup(ev_name);
1122 } 1170 }
1123 1171
1124 return perf_evsel_menu__run(&menu, help); 1172 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1173 arg, delay_secs);
1125} 1174}
1126 1175
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1176int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1177 void(*timer)(void *arg), void *arg,
1178 int delay_secs)
1128{ 1179{
1129 1180
1130 if (evlist->nr_entries == 1) { 1181 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1182 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1183 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1184 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1185 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1186 ev_name, false, timer, arg,
1187 delay_secs);
1135 } 1188 }
1136 1189
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1190 return __perf_evlist__tui_browse_hists(evlist, help,
1191 timer, arg, delay_secs);
1138} 1192}
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index 9b6b43b32ac8..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,236 +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 "../ui.h"
15#include "../../evlist.h"
16#include "../../hist.h"
17#include "../../sort.h"
18#include "../../symbol.h"
19#include "../../session.h"
20#include "../../top.h"
21
22struct perf_top_browser {
23 struct ui_browser b;
24 struct rb_root root;
25 struct sym_entry *selection;
26 float sum_ksamples;
27 int dso_width;
28 int dso_short_width;
29 int sym_width;
30};
31
32static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
33{
34 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
35 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
36 bool current_entry = ui_browser__is_current_entry(browser, row);
37 struct symbol *symbol = sym_entry__symbol(syme);
38 struct perf_top *top = browser->priv;
39 int width = browser->width;
40 double pcnt;
41
42 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
43 top_browser->sum_ksamples));
44 ui_browser__set_percent_color(browser, pcnt, current_entry);
45
46 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
47 slsmg_printf("%20.2f ", syme->weight);
48 width -= 21;
49 } else {
50 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
51 width -= 20;
52 }
53
54 slsmg_printf("%4.1f%%", pcnt);
55 width -= 7;
56
57 if (verbose) {
58 slsmg_printf(" %016" PRIx64, symbol->start);
59 width -= 17;
60 }
61
62 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
63 symbol->name);
64 width -= top_browser->sym_width;
65 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
66 syme->map->dso->long_name :
67 syme->map->dso->short_name, width);
68
69 if (current_entry)
70 top_browser->selection = syme;
71}
72
73static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
74{
75 struct perf_top *top = browser->b.priv;
76 u64 top_idx = browser->b.top_idx;
77
78 browser->root = RB_ROOT;
79 browser->b.top = NULL;
80 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
81 /*
82 * No active symbols
83 */
84 if (top->rb_entries == 0)
85 return;
86
87 perf_top__find_widths(top, &browser->root, &browser->dso_width,
88 &browser->dso_short_width,
89 &browser->sym_width);
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
91 browser->dso_width = browser->dso_short_width;
92 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
93 browser->sym_width = browser->b.width - browser->dso_width - 29;
94 }
95
96 /*
97 * Adjust the ui_browser indexes since the entries in the browser->root
98 * rb_tree may have changed, then seek it from start, so that we get a
99 * possible new top of the screen.
100 */
101 browser->b.nr_entries = top->rb_entries;
102
103 if (top_idx >= browser->b.nr_entries) {
104 if (browser->b.height >= browser->b.nr_entries)
105 top_idx = browser->b.nr_entries - browser->b.height;
106 else
107 top_idx = 0;
108 }
109
110 if (browser->b.index >= top_idx + browser->b.height)
111 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
112
113 if (browser->b.index >= browser->b.nr_entries)
114 browser->b.index = browser->b.nr_entries - 1;
115
116 browser->b.top_idx = top_idx;
117 browser->b.seek(&browser->b, top_idx, SEEK_SET);
118}
119
120static void perf_top_browser__annotate(struct perf_top_browser *browser)
121{
122 struct sym_entry *syme = browser->selection;
123 struct symbol *sym = sym_entry__symbol(syme);
124 struct annotation *notes = symbol__annotation(sym);
125 struct perf_top *top = browser->b.priv;
126
127 if (notes->src != NULL)
128 goto do_annotation;
129
130 pthread_mutex_lock(&notes->lock);
131
132 top->sym_filter_entry = NULL;
133
134 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
135 pr_err("Not enough memory for annotating '%s' symbol!\n",
136 sym->name);
137 pthread_mutex_unlock(&notes->lock);
138 return;
139 }
140
141 top->sym_filter_entry = syme;
142
143 pthread_mutex_unlock(&notes->lock);
144do_annotation:
145 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
146}
147
148static void perf_top_browser__warn_lost(struct perf_top_browser *browser)
149{
150 struct perf_top *top = browser->b.priv;
151 char msg[128];
152 int len;
153
154 top->total_lost_warned = top->session->hists.stats.total_lost;
155 pthread_mutex_lock(&ui__lock);
156 ui_browser__set_color(&browser->b, HE_COLORSET_TOP);
157 len = snprintf(msg, sizeof(msg),
158 " WARNING: LOST %" PRIu64 " events, Check IO/CPU overload",
159 top->total_lost_warned);
160 if (len > browser->b.width)
161 len = browser->b.width;
162 SLsmg_gotorc(0, browser->b.width - len);
163 slsmg_write_nstring(msg, len);
164 pthread_mutex_unlock(&ui__lock);
165}
166
167static int perf_top_browser__run(struct perf_top_browser *browser)
168{
169 int key;
170 char title[160];
171 struct perf_top *top = browser->b.priv;
172 int delay_msecs = top->delay_secs * 1000;
173 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
174
175 perf_top_browser__update_rb_tree(browser);
176 perf_top__header_snprintf(top, title, sizeof(title));
177 perf_top__reset_sample_counters(top);
178
179 if (ui_browser__show(&browser->b, title,
180 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
181 return -1;
182
183 newtFormSetTimer(browser->b.form, delay_msecs);
184 ui_browser__add_exit_keys(&browser->b, exit_keys);
185
186 while (1) {
187 key = ui_browser__run(&browser->b);
188
189 switch (key) {
190 case -1:
191 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
192 perf_top_browser__update_rb_tree(browser);
193 perf_top__header_snprintf(top, title, sizeof(title));
194 perf_top__reset_sample_counters(top);
195 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
196 SLsmg_gotorc(0, 0);
197 slsmg_write_nstring(title, browser->b.width);
198
199 if (top->total_lost_warned != top->session->hists.stats.total_lost)
200 perf_top_browser__warn_lost(browser);
201 break;
202 case 'a':
203 case NEWT_KEY_RIGHT:
204 case NEWT_KEY_ENTER:
205 if (browser->selection)
206 perf_top_browser__annotate(browser);
207 break;
208 case NEWT_KEY_LEFT:
209 continue;
210 case NEWT_KEY_ESCAPE:
211 if (!ui__dialog_yesno("Do you really want to exit?"))
212 continue;
213 /* Fall thru */
214 default:
215 goto out;
216 }
217 }
218out:
219 ui_browser__hide(&browser->b);
220 return key;
221}
222
223int perf_top__tui_browser(struct perf_top *top)
224{
225 struct perf_top_browser browser = {
226 .b = {
227 .entries = &browser.root,
228 .refresh = ui_browser__rb_tree_refresh,
229 .seek = ui_browser__rb_tree_seek,
230 .write = perf_top_browser__write,
231 .priv = top,
232 },
233 };
234
235 return perf_top_browser__run(&browser);
236}