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:
Ingo Molnar 2014-07-16 13:46:34 +02:00
Родитель fbe26abe11 4414a3c510
Коммит f4aa84fc2a
17 изменённых файлов: 250 добавлений и 92 удалений

Просмотреть файл

@ -2,3 +2,4 @@ ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1 PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o

Просмотреть файл

@ -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/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
LIB_H += arch/$(ARCH)/util/tsc.h LIB_H += arch/$(ARCH)/util/tsc.h
HAVE_KVM_STAT_SUPPORT := 1

Просмотреть файл

@ -29,7 +29,7 @@
#include <pthread.h> #include <pthread.h>
#include <math.h> #include <math.h>
#if defined(__i386__) || defined(__x86_64__) #ifdef HAVE_KVM_STAT_SUPPORT
#include <asm/svm.h> #include <asm/svm.h>
#include <asm/vmx.h> #include <asm/vmx.h>
#include <asm/kvm.h> #include <asm/kvm.h>
@ -99,7 +99,6 @@ struct perf_kvm_stat {
int trace_vcpu; int trace_vcpu;
struct exit_reasons_table *exit_reasons; struct exit_reasons_table *exit_reasons;
int exit_reasons_size;
const char *exit_reasons_isa; const char *exit_reasons_isa;
struct kvm_events_ops *events_ops; struct kvm_events_ops *events_ops;
@ -158,20 +157,19 @@ static bool exit_event_end(struct perf_evsel *evsel,
return kvm_entry_event(evsel); return kvm_entry_event(evsel);
} }
static struct exit_reasons_table vmx_exit_reasons[] = { #define define_exit_reasons_table(name, symbols) \
VMX_EXIT_REASONS static struct exit_reasons_table name[] = { \
}; symbols, { -1, NULL } \
}
static struct exit_reasons_table svm_exit_reasons[] = { define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
SVM_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; while (tbl->reason != NULL) {
struct exit_reasons_table *tbl = kvm->exit_reasons;
while (i--) {
if (tbl->exit_code == exit_code) if (tbl->exit_code == exit_code)
return tbl->reason; return tbl->reason;
tbl++; tbl++;
@ -186,7 +184,8 @@ static void exit_event_decode_key(struct perf_kvm_stat *kvm,
struct event_key *key, struct event_key *key,
char decode[20]) 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); scnprintf(decode, 20, "%s", exit_reason);
} }
@ -836,37 +835,45 @@ static int process_sample_event(struct perf_tool *tool,
return 0; 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) static int cpu_isa_config(struct perf_kvm_stat *kvm)
{ {
char buf[64], *cpuid; char buf[64], *cpuid;
int err, isa; int err;
if (kvm->live) { if (kvm->live) {
err = get_cpuid(buf, sizeof(buf)); err = get_cpuid(buf, sizeof(buf));
if (err != 0) { 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; return err;
} }
cpuid = buf; cpuid = buf;
} else } else
cpuid = kvm->session->header.env.cpuid; cpuid = kvm->session->header.env.cpuid;
if (strstr(cpuid, "Intel")) if (!cpuid) {
isa = 1; pr_err("Failed to look up CPU type\n");
else if (strstr(cpuid, "AMD")) return -EINVAL;
isa = 0; }
else {
err = cpu_isa_init(kvm, cpuid);
if (err == -ENOTSUP)
pr_err("CPU %s is not supported.\n", cpuid); pr_err("CPU %s is not supported.\n", cpuid);
return -ENOTSUP;
}
if (isa == 1) { return err;
kvm->exit_reasons = vmx_exit_reasons;
kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
kvm->exit_reasons_isa = "VMX";
}
return 0;
} }
static bool verify_vcpu(int vcpu) 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", .report_event = "vmexit",
.sort_key = "sample", .sort_key = "sample",
.exit_reasons = svm_exit_reasons,
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
.exit_reasons_isa = "SVM",
}; };
if (argc == 1) { if (argc == 1) {
@ -1609,7 +1613,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
perf_stat: perf_stat:
return cmd_stat(argc, argv, NULL); 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) 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); return cmd_top(argc, argv, NULL);
else if (!strncmp(argv[0], "buildid-list", 12)) else if (!strncmp(argv[0], "buildid-list", 12))
return __cmd_buildid_list(file_name, argc, argv); 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)) else if (!strncmp(argv[0], "stat", 4))
return kvm_cmd_stat(file_name, argc, argv); return kvm_cmd_stat(file_name, argc, argv);
#endif #endif

Просмотреть файл

