diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-12 20:44:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-12 20:44:53 -0400 |
commit | aa11d958d1a6572eda08214d7c6a735804fe48a5 (patch) | |
tree | d025b05270ad1e010660d17eeadc6ac3c1abbd7d /tools/perf/builtin-top.c | |
parent | 07f6642ee9418e962e54cbc07471cfe2e559c568 (diff) | |
parent | 9799218ae36910af50f002a5db1802d576fffb43 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
arch/microblaze/include/asm/socket.h
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 77 |
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; | |||
58 | static int print_entries = 15; | 58 | static int print_entries = 15; |
59 | 59 | ||
60 | static int target_pid = -1; | 60 | static int target_pid = -1; |
61 | static int inherit = 0; | ||
61 | static int profile_cpu = -1; | 62 | static int profile_cpu = -1; |
62 | static int nr_cpus = 0; | 63 | static int nr_cpus = 0; |
63 | static unsigned int realtime_prio = 0; | 64 | static unsigned int realtime_prio = 0; |
@@ -66,6 +67,7 @@ static unsigned int page_size; | |||
66 | static unsigned int mmap_pages = 16; | 67 | static unsigned int mmap_pages = 16; |
67 | static int freq = 0; | 68 | static int freq = 0; |
68 | static int verbose = 0; | 69 | static int verbose = 0; |
70 | static char *vmlinux = NULL; | ||
69 | 71 | ||
70 | static char *sym_filter; | 72 | static char *sym_filter; |
71 | static unsigned long filter_start; | 73 | static 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 | ||
272 | static void *display_thread(void *arg) | 264 | static 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. */ | ||
282 | static 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 | |||
289 | static int symbol_filter(struct dso *self, struct symbol *sym) | 294 | static 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) | |||
407 | struct mmap_data { | 420 | struct 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; | |||
538 | static void start_counter(int i, int counter) | 551 | static 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 | ||
552 | try_again: | 566 | try_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 | ||
689 | int cmd_top(int argc, const char **argv, const char *prefix) | 706 | int 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); |