linux/tools/perf/ui/gtk/hists.c
<<
>>
Prefs
   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
  16static 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)                                   \
  44static u64 he_get_##_field(struct hist_entry *he)                               \
  45{                                                                               \
  46        return he->stat._field;                                                 \
  47}                                                                               \
  48                                                                                \
  49static 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)                               \
  58static u64 he_get_acc_##_field(struct hist_entry *he)                           \
  59{                                                                               \
  60        return he->stat_acc->_field;                                            \
  61}                                                                               \
  62                                                                                \
  63static 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
  81void 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
  97static 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
 160static 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
 220static 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
 270static 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
 281static 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
 293static 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
 405static 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
 497static 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
 593int 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}
 684