perf/core improvements and fixes:

- Record min/max LBR cycles (>= skylake) and add 'perf annotate' TUI
   hotkey to show it (c) (Jin Yao)
 
 - Fix machine->kernel_start for PTI on x86 (Adrian Hunter)
 
 - Make machine->env->arch always available, e.g. in 'perf top', not
   just when reading that info from perf.data files (Adrian Hunter)
 
 - Reduce the number of files read at 'perf' start, leaving information such as
   cacheline size, tracefs mount point determination, max_stack, etc, to be
   lazily read as tools needs then (Arnaldo Carvalho de Melo)
 
 - Fixup BPF include and examples install messages (Arnaldo Carvalho de Melo)
 
 - Fixup callchain addresses and symbol offsets in 'perf script', to help
   correlating with objdump output (Sandipan Das)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEELb9bqkb7Te0zijNb1lAW81NSqkAFAlsAAa4ACgkQ1lAW81NS
 qkAcag//UGyLeatnVTZhsNyFeVzS3a8nb//OWOKAYx70iWXTlriOXDjnF2UEmeoZ
 PMosDi2QksbiHoFiKRwYs8HlNbnUgCf+XqJfXY6wusQEyvlvm2TQzxclW9jgA6aU
 DuYJiaWFZdsJsEug2qKmBR6P0rE9JjB1m8frP6mpjqa0be39PbzEkMp7BamoEPoM
 FmLjARE4ob2Q56sq8BogjhjRsOkwqPbcJHRkH7EfOrjqRsqjvnjg4LAvf2qf7jXG
 aliPUCOhihxtP67uMo9i9D0D94M7zKdwvZHfweCi2atz9I7cF8rOdjtAzUpdCnhh
 YvmhBCmaEYfd2VLnSGHTcgSRZcuMO0+QDDECS2/MvYn8mzGSJLqPMLR9EGoYHcI5
 0LWDxQHxHGBUBezcv4iq1YYaec9r+kFMXVFkC/v4v2CUisCfjLIbn0qC64FlK0hm
 dl60f5nZ/O7FHN2ObvNbtfSIHoKnb6/TIfASQHO3uCGlwF+EF2HpJ79h/vWcCY3S
 0d4ENf4JrVZQxN7s9qly8XJ8jZkWQsVDVYu3EPyOKkVp/F7x6y2jO+ap1s3uSMjI
 g8lrNnhyeUQiTf/fnoascvrq1Opl3gLm/iJ92UOTV9fnCn4rFnt0TsZh9+yw9LsH
 o/m2mPo52ZBxcMDHSUQJ87SsP8CzOEq7JRiKuBJpA5L60nvql10=
 =RER4
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo-4.18-20180519' 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:

- Record min/max LBR cycles (>= Skylake) and add 'perf annotate' TUI
  hotkey to show it (c) (Jin Yao)

- Fix machine->kernel_start for PTI on x86 (Adrian Hunter)

- Make machine->env->arch always available, e.g. in 'perf top', not
  just when reading that info from perf.data files (Adrian Hunter)

- Reduce the number of files read at 'perf' start, leaving information such as
  cacheline size, tracefs mount point determination, max_stack, etc, to be
  lazily read as tools needs then (Arnaldo Carvalho de Melo)

- Fix up BPF include and examples install messages (Arnaldo Carvalho de Melo)

- Fix up callchain addresses and symbol offsets in 'perf script', to help
  correlating with objdump output (Sandipan Das)

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 2018-05-19 13:32:27 +02:00
commit 2996123e7e
28 changed files with 279 additions and 120 deletions

View File

@ -21,6 +21,9 @@
/* &a[0] degrades to a pointer: a different type from an array */ /* &a[0] degrades to a pointer: a different type from an array */
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
#ifndef __pure
#define __pure __attribute__((pure))
#endif
#define noinline __attribute__((noinline)) #define noinline __attribute__((noinline))
#ifndef __packed #ifndef __packed
#define __packed __attribute__((packed)) #define __packed __attribute__((packed))

View File

@ -13,11 +13,9 @@
#include "tracing_path.h" #include "tracing_path.h"
static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug";
char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; static char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing";
char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; static char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events";
char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events";
static void __tracing_path_set(const char *tracing, const char *mountpoint) static void __tracing_path_set(const char *tracing, const char *mountpoint)
{ {
@ -76,7 +74,7 @@ char *get_tracing_file(const char *name)
{ {
char *file; char *file;
if (asprintf(&file, "%s/%s", tracing_path, name) < 0) if (asprintf(&file, "%s/%s", tracing_path_mount(), name) < 0)
return NULL; return NULL;
return file; return file;
@ -87,6 +85,34 @@ void put_tracing_file(char *file)
free(file); free(file);
} }
char *get_events_file(const char *name)
{
char *file;
if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0)
return NULL;
return file;
}
void put_events_file(char *file)
{
free(file);
}
DIR *tracing_events__opendir(void)
{
DIR *dir = NULL;
char *path = get_tracing_file("events");
if (path) {
dir = opendir(path);
put_events_file(path);
}
return dir;
}
int tracing_path__strerror_open_tp(int err, char *buf, size_t size, int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
const char *sys, const char *name) const char *sys, const char *name)
{ {
@ -129,7 +155,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
snprintf(buf, size, snprintf(buf, size,
"Error:\tNo permissions to read %s/%s\n" "Error:\tNo permissions to read %s/%s\n"
"Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
tracing_events_path, filename, tracing_mnt); tracing_events_path, filename, tracing_path_mount());
} }
break; break;
default: default:

