root/tools/perf/ui/gtk/hists.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __percent_color_snprintf
  2. __HPP_COLOR_PERCENT_FN
  3. perf_gtk__add_callchain_flat
  4. perf_gtk__add_callchain_folded
  5. perf_gtk__add_callchain_graph
  6. perf_gtk__add_callchain
  7. on_row_activated
  8. perf_gtk__show_hists
  9. perf_gtk__add_hierarchy_entries
  10. perf_gtk__show_hierarchy
  11. perf_evlist__gtk_browse_hists

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include "../evlist.h"
   3 #include "../callchain.h"
   4 #include "../evsel.h"
   5 #include "../sort.h"
   6 #include "../hist.h"
   7 #include "../helpline.h"
   8 #include "../string2.h"
   9 #include "gtk.h"
  10 #include <signal.h>
  11 #include <stdlib.h>
  12 #include <linux/string.h>
  13 
  14 #define MAX_COLUMNS                     32
  15 
  16 static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
  17 {
  18         int ret = 0;
  19         int len;
  20         va_list args;
  21         double percent;
  22         const char *markup;
  23         char *buf = hpp->buf;
  24         size_t size = hpp->size;
  25 
  26         va_start(args, fmt);
  27         len = va_arg(args, int);
  28         percent = va_arg(args, double);
  29         va_end(args);
  30 
  31         markup = perf_gtk__get_percent_color(percent);
  32         if (markup)
  33                 ret += scnprintf(buf, size, markup);
  34 
  35         ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
  36 
  37         if (markup)
  38                 ret += scnprintf(buf + ret, size - ret, "</span>");
  39 
  40         return ret;
  41 }
  42 
  43 #define __HPP_COLOR_PERCENT_FN(_type, _field)                                   \
  44 static u64 he_get_##_field(struct hist_entry *he)                               \
  45 {                                                                               \
  46         return he->stat._field;                                                 \
  47 }                                                                               \
  48                                                                                 \
  49 static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,                \
  50                                        struct perf_hpp *hpp,                    \
  51                                        struct hist_entry *he)                   \
  52 {                                                                               \
  53         return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
  54                         __percent_color_snprintf, true);                        \
  55 }
  56 
  57 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                               \
  58 static u64 he_get_acc_##_field(struct hist_entry *he)                           \
  59 {                                                                               \
  60         return he->stat_acc->_field;                                            \
  61 }                                                                               \
  62                                                                                 \
  63 static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,                \
  64                                        struct perf_hpp *hpp,                    \
  65                                        struct hist_entry *he)                   \
  66 {                                                                               \
  67         return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
  68                             __percent_color_snprintf, true);                    \
  69 }
  70 
  71 __HPP_COLOR_PERCENT_FN(overhead, period)
  72 __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
  73 __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
  74 __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
  75 __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
  76 __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
  77 
  78 #undef __HPP_COLOR_PERCENT_FN
  79 
  80 
  81 void perf_gtk__init_hpp(void)
  82 {
  83         perf_hpp__format[PERF_HPP__OVERHEAD].color =
  84                                 perf_gtk__hpp_color_overhead;
  85         perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
  86                                 perf_gtk__hpp_color_overhead_sys;
  87         perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
  88                                 perf_gtk__hpp_color_overhead_us;
  89         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
  90                                 perf_gtk__hpp_color_overhead_guest_sys;
  91         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
  92                                 perf_gtk__hpp_color_overhead_guest_us;
  93         perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
  94                                 perf_gtk__hpp_color_overhead_acc;
  95 }
  96 
  97 static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
  98                                          GtkTreeIter *parent, int col, u64 total)
  99 {
 100         struct rb_node *nd;
 101         bool has_single_node = (rb_first(root) == rb_last(root));
 102 
 103         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
 104                 struct callchain_node *node;
 105                 struct callchain_list *chain;
 106                 GtkTreeIter iter, new_parent;
 107                 bool need_new_parent;
 108 
 109                 node = rb_entry(nd, struct callchain_node, rb_node);
 110 
 111                 new_parent = *parent;
 112                 need_new_parent = !has_single_node;
 113 
 114                 callchain_node__make_parent_list(node);
 115 
 116                 list_for_each_entry(chain, &node->parent_val, list) {
 117                         char buf[128];
 118 
 119                         gtk_tree_store_append(store, &iter, &new_parent);
 120 
 121                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
 122                         gtk_tree_store_set(store, &iter, 0, buf, -1);
 123 
 124                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
 125                         gtk_tree_store_set(store, &iter, col, buf, -1);
 126 
 127                         if (need_new_parent) {
 128                                 /*
 129                                  * Only show the top-most symbol in a callchain
 130                                  * if it's not the only callchain.
 131                                  */
 132                                 new_parent = iter;
 133                                 need_new_parent = false;
 134                         }
 135                 }
 136 
 137                 list_for_each_entry(chain, &node->val, list) {
 138                         char buf[128];
 139 
 140                         gtk_tree_store_append(store, &iter, &new_parent);
 141 
 142                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
 143                         gtk_tree_store_set(store, &iter, 0, buf, -1);
 144 
 145                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
 146                         gtk_tree_store_set(store, &iter, col, buf, -1);
 147 
 148                         if (need_new_parent) {
 149                                 /*
 150                                  * Only show the top-most symbol in a callchain
 151                                  * if it's not the only callchain.
 152                                  */
 153                                 new_parent = iter;
 154                                 need_new_parent = false;
 155                         }
 156                 }
 157         }
 158 }
 159 
 160 static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
 161                                            GtkTreeIter *parent, int col, u64 total)
 162 {
 163         struct rb_node *nd;
 164 
 165         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
 166                 struct callchain_node *node;
 167                 struct callchain_list *chain;
 168                 GtkTreeIter iter;
 169                 char buf[64];
 170                 char *str, *str_alloc = NULL;
 171                 bool first = true;
 172 
 173                 node = rb_entry(nd, struct callchain_node, rb_node);
 174 
 175                 callchain_node__make_parent_list(node);
 176 
 177                 list_for_each_entry(chain, &node->parent_val, list) {
 178                         char name[1024];
 179 
 180                         callchain_list__sym_name(chain, name, sizeof(name), false);
 181 
 182                         if (asprintf(&str, "%s%s%s",
 183                                      first ? "" : str_alloc,
 184                                      first ? "" : symbol_conf.field_sep ?: "; ",
 185                                      name) < 0)
 186                                 return;
 187 
 188                         first = false;
 189                         free(str_alloc);
 190                         str_alloc = str;
 191                 }
 192 
 193                 list_for_each_entry(chain, &node->val, list) {
 194                         char name[1024];
 195 
 196                         callchain_list__sym_name(chain, name, sizeof(name), false);
 197 
 198                         if (asprintf(&str, "%s%s%s",
 199                                      first ? "" : str_alloc,
 200                                      first ? "" : symbol_conf.field_sep ?: "; ",
 201                                      name) < 0)
 202                                 return;
 203 
 204                         first = false;
 205                         free(str_alloc);
 206                         str_alloc = str;
 207                 }
 208 
 209                 gtk_tree_store_append(store, &iter, parent);
 210 
 211                 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
 212                 gtk_tree_store_set(store, &iter, 0, buf, -1);
 213 
 214                 gtk_tree_store_set(store, &iter, col, str, -1);
 215 
 216                 free(str_alloc);
 217         }
 218 }
 219 
 220 static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
 221                                           GtkTreeIter *parent, int col, u64 total)
 222 {
 223         struct rb_node *nd;
 224         bool has_single_node = (rb_first(root) == rb_last(root));
 225 
 226         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
 227                 struct callchain_node *node;
 228                 struct callchain_list *chain;
 229                 GtkTreeIter iter, new_parent;
 230                 bool need_new_parent;
 231                 u64 child_total;
 232 
 233                 node = rb_entry(nd, struct callchain_node, rb_node);
 234 
 235                 new_parent = *parent;
 236                 need_new_parent = !has_single_node && (node->val_nr > 1);
 237 
 238                 list_for_each_entry(chain, &node->val, list) {
 239                         char buf[128];
 240 
 241                         gtk_tree_store_append(store, &iter, &new_parent);
 242 
 243                         callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
 244                         gtk_tree_store_set(store, &iter, 0, buf, -1);
 245 
 246                         callchain_list__sym_name(chain, buf, sizeof(buf), false);
 247                         gtk_tree_store_set(store, &iter, col, buf, -1);
 248 
 249                         if (need_new_parent) {
 250                                 /*
 251                                  * Only show the top-most symbol in a callchain
 252                                  * if it's not the only callchain.
 253                                  */
 254                                 new_parent = iter;
 255                                 need_new_parent = false;
 256                         }
 257                 }
 258 
 259                 if (callchain_param.mode == CHAIN_GRAPH_REL)
 260                         child_total = node->children_hit;
 261                 else
 262                         child_total = total;
 263 
 264                 /* Now 'iter' contains info of the last callchain_list */
 265                 perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
 266                                               child_total);
 267         }
 268 }
 269 
 270 static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
 271                                     GtkTreeIter *parent, int col, u64 total)
 272 {
 273         if (callchain_param.mode == CHAIN_FLAT)
 274                 perf_gtk__add_callchain_flat(root, store, parent, col, total);
 275         else if (callchain_param.mode == CHAIN_FOLDED)
 276                 perf_gtk__add_callchain_folded(root, store, parent, col, total);
 277         else
 278                 perf_gtk__add_callchain_graph(root, store, parent, col, total);
 279 }
 280 
 281 static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
 282                              GtkTreeViewColumn *col __maybe_unused,
 283                              gpointer user_data __maybe_unused)
 284 {
 285         bool expanded = gtk_tree_view_row_expanded(view, path);
 286 
 287         if (expanded)
 288                 gtk_tree_view_collapse_row(view, path);
 289         else
 290                 gtk_tree_view_expand_row(view, path, FALSE);
 291 }
 292 
 293 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
 294                                  float min_pcnt)
 295 {
 296         struct perf_hpp_fmt *fmt;
 297         GType col_types[MAX_COLUMNS];
 298         GtkCellRenderer *renderer;
 299         GtkTreeStore *store;
 300         struct rb_node *nd;
 301         GtkWidget *view;
 302         int col_idx;
 303         int sym_col = -1;
 304         int nr_cols;
 305         char s[512];
 306 
 307         struct perf_hpp hpp = {
 308                 .buf            = s,
 309                 .size           = sizeof(s),
 310         };
 311 
 312         nr_cols = 0;
 313 
 314         hists__for_each_format(hists, fmt)
 315                 col_types[nr_cols++] = G_TYPE_STRING;
 316 
 317         store = gtk_tree_store_newv(nr_cols, col_types);
 318 
 319         view = gtk_tree_view_new();
 320 
 321         renderer = gtk_cell_renderer_text_new();
 322 
 323         col_idx = 0;
 324 
 325         hists__for_each_format(hists, fmt) {
 326                 if (perf_hpp__should_skip(fmt, hists))
 327                         continue;
 328 
 329                 /*
 330                  * XXX no way to determine where symcol column is..
 331                  *     Just use last column for now.
 332                  */
 333                 if (perf_hpp__is_sort_entry(fmt))
 334                         sym_col = col_idx;
 335 
 336                 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
 337                                                             -1, fmt->name,
 338                                                             renderer, "markup",
 339                                                             col_idx++, NULL);
 340         }
 341 
 342         for (col_idx = 0; col_idx < nr_cols; col_idx++) {
 343                 GtkTreeViewColumn *column;
 344 
 345                 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
 346                 gtk_tree_view_column_set_resizable(column, TRUE);
 347 
 348                 if (col_idx == sym_col) {
 349                         gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
 350                                                           column);
 351                 }
 352         }
 353 
 354         gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
 355 
 356         g_object_unref(GTK_TREE_MODEL(store));
 357 
 358         for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
 359                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
 360                 GtkTreeIter iter;
 361                 u64 total = hists__total_period(h->hists);
 362                 float percent;
 363 
 364                 if (h->filtered)
 365                         continue;
 366 
 367                 percent = hist_entry__get_percent_limit(h);
 368                 if (percent < min_pcnt)
 369                         continue;
 370 
 371                 gtk_tree_store_append(store, &iter, NULL);
 372 
 373                 col_idx = 0;
 374 
 375                 hists__for_each_format(hists, fmt) {
 376                         if (perf_hpp__should_skip(fmt, h->hists))
 377                                 continue;
 378 
 379                         if (fmt->color)
 380                                 fmt->color(fmt, &hpp, h);
 381                         else
 382                                 fmt->entry(fmt, &hpp, h);
 383 
 384                         gtk_tree_store_set(store, &iter, col_idx++, s, -1);
 385                 }
 386 
 387                 if (hist_entry__has_callchains(h) &&
 388                     symbol_conf.use_callchain && hists__has(hists, sym)) {
 389                         if (callchain_param.mode == CHAIN_GRAPH_REL)
 390                                 total = symbol_conf.cumulate_callchain ?
 391                                         h->stat_acc->period : h->stat.period;
 392 
 393                         perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
 394                                                 sym_col, total);
 395                 }
 396         }
 397 
 398         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
 399 
 400         g_signal_connect(view, "row-activated",
 401                          G_CALLBACK(on_row_activated), NULL);
 402         gtk_container_add(GTK_CONTAINER(window), view);
 403 }
 404 
 405 static void perf_gtk__add_hierarchy_entries(struct hists *hists,
 406                                             struct rb_root_cached *root,
 407                                             GtkTreeStore *store,
 408                                             GtkTreeIter *parent,
 409                                             struct perf_hpp *hpp,
 410                                             float min_pcnt)
 411 {
 412         int col_idx = 0;
 413         struct rb_node *node;
 414         struct hist_entry *he;
 415         struct perf_hpp_fmt *fmt;
 416         struct perf_hpp_list_node *fmt_node;
 417         u64 total = hists__total_period(hists);
 418         int size;
 419 
 420         for (node = rb_first_cached(root); node; node = rb_next(node)) {
 421                 GtkTreeIter iter;
 422                 float percent;
 423                 char *bf;
 424 
 425                 he = rb_entry(node, struct hist_entry, rb_node);
 426                 if (he->filtered)
 427                         continue;
 428 
 429                 percent = hist_entry__get_percent_limit(he);
 430                 if (percent < min_pcnt)
 431                         continue;
 432 
 433                 gtk_tree_store_append(store, &iter, parent);
 434 
 435                 col_idx = 0;
 436 
 437                 /* the first hpp_list_node is for overhead columns */
 438                 fmt_node = list_first_entry(&hists->hpp_formats,
 439                                             struct perf_hpp_list_node, list);
 440                 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
 441                         if (fmt->color)
 442                                 fmt->color(fmt, hpp, he);
 443                         else
 444                                 fmt->entry(fmt, hpp, he);
 445 
 446                         gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
 447                 }
 448 
 449                 bf = hpp->buf;
 450                 size = hpp->size;
 451                 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
 452                         int ret;
 453 
 454                         if (fmt->color)
 455                                 ret = fmt->color(fmt, hpp, he);
 456                         else
 457                                 ret = fmt->entry(fmt, hpp, he);
 458 
 459                         snprintf(hpp->buf + ret, hpp->size - ret, "  ");
 460                         advance_hpp(hpp, ret + 2);
 461                 }
 462 
 463                 gtk_tree_store_set(store, &iter, col_idx, strim(bf), -1);
 464 
 465                 if (!he->leaf) {
 466                         hpp->buf = bf;
 467                         hpp->size = size;
 468 
 469                         perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
 470                                                         store, &iter, hpp,
 471                                                         min_pcnt);
 472 
 473                         if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
 474                                 char buf[32];
 475                                 GtkTreeIter child;
 476 
 477                                 snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
 478                                          min_pcnt);
 479 
 480                                 gtk_tree_store_append(store, &child, &iter);
 481                                 gtk_tree_store_set(store, &child, col_idx, buf, -1);
 482                         }
 483                 }
 484 
 485                 if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
 486                         if (callchain_param.mode == CHAIN_GRAPH_REL)
 487                                 total = symbol_conf.cumulate_callchain ?
 488                                         he->stat_acc->period : he->stat.period;
 489 
 490                         perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
 491                                                 col_idx, total);
 492                 }
 493         }
 494 
 495 }
 496 
 497 static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
 498                                      float min_pcnt)
 499 {
 500         struct perf_hpp_fmt *fmt;
 501         struct perf_hpp_list_node *fmt_node;
 502         GType col_types[MAX_COLUMNS];
 503         GtkCellRenderer *renderer;
 504         GtkTreeStore *store;
 505         GtkWidget *view;
 506         int col_idx;
 507         int nr_cols = 0;
 508         char s[512];
 509         char buf[512];
 510         bool first_node, first_col;
 511         struct perf_hpp hpp = {
 512                 .buf            = s,
 513                 .size           = sizeof(s),
 514         };
 515 
 516         hists__for_each_format(hists, fmt) {
 517                 if (perf_hpp__is_sort_entry(fmt) ||
 518                     perf_hpp__is_dynamic_entry(fmt))
 519                         break;
 520 
 521                 col_types[nr_cols++] = G_TYPE_STRING;
 522         }
 523         col_types[nr_cols++] = G_TYPE_STRING;
 524 
 525         store = gtk_tree_store_newv(nr_cols, col_types);
 526         view = gtk_tree_view_new();
 527         renderer = gtk_cell_renderer_text_new();
 528 
 529         col_idx = 0;
 530 
 531         /* the first hpp_list_node is for overhead columns */
 532         fmt_node = list_first_entry(&hists->hpp_formats,
 533                                     struct perf_hpp_list_node, list);
 534         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
 535                 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
 536                                                             -1, fmt->name,
 537                                                             renderer, "markup",
 538                                                             col_idx++, NULL);
 539         }
 540 
 541         /* construct merged column header since sort keys share single column */
 542         buf[0] = '\0';
 543         first_node = true;
 544         list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
 545                 if (!first_node)
 546                         strcat(buf, " / ");
 547                 first_node = false;
 548 
 549                 first_col = true;
 550                 perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
 551                         if (perf_hpp__should_skip(fmt, hists))
 552                                 continue;
 553 
 554                         if (!first_col)
 555                                 strcat(buf, "+");
 556                         first_col = false;
 557 
 558                         fmt->header(fmt, &hpp, hists, 0, NULL);
 559                         strcat(buf, strim(hpp.buf));
 560                 }
 561         }
 562 
 563         gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
 564                                                     -1, buf,
 565                                                     renderer, "markup",
 566                                                     col_idx++, NULL);
 567 
 568         for (col_idx = 0; col_idx < nr_cols; col_idx++) {
 569                 GtkTreeViewColumn *column;
 570 
 571                 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
 572                 gtk_tree_view_column_set_resizable(column, TRUE);
 573 
 574                 if (col_idx == 0) {
 575                         gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
 576                                                           column);
 577                 }
 578         }
 579 
 580         gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
 581         g_object_unref(GTK_TREE_MODEL(store));
 582 
 583         perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
 584                                         NULL, &hpp, min_pcnt);
 585 
 586         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
 587 
 588         g_signal_connect(view, "row-activated",
 589                          G_CALLBACK(on_row_activated), NULL);
 590         gtk_container_add(GTK_CONTAINER(window), view);
 591 }
 592 
 593 int perf_evlist__gtk_browse_hists(struct evlist *evlist,
 594                                   const char *help,
 595                                   struct hist_browser_timer *hbt __maybe_unused,
 596                                   float min_pcnt)
 597 {
 598         struct evsel *pos;
 599         GtkWidget *vbox;
 600         GtkWidget *notebook;
 601         GtkWidget *info_bar;
 602         GtkWidget *statbar;
 603         GtkWidget *window;
 604 
 605         signal(SIGSEGV, perf_gtk__signal);
 606         signal(SIGFPE,  perf_gtk__signal);
 607         signal(SIGINT,  perf_gtk__signal);
 608         signal(SIGQUIT, perf_gtk__signal);
 609         signal(SIGTERM, perf_gtk__signal);
 610 
 611         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 612 
 613         gtk_window_set_title(GTK_WINDOW(window), "perf report");
 614 
 615         g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
 616 
 617         pgctx = perf_gtk__activate_context(window);
 618         if (!pgctx)
 619                 return -1;
 620 
 621         vbox = gtk_vbox_new(FALSE, 0);
 622 
 623         notebook = gtk_notebook_new();
 624 
 625         gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
 626 
 627         info_bar = perf_gtk__setup_info_bar();
 628         if (info_bar)
 629                 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
 630 
 631         statbar = perf_gtk__setup_statusbar();
 632         gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
 633 
 634         gtk_container_add(GTK_CONTAINER(window), vbox);
 635 
 636         evlist__for_each_entry(evlist, pos) {
 637                 struct hists *hists = evsel__hists(pos);
 638                 const char *evname = perf_evsel__name(pos);
 639                 GtkWidget *scrolled_window;
 640                 GtkWidget *tab_label;
 641                 char buf[512];
 642                 size_t size = sizeof(buf);
 643 
 644                 if (symbol_conf.event_group) {
 645                         if (!perf_evsel__is_group_leader(pos))
 646                                 continue;
 647 
 648                         if (pos->core.nr_members > 1) {
 649                                 perf_evsel__group_desc(pos, buf, size);
 650                                 evname = buf;
 651                         }
 652                 }
 653 
 654                 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 655 
 656                 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
 657                                                         GTK_POLICY_AUTOMATIC,
 658                                                         GTK_POLICY_AUTOMATIC);
 659 
 660                 if (symbol_conf.report_hierarchy)
 661                         perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
 662                 else
 663                         perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
 664 
 665                 tab_label = gtk_label_new(evname);
 666 
 667                 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
 668         }
 669 
 670         gtk_widget_show_all(window);
 671 
 672         perf_gtk__resize_window(window);
 673 
 674         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 675 
 676         ui_helpline__push(help);
 677 
 678         gtk_main();
 679 
 680         perf_gtk__deactivate_context(&pgctx);
 681 
 682         return 0;
 683 }

/* [<][>][^][v][top][bottom][index][help] */