mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 16:11:38 +00:00
perf/core improvements and fixes
User visible: o Prep patches to support 'perf kvm stat' on s390 (Alexander Yarygin) o Add pagefault statistics in 'trace' (Stanislav Fomichev) o Add header for columns in 'top' and 'report' TUI browsers (Jiri Olsa) o Add pagefault statistics in 'trace' (Stanislav Fomichev) Build fixes: Fix build on 32-bit systems (Arnaldo Carvalho de Melo) Cleanups: o Convert open coded equivalents to asprintf() (Andy Shevchenko) Plumbing: o Allow reserving a row for header purposes in the hists browser (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTvEAcAAoJENZQFvNTUqpA/MgP/iv8Qfe464fpsqnUZCAHMEw5 CINVqTagB0xA5ga+UO9sMTuxY6ZEvd7C9eIsTBcuhxx84J7AHMuwaxFB6KnmaDGf 5KyP81nP/lafKO06eiD/ERxi/Y1X6UjB9x5dYtItMVL+uyFRmBzyfFFfjAzju/rR RiC3HdnTm0xiFXKAEQShhVcLb1xpnm49amiFLgz+zK/WTWK1Mo2/jMuEIGFy9F8R zFuVbRuHFYmoFkNAlv5byHbGm+d2mwMZa7jc5hVbkFGb/SxZTMYANUTmYMFEZImU lOo4g6UwdZ/aEO/p/iqWV/mhhV8qTKzgoMhGR239xG/yA6MDqwDrkDKZZz4xHQJZ I5i6/xj3iesViSO8p7nYEZPq3VARPo+93x38snq+fMPTj/beSTlLcWcr7iP+L6EZ 5iJ9lWTLqohpi3Lvla2soqlpS8vwKNspsL6VRzBiGSmp4vLs3KGDCACjIaLA1D0u 4uCrDq68lwR8BT+sE+4AJ2q/7KRU1VM7RC7k9B27OiF8Cb2RXQQ5LpW8i2Er6spV DYfbBCi+Tkgn/Y0Vr9OqnvxvFRtYA1iD6pfWzsDjLovzVcdXwVEs5FtGzfl2A0vB ZriNg2ByudA/K6Yj0jbox7O+aJaYzvOBn9gHTZSuWfnOwOEX0SCDIV8lZaqVWem3 rzy3m/ArvTYyzzW4+W85 =tb1y -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: o Prep patches to support 'perf kvm stat' on s390 (Alexander Yarygin) o Add pagefault statistics in 'trace' (Stanislav Fomichev) o Add header for columns in 'top' and 'report' TUI browsers (Jiri Olsa) o Add pagefault statistics in 'trace' (Stanislav Fomichev) Build fixes: o Fix build on 32-bit systems (Arnaldo Carvalho de Melo) Cleanups: o Convert open coded equivalents to asprintf() (Andy Shevchenko) Plumbing changes: o Allow reserving a row for header purposes in the hists browser (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
f4aa84fc2a
@ -2,3 +2,4 @@ ifndef NO_DWARF
|
||||
PERF_HAVE_DWARF_REGS := 1
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
|
||||
|
28
tools/perf/arch/s390/util/header.c
Normal file
28
tools/perf/arch/s390/util/header.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Implementation of get_cpuid().
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License (version 2 only)
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../util/header.h"
|
||||
|
||||
int get_cpuid(char *buffer, size_t sz)
|
||||
{
|
||||
const char *cpuid = "IBM/S390";
|
||||
|
||||
if (strlen(cpuid) + 1 > sz)
|
||||
return -1;
|
||||
|
||||
strcpy(buffer, cpuid);
|
||||
return 0;
|
||||
}
|
@ -15,3 +15,4 @@ endif
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
|
||||
LIB_H += arch/$(ARCH)/util/tsc.h
|
||||
HAVE_KVM_STAT_SUPPORT := 1
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <pthread.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#ifdef HAVE_KVM_STAT_SUPPORT
|
||||
#include <asm/svm.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <asm/kvm.h>
|
||||
@ -99,7 +99,6 @@ struct perf_kvm_stat {
|
||||
int trace_vcpu;
|
||||
|
||||
struct exit_reasons_table *exit_reasons;
|
||||
int exit_reasons_size;
|
||||
const char *exit_reasons_isa;
|
||||
|
||||
struct kvm_events_ops *events_ops;
|
||||
@ -158,20 +157,19 @@ static bool exit_event_end(struct perf_evsel *evsel,
|
||||
return kvm_entry_event(evsel);
|
||||
}
|
||||
|
||||
static struct exit_reasons_table vmx_exit_reasons[] = {
|
||||
VMX_EXIT_REASONS
|
||||
};
|
||||
#define define_exit_reasons_table(name, symbols) \
|
||||
static struct exit_reasons_table name[] = { \
|
||||
symbols, { -1, NULL } \
|
||||
}
|
||||
|
||||
static struct exit_reasons_table svm_exit_reasons[] = {
|
||||
SVM_EXIT_REASONS
|
||||
};
|
||||
define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
|
||||
define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
|
||||
|
||||
static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
|
||||
static const char *get_exit_reason(struct perf_kvm_stat *kvm,
|
||||
struct exit_reasons_table *tbl,
|
||||
u64 exit_code)
|
||||
{
|
||||
int i = kvm->exit_reasons_size;
|
||||
struct exit_reasons_table *tbl = kvm->exit_reasons;
|
||||
|
||||
while (i--) {
|
||||
while (tbl->reason != NULL) {
|
||||
if (tbl->exit_code == exit_code)
|
||||
return tbl->reason;
|
||||
tbl++;
|
||||
@ -186,7 +184,8 @@ static void exit_event_decode_key(struct perf_kvm_stat *kvm,
|
||||
struct event_key *key,
|
||||
char decode[20])
|
||||
{
|
||||
const char *exit_reason = get_exit_reason(kvm, key->key);
|
||||
const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons,
|
||||
key->key);
|
||||
|
||||
scnprintf(decode, 20, "%s", exit_reason);
|
||||
}
|
||||
@ -836,37 +835,45 @@ static int process_sample_event(struct perf_tool *tool,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
|
||||
{
|
||||
if (strstr(cpuid, "Intel")) {
|
||||
kvm->exit_reasons = vmx_exit_reasons;
|
||||
kvm->exit_reasons_isa = "VMX";
|
||||
} else if (strstr(cpuid, "AMD")) {
|
||||
kvm->exit_reasons = svm_exit_reasons;
|
||||
kvm->exit_reasons_isa = "SVM";
|
||||
} else
|
||||
return -ENOTSUP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_isa_config(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
char buf[64], *cpuid;
|
||||
int err, isa;
|
||||
int err;
|
||||
|
||||
if (kvm->live) {
|
||||
err = get_cpuid(buf, sizeof(buf));
|
||||
if (err != 0) {
|
||||
pr_err("Failed to look up CPU type (Intel or AMD)\n");
|
||||
pr_err("Failed to look up CPU type\n");
|
||||
return err;
|
||||
}
|
||||
cpuid = buf;
|
||||
} else
|
||||
cpuid = kvm->session->header.env.cpuid;
|
||||
|
||||
if (strstr(cpuid, "Intel"))
|
||||
isa = 1;
|
||||
else if (strstr(cpuid, "AMD"))
|
||||
isa = 0;
|
||||
else {
|
||||
if (!cpuid) {
|
||||
pr_err("Failed to look up CPU type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = cpu_isa_init(kvm, cpuid);
|
||||
if (err == -ENOTSUP)
|
||||
pr_err("CPU %s is not supported.\n", cpuid);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (isa == 1) {
|
||||
kvm->exit_reasons = vmx_exit_reasons;
|
||||
kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
|
||||
kvm->exit_reasons_isa = "VMX";
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool verify_vcpu(int vcpu)
|
||||
@ -1585,9 +1592,6 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
|
||||
.report_event = "vmexit",
|
||||
.sort_key = "sample",
|
||||
|
||||
.exit_reasons = svm_exit_reasons,
|
||||
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
|
||||
.exit_reasons_isa = "SVM",
|
||||
};
|
||||
|
||||
if (argc == 1) {
|
||||
@ -1609,7 +1613,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
|
||||
perf_stat:
|
||||
return cmd_stat(argc, argv, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_KVM_STAT_SUPPORT */
|
||||
|
||||
static int __cmd_record(const char *file_name, int argc, const char **argv)
|
||||
{
|
||||
@ -1726,7 +1730,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
return cmd_top(argc, argv, NULL);
|
||||
else if (!strncmp(argv[0], "buildid-list", 12))
|
||||
return __cmd_buildid_list(file_name, argc, argv);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#ifdef HAVE_KVM_STAT_SUPPORT
|
||||
else if (!strncmp(argv[0], "stat", 4))
|
||||
return kvm_cmd_stat(file_name, argc, argv);
|
||||
#endif
|
||||
|
@ -1133,6 +1133,7 @@ struct thread_trace {
|
||||
u64 exit_time;
|
||||
bool entry_pending;
|
||||
unsigned long nr_events;
|
||||
unsigned long pfmaj, pfmin;
|
||||
char *entry_str;
|
||||
double runtime_ms;
|
||||
struct {
|
||||
@ -1787,12 +1788,12 @@ static void print_location(FILE *f, struct perf_sample *sample,
|
||||
fprintf(f, "%s@", al->map->dso->long_name);
|
||||
|
||||
if ((verbose || print_sym) && al->sym)
|
||||
fprintf(f, "%s+0x%lx", al->sym->name,
|
||||
fprintf(f, "%s+0x%" PRIx64, al->sym->name,
|
||||
al->addr - al->sym->start);
|
||||
else if (al->map)
|
||||
fprintf(f, "0x%lx", al->addr);
|
||||
fprintf(f, "0x%" PRIx64, al->addr);
|
||||
else
|
||||
fprintf(f, "0x%lx", sample->addr);
|
||||
fprintf(f, "0x%" PRIx64, sample->addr);
|
||||
}
|
||||
|
||||
static int trace__pgfault(struct trace *trace,
|
||||
@ -1804,8 +1805,20 @@ static int trace__pgfault(struct trace *trace,
|
||||
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
struct addr_location al;
|
||||
char map_type = 'd';
|
||||
struct thread_trace *ttrace;
|
||||
|
||||
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||
ttrace = thread__trace(thread, trace->output);
|
||||
if (ttrace == NULL)
|
||||
return -1;
|
||||
|
||||
if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
|
||||
ttrace->pfmaj++;
|
||||
else
|
||||
ttrace->pfmin++;
|
||||
|
||||
if (trace->summary_only)
|
||||
return 0;
|
||||
|
||||
thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
|
||||
sample->ip, &al);
|
||||
@ -2346,6 +2359,10 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
|
||||
printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
|
||||
printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
|
||||
printed += fprintf(fp, "%.1f%%", ratio);
|
||||
if (ttrace->pfmaj)
|
||||
printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
|
||||
if (ttrace->pfmin)
|
||||
printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
|
||||
printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
|
||||
printed += thread__dump_stats(ttrace, trace, fp);
|
||||
|
||||
|
@ -594,6 +594,10 @@ ifndef NO_LIBNUMA
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef HAVE_KVM_STAT_SUPPORT
|
||||
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
|
||||
endif
|
||||
|
||||
# Among the variables below, these:
|
||||
# perfexecdir
|
||||
# template_dir
|
||||
|
@ -54,6 +54,7 @@
|
||||
#define mb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define wmb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define rmb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define CPUINFO_PROC "vendor_id"
|
||||
#endif
|
||||
|
||||
#ifdef __sh__
|
||||
|
@ -150,7 +150,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
|
||||
while (nd != NULL) {
|
||||
ui_browser__gotorc(browser, row, 0);
|
||||
browser->write(browser, nd, row);
|
||||
if (++row == browser->height)
|
||||
if (++row == browser->rows)
|
||||
break;
|
||||
nd = rb_next(nd);
|
||||
}
|
||||
@ -166,7 +166,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
|
||||
void ui_browser__refresh_dimensions(struct ui_browser *browser)
|
||||
{
|
||||
browser->width = SLtt_Screen_Cols - 1;
|
||||
browser->height = SLtt_Screen_Rows - 2;
|
||||
browser->height = browser->rows = SLtt_Screen_Rows - 2;
|
||||
browser->y = 1;
|
||||
browser->x = 0;
|
||||
}
|
||||
@ -250,7 +250,10 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
|
||||
int err;
|
||||
va_list ap;
|
||||
|
||||
ui_browser__refresh_dimensions(browser);
|
||||
if (browser->refresh_dimensions == NULL)
|
||||
browser->refresh_dimensions = ui_browser__refresh_dimensions;
|
||||
|
||||
browser->refresh_dimensions(browser);
|
||||
|
||||
pthread_mutex_lock(&ui__lock);
|
||||
__ui_browser__show_title(browser, title);
|
||||
@ -367,7 +370,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
|
||||
|
||||
if (key == K_RESIZE) {
|
||||
ui__refresh_dimensions(false);
|
||||
ui_browser__refresh_dimensions(browser);
|
||||
browser->refresh_dimensions(browser);
|
||||
__ui_browser__show_title(browser, browser->title);
|
||||
ui_helpline__puts(browser->helpline);
|
||||
continue;
|
||||
@ -389,7 +392,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
|
||||
if (browser->index == browser->nr_entries - 1)
|
||||
break;
|
||||
++browser->index;
|
||||
if (browser->index == browser->top_idx + browser->height) {
|
||||
if (browser->index == browser->top_idx + browser->rows) {
|
||||
++browser->top_idx;
|
||||
browser->seek(browser, +1, SEEK_CUR);
|
||||
}
|
||||
@ -405,10 +408,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
|
||||
break;
|
||||
case K_PGDN:
|
||||
case ' ':
|
||||
if (browser->top_idx + browser->height > browser->nr_entries - 1)
|
||||
if (browser->top_idx + browser->rows > browser->nr_entries - 1)
|
||||
break;
|
||||
|
||||
offset = browser->height;
|
||||
offset = browser->rows;
|
||||
if (browser->index + offset > browser->nr_entries - 1)
|
||||
offset = browser->nr_entries - 1 - browser->index;
|
||||
browser->index += offset;
|
||||
@ -419,10 +422,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
|
||||
if (browser->top_idx == 0)
|
||||
break;
|
||||
|
||||
if (browser->top_idx < browser->height)
|
||||
if (browser->top_idx < browser->rows)
|
||||
offset = browser->top_idx;
|
||||
else
|
||||
offset = browser->height;
|
||||
offset = browser->rows;
|
||||
|
||||
browser->index -= offset;
|
||||
browser->top_idx -= offset;
|
||||
@ -432,7 +435,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
|
||||
ui_browser__reset_index(browser);
|
||||
break;
|
||||
case K_END:
|
||||
offset = browser->height - 1;
|
||||
offset = browser->rows - 1;
|
||||
if (offset >= browser->nr_entries)
|
||||
offset = browser->nr_entries - 1;
|
||||
|
||||
@ -462,7 +465,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
|
||||
if (!browser->filter || !browser->filter(browser, pos)) {
|
||||
ui_browser__gotorc(browser, row, 0);
|
||||
browser->write(browser, pos, row);
|
||||
if (++row == browser->height)
|
||||
if (++row == browser->rows)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -587,7 +590,7 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
|
||||
if (!browser->filter || !browser->filter(browser, *pos)) {
|
||||
ui_browser__gotorc(browser, row, 0);
|
||||
browser->write(browser, pos, row);
|
||||
if (++row == browser->height)
|
||||
if (++row == browser->rows)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -623,7 +626,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
|
||||
|
||||
SLsmg_set_char_set(1);
|
||||
|
||||
if (start < browser->top_idx + browser->height) {
|
||||
if (start < browser->top_idx + browser->rows) {
|
||||
row = start - browser->top_idx;
|
||||
ui_browser__gotorc(browser, row, column);
|
||||
SLsmg_write_char(SLSMG_LLCORN_CHAR);
|
||||
@ -633,7 +636,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
|
||||
if (row-- == 0)
|
||||
goto out;
|
||||
} else
|
||||
row = browser->height - 1;
|
||||
row = browser->rows - 1;
|
||||
|
||||
if (end > browser->top_idx)
|
||||
end_row = end - browser->top_idx;
|
||||
@ -675,8 +678,8 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
|
||||
} else
|
||||
row = 0;
|
||||
|
||||
if (end >= browser->top_idx + browser->height)
|
||||
end_row = browser->height - 1;
|
||||
if (end >= browser->top_idx + browser->rows)
|
||||
end_row = browser->rows - 1;
|
||||
else
|
||||
end_row = end - browser->top_idx;
|
||||
|
||||
@ -684,7 +687,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
|
||||
SLsmg_draw_vline(end_row - row + 1);
|
||||
|
||||
ui_browser__gotorc(browser, end_row, column);
|
||||
if (end < browser->top_idx + browser->height) {
|
||||
if (end < browser->top_idx + browser->rows) {
|
||||
SLsmg_write_char(SLSMG_LLCORN_CHAR);
|
||||
ui_browser__gotorc(browser, end_row, column + 1);
|
||||
SLsmg_write_char(SLSMG_HLINE_CHAR);
|
||||
|
@ -14,11 +14,12 @@
|
||||
struct ui_browser {
|
||||
u64 index, top_idx;
|
||||
void *top, *entries;
|
||||
u16 y, x, width, height;
|
||||
u16 y, x, width, height, rows;
|
||||
int current_color;
|
||||
void *priv;
|
||||
const char *title;
|
||||
char *helpline;
|
||||
void (*refresh_dimensions)(struct ui_browser *browser);
|
||||
unsigned int (*refresh)(struct ui_browser *browser);
|
||||
void (*write)(struct ui_browser *browser, void *entry, int row);
|
||||
void (*seek)(struct ui_browser *browser, off_t offset, int whence);
|
||||
|
@ -26,6 +26,7 @@ struct hist_browser {
|
||||
struct map_symbol *selection;
|
||||
int print_seq;
|
||||
bool show_dso;
|
||||
bool show_headers;
|
||||
float min_pcnt;
|
||||
u64 nr_non_filtered_entries;
|
||||
u64 nr_callchain_rows;
|
||||
@ -56,11 +57,42 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
|
||||
return nr_entries + hb->nr_callchain_rows;
|
||||
}
|
||||
|
||||
static void hist_browser__refresh_dimensions(struct hist_browser *browser)
|
||||
static void hist_browser__update_rows(struct hist_browser *hb)
|
||||
{
|
||||
struct ui_browser *browser = &hb->b;
|
||||
u16 header_offset = hb->show_headers ? 1 : 0, index_row;
|
||||
|
||||
browser->rows = browser->height - header_offset;
|
||||
/*
|
||||
* Verify if we were at the last line and that line isn't
|
||||
* visibe because we now show the header line(s).
|
||||
*/
|
||||
index_row = browser->index - browser->top_idx;
|
||||
if (index_row >= browser->rows)
|
||||
browser->index -= index_row - browser->rows + 1;
|
||||
}
|
||||
|
||||
static void hist_browser__refresh_dimensions(struct ui_browser *browser)
|
||||
{
|
||||
struct hist_browser *hb = container_of(browser, struct hist_browser, b);
|
||||
|
||||
/* 3 == +/- toggle symbol before actual hist_entry rendering */
|
||||
browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
|
||||
sizeof("[k]"));
|
||||
browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
|
||||
/*
|
||||
* FIXME: Just keeping existing behaviour, but this really should be
|
||||
* before updating browser->width, as it will invalidate the
|
||||
* calculation above. Fix this and the fallout in another
|
||||
* changeset.
|
||||
*/
|
||||
ui_browser__refresh_dimensions(browser);
|
||||
hist_browser__update_rows(hb);
|
||||
}
|
||||
|
||||
static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
|
||||
{
|
||||
u16 header_offset = browser->show_headers ? 1 : 0;
|
||||
|
||||
ui_browser__gotorc(&browser->b, row + header_offset, column);
|
||||
}
|
||||
|
||||
static void hist_browser__reset(struct hist_browser *browser)
|
||||
@ -73,7 +105,7 @@ static void hist_browser__reset(struct hist_browser *browser)
|
||||
|
||||
hist_browser__update_nr_entries(browser);
|
||||
browser->b.nr_entries = hist_browser__nr_entries(browser);
|
||||
hist_browser__refresh_dimensions(browser);
|
||||
hist_browser__refresh_dimensions(&browser->b);
|
||||
ui_browser__reset_index(&browser->b);
|
||||
}
|
||||
|
||||
@ -355,7 +387,6 @@ static int hist_browser__run(struct hist_browser *browser,
|
||||
browser->b.entries = &browser->hists->entries;
|
||||
browser->b.nr_entries = hist_browser__nr_entries(browser);
|
||||
|
||||
hist_browser__refresh_dimensions(browser);
|
||||
hists__browser_title(browser->hists, title, sizeof(title));
|
||||
|
||||
if (ui_browser__show(&browser->b, title,
|
||||
@ -392,10 +423,10 @@ static int hist_browser__run(struct hist_browser *browser,
|
||||
struct hist_entry *h = rb_entry(browser->b.top,
|
||||
struct hist_entry, rb_node);
|
||||
ui_helpline__pop();
|
||||
ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
|
||||
ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
|
||||
seq++, browser->b.nr_entries,
|
||||
browser->hists->nr_entries,
|
||||
browser->b.height,
|
||||
browser->b.rows,
|
||||
browser->b.index,
|
||||
browser->b.top_idx,
|
||||
h->row_offset, h->nr_rows);
|
||||
@ -409,6 +440,10 @@ static int hist_browser__run(struct hist_browser *browser,
|
||||
/* Expand the whole world. */
|
||||
hist_browser__set_folding(browser, true);
|
||||
break;
|
||||
case 'H':
|
||||
browser->show_headers = !browser->show_headers;
|
||||
hist_browser__update_rows(browser);
|
||||
break;
|
||||
case K_ENTER:
|
||||
if (hist_browser__toggle_fold(browser))
|
||||
break;
|
||||
@ -508,13 +543,13 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
|
||||
}
|
||||
|
||||
ui_browser__set_color(&browser->b, color);
|
||||
ui_browser__gotorc(&browser->b, row, 0);
|
||||
hist_browser__gotorc(browser, row, 0);
|
||||
slsmg_write_nstring(" ", offset + extra_offset);
|
||||
slsmg_printf("%c ", folded_sign);
|
||||
slsmg_write_nstring(str, width);
|
||||
free(alloc_str);
|
||||
|
||||
if (++row == browser->b.height)
|
||||
if (++row == browser->b.rows)
|
||||
goto out;
|
||||
do_next:
|
||||
if (folded_sign == '+')
|
||||
@ -527,7 +562,7 @@ do_next:
|
||||
new_level, row, row_offset,
|
||||
is_current_entry);
|
||||
}
|
||||
if (row == browser->b.height)
|
||||
if (row == browser->b.rows)
|
||||
goto out;
|
||||
node = next;
|
||||
}
|
||||
@ -567,13 +602,13 @@ static int hist_browser__show_callchain_node(struct hist_browser *browser,
|
||||
|
||||
s = callchain_list__sym_name(chain, bf, sizeof(bf),
|
||||
browser->show_dso);
|
||||
ui_browser__gotorc(&browser->b, row, 0);
|
||||
hist_browser__gotorc(browser, row, 0);
|
||||
ui_browser__set_color(&browser->b, color);
|
||||
slsmg_write_nstring(" ", offset);
|
||||
slsmg_printf("%c ", folded_sign);
|
||||
slsmg_write_nstring(s, width - 2);
|
||||
|
||||
if (++row == browser->b.height)
|
||||
if (++row == browser->b.rows)
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -602,7 +637,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
|
||||
row += hist_browser__show_callchain_node(browser, node, level,
|
||||
row, row_offset,
|
||||
is_current_entry);
|
||||
if (row == browser->b.height)
|
||||
if (row == browser->b.rows)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -732,7 +767,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||
.ptr = &arg,
|
||||
};
|
||||
|
||||
ui_browser__gotorc(&browser->b, row, 0);
|
||||
hist_browser__gotorc(browser, row, 0);
|
||||
|
||||
perf_hpp__for_each_format(fmt) {
|
||||
if (perf_hpp__should_skip(fmt))
|
||||
@ -776,7 +811,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||
} else
|
||||
--row_offset;
|
||||
|
||||
if (folded_sign == '-' && row != browser->b.height) {
|
||||
if (folded_sign == '-' && row != browser->b.rows) {
|
||||
printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
|
||||
1, row, &row_offset,
|
||||
¤t_entry);
|
||||
@ -787,6 +822,56 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||
return printed;
|
||||
}
|
||||
|
||||
static int advance_hpp_check(struct perf_hpp *hpp, int inc)
|
||||
{
|
||||
advance_hpp(hpp, inc);
|
||||
return hpp->size <= 0;
|
||||
}
|
||||
|
||||
static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
|
||||
{
|
||||
struct perf_hpp dummy_hpp = {
|
||||
.buf = buf,
|
||||
.size = size,
|
||||
};
|
||||
struct perf_hpp_fmt *fmt;
|
||||
size_t ret = 0;
|
||||
|
||||
if (symbol_conf.use_callchain) {
|
||||
ret = scnprintf(buf, size, " ");
|
||||
if (advance_hpp_check(&dummy_hpp, ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
perf_hpp__for_each_format(fmt) {
|
||||
if (perf_hpp__should_skip(fmt))
|
||||
continue;
|
||||
|
||||
/* We need to add the length of the columns header. */
|
||||
perf_hpp__reset_width(fmt, hists);
|
||||
|
||||
ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
|
||||
if (advance_hpp_check(&dummy_hpp, ret))
|
||||
break;
|
||||
|
||||
ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
|
||||
if (advance_hpp_check(&dummy_hpp, ret))
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hist_browser__show_headers(struct hist_browser *browser)
|
||||
{
|
||||
char headers[1024];
|
||||
|
||||
hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
|
||||
ui_browser__gotorc(&browser->b, 0, 0);
|
||||
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
|
||||
slsmg_write_nstring(headers, browser->b.width + 1);
|
||||
}
|
||||
|
||||
static void ui_browser__hists_init_top(struct ui_browser *browser)
|
||||
{
|
||||
if (browser->top == NULL) {
|
||||
@ -800,9 +885,15 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
|
||||
static unsigned int hist_browser__refresh(struct ui_browser *browser)
|
||||
{
|
||||
unsigned row = 0;
|
||||
u16 header_offset = 0;
|
||||
struct rb_node *nd;
|
||||
struct hist_browser *hb = container_of(browser, struct hist_browser, b);
|
||||
|
||||
if (hb->show_headers) {
|
||||
hist_browser__show_headers(hb);
|
||||
header_offset = 1;
|
||||
}
|
||||
|
||||
ui_browser__hists_init_top(browser);
|
||||
|
||||
for (nd = browser->top; nd; nd = rb_next(nd)) {
|
||||
@ -817,11 +908,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
|
||||
continue;
|
||||
|
||||
row += hist_browser__show_entry(hb, h, row);
|
||||
if (row == browser->height)
|
||||
if (row == browser->rows)
|
||||
break;
|
||||
}
|
||||
|
||||
return row;
|
||||
return row + header_offset;
|
||||
}
|
||||
|
||||
static struct rb_node *hists__filter_entries(struct rb_node *nd,
|
||||
@ -1190,8 +1281,10 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
|
||||
if (browser) {
|
||||
browser->hists = hists;
|
||||
browser->b.refresh = hist_browser__refresh;
|
||||
browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
|
||||
browser->b.seek = ui_browser__hists_seek;
|
||||
browser->b.use_navkeypressed = true;
|
||||
browser->show_headers = symbol_conf.show_hist_headers;
|
||||
}
|
||||
|
||||
return browser;
|
||||
@ -1421,6 +1514,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
|
||||
"d Zoom into current DSO\n" \
|
||||
"E Expand all callchains\n" \
|
||||
"F Toggle percentage of filtered entries\n" \
|
||||
"H Display column headers\n" \
|
||||
|
||||
/* help messages are sorted by lexical order of the hotkey */
|
||||
const char report_help[] = HIST_BROWSER_HELP_COMMON
|
||||
|
@ -350,6 +350,16 @@ static int perf_default_core_config(const char *var __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_ui_config(const char *var, const char *value)
|
||||
{
|
||||
/* Add other config variables here. */
|
||||
if (!strcmp(var, "ui.show-headers")) {
|
||||
symbol_conf.show_hist_headers = perf_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_default_config(const char *var, const char *value,
|
||||
void *dummy __maybe_unused)
|
||||
{
|
||||
@ -359,6 +369,9 @@ int perf_default_config(const char *var, const char *value,
|
||||
if (!prefixcmp(var, "hist."))
|
||||
return perf_hist_config(var, value);
|
||||
|
||||
if (!prefixcmp(var, "ui."))
|
||||
return perf_ui_config(var, value);
|
||||
|
||||
/* Add other config variables here. */
|
||||
return 0;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ static int open_file_read(struct perf_data_file *file)
|
||||
goto out_close;
|
||||
|
||||
if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
|
||||
pr_err("file %s not owned by current user or root\n",
|
||||
pr_err("File %s not owned by current user or root (use -f to override)\n",
|
||||
file->path);
|
||||
goto out_close;
|
||||
}
|
||||
|
@ -1215,7 +1215,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
||||
hse = container_of(fmt, struct hpp_sort_entry, hpp);
|
||||
len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
|
||||
|
||||
return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
|
||||
return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
|
||||
}
|
||||
|
||||
static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
|
||||
|
@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
|
||||
.annotate_src = true,
|
||||
.demangle = true,
|
||||
.cumulate_callchain = true,
|
||||
.show_hist_headers = true,
|
||||
.symfs = "",
|
||||
};
|
||||
|
||||
|
@ -118,7 +118,8 @@ struct symbol_conf {
|
||||
annotate_src,
|
||||
event_group,
|
||||
demangle,
|
||||
filter_relative;
|
||||
filter_relative,
|
||||
show_hist_headers;
|
||||
const char *vmlinux_name,
|
||||
*kallsyms_name,
|
||||
*source_prefix,
|
||||
|
@ -191,12 +191,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
|
||||
strcmp(dent->d_name, "..") == 0 ||
|
||||
!name_in_tp_list(dent->d_name, tps))
|
||||
continue;
|
||||
format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
|
||||
if (!format) {
|
||||
if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
sprintf(format, "%s/%s/format", sys, dent->d_name);
|
||||
ret = stat(format, &st);
|
||||
free(format);
|
||||
if (ret < 0)
|
||||
@ -217,12 +215,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
|
||||
strcmp(dent->d_name, "..") == 0 ||
|
||||
!name_in_tp_list(dent->d_name, tps))
|
||||
continue;
|
||||
format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
|
||||
if (!format) {
|
||||
if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
sprintf(format, "%s/%s/format", sys, dent->d_name);
|
||||
ret = stat(format, &st);
|
||||
|
||||
if (ret >= 0) {
|
||||
@ -317,12 +313,10 @@ static int record_event_files(struct tracepoint_path *tps)
|
||||
strcmp(dent->d_name, "ftrace") == 0 ||
|
||||
!system_in_tp_list(dent->d_name, tps))
|
||||
continue;
|
||||
sys = malloc(strlen(path) + strlen(dent->d_name) + 2);
|
||||
if (!sys) {
|
||||
if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
sprintf(sys, "%s/%s", path, dent->d_name);
|
||||
ret = stat(sys, &st);
|
||||
if (ret >= 0) {
|
||||
ssize_t size = strlen(dent->d_name) + 1;
|
||||
|
@ -333,12 +333,9 @@ const char *find_tracing_dir(void)
|
||||
if (!debugfs)
|
||||
return NULL;
|
||||
|
||||
tracing = malloc(strlen(debugfs) + 9);
|
||||
if (!tracing)
|
||||
if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
|
||||
return NULL;
|
||||
|
||||
sprintf(tracing, "%s/tracing", debugfs);
|
||||
|
||||
tracing_found = 1;
|
||||
return tracing;
|
||||
}
|
||||
@ -352,11 +349,9 @@ char *get_tracing_file(const char *name)
|
||||
if (!tracing)
|
||||
return NULL;
|
||||
|
||||
file = malloc(strlen(tracing) + strlen(name) + 2);
|
||||
if (!file)
|
||||
if (asprintf(&file, "%s/%s", tracing, name) < 0)
|
||||
return NULL;
|
||||
|
||||
sprintf(file, "%s/%s", tracing, name);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user