1 #include "../evlist.h" 2 #include "../cache.h" 3 #include "../evsel.h" 4 #include "../sort.h" 5 #include "../hist.h" 6 #include "gtk.h" 7 8 #include <signal.h> 9 10 #define MAX_COLUMNS 32 11 12 static void perf_gtk__signal(int sig) 13 { 14 perf_gtk__exit(false); 15 psignal(sig, "perf"); 16 } 17 18 static void perf_gtk__resize_window(GtkWidget *window) 19 { 20 GdkRectangle rect; 21 GdkScreen *screen; 22 int monitor; 23 int height; 24 int width; 25 26 screen = gtk_widget_get_screen(window); 27 28 monitor = gdk_screen_get_monitor_at_window(screen, window->window); 29 30 gdk_screen_get_monitor_geometry(screen, monitor, &rect); 31 32 width = rect.width * 3 / 4; 33 height = rect.height * 3 / 4; 34 35 gtk_window_resize(GTK_WINDOW(window), width, height); 36 } 37 38 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) 39 { 40 GType col_types[MAX_COLUMNS]; 41 GtkCellRenderer *renderer; 42 struct sort_entry *se; 43 GtkListStore *store; 44 struct rb_node *nd; 45 u64 total_period; 46 GtkWidget *view; 47 int col_idx; 48 int nr_cols; 49 50 nr_cols = 0; 51 52 /* The percentage column */ 53 col_types[nr_cols++] = G_TYPE_STRING; 54 55 list_for_each_entry(se, &hist_entry__sort_list, list) { 56 if (se->elide) 57 continue; 58 59 col_types[nr_cols++] = G_TYPE_STRING; 60 } 61 62 store = gtk_list_store_newv(nr_cols, col_types); 63 64 view = gtk_tree_view_new(); 65 66 renderer = gtk_cell_renderer_text_new(); 67 68 col_idx = 0; 69 70 /* The percentage column */ 71 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 72 -1, "Overhead (%)", 73 renderer, "text", 74 col_idx++, NULL); 75 76 list_for_each_entry(se, &hist_entry__sort_list, list) { 77 if (se->elide) 78 continue; 79 80 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 81 -1, se->se_header, 82 renderer, "text", 83 col_idx++, NULL); 84 } 85 86 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 87 88 g_object_unref(GTK_TREE_MODEL(store)); 89 90 total_period = hists->stats.total_period; 91 92 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 93 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 94 GtkTreeIter iter; 95 double percent; 96 char s[512]; 97 98 if (h->filtered) 99 continue; 100 101 gtk_list_store_append(store, &iter); 102 103 col_idx = 0; 104 105 percent = (h->period * 100.0) / total_period; 106 107 snprintf(s, ARRAY_SIZE(s), "%.2f", percent); 108 109 gtk_list_store_set(store, &iter, col_idx++, s, -1); 110 111 list_for_each_entry(se, &hist_entry__sort_list, list) { 112 if (se->elide) 113 continue; 114 115 se->se_snprintf(h, s, ARRAY_SIZE(s), 116 hists__col_len(hists, se->se_width_idx)); 117 118 gtk_list_store_set(store, &iter, col_idx++, s, -1); 119 } 120 } 121 122 gtk_container_add(GTK_CONTAINER(window), view); 123 } 124 125 #ifdef HAVE_GTK_INFO_BAR 126 static GtkWidget *perf_gtk__setup_info_bar(void) 127 { 128 GtkWidget *info_bar; 129 GtkWidget *label; 130 GtkWidget *content_area; 131 132 info_bar = gtk_info_bar_new(); 133 gtk_widget_set_no_show_all(info_bar, TRUE); 134 135 label = gtk_label_new(""); 136 gtk_widget_show(label); 137 138 content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar)); 139 gtk_container_add(GTK_CONTAINER(content_area), label); 140 141 gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK, 142 GTK_RESPONSE_OK); 143 g_signal_connect(info_bar, "response", 144 G_CALLBACK(gtk_widget_hide), NULL); 145 146 pgctx->info_bar = info_bar; 147 pgctx->message_label = label; 148 149 return info_bar; 150 } 151 #endif 152 153 static GtkWidget *perf_gtk__setup_statusbar(void) 154 { 155 GtkWidget *stbar; 156 unsigned ctxid; 157 158 stbar = gtk_statusbar_new(); 159 160 ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar), 161 "perf report"); 162 pgctx->statbar = stbar; 163 pgctx->statbar_ctx_id = ctxid; 164 165 return stbar; 166 } 167 168 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 169 const char *help __used, 170 void (*timer) (void *arg)__used, 171 void *arg __used, int delay_secs __used) 172 { 173 struct perf_evsel *pos; 174 GtkWidget *vbox; 175 GtkWidget *notebook; 176 GtkWidget *info_bar; 177 GtkWidget *statbar; 178 GtkWidget *window; 179 180 signal(SIGSEGV, perf_gtk__signal); 181 signal(SIGFPE, perf_gtk__signal); 182 signal(SIGINT, perf_gtk__signal); 183 signal(SIGQUIT, perf_gtk__signal); 184 signal(SIGTERM, perf_gtk__signal); 185 186 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 187 188 gtk_window_set_title(GTK_WINDOW(window), "perf report"); 189 190 g_signal_connect(window, "delete_event", gtk_main_quit, NULL); 191 192 pgctx = perf_gtk__activate_context(window); 193 if (!pgctx) 194 return -1; 195 196 vbox = gtk_vbox_new(FALSE, 0); 197 198 notebook = gtk_notebook_new(); 199 200 list_for_each_entry(pos, &evlist->entries, node) { 201 struct hists *hists = &pos->hists; 202 const char *evname = perf_evsel__name(pos); 203 GtkWidget *scrolled_window; 204 GtkWidget *tab_label; 205 206 scrolled_window = gtk_scrolled_window_new(NULL, NULL); 207 208 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 209 GTK_POLICY_AUTOMATIC, 210 GTK_POLICY_AUTOMATIC); 211 212 perf_gtk__show_hists(scrolled_window, hists); 213 214 tab_label = gtk_label_new(evname); 215 216 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); 217 } 218 219 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); 220 221 info_bar = perf_gtk__setup_info_bar(); 222 if (info_bar) 223 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); 224 225 statbar = perf_gtk__setup_statusbar(); 226 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); 227 228 gtk_container_add(GTK_CONTAINER(window), vbox); 229 230 gtk_widget_show_all(window); 231 232 perf_gtk__resize_window(window); 233 234 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 235 236 gtk_main(); 237 238 perf_gtk__deactivate_context(&pgctx); 239 240 return 0; 241 } 242