aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-10-05 18:16:15 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-10-07 15:56:44 -0400
commitab81f3fd350c510730adb1ca40ef55c2b2952121 (patch)
tree7b442d9592dd5666eb2cae6194962e545bd693a7 /tools
parent81cce8de9437be9234f651be1f03e596c1b1a79a (diff)
perf top: Reuse the 'report' hist_entry/hists classes
This actually fixes several problems we had in the old 'perf top': 1. Unresolved symbols not show, limitation that came from the old "KernelTop" codebase, to solve it we would need to do changes that would make sym_entry have most of the hist_entry fields. 2. It was using the number of samples, not the sum of sample->period. And brings the --sort code that allows us to have all the views in 'perf report', for instance: [root@emilia ~]# perf top --sort dso PerfTop: 5903 irqs/sec kernel:77.5% exact: 0.0% [1000Hz cycles], (all, 8 CPUs) ------------------------------------------------------------------------------ 31.59% libcrypto.so.1.0.0 21.55% [kernel] 18.57% libpython2.6.so.1.0 7.04% libc-2.12.so 6.99% _backend_agg.so 4.72% sshd 1.48% multiarray.so 1.39% libfreetype.so.6.3.22 1.37% perf 0.71% libgobject-2.0.so.0.2200.5 0.53% [tg3] 0.48% libglib-2.0.so.0.2200.5 0.44% libstdc++.so.6.0.13 0.40% libcairo.so.2.10800.8 0.38% libm-2.12.so 0.34% umath.so 0.30% libgdk-x11-2.0.so.0.1800.9 0.22% libpthread-2.12.so 0.20% libgtk-x11-2.0.so.0.1800.9 0.20% librt-2.12.so 0.15% _path.so 0.13% libpango-1.0.so.0.2800.1 0.11% libatlas.so.3.0 0.09% ft2font.so 0.09% libpangoft2-1.0.so.0.2800.1 0.08% libX11.so.6.3.0 0.07% [vdso] 0.06% cyclictest ^C All the filter lists can be used as well: --dsos, --comms, --symbols, etc. The 'perf report' TUI is also reused, being possible to apply all the zoom operations, do annotation, etc. This change will allow multiple simplifications in the symbol system as well, that will be detailed in upcoming changesets. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-xzaaldxq7zhqrrxdxjifk1mh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-top.txt23
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-top.c282
-rw-r--r--tools/perf/util/hist.c50
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h36
-rw-r--r--tools/perf/util/ui/browsers/top.c236
8 files changed, 196 insertions, 579 deletions
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index f6eb1cdafb77..d146ba33d691 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -106,6 +106,26 @@ 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
109INTERACTIVE PROMPTING KEYS 129INTERACTIVE PROMPTING KEYS
110-------------------------- 130--------------------------
111 131
@@ -130,9 +150,6 @@ INTERACTIVE PROMPTING KEYS
130[S]:: 150[S]::
131 Stop annotation, return to full profile display. 151 Stop annotation, return to full profile display.
132 152
133[w]::
134 Toggle between weighted sum and individual count[E]r profile.
135
136[z]:: 153[z]::
137 Toggle event count zeroing across display updates. 154 Toggle event count zeroing across display updates.
138 155
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/builtin-top.c b/tools/perf/builtin-top.c
index 5ede7d7c9239..2cf5e50a6997 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
@@ -85,7 +83,6 @@ static bool vmlinux_warned;
85static bool inherit = false; 83static bool inherit = false;
86static int realtime_prio = 0; 84static int realtime_prio = 0;
87static bool group = false; 85static bool group = false;
88static unsigned int page_size;
89static unsigned int mmap_pages = 128; 86static unsigned int mmap_pages = 128;
90 87
91static bool dump_symtab = false; 88static bool dump_symtab = false;
@@ -93,7 +90,6 @@ static bool dump_symtab = false;
93static struct winsize winsize; 90static struct winsize winsize;
94 91
95static const char *sym_filter = NULL; 92static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 93static int sym_pcnt_filter = 5;
98 94
99/* 95/*
@@ -136,18 +132,18 @@ static void sig_winch_handler(int sig __used)
136 update_print_entries(&winsize); 132 update_print_entries(&winsize);
137} 133}
138 134
139static int parse_source(struct sym_entry *syme) 135static int parse_source(struct hist_entry *he)
140{ 136{
141 struct symbol *sym; 137 struct symbol *sym;
142 struct annotation *notes; 138 struct annotation *notes;
143 struct map *map; 139 struct map *map;
144 int err = -1; 140 int err = -1;
145 141
146 if (!syme) 142 if (!he || !he->ms.sym)
147 return -1; 143 return -1;
148 144
149 sym = sym_entry__symbol(syme); 145 sym = he->ms.sym;
150 map = syme->map; 146 map = he->ms.map;
151 147
152 /* 148 /*
153 * We can't annotate with just /proc/kallsyms 149 * We can't annotate with just /proc/kallsyms
@@ -175,53 +171,62 @@ static int parse_source(struct sym_entry *syme)
175 return err; 171 return err;
176 } 172 }
177 173
178 err = symbol__annotate(sym, syme->map, 0); 174 err = symbol__annotate(sym, map, 0);
179 if (err == 0) { 175 if (err == 0) {
180out_assign: 176out_assign:
181 top.sym_filter_entry = syme; 177 top.sym_filter_entry = he;
182 } 178 }
183 179
184 pthread_mutex_unlock(&notes->lock); 180 pthread_mutex_unlock(&notes->lock);
185 return err; 181 return err;
186} 182}
187 183
188static void __zero_source_counters(struct sym_entry *syme) 184static void __zero_source_counters(struct hist_entry *he)
189{ 185{
190 struct symbol *sym = sym_entry__symbol(syme); 186 struct symbol *sym = he->ms.sym;
191 symbol__annotate_zero_histograms(sym); 187 symbol__annotate_zero_histograms(sym);
192} 188}
193 189
194static void record_precise_ip(struct sym_entry *syme, struct map *map, 190static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
195 int counter, u64 ip)
196{ 191{
197 struct annotation *notes; 192 struct annotation *notes;
198 struct symbol *sym; 193 struct symbol *sym;
199 194
200 if (syme != top.sym_filter_entry) 195 if (he == NULL || he->ms.sym == NULL ||
196 (he != top.sym_filter_entry && use_browser != 1))
201 return; 197 return;
202 198
203 sym = sym_entry__symbol(syme); 199 sym = he->ms.sym;
204 notes = symbol__annotation(sym); 200 notes = symbol__annotation(sym);
205 201
206 if (pthread_mutex_trylock(&notes->lock)) 202 if (pthread_mutex_trylock(&notes->lock))
207 return; 203 return;
208 204
209 ip = map->map_ip(map, ip); 205 if (notes->src == NULL &&
210 symbol__inc_addr_samples(sym, map, counter, ip); 206 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
207 pthread_mutex_unlock(&notes->lock);
208 pr_err("Not enough memory for annotating '%s' symbol!\n",
209 sym->name);
210 sleep(1);
211 return;
212 }
213
214 ip = he->ms.map->map_ip(he->ms.map, ip);
215 symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
211 216
212 pthread_mutex_unlock(&notes->lock); 217 pthread_mutex_unlock(&notes->lock);
213} 218}
214 219
215static void show_details(struct sym_entry *syme) 220static void show_details(struct hist_entry *he)
216{ 221{
217 struct annotation *notes; 222 struct annotation *notes;
218 struct symbol *symbol; 223 struct symbol *symbol;
219 int more; 224 int more;
220 225
221 if (!syme) 226 if (!he)
222 return; 227 return;
223 228
224 symbol = sym_entry__symbol(syme); 229 symbol = he->ms.sym;
225 notes = symbol__annotation(symbol); 230 notes = symbol__annotation(symbol);
226 231
227 pthread_mutex_lock(&notes->lock); 232 pthread_mutex_lock(&notes->lock);
@@ -232,7 +237,7 @@ static void show_details(struct sym_entry *syme)
232 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 237 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
233 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 238 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
234 239
235 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, 240 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
236 0, sym_pcnt_filter, top.print_entries, 4); 241 0, sym_pcnt_filter, top.print_entries, 4);
237 if (top.zero) 242 if (top.zero)
238 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 243 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
@@ -246,21 +251,28 @@ out_unlock:
246 251
247static const char CONSOLE_CLEAR[] = ""; 252static const char CONSOLE_CLEAR[] = "";
248 253
249static void __list_insert_active_sym(struct sym_entry *syme) 254static struct hist_entry *
255 perf_session__add_hist_entry(struct perf_session *session,
256 struct addr_location *al,
257 struct perf_sample *sample,
258 struct perf_evsel *evsel)
250{ 259{
251 list_add(&syme->node, &top.active_symbols); 260 struct hist_entry *he;
261
262 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
263 if (he == NULL)
264 return NULL;
265
266 session->hists.stats.total_period += sample->period;
267 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
268 return he;
252} 269}
253 270
254static void print_sym_table(void) 271static void print_sym_table(void)
255{ 272{
256 char bf[160]; 273 char bf[160];
257 int printed = 0; 274 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; 275 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 276
265 puts(CONSOLE_CLEAR); 277 puts(CONSOLE_CLEAR);
266 278
@@ -276,6 +288,7 @@ static void print_sym_table(void)
276 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 288 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
277 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 289 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
278 top.total_lost_warned); 290 top.total_lost_warned);
291 ++printed;
279 } 292 }
280 293
281 if (top.sym_filter_entry) { 294 if (top.sym_filter_entry) {
@@ -283,58 +296,13 @@ static void print_sym_table(void)
283 return; 296 return;
284 } 297 }
285 298
286 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 299 hists__collapse_resort_threaded(&top.sym_evsel->hists);
287 &sym_width); 300 hists__output_resort_threaded(&top.sym_evsel->hists);
288 301 hists__decay_entries(&top.sym_evsel->hists);
289 if (sym_width + dso_width > winsize.ws_col - 29) { 302 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'); 303 putchar('\n');
295 if (top.evlist->nr_entries == 1) 304 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
296 printf(" samples pcnt"); 305 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} 306}
339 307
340static void prompt_integer(int *target, const char *msg) 308static void prompt_integer(int *target, const char *msg)
@@ -372,10 +340,11 @@ static void prompt_percent(int *target, const char *msg)
372 *target = tmp; 340 *target = tmp;
373} 341}
374 342
375static void prompt_symbol(struct sym_entry **target, const char *msg) 343static void prompt_symbol(struct hist_entry **target, const char *msg)
376{ 344{
377 char *buf = malloc(0), *p; 345 char *buf = malloc(0), *p;
378 struct sym_entry *syme = *target, *n, *found = NULL; 346 struct hist_entry *syme = *target, *n, *found = NULL;
347 struct rb_node *next;
379 size_t dummy = 0; 348 size_t dummy = 0;
380 349
381 /* zero counters of active symbol */ 350 /* zero counters of active symbol */
@@ -392,17 +361,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
392 if (p) 361 if (p)
393 *p = 0; 362 *p = 0;
394 363
395 pthread_mutex_lock(&top.active_symbols_lock); 364 next = rb_first(&top.sym_evsel->hists.entries);
396 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 365 while (next) {
397 pthread_mutex_unlock(&top.active_symbols_lock); 366 n = rb_entry(next, struct hist_entry, rb_node);
398 367 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
399 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 368 found = n;
400 struct symbol *sym = sym_entry__symbol(syme);
401
402 if (!strcmp(buf, sym->name)) {
403 found = syme;
404 break; 369 break;
405 } 370 }
371 next = rb_next(&n->rb_node);
406 } 372 }
407 373
408 if (!found) { 374 if (!found) {
@@ -421,7 +387,7 @@ static void print_mapped_keys(void)
421 char *name = NULL; 387 char *name = NULL;
422 388
423 if (top.sym_filter_entry) { 389 if (top.sym_filter_entry) {
424 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 390 struct symbol *sym = top.sym_filter_entry->ms.sym;
425 name = sym->name; 391 name = sym->name;
426 } 392 }
427 393
@@ -438,9 +404,6 @@ static void print_mapped_keys(void)
438 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 404 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
439 fprintf(stdout, "\t[S] stop annotation.\n"); 405 fprintf(stdout, "\t[S] stop annotation.\n");
440 406
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, 407 fprintf(stdout,
445 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 408 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
446 top.hide_kernel_symbols ? "yes" : "no"); 409 top.hide_kernel_symbols ? "yes" : "no");
@@ -467,8 +430,6 @@ static int key_mapped(int c)
467 case 'S': 430 case 'S':
468 return 1; 431 return 1;
469 case 'E': 432 case 'E':
470 case 'w':
471 return top.evlist->nr_entries > 1 ? 1 : 0;
472 default: 433 default:
473 break; 434 break;
474 } 435 }
@@ -561,7 +522,7 @@ static void handle_keypress(int c)
561 if (!top.sym_filter_entry) 522 if (!top.sym_filter_entry)
562 break; 523 break;
563 else { 524 else {
564 struct sym_entry *syme = top.sym_filter_entry; 525 struct hist_entry *syme = top.sym_filter_entry;
565 526
566 top.sym_filter_entry = NULL; 527 top.sym_filter_entry = NULL;
567 __zero_source_counters(syme); 528 __zero_source_counters(syme);
@@ -570,9 +531,6 @@ static void handle_keypress(int c)
570 case 'U': 531 case 'U':
571 top.hide_user_symbols = !top.hide_user_symbols; 532 top.hide_user_symbols = !top.hide_user_symbols;
572 break; 533 break;
573 case 'w':
574 top.display_weighted = ~top.display_weighted;
575 break;
576 case 'z': 534 case 'z':
577 top.zero = !top.zero; 535 top.zero = !top.zero;
578 break; 536 break;
@@ -581,19 +539,29 @@ static void handle_keypress(int c)
581 } 539 }
582} 540}
583 541
542static void perf_top__sort_new_samples(void *arg)
543{
544 struct perf_top *t = arg;
545 perf_top__reset_sample_counters(t);
546
547 if (t->evlist->selected != NULL)
548 t->sym_evsel = t->evlist->selected;
549
550 hists__collapse_resort_threaded(&t->sym_evsel->hists);
551 hists__output_resort_threaded(&t->sym_evsel->hists);
552 hists__decay_entries(&t->sym_evsel->hists);
553 hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3);
554}
555
584static void *display_thread_tui(void *arg __used) 556static void *display_thread_tui(void *arg __used)
585{ 557{
586 int err = 0; 558 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
587 pthread_mutex_lock(&top.active_symbols_lock); 559
588 while (list_empty(&top.active_symbols)) { 560 perf_top__sort_new_samples(&top);
589 err = pthread_cond_wait(&top.active_symbols_cond, 561 perf_evlist__tui_browse_hists(top.evlist, help,
590 &top.active_symbols_lock); 562 perf_top__sort_new_samples,
591 if (err) 563 &top, top.delay_secs);
592 break; 564
593 }
594 pthread_mutex_unlock(&top.active_symbols_lock);
595 if (!err)
596 perf_top__tui_browser(&top);
597 exit_browser(0); 565 exit_browser(0);
598 exit(0); 566 exit(0);
599 return NULL; 567 return NULL;
@@ -645,9 +613,8 @@ static const char *skip_symbols[] = {
645 NULL 613 NULL
646}; 614};
647 615
648static int symbol_filter(struct map *map, struct symbol *sym) 616static int symbol_filter(struct map *map __used, struct symbol *sym)
649{ 617{
650 struct sym_entry *syme;
651 const char *name = sym->name; 618 const char *name = sym->name;
652 int i; 619 int i;
653 620
@@ -667,16 +634,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
667 strstr(name, "_text_end")) 634 strstr(name, "_text_end"))
668 return 1; 635 return 1;
669 636
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++) { 637 for (i = 0; skip_symbols[i]; i++) {
681 if (!strcmp(skip_symbols[i], name)) { 638 if (!strcmp(skip_symbols[i], name)) {
682 sym->ignore = true; 639 sym->ignore = true;
@@ -692,7 +649,6 @@ static void perf_event__process_sample(const union perf_event *event,
692 struct perf_session *session) 649 struct perf_session *session)
693{ 650{
694 u64 ip = event->ip.ip; 651 u64 ip = event->ip.ip;
695 struct sym_entry *syme;
696 struct addr_location al; 652 struct addr_location al;
697 struct machine *machine; 653 struct machine *machine;
698 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 654 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -783,46 +739,25 @@ static void perf_event__process_sample(const union perf_event *event,
783 sleep(5); 739 sleep(5);
784 vmlinux_warned = true; 740 vmlinux_warned = true;
785 } 741 }
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 } 742 }
806 743
807 syme = symbol__priv(al.sym); 744 if (al.sym == NULL || !al.sym->ignore) {
808 if (!al.sym->ignore) {
809 struct perf_evsel *evsel; 745 struct perf_evsel *evsel;
746 struct hist_entry *he;
810 747
811 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 748 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
812 assert(evsel != NULL); 749 assert(evsel != NULL);
813 syme->count[evsel->idx]++; 750
814 record_precise_ip(syme, al.map, evsel->idx, ip); 751 he = perf_session__add_hist_entry(session, &al, sample, evsel);
815 pthread_mutex_lock(&top.active_symbols_lock); 752 if (he == NULL) {
816 if (list_empty(&syme->node) || !syme->node.next) { 753 pr_err("Problem incrementing symbol period, skipping event\n");
817 static bool first = true; 754 return;
818 __list_insert_active_sym(syme);
819 if (first) {
820 pthread_cond_broadcast(&top.active_symbols_cond);
821 first = false;
822 }
823 } 755 }
824 pthread_mutex_unlock(&top.active_symbols_lock); 756
757 record_precise_ip(he, evsel->idx, ip);
825 } 758 }
759
760 return;
826} 761}
827 762
828static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 763static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
@@ -874,6 +809,7 @@ static void start_counters(struct perf_evlist *evlist)
874 } 809 }
875 810
876 attr->mmap = 1; 811 attr->mmap = 1;
812 attr->comm = 1;
877 attr->inherit = inherit; 813 attr->inherit = inherit;
878try_again: 814try_again:
879 if (perf_evsel__open(counter, top.evlist->cpus, 815 if (perf_evsel__open(counter, top.evlist->cpus,
@@ -1019,7 +955,7 @@ static const struct option options[] = {
1019 "put the counters into a counter group"), 955 "put the counters into a counter group"),
1020 OPT_BOOLEAN('i', "inherit", &inherit, 956 OPT_BOOLEAN('i', "inherit", &inherit,
1021 "child tasks inherit counters"), 957 "child tasks inherit counters"),
1022 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 958 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1023 "symbol to annotate"), 959 "symbol to annotate"),
1024 OPT_BOOLEAN('z', "zero", &top.zero, 960 OPT_BOOLEAN('z', "zero", &top.zero,
1025 "zero history across updates"), 961 "zero history across updates"),
@@ -1033,6 +969,18 @@ static const struct option options[] = {
1033 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 969 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1034 OPT_INCR('v', "verbose", &verbose, 970 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 971 "be more verbose (show counter open errors, etc)"),
972 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
973 "sort by key(s): pid, comm, dso, symbol, parent"),
974 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
975 "Show a column with the number of samples"),
976 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
977 "Show a column with the sum of periods"),
978 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
979 "only consider symbols in these dsos"),
980 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
981 "only consider symbols in these comms"),
982 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
983 "only consider these symbols"),
1036 OPT_END() 984 OPT_END()
1037}; 985};
1038 986
@@ -1045,12 +993,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1045 if (top.evlist == NULL) 993 if (top.evlist == NULL)
1046 return -ENOMEM; 994 return -ENOMEM;
1047 995
1048 page_size = sysconf(_SC_PAGE_SIZE); 996 symbol_conf.exclude_other = false;
1049 997
1050 argc = parse_options(argc, argv, options, top_usage, 0); 998 argc = parse_options(argc, argv, options, top_usage, 0);
1051 if (argc) 999 if (argc)
1052 usage_with_options(top_usage, options); 1000 usage_with_options(top_usage, options);
1053 1001
1002 if (sort_order == default_sort_order)
1003 sort_order = "dso,symbol";
1004
1005 setup_sorting(top_usage, options);
1006
1054 /* 1007 /*
1055 * XXX For now start disabled, only using TUI if explicitely asked for. 1008 * XXX For now start disabled, only using TUI if explicitely asked for.
1056 * Change that when handle_keys equivalent gets written, live annotation 1009 * Change that when handle_keys equivalent gets written, live annotation
@@ -1119,13 +1072,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1119 1072
1120 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1073 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1121 1074
1122 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1075 symbol_conf.priv_size = sizeof(struct annotation);
1123 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1124 1076
1125 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1077 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1126 if (symbol__init() < 0) 1078 if (symbol__init() < 0)
1127 return -1; 1079 return -1;
1128 1080
1081 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1082 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1083 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1084
1129 get_term_dimensions(&winsize); 1085 get_term_dimensions(&winsize);
1130 if (top.print_entries == 0) { 1086 if (top.print_entries == 0) {
1131 update_print_entries(&winsize); 1087 update_print_entries(&winsize);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 80fe30d90d72..87ef5c7797de 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -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 */
@@ -635,6 +670,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
635 return ret; 670 return ret;
636} 671}
637 672
673void hists__output_recalc_col_len(struct hists *hists, int max_rows)
674{
675 struct rb_node *next = rb_first(&hists->entries);
676 struct hist_entry *n;
677 int row = 0;
678
679 hists__reset_col_len(hists);
680
681 while (next && row++ < max_rows) {
682 n = rb_entry(next, struct hist_entry, rb_node);
683 hists__calc_col_len(hists, n);
684 next = rb_next(&n->rb_node);
685 }
686}
687
638int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 688int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
639 struct hists *hists, struct hists *pair_hists, 689 struct hists *hists, struct hists *pair_hists,
640 bool show_displacement, long displacement, 690 bool show_displacement, long displacement,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 424f9eb8310c..f87677bfaff9 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -78,6 +78,9 @@ void hists__output_resort_threaded(struct hists *hists);
78void hists__collapse_resort(struct hists *self); 78void hists__collapse_resort(struct hists *self);
79void hists__collapse_resort_threaded(struct hists *hists); 79void hists__collapse_resort_threaded(struct hists *hists);
80 80
81void hists__decay_entries(struct hists *hists);
82void hists__output_recalc_col_len(struct hists *hists, int max_rows);
83
81void hists__inc_nr_events(struct hists *self, u32 type); 84void hists__inc_nr_events(struct hists *self, u32 type);
82size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 85size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
83 86
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/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index d43875b2356f..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, NULL, NULL, 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}