aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c77
1 files changed, 48 insertions, 29 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index cf0d21f1ae10..f139f1ab9333 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -23,7 +23,7 @@
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/color.h" 24#include "util/color.h"
25#include "util/util.h" 25#include "util/util.h"
26#include "util/rbtree.h" 26#include <linux/rbtree.h>
27#include "util/parse-options.h" 27#include "util/parse-options.h"
28#include "util/parse-events.h" 28#include "util/parse-events.h"
29 29
@@ -58,6 +58,7 @@ static u64 count_filter = 5;
58static int print_entries = 15; 58static int print_entries = 15;
59 59
60static int target_pid = -1; 60static int target_pid = -1;
61static int inherit = 0;
61static int profile_cpu = -1; 62static int profile_cpu = -1;
62static int nr_cpus = 0; 63static int nr_cpus = 0;
63static unsigned int realtime_prio = 0; 64static unsigned int realtime_prio = 0;
@@ -66,6 +67,7 @@ static unsigned int page_size;
66static unsigned int mmap_pages = 16; 67static unsigned int mmap_pages = 16;
67static int freq = 0; 68static int freq = 0;
68static int verbose = 0; 69static int verbose = 0;
70static char *vmlinux = NULL;
69 71
70static char *sym_filter; 72static char *sym_filter;
71static unsigned long filter_start; 73static unsigned long filter_start;
@@ -238,7 +240,6 @@ static void print_sym_table(void)
238 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 240 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
239 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); 241 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
240 struct symbol *sym = (struct symbol *)(syme + 1); 242 struct symbol *sym = (struct symbol *)(syme + 1);
241 char *color = PERF_COLOR_NORMAL;
242 double pcnt; 243 double pcnt;
243 244
244 if (++printed > print_entries || syme->snap_count < count_filter) 245 if (++printed > print_entries || syme->snap_count < count_filter)
@@ -247,29 +248,20 @@ static void print_sym_table(void)
247 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 248 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
248 sum_ksamples)); 249 sum_ksamples));
249 250
250 /*
251 * We color high-overhead entries in red, mid-overhead
252 * entries in green - and keep the low overhead places
253 * normal:
254 */
255 if (pcnt >= 5.0) {
256 color = PERF_COLOR_RED;
257 } else {
258 if (pcnt >= 0.5)
259 color = PERF_COLOR_GREEN;
260 }
261
262 if (nr_counters == 1) 251 if (nr_counters == 1)
263 printf("%20.2f - ", syme->weight); 252 printf("%20.2f - ", syme->weight);
264 else 253 else
265 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 254 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
266 255
267 color_fprintf(stdout, color, "%4.1f%%", pcnt); 256 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
268 printf(" - %016llx : %s\n", sym->start, sym->name); 257 printf(" - %016llx : %s", sym->start, sym->name);
258 if (sym->module)
259 printf("\t[%s]", sym->module->name);
260 printf("\n");
269 } 261 }
270} 262}
271 263
272static void *display_thread(void *arg) 264static void *display_thread(void *arg __used)
273{ 265{
274 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 266 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
275 int delay_msecs = delay_secs * 1000; 267 int delay_msecs = delay_secs * 1000;
@@ -286,11 +278,32 @@ static void *display_thread(void *arg)
286 return NULL; 278 return NULL;
287} 279}
288 280
281/* Tag samples to be skipped. */
282static const char *skip_symbols[] = {
283 "default_idle",
284 "cpu_idle",
285 "enter_idle",
286 "exit_idle",
287 "mwait_idle",
288 "mwait_idle_with_hints",
289 "ppc64_runlatch_off",
290 "pseries_dedicated_idle_sleep",
291 NULL
292};
293
289static int symbol_filter(struct dso *self, struct symbol *sym) 294static int symbol_filter(struct dso *self, struct symbol *sym)
290{ 295{
291 static int filter_match; 296 static int filter_match;
292 struct sym_entry *syme; 297 struct sym_entry *syme;
293 const char *name = sym->name; 298 const char *name = sym->name;
299 int i;
300
301 /*
302 * ppc64 uses function descriptors and appends a '.' to the
303 * start of every instruction address. Remove it.
304 */
305 if (name[0] == '.')
306 name++;
294 307
295 if (!strcmp(name, "_text") || 308 if (!strcmp(name, "_text") ||
296 !strcmp(name, "_etext") || 309 !strcmp(name, "_etext") ||
@@ -302,13 +315,12 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
302 return 1; 315 return 1;
303 316
304 syme = dso__sym_priv(self, sym); 317 syme = dso__sym_priv(self, sym);
305 /* Tag samples to be skipped. */ 318 for (i = 0; skip_symbols[i]; i++) {
306 if (!strcmp("default_idle", name) || 319 if (!strcmp(skip_symbols[i], name)) {
307 !strcmp("cpu_idle", name) || 320 syme->skip = 1;
308 !strcmp("enter_idle", name) || 321 break;
309 !strcmp("exit_idle", name) || 322 }
310 !strcmp("mwait_idle", name)) 323 }
311 syme->skip = 1;
312 324
313 if (filter_match == 1) { 325 if (filter_match == 1) {
314 filter_end = sym->start; 326 filter_end = sym->start;
@@ -340,12 +352,13 @@ static int parse_symbols(void)
340{ 352{
341 struct rb_node *node; 353 struct rb_node *node;
342 struct symbol *sym; 354 struct symbol *sym;
355 int modules = vmlinux ? 1 : 0;
343 356
344 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 357 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
345 if (kernel_dso == NULL) 358 if (kernel_dso == NULL)
346 return -1; 359 return -1;
347 360
348 if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) 361 if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
349 goto out_delete_dso; 362 goto out_delete_dso;
350 363
351 node = rb_first(&kernel_dso->syms); 364 node = rb_first(&kernel_dso->syms);
@@ -407,7 +420,7 @@ static void process_event(u64 ip, int counter, int user)
407struct mmap_data { 420struct mmap_data {
408 int counter; 421 int counter;
409 void *base; 422 void *base;
410 unsigned int mask; 423 int mask;
411 unsigned int prev; 424 unsigned int prev;
412}; 425};
413 426
@@ -538,7 +551,7 @@ int group_fd;
538static void start_counter(int i, int counter) 551static void start_counter(int i, int counter)
539{ 552{
540 struct perf_counter_attr *attr; 553 struct perf_counter_attr *attr;
541 unsigned int cpu; 554 int cpu;
542 555
543 cpu = profile_cpu; 556 cpu = profile_cpu;
544 if (target_pid == -1 && profile_cpu == -1) 557 if (target_pid == -1 && profile_cpu == -1)
@@ -548,6 +561,7 @@ static void start_counter(int i, int counter)
548 561
549 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 562 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
550 attr->freq = freq; 563 attr->freq = freq;
564 attr->inherit = (cpu < 0) && inherit;
551 565
552try_again: 566try_again:
553 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 567 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
@@ -661,6 +675,7 @@ static const struct option options[] = {
661 "system-wide collection from all CPUs"), 675 "system-wide collection from all CPUs"),
662 OPT_INTEGER('C', "CPU", &profile_cpu, 676 OPT_INTEGER('C', "CPU", &profile_cpu,
663 "CPU to profile on"), 677 "CPU to profile on"),
678 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
664 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 679 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
665 "number of mmap data pages"), 680 "number of mmap data pages"),
666 OPT_INTEGER('r', "realtime", &realtime_prio, 681 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -673,9 +688,11 @@ static const struct option options[] = {
673 "only display functions with more events than this"), 688 "only display functions with more events than this"),
674 OPT_BOOLEAN('g', "group", &group, 689 OPT_BOOLEAN('g', "group", &group,
675 "put the counters into a counter group"), 690 "put the counters into a counter group"),
691 OPT_BOOLEAN('i', "inherit", &inherit,
692 "child tasks inherit counters"),
676 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 693 OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
677 "only display symbols matchig this pattern"), 694 "only display symbols matchig this pattern"),
678 OPT_BOOLEAN('z', "zero", &group, 695 OPT_BOOLEAN('z', "zero", &zero,
679 "zero history across updates"), 696 "zero history across updates"),
680 OPT_INTEGER('F', "freq", &freq, 697 OPT_INTEGER('F', "freq", &freq,
681 "profile at this frequency"), 698 "profile at this frequency"),
@@ -686,10 +703,12 @@ static const struct option options[] = {
686 OPT_END() 703 OPT_END()
687}; 704};
688 705
689int cmd_top(int argc, const char **argv, const char *prefix) 706int cmd_top(int argc, const char **argv, const char *prefix __used)
690{ 707{
691 int counter; 708 int counter;
692 709
710 symbol__init();
711
693 page_size = sysconf(_SC_PAGE_SIZE); 712 page_size = sysconf(_SC_PAGE_SIZE);
694 713
695 argc = parse_options(argc, argv, options, top_usage, 0); 714 argc = parse_options(argc, argv, options, top_usage, 0);