Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 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" |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 10 | #include "../../annotate.h" |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 11 | #include "../helpline.h" |
| 12 | #include "../libslang.h" |
Arnaldo Carvalho de Melo | c16bfe9 | 2011-02-25 09:30:29 -0300 | [diff] [blame^] | 13 | #include "../util.h" |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 14 | #include "../../evlist.h" |
| 15 | #include "../../hist.h" |
| 16 | #include "../../sort.h" |
| 17 | #include "../../symbol.h" |
| 18 | #include "../../top.h" |
| 19 | |
| 20 | struct perf_top_browser { |
| 21 | struct ui_browser b; |
| 22 | struct rb_root root; |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 23 | struct sym_entry *selection; |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 24 | float sum_ksamples; |
| 25 | int dso_width; |
| 26 | int dso_short_width; |
| 27 | int sym_width; |
| 28 | }; |
| 29 | |
| 30 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) |
| 31 | { |
| 32 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); |
| 33 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); |
| 34 | bool current_entry = ui_browser__is_current_entry(browser, row); |
| 35 | struct symbol *symbol = sym_entry__symbol(syme); |
| 36 | struct perf_top *top = browser->priv; |
| 37 | int width = browser->width; |
| 38 | double pcnt; |
| 39 | |
| 40 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / |
| 41 | top_browser->sum_ksamples)); |
| 42 | ui_browser__set_percent_color(browser, pcnt, current_entry); |
| 43 | |
| 44 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { |
| 45 | slsmg_printf("%20.2f ", syme->weight); |
| 46 | width -= 24; |
| 47 | } else { |
| 48 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); |
| 49 | width -= 23; |
| 50 | } |
| 51 | |
| 52 | slsmg_printf("%4.1f%%", pcnt); |
| 53 | width -= 7; |
| 54 | |
| 55 | if (verbose) { |
| 56 | slsmg_printf(" %016" PRIx64, symbol->start); |
| 57 | width -= 17; |
| 58 | } |
| 59 | |
| 60 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, |
| 61 | symbol->name); |
| 62 | width -= top_browser->sym_width; |
| 63 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? |
| 64 | syme->map->dso->long_name : |
| 65 | syme->map->dso->short_name, width); |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 66 | |
| 67 | if (current_entry) |
| 68 | top_browser->selection = syme; |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) |
| 72 | { |
| 73 | struct perf_top *top = browser->b.priv; |
Arnaldo Carvalho de Melo | 6435a5e | 2011-02-23 07:25:02 -0300 | [diff] [blame] | 74 | u64 top_idx = browser->b.top_idx; |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 75 | |
| 76 | browser->root = RB_ROOT; |
| 77 | browser->b.top = NULL; |
| 78 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); |
| 79 | perf_top__find_widths(top, &browser->root, &browser->dso_width, |
| 80 | &browser->dso_short_width, |
| 81 | &browser->sym_width); |
| 82 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { |
| 83 | browser->dso_width = browser->dso_short_width; |
| 84 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) |
| 85 | browser->sym_width = browser->b.width - browser->dso_width - 29; |
| 86 | } |
Arnaldo Carvalho de Melo | 6435a5e | 2011-02-23 07:25:02 -0300 | [diff] [blame] | 87 | |
| 88 | /* |
| 89 | * Adjust the ui_browser indexes since the entries in the browser->root |
| 90 | * rb_tree may have changed, then seek it from start, so that we get a |
| 91 | * possible new top of the screen. |
| 92 | */ |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 93 | browser->b.nr_entries = top->rb_entries; |
Arnaldo Carvalho de Melo | 6435a5e | 2011-02-23 07:25:02 -0300 | [diff] [blame] | 94 | |
| 95 | if (top_idx >= browser->b.nr_entries) { |
| 96 | if (browser->b.height >= browser->b.nr_entries) |
| 97 | top_idx = browser->b.nr_entries - browser->b.height; |
| 98 | else |
| 99 | top_idx = 0; |
| 100 | } |
| 101 | |
| 102 | if (browser->b.index >= top_idx + browser->b.height) |
| 103 | browser->b.index = top_idx + browser->b.index - browser->b.top_idx; |
| 104 | |
| 105 | if (browser->b.index >= browser->b.nr_entries) |
| 106 | browser->b.index = browser->b.nr_entries - 1; |
| 107 | |
| 108 | browser->b.top_idx = top_idx; |
| 109 | browser->b.seek(&browser->b, top_idx, SEEK_SET); |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 110 | } |
| 111 | |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 112 | static void perf_top_browser__annotate(struct perf_top_browser *browser) |
| 113 | { |
| 114 | struct sym_entry *syme = browser->selection; |
| 115 | struct symbol *sym = sym_entry__symbol(syme); |
| 116 | struct annotation *notes = symbol__annotation(sym); |
| 117 | struct perf_top *top = browser->b.priv; |
| 118 | |
| 119 | if (notes->src != NULL) |
| 120 | goto do_annotation; |
| 121 | |
| 122 | pthread_mutex_lock(¬es->lock); |
| 123 | |
| 124 | top->sym_filter_entry = NULL; |
| 125 | |
| 126 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { |
| 127 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
| 128 | sym->name); |
| 129 | pthread_mutex_unlock(¬es->lock); |
| 130 | return; |
| 131 | } |
| 132 | |
| 133 | top->sym_filter_entry = syme; |
| 134 | |
| 135 | pthread_mutex_unlock(¬es->lock); |
| 136 | do_annotation: |
| 137 | symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); |
| 138 | } |
| 139 | |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 140 | static int perf_top_browser__run(struct perf_top_browser *browser) |
| 141 | { |
| 142 | int key; |
| 143 | char title[160]; |
| 144 | struct perf_top *top = browser->b.priv; |
| 145 | int delay_msecs = top->delay_secs * 1000; |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 146 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 147 | |
| 148 | perf_top_browser__update_rb_tree(browser); |
| 149 | perf_top__header_snprintf(top, title, sizeof(title)); |
| 150 | perf_top__reset_sample_counters(top); |
| 151 | |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 152 | if (ui_browser__show(&browser->b, title, |
| 153 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 154 | return -1; |
| 155 | |
| 156 | newtFormSetTimer(browser->b.form, delay_msecs); |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 157 | ui_browser__add_exit_keys(&browser->b, exit_keys); |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 158 | |
| 159 | while (1) { |
| 160 | key = ui_browser__run(&browser->b); |
| 161 | |
| 162 | switch (key) { |
| 163 | case -1: |
| 164 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ |
| 165 | perf_top_browser__update_rb_tree(browser); |
| 166 | perf_top__header_snprintf(top, title, sizeof(title)); |
| 167 | perf_top__reset_sample_counters(top); |
| 168 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); |
| 169 | SLsmg_gotorc(0, 0); |
| 170 | slsmg_write_nstring(title, browser->b.width); |
| 171 | break; |
Arnaldo Carvalho de Melo | c97cf42 | 2011-02-22 12:02:07 -0300 | [diff] [blame] | 172 | case 'a': |
| 173 | case NEWT_KEY_RIGHT: |
| 174 | case NEWT_KEY_ENTER: |
| 175 | if (browser->selection) |
| 176 | perf_top_browser__annotate(browser); |
| 177 | break; |
Arnaldo Carvalho de Melo | c16bfe9 | 2011-02-25 09:30:29 -0300 | [diff] [blame^] | 178 | case NEWT_KEY_LEFT: |
| 179 | continue; |
| 180 | case NEWT_KEY_ESCAPE: |
| 181 | if (!ui__dialog_yesno("Do you really want to exit?")) |
| 182 | continue; |
| 183 | /* Fall thru */ |
Arnaldo Carvalho de Melo | c0443df | 2011-01-31 18:19:33 -0200 | [diff] [blame] | 184 | default: |
| 185 | goto out; |
| 186 | } |
| 187 | } |
| 188 | out: |
| 189 | ui_browser__hide(&browser->b); |
| 190 | return key; |
| 191 | } |
| 192 | |
| 193 | int perf_top__tui_browser(struct perf_top *top) |
| 194 | { |
| 195 | struct perf_top_browser browser = { |
| 196 | .b = { |
| 197 | .entries = &browser.root, |
| 198 | .refresh = ui_browser__rb_tree_refresh, |
| 199 | .seek = ui_browser__rb_tree_seek, |
| 200 | .write = perf_top_browser__write, |
| 201 | .priv = top, |
| 202 | }, |
| 203 | }; |
| 204 | |
| 205 | ui_helpline__push("Press <- or ESC to exit"); |
| 206 | return perf_top_browser__run(&browser); |
| 207 | } |