@ -1133,6 +1133,7 @@ struct thread_trace {
u64 exit_time; u64 exit_time;
bool entry_pending; bool entry_pending;
unsigned long nr_events; unsigned long nr_events;
unsigned long pfmaj, pfmin;
char *entry_str; char *entry_str;
double runtime_ms; double runtime_ms;
struct { struct {
@ -1787,12 +1788,12 @@ static void print_location(FILE *f, struct perf_sample *sample,
fprintf(f, "%s@", al->map->dso->long_name); fprintf(f, "%s@", al->map->dso->long_name);
if ((verbose || print_sym) && al->sym) 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); al->addr - al->sym->start);
else if (al->map) else if (al->map)
fprintf(f, "0x%lx", al->addr); fprintf(f, "0x%" PRIx64, al->addr);
else else
fprintf(f, "0x%lx", sample->addr); fprintf(f, "0x%" PRIx64, sample->addr);
} }
static int trace__pgfault(struct trace *trace, 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; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct addr_location al; struct addr_location al;
char map_type = 'd'; char map_type = 'd';
struct thread_trace *ttrace;
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 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, thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
sample->ip, &al); 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, " %s (%d), ", thread__comm_str(thread), thread->tid);
printed += fprintf(fp, "%lu events, ", ttrace->nr_events); printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
printed += fprintf(fp, "%.1f%%", ratio); 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 += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
printed += thread__dump_stats(ttrace, trace, fp); printed += thread__dump_stats(ttrace, trace, fp);

Просмотреть файл

@ -594,6 +594,10 @@ ifndef NO_LIBNUMA
endif endif
endif endif
ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif
# Among the variables below, these: # Among the variables below, these:
# perfexecdir # perfexecdir
# template_dir # template_dir

Просмотреть файл

@ -54,6 +54,7 @@
#define mb() asm volatile("bcr 15,0" ::: "memory") #define mb() asm volatile("bcr 15,0" ::: "memory")
#define wmb() asm volatile("bcr 15,0" ::: "memory") #define wmb() asm volatile("bcr 15,0" ::: "memory")
#define rmb() asm volatile("bcr 15,0" ::: "memory") #define rmb() asm volatile("bcr 15,0" ::: "memory")
#define CPUINFO_PROC "vendor_id"
#endif #endif
#ifdef __sh__ #ifdef __sh__

Просмотреть файл

