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 */
#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))
#ifndef __packed
#define __packed __attribute__((packed))

View File

@ -13,11 +13,9 @@
#include "tracing_path.h"
char tracing_mnt[PATH_MAX] = "/sys/kernel/debug";
char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing";
char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events";
static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug";
static char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing";
static char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events";
static void __tracing_path_set(const char *tracing, const char *mountpoint)
{
@ -76,7 +74,7 @@ char *get_tracing_file(const char *name)
{
char *file;
if (asprintf(&file, "%s/%s", tracing_path, name) < 0)
if (asprintf(&file, "%s/%s", tracing_path_mount(), name) < 0)
return NULL;
return file;
@ -87,6 +85,34 @@ void put_tracing_file(char *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,
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,
"Error:\tNo permissions to read %s/%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;
default:

View File

@ -3,9 +3,9 @@
#define __API_FS_TRACING_PATH_H
#include <linux/types.h>
#include <dirent.h>
extern char tracing_path[];
extern char tracing_events_path[];
DIR *tracing_events__opendir(void);
void tracing_path_set(const char *mountpoint);
const char *tracing_path_mount(void);
@ -13,5 +13,10 @@ const char *tracing_path_mount(void);
char *get_tracing_file(const char *name);
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);
#endif /* __API_FS_TRACING_PATH_H */

View File

@ -770,9 +770,11 @@ endif
ifndef NO_LIBBPF
$(call QUIET_INSTALL, lib) \
$(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'
$(call QUIET_INSTALL, lib) \
$(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'
endif
$(call QUIET_INSTALL, perf-archive) \

View File

@ -153,8 +153,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_PERIOD,
PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
},
@ -165,8 +165,9 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,
PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
PERF_OUTPUT_BPF_OUTPUT,
.invalid_fields = PERF_OUTPUT_TRACE,
},
@ -185,10 +186,10 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT |
PERF_OUTPUT_PHYS_ADDR,
PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
PERF_OUTPUT_ADDR | PERF_OUTPUT_DATA_SRC |
PERF_OUTPUT_WEIGHT | PERF_OUTPUT_PHYS_ADDR,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
},
@ -199,8 +200,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_PERIOD,
PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
},
@ -211,8 +212,8 @@ static struct {
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_SYNTH,
PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
PERF_OUTPUT_DSO | PERF_OUTPUT_SYNTH,
.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) {
output[j].fields |= PERF_OUTPUT_IP;
output[j].fields |= PERF_OUTPUT_SYM;
output[j].fields |= PERF_OUTPUT_SYMOFFSET;
output[j].fields |= PERF_OUTPUT_DSO;
set_print_ip_opts(attr);
goto out;

View File

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

View File

@ -3162,7 +3162,7 @@ int cmd_trace(int argc, const char **argv)
mmap_pages_user_set = false;
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;
}

View File

@ -238,7 +238,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
(*argc)--;
} else if (strstarts(cmd, 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)
*envchanged = 1;
} else if (!strcmp(cmd, "--list-cmds")) {
@ -421,22 +421,11 @@ void pthread__unblock_sigwinch(void)
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 err;
const char *cmd;
char sbuf[STRERR_BUFSIZE];
int value;
/* libsubcmd init */
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. */
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]);
if (!cmd)
@ -458,15 +440,11 @@ int main(int argc, const char **argv)
srandom(time(NULL));
perf_config__init();
err = perf_config(perf_default_config, NULL);
if (err)
return err;
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:
*

View File

@ -1323,12 +1323,12 @@ static int count_tracepoints(void)
DIR *events_dir;
int cnt = 0;
events_dir = opendir(tracing_events_path);
events_dir = tracing_events__opendir();
TEST_ASSERT_VAL("Can't open events dir", events_dir);
while ((events_ent = readdir(events_dir))) {
char sys_path[PATH_MAX];
char *sys_path;
struct dirent *sys_ent;
DIR *sys_dir;
@ -1339,8 +1339,8 @@ static int count_tracepoints(void)
|| !strcmp(events_ent->d_name, "header_page"))
continue;
scnprintf(sys_path, PATH_MAX, "%s/%s",
tracing_events_path, events_ent->d_name);
sys_path = get_events_file(events_ent->d_name);
TEST_ASSERT_VAL("Can't get sys path", sys_path);
sys_dir = opendir(sys_path);
TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
@ -1356,6 +1356,7 @@ static int count_tracepoints(void)
}
closedir(sys_dir);
put_events_file(sys_path);
}
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() {
idx=0
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
s390x)
eventattr='call-graph=dwarf,max-stack=4'
expected[2]="gaih_inet.*[[:space:]]\($libc|inlined\)$"
expected[3]="(__GI_)?getaddrinfo[[:space:]]\($libc|inlined\)$"
expected[4]="main[[:space:]]\(.*/bin/ping.*\)$"
expected[2]="gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$"
expected[3]="(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$"
expected[4]="main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$"
;;
*)
eventattr='max-stack=3'
expected[2]="getaddrinfo[[:space:]]\($libc\)$"
expected[3]=".*\(.*/bin/ping.*\)$"
expected[2]="getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$"
expected[3]=".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$"
;;
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"
"s Toggle source code view\n"
"t Circulate percent, total period, samples view\n"
"c Show min/max cycle\n"
"/ Search string\n"
"k Toggle line numbers\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;
annotation__update_column_widths(notes);
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_ESC:
case 'q':