View File

@ -3,9 +3,9 @@
#define __API_FS_TRACING_PATH_H #define __API_FS_TRACING_PATH_H
#include <linux/types.h> #include <linux/types.h>
#include <dirent.h>
extern char tracing_path[]; DIR *tracing_events__opendir(void);
extern char tracing_events_path[];
void tracing_path_set(const char *mountpoint); void tracing_path_set(const char *mountpoint);
const char *tracing_path_mount(void); const char *tracing_path_mount(void);
@ -13,5 +13,10 @@ const char *tracing_path_mount(void);
char *get_tracing_file(const char *name); char *get_tracing_file(const char *name);
void put_tracing_file(char *file); void put_tracing_file(char *file);
char *get_events_file(const char *name);
void put_events_file(char *file);
#define zput_events_file(ptr) ({ free(*ptr); *ptr = NULL; })
int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name);
#endif /* __API_FS_TRACING_PATH_H */ #endif /* __API_FS_TRACING_PATH_H */

View File

@ -770,9 +770,11 @@ endif
ifndef NO_LIBBPF ifndef NO_LIBBPF
$(call QUIET_INSTALL, lib) \ $(call QUIET_INSTALL, lib) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'
$(call QUIET_INSTALL, include/bpf) \
$(INSTALL) include/bpf/*.h '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' $(INSTALL) include/bpf/*.h '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'
$(call QUIET_INSTALL, lib) \ $(call QUIET_INSTALL, lib) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
$(call QUIET_INSTALL, examples/bpf) \
$(INSTALL) examples/bpf/*.c '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' $(INSTALL) examples/bpf/*.c '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
endif endif
$(call QUIET_INSTALL, perf-archive) \ $(call QUIET_INSTALL, perf-archive) \

View File

@ -153,8 +153,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_PERIOD, PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
}, },
@ -165,8 +165,9 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT, PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
PERF_OUTPUT_BPF_OUTPUT,
.invalid_fields = PERF_OUTPUT_TRACE, .invalid_fields = PERF_OUTPUT_TRACE,
}, },
@ -185,10 +186,10 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT | PERF_OUTPUT_ADDR | PERF_OUTPUT_DATA_SRC |
PERF_OUTPUT_PHYS_ADDR, PERF_OUTPUT_WEIGHT | PERF_OUTPUT_PHYS_ADDR,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
}, },
@ -199,8 +200,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_PERIOD, PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
}, },
@ -211,8 +212,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_SYNTH, PERF_OUTPUT_DSO | PERF_OUTPUT_SYNTH,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
}, },
@ -544,6 +545,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {
output[j].fields |= PERF_OUTPUT_IP; output[j].fields |= PERF_OUTPUT_IP;
output[j].fields |= PERF_OUTPUT_SYM; output[j].fields |= PERF_OUTPUT_SYM;
output[j].fields |= PERF_OUTPUT_SYMOFFSET;
output[j].fields |= PERF_OUTPUT_DSO; output[j].fields |= PERF_OUTPUT_DSO;
set_print_ip_opts(attr); set_print_ip_opts(attr);
goto out; goto out;

View File

@ -1264,7 +1264,7 @@ int cmd_top(int argc, const char **argv)
.proc_map_timeout = 500, .proc_map_timeout = 500,
.overwrite = 1, .overwrite = 1,
}, },
.max_stack = sysctl_perf_event_max_stack, .max_stack = sysctl__max_stack(),
.sym_pcnt_filter = 5, .sym_pcnt_filter = 5,
.nr_threads_synthesize = UINT_MAX, .nr_threads_synthesize = UINT_MAX,
}; };

View File

@ -3162,7 +3162,7 @@ int cmd_trace(int argc, const char **argv)
mmap_pages_user_set = false; mmap_pages_user_set = false;
if (trace.max_stack == UINT_MAX) { if (trace.max_stack == UINT_MAX) {
trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack; trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
max_stack_user_set = false; max_stack_user_set = false;
} }

View File

@ -238,7 +238,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
(*argc)--; (*argc)--;
} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) { } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
fprintf(stderr, "dir: %s\n", tracing_path); fprintf(stderr, "dir: %s\n", tracing_path_mount());
if (envchanged) if (envchanged)
*envchanged = 1; *envchanged = 1;
} else if (!strcmp(cmd, "--list-cmds")) { } else if (!strcmp(cmd, "--list-cmds")) {
@ -421,22 +421,11 @@ void pthread__unblock_sigwinch(void)
pthread_sigmask(SIG_UNBLOCK, &set, NULL); pthread_sigmask(SIG_UNBLOCK, &set, NULL);
} }
#ifdef _SC_LEVEL1_DCACHE_LINESIZE
#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
#else
static void cache_line_size(int *cacheline_sizep)
{
if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep))
pr_debug("cannot determine cache line size");
}
#endif
int main(int argc, const char **argv) int main(int argc, const char **argv)
{ {
int err; int err;
const char *cmd; const char *cmd;
char sbuf[STRERR_BUFSIZE]; char sbuf[STRERR_BUFSIZE];
int value;
/* libsubcmd init */ /* libsubcmd init */
exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
@ -444,13 +433,6 @@ int main(int argc, const char **argv)
/* The page_size is placed in util object. */ /* The page_size is placed in util object. */
page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
cache_line_size(&cacheline_size);
if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
sysctl_perf_event_max_stack = value;
if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
sysctl_perf_event_max_contexts_per_stack = value;
cmd = extract_argv0_path(argv[0]); cmd = extract_argv0_path(argv[0]);
if (!cmd) if (!cmd)
@ -458,15 +440,11 @@ int main(int argc, const char **argv)
srandom(time(NULL)); srandom(time(NULL));
perf_config__init();
err = perf_config(perf_default_config, NULL); err = perf_config(perf_default_config, NULL);
if (err) if (err)
return err; return err;
set_buildid_dir(NULL); set_buildid_dir(NULL);
/* get debugfs/tracefs mount point from /proc/mounts */
tracing_path_mount();
/* /*
* "perf-xxxx" is the same as "perf xxxx", but we obviously: * "perf-xxxx" is the same as "perf xxxx", but we obviously:
* *

View File

@ -1323,12 +1323,12 @@ static int count_tracepoints(void)
DIR *events_dir; DIR *events_dir;
int cnt = 0; int cnt = 0;
events_dir = opendir(tracing_events_path); events_dir = tracing_events__opendir();
TEST_ASSERT_VAL("Can't open events dir", events_dir); TEST_ASSERT_VAL("Can't open events dir", events_dir);
while ((events_ent = readdir(events_dir))) { while ((events_ent = readdir(events_dir))) {
char sys_path[PATH_MAX]; char *sys_path;
struct dirent *sys_ent; struct dirent *sys_ent;
DIR *sys_dir; DIR *sys_dir;
@ -1339,8 +1339,8 @@ static int count_tracepoints(void)
|| !strcmp(events_ent->d_name, "header_page")) || !strcmp(events_ent->d_name, "header_page"))
continue; continue;
scnprintf(sys_path, PATH_MAX, "%s/%s", sys_path = get_events_file(events_ent->d_name);
tracing_events_path, events_ent->d_name); TEST_ASSERT_VAL("Can't get sys path", sys_path);
sys_dir = opendir(sys_path); sys_dir = opendir(sys_path);
TEST_ASSERT_VAL("Can't open sys dir", sys_dir); TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
@ -1356,6 +1356,7 @@ static int count_tracepoints(void)
} }
closedir(sys_dir); closedir(sys_dir);
put_events_file(sys_path);
} }
closedir(events_dir); closedir(events_dir);

View File

@ -16,18 +16,18 @@ nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254
trace_libc_inet_pton_backtrace() { trace_libc_inet_pton_backtrace() {
idx=0 idx=0
expected[0]="ping[][0-9 \.:]+probe_libc:inet_pton: \([[:xdigit:]]+\)" expected[0]="ping[][0-9 \.:]+probe_libc:inet_pton: \([[:xdigit:]]+\)"
expected[1]=".*inet_pton[[:space:]]\($libc|inlined\)$" expected[1]=".*inet_pton\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$"
case "$(uname -m)" in case "$(uname -m)" in
s390x) s390x)
eventattr='call-graph=dwarf,max-stack=4' eventattr='call-graph=dwarf,max-stack=4'
expected[2]="gaih_inet.*[[:space:]]\($libc|inlined\)$" expected[2]="gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$"
expected[3]="(__GI_)?getaddrinfo[[:space:]]\($libc|inlined\)$" expected[3]="(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$"
expected[4]="main[[:space:]]\(.*/bin/ping.*\)$" expected[4]="main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$"
;; ;;
*) *)
eventattr='max-stack=3' eventattr='max-stack=3'
expected[2]="getaddrinfo[[:space:]]\($libc\)$" expected[2]="getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$"
expected[3]=".*\(.*/bin/ping.*\)$" expected[3]=".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$"
;; ;;
esac esac

