mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-30 07:38:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
252
tools/perf/ui/gtk/annotate.c
Normal file
252
tools/perf/ui/gtk/annotate.c
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
#include "gtk.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/annotate.h"
|
||||
#include "util/evsel.h"
|
||||
#include "ui/helpline.h"
|
||||
|
||||
|
||||
enum {
|
||||
ANN_COL__PERCENT,
|
||||
ANN_COL__OFFSET,
|
||||
ANN_COL__LINE,
|
||||
|
||||
MAX_ANN_COLS
|
||||
};
|
||||
|
||||
static const char *const col_names[] = {
|
||||
"Overhead",
|
||||
"Offset",
|
||||
"Line"
|
||||
};
|
||||
|
||||
static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
|
||||
struct disasm_line *dl, int evidx)
|
||||
{
|
||||
struct sym_hist *symhist;
|
||||
double percent = 0.0;
|
||||
const char *markup;
|
||||
int ret = 0;
|
||||
|
||||
strcpy(buf, "");
|
||||
|
||||
if (dl->offset == (s64) -1)
|
||||
return 0;
|
||||
|
||||
symhist = annotation__histogram(symbol__annotation(sym), evidx);
|
||||
if (!symbol_conf.event_group && !symhist->addr[dl->offset])
|
||||
return 0;
|
||||
|
||||
percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
|
||||
|
||||
markup = perf_gtk__get_percent_color(percent);
|
||||
if (markup)
|
||||
ret += scnprintf(buf, size, "%s", markup);
|
||||
ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
|
||||
if (markup)
|
||||
ret += scnprintf(buf + ret, size - ret, "</span>");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
|
||||
struct map *map, struct disasm_line *dl)
|
||||
{
|
||||
u64 start = map__rip_2objdump(map, sym->start);
|
||||
|
||||
strcpy(buf, "");
|
||||
|
||||
if (dl->offset == (s64) -1)
|
||||
return 0;
|
||||
|
||||
return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
|
||||
}
|
||||
|
||||
static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
|
||||
{
|
||||
int ret = 0;
|
||||
char *line = g_markup_escape_text(dl->line, -1);
|
||||
const char *markup = "<span fgcolor='gray'>";
|
||||
|
||||
strcpy(buf, "");
|
||||
|
||||
if (!line)
|
||||
return 0;
|
||||
|
||||
if (dl->offset != (s64) -1)
|
||||
markup = NULL;
|
||||
|
||||
if (markup)
|
||||
ret += scnprintf(buf, size, "%s", markup);
|
||||
ret += scnprintf(buf + ret, size - ret, "%s", line);
|
||||
if (markup)
|
||||
ret += scnprintf(buf + ret, size - ret, "</span>");
|
||||
|
||||
g_free(line);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
|
||||
struct map *map, struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt __maybe_unused)
|
||||
{
|
||||
struct disasm_line *pos, *n;
|
||||
struct annotation *notes;
|
||||
GType col_types[MAX_ANN_COLS];
|
||||
GtkCellRenderer *renderer;
|
||||
GtkListStore *store;
|
||||
GtkWidget *view;
|
||||
int i;
|
||||
char s[512];
|
||||
|
||||
notes = symbol__annotation(sym);
|
||||
|
||||
for (i = 0; i < MAX_ANN_COLS; i++) {
|
||||
col_types[i] = G_TYPE_STRING;
|
||||
}
|
||||
store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
|
||||
|
||||
view = gtk_tree_view_new();
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
|
||||
for (i = 0; i < MAX_ANN_COLS; i++) {
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
|
||||
-1, col_names[i], renderer, "markup",
|
||||
i, NULL);
|
||||
}
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
|
||||
g_object_unref(GTK_TREE_MODEL(store));
|
||||
|
||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
||||
GtkTreeIter iter;
|
||||
int ret = 0;
|
||||
|
||||
gtk_list_store_append(store, &iter);
|
||||
|
||||
if (perf_evsel__is_group_event(evsel)) {
|
||||
for (i = 0; i < evsel->nr_members; i++) {
|
||||
ret += perf_gtk__get_percent(s + ret,
|
||||
sizeof(s) - ret,
|
||||
sym, pos,
|
||||
evsel->idx + i);
|
||||
ret += scnprintf(s + ret, sizeof(s) - ret, " ");
|
||||
}
|
||||
} else {
|
||||
ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
|
||||
evsel->idx);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
|
||||
if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
|
||||
gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
|
||||
if (perf_gtk__get_line(s, sizeof(s), pos))
|
||||
gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
|
||||
}
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), view);
|
||||
|
||||
list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
|
||||
list_del(&pos->node);
|
||||
disasm_line__free(pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
|
||||
struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *notebook;
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *tab_label;
|
||||
|
||||
if (map->dso->annotate_warned)
|
||||
return -1;
|
||||
|
||||
if (symbol__annotate(sym, map, 0) < 0) {
|
||||
ui__error("%s", ui_helpline__current);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_gtk__is_active_context(pgctx)) {
|
||||
window = pgctx->main_window;
|
||||
notebook = pgctx->notebook;
|
||||
} else {
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *infobar;
|
||||
GtkWidget *statbar;
|
||||
|
||||
signal(SIGSEGV, perf_gtk__signal);
|
||||
signal(SIGFPE, perf_gtk__signal);
|
||||
signal(SIGINT, perf_gtk__signal);
|
||||
signal(SIGQUIT, perf_gtk__signal);
|
||||
signal(SIGTERM, perf_gtk__signal);
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
|
||||
|
||||
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
pgctx = perf_gtk__activate_context(window);
|
||||
if (!pgctx)
|
||||
return -1;
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
notebook = gtk_notebook_new();
|
||||
pgctx->notebook = notebook;
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
|
||||
|
||||
infobar = perf_gtk__setup_info_bar();
|
||||
if (infobar) {
|
||||
gtk_box_pack_start(GTK_BOX(vbox), infobar,
|
||||
FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
statbar = perf_gtk__setup_statusbar();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
||||
}
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
||||
tab_label = gtk_label_new(sym->name);
|
||||
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
|
||||
tab_label);
|
||||
|
||||
perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hist_entry__gtk_annotate(struct hist_entry *he,
|
||||
struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt)
|
||||
{
|
||||
return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
|
||||
}
|
||||
|
||||
void perf_gtk__show_annotations(void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
|
||||
if (!perf_gtk__is_active_context(pgctx))
|
||||
return;
|
||||
|
||||
window = pgctx->main_window;
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
perf_gtk__resize_window(window);
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
||||
|
||||
gtk_main();
|
||||
|
||||
perf_gtk__deactivate_context(&pgctx);
|
||||
}
|
||||
87
tools/perf/ui/gtk/browser.c
Normal file
87
tools/perf/ui/gtk/browser.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#include "../evlist.h"
|
||||
#include "../cache.h"
|
||||
#include "../evsel.h"
|
||||
#include "../sort.h"
|
||||
#include "../hist.h"
|
||||
#include "../helpline.h"
|
||||
#include "gtk.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
void perf_gtk__signal(int sig)
|
||||
{
|
||||
perf_gtk__exit(false);
|
||||
psignal(sig, "perf");
|
||||
}
|
||||
|
||||
void perf_gtk__resize_window(GtkWidget *window)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkScreen *screen;
|
||||
int monitor;
|
||||
int height;
|
||||
int width;
|
||||
|
||||
screen = gtk_widget_get_screen(window);
|
||||
|
||||
monitor = gdk_screen_get_monitor_at_window(screen, window->window);
|
||||
|
||||
gdk_screen_get_monitor_geometry(screen, monitor, &rect);
|
||||
|
||||
width = rect.width * 3 / 4;
|
||||
height = rect.height * 3 / 4;
|
||||
|
||||
gtk_window_resize(GTK_WINDOW(window), width, height);
|
||||
}
|
||||
|
||||
const char *perf_gtk__get_percent_color(double percent)
|
||||
{
|
||||
if (percent >= MIN_RED)
|
||||
return "<span fgcolor='red'>";
|
||||
if (percent >= MIN_GREEN)
|
||||
return "<span fgcolor='dark green'>";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GTK_INFO_BAR_SUPPORT
|
||||
GtkWidget *perf_gtk__setup_info_bar(void)
|
||||
{
|
||||
GtkWidget *info_bar;
|
||||
GtkWidget *label;
|
||||
GtkWidget *content_area;
|
||||
|
||||
info_bar = gtk_info_bar_new();
|
||||
gtk_widget_set_no_show_all(info_bar, TRUE);
|
||||
|
||||
label = gtk_label_new("");
|
||||
gtk_widget_show(label);
|
||||
|
||||
content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
|
||||
gtk_container_add(GTK_CONTAINER(content_area), label);
|
||||
|
||||
gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
|
||||
GTK_RESPONSE_OK);
|
||||
g_signal_connect(info_bar, "response",
|
||||
G_CALLBACK(gtk_widget_hide), NULL);
|
||||
|
||||
pgctx->info_bar = info_bar;
|
||||
pgctx->message_label = label;
|
||||
|
||||
return info_bar;
|
||||
}
|
||||
#endif
|
||||
|
||||
GtkWidget *perf_gtk__setup_statusbar(void)
|
||||
{
|
||||
GtkWidget *stbar;
|
||||
unsigned ctxid;
|
||||
|
||||
stbar = gtk_statusbar_new();
|
||||
|
||||
ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
|
||||
"perf report");
|
||||
pgctx->statbar = stbar;
|
||||
pgctx->statbar_ctx_id = ctxid;
|
||||
|
||||
return stbar;
|
||||
}
|
||||
67
tools/perf/ui/gtk/gtk.h
Normal file
67
tools/perf/ui/gtk/gtk.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef _PERF_GTK_H_
|
||||
#define _PERF_GTK_H_ 1
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic error "-Wstrict-prototypes"
|
||||
|
||||
|
||||
struct perf_gtk_context {
|
||||
GtkWidget *main_window;
|
||||
GtkWidget *notebook;
|
||||
|
||||
#ifdef HAVE_GTK_INFO_BAR_SUPPORT
|
||||
GtkWidget *info_bar;
|
||||
GtkWidget *message_label;
|
||||
#endif
|
||||
GtkWidget *statbar;
|
||||
guint statbar_ctx_id;
|
||||
};
|
||||
|
||||
int perf_gtk__init(void);
|
||||
void perf_gtk__exit(bool wait_for_ok);
|
||||
|
||||
extern struct perf_gtk_context *pgctx;
|
||||
|
||||
static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
|
||||
{
|
||||
return ctx && ctx->main_window;
|
||||
}
|
||||
|
||||
struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
|
||||
int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
|
||||
|
||||
void perf_gtk__init_helpline(void);
|
||||
void gtk_ui_progress__init(void);
|
||||
void perf_gtk__init_hpp(void);
|
||||
|
||||
void perf_gtk__signal(int sig);
|
||||
void perf_gtk__resize_window(GtkWidget *window);
|
||||
const char *perf_gtk__get_percent_color(double percent);
|
||||
GtkWidget *perf_gtk__setup_statusbar(void);
|
||||
|
||||
#ifdef HAVE_GTK_INFO_BAR_SUPPORT
|
||||
GtkWidget *perf_gtk__setup_info_bar(void);
|
||||
#else
|
||||
static inline GtkWidget *perf_gtk__setup_info_bar(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct perf_evsel;
|
||||
struct perf_evlist;
|
||||
struct hist_entry;
|
||||
struct hist_browser_timer;
|
||||
|
||||
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
|
||||
struct hist_browser_timer *hbt,
|
||||
float min_pcnt);
|
||||
int hist_entry__gtk_annotate(struct hist_entry *he,
|
||||
struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt);
|
||||
void perf_gtk__show_annotations(void);
|
||||
|
||||
#endif /* _PERF_GTK_H_ */
|
||||
57
tools/perf/ui/gtk/helpline.c
Normal file
57
tools/perf/ui/gtk/helpline.c
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gtk.h"
|
||||
#include "../ui.h"
|
||||
#include "../helpline.h"
|
||||
#include "../../util/debug.h"
|
||||
|
||||
static void gtk_helpline_pop(void)
|
||||
{
|
||||
if (!perf_gtk__is_active_context(pgctx))
|
||||
return;
|
||||
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
|
||||
pgctx->statbar_ctx_id);
|
||||
}
|
||||
|
||||
static void gtk_helpline_push(const char *msg)
|
||||
{
|
||||
if (!perf_gtk__is_active_context(pgctx))
|
||||
return;
|
||||
|
||||
gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
|
||||
pgctx->statbar_ctx_id, msg);
|
||||
}
|
||||
|
||||
static int gtk_helpline_show(const char *fmt, va_list ap)
|
||||
{
|
||||
int ret;
|
||||
char *ptr;
|
||||
static int backlog;
|
||||
|
||||
ret = vscnprintf(ui_helpline__current + backlog,
|
||||
sizeof(ui_helpline__current) - backlog, fmt, ap);
|
||||
backlog += ret;
|
||||
|
||||
/* only first line can be displayed */
|
||||
ptr = strchr(ui_helpline__current, '\n');
|
||||
if (ptr && (ptr - ui_helpline__current) <= backlog) {
|
||||
*ptr = '\0';
|
||||
ui_helpline__puts(ui_helpline__current);
|
||||
backlog = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ui_helpline gtk_helpline_fns = {
|
||||
.pop = gtk_helpline_pop,
|
||||
.push = gtk_helpline_push,
|
||||
.show = gtk_helpline_show,
|
||||
};
|
||||
|
||||
void perf_gtk__init_helpline(void)
|
||||
{
|
||||
helpline_fns = >k_helpline_fns;
|
||||
}
|
||||
365
tools/perf/ui/gtk/hists.c
Normal file
365
tools/perf/ui/gtk/hists.c
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
#include "../evlist.h"
|
||||
#include "../cache.h"
|
||||
#include "../evsel.h"
|
||||
#include "../sort.h"
|
||||
#include "../hist.h"
|
||||
#include "../helpline.h"
|
||||
#include "gtk.h"
|
||||
|
||||
#define MAX_COLUMNS 32
|
||||
|
||||
static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
int len;
|
||||
va_list args;
|
||||
double percent;
|
||||
const char *markup;
|
||||
char *buf = hpp->buf;
|
||||
size_t size = hpp->size;
|
||||
|
||||
va_start(args, fmt);
|
||||
len = va_arg(args, int);
|
||||
percent = va_arg(args, double);
|
||||
va_end(args);
|
||||
|
||||
markup = perf_gtk__get_percent_color(percent);
|
||||
if (markup)
|
||||
ret += scnprintf(buf, size, markup);
|
||||
|
||||
ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
|
||||
|
||||
if (markup)
|
||||
ret += scnprintf(buf + ret, size - ret, "</span>");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define __HPP_COLOR_PERCENT_FN(_type, _field) \
|
||||
static u64 he_get_##_field(struct hist_entry *he) \
|
||||
{ \
|
||||
return he->stat._field; \
|
||||
} \
|
||||
\
|
||||
static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
|
||||
struct perf_hpp *hpp, \
|
||||
struct hist_entry *he) \
|
||||
{ \
|
||||
return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
|
||||
__percent_color_snprintf, true); \
|
||||
}
|
||||
|
||||
#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
|
||||
static u64 he_get_acc_##_field(struct hist_entry *he) \
|
||||
{ \
|
||||
return he->stat_acc->_field; \
|
||||
} \
|
||||
\
|
||||
static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
|
||||
struct perf_hpp *hpp, \
|
||||
struct hist_entry *he) \
|
||||
{ \
|
||||
return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
|
||||
__percent_color_snprintf, true); \
|
||||
}
|
||||
|
||||
__HPP_COLOR_PERCENT_FN(overhead, period)
|
||||
__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
|
||||
__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
|
||||
__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
|
||||
__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
|
||||
__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
|
||||
|
||||
#undef __HPP_COLOR_PERCENT_FN
|
||||
|
||||
|
||||
void perf_gtk__init_hpp(void)
|
||||
{
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD].color =
|
||||
perf_gtk__hpp_color_overhead;
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
|
||||
perf_gtk__hpp_color_overhead_sys;
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
|
||||
perf_gtk__hpp_color_overhead_us;
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
|
||||
perf_gtk__hpp_color_overhead_guest_sys;
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
|
||||
perf_gtk__hpp_color_overhead_guest_us;
|
||||
perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
|
||||
perf_gtk__hpp_color_overhead_acc;
|
||||
}
|
||||
|
||||
static void callchain_list__sym_name(struct callchain_list *cl,
|
||||
char *bf, size_t bfsize)
|
||||
{
|
||||
if (cl->ms.sym)
|
||||
scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
|
||||
else
|
||||
scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
|
||||
}
|
||||
|
||||
static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
|
||||
GtkTreeIter *parent, int col, u64 total)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
bool has_single_node = (rb_first(root) == rb_last(root));
|
||||
|
||||
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
|
||||
struct callchain_node *node;
|
||||
struct callchain_list *chain;
|
||||
GtkTreeIter iter, new_parent;
|
||||
bool need_new_parent;
|
||||
double percent;
|
||||
u64 hits, child_total;
|
||||
|
||||
node = rb_entry(nd, struct callchain_node, rb_node);
|
||||
|
||||
hits = callchain_cumul_hits(node);
|
||||
percent = 100.0 * hits / total;
|
||||
|
||||
new_parent = *parent;
|
||||
need_new_parent = !has_single_node && (node->val_nr > 1);
|
||||
|
||||
list_for_each_entry(chain, &node->val, list) {
|
||||
char buf[128];
|
||||
|
||||
gtk_tree_store_append(store, &iter, &new_parent);
|
||||
|
||||
scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
|
||||
gtk_tree_store_set(store, &iter, 0, buf, -1);
|
||||
|
||||
callchain_list__sym_name(chain, buf, sizeof(buf));
|
||||
gtk_tree_store_set(store, &iter, col, buf, -1);
|
||||
|
||||
if (need_new_parent) {
|
||||
/*
|
||||
* Only show the top-most symbol in a callchain
|
||||
* if it's not the only callchain.
|
||||
*/
|
||||
new_parent = iter;
|
||||
need_new_parent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (callchain_param.mode == CHAIN_GRAPH_REL)
|
||||
child_total = node->children_hit;
|
||||
else
|
||||
child_total = total;
|
||||
|
||||
/* Now 'iter' contains info of the last callchain_list */
|
||||
perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
|
||||
child_total);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
|
||||
GtkTreeViewColumn *col __maybe_unused,
|
||||
gpointer user_data __maybe_unused)
|
||||
{
|
||||
bool expanded = gtk_tree_view_row_expanded(view, path);
|
||||
|
||||
if (expanded)
|
||||
gtk_tree_view_collapse_row(view, path);
|
||||
else
|
||||
gtk_tree_view_expand_row(view, path, FALSE);
|
||||
}
|
||||
|
||||
static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
|
||||
float min_pcnt)
|
||||
{
|
||||
struct perf_hpp_fmt *fmt;
|
||||
GType col_types[MAX_COLUMNS];
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeStore *store;
|
||||
struct rb_node *nd;
|
||||
GtkWidget *view;
|
||||
int col_idx;
|
||||
int sym_col = -1;
|
||||
int nr_cols;
|
||||
char s[512];
|
||||
|
||||
struct perf_hpp hpp = {
|
||||
.buf = s,
|
||||
.size = sizeof(s),
|
||||
};
|
||||
|
||||
nr_cols = 0;
|
||||
|
||||
perf_hpp__for_each_format(fmt)
|
||||
col_types[nr_cols++] = G_TYPE_STRING;
|
||||
|
||||
store = gtk_tree_store_newv(nr_cols, col_types);
|
||||
|
||||
view = gtk_tree_view_new();
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
|
||||
col_idx = 0;
|
||||
|
||||
perf_hpp__for_each_format(fmt) {
|
||||
if (perf_hpp__should_skip(fmt))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* XXX no way to determine where symcol column is..
|
||||
* Just use last column for now.
|
||||
*/
|
||||
if (perf_hpp__is_sort_entry(fmt))
|
||||
sym_col = col_idx;
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
|
||||
-1, fmt->name,
|
||||
renderer, "markup",
|
||||
col_idx++, NULL);
|
||||
}
|
||||
|
||||
for (col_idx = 0; col_idx < nr_cols; col_idx++) {
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
|
||||
gtk_tree_view_column_set_resizable(column, TRUE);
|
||||
|
||||
if (col_idx == sym_col) {
|
||||
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
|
||||
column);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
|
||||
|
||||
g_object_unref(GTK_TREE_MODEL(store));
|
||||
|
||||
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
GtkTreeIter iter;
|
||||
u64 total = hists__total_period(h->hists);
|
||||
float percent;
|
||||
|
||||
if (h->filtered)
|
||||
continue;
|
||||
|
||||
percent = hist_entry__get_percent_limit(h);
|
||||
if (percent < min_pcnt)
|
||||
continue;
|
||||
|
||||
gtk_tree_store_append(store, &iter, NULL);
|
||||
|
||||
col_idx = 0;
|
||||
|
||||
perf_hpp__for_each_format(fmt) {
|
||||
if (perf_hpp__should_skip(fmt))
|
||||
continue;
|
||||
|
||||
if (fmt->color)
|
||||
fmt->color(fmt, &hpp, h);
|
||||
else
|
||||
fmt->entry(fmt, &hpp, h);
|
||||
|
||||
gtk_tree_store_set(store, &iter, col_idx++, s, -1);
|
||||
}
|
||||
|
||||
if (symbol_conf.use_callchain && sort__has_sym) {
|
||||
if (callchain_param.mode == CHAIN_GRAPH_REL)
|
||||
total = symbol_conf.cumulate_callchain ?
|
||||
h->stat_acc->period : h->stat.period;
|
||||
|
||||
perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
|
||||
sym_col, total);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
|
||||
|
||||
g_signal_connect(view, "row-activated",
|
||||
G_CALLBACK(on_row_activated), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(window), view);
|
||||
}
|
||||
|
||||
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
||||
const char *help,
|
||||
struct hist_browser_timer *hbt __maybe_unused,
|
||||
float min_pcnt)
|
||||
{
|
||||
struct perf_evsel *pos;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *notebook;
|
||||
GtkWidget *info_bar;
|
||||
GtkWidget *statbar;
|
||||
GtkWidget *window;
|
||||
|
||||
signal(SIGSEGV, perf_gtk__signal);
|
||||
signal(SIGFPE, perf_gtk__signal);
|
||||
signal(SIGINT, perf_gtk__signal);
|
||||
signal(SIGQUIT, perf_gtk__signal);
|
||||
signal(SIGTERM, perf_gtk__signal);
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(window), "perf report");
|
||||
|
||||
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
pgctx = perf_gtk__activate_context(window);
|
||||
if (!pgctx)
|
||||
return -1;
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
|
||||
notebook = gtk_notebook_new();
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
|
||||
|
||||
info_bar = perf_gtk__setup_info_bar();
|
||||
if (info_bar)
|
||||
gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
|
||||
|
||||
statbar = perf_gtk__setup_statusbar();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
||||
|
||||
evlist__for_each(evlist, pos) {
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
const char *evname = perf_evsel__name(pos);
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *tab_label;
|
||||
char buf[512];
|
||||
size_t size = sizeof(buf);
|
||||
|
||||
if (symbol_conf.event_group) {
|
||||
if (!perf_evsel__is_group_leader(pos))
|
||||
continue;
|
||||
|
||||
if (pos->nr_members > 1) {
|
||||
perf_evsel__group_desc(pos, buf, size);
|
||||
evname = buf;
|
||||
}
|
||||
}
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
||||
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
|
||||
perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
|
||||
|
||||
tab_label = gtk_label_new(evname);
|
||||
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
|
||||
}
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
perf_gtk__resize_window(window);
|
||||
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
||||
|
||||
ui_helpline__push(help);
|
||||
|
||||
gtk_main();
|
||||
|
||||
perf_gtk__deactivate_context(&pgctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
59
tools/perf/ui/gtk/progress.c
Normal file
59
tools/perf/ui/gtk/progress.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include "gtk.h"
|
||||
#include "../progress.h"
|
||||
#include "util.h"
|
||||
|
||||
static GtkWidget *dialog;
|
||||
static GtkWidget *progress;
|
||||
|
||||
static void gtk_ui_progress__update(struct ui_progress *p)
|
||||
{
|
||||
double fraction = p->total ? 1.0 * p->curr / p->total : 0.0;
|
||||
char buf[1024];
|
||||
|
||||
if (dialog == NULL) {
|
||||
GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
|
||||
GtkWidget *label = gtk_label_new(p->title);
|
||||
|
||||
dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
progress = gtk_progress_bar_new();
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 3);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(dialog), vbox);
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), "perf");
|
||||
gtk_window_resize(GTK_WINDOW(dialog), 300, 80);
|
||||
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
|
||||
|
||||
gtk_widget_show_all(dialog);
|
||||
}
|
||||
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
|
||||
snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, p->curr, p->total);
|
||||
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
|
||||
|
||||
/* we didn't call gtk_main yet, so do it manually */
|
||||
while (gtk_events_pending())
|
||||
gtk_main_iteration();
|
||||
}
|
||||
|
||||
static void gtk_ui_progress__finish(void)
|
||||
{
|
||||
/* this will also destroy all of its children */
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
dialog = NULL;
|
||||
}
|
||||
|
||||
static struct ui_progress_ops gtk_ui_progress__ops = {
|
||||
.update = gtk_ui_progress__update,
|
||||
.finish = gtk_ui_progress__finish,
|
||||
};
|
||||
|
||||
void gtk_ui_progress__init(void)
|
||||
{
|
||||
ui_progress__ops = >k_ui_progress__ops;
|
||||
}
|
||||
23
tools/perf/ui/gtk/setup.c
Normal file
23
tools/perf/ui/gtk/setup.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "gtk.h"
|
||||
#include "../../util/cache.h"
|
||||
#include "../../util/debug.h"
|
||||
|
||||
extern struct perf_error_ops perf_gtk_eops;
|
||||
|
||||
int perf_gtk__init(void)
|
||||
{
|
||||
perf_error__register(&perf_gtk_eops);
|
||||
perf_gtk__init_helpline();
|
||||
gtk_ui_progress__init();
|
||||
perf_gtk__init_hpp();
|
||||
|
||||
return gtk_init_check(NULL, NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
void perf_gtk__exit(bool wait_for_ok __maybe_unused)
|
||||
{
|
||||
if (!perf_gtk__is_active_context(pgctx))
|
||||
return;
|
||||
perf_error__unregister(&perf_gtk_eops);
|
||||
gtk_main_quit();
|
||||
}
|
||||
112
tools/perf/ui/gtk/util.c
Normal file
112
tools/perf/ui/gtk/util.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include "../util.h"
|
||||
#include "../../util/debug.h"
|
||||
#include "gtk.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct perf_gtk_context *pgctx;
|
||||
|
||||
struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
|
||||
{
|
||||
struct perf_gtk_context *ctx;
|
||||
|
||||
ctx = malloc(sizeof(*pgctx));
|
||||
if (ctx)
|
||||
ctx->main_window = window;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
|
||||
{
|
||||
if (!perf_gtk__is_active_context(*ctx))
|
||||
return -1;
|
||||
|
||||
zfree(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_gtk__error(const char *format, va_list args)
|
||||
{
|
||||
char *msg;
|
||||
GtkWidget *dialog;
|
||||
|
||||
if (!perf_gtk__is_active_context(pgctx) ||
|
||||
vasprintf(&msg, format, args) < 0) {
|
||||
fprintf(stderr, "Error:\n");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"<b>Error</b>\n\n%s", msg);
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GTK_INFO_BAR_SUPPORT
|
||||
static int perf_gtk__warning_info_bar(const char *format, va_list args)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
if (!perf_gtk__is_active_context(pgctx) ||
|
||||
vasprintf(&msg, format, args) < 0) {
|
||||
fprintf(stderr, "Warning:\n");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
|
||||
gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
|
||||
GTK_MESSAGE_WARNING);
|
||||
gtk_widget_show(pgctx->info_bar);
|
||||
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int perf_gtk__warning_statusbar(const char *format, va_list args)
|
||||
{
|
||||
char *msg, *p;
|
||||
|
||||
if (!perf_gtk__is_active_context(pgctx) ||
|
||||
vasprintf(&msg, format, args) < 0) {
|
||||
fprintf(stderr, "Warning:\n");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
|
||||
pgctx->statbar_ctx_id);
|
||||
|
||||
/* Only first line can be displayed */
|
||||
p = strchr(msg, '\n');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
|
||||
pgctx->statbar_ctx_id, msg);
|
||||
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct perf_error_ops perf_gtk_eops = {
|
||||
.error = perf_gtk__error,
|
||||
#ifdef HAVE_GTK_INFO_BAR_SUPPORT
|
||||
.warning = perf_gtk__warning_info_bar,
|
||||
#else
|
||||
.warning = perf_gtk__warning_statusbar,
|
||||
#endif
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue