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:
Ingo Molnar 2019-05-30 09:47:57 +02:00
commit b33fb3cf6f
45 changed files with 889 additions and 107 deletions

View File

@ -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))

View File

@ -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;
}

View File

@ -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:

View File

@ -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.

View File

@ -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
--------------------------

View File

@ -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
#

View File

@ -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"),

View File

@ -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;

View File

@ -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",

View File

@ -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:

View File

@ -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" \{\} \;

View File

@ -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()

View File

@ -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()

View File

@ -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")

View File

@ -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)

View File

@ -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,
},

View 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;
}

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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);

View 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"

View 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);
}

View 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"

View 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);
}

View 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"

View 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);
}

View 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"

View 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);
}

View 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"

View File

@ -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,

View File

@ -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')

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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")) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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);