@ -150,7 +150,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
while (nd != NULL) { while (nd != NULL) {
ui_browser__gotorc(browser, row, 0); ui_browser__gotorc(browser, row, 0);
browser->write(browser, nd, row); browser->write(browser, nd, row);
if (++row == browser->height) if (++row == browser->rows)
break; break;
nd = rb_next(nd); 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) void ui_browser__refresh_dimensions(struct ui_browser *browser)
{ {
browser->width = SLtt_Screen_Cols - 1; browser->width = SLtt_Screen_Cols - 1;
browser->height = SLtt_Screen_Rows - 2; browser->height = browser->rows = SLtt_Screen_Rows - 2;
browser->y = 1; browser->y = 1;
browser->x = 0; browser->x = 0;
} }
@ -250,7 +250,10 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
int err; int err;
va_list ap; 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); pthread_mutex_lock(&ui__lock);
__ui_browser__show_title(browser, title); __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) { if (key == K_RESIZE) {
ui__refresh_dimensions(false); ui__refresh_dimensions(false);
ui_browser__refresh_dimensions(browser); browser->refresh_dimensions(browser);
__ui_browser__show_title(browser, browser->title); __ui_browser__show_title(browser, browser->title);
ui_helpline__puts(browser->helpline); ui_helpline__puts(browser->helpline);
continue; continue;
@ -389,7 +392,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
if (browser->index == browser->nr_entries - 1) if (browser->index == browser->nr_entries - 1)
break; break;
++browser->index; ++browser->index;
if (browser->index == browser->top_idx + browser->height) { if (browser->index == browser->top_idx + browser->rows) {
++browser->top_idx; ++browser->top_idx;
browser->seek(browser, +1, SEEK_CUR); browser->seek(browser, +1, SEEK_CUR);
} }
@ -405,10 +408,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
break; break;
case K_PGDN: case K_PGDN:
case ' ': case ' ':
if (browser->top_idx + browser->height > browser->nr_entries - 1) if (browser->top_idx + browser->rows > browser->nr_entries - 1)
break; break;
offset = browser->height; offset = browser->rows;
if (browser->index + offset > browser->nr_entries - 1) if (browser->index + offset > browser->nr_entries - 1)
offset = browser->nr_entries - 1 - browser->index; offset = browser->nr_entries - 1 - browser->index;
browser->index += offset; browser->index += offset;
@ -419,10 +422,10 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs)
if (browser->top_idx == 0) if (browser->top_idx == 0)
break; break;
if (browser->top_idx < browser->height) if (browser->top_idx < browser->rows)
offset = browser->top_idx; offset = browser->top_idx;
else else
offset = browser->height; offset = browser->rows;
browser->index -= offset; browser->index -= offset;
browser->top_idx -= 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); ui_browser__reset_index(browser);
break; break;
case K_END: case K_END:
offset = browser->height - 1; offset = browser->rows - 1;
if (offset >= browser->nr_entries) if (offset >= browser->nr_entries)
offset = browser->nr_entries - 1; 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)) { if (!browser->filter || !browser->filter(browser, pos)) {
ui_browser__gotorc(browser, row, 0); ui_browser__gotorc(browser, row, 0);
browser->write(browser, pos, row); browser->write(browser, pos, row);
if (++row == browser->height) if (++row == browser->rows)
break; break;
} }
} }
@ -587,7 +590,7 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
if (!browser->filter || !browser->filter(browser, *pos)) { if (!browser->filter || !browser->filter(browser, *pos)) {
ui_browser__gotorc(browser, row, 0); ui_browser__gotorc(browser, row, 0);
browser->write(browser, pos, row); browser->write(browser, pos, row);
if (++row == browser->height) if (++row == browser->rows)
break; break;
} }
@ -623,7 +626,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
SLsmg_set_char_set(1); SLsmg_set_char_set(1);
if (start < browser->top_idx + browser->height) { if (start < browser->top_idx + browser->rows) {
row = start - browser->top_idx; row = start - browser->top_idx;
ui_browser__gotorc(browser, row, column); ui_browser__gotorc(browser, row, column);
SLsmg_write_char(SLSMG_LLCORN_CHAR); SLsmg_write_char(SLSMG_LLCORN_CHAR);
@ -633,7 +636,7 @@ static void __ui_browser__line_arrow_up(struct ui_browser *browser,
if (row-- == 0) if (row-- == 0)
goto out; goto out;
} else } else
row = browser->height - 1; row = browser->rows - 1;
if (end > browser->top_idx) if (end > browser->top_idx)
end_row = 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 } else
row = 0; row = 0;
if (end >= browser->top_idx + browser->height) if (end >= browser->top_idx + browser->rows)
end_row = browser->height - 1; end_row = browser->rows - 1;
else else
end_row = end - browser->top_idx; 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); SLsmg_draw_vline(end_row - row + 1);
ui_browser__gotorc(browser, end_row, column); 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); SLsmg_write_char(SLSMG_LLCORN_CHAR);
ui_browser__gotorc(browser, end_row, column + 1); ui_browser__gotorc(browser, end_row, column + 1);
SLsmg_write_char(SLSMG_HLINE_CHAR); SLsmg_write_char(SLSMG_HLINE_CHAR);

Просмотреть файл

