mirror of https://gitee.com/openkylin/linux.git
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:
commit
2996123e7e
|
@ -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))
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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, " ");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue