perf/core improvements and fixes:
BPF: Jiri Olsa: - Preserve eBPF maps when loading kcore. - Fix up DSO name padding in 'perf script --call-trace', as BPF DSO names are much larger than what we used to have there. - Add --show-bpf-events to 'perf script'. perf trace: Arnaldo Carvalho de Melo: - Add string table generators and beautify arguments for the new fspick, fsmount, fsconfig, fsopen, move_mount and open_tree syscalls, as well as new values for arguments of clone and sync_file_range syscalls. perf version: Arnaldo Carvalho de Melo: - Append 12 git SHA chars to the version string. Namespaces: Namhyung Kim: - Add missing --namespaces option to 'perf top', to generate and process namespace events, just like present for 'perf record'. Intel PT: Andrian Hunter: - Fix itrace defaults for 'perf script', not using the 'use_browser' variable to figure out what options are better for 'script' and 'report' - Allow root fixing up buildid cache permissions in the perf-with-kcore.sh script when sharing that cache with another user. - Improve sync_switch, a facility used to synchronize decoding of HW traces more closely with the point in the kerne where a context switch took place, by processing the PERF_RECORD_CONTEXT_SWITCH "in" metadata records too. - Make the exported-sql-viewer.py GUI also support pyside2, which upgrades from qt4 used in pyside to qt5. Use the argparser module for more easily addition of new command line args. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCXO6GDwAKCRCyPKLppCJ+ J5JmAQDoIRRVGZFN+GCAR8gDSL42xcFzVlInSMxXdPNzCQrtWgEAm0QP+hdM0zUp m6v7XTTzJkJ49CE7Z9O4mt6/LY1/Fw0= =sEiy -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-5.3-20190529' 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: BPF: Jiri Olsa: - Preserve eBPF maps when loading kcore. - Fix up DSO name padding in 'perf script --call-trace', as BPF DSO names are much larger than what we used to have there. - Add --show-bpf-events to 'perf script'. perf trace: Arnaldo Carvalho de Melo: - Add string table generators and beautify arguments for the new fspick, fsmount, fsconfig, fsopen, move_mount and open_tree syscalls, as well as new values for arguments of clone and sync_file_range syscalls. perf version: Arnaldo Carvalho de Melo: - Append 12 git SHA chars to the version string. Namespaces: Namhyung Kim: - Add missing --namespaces option to 'perf top', to generate and process namespace events, just like present for 'perf record'. Intel PT: Andrian Hunter: - Fix itrace defaults for 'perf script', not using the 'use_browser' variable to figure out what options are better for 'script' and 'report' - Allow root fixing up buildid cache permissions in the perf-with-kcore.sh script when sharing that cache with another user. - Improve sync_switch, a facility used to synchronize decoding of HW traces more closely with the point in the kerne where a context switch took place, by processing the PERF_RECORD_CONTEXT_SWITCH "in" metadata records too. - Make the exported-sql-viewer.py GUI also support pyside2, which upgrades from qt4 used in pyside to qt5. Use the argparser module for more easily addition of new command line args. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
b33fb3cf6f
tools
include/linux
lib
perf
Documentation
Makefile.perfbuiltin-script.cbuiltin-top.cbuiltin-trace.cexamples/bpf
perf-with-kcore.shscripts/python
tests
trace/beauty
Buildbeauty.hclone.cfsconfig.shfsmount.cfsmount.shfspick.cfspick.shmove_mount.cmove_mount_flags.shsync_file_range.csync_file_range.sh
ui/browsers
util
@ -102,6 +102,7 @@
|
||||
|
||||
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
||||
int scnprintf(char * buf, size_t size, const char * fmt, ...);
|
||||
int scnprintf_pad(char * buf, size_t size, const char * fmt, ...);
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
||||
|
||||
|
@ -23,3 +23,22 @@ int scnprintf(char * buf, size_t size, const char * fmt, ...)
|
||||
|
||||
return (i >= ssize) ? (ssize - 1) : i;
|
||||
}
|
||||
|
||||
int scnprintf_pad(char * buf, size_t size, const char * fmt, ...)
|
||||
{
|
||||
ssize_t ssize = size;
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vscnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (i < (int) size) {
|
||||
for (; i < (int) size; i++)
|
||||
buf[i] = ' ';
|
||||
buf[i] = 0x0;
|
||||
}
|
||||
|
||||
return (i >= ssize) ? (ssize - 1) : i;
|
||||
}
|
||||
|
@ -88,16 +88,16 @@ smaller.
|
||||
|
||||
To represent software control flow, "branches" samples are produced. By default
|
||||
a branch sample is synthesized for every single branch. To get an idea what
|
||||
data is available you can use the 'perf script' tool with no parameters, which
|
||||
will list all the samples.
|
||||
data is available you can use the 'perf script' tool with all itrace sampling
|
||||
options, which will list all the samples.
|
||||
|
||||
perf record -e intel_pt//u ls
|
||||
perf script
|
||||
perf script --itrace=ibxwpe
|
||||
|
||||
An interesting field that is not printed by default is 'flags' which can be
|
||||
displayed as follows:
|
||||
|
||||
perf script -Fcomm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr,symoff,flags
|
||||
perf script --itrace=ibxwpe -F+flags
|
||||
|
||||
The flags are "bcrosyiABEx" which stand for branch, call, return, conditional,
|
||||
system, asynchronous, interrupt, transaction abort, trace begin, trace end, and
|
||||
@ -713,7 +713,7 @@ Having no option is the same as
|
||||
|
||||
which, in turn, is the same as
|
||||
|
||||
--itrace=ibxwpe
|
||||
--itrace=cepwx
|
||||
|
||||
The letters are:
|
||||
|
||||
|
@ -313,6 +313,9 @@ OPTIONS
|
||||
--show-round-events
|
||||
Display finished round events i.e. events of type PERF_RECORD_FINISHED_ROUND.
|
||||
|
||||
--show-bpf-events
|
||||
Display bpf events i.e. events of type PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT.
|
||||
|
||||
--demangle::
|
||||
Demangle symbol names to human readable form. It's enabled by default,
|
||||
disable with --no-demangle.
|
||||
|
@ -262,6 +262,11 @@ Default is to monitor all CPUS.
|
||||
The number of threads to run when synthesizing events for existing processes.
|
||||
By default, the number of threads equals to the number of online CPUs.
|
||||
|
||||
--namespaces::
|
||||
Record events of type PERF_RECORD_NAMESPACES and display it with the
|
||||
'cgroup_id' sort key.
|
||||
|
||||
|
||||
INTERACTIVE PROMPTING KEYS
|
||||
--------------------------
|
||||
|
||||
|
@ -419,6 +419,24 @@ fadvise_advice_tbl := $(srctree)/tools/perf/trace/beauty/fadvise.sh
|
||||
$(fadvise_advice_array): $(linux_uapi_dir)/in.h $(fadvise_advice_tbl)
|
||||
$(Q)$(SHELL) '$(fadvise_advice_tbl)' $(linux_uapi_dir) > $@
|
||||
|
||||
fsmount_arrays := $(beauty_outdir)/fsmount_arrays.c
|
||||
fsmount_tbls := $(srctree)/tools/perf/trace/beauty/fsmount.sh
|
||||
|
||||
$(fsmount_arrays): $(linux_uapi_dir)/fs.h $(fsmount_tbls)
|
||||
$(Q)$(SHELL) '$(fsmount_tbls)' $(linux_uapi_dir) > $@
|
||||
|
||||
fspick_arrays := $(beauty_outdir)/fspick_arrays.c
|
||||
fspick_tbls := $(srctree)/tools/perf/trace/beauty/fspick.sh
|
||||
|
||||
$(fspick_arrays): $(linux_uapi_dir)/fs.h $(fspick_tbls)
|
||||
$(Q)$(SHELL) '$(fspick_tbls)' $(linux_uapi_dir) > $@
|
||||
|
||||
fsconfig_arrays := $(beauty_outdir)/fsconfig_arrays.c
|
||||
fsconfig_tbls := $(srctree)/tools/perf/trace/beauty/fsconfig.sh
|
||||
|
||||
$(fsconfig_arrays): $(linux_uapi_dir)/fs.h $(fsconfig_tbls)
|
||||
$(Q)$(SHELL) '$(fsconfig_tbls)' $(linux_uapi_dir) > $@
|
||||
|
||||
pkey_alloc_access_rights_array := $(beauty_outdir)/pkey_alloc_access_rights_array.c
|
||||
asm_generic_hdr_dir := $(srctree)/tools/include/uapi/asm-generic/
|
||||
pkey_alloc_access_rights_tbl := $(srctree)/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
|
||||
@ -493,6 +511,12 @@ mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh
|
||||
$(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl)
|
||||
$(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@
|
||||
|
||||
move_mount_flags_array := $(beauty_outdir)/move_mount_flags_array.c
|
||||
move_mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/move_mount_flags.sh
|
||||
|
||||
$(move_mount_flags_array): $(linux_uapi_dir)/fs.h $(move_mount_flags_tbl)
|
||||
$(Q)$(SHELL) '$(move_mount_flags_tbl)' $(linux_uapi_dir) > $@
|
||||
|
||||
prctl_option_array := $(beauty_outdir)/prctl_option_array.c
|
||||
prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/
|
||||
prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
|
||||
@ -525,6 +549,12 @@ arch_errno_tbl := $(srctree)/tools/perf/trace/beauty/arch_errno_names.sh
|
||||
$(arch_errno_name_array): $(arch_errno_tbl)
|
||||
$(Q)$(SHELL) '$(arch_errno_tbl)' $(CC) $(arch_errno_hdr_dir) > $@
|
||||
|
||||
sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c
|
||||
sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh
|
||||
|
||||
$(sync_file_range_arrays): $(linux_uapi_dir)/fs.h $(sync_file_range_tbls)
|
||||
$(Q)$(SHELL) '$(sync_file_range_tbls)' $(linux_uapi_dir) > $@
|
||||
|
||||
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
||||
|
||||
# Create python binding output directory if not already present
|
||||
@ -628,6 +658,9 @@ build-dir = $(if $(__build-dir),$(__build-dir),.)
|
||||
|
||||
prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioctl_array) \
|
||||
$(fadvise_advice_array) \
|
||||
$(fsconfig_arrays) \
|
||||
$(fsmount_arrays) \
|
||||
$(fspick_arrays) \
|
||||
$(pkey_alloc_access_rights_array) \
|
||||
$(sndrv_pcm_ioctl_array) \
|
||||
$(sndrv_ctl_ioctl_array) \
|
||||
@ -638,12 +671,14 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
|
||||
$(madvise_behavior_array) \
|
||||
$(mmap_flags_array) \
|
||||
$(mount_flags_array) \
|
||||
$(move_mount_flags_array) \
|
||||
$(perf_ioctl_array) \
|
||||
$(prctl_option_array) \
|
||||
$(usbdevfs_ioctl_array) \
|
||||
$(x86_arch_prctl_code_array) \
|
||||
$(rename_flags_array) \
|
||||
$(arch_errno_name_array)
|
||||
$(arch_errno_name_array) \
|
||||
$(sync_file_range_arrays)
|
||||
|
||||
$(OUTPUT)%.o: %.c prepare FORCE
|
||||
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
|
||||
@ -922,9 +957,13 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
|
||||
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
|
||||
$(OUTPUT)pmu-events/pmu-events.c \
|
||||
$(OUTPUT)$(fadvise_advice_array) \
|
||||
$(OUTPUT)$(fsconfig_arrays) \
|
||||
$(OUTPUT)$(fsmount_arrays) \
|
||||
$(OUTPUT)$(fspick_arrays) \
|
||||
$(OUTPUT)$(madvise_behavior_array) \
|
||||
$(OUTPUT)$(mmap_flags_array) \
|
||||
$(OUTPUT)$(mount_flags_array) \
|
||||
$(OUTPUT)$(move_mount_flags_array) \
|
||||
$(OUTPUT)$(drm_ioctl_array) \
|
||||
$(OUTPUT)$(pkey_alloc_access_rights_array) \
|
||||
$(OUTPUT)$(sndrv_ctl_ioctl_array) \
|
||||
@ -938,7 +977,8 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
|
||||
$(OUTPUT)$(usbdevfs_ioctl_array) \
|
||||
$(OUTPUT)$(x86_arch_prctl_code_array) \
|
||||
$(OUTPUT)$(rename_flags_array) \
|
||||
$(OUTPUT)$(arch_errno_name_array)
|
||||
$(OUTPUT)$(arch_errno_name_array) \
|
||||
$(OUTPUT)$(sync_file_range_arrays)
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||
|
||||
#
|
||||
|
@ -1606,6 +1606,7 @@ struct perf_script {
|
||||
bool show_namespace_events;
|
||||
bool show_lost_events;
|
||||
bool show_round_events;
|
||||
bool show_bpf_events;
|
||||
bool allocated;
|
||||
bool per_event_dump;
|
||||
struct cpu_map *cpus;
|
||||
@ -2318,6 +2319,41 @@ process_finished_round_event(struct perf_tool *tool __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_bpf_events(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||
struct perf_session *session = script->session;
|
||||
struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
|
||||
|
||||
if (machine__process_ksymbol(machine, event, sample) < 0)
|
||||
return -1;
|
||||
|
||||
if (!evsel->attr.sample_id_all) {
|
||||
perf_event__fprintf(event, stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread = machine__findnew_thread(machine, sample->pid, sample->tid);
|
||||
if (thread == NULL) {
|
||||
pr_debug("problem processing MMAP event, skipping it.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!filter_cpu(sample)) {
|
||||
perf_sample__fprintf_start(sample, thread, evsel,
|
||||
event->header.type, stdout);
|
||||
perf_event__fprintf(event, stdout);
|
||||
}
|
||||
|
||||
thread__put(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sig_handler(int sig __maybe_unused)
|
||||
{
|
||||
session_done = 1;
|
||||
@ -2420,6 +2456,10 @@ static int __cmd_script(struct perf_script *script)
|
||||
script->tool.ordered_events = false;
|
||||
script->tool.finished_round = process_finished_round_event;
|
||||
}
|
||||
if (script->show_bpf_events) {
|
||||
script->tool.ksymbol = process_bpf_events;
|
||||
script->tool.bpf_event = process_bpf_events;
|
||||
}
|
||||
|
||||
if (perf_script__setup_per_event_dump(script)) {
|
||||
pr_err("Couldn't create the per event dump files\n");
|
||||
@ -3297,6 +3337,7 @@ static int parse_call_trace(const struct option *opt __maybe_unused,
|
||||
parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0);
|
||||
itrace_parse_synth_opts(opt, "cewp", 0);
|
||||
symbol_conf.nanosecs = true;
|
||||
symbol_conf.pad_output_len_dso = 50;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3438,6 +3479,8 @@ int cmd_script(int argc, const char **argv)
|
||||
"Show lost events (if recorded)"),
|
||||
OPT_BOOLEAN('\0', "show-round-events", &script.show_round_events,
|
||||
"Show round events (if recorded)"),
|
||||
OPT_BOOLEAN('\0', "show-bpf-events", &script.show_bpf_events,
|
||||
"Show bpf related events (if recorded)"),
|
||||
OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump,
|
||||
"Dump trace output to files named by the monitored events"),
|
||||
OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
|
||||
|
@ -1208,11 +1208,14 @@ static int __cmd_top(struct perf_top *top)
|
||||
|
||||
init_process_thread(top);
|
||||
|
||||
if (opts->record_namespaces)
|
||||
top->tool.namespace_events = true;
|
||||
|
||||
ret = perf_event__synthesize_bpf_events(top->session, perf_event__process,
|
||||
&top->session->machines.host,
|
||||
&top->record_opts);
|
||||
if (ret < 0)
|
||||
pr_warning("Couldn't synthesize bpf events.\n");
|
||||
pr_debug("Couldn't synthesize BPF events: Pre-existing BPF programs won't have symbols resolved.\n");
|
||||
|
||||
machine__synthesize_threads(&top->session->machines.host, &opts->target,
|
||||
top->evlist->threads, false,
|
||||
@ -1500,6 +1503,8 @@ int cmd_top(int argc, const char **argv)
|
||||
OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"),
|
||||
OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize,
|
||||
"number of thread to run event synthesize"),
|
||||
OPT_BOOLEAN(0, "namespaces", &opts->record_namespaces,
|
||||
"Record namespaces events"),
|
||||
OPT_END()
|
||||
};
|
||||
struct perf_evlist *sb_evlist = NULL;
|
||||
|
@ -403,6 +403,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
|
||||
|
||||
#define SCA_STRARRAY syscall_arg__scnprintf_strarray
|
||||
|
||||
size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
return strarray__scnprintf_flags(arg->parm, bf, size, arg->show_string_prefix, arg->val);
|
||||
}
|
||||
|
||||
size_t strarrays__scnprintf(struct strarrays *sas, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
|
||||
{
|
||||
size_t printed;
|
||||
@ -482,6 +487,15 @@ static const char *bpf_cmd[] = {
|
||||
};
|
||||
static DEFINE_STRARRAY(bpf_cmd, "BPF_");
|
||||
|
||||
static const char *fsmount_flags[] = {
|
||||
[1] = "CLOEXEC",
|
||||
};
|
||||
static DEFINE_STRARRAY(fsmount_flags, "FSMOUNT_");
|
||||
|
||||
#include "trace/beauty/generated/fsconfig_arrays.c"
|
||||
|
||||
static DEFINE_STRARRAY(fsconfig_cmds, "FSCONFIG_");
|
||||
|
||||
static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
|
||||
static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, "EPOLL_CTL_", 1);
|
||||
|
||||
@ -642,6 +656,10 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
|
||||
{ .scnprintf = SCA_STRARRAY, \
|
||||
.parm = &strarray__##array, }
|
||||
|
||||
#define STRARRAY_FLAGS(name, array) \
|
||||
{ .scnprintf = SCA_STRARRAY_FLAGS, \
|
||||
.parm = &strarray__##array, }
|
||||
|
||||
#include "trace/beauty/arch_errno_names.c"
|
||||
#include "trace/beauty/eventfd.c"
|
||||
#include "trace/beauty/futex_op.c"
|
||||
@ -713,6 +731,15 @@ static struct syscall_fmt {
|
||||
[2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
|
||||
{ .name = "flock",
|
||||
.arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
|
||||
{ .name = "fsconfig",
|
||||
.arg = { [1] = STRARRAY(cmd, fsconfig_cmds), }, },
|
||||
{ .name = "fsmount",
|
||||
.arg = { [1] = STRARRAY_FLAGS(flags, fsmount_flags),
|
||||
[2] = { .scnprintf = SCA_FSMOUNT_ATTR_FLAGS, /* attr_flags */ }, }, },
|
||||
{ .name = "fspick",
|
||||
.arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
|
||||
[1] = { .scnprintf = SCA_FILENAME, /* path */ },
|
||||
[2] = { .scnprintf = SCA_FSPICK_FLAGS, /* flags */ }, }, },
|
||||
{ .name = "fstat", .alias = "newfstat", },
|
||||
{ .name = "fstatat", .alias = "newfstatat", },
|
||||
{ .name = "futex",
|
||||
@ -775,6 +802,12 @@ static struct syscall_fmt {
|
||||
.arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
|
||||
[3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */
|
||||
.mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, },
|
||||
{ .name = "move_mount",
|
||||
.arg = { [0] = { .scnprintf = SCA_FDAT, /* from_dfd */ },
|
||||
[1] = { .scnprintf = SCA_FILENAME, /* from_pathname */ },
|
||||
[2] = { .scnprintf = SCA_FDAT, /* to_dfd */ },
|
||||
[3] = { .scnprintf = SCA_FILENAME, /* to_pathname */ },
|
||||
[4] = { .scnprintf = SCA_MOVE_MOUNT_FLAGS, /* flags */ }, }, },
|
||||
{ .name = "mprotect",
|
||||
.arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
|
||||
[2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
|
||||
@ -879,6 +912,8 @@ static struct syscall_fmt {
|
||||
.arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
|
||||
{ .name = "symlinkat",
|
||||
.arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
|
||||
{ .name = "sync_file_range",
|
||||
.arg = { [3] = { .scnprintf = SCA_SYNC_FILE_RANGE_FLAGS, /* flags */ }, }, },
|
||||
{ .name = "tgkill",
|
||||
.arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
|
||||
{ .name = "tkill",
|
||||
|
@ -87,7 +87,7 @@ struct augmented_filename {
|
||||
#define SYS_SYMLINKAT 266
|
||||
#define SYS_MEMFD_CREATE 319
|
||||
|
||||
/* syscalls where the first arg is a string */
|
||||
/* syscalls where the second arg is a string */
|
||||
|
||||
#define SYS_PWRITE64 18
|
||||
#define SYS_EXECVE 59
|
||||
@ -117,6 +117,8 @@ struct augmented_filename {
|
||||
#define SYS_RENAMEAT2 316
|
||||
#define SYS_EXECVEAT 322
|
||||
#define SYS_STATX 332
|
||||
#define SYS_MOVE_MOUNT 429
|
||||
#define SYS_FSPICK 433
|
||||
|
||||
pid_filter(pids_filtered);
|
||||
|
||||
@ -252,11 +254,22 @@ int sys_enter(struct syscall_enter_args *args)
|
||||
case SYS_FINIT_MODULE:
|
||||
case SYS_FREMOVEXATTR:
|
||||
case SYS_FSETXATTR:
|
||||
case SYS_FSPICK:
|
||||
case SYS_FUTIMESAT:
|
||||
case SYS_INOTIFY_ADD_WATCH:
|
||||
case SYS_LINKAT:
|
||||
case SYS_MKDIRAT:
|
||||
case SYS_MKNODAT:
|
||||
// case SYS_MOVE_MOUNT:
|
||||
// For now don't copy move_mount first string arg, as it has two and
|
||||
// 'perf trace's syscall_arg__scnprintf_filename() will use the one
|
||||
// copied here, the first, for both args, duplicating the first and
|
||||
// ignoring the second.
|
||||
//
|
||||
// We need to copy both here and make syscall_arg__scnprintf_filename
|
||||
// skip the first when reading the second, using the size of the first, etc.
|
||||
// Shouldn't be difficult, but now its perf/urgent time, lets wait for
|
||||
// the next devel window.
|
||||
case SYS_MQ_TIMEDSEND:
|
||||
case SYS_NAME_TO_HANDLE_AT:
|
||||
case SYS_NEWFSTATAT:
|
||||
|
@ -111,11 +111,6 @@ fix_buildid_cache_permissions()
|
||||
|
||||
USER_HOME=$(bash <<< "echo ~$SUDO_USER")
|
||||
|
||||
if [ "$HOME" != "$USER_HOME" ] ; then
|
||||
echo "Fix unnecessary because root has a home: $HOME" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fixing buildid cache permissions"
|
||||
|
||||
find "$USER_HOME/.debug" -xdev -type d ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \;
|
||||
|
@ -27,18 +27,31 @@ import datetime
|
||||
#
|
||||
# fedora:
|
||||
#
|
||||
# $ sudo yum install postgresql postgresql-server python-pyside qt-postgresql
|
||||
# $ sudo yum install postgresql postgresql-server qt-postgresql
|
||||
# $ sudo su - postgres -c initdb
|
||||
# $ sudo service postgresql start
|
||||
# $ sudo su - postgres
|
||||
# $ createuser <your user id here>
|
||||
# $ createuser -s <your user id here> # Older versions may not support -s, in which case answer the prompt below:
|
||||
# Shall the new role be a superuser? (y/n) y
|
||||
# $ sudo yum install python-pyside
|
||||
#
|
||||
# Alternately, to use Python3 and/or pyside 2, one of the following:
|
||||
# $ sudo yum install python3-pyside
|
||||
# $ pip install --user PySide2
|
||||
# $ pip3 install --user PySide2
|
||||
#
|
||||
# ubuntu:
|
||||
#
|
||||
# $ sudo apt-get install postgresql python-pyside.qtsql libqt4-sql-psql
|
||||
# $ sudo apt-get install postgresql
|
||||
# $ sudo su - postgres
|
||||
# $ createuser -s <your user id here>
|
||||
# $ sudo apt-get install python-pyside.qtsql libqt4-sql-psql
|
||||
#
|
||||
# Alternately, to use Python3 and/or pyside 2, one of the following:
|
||||
#
|
||||
# $ sudo apt-get install python3-pyside.qtsql libqt4-sql-psql
|
||||
# $ sudo apt-get install python-pyside2.qtsql libqt5sql5-psql
|
||||
# $ sudo apt-get install python3-pyside2.qtsql libqt5sql5-psql
|
||||
#
|
||||
# An example of using this script with Intel PT:
|
||||
#
|
||||
@ -199,7 +212,16 @@ import datetime
|
||||
# print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5))
|
||||
# call_path_id = query.value(6)
|
||||
|
||||
from PySide.QtSql import *
|
||||
pyside_version_1 = True
|
||||
if not "pyside-version-1" in sys.argv:
|
||||
try:
|
||||
from PySide2.QtSql import *
|
||||
pyside_version_1 = False
|
||||
except:
|
||||
pass
|
||||
|
||||
if pyside_version_1:
|
||||
from PySide.QtSql import *
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
def toserverstr(str):
|
||||
@ -255,11 +277,12 @@ def printdate(*args, **kw_args):
|
||||
print(datetime.datetime.today(), *args, sep=' ', **kw_args)
|
||||
|
||||
def usage():
|
||||
printerr("Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]")
|
||||
printerr("where: columns 'all' or 'branches'")
|
||||
printerr(" calls 'calls' => create calls and call_paths table")
|
||||
printerr(" callchains 'callchains' => create call_paths table")
|
||||
raise Exception("Too few arguments")
|
||||
printerr("Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>] [<pyside-version-1>]");
|
||||
printerr("where: columns 'all' or 'branches'");
|
||||
printerr(" calls 'calls' => create calls and call_paths table");
|
||||
printerr(" callchains 'callchains' => create call_paths table");
|
||||
printerr(" pyside-version-1 'pyside-version-1' => use pyside version 1");
|
||||
raise Exception("Too few or bad arguments")
|
||||
|
||||
if (len(sys.argv) < 2):
|
||||
usage()
|
||||
@ -281,6 +304,8 @@ for i in range(3,len(sys.argv)):
|
||||
perf_db_export_calls = True
|
||||
elif (sys.argv[i] == "callchains"):
|
||||
perf_db_export_callchains = True
|
||||
elif (sys.argv[i] == "pyside-version-1"):
|
||||
pass
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
@ -21,6 +21,26 @@ import datetime
|
||||
# provides LGPL-licensed Python bindings for Qt. You will also need the package
|
||||
# libqt4-sql-sqlite for Qt sqlite3 support.
|
||||
#
|
||||
# Examples of installing pyside:
|
||||
#
|
||||
# ubuntu:
|
||||
#
|
||||
# $ sudo apt-get install python-pyside.qtsql libqt4-sql-psql
|
||||
#
|
||||
# Alternately, to use Python3 and/or pyside 2, one of the following:
|
||||
#
|
||||
# $ sudo apt-get install python3-pyside.qtsql libqt4-sql-psql
|
||||
# $ sudo apt-get install python-pyside2.qtsql libqt5sql5-psql
|
||||
# $ sudo apt-get install python3-pyside2.qtsql libqt5sql5-psql
|
||||
# fedora:
|
||||
#
|
||||
# $ sudo yum install python-pyside
|
||||
#
|
||||
# Alternately, to use Python3 and/or pyside 2, one of the following:
|
||||
# $ sudo yum install python3-pyside
|
||||
# $ pip install --user PySide2
|
||||
# $ pip3 install --user PySide2
|
||||
#
|
||||
# An example of using this script with Intel PT:
|
||||
#
|
||||
# $ perf record -e intel_pt//u ls
|
||||
@ -49,7 +69,16 @@ import datetime
|
||||
# difference is the 'transaction' column of the 'samples' table which is
|
||||
# renamed 'transaction_' in sqlite because 'transaction' is a reserved word.
|
||||
|
||||
from PySide.QtSql import *
|
||||
pyside_version_1 = True
|
||||
if not "pyside-version-1" in sys.argv:
|
||||
try:
|
||||
from PySide2.QtSql import *
|
||||
pyside_version_1 = False
|
||||
except:
|
||||
pass
|
||||
|
||||
if pyside_version_1:
|
||||
from PySide.QtSql import *
|
||||
|
||||
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
|
||||
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
|
||||
@ -69,11 +98,12 @@ def printdate(*args, **kw_args):
|
||||
print(datetime.datetime.today(), *args, sep=' ', **kw_args)
|
||||
|
||||
def usage():
|
||||
printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>]");
|
||||
printerr("where: columns 'all' or 'branches'");
|
||||
printerr(" calls 'calls' => create calls and call_paths table");
|
||||
printerr(" callchains 'callchains' => create call_paths table");
|
||||
raise Exception("Too few arguments")
|
||||
printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>] [<pyside-version-1>]");
|
||||
printerr("where: columns 'all' or 'branches'");
|
||||
printerr(" calls 'calls' => create calls and call_paths table");
|
||||
printerr(" callchains 'callchains' => create call_paths table");
|
||||
printerr(" pyside-version-1 'pyside-version-1' => use pyside version 1");
|
||||
raise Exception("Too few or bad arguments")
|
||||
|
||||
if (len(sys.argv) < 2):
|
||||
usage()
|
||||
@ -95,6 +125,8 @@ for i in range(3,len(sys.argv)):
|
||||
perf_db_export_calls = True
|
||||
elif (sys.argv[i] == "callchains"):
|
||||
perf_db_export_callchains = True
|
||||
elif (sys.argv[i] == "pyside-version-1"):
|
||||
pass
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# exported-sql-viewer.py: view data from sql database
|
||||
# Copyright (c) 2014-2018, Intel Corporation.
|
||||
@ -91,6 +91,7 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import weakref
|
||||
import threading
|
||||
import string
|
||||
@ -104,10 +105,23 @@ except ImportError:
|
||||
glb_nsz = 16
|
||||
import re
|
||||
import os
|
||||
from PySide.QtCore import *
|
||||
from PySide.QtGui import *
|
||||
from PySide.QtSql import *
|
||||
|
||||
pyside_version_1 = True
|
||||
if not "--pyside-version-1" in sys.argv:
|
||||
try:
|
||||
from PySide2.QtCore import *
|
||||
from PySide2.QtGui import *
|
||||
from PySide2.QtSql import *
|
||||
from PySide2.QtWidgets import *
|
||||
pyside_version_1 = False
|
||||
except:
|
||||
pass
|
||||
|
||||
if pyside_version_1:
|
||||
from PySide.QtCore import *
|
||||
from PySide.QtGui import *
|
||||
from PySide.QtSql import *
|
||||
|
||||
from decimal import *
|
||||
from ctypes import *
|
||||
from multiprocessing import Process, Array, Value, Event
|
||||
@ -2754,7 +2768,7 @@ class WindowMenu():
|
||||
action = self.window_menu.addAction(label)
|
||||
action.setCheckable(True)
|
||||
action.setChecked(sub_window == self.mdi_area.activeSubWindow())
|
||||
action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x))
|
||||
action.triggered.connect(lambda a=None,x=nr: self.setActiveSubWindow(x))
|
||||
self.window_menu.addAction(action)
|
||||
nr += 1
|
||||
|
||||
@ -3114,14 +3128,14 @@ class MainWindow(QMainWindow):
|
||||
event = event.split(":")[0]
|
||||
if event == "branches":
|
||||
label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
|
||||
reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self))
|
||||
reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewBranchView(x), self))
|
||||
label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")"
|
||||
reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self))
|
||||
reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewSelectedBranchView(x), self))
|
||||
|
||||
def TableMenu(self, tables, menu):
|
||||
table_menu = menu.addMenu("&Tables")
|
||||
for table in tables:
|
||||
table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self))
|
||||
table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda a=None,t=table: self.NewTableView(t), self))
|
||||
|
||||
def NewCallGraph(self):
|
||||
CallGraphWindow(self.glb, self)
|
||||
@ -3361,18 +3375,27 @@ class DBRef():
|
||||
# Main
|
||||
|
||||
def Main():
|
||||
if (len(sys.argv) < 2):
|
||||
printerr("Usage is: exported-sql-viewer.py {<database name> | --help-only}");
|
||||
raise Exception("Too few arguments")
|
||||
usage_str = "exported-sql-viewer.py [--pyside-version-1] <database name>\n" \
|
||||
" or: exported-sql-viewer.py --help-only"
|
||||
ap = argparse.ArgumentParser(usage = usage_str, add_help = False)
|
||||
ap.add_argument("--pyside-version-1", action='store_true')
|
||||
ap.add_argument("dbname", nargs="?")
|
||||
ap.add_argument("--help-only", action='store_true')
|
||||
args = ap.parse_args()
|
||||
|
||||
dbname = sys.argv[1]
|
||||
if dbname == "--help-only":
|
||||
if args.help_only:
|
||||
app = QApplication(sys.argv)
|
||||
mainwindow = HelpOnlyWindow()
|
||||
mainwindow.show()
|
||||
err = app.exec_()
|
||||
sys.exit(err)
|
||||
|
||||
dbname = args.dbname
|
||||
if dbname is None:
|
||||
ap.print_usage()
|
||||
print("Too few arguments")
|
||||
sys.exit(1)
|
||||
|
||||
is_sqlite3 = False
|
||||
try:
|
||||
f = open(dbname, "rb")
|
||||
|
@ -50,6 +50,7 @@ perf-y += perf-hooks.o
|
||||
perf-y += clang.o
|
||||
perf-y += unit_number__scnprintf.o
|
||||
perf-y += mem2node.o
|
||||
perf-y += map_groups.o
|
||||
|
||||
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
|
||||
$(call rule_mkdir)
|
||||
|
@ -289,6 +289,10 @@ static struct test generic_tests[] = {
|
||||
.desc = "mem2node",
|
||||
.func = test__mem2node,
|
||||
},
|
||||
{
|
||||
.desc = "map_groups__merge_in",
|
||||
.func = test__map_groups__merge_in,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
|
120
tools/perf/tests/map_groups.c
Normal file
120
tools/perf/tests/map_groups.c
Normal file
@ -0,0 +1,120 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "tests.h"
|
||||
#include "map.h"
|
||||
#include "map_groups.h"
|
||||
#include "dso.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct map_def {
|
||||
const char *name;
|
||||
u64 start;
|
||||
u64 end;
|
||||
};
|
||||
|
||||
static int check_maps(struct map_def *merged, unsigned int size, struct map_groups *mg)
|
||||
{
|
||||
struct map *map;
|
||||
unsigned int i = 0;
|
||||
|
||||
map = map_groups__first(mg);
|
||||
while (map) {
|
||||
TEST_ASSERT_VAL("wrong map start", map->start == merged[i].start);
|
||||
TEST_ASSERT_VAL("wrong map end", map->end == merged[i].end);
|
||||
TEST_ASSERT_VAL("wrong map name", !strcmp(map->dso->name, merged[i].name));
|
||||
TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 2);
|
||||
|
||||
i++;
|
||||
map = map_groups__next(map);
|
||||
|
||||
TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size));
|
||||
}
|
||||
|
||||
return TEST_OK;
|
||||
}
|
||||
|
||||
int test__map_groups__merge_in(struct test *t __maybe_unused, int subtest __maybe_unused)
|
||||
{
|
||||
struct map_groups mg;
|
||||
unsigned int i;
|
||||
struct map_def bpf_progs[] = {
|
||||
{ "bpf_prog_1", 200, 300 },
|
||||
{ "bpf_prog_2", 500, 600 },
|
||||
{ "bpf_prog_3", 800, 900 },
|
||||
};
|
||||
struct map_def merged12[] = {
|
||||
{ "kcore1", 100, 200 },
|
||||
{ "bpf_prog_1", 200, 300 },
|
||||
{ "kcore1", 300, 500 },
|
||||
{ "bpf_prog_2", 500, 600 },
|
||||
{ "kcore1", 600, 800 },
|
||||
{ "bpf_prog_3", 800, 900 },
|
||||
{ "kcore1", 900, 1000 },
|
||||
};
|
||||
struct map_def merged3[] = {
|
||||
{ "kcore1", 100, 200 },
|
||||
{ "bpf_prog_1", 200, 300 },
|
||||
{ "kcore1", 300, 500 },
|
||||
{ "bpf_prog_2", 500, 600 },
|
||||
{ "kcore1", 600, 800 },
|
||||
{ "bpf_prog_3", 800, 900 },
|
||||
{ "kcore1", 900, 1000 },
|
||||
{ "kcore3", 1000, 1100 },
|
||||
};
|
||||
struct map *map_kcore1, *map_kcore2, *map_kcore3;
|
||||
int ret;
|
||||
|
||||
map_groups__init(&mg, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) {
|
||||
struct map *map;
|
||||
|
||||
map = dso__new_map(bpf_progs[i].name);
|
||||
TEST_ASSERT_VAL("failed to create map", map);
|
||||
|
||||
map->start = bpf_progs[i].start;
|
||||
map->end = bpf_progs[i].end;
|
||||
map_groups__insert(&mg, map);
|
||||
map__put(map);
|
||||
}
|
||||
|
||||
map_kcore1 = dso__new_map("kcore1");
|
||||
TEST_ASSERT_VAL("failed to create map", map_kcore1);
|
||||
|
||||
map_kcore2 = dso__new_map("kcore2");
|
||||
TEST_ASSERT_VAL("failed to create map", map_kcore2);
|
||||
|
||||
map_kcore3 = dso__new_map("kcore3");
|
||||
TEST_ASSERT_VAL("failed to create map", map_kcore3);
|
||||
|
||||
/* kcore1 map overlaps over all bpf maps */
|
||||
map_kcore1->start = 100;
|
||||
map_kcore1->end = 1000;
|
||||
|
||||
/* kcore2 map hides behind bpf_prog_2 */
|
||||
map_kcore2->start = 550;
|
||||
map_kcore2->end = 570;
|
||||
|
||||
/* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */
|
||||
map_kcore3->start = 880;
|
||||
map_kcore3->end = 1100;
|
||||
|
||||
ret = map_groups__merge_in(&mg, map_kcore1);
|
||||
TEST_ASSERT_VAL("failed to merge map", !ret);
|
||||
|
||||
ret = check_maps(merged12, ARRAY_SIZE(merged12), &mg);
|
||||
TEST_ASSERT_VAL("merge check failed", !ret);
|
||||
|
||||
ret = map_groups__merge_in(&mg, map_kcore2);
|
||||
TEST_ASSERT_VAL("failed to merge map", !ret);
|
||||
|
||||
ret = check_maps(merged12, ARRAY_SIZE(merged12), &mg);
|
||||
TEST_ASSERT_VAL("merge check failed", !ret);
|
||||
|
||||
ret = map_groups__merge_in(&mg, map_kcore3);
|
||||
TEST_ASSERT_VAL("failed to merge map", !ret);
|
||||
|
||||
ret = check_maps(merged3, ARRAY_SIZE(merged3), &mg);
|
||||
TEST_ASSERT_VAL("merge check failed", !ret);
|
||||
return TEST_OK;
|
||||
}
|
@ -107,6 +107,7 @@ const char *test__clang_subtest_get_desc(int subtest);
|
||||
int test__clang_subtest_get_nr(void);
|
||||
int test__unit_number__scnprint(struct test *test, int subtest);
|
||||
int test__mem2node(struct test *t, int subtest);
|
||||
int test__map_groups__merge_in(struct test *t, int subtest);
|
||||
|
||||
bool test__bp_signal_is_supported(void);
|
||||
bool test__wp_is_supported(void);
|
||||
|
@ -1,11 +1,14 @@
|
||||
perf-y += clone.o
|
||||
perf-y += fcntl.o
|
||||
perf-y += flock.o
|
||||
perf-y += fsmount.o
|
||||
perf-y += fspick.o
|
||||
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86))
|
||||
perf-y += ioctl.o
|
||||
endif
|
||||
perf-y += kcmp.o
|
||||
perf-y += mount_flags.o
|
||||
perf-y += move_mount.o
|
||||
perf-y += pkey_alloc.o
|
||||
perf-y += arch_prctl.o
|
||||
perf-y += prctl.o
|
||||
@ -13,3 +16,4 @@ perf-y += renameat.o
|
||||
perf-y += sockaddr.o
|
||||
perf-y += socket.o
|
||||
perf-y += statx.o
|
||||
perf-y += sync_file_range.o
|
||||
|
@ -108,6 +108,9 @@ struct syscall_arg {
|
||||
|
||||
unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx);
|
||||
|
||||
size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_STRARRAY_FLAGS syscall_arg__scnprintf_strarray_flags
|
||||
|
||||
size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays
|
||||
|
||||
@ -141,6 +144,12 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar
|
||||
size_t syscall_arg__scnprintf_flock(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_FLOCK syscall_arg__scnprintf_flock
|
||||
|
||||
size_t syscall_arg__scnprintf_fsmount_attr_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_FSMOUNT_ATTR_FLAGS syscall_arg__scnprintf_fsmount_attr_flags
|
||||
|
||||
size_t syscall_arg__scnprintf_fspick_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_FSPICK_FLAGS syscall_arg__scnprintf_fspick_flags
|
||||
|
||||
size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_IOCTL_CMD syscall_arg__scnprintf_ioctl_cmd
|
||||
|
||||
@ -156,6 +165,9 @@ unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg, unsigne
|
||||
size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_MOUNT_FLAGS syscall_arg__scnprintf_mount_flags
|
||||
|
||||
size_t syscall_arg__scnprintf_move_mount_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_MOVE_MOUNT_FLAGS syscall_arg__scnprintf_move_mount_flags
|
||||
|
||||
size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights
|
||||
|
||||
@ -189,6 +201,9 @@ size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_
|
||||
size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask
|
||||
|
||||
size_t syscall_arg__scnprintf_sync_file_range_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_SYNC_FILE_RANGE_FLAGS syscall_arg__scnprintf_sync_file_range_flags
|
||||
|
||||
size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix);
|
||||
|
||||
void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
|
||||
|
@ -25,6 +25,7 @@ static size_t clone__scnprintf_flags(unsigned long flags, char *bf, size_t size,
|
||||
P_FLAG(FS);
|
||||
P_FLAG(FILES);
|
||||
P_FLAG(SIGHAND);
|
||||
P_FLAG(PIDFD);
|
||||
P_FLAG(PTRACE);
|
||||
P_FLAG(VFORK);
|
||||
P_FLAG(PARENT);
|
||||
|
17
tools/perf/trace/beauty/fsconfig.sh
Executable file
17
tools/perf/trace/beauty/fsconfig.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
linux_header_dir=tools/include/uapi/linux
|
||||
else
|
||||
linux_header_dir=$1
|
||||
fi
|
||||
|
||||
linux_mount=${linux_header_dir}/mount.h
|
||||
|
||||
printf "static const char *fsconfig_cmds[] = {\n"
|
||||
regex='^[[:space:]]*+FSCONFIG_([[:alnum:]_]+)[[:space:]]*=[[:space:]]*([[:digit:]]+)[[:space:]]*,[[:space:]]*.*'
|
||||
egrep $regex ${linux_mount} | \
|
||||
sed -r "s/$regex/\2 \1/g" | \
|
||||
xargs printf "\t[%s] = \"%s\",\n"
|
||||
printf "};\n"
|
34
tools/perf/trace/beauty/fsmount.c
Normal file
34
tools/perf/trace/beauty/fsmount.c
Normal file
@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* trace/beauty/fsmount.c
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
|
||||
#include "trace/beauty/beauty.h"
|
||||
#include <linux/log2.h>
|
||||
#include <uapi/linux/mount.h>
|
||||
|
||||
static size_t fsmount__scnprintf_attr_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
#include "trace/beauty/generated/fsmount_arrays.c"
|
||||
static DEFINE_STRARRAY(fsmount_attr_flags, "MOUNT_ATTR_");
|
||||
size_t printed = 0;
|
||||
|
||||
if ((flags & ~MOUNT_ATTR__ATIME) != 0)
|
||||
printed += strarray__scnprintf_flags(&strarray__fsmount_attr_flags, bf, size, show_prefix, flags);
|
||||
|
||||
if ((flags & MOUNT_ATTR__ATIME) == MOUNT_ATTR_RELATIME) {
|
||||
printed += scnprintf(bf + printed, size - printed, "%s%s%s",
|
||||
printed ? "|" : "", show_prefix ? "MOUNT_ATTR_" : "", "RELATIME");
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_fsmount_attr_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long flags = arg->val;
|
||||
|
||||
return fsmount__scnprintf_attr_flags(flags, bf, size, arg->show_string_prefix);
|
||||
}
|
22
tools/perf/trace/beauty/fsmount.sh
Executable file
22
tools/perf/trace/beauty/fsmount.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
linux_header_dir=tools/include/uapi/linux
|
||||
else
|
||||
linux_header_dir=$1
|
||||
fi
|
||||
|
||||
linux_mount=${linux_header_dir}/mount.h
|
||||
|
||||
# Remove MOUNT_ATTR_RELATIME as it is zeros, handle it a special way in the beautifier
|
||||
# Only handle MOUNT_ATTR_ followed by a capital letter/num as __ is special case
|
||||
# for things like MOUNT_ATTR__ATIME that is a mask for the possible ATIME handling
|
||||
# bits. Special case it as well in the beautifier
|
||||
|
||||
printf "static const char *fsmount_attr_flags[] = {\n"
|
||||
regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MOUNT_ATTR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*'
|
||||
egrep $regex ${linux_mount} | grep -v MOUNT_ATTR_RELATIME | \
|
||||
sed -r "s/$regex/\2 \1/g" | \
|
||||
xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n"
|
||||
printf "};\n"
|
24
tools/perf/trace/beauty/fspick.c
Normal file
24
tools/perf/trace/beauty/fspick.c
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* trace/beauty/fspick.c
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
|
||||
#include "trace/beauty/beauty.h"
|
||||
#include <linux/log2.h>
|
||||
|
||||
static size_t fspick__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
#include "trace/beauty/generated/fspick_arrays.c"
|
||||
static DEFINE_STRARRAY(fspick_flags, "FSPICK_");
|
||||
|
||||
return strarray__scnprintf_flags(&strarray__fspick_flags, bf, size, show_prefix, flags);
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_fspick_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long flags = arg->val;
|
||||
|
||||
return fspick__scnprintf_flags(flags, bf, size, arg->show_string_prefix);
|
||||
}
|
17
tools/perf/trace/beauty/fspick.sh
Executable file
17
tools/perf/trace/beauty/fspick.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
linux_header_dir=tools/include/uapi/linux
|
||||
else
|
||||
linux_header_dir=$1
|
||||
fi
|
||||
|
||||
linux_mount=${linux_header_dir}/mount.h
|
||||
|
||||
printf "static const char *fspick_flags[] = {\n"
|
||||
regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+FSPICK_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*'
|
||||
egrep $regex ${linux_mount} | \
|
||||
sed -r "s/$regex/\2 \1/g" | \
|
||||
xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n"
|
||||
printf "};\n"
|
24
tools/perf/trace/beauty/move_mount.c
Normal file
24
tools/perf/trace/beauty/move_mount.c
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* trace/beauty/move_mount.c
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
|
||||
#include "trace/beauty/beauty.h"
|
||||
#include <linux/log2.h>
|
||||
|
||||
static size_t move_mount__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
#include "trace/beauty/generated/move_mount_flags_array.c"
|
||||
static DEFINE_STRARRAY(move_mount_flags, "MOVE_MOUNT_");
|
||||
|
||||
return strarray__scnprintf_flags(&strarray__move_mount_flags, bf, size, show_prefix, flags);
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_move_mount_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long flags = arg->val;
|
||||
|
||||
return move_mount__scnprintf_flags(flags, bf, size, arg->show_string_prefix);
|
||||
}
|
17
tools/perf/trace/beauty/move_mount_flags.sh
Executable file
17
tools/perf/trace/beauty/move_mount_flags.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
linux_header_dir=tools/include/uapi/linux
|
||||
else
|
||||
linux_header_dir=$1
|
||||
fi
|
||||
|
||||
linux_mount=${linux_header_dir}/mount.h
|
||||
|
||||
printf "static const char *move_mount_flags[] = {\n"
|
||||
regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MOVE_MOUNT_([FT]_[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*'
|
||||
egrep $regex ${linux_mount} | \
|
||||
sed -r "s/$regex/\2 \1/g" | \
|
||||
xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n"
|
||||
printf "};\n"
|
31
tools/perf/trace/beauty/sync_file_range.c
Normal file
31
tools/perf/trace/beauty/sync_file_range.c
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* trace/beauty/sync_file_range.c
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
|
||||
#include "trace/beauty/beauty.h"
|
||||
#include <linux/log2.h>
|
||||
#include <uapi/linux/fs.h>
|
||||
|
||||
static size_t sync_file_range__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
#include "trace/beauty/generated/sync_file_range_arrays.c"
|
||||
static DEFINE_STRARRAY(sync_file_range_flags, "SYNC_FILE_RANGE_");
|
||||
size_t printed = 0;
|
||||
|
||||
if ((flags & SYNC_FILE_RANGE_WRITE_AND_WAIT) == SYNC_FILE_RANGE_WRITE_AND_WAIT) {
|
||||
printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? "SYNC_FILE_RANGE_" : "", "WRITE_AND_WAIT");
|
||||
flags &= ~SYNC_FILE_RANGE_WRITE_AND_WAIT;
|
||||
}
|
||||
|
||||
return printed + strarray__scnprintf_flags(&strarray__sync_file_range_flags, bf + printed, size - printed, show_prefix, flags);
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_sync_file_range_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long flags = arg->val;
|
||||
|
||||
return sync_file_range__scnprintf_flags(flags, bf, size, arg->show_string_prefix);
|
||||
}
|
17
tools/perf/trace/beauty/sync_file_range.sh
Executable file
17
tools/perf/trace/beauty/sync_file_range.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
linux_header_dir=tools/include/uapi/linux
|
||||
else
|
||||
linux_header_dir=$1
|
||||
fi
|
||||
|
||||
linux_fs=${linux_header_dir}/fs.h
|
||||
|
||||
printf "static const char *sync_file_range_flags[] = {\n"
|
||||
regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+SYNC_FILE_RANGE_([[:alnum:]_]+)[[:space:]]+([[:xdigit:]]+)[[:space:]]*.*'
|
||||
egrep $regex ${linux_fs} | \
|
||||
sed -r "s/$regex/\2 \1/g" | \
|
||||
xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n"
|
||||
printf "};\n"
|
@ -97,11 +97,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
||||
struct annotation *notes = browser__annotation(browser);
|
||||
struct annotation_line *al = list_entry(entry, struct annotation_line, node);
|
||||
const bool is_current_entry = ui_browser__is_current_entry(browser, row);
|
||||
struct annotation_write_ops ops = {
|
||||
.first_line = row == 0,
|
||||
.current_entry = ui_browser__is_current_entry(browser, row),
|
||||
.current_entry = is_current_entry,
|
||||
.change_color = (!notes->options->hide_src_code &&
|
||||
(!ops.current_entry ||
|
||||
(!is_current_entry ||
|
||||
(browser->use_navkeypressed &&
|
||||
!browser->navkeypressed))),
|
||||
.width = browser->width,
|
||||
|
@ -19,7 +19,7 @@ TAG=
|
||||
if test -d ../../.git -o -f ../../.git
|
||||
then
|
||||
TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null )
|
||||
CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
|
||||
CID=$(git log -1 --abbrev=12 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
|
||||
elif test -f ../../PERF-VERSION-FILE
|
||||
then
|
||||
TAG=$(cut -d' ' -f3 ../../PERF-VERSION-FILE | sed -e 's/\"//g')
|
||||
|
@ -1010,7 +1010,8 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
itrace_synth_opts__set_default(synth_opts, false);
|
||||
itrace_synth_opts__set_default(synth_opts,
|
||||
synth_opts->default_no_sample);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "bpf-event.h"
|
||||
#include "compress.h"
|
||||
#include "namespaces.h"
|
||||
#include "path.h"
|
||||
@ -706,6 +708,44 @@ bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
|
||||
return false;
|
||||
}
|
||||
|
||||
static ssize_t bpf_read(struct dso *dso, u64 offset, char *data)
|
||||
{
|
||||
struct bpf_prog_info_node *node;
|
||||
ssize_t size = DSO__DATA_CACHE_SIZE;
|
||||
u64 len;
|
||||
u8 *buf;
|
||||
|
||||
node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id);
|
||||
if (!node || !node->info_linear) {
|
||||
dso->data.status = DSO_DATA_STATUS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = node->info_linear->info.jited_prog_len;
|
||||
buf = (u8 *)(uintptr_t)node->info_linear->info.jited_prog_insns;
|
||||
|
||||
if (offset >= len)
|
||||
return -1;
|
||||
|
||||
size = (ssize_t)min(len - offset, (u64)size);
|
||||
memcpy(data, buf + offset, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int bpf_size(struct dso *dso)
|
||||
{
|
||||
struct bpf_prog_info_node *node;
|
||||
|
||||
node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id);
|
||||
if (!node || !node->info_linear) {
|
||||
dso->data.status = DSO_DATA_STATUS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dso->data.file_size = node->info_linear->info.jited_prog_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dso_cache__free(struct dso *dso)
|
||||
{
|
||||
@ -794,48 +834,53 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset,
|
||||
return cache_size;
|
||||
}
|
||||
|
||||
static ssize_t file_read(struct dso *dso, struct machine *machine,
|
||||
u64 offset, char *data)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
pthread_mutex_lock(&dso__data_open_lock);
|
||||
|
||||
/*
|
||||
* dso->data.fd might be closed if other thread opened another
|
||||
* file (dso) due to open file limit (RLIMIT_NOFILE).
|
||||
*/
|
||||
try_to_open_dso(dso, machine);
|
||||
|
||||
if (dso->data.fd < 0) {
|
||||
dso->data.status = DSO_DATA_STATUS_ERROR;
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pread(dso->data.fd, data, DSO__DATA_CACHE_SIZE, offset);
|
||||
out:
|
||||
pthread_mutex_unlock(&dso__data_open_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dso_cache__read(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size)
|
||||
{
|
||||
u64 cache_offset = offset & DSO__DATA_CACHE_MASK;
|
||||
struct dso_cache *cache;
|
||||
struct dso_cache *old;
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
u64 cache_offset;
|
||||
cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
|
||||
if (!cache)
|
||||
return -ENOMEM;
|
||||
|
||||
cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
|
||||
if (!cache)
|
||||
return -ENOMEM;
|
||||
|
||||
pthread_mutex_lock(&dso__data_open_lock);
|
||||
|
||||
/*
|
||||
* dso->data.fd might be closed if other thread opened another
|
||||
* file (dso) due to open file limit (RLIMIT_NOFILE).
|
||||
*/
|
||||
try_to_open_dso(dso, machine);
|
||||
|
||||
if (dso->data.fd < 0) {
|
||||
ret = -errno;
|
||||
dso->data.status = DSO_DATA_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
cache_offset = offset & DSO__DATA_CACHE_MASK;
|
||||
|
||||
ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
cache->offset = cache_offset;
|
||||
cache->size = ret;
|
||||
} while (0);
|
||||
|
||||
pthread_mutex_unlock(&dso__data_open_lock);
|
||||
if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
|
||||
ret = bpf_read(dso, cache_offset, cache->data);
|
||||
else
|
||||
ret = file_read(dso, machine, cache_offset, cache->data);
|
||||
|
||||
if (ret > 0) {
|
||||
cache->offset = cache_offset;
|
||||
cache->size = ret;
|
||||
|
||||
old = dso_cache__insert(dso, cache);
|
||||
if (old) {
|
||||
/* we lose the race */
|
||||
@ -898,18 +943,12 @@ static ssize_t cached_read(struct dso *dso, struct machine *machine,
|
||||
return r;
|
||||
}
|
||||
|
||||
int dso__data_file_size(struct dso *dso, struct machine *machine)
|
||||
static int file_size(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
char sbuf[STRERR_BUFSIZE];
|
||||
|
||||
if (dso->data.file_size)
|
||||
return 0;
|
||||
|
||||
if (dso->data.status == DSO_DATA_STATUS_ERROR)
|
||||
return -1;
|
||||
|
||||
pthread_mutex_lock(&dso__data_open_lock);
|
||||
|
||||
/*
|
||||
@ -938,6 +977,20 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dso__data_file_size(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
if (dso->data.file_size)
|
||||
return 0;
|
||||
|
||||
if (dso->data.status == DSO_DATA_STATUS_ERROR)
|
||||
return -1;
|
||||
|
||||
if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
|
||||
return bpf_size(dso);
|
||||
|
||||
return file_size(dso, machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* dso__data_size - Return dso data size
|
||||
* @dso: dso object
|
||||
|
@ -1486,7 +1486,7 @@ static size_t perf_event__fprintf_lost(union perf_event *event, FILE *fp)
|
||||
|
||||
size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp)
|
||||
{
|
||||
return fprintf(fp, " ksymbol event with addr %" PRIx64 " len %u type %u flags 0x%x name %s\n",
|
||||
return fprintf(fp, " addr %" PRIx64 " len %u type %u flags 0x%x name %s\n",
|
||||
event->ksymbol_event.addr, event->ksymbol_event.len,
|
||||
event->ksymbol_event.ksym_type,
|
||||
event->ksymbol_event.flags, event->ksymbol_event.name);
|
||||
@ -1494,7 +1494,7 @@ size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp)
|
||||
|
||||
size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp)
|
||||
{
|
||||
return fprintf(fp, " bpf event with type %u, flags %u, id %u\n",
|
||||
return fprintf(fp, " type %u, flags %u, id %u\n",
|
||||
event->bpf_event.type, event->bpf_event.flags,
|
||||
event->bpf_event.id);
|
||||
}
|
||||
|
@ -2561,7 +2561,7 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh
|
||||
char unit;
|
||||
int printed;
|
||||
const struct dso *dso = hists->dso_filter;
|
||||
const struct thread *thread = hists->thread_filter;
|
||||
struct thread *thread = hists->thread_filter;
|
||||
int socket_id = hists->socket_filter;
|
||||
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
u64 nr_events = hists->stats.total_period;
|
||||
|
@ -1859,7 +1859,6 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
|
||||
|
||||
switch (ptq->switch_state) {
|
||||
case INTEL_PT_SS_NOT_TRACING:
|
||||
ptq->next_tid = -1;
|
||||
break;
|
||||
case INTEL_PT_SS_UNKNOWN:
|
||||
case INTEL_PT_SS_TRACING:
|
||||
@ -1879,13 +1878,14 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
|
||||
ptq->switch_state = INTEL_PT_SS_TRACING;
|
||||
break;
|
||||
case INTEL_PT_SS_EXPECTING_SWITCH_IP:
|
||||
ptq->next_tid = tid;
|
||||
intel_pt_log("ERROR: cpu %d expecting switch ip\n", cpu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ptq->next_tid = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1914,6 +1914,44 @@ static int intel_pt_process_switch(struct intel_pt *pt,
|
||||
return machine__set_current_tid(pt->machine, cpu, -1, tid);
|
||||
}
|
||||
|
||||
static int intel_pt_context_switch_in(struct intel_pt *pt,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
pid_t pid = sample->pid;
|
||||
pid_t tid = sample->tid;
|
||||
int cpu = sample->cpu;
|
||||
|
||||
if (pt->sync_switch) {
|
||||
struct intel_pt_queue *ptq;
|
||||
|
||||
ptq = intel_pt_cpu_to_ptq(pt, cpu);
|
||||
if (ptq && ptq->sync_switch) {
|
||||
ptq->next_tid = -1;
|
||||
switch (ptq->switch_state) {
|
||||
case INTEL_PT_SS_NOT_TRACING:
|
||||
case INTEL_PT_SS_UNKNOWN:
|
||||
case INTEL_PT_SS_TRACING:
|
||||
break;
|
||||
case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
|
||||
case INTEL_PT_SS_EXPECTING_SWITCH_IP:
|
||||
ptq->switch_state = INTEL_PT_SS_TRACING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current tid has not been updated yet, ensure it is now that
|
||||
* a "switch in" event has occurred.
|
||||
*/
|
||||
if (machine__get_current_tid(pt->machine, cpu) == tid)
|
||||
return 0;
|
||||
|
||||
return machine__set_current_tid(pt->machine, cpu, pid, tid);
|
||||
}
|
||||
|
||||
static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
@ -1925,7 +1963,7 @@ static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
|
||||
|
||||
if (pt->have_sched_switch == 3) {
|
||||
if (!out)
|
||||
return 0;
|
||||
return intel_pt_context_switch_in(pt, sample);
|
||||
if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) {
|
||||
pr_err("Expecting CPU-wide context switch event\n");
|
||||
return -EINVAL;
|
||||
@ -2588,7 +2626,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
|
||||
} else {
|
||||
itrace_synth_opts__set_default(&pt->synth_opts,
|
||||
session->itrace_synth_opts->default_no_sample);
|
||||
if (use_browser != -1) {
|
||||
if (!session->itrace_synth_opts->default_no_sample &&
|
||||
!session->itrace_synth_opts->inject) {
|
||||
pt->synth_opts.branches = false;
|
||||
pt->synth_opts.callchain = true;
|
||||
}
|
||||
|
@ -704,12 +704,12 @@ static int machine__process_ksymbol_register(struct machine *machine,
|
||||
return -ENOMEM;
|
||||
|
||||
map->start = event->ksymbol_event.addr;
|
||||
map->pgoff = map->start;
|
||||
map->end = map->start + event->ksymbol_event.len;
|
||||
map_groups__insert(&machine->kmaps, map);
|
||||
}
|
||||
|
||||
sym = symbol__new(event->ksymbol_event.addr, event->ksymbol_event.len,
|
||||
sym = symbol__new(map->map_ip(map, map->start),
|
||||
event->ksymbol_event.len,
|
||||
0, 0, event->ksymbol_event.name);
|
||||
if (!sym)
|
||||
return -ENOMEM;
|
||||
@ -1241,9 +1241,9 @@ static char *get_kernel_version(const char *root_dir)
|
||||
return NULL;
|
||||
|
||||
tmp = fgets(version, sizeof(version), file);
|
||||
if (!tmp)
|
||||
*version = '\0';
|
||||
fclose(file);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
|
||||
name = strstr(version, prefix);
|
||||
if (!name)
|
||||
|
@ -405,6 +405,7 @@ size_t map__fprintf(struct map *map, FILE *fp)
|
||||
|
||||
size_t map__fprintf_dsoname(struct map *map, FILE *fp)
|
||||
{
|
||||
char buf[symbol_conf.pad_output_len_dso + 1];
|
||||
const char *dsoname = "[unknown]";
|
||||
|
||||
if (map && map->dso) {
|
||||
@ -414,6 +415,11 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
|
||||
dsoname = map->dso->name;
|
||||
}
|
||||
|
||||
if (symbol_conf.pad_output_len_dso) {
|
||||
scnprintf_pad(buf, symbol_conf.pad_output_len_dso, "%s", dsoname);
|
||||
dsoname = buf;
|
||||
}
|
||||
|
||||
return fprintf(fp, "%s", dsoname);
|
||||
}
|
||||
|
||||
|
@ -88,4 +88,6 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, FILE
|
||||
|
||||
struct map *map_groups__find_by_name(struct map_groups *mg, const char *name);
|
||||
|
||||
int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map);
|
||||
|
||||
#endif // __PERF_MAP_GROUPS_H
|
||||
|
@ -17,6 +17,8 @@ if cc == "clang":
|
||||
vars[var] = sub("-fcf-protection", "", vars[var])
|
||||
if not clang_has_option("-fstack-clash-protection"):
|
||||
vars[var] = sub("-fstack-clash-protection", "", vars[var])
|
||||
if not clang_has_option("-fstack-protector-strong"):
|
||||
vars[var] = sub("-fstack-protector-strong", "", vars[var])
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
|
@ -1166,6 +1166,85 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges map into map_groups by splitting the new map
|
||||
* within the existing map regions.
|
||||
*/
|
||||
int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map)
|
||||
{
|
||||
struct map *old_map;
|
||||
LIST_HEAD(merged);
|
||||
|
||||
for (old_map = map_groups__first(kmaps); old_map;
|
||||
old_map = map_groups__next(old_map)) {
|
||||
|
||||
/* no overload with this one */
|
||||
if (new_map->end < old_map->start ||
|
||||
new_map->start >= old_map->end)
|
||||
continue;
|
||||
|
||||
if (new_map->start < old_map->start) {
|
||||
/*
|
||||
* |new......
|
||||
* |old....
|
||||
*/
|
||||
if (new_map->end < old_map->end) {
|
||||
/*
|
||||
* |new......| -> |new..|
|
||||
* |old....| -> |old....|
|
||||
*/
|
||||
new_map->end = old_map->start;
|
||||
} else {
|
||||
/*
|
||||
* |new.............| -> |new..| |new..|
|
||||
* |old....| -> |old....|
|
||||
*/
|
||||
struct map *m = map__clone(new_map);
|
||||
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
m->end = old_map->start;
|
||||
list_add_tail(&m->node, &merged);
|
||||
new_map->start = old_map->end;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* |new......
|
||||
* |old....
|
||||
*/
|
||||
if (new_map->end < old_map->end) {
|
||||
/*
|
||||
* |new..| -> x
|
||||
* |old.........| -> |old.........|
|
||||
*/
|
||||
map__put(new_map);
|
||||
new_map = NULL;
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* |new......| -> |new...|
|
||||
* |old....| -> |old....|
|
||||
*/
|
||||
new_map->start = old_map->end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!list_empty(&merged)) {
|
||||
old_map = list_entry(merged.next, struct map, node);
|
||||
list_del_init(&old_map->node);
|
||||
map_groups__insert(kmaps, old_map);
|
||||
map__put(old_map);
|
||||
}
|
||||
|
||||
if (new_map) {
|
||||
map_groups__insert(kmaps, new_map);
|
||||
map__put(new_map);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
const char *kallsyms_filename)
|
||||
{
|
||||
@ -1222,7 +1301,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
while (old_map) {
|
||||
struct map *next = map_groups__next(old_map);
|
||||
|
||||
if (old_map != map)
|
||||
/*
|
||||
* We need to preserve eBPF maps even if they are
|
||||
* covered by kcore, because we need to access
|
||||
* eBPF dso for source data.
|
||||
*/
|
||||
if (old_map != map && !__map__is_bpf_prog(old_map))
|
||||
map_groups__remove(kmaps, old_map);
|
||||
old_map = next;
|
||||
}
|
||||
@ -1256,11 +1340,16 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
map_groups__remove(kmaps, map);
|
||||
map_groups__insert(kmaps, map);
|
||||
map__put(map);
|
||||
map__put(new_map);
|
||||
} else {
|
||||
map_groups__insert(kmaps, new_map);
|
||||
/*
|
||||
* Merge kcore map into existing maps,
|
||||
* and ensure that current maps (eBPF)
|
||||
* stay intact.
|
||||
*/
|
||||
if (map_groups__merge_in(kmaps, new_map))
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
map__put(new_map);
|
||||
}
|
||||
|
||||
if (machine__is(machine, "x86_64")) {
|
||||
|
@ -69,6 +69,7 @@ struct symbol_conf {
|
||||
*tid_list;
|
||||
const char *symfs;
|
||||
int res_sample;
|
||||
int pad_output_len_dso;
|
||||
};
|
||||
|
||||
extern struct symbol_conf symbol_conf;
|
||||
|
@ -141,13 +141,13 @@ static struct namespaces *__thread__namespaces(const struct thread *thread)
|
||||
return list_first_entry(&thread->namespaces_list, struct namespaces, list);
|
||||
}
|
||||
|
||||
struct namespaces *thread__namespaces(const struct thread *thread)
|
||||
struct namespaces *thread__namespaces(struct thread *thread)
|
||||
{
|
||||
struct namespaces *ns;
|
||||
|
||||
down_read((struct rw_semaphore *)&thread->namespaces_lock);
|
||||
down_read(&thread->namespaces_lock);
|
||||
ns = __thread__namespaces(thread);
|
||||
up_read((struct rw_semaphore *)&thread->namespaces_lock);
|
||||
up_read(&thread->namespaces_lock);
|
||||
|
||||
return ns;
|
||||
}
|
||||
@ -271,13 +271,13 @@ static const char *__thread__comm_str(const struct thread *thread)
|
||||
return comm__str(comm);
|
||||
}
|
||||
|
||||
const char *thread__comm_str(const struct thread *thread)
|
||||
const char *thread__comm_str(struct thread *thread)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
down_read((struct rw_semaphore *)&thread->comm_lock);
|
||||
down_read(&thread->comm_lock);
|
||||
str = __thread__comm_str(thread);
|
||||
up_read((struct rw_semaphore *)&thread->comm_lock);
|
||||
up_read(&thread->comm_lock);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ static inline void thread__exited(struct thread *thread)
|
||||
thread->dead = true;
|
||||
}
|
||||
|
||||
struct namespaces *thread__namespaces(const struct thread *thread);
|
||||
struct namespaces *thread__namespaces(struct thread *thread);
|
||||
int thread__set_namespaces(struct thread *thread, u64 timestamp,
|
||||
struct namespaces_event *event);
|
||||
|
||||
@ -93,7 +93,7 @@ int thread__set_comm_from_proc(struct thread *thread);
|
||||
int thread__comm_len(struct thread *thread);
|
||||
struct comm *thread__comm(const struct thread *thread);
|
||||
struct comm *thread__exec_comm(const struct thread *thread);
|
||||
const char *thread__comm_str(const struct thread *thread);
|
||||
const char *thread__comm_str(struct thread *thread);
|
||||
int thread__insert_map(struct thread *thread, struct map *map);
|
||||
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone);
|
||||
size_t thread__fprintf(struct thread *thread, FILE *fp);
|
||||
|
Loading…
Reference in New Issue
Block a user