perf_counter tools: Provide helper to print percents color
[safe/jmp/linux-2.6] / tools / perf / builtin-top.c
index 6da30a1..95d5c0a 100644 (file)
@@ -23,7 +23,7 @@
 #include "util/symbol.h"
 #include "util/color.h"
 #include "util/util.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
@@ -54,7 +54,7 @@ static int                    system_wide                     =  0;
 
 static int                     default_interval                = 100000;
 
-static __u64                   count_filter                    =  5;
+static u64                     count_filter                    =  5;
 static int                     print_entries                   = 15;
 
 static int                     target_pid                      = -1;
@@ -65,6 +65,8 @@ static int                    group                           =  0;
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      = 16;
 static int                     freq                            =  0;
+static int                     verbose                         =  0;
+static char                    *vmlinux                        =  NULL;
 
 static char                    *sym_filter;
 static unsigned long           filter_start;
@@ -78,8 +80,8 @@ static int                    dump_symtab;
  * Symbols
  */
 
-static uint64_t                        min_ip;
-static uint64_t                        max_ip = -1ll;
+static u64                     min_ip;
+static u64                     max_ip = -1ll;
 
 struct sym_entry {
        struct rb_node          rb_node;
@@ -193,7 +195,7 @@ static void print_sym_table(void)
                100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
 
        if (nr_counters == 1) {
-               printf("%Ld", attrs[0].sample_period);
+               printf("%Ld", (u64)attrs[0].sample_period);
                if (freq)
                        printf("Hz ");
                else
@@ -237,7 +239,6 @@ static void print_sym_table(void)
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
                struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
                struct symbol *sym = (struct symbol *)(syme + 1);
-               char *color = PERF_COLOR_NORMAL;
                double pcnt;
 
                if (++printed > print_entries || syme->snap_count < count_filter)
@@ -246,26 +247,20 @@ static void print_sym_table(void)
                pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
                                         sum_ksamples));
 
-               /*
-                * We color high-overhead entries in red, low-overhead
-                * entries in green - and keep the middle ground normal:
-                */
-               if (pcnt >= 5.0)
-                       color = PERF_COLOR_RED;
-               if (pcnt < 0.5)
-                       color = PERF_COLOR_GREEN;
-
                if (nr_counters == 1)
                        printf("%20.2f - ", syme->weight);
                else
                        printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
 
-               color_fprintf(stdout, color, "%4.1f%%", pcnt);
-               printf(" - %016llx : %s\n", sym->start, sym->name);
+               percent_color_fprintf(stdout, "%4.1f%%", pcnt);
+               printf(" - %016llx : %s", sym->start, sym->name);
+               if (sym->module)
+                       printf("\t[%s]", sym->module->name);
+               printf("\n");
        }
 }
 
-static void *display_thread(void *arg)
+static void *display_thread(void *arg __used)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
        int delay_msecs = delay_secs * 1000;
@@ -282,11 +277,31 @@ static void *display_thread(void *arg)
        return NULL;
 }
 