@ -14,11 +14,12 @@
struct ui_browser { struct ui_browser {
u64 index, top_idx; u64 index, top_idx;
void *top, *entries; void *top, *entries;
u16 y, x, width, height; u16 y, x, width, height, rows;
int current_color; int current_color;
void *priv; void *priv;
const char *title; const char *title;
char *helpline; char *helpline;
void (*refresh_dimensions)(struct ui_browser *browser);
unsigned int (*refresh)(struct ui_browser *browser); unsigned int (*refresh)(struct ui_browser *browser);
void (*write)(struct ui_browser *browser, void *entry, int row); void (*write)(struct ui_browser *browser, void *entry, int row);
void (*seek)(struct ui_browser *browser, off_t offset, int whence); void (*seek)(struct ui_browser *browser, off_t offset, int whence);

Просмотреть файл

@ -26,6 +26,7 @@ struct hist_browser {
struct map_symbol *selection; struct map_symbol *selection;
int print_seq; int print_seq;
bool show_dso; bool show_dso;
bool show_headers;
float min_pcnt; float min_pcnt;
u64 nr_non_filtered_entries; u64 nr_non_filtered_entries;
u64 nr_callchain_rows; 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; 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 */ /* 3 == +/- toggle symbol before actual hist_entry rendering */
browser->b.width = 3 + (hists__sort_list_width(browser->hists) + browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
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) 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); hist_browser__update_nr_entries(browser);
browser->b.nr_entries = hist_browser__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); 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.entries = &browser->hists->entries;
browser->b.nr_entries = hist_browser__nr_entries(browser); browser->b.nr_entries = hist_browser__nr_entries(browser);
hist_browser__refresh_dimensions(browser);
hists__browser_title(browser->hists, title, sizeof(title)); hists__browser_title(browser->hists, title, sizeof(title));
if (ui_browser__show(&browser->b, 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 *h = rb_entry(browser->b.top,
struct hist_entry, rb_node); struct hist_entry, rb_node);
ui_helpline__pop(); 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, seq++, browser->b.nr_entries,
browser->hists->nr_entries, browser->hists->nr_entries,
browser->b.height, browser->b.rows,
browser->b.index, browser->b.index,
browser->b.top_idx, browser->b.top_idx,
h->row_offset, h->nr_rows); h->row_offset, h->nr_rows);
@ -409,6 +440,10 @@ static int hist_browser__run(struct hist_browser *browser,
/* Expand the whole world. */ /* Expand the whole world. */
hist_browser__set_folding(browser, true); hist_browser__set_folding(browser, true);
break; break;
case 'H':
browser->show_headers = !browser->show_headers;
hist_browser__update_rows(browser);
break;
case K_ENTER: case K_ENTER:
if (hist_browser__toggle_fold(browser)) if (hist_browser__toggle_fold(browser))
break; 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__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_write_nstring(" ", offset + extra_offset);
slsmg_printf("%c ", folded_sign); slsmg_printf("%c ", folded_sign);
slsmg_write_nstring(str, width); slsmg_write_nstring(str, width);
free(alloc_str); free(alloc_str);
if (++row == browser->b.height) if (++row == browser->b.rows)
goto out; goto out;
do_next: do_next:
if (folded_sign == '+') if (folded_sign == '+')
@ -527,7 +562,7 @@ do_next:
new_level, row, row_offset, new_level, row, row_offset,
is_current_entry); is_current_entry);
} }
if (row == browser->b.height) if (row == browser->b.rows)
goto out; goto out;
node = next; 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), s = callchain_list__sym_name(chain, bf, sizeof(bf),
browser->show_dso); browser->show_dso);
ui_browser__gotorc(&browser->b, row, 0); hist_browser__gotorc(browser, row, 0);
ui_browser__set_color(&browser->b, color); ui_browser__set_color(&browser->b, color);
slsmg_write_nstring(" ", offset); slsmg_write_nstring(" ", offset);
slsmg_printf("%c ", folded_sign); slsmg_printf("%c ", folded_sign);
slsmg_write_nstring(s, width - 2); slsmg_write_nstring(s, width - 2);
if (++row == browser->b.height) if (++row == browser->b.rows)
goto out; 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 += hist_browser__show_callchain_node(browser, node, level,
row, row_offset, row, row_offset,
is_current_entry); is_current_entry);
if (row == browser->b.height) if (row == browser->b.rows)
break; break;
} }
@ -732,7 +767,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.ptr = &arg, .ptr = &arg,
}; };
ui_browser__gotorc(&browser->b, row, 0); hist_browser__gotorc(browser, row, 0);
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt)) if (perf_hpp__should_skip(fmt))
@ -776,7 +811,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
} else } else
--row_offset; --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, printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
1, row, &row_offset, 1, row, &row_offset,
&current_entry); &current_entry);
@ -787,6 +822,56 @@ static int hist_browser__show_entry(struct hist_browser *browser,
return printed; 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) static void ui_browser__hists_init_top(struct ui_browser *browser)
{ {
if (browser->top == NULL) { 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) static unsigned int hist_browser__refresh(struct ui_browser *browser)
{ {
unsigned row = 0; unsigned row = 0;
u16 header_offset = 0;
struct rb_node *nd; struct rb_node *nd;
struct hist_browser *hb = container_of(browser, struct hist_browser, b); 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); ui_browser__hists_init_top(browser);
for (nd = browser->top; nd; nd = rb_next(nd)) { for (nd = browser->top; nd; nd = rb_next(nd)) {
@ -817,11 +908,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
continue; continue;
row += hist_browser__show_entry(hb, h, row); row += hist_browser__show_entry(hb, h, row);
if (row == browser->height) if (row == browser->rows)
break; break;
} }
return row; return row + header_offset;
} }
static struct rb_node *hists__filter_entries(struct rb_node *nd, 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) { if (browser) {
browser->hists = hists; browser->hists = hists;
browser->b.refresh = hist_browser__refresh; browser->b.refresh = hist_browser__refresh;
browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
browser->b.seek = ui_browser__hists_seek; browser->b.seek = ui_browser__hists_seek;
browser->b.use_navkeypressed = true; browser->b.use_navkeypressed = true;
browser->show_headers = symbol_conf.show_hist_headers;
} }
return browser; 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" \ "d Zoom into current DSO\n" \
"E Expand all callchains\n" \ "E Expand all callchains\n" \
"F Toggle percentage of filtered entries\n" \ "F Toggle percentage of filtered entries\n" \
"H Display column headers\n" \
/* help messages are sorted by lexical order of the hotkey */ /* help messages are sorted by lexical order of the hotkey */
const char report_help[] = HIST_BROWSER_HELP_COMMON 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; 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, int perf_default_config(const char *var, const char *value,
void *dummy __maybe_unused) void *dummy __maybe_unused)
{ {
@ -359,6 +369,9 @@ int perf_default_config(const char *var, const char *value,
if (!prefixcmp(var, "hist.")) if (!prefixcmp(var, "hist."))
return perf_hist_config(var, value); return perf_hist_config(var, value);
if (!prefixcmp(var, "ui."))
return perf_ui_config(var, value);
/* Add other config variables here. */ /* Add other config variables here. */
return 0; return 0;
} }

Просмотреть файл

@ -65,7 +65,7 @@ static int open_file_read(struct perf_data_file *file)
goto out_close; goto out_close;
if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 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); file->path);
goto out_close; 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); hse = container_of(fmt, struct hpp_sort_entry, hpp);
len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 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, static int __sort__hpp_width(struct perf_hpp_fmt *fmt,

Просмотреть файл

@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
.annotate_src = true, .annotate_src = true,
.demangle = true, .demangle = true,
.cumulate_callchain = true, .cumulate_callchain = true,
.show_hist_headers = true,
.symfs = "", .symfs = "",
}; };