View File

@ -695,6 +695,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
"O Bump offset level (jump targets -> +call -> all -> cycle thru)\n" "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
"s Toggle source code view\n" "s Toggle source code view\n"
"t Circulate percent, total period, samples view\n" "t Circulate percent, total period, samples view\n"
"c Show min/max cycle\n"
"/ Search string\n" "/ Search string\n"
"k Toggle line numbers\n" "k Toggle line numbers\n"
"P Print to [symbol_name].annotation file.\n" "P Print to [symbol_name].annotation file.\n"
@ -791,6 +792,13 @@ static int annotate_browser__run(struct annotate_browser *browser,
notes->options->show_total_period = true; notes->options->show_total_period = true;
annotation__update_column_widths(notes); annotation__update_column_widths(notes);
continue; continue;
case 'c':
if (notes->options->show_minmax_cycle)
notes->options->show_minmax_cycle = false;
else
notes->options->show_minmax_cycle = true;
annotation__update_column_widths(notes);
continue;
case K_LEFT: case K_LEFT:
case K_ESC: case K_ESC:
case 'q': case 'q':

View File

@ -760,6 +760,15 @@ static int __symbol__account_cycles(struct annotation *notes,
ch[offset].num_aggr++; ch[offset].num_aggr++;
ch[offset].cycles_aggr += cycles; ch[offset].cycles_aggr += cycles;
if (cycles > ch[offset].cycles_max)
ch[offset].cycles_max = cycles;
if (ch[offset].cycles_min) {
if (cycles && cycles < ch[offset].cycles_min)
ch[offset].cycles_min = cycles;
} else
ch[offset].cycles_min = cycles;
if (!have_start && ch[offset].have_start) if (!have_start && ch[offset].have_start)
return 0; return 0;
if (ch[offset].num) { if (ch[offset].num) {
@ -953,8 +962,11 @@ void annotation__compute_ipc(struct annotation *notes, size_t size)
if (ch->have_start) if (ch->have_start)
annotation__count_and_fill(notes, ch->start, offset, ch); annotation__count_and_fill(notes, ch->start, offset, ch);
al = notes->offsets[offset]; al = notes->offsets[offset];
if (al && ch->num_aggr) if (al && ch->num_aggr) {
al->cycles = ch->cycles_aggr / ch->num_aggr; al->cycles = ch->cycles_aggr / ch->num_aggr;
al->cycles_max = ch->cycles_max;
al->cycles_min = ch->cycles_min;
}
notes->have_cycles = true; notes->have_cycles = true;
} }
} }
@ -2486,13 +2498,38 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
else else
obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
if (al->cycles) if (!notes->options->show_minmax_cycle) {
obj__printf(obj, "%*" PRIu64 " ", if (al->cycles)
obj__printf(obj, "%*" PRIu64 " ",
ANNOTATION__CYCLES_WIDTH - 1, al->cycles); ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
else if (!show_title) else if (!show_title)
obj__printf(obj, "%*s", ANNOTATION__CYCLES_WIDTH, " "); obj__printf(obj, "%*s",
else ANNOTATION__CYCLES_WIDTH, " ");
obj__printf(obj, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); else
obj__printf(obj, "%*s ",
ANNOTATION__CYCLES_WIDTH - 1,
"Cycle");
} else {
if (al->cycles) {
char str[32];
scnprintf(str, sizeof(str),
"%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
al->cycles, al->cycles_min,
al->cycles_max);
obj__printf(obj, "%*s ",
ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
str);
} else if (!show_title)
obj__printf(obj, "%*s",
ANNOTATION__MINMAX_CYCLES_WIDTH,
" ");
else
obj__printf(obj, "%*s ",
ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
"Cycle(min/max)");
}
} }
obj__printf(obj, " "); obj__printf(obj, " ");

View File

@ -61,6 +61,7 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2);
#define ANNOTATION__IPC_WIDTH 6 #define ANNOTATION__IPC_WIDTH 6
#define ANNOTATION__CYCLES_WIDTH 6 #define ANNOTATION__CYCLES_WIDTH 6
#define ANNOTATION__MINMAX_CYCLES_WIDTH 19
struct annotation_options { struct annotation_options {
bool hide_src_code, bool hide_src_code,
@ -69,7 +70,8 @@ struct annotation_options {
show_linenr, show_linenr,
show_nr_jumps, show_nr_jumps,
show_nr_samples, show_nr_samples,
show_total_period; show_total_period,
show_minmax_cycle;
u8 offset_level; u8 offset_level;
}; };
@ -105,6 +107,8 @@ struct annotation_line {
int jump_sources; int jump_sources;
float ipc; float ipc;
u64 cycles; u64 cycles;
u64 cycles_max;
u64 cycles_min;
size_t privsize; size_t privsize;
char *path; char *path;
u32 idx; u32 idx;
@ -186,6 +190,8 @@ struct cyc_hist {
u64 start; u64 start;
u64 cycles; u64 cycles;
u64 cycles_aggr; u64 cycles_aggr;
u64 cycles_max;
u64 cycles_min;
u32 num; u32 num;
u32 num_aggr; u32 num_aggr;
u8 have_start; u8 have_start;
@ -239,6 +245,9 @@ struct annotation {
static inline int annotation__cycles_width(struct annotation *notes) static inline int annotation__cycles_width(struct annotation *notes)
{ {
if (notes->have_cycles && notes->options->show_minmax_cycle)
return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;
return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
} }

View File

@ -707,6 +707,14 @@ struct perf_config_set *perf_config_set__new(void)
return set; return set;
} }
static int perf_config__init(void)
{
if (config_set == NULL)
config_set = perf_config_set__new();
return config_set == NULL;
}
int perf_config(config_fn_t fn, void *data) int perf_config(config_fn_t fn, void *data)
{ {
int ret = 0; int ret = 0;
@ -714,7 +722,7 @@ int perf_config(config_fn_t fn, void *data)
struct perf_config_section *section; struct perf_config_section *section;
struct perf_config_item *item; struct perf_config_item *item;
if (config_set == NULL) if (config_set == NULL && perf_config__init())
return -1; return -1;
perf_config_set__for_each_entry(config_set, section, item) { perf_config_set__for_each_entry(config_set, section, item) {
@ -735,12 +743,6 @@ int perf_config(config_fn_t fn, void *data)
return ret; return ret;
} }
void perf_config__init(void)
{
if (config_set == NULL)
config_set = perf_config_set__new();
}
void perf_config__exit(void) void perf_config__exit(void)
{ {
perf_config_set__delete(config_set); perf_config_set__delete(config_set);

View File

@ -38,7 +38,6 @@ struct perf_config_set *perf_config_set__new(void);
void perf_config_set__delete(struct perf_config_set *set); void perf_config_set__delete(struct perf_config_set *set);
int perf_config_set__collect(struct perf_config_set *set, const char *file_name, int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
const char *var, const char *value); const char *var, const char *value);
void perf_config__init(void);
void perf_config__exit(void); void perf_config__exit(void);
void perf_config__refresh(void); void perf_config__refresh(void);

View File

@ -93,6 +93,24 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
return 0; return 0;
} }
static int perf_env__read_arch(struct perf_env *env)
{
struct utsname uts;
if (env->arch)
return 0;
if (!uname(&uts))
env->arch = strdup(uts.machine);
return env->arch ? 0 : -ENOMEM;
}
const char *perf_env__raw_arch(struct perf_env *env)
{
return env && !perf_env__read_arch(env) ? env->arch : "unknown";
}
void cpu_cache_level__free(struct cpu_cache_level *cache) void cpu_cache_level__free(struct cpu_cache_level *cache)
{ {
free(cache->type); free(cache->type);

View File

@ -76,4 +76,6 @@ int perf_env__read_cpu_topology_map(struct perf_env *env);
void cpu_cache_level__free(struct cpu_cache_level *cache); void cpu_cache_level__free(struct cpu_cache_level *cache);
const char *perf_env__arch(struct perf_env *env); const char *perf_env__arch(struct perf_env *env);
const char *perf_env__raw_arch(struct perf_env *env);
#endif /* __PERF_ENV_H */ #endif /* __PERF_ENV_H */

View File

@ -2862,7 +2862,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
return scnprintf(msg, size, return scnprintf(msg, size,
"Not enough memory to setup event with callchain.\n" "Not enough memory to setup event with callchain.\n"
"Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n" "Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n"
"Hint: Current value: %d", sysctl_perf_event_max_stack); "Hint: Current value: %d", sysctl__max_stack());
break; break;
case ENODEV: case ENODEV:
if (target->cpu_list) if (target->cpu_list)

View File

@ -1764,7 +1764,7 @@ static int add_callchain_ip(struct thread *thread,
} }
srcline = callchain_srcline(al.map, al.sym, al.addr); srcline = callchain_srcline(al.map, al.sym, al.addr);
return callchain_cursor_append(cursor, al.addr, al.map, al.sym, return callchain_cursor_append(cursor, ip, al.map, al.sym,
branch, flags, nr_loop_iter, branch, flags, nr_loop_iter,
iter_cycles, branch_from, srcline); iter_cycles, branch_from, srcline);
} }
@ -2296,6 +2296,15 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
return 0; return 0;
} }
/*
* Compares the raw arch string. N.B. see instead perf_env__arch() if a
* normalized arch is needed.
*/
bool machine__is(struct machine *machine, const char *arch)
{
return machine && !strcmp(perf_env__raw_arch(machine->env), arch);
}
int machine__get_kernel_start(struct machine *machine) int machine__get_kernel_start(struct machine *machine)
{ {
struct map *map = machine__kernel_map(machine); struct map *map = machine__kernel_map(machine);
@ -2312,7 +2321,12 @@ int machine__get_kernel_start(struct machine *machine)
machine->kernel_start = 1ULL << 63; machine->kernel_start = 1ULL << 63;
if (map) { if (map) {
err = map__load(map); err = map__load(map);
if (!err) /*
* On x86_64, PTI entry trampolines are less than the
* start of kernel text, but still above 2^63. So leave
* kernel_start = 1ULL << 63 for x86_64.
*/
if (!err && !machine__is(machine, "x86_64"))
machine->kernel_start = map->start; machine->kernel_start = map->start;
} }
return err; return err;

View File

@ -188,6 +188,8 @@ static inline bool machine__is_host(struct machine *machine)
return machine ? machine->pid == HOST_KERNEL_ID : false; return machine ? machine->pid == HOST_KERNEL_ID : false;
} }
bool machine__is(struct machine *machine, const char *arch);
struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid); struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid);
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid); struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid);