+/* Tag samples to be skipped. */
+static const char *skip_symbols[] = {
+       "default_idle",
+       "cpu_idle",
+       "enter_idle",
+       "exit_idle",
+       "mwait_idle",
+       "ppc64_runlatch_off",
+       "pseries_dedicated_idle_sleep",
+       NULL
+};
+
 static int symbol_filter(struct dso *self, struct symbol *sym)
 {
        static int filter_match;
        struct sym_entry *syme;
        const char *name = sym->name;
+       int i;
+
+       /*
+        * ppc64 uses function descriptors and appends a '.' to the
+        * start of every instruction address. Remove it.
+        */
+       if (name[0] == '.')
+               name++;
 
        if (!strcmp(name, "_text") ||
            !strcmp(name, "_etext") ||
@@ -298,13 +313,12 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
                return 1;
 
        syme = dso__sym_priv(self, sym);
-       /* Tag samples to be skipped. */
-       if (!strcmp("default_idle", name) ||
-           !strcmp("cpu_idle", name) ||
-           !strcmp("enter_idle", name) ||
-           !strcmp("exit_idle", name) ||
-           !strcmp("mwait_idle", name))
-               syme->skip = 1;
+       for (i = 0; skip_symbols[i]; i++) {
+               if (!strcmp(skip_symbols[i], name)) {
+                       syme->skip = 1;
+                       break;
+               }
+       }
 
        if (filter_match == 1) {
                filter_end = sym->start;
@@ -336,12 +350,13 @@ static int parse_symbols(void)
 {
        struct rb_node *node;
        struct symbol  *sym;
+       int modules = vmlinux ? 1 : 0;
 
        kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
        if (kernel_dso == NULL)
                return -1;
 
-       if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0)
+       if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
                goto out_delete_dso;
 
        node = rb_first(&kernel_dso->syms);
@@ -368,7 +383,7 @@ out_delete_dso:
 /*
  * Binary search in the histogram table and record the hit:
  */
-static void record_ip(uint64_t ip, int counter)
+static void record_ip(u64 ip, int counter)
 {
        struct symbol *sym = dso__find_symbol(kernel_dso, ip);
 
@@ -388,11 +403,11 @@ static void record_ip(uint64_t ip, int counter)
        samples--;
 }
 
-static void process_event(uint64_t ip, int counter)
+static void process_event(u64 ip, int counter, int user)
 {
        samples++;
 
-       if (ip < min_ip || ip > max_ip) {
+       if (user) {
                userspace_samples++;
                return;
        }
@@ -403,7 +418,7 @@ static void process_event(uint64_t ip, int counter)
 struct mmap_data {
        int                     counter;
        void                    *base;
-       unsigned int            mask;
+       int                     mask;
        unsigned int            prev;
 };
 
@@ -459,15 +474,15 @@ static void mmap_read_counter(struct mmap_data *md)
        for (; old != head;) {
                struct ip_event {
                        struct perf_event_header header;
-                       __u64 ip;
-                       __u32 pid, target_pid;
+                       u64 ip;
+                       u32 pid, target_pid;
                };
                struct mmap_event {
                        struct perf_event_header header;
-                       __u32 pid, target_pid;
-                       __u64 start;
-                       __u64 len;
-                       __u64 pgoff;
+                       u32 pid, target_pid;
+                       u64 start;
+                       u64 len;
+                       u64 pgoff;
                        char filename[PATH_MAX];
                };
 
@@ -505,9 +520,10 @@ static void mmap_read_counter(struct mmap_data *md)
 
                old += size;
 
-               if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
-                       if (event->header.type & PERF_SAMPLE_IP)
-                               process_event(event->ip.ip, md->counter);
+               if (event->header.type == PERF_EVENT_SAMPLE) {
+                       int user =
+       (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
+                       process_event(event->ip.ip, md->counter, user);
                }
        }
 
@@ -550,24 +566,27 @@ try_again:
        if (fd[i][counter] < 0) {
                int err = errno;
 
-               error("sys_perf_counter_open() syscall returned with %d (%s)\n",
-                       fd[i][counter], strerror(err));
-
                if (err == EPERM)
-                       die(" No permission - are you root?\n");
+                       die("No permission - are you root?\n");
                /*
                 * If it's cycles then fall back to hrtimer
                 * based cpu-clock-tick sw counter, which
                 * is always available even if no PMU support:
                 */
                if (attr->type == PERF_TYPE_HARDWARE
-                       && attr->config == PERF_COUNT_CPU_CYCLES) {
+                       && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
+
+                       if (verbose)
+                               warning(" ... trying to fall back to cpu-clock-ticks\n");
 
-                       warning(" ... trying to fall back to cpu-clock-ticks\n");
                        attr->type = PERF_TYPE_SOFTWARE;
-                       attr->config = PERF_COUNT_CPU_CLOCK;
+                       attr->config = PERF_COUNT_SW_CPU_CLOCK;
                        goto try_again;
                }
+               printf("\n");
+               error("perfcounter syscall returned with %d (%s)\n",
+                       fd[i][counter], strerror(err));
+               die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n");
                exit(-1);
        }
        assert(fd[i][counter] >= 0);
@@ -653,6 +672,7 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
+       OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
                    "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -667,19 +687,23 @@ static const struct option options[] = {
                            "put the counters into a counter group"),
        OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
                    "only display symbols matchig this pattern"),
-       OPT_BOOLEAN('z', "zero", &group,
+       OPT_BOOLEAN('z', "zero", &zero,
                    "zero history across updates"),
        OPT_INTEGER('F', "freq", &freq,
                    "profile at this frequency"),
        OPT_INTEGER('E', "entries", &print_entries,
                    "display this many functions"),
+       OPT_BOOLEAN('v', "verbose", &verbose,
+                   "be more verbose (show counter open errors, etc)"),
        OPT_END()
 };
 
-int cmd_top(int argc, const char **argv, const char *prefix)
+int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
+       symbol__init();
+
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);