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 166 if (map->dso->annotate_warned) 167 return -1; 168 169 if (symbol__annotate(sym, map, 0) < 0) { 170 ui__error("%s", ui_helpline__current); 171 return -1; 172 } 173 174 if (perf_gtk__is_active_context(pgctx)) { 175 window = pgctx->main_window; 176 notebook = pgctx->notebook; 177 } else { 178 GtkWidget *vbox; 179 GtkWidget *infobar; 180 GtkWidget *statbar; 181 182 signal(SIGSEGV, perf_gtk__signal); 183 signal(SIGFPE, perf_gtk__signal); 184 signal(SIGINT, perf_gtk__signal); 185 signal(SIGQUIT, perf_gtk__signal); 186 signal(SIGTERM, perf_gtk__signal); 187 188 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 189 gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); 190 191 g_signal_connect(window, "delete_event", gtk_main_quit, NULL); 192 193 pgctx = perf_gtk__activate_context(window); 194 if (!pgctx) 195 return -1; 196 197 vbox = gtk_vbox_new(FALSE, 0); 198 notebook = gtk_notebook_new(); 199 pgctx->notebook = notebook; 200 201 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); 202 203 infobar = perf_gtk__setup_info_bar(); 204 if (infobar) { 205 gtk_box_pack_start(GTK_BOX(vbox), infobar, 206 FALSE, FALSE, 0); 207 } 208 209 statbar = perf_gtk__setup_statusbar(); 210 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); 211 212 gtk_container_add(GTK_CONTAINER(window), vbox); 213 } 214 215 scrolled_window = gtk_scrolled_window_new(NULL, NULL); 216 tab_label = gtk_label_new(sym->name); 217 218 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 219 GTK_POLICY_AUTOMATIC, 220 GTK_POLICY_AUTOMATIC); 221 222 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, 223 tab_label); 224 225 perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt); 226 return 0; 227 } 228 229 int hist_entry__gtk_annotate(struct hist_entry *he, 230 struct perf_evsel *evsel, 231 struct hist_browser_timer *hbt) 232 { 233 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); 234 } 235 236 void perf_gtk__show_annotations(void) 237 { 238 GtkWidget *window; 239 240 if (!perf_gtk__is_active_context(pgctx)) 241 return; 242 243 window = pgctx->main_window; 244 gtk_widget_show_all(window); 245 246 perf_gtk__resize_window(window); 247 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 248 249 gtk_main(); 250 251 perf_gtk__deactivate_context(&pgctx); 252 } 253