View File

@ -156,13 +156,12 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
(strcmp(sys_dirent->d_name, ".")) && \ (strcmp(sys_dirent->d_name, ".")) && \
(strcmp(sys_dirent->d_name, ".."))) (strcmp(sys_dirent->d_name, "..")))
static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) static int tp_event_has_id(const char *dir_path, struct dirent *evt_dir)
{ {
char evt_path[MAXPATHLEN]; char evt_path[MAXPATHLEN];
int fd; int fd;
snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name);
sys_dir->d_name, evt_dir->d_name);
fd = open(evt_path, O_RDONLY); fd = open(evt_path, O_RDONLY);
if (fd < 0) if (fd < 0)
return -EINVAL; return -EINVAL;
@ -171,12 +170,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
return 0; return 0;
} }
#define for_each_event(sys_dirent, evt_dir, evt_dirent) \ #define for_each_event(dir_path, evt_dir, evt_dirent) \
while ((evt_dirent = readdir(evt_dir)) != NULL) \ while ((evt_dirent = readdir(evt_dir)) != NULL) \
if (evt_dirent->d_type == DT_DIR && \ if (evt_dirent->d_type == DT_DIR && \
(strcmp(evt_dirent->d_name, ".")) && \ (strcmp(evt_dirent->d_name, ".")) && \
(strcmp(evt_dirent->d_name, "..")) && \ (strcmp(evt_dirent->d_name, "..")) && \
(!tp_event_has_id(sys_dirent, evt_dirent))) (!tp_event_has_id(dir_path, evt_dirent)))
#define MAX_EVENT_LENGTH 512 #define MAX_EVENT_LENGTH 512
@ -190,21 +189,21 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
int fd; int fd;
u64 id; u64 id;
char evt_path[MAXPATHLEN]; char evt_path[MAXPATHLEN];
char dir_path[MAXPATHLEN]; char *dir_path;
sys_dir = opendir(tracing_events_path); sys_dir = tracing_events__opendir();
if (!sys_dir) if (!sys_dir)
return NULL; return NULL;
for_each_subsystem(sys_dir, sys_dirent) { for_each_subsystem(sys_dir, sys_dirent) {
dir_path = get_events_file(sys_dirent->d_name);
snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, if (!dir_path)
sys_dirent->d_name); continue;
evt_dir = opendir(dir_path); evt_dir = opendir(dir_path);
if (!evt_dir) if (!evt_dir)
continue; goto next;
for_each_event(sys_dirent, evt_dir, evt_dirent) { for_each_event(dir_path, evt_dir, evt_dirent) {
scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
evt_dirent->d_name); evt_dirent->d_name);
@ -218,6 +217,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
close(fd); close(fd);
id = atoll(id_buf); id = atoll(id_buf);
if (id == config) { if (id == config) {
put_events_file(dir_path);
closedir(evt_dir); closedir(evt_dir);
closedir(sys_dir); closedir(sys_dir);
path = zalloc(sizeof(*path)); path = zalloc(sizeof(*path));
@ -242,6 +242,8 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
} }
} }
closedir(evt_dir); closedir(evt_dir);
next:
put_events_file(dir_path);
} }
closedir(sys_dir); closedir(sys_dir);
@ -512,14 +514,19 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx,
struct parse_events_error *err, struct parse_events_error *err,
struct list_head *head_config) struct list_head *head_config)
{ {
char evt_path[MAXPATHLEN]; char *evt_path;
struct dirent *evt_ent; struct dirent *evt_ent;
DIR *evt_dir; DIR *evt_dir;
int ret = 0, found = 0; int ret = 0, found = 0;
snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_path = get_events_file(sys_name);
if (!evt_path) {
tracepoint_error(err, errno, sys_name, evt_name);
return -1;
}
evt_dir = opendir(evt_path); evt_dir = opendir(evt_path);
if (!evt_dir) { if (!evt_dir) {
put_events_file(evt_path);
tracepoint_error(err, errno, sys_name, evt_name); tracepoint_error(err, errno, sys_name, evt_name);
return -1; return -1;
} }
@ -545,6 +552,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx,
ret = -1; ret = -1;
} }
put_events_file(evt_path);
closedir(evt_dir); closedir(evt_dir);
return ret; return ret;
} }
@ -570,7 +578,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
DIR *events_dir; DIR *events_dir;
int ret = 0; int ret = 0;
events_dir = opendir(tracing_events_path); events_dir = tracing_events__opendir();
if (!events_dir) { if (!events_dir) {
tracepoint_error(err, errno, sys_name, evt_name); tracepoint_error(err, errno, sys_name, evt_name);
return -1; return -1;
@ -2092,13 +2100,13 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
DIR *sys_dir, *evt_dir; DIR *sys_dir, *evt_dir;
struct dirent *sys_dirent, *evt_dirent; struct dirent *sys_dirent, *evt_dirent;
char evt_path[MAXPATHLEN]; char evt_path[MAXPATHLEN];
char dir_path[MAXPATHLEN]; char *dir_path;
char **evt_list = NULL; char **evt_list = NULL;
unsigned int evt_i = 0, evt_num = 0; unsigned int evt_i = 0, evt_num = 0;
bool evt_num_known = false; bool evt_num_known = false;
restart: restart:
sys_dir = opendir(tracing_events_path); sys_dir = tracing_events__opendir();
if (!sys_dir) if (!sys_dir)
return; return;
@ -2113,13 +2121,14 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
!strglobmatch(sys_dirent->d_name, subsys_glob)) !strglobmatch(sys_dirent->d_name, subsys_glob))
continue; continue;
snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, dir_path = get_events_file(sys_dirent->d_name);
sys_dirent->d_name); if (!dir_path)
continue;
evt_dir = opendir(dir_path); evt_dir = opendir(dir_path);
if (!evt_dir) if (!evt_dir)
continue; goto next;
for_each_event(sys_dirent, evt_dir, evt_dirent) { for_each_event(dir_path, evt_dir, evt_dirent) {
if (event_glob != NULL && if (event_glob != NULL &&
!strglobmatch(evt_dirent->d_name, event_glob)) !strglobmatch(evt_dirent->d_name, event_glob))
continue; continue;
@ -2133,11 +2142,15 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
sys_dirent->d_name, evt_dirent->d_name); sys_dirent->d_name, evt_dirent->d_name);
evt_list[evt_i] = strdup(evt_path); evt_list[evt_i] = strdup(evt_path);
if (evt_list[evt_i] == NULL) if (evt_list[evt_i] == NULL) {
put_events_file(dir_path);
goto out_close_evt_dir; goto out_close_evt_dir;
}
evt_i++; evt_i++;
} }
closedir(evt_dir); closedir(evt_dir);
next:
put_events_file(dir_path);
} }
closedir(sys_dir); closedir(sys_dir);
@ -2185,21 +2198,21 @@ int is_valid_tracepoint(const char *event_string)
DIR *sys_dir, *evt_dir; DIR *sys_dir, *evt_dir;
struct dirent *sys_dirent, *evt_dirent; struct dirent *sys_dirent, *evt_dirent;
char evt_path[MAXPATHLEN]; char evt_path[MAXPATHLEN];
char dir_path[MAXPATHLEN]; char *dir_path;
sys_dir = opendir(tracing_events_path); sys_dir = tracing_events__opendir();
if (!sys_dir) if (!sys_dir)
return 0; return 0;
for_each_subsystem(sys_dir, sys_dirent) { for_each_subsystem(sys_dir, sys_dirent) {
dir_path = get_events_file(sys_dirent->d_name);
snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, if (!dir_path)
sys_dirent->d_name); continue;
evt_dir = opendir(dir_path); evt_dir = opendir(dir_path);
if (!evt_dir) if (!evt_dir)
continue; goto next;
for_each_event(sys_dirent, evt_dir, evt_dirent) { for_each_event(dir_path, evt_dir, evt_dirent) {
snprintf(evt_path, MAXPATHLEN, "%s:%s", snprintf(evt_path, MAXPATHLEN, "%s:%s",
sys_dirent->d_name, evt_dirent->d_name); sys_dirent->d_name, evt_dirent->d_name);
if (!strcmp(evt_path, event_string)) { if (!strcmp(evt_path, event_string)) {
@ -2209,6 +2222,8 @@ int is_valid_tracepoint(const char *event_string)
} }
} }
closedir(evt_dir); closedir(evt_dir);
next:
put_events_file(dir_path);
} }
closedir(sys_dir); closedir(sys_dir);
return 0; return 0;

