These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / tools / perf / ui / browsers / annotate.c
index e5250eb..d4d7cc2 100644 (file)
@@ -1,7 +1,6 @@
 #include "../../util/util.h"
 #include "../browser.h"
 #include "../helpline.h"
-#include "../libslang.h"
 #include "../ui.h"
 #include "../util.h"
 #include "../../util/annotate.h"
 #include "../../util/evsel.h"
 #include <pthread.h>
 
+struct disasm_line_samples {
+       double          percent;
+       u64             nr;
+};
+
+#define IPC_WIDTH 6
+#define CYCLES_WIDTH 6
+
 struct browser_disasm_line {
-       struct rb_node  rb_node;
-       u32             idx;
-       int             idx_asm;
-       int             jump_sources;
+       struct rb_node                  rb_node;
+       u32                             idx;
+       int                             idx_asm;
+       int                             jump_sources;
        /*
         * actual length of this array is saved on the nr_events field
         * of the struct annotate_browser
         */
-       double          percent[1];
+       struct disasm_line_samples      samples[1];
 };
 
 static struct annotate_browser_opt {
@@ -28,7 +35,8 @@ static struct annotate_browser_opt {
             use_offset,
             jump_arrows,
             show_linenr,
-            show_nr_jumps;
+            show_nr_jumps,
+            show_total_period;
 } annotate_browser__opts = {
        .use_offset     = true,
        .jump_arrows    = true,
@@ -47,6 +55,7 @@ struct annotate_browser {
        int                 max_jump_sources;
        int                 nr_jumps;
        bool                searching_backwards;
+       bool                have_cycles;
        u8                  addr_width;
        u8                  jumps_width;
        u8                  target_width;
@@ -90,6 +99,15 @@ static int annotate_browser__set_jumps_percent_color(struct annotate_browser *br
         return ui_browser__set_color(&browser->b, color);
 }
 
+static int annotate_browser__pcnt_width(struct annotate_browser *ab)
+{
+       int w = 7 * ab->nr_events;
+
+       if (ab->have_cycles)
+               w += IPC_WIDTH + CYCLES_WIDTH;
+       return w;
+}
+
 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
 {
        struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -100,24 +118,46 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                             (!current_entry || (browser->use_navkeypressed &&
                                                 !browser->navkeypressed)));
        int width = browser->width, printed;
-       int i, pcnt_width = 7 * ab->nr_events;
+       int i, pcnt_width = annotate_browser__pcnt_width(ab);
        double percent_max = 0.0;
        char bf[256];
 
        for (i = 0; i < ab->nr_events; i++) {
-               if (bdl->percent[i] > percent_max)
-                       percent_max = bdl->percent[i];
+               if (bdl->samples[i].percent > percent_max)
+                       percent_max = bdl->samples[i].percent;
        }
 
        if (dl->offset != -1 && percent_max != 0.0) {
-               for (i = 0; i < ab->nr_events; i++) {
-                       ui_browser__set_percent_color(browser, bdl->percent[i],
-                                                     current_entry);
-                       slsmg_printf("%6.2f ", bdl->percent[i]);
+               if (percent_max != 0.0) {
+                       for (i = 0; i < ab->nr_events; i++) {
+                               ui_browser__set_percent_color(browser,
+                                                       bdl->samples[i].percent,
+                                                       current_entry);
+                               if (annotate_browser__opts.show_total_period) {
+                                       ui_browser__printf(browser, "%6" PRIu64 " ",
+                                                          bdl->samples[i].nr);
+                               } else {
+                                       ui_browser__printf(browser, "%6.2f ",
+                                                          bdl->samples[i].percent);
+                               }
+                       }
+               } else {
+                       ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
                }
        } else {
                ui_browser__set_percent_color(browser, 0, current_entry);
-               slsmg_write_nstring(" ", pcnt_width);
+               ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
+       }
+       if (ab->have_cycles) {
+               if (dl->ipc)
+                       ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
+               else
+                       ui_browser__write_nstring(browser, " ", IPC_WIDTH);
+               if (dl->cycles)
+                       ui_browser__printf(browser, "%*" PRIu64 " ",
+                                          CYCLES_WIDTH - 1, dl->cycles);
+               else
+                       ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
        }
 
        SLsmg_write_char(' ');
@@ -127,7 +167,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                width += 1;
 
        if (!*dl->line)
-               slsmg_write_nstring(" ", width - pcnt_width);
+               ui_browser__write_nstring(browser, " ", width - pcnt_width);
        else if (dl->offset == -1) {
                if (dl->line_nr && annotate_browser__opts.show_linenr)
                        printed = scnprintf(bf, sizeof(bf), "%-*d ",
@@ -135,8 +175,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                else
                        printed = scnprintf(bf, sizeof(bf), "%*s  ",
                                    ab->addr_width, " ");
-               slsmg_write_nstring(bf, printed);
-               slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
+               ui_browser__write_nstring(browser, bf, printed);
+               ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
        } else {
                u64 addr = dl->offset;
                int color = -1;
@@ -155,7 +195,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                                                            bdl->jump_sources);
                                        prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
                                                                                         current_entry);
-                                       slsmg_write_nstring(bf, printed);
+                                       ui_browser__write_nstring(browser, bf, printed);
                                        ui_browser__set_color(browser, prev);
                                }
 
@@ -169,7 +209,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
 
                if (change_color)
                        color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
-               slsmg_write_nstring(bf, printed);
+               ui_browser__write_nstring(browser, bf, printed);
                if (change_color)
                        ui_browser__set_color(browser, color);
                if (dl->ins && dl->ins->ops->scnprintf) {
@@ -183,11 +223,11 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                                ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
                                SLsmg_write_char(' ');
                        } else {
-                               slsmg_write_nstring(" ", 2);
+                               ui_browser__write_nstring(browser, " ", 2);
                        }
                } else {
                        if (strcmp(dl->name, "retq")) {
-                               slsmg_write_nstring(" ", 2);
+                               ui_browser__write_nstring(browser, " ", 2);
                        } else {
                                ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
                                SLsmg_write_char(' ');
@@ -195,7 +235,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                }
 
                disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
-               slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
+               ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
        }
 
        if (current_entry)
@@ -220,7 +260,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
        unsigned int from, to;
        struct map_symbol *ms = ab->b.priv;
        struct symbol *sym = ms->sym;
-       u8 pcnt_width = 7;
+       u8 pcnt_width = annotate_browser__pcnt_width(ab);
 
        /* PLT symbols contain external offsets */
        if (strstr(sym->name, "@plt"))
@@ -244,8 +284,6 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
                to = (u64)btarget->idx;
        }
 
-       pcnt_width *= ab->nr_events;
-
        ui_browser__set_color(browser, HE_COLORSET_CODE);
        __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
                                 from, to);