Просмотреть файл

@ -118,7 +118,8 @@ struct symbol_conf {
annotate_src, annotate_src,
event_group, event_group,
demangle, demangle,
filter_relative; filter_relative,
show_hist_headers;
const char *vmlinux_name, const char *vmlinux_name,
*kallsyms_name, *kallsyms_name,
*source_prefix, *source_prefix,

Просмотреть файл

@ -191,12 +191,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "..") == 0 ||
!name_in_tp_list(dent->d_name, tps)) !name_in_tp_list(dent->d_name, tps))
continue; continue;
format = malloc(strlen(sys) + strlen(dent->d_name) + 10); if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
if (!format) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
sprintf(format, "%s/%s/format", sys, dent->d_name);
ret = stat(format, &st); ret = stat(format, &st);
free(format); free(format);
if (ret < 0) if (ret < 0)
@ -217,12 +215,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "..") == 0 ||
!name_in_tp_list(dent->d_name, tps)) !name_in_tp_list(dent->d_name, tps))
continue; continue;
format = malloc(strlen(sys) + strlen(dent->d_name) + 10); if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
if (!format) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
sprintf(format, "%s/%s/format", sys, dent->d_name);
ret = stat(format, &st); ret = stat(format, &st);
if (ret >= 0) { if (ret >= 0) {
@ -317,12 +313,10 @@ static int record_event_files(struct tracepoint_path *tps)
strcmp(dent->d_name, "ftrace") == 0 || strcmp(dent->d_name, "ftrace") == 0 ||
!system_in_tp_list(dent->d_name, tps)) !system_in_tp_list(dent->d_name, tps))
continue; continue;
sys = malloc(strlen(path) + strlen(dent->d_name) + 2); if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
if (!sys) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
sprintf(sys, "%s/%s", path, dent->d_name);
ret = stat(sys, &st); ret = stat(sys, &st);
if (ret >= 0) { if (ret >= 0) {
ssize_t size = strlen(dent->d_name) + 1; ssize_t size = strlen(dent->d_name) + 1;

Просмотреть файл

@ -333,12 +333,9 @@ const char *find_tracing_dir(void)
if (!debugfs) if (!debugfs)
return NULL; return NULL;
tracing = malloc(strlen(debugfs) + 9); if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
if (!tracing)
return NULL; return NULL;
sprintf(tracing, "%s/tracing", debugfs);
tracing_found = 1; tracing_found = 1;
return tracing; return tracing;
} }
@ -352,11 +349,9 @@ char *get_tracing_file(const char *name)
if (!tracing) if (!tracing)
return NULL; return NULL;
file = malloc(strlen(tracing) + strlen(name) + 2); if (asprintf(&file, "%s/%s", tracing, name) < 0)
if (!file)
return NULL; return NULL;
sprintf(file, "%s/%s", tracing, name);
return file; return file;
} }