View File

@ -84,8 +84,7 @@ int open_trace_file(const char *trace_file, bool readwrite)
char buf[PATH_MAX]; char buf[PATH_MAX];
int ret; int ret;
ret = e_snprintf(buf, PATH_MAX, "%s/%s", ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
tracing_path, trace_file);
if (ret >= 0) { if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite); pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run) if (readwrite && !probe_event_dry_run)

View File

@ -2582,7 +2582,7 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
if (sort__mode != SORT_MODE__MEMORY) if (sort__mode != SORT_MODE__MEMORY)
return -EINVAL; return -EINVAL;
if (sd->entry == &sort_mem_dcacheline && cacheline_size == 0) if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0)
return -EINVAL; return -EINVAL;
if (sd->entry == &sort_mem_daddr_sym) if (sd->entry == &sort_mem_daddr_sym)
@ -2628,7 +2628,7 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str,
if (*tok) { if (*tok) {
ret = sort_dimension__add(list, tok, evlist, level); ret = sort_dimension__add(list, tok, evlist, level);
if (ret == -EINVAL) { if (ret == -EINVAL) {
if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok)))
pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system");
else else
pr_err("Invalid --sort key: `%s'", tok); pr_err("Invalid --sort key: `%s'", tok);

View File

@ -186,13 +186,13 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he)
static inline u64 cl_address(u64 address) static inline u64 cl_address(u64 address)
{ {
/* return the cacheline of the address */ /* return the cacheline of the address */
return (address & ~(cacheline_size - 1)); return (address & ~(cacheline_size() - 1));
} }
static inline u64 cl_offset(u64 address) static inline u64 cl_offset(u64 address)
{ {
/* return the cacheline of the address */ /* return the cacheline of the address */
return (address & (cacheline_size - 1)); return (address & (cacheline_size() - 1));
} }
enum sort_mode { enum sort_mode {

View File

@ -103,11 +103,10 @@ static int record_file(const char *file, ssize_t hdr_sz)
static int record_header_files(void) static int record_header_files(void)
{ {
char *path; char *path = get_events_file("header_page");
struct stat st; struct stat st;
int err = -EIO; int err = -EIO;
path = get_tracing_file("events/header_page");
if (!path) { if (!path) {
pr_debug("can't get tracing/events/header_page"); pr_debug("can't get tracing/events/header_page");
return -ENOMEM; return -ENOMEM;
@ -128,9 +127,9 @@ static int record_header_files(void)
goto out; goto out;
} }
put_tracing_file(path); put_events_file(path);
path = get_tracing_file("events/header_event"); path = get_events_file("header_event");
if (!path) { if (!path) {
pr_debug("can't get tracing/events/header_event"); pr_debug("can't get tracing/events/header_event");
err = -ENOMEM; err = -ENOMEM;
@ -154,7 +153,7 @@ static int record_header_files(void)
err = 0; err = 0;
out: out:
put_tracing_file(path); put_events_file(path);
return err; return err;
} }
@ -243,7 +242,7 @@ static int record_ftrace_files(struct tracepoint_path *tps)
char *path; char *path;
int ret; int ret;
path = get_tracing_file("events/ftrace"); path = get_events_file("ftrace");
if (!path) { if (!path) {
pr_debug("can't get tracing/events/ftrace"); pr_debug("can't get tracing/events/ftrace");
return -ENOMEM; return -ENOMEM;

View File

@ -75,6 +75,7 @@ void trace_event__cleanup(struct trace_event *t)
static struct event_format* static struct event_format*
tp_format(const char *sys, const char *name) tp_format(const char *sys, const char *name)
{ {
char *tp_dir = get_events_file(sys);
struct pevent *pevent = tevent.pevent; struct pevent *pevent = tevent.pevent;
struct event_format *event = NULL; struct event_format *event = NULL;
char path[PATH_MAX]; char path[PATH_MAX];
@ -82,8 +83,11 @@ tp_format(const char *sys, const char *name)
char *data; char *data;
int err; int err;
scnprintf(path, PATH_MAX, "%s/%s/%s/format", if (!tp_dir)
tracing_events_path, sys, name); return ERR_PTR(-errno);
scnprintf(path, PATH_MAX, "%s/%s/format", tp_dir, name);
put_events_file(tp_dir);
err = filename__read_str(path, &data, &size); err = filename__read_str(path, &data, &size);
if (err) if (err)

View File

@ -38,11 +38,43 @@ void perf_set_multithreaded(void)
} }
unsigned int page_size; unsigned int page_size;
int cacheline_size;
#ifdef _SC_LEVEL1_DCACHE_LINESIZE
#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
#else
static void cache_line_size(int *cacheline_sizep)
{
if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep))
pr_debug("cannot determine cache line size");
}
#endif
int cacheline_size(void)
{
static int size;
if (!size)
cache_line_size(&size);
return size;
}
int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
int sysctl__max_stack(void)
{
int value;
if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
sysctl_perf_event_max_stack = value;
if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
sysctl_perf_event_max_contexts_per_stack = value;
return sysctl_perf_event_max_stack;
}
bool test_attr__enabled; bool test_attr__enabled;
bool perf_host = true; bool perf_host = true;

View File

@ -43,7 +43,9 @@ size_t hex_width(u64 v);
int hex2u64(const char *ptr, u64 *val); int hex2u64(const char *ptr, u64 *val);
extern unsigned int page_size; extern unsigned int page_size;
extern int cacheline_size; int __pure cacheline_size(void);
int sysctl__max_stack(void);
int fetch_kernel_version(unsigned int *puint, int fetch_kernel_version(unsigned int *puint,
char *str, size_t str_sz); char *str, size_t str_sz);