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