View File

@ -760,6 +760,15 @@ static int __symbol__account_cycles(struct annotation *notes,
ch[offset].num_aggr++;
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)
return 0;
if (ch[offset].num) {
@ -953,8 +962,11 @@ void annotation__compute_ipc(struct annotation *notes, size_t size)
if (ch->have_start)
annotation__count_and_fill(notes, ch->start, offset, ch);
al = notes->offsets[offset];
if (al && ch->num_aggr)
if (al && 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;
}
}
@ -2486,13 +2498,38 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
else
obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
if (al->cycles)
obj__printf(obj, "%*" PRIu64 " ",
if (!notes->options->show_minmax_cycle) {
if (al->cycles)
obj__printf(obj, "%*" PRIu64 " ",
ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
else if (!show_title)
obj__printf(obj, "%*s", ANNOTATION__CYCLES_WIDTH, " ");
else
obj__printf(obj, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle");
else if (!show_title)
obj__printf(obj, "%*s",
ANNOTATION__CYCLES_WIDTH, " ");
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, " ");

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__CYCLES_WIDTH 6
#define ANNOTATION__MINMAX_CYCLES_WIDTH 19
struct annotation_options {
bool hide_src_code,
@ -69,7 +70,8 @@ struct annotation_options {
show_linenr,
show_nr_jumps,
show_nr_samples,
show_total_period;
show_total_period,
show_minmax_cycle;
u8 offset_level;
};
@ -105,6 +107,8 @@ struct annotation_line {
int jump_sources;
float ipc;
u64 cycles;
u64 cycles_max;
u64 cycles_min;
size_t privsize;
char *path;
u32 idx;
@ -186,6 +190,8 @@ struct cyc_hist {
u64 start;
u64 cycles;
u64 cycles_aggr;
u64 cycles_max;
u64 cycles_min;
u32 num;
u32 num_aggr;
u8 have_start;
@ -239,6 +245,9 @@ struct annotation {
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;
}

View File

@ -707,6 +707,14 @@ struct perf_config_set *perf_config_set__new(void)
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 ret = 0;
@ -714,7 +722,7 @@ int perf_config(config_fn_t fn, void *data)
struct perf_config_section *section;
struct perf_config_item *item;
if (config_set == NULL)
if (config_set == NULL && perf_config__init())
return -1;
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;
}
void perf_config__init(void)
{
if (config_set == NULL)
config_set = perf_config_set__new();
}
void perf_config__exit(void)
{
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);
int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
const char *var, const char *value);
void perf_config__init(void);
void perf_config__exit(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;
}
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)
{
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);
const char *perf_env__arch(struct perf_env *env);
const char *perf_env__raw_arch(struct perf_env *env);
#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,
"Not enough memory to setup event with callchain.\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;
case ENODEV:
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);
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,
iter_cycles, branch_from, srcline);
}
@ -2296,6 +2296,15 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
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)
{
struct map *map = machine__kernel_map(machine);
@ -2312,7 +2321,12 @@ int machine__get_kernel_start(struct machine *machine)
machine->kernel_start = 1ULL << 63;
if (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;
}
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;
}
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);

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

View File

@ -84,8 +84,7 @@ int open_trace_file(const char *trace_file, bool readwrite)
char buf[PATH_MAX];
int ret;
ret = e_snprintf(buf, PATH_MAX, "%s/%s",
tracing_path, trace_file);
ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite);
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)
return -EINVAL;
if (sd->entry == &sort_mem_dcacheline && cacheline_size == 0)
if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0)
return -EINVAL;
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) {
ret = sort_dimension__add(list, tok, evlist, level);
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");
else
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)
{
/* return the cacheline of the address */
return (address & ~(cacheline_size - 1));
return (address & ~(cacheline_size() - 1));
}
static inline u64 cl_offset(u64 address)
{
/* return the cacheline of the address */
return (address & (cacheline_size - 1));
return (address & (cacheline_size() - 1));
}
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)
{
char *path;
char *path = get_events_file("header_page");
struct stat st;
int err = -EIO;
path = get_tracing_file("events/header_page");
if (!path) {
pr_debug("can't get tracing/events/header_page");
return -ENOMEM;
@ -128,9 +127,9 @@ static int record_header_files(void)
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) {
pr_debug("can't get tracing/events/header_event");
err = -ENOMEM;
@ -154,7 +153,7 @@ static int record_header_files(void)
err = 0;
out:
put_tracing_file(path);
put_events_file(path);
return err;
}
@ -243,7 +242,7 @@ static int record_ftrace_files(struct tracepoint_path *tps)
char *path;
int ret;
path = get_tracing_file("events/ftrace");
path = get_events_file("ftrace");
if (!path) {
pr_debug("can't get tracing/events/ftrace");
return -ENOMEM;

View File

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

View File

@ -38,11 +38,43 @@ void perf_set_multithreaded(void)
}
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_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 perf_host = true;

View File

@ -43,7 +43,9 @@ size_t hex_width(u64 v);
int hex2u64(const char *ptr, u64 *val);
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,
char *str, size_t str_sz);