forked from luck/tmp_suning_uos_patched
b1d1b094f7
So that we can remove dso.h from symbol.h and reduce the header dependency tree. Fixup cases where struct dso guts are needed but were obtained via symbol.h, indirectly. Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: https://lkml.kernel.org/n/tip-ip683cegt306ncu3gsz7ii21@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
265 lines
6.3 KiB
C
265 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "gtk.h"
|
|
#include "util/sort.h"
|
|
#include "util/debug.h"
|
|
#include "util/annotate.h"
|
|
#include "util/evsel.h"
|
|
#include "util/map.h"
|
|
#include "util/dso.h"
|
|
#include "util/symbol.h"
|
|
#include "ui/helpline.h"
|
|
#include <inttypes.h>
|
|
#include <signal.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->al.offset == (s64) -1)
|
|
return 0;
|
|
|
|
symhist = annotation__histogram(symbol__annotation(sym), evidx);
|
|
if (!symbol_conf.event_group && !symhist->addr[dl->al.offset].nr_samples)
|
|
return 0;
|
|
|
|
percent = 100.0 * symhist->addr[dl->al.offset].nr_samples / symhist->nr_samples;
|
|
|
|
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->al.offset == (s64) -1)
|
|
return 0;
|
|
|
|
return scnprintf(buf, size, "%"PRIx64, start + dl->al.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->al.line, -1);
|
|
const char *markup = "<span fgcolor='gray'>";
|
|
|
|
strcpy(buf, "");
|
|
|
|
if (!line)
|
|
return 0;
|
|
|
|
if (dl->al.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 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, al.node) {
|
|
GtkTreeIter iter;
|
|
int ret = 0;
|
|
|
|
gtk_list_store_append(store, &iter);
|
|
|
|
if (perf_evsel__is_group_event(evsel)) {
|
|
for (i = 0; i < evsel->core.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, al.node) {
|
|
list_del_init(&pos->al.node);
|
|
disasm_line__free(pos);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
|
|
struct evsel *evsel,
|
|
struct hist_browser_timer *hbt)
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *notebook;
|
|
GtkWidget *scrolled_window;
|
|
GtkWidget *tab_label;
|
|
int err;
|
|
|
|
if (map->dso->annotate_warned)
|
|
return -1;
|
|
|
|
err = symbol__annotate(sym, map, evsel, 0, &annotation__default_options, NULL);
|
|
if (err) {
|
|
char msg[BUFSIZ];
|
|
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
|
|
ui__error("Couldn't annotate %s: %s\n", sym->name, msg);
|
|
return -1;
|
|
}
|
|
|
|
symbol__calc_percent(sym, evsel);
|
|
|
|
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 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);
|
|
}
|