1 #include "gtk.h" 2 #include "util/debug.h" 3 #include "util/annotate.h" 4 #include "util/evsel.h" 5 #include "ui/helpline.h" 6 7 8 enum { 9 ANN_COL__PERCENT, 10 ANN_COL__OFFSET, 11 ANN_COL__LINE, 12 13 MAX_ANN_COLS 14 }; 15 16 static const char *const col_names[] = { 17 "Overhead", 18 "Offset", 19 "Line" 20 }; 21 22 static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, 23 struct disasm_line *dl, int evidx) 24 { 25 struct sym_hist *symhist; 26 double percent = 0.0; 27 const char *markup; 28 int ret = 0; 29 30 strcpy(buf, ""); 31 32 if (dl->offset == (s64) -1) 33 return 0; 34 35 symhist = annotation__histogram(symbol__annotation(sym), evidx); 36 if (!symbol_conf.event_group && !symhist->addr[dl->offset]) 37 return 0; 38 39 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; 40 41 markup = perf_gtk__get_percent_color(percent); 42 if (markup) 43 ret += scnprintf(buf, size, "%s", markup); 44 ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent); 45 if (markup) 46 ret += scnprintf(buf + ret, size - ret, "</span>"); 47 48 return ret; 49 } 50 51 static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym, 52 struct map *map, struct disasm_line *dl) 53 { 54 u64 start = map__rip_2objdump(map, sym->start); 55 56 strcpy(buf, ""); 57 58 if (dl->offset == (s64) -1) 59 return 0; 60 61 return scnprintf(buf, size, "%"PRIx64, start + dl->offset); 62 } 63 64 static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) 65 { 66 int ret = 0; 67 char *line = g_markup_escape_text(dl->line, -1); 68 const char *markup = "<span fgcolor='gray'>"; 69 70 strcpy(buf, ""); 71 72 if (!line) 73 return 0; 74 75 if (dl->offset != (s64) -1) 76 markup = NULL; 77 78 if (markup) 79 ret += scnprintf(buf, size, "%s", markup); 80 ret += scnprintf(buf + ret, size - ret, "%s", line); 81 if (markup) 82 ret += scnprintf(buf + ret, size - ret, "</span>"); 83 84 g_free(line); 85 return ret; 86 } 87 88 static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, 89 struct map *map, struct perf_evsel *evsel, 90 struct hist_browser_timer *hbt __maybe_unused) 91 { 92 struct disasm_line *pos, *n; 93 struct annotation *notes; 94 GType col_types[MAX_ANN_COLS]; 95 GtkCellRenderer *renderer; 96 GtkListStore *store; 97 GtkWidget *view; 98 int i; 99 char s[512]; 100 101 notes = symbol__annotation(sym); 102 103 for (i = 0; i < MAX_ANN_COLS; i++) { 104 col_types[i] = G_TYPE_STRING; 105 } 106 store = gtk_list_store_newv(MAX_ANN_COLS, col_types); 107 108 view = gtk_tree_view_new(); 109 renderer = gtk_cell_renderer_text_new(); 110 111 for (i = 0; i < MAX_ANN_COLS; i++) { 112 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 113 -1, col_names[i], renderer, "markup", 114 i, NULL); 115 } 116 117 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 118 g_object_unref(GTK_TREE_MODEL(store)); 119 120 list_for_each_entry(pos, ¬es->src->source, node) { 121 GtkTreeIter iter; 122 int ret = 0; 123 124 gtk_list_store_append(store, &iter); 125 126 if (perf_evsel__is_group_event(evsel)) { 127 for (i = 0; i < evsel->nr_members; i++) { 128 ret += perf_gtk__get_percent(s + ret, 129 sizeof(s) - ret, 130 sym, pos, 131 evsel->idx + i); 132 ret += scnprintf(s + ret, sizeof(s) - ret, " "); 133 } 134 } else { 135 ret = perf_gtk__get_percent(s, sizeof(s), sym, pos, 136 evsel->idx); 137 } 138 139 if (ret) 140 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); 141 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) 142 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); 143 if (perf_gtk__get_line(s, sizeof(s), pos)) 144 gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1); 145 } 146 147 gtk_container_add(GTK_CONTAINER(window), view); 148 149 list_for_each_entry_safe(pos, n, ¬es->src->source, node) { 150 list_del(&pos->node); 151 disasm_line__free(pos); 152 } 153 154 return 0; 155 } 156 157 static int symbol__gtk_annotate(struct symbol *sym, struct map *map, 158 struct perf_evsel *evsel, 159 struct hist_browser_timer *hbt) 160 { 161 GtkWidget *window; 162 GtkWidget *notebook; 163 GtkWidget *scrolled_window; 164 GtkWidget *tab_label; 165 int err; 166 167 if (map->dso->annotate_warned) 168 return -1; 169 170 err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0); 171 if (err) { 172 char msg[BUFSIZ]; 173 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); 174 ui__error("Couldn't annotate %s: %s\n", sym->name, msg); 175 return -1; 176 } 177 178 if (perf_gtk__is_active_context(pgctx)) { 179 window = pgctx->main_window; 180 notebook = pgctx->notebook; 181 } else { 182 GtkWidget *vbox; 183 GtkWidget *infobar; 184 GtkWidget *statbar; 185 186 signal(SIGSEGV, perf_gtk__signal); 187 signal(SIGFPE, perf_gtk__signal); 188 signal(SIGINT, perf_gtk__signal); 189 signal(SIGQUIT, perf_gtk__signal); 190 signal(SIGTERM, perf_gtk__signal); 191 192 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 193 gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); 194 195 g_signal_connect(window, "delete_event", gtk_main_quit, NULL); 196 197 pgctx = perf_gtk__activate_context(window); 198 if (!pgctx) 199 return -1; 200 201 vbox = gtk_vbox_new(FALSE, 0); 202 notebook = gtk_notebook_new(); 203 pgctx->notebook = notebook; 204 205 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); 206 207 infobar = perf_gtk__setup_info_bar(); 208 if (infobar) { 209 gtk_box_pack_start(GTK_BOX(vbox), infobar, 210 FALSE, FALSE, 0); 211 } 212 213 statbar = perf_gtk__setup_statusbar(); 214 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); 215 216 gtk_container_add(GTK_CONTAINER(window), vbox); 217 } 218 219 scrolled_window = gtk_scrolled_window_new(NULL, NULL); 220 tab_label = gtk_label_new(sym->name); 221 222 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 223 GTK_POLICY_AUTOMATIC, 224 GTK_POLICY_AUTOMATIC); 225 226 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, 227 tab_label); 228 229 perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt); 230 return 0; 231 } 232 233 int hist_entry__gtk_annotate(struct hist_entry *he, 234 struct perf_evsel *evsel, 235 struct hist_browser_timer *hbt) 236 { 237 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); 238 } 239 240 void perf_gtk__show_annotations(void) 241 { 242 GtkWidget *window; 243 244 if (!perf_gtk__is_active_context(pgctx)) 245 return; 246 247 window = pgctx->main_window; 248 gtk_widget_show_all(window); 249 250 perf_gtk__resize_window(window); 251 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 252 253 gtk_main(); 254 255 perf_gtk__deactivate_context(&pgctx); 256 } 257