@@ -255,9 +293,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser)
 {
        struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
        int ret = ui_browser__list_head_refresh(browser);
-       int pcnt_width;
-
-       pcnt_width = 7 * ab->nr_events;
+       int pcnt_width = annotate_browser__pcnt_width(ab);
 
        if (annotate_browser__opts.jump_arrows)
                annotate_browser__draw_current_jump(browser);
@@ -273,9 +309,9 @@ static int disasm__cmp(struct browser_disasm_line *a,
        int i;
 
        for (i = 0; i < nr_pcnt; i++) {
-               if (a->percent[i] == b->percent[i])
+               if (a->samples[i].percent == b->samples[i].percent)
                        continue;
-               return a->percent[i] < b->percent[i];
+               return a->samples[i].percent < b->samples[i].percent;
        }
        return 0;
 }
@@ -366,17 +402,20 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
                next = disasm__get_next_ip_line(&notes->src->source, pos);
 
                for (i = 0; i < browser->nr_events; i++) {
-                       bpos->percent[i] = disasm__calc_percent(notes,
+                       u64 nr_samples;
+
+                       bpos->samples[i].percent = disasm__calc_percent(notes,
                                                evsel->idx + i,
                                                pos->offset,
                                                next ? next->offset : len,
-                                               &path);
+                                               &path, &nr_samples);
+                       bpos->samples[i].nr = nr_samples;
 
-                       if (max_percent < bpos->percent[i])
-                               max_percent = bpos->percent[i];
+                       if (max_percent < bpos->samples[i].percent)
+                               max_percent = bpos->samples[i].percent;
                }
 
-               if (max_percent < 0.01) {
+               if (max_percent < 0.01 && pos->ipc == 0) {
                        RB_CLEAR_NODE(&bpos->rb_node);
                        continue;
                }
@@ -729,14 +768,15 @@ static int annotate_browser__run(struct annotate_browser *browser,
                "UP/DOWN/PGUP\n"
                "PGDN/SPACE    Navigate\n"
                "q/ESC/CTRL+C  Exit\n\n"
-               "->            Go to target\n"
-               "<-            Exit\n"
+               "ENTER         Go to target\n"
+               "ESC           Exit\n"
                "H             Cycle thru hottest instructions\n"
                "j             Toggle showing jump to target arrows\n"
                "J             Toggle showing number of jump sources on targets\n"
                "n             Search next string\n"
                "o             Toggle disassembler output/simplified view\n"
                "s             Toggle source code view\n"
+               "t             Toggle total period view\n"
                "/             Search string\n"
                "k             Toggle line numbers\n"
                "r             Run available scripts\n"
@@ -812,6 +852,11 @@ show_sup_ins:
                                ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
                        }
                        continue;
+               case 't':
+                       annotate_browser__opts.show_total_period =
+                         !annotate_browser__opts.show_total_period;
+                       annotate_browser__update_addr_width(browser);
+                       continue;
                case K_LEFT:
                case K_ESC:
                case 'q':
@@ -832,15 +877,92 @@ out:
 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
                             struct hist_browser_timer *hbt)
 {
+       /* Set default value for show_total_period.  */
+       annotate_browser__opts.show_total_period =
+         symbol_conf.show_total_period;
+
        return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
 }
 
 int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
                             struct hist_browser_timer *hbt)
 {
+       /* reset abort key so that it can get Ctrl-C as a key */
+       SLang_reset_tty();
+       SLang_init_tty(0, 0, 0);
+
        return map_symbol__tui_annotate(&he->ms, evsel, hbt);
 }
 
+
+static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
+{
+       unsigned n_insn = 0;
+       u64 offset;
+
+       for (offset = start; offset <= end; offset++) {
+               if (browser->offsets[offset])
+                       n_insn++;
+       }
+       return n_insn;
+}
+
+static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
+                          struct cyc_hist *ch)
+{
+       unsigned n_insn;
+       u64 offset;
+
+       n_insn = count_insn(browser, start, end);
+       if (n_insn && ch->num && ch->cycles) {
+               float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
+
+               /* Hide data when there are too many overlaps. */
+               if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
+                       return;
+
+               for (offset = start; offset <= end; offset++) {
+                       struct disasm_line *dl = browser->offsets[offset];
+
+                       if (dl)
+                               dl->ipc = ipc;
+               }
+       }
+}
+
+/*
+ * This should probably be in util/annotate.c to share with the tty
+ * annotate, but right now we need the per byte offsets arrays,
+ * which are only here.
+ */
+static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
+                          struct symbol *sym)
+{
+       u64 offset;
+       struct annotation *notes = symbol__annotation(sym);
+
+       if (!notes->src || !notes->src->cycles_hist)
+               return;
+
+       pthread_mutex_lock(&notes->lock);
+       for (offset = 0; offset < size; ++offset) {
+               struct cyc_hist *ch;
+
+               ch = &notes->src->cycles_hist[offset];
+               if (ch && ch->cycles) {
+                       struct disasm_line *dl;
+
+                       if (ch->have_start)
+                               count_and_fill(browser, ch->start, offset, ch);
+                       dl = browser->offsets[offset];
+                       if (dl && ch->num_aggr)
+                               dl->cycles = ch->cycles_aggr / ch->num_aggr;
+                       browser->have_cycles = true;
+               }
+       }
+       pthread_mutex_unlock(&notes->lock);
+}
+
 static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
                                                size_t size)
 {
@@ -925,7 +1047,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
 
        if (perf_evsel__is_group_event(evsel)) {
                nr_pcnt = evsel->nr_members;
-               sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
+               sizeof_bdl += sizeof(struct disasm_line_samples) *
+                 (nr_pcnt - 1);
        }
 
        if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
@@ -933,7 +1056,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
                goto out_free_offsets;
        }
 
-       ui_helpline__push("Press <- or ESC to exit");
+       ui_helpline__push("Press ESC to exit");
 
        notes = symbol__annotation(sym);
        browser.start = map__rip_2objdump(map, sym->start);
@@ -962,6 +1085,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
        }
 
        annotate_browser__mark_jump_targets(&browser, size);
+       annotate__compute_ipc(&browser, size, sym);
 
        browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
        browser.max_addr_width = hex_width(sym->end);
@@ -1001,6 +1125,7 @@ static struct annotate_config {
        ANNOTATE_CFG(jump_arrows),
        ANNOTATE_CFG(show_linenr),
        ANNOTATE_CFG(show_nr_jumps),
+       ANNOTATE_CFG(show_total_period),
        ANNOTATE_CFG(use_offset),
 };
 
@@ -1027,9 +1152,9 @@ static int annotate__config(const char *var, const char *value,
                      sizeof(struct annotate_config), annotate_config__cmp);
 
        if (cfg == NULL)
-               return -1;
-
-       *cfg->value = perf_config_bool(name, value);
+               ui__warning("%s variable unknown, ignoring...", var);
+       else
+               *cfg->value = perf_config_bool(name, value);
        return 0;
 }