summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/include/uapi/linux/kcmp.h27
-rw-r--r--tools/include/uapi/linux/prctl.h200
-rw-r--r--tools/perf/Documentation/perf-script.txt4
-rw-r--r--tools/perf/Makefile.perf22
-rw-r--r--tools/perf/builtin-annotate.c10
-rw-r--r--tools/perf/builtin-buildid-cache.c8
-rw-r--r--tools/perf/builtin-buildid-list.c16
-rw-r--r--tools/perf/builtin-c2c.c10
-rw-r--r--tools/perf/builtin-diff.c18
-rw-r--r--tools/perf/builtin-evlist.c12
-rw-r--r--tools/perf/builtin-inject.c36
-rw-r--r--tools/perf/builtin-kmem.c8
-rw-r--r--tools/perf/builtin-kvm.c14
-rw-r--r--tools/perf/builtin-lock.c12
-rw-r--r--tools/perf/builtin-mem.c12
-rw-r--r--tools/perf/builtin-record.c50
-rw-r--r--tools/perf/builtin-report.c14
-rw-r--r--tools/perf/builtin-sched.c24
-rw-r--r--tools/perf/builtin-script.c169
-rw-r--r--tools/perf/builtin-stat.c39
-rw-r--r--tools/perf/builtin-timechart.c14
-rw-r--r--tools/perf/builtin-trace.c40
-rwxr-xr-xtools/perf/check-headers.sh2
-rw-r--r--tools/perf/tests/topology.c22
-rw-r--r--tools/perf/trace/beauty/Build2
-rw-r--r--tools/perf/trace/beauty/beauty.h18
-rw-r--r--tools/perf/trace/beauty/kcmp.c44
-rwxr-xr-xtools/perf/trace/beauty/kcmp_type.sh10
-rw-r--r--tools/perf/trace/beauty/prctl.c82
-rwxr-xr-xtools/perf/trace/beauty/prctl_option.sh17
-rw-r--r--tools/perf/util/auxtrace.c4
-rw-r--r--tools/perf/util/callchain.c5
-rw-r--r--tools/perf/util/data-convert-bt.c12
-rw-r--r--tools/perf/util/data.c94
-rw-r--r--tools/perf/util/data.h38
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/header.c20
-rw-r--r--tools/perf/util/intel-bts.c6
-rw-r--r--tools/perf/util/intel-pt.c6
-rw-r--r--tools/perf/util/jit.h2
-rw-r--r--tools/perf/util/jitdump.c10
-rw-r--r--tools/perf/util/session.c44
-rw-r--r--tools/perf/util/session.h4
-rw-r--r--tools/perf/util/srcline.c102
-rw-r--r--tools/perf/util/stat-shadow.c48
-rw-r--r--tools/perf/util/stat.c24
-rw-r--r--tools/perf/util/stat.h2
47 files changed, 999 insertions, 381 deletions
diff --git a/tools/include/uapi/linux/kcmp.h b/tools/include/uapi/linux/kcmp.h
new file mode 100644
index 000000000000..481e103da78e
--- /dev/null
+++ b/tools/include/uapi/linux/kcmp.h
@@ -0,0 +1,27 @@
+#ifndef _UAPI_LINUX_KCMP_H
+#define _UAPI_LINUX_KCMP_H
+
+#include <linux/types.h>
+
+/* Comparison type */
+enum kcmp_type {
+ KCMP_FILE,
+ KCMP_VM,
+ KCMP_FILES,
+ KCMP_FS,
+ KCMP_SIGHAND,
+ KCMP_IO,
+ KCMP_SYSVSEM,
+ KCMP_EPOLL_TFD,
+
+ KCMP_TYPES,
+};
+
+/* Slot for KCMP_EPOLL_TFD */
+struct kcmp_epoll_slot {
+ __u32 efd; /* epoll file descriptor */
+ __u32 tfd; /* target file number */
+ __u32 toff; /* target offset within same numbered sequence */
+};
+
+#endif /* _UAPI_LINUX_KCMP_H */
diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h
new file mode 100644
index 000000000000..a8d0759a9e40
--- /dev/null
+++ b/tools/include/uapi/linux/prctl.h
@@ -0,0 +1,200 @@
+#ifndef _LINUX_PRCTL_H
+#define _LINUX_PRCTL_H
+
+#include <linux/types.h>
+
+/* Values to pass as first argument to prctl() */
+
+#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */
+#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */
+
+/* Get/set current->mm->dumpable */
+#define PR_GET_DUMPABLE 3
+#define PR_SET_DUMPABLE 4
+
+/* Get/set unaligned access control bits (if meaningful) */
+#define PR_GET_UNALIGN 5
+#define PR_SET_UNALIGN 6
+# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */
+# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */
+
+/* Get/set whether or not to drop capabilities on setuid() away from
+ * uid 0 (as per security/commoncap.c) */
+#define PR_GET_KEEPCAPS 7
+#define PR_SET_KEEPCAPS 8
+
+/* Get/set floating-point emulation control bits (if meaningful) */
+#define PR_GET_FPEMU 9
+#define PR_SET_FPEMU 10
+# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */
+# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */
+
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC 11
+#define PR_SET_FPEXC 12
+# define PR_FP_EXC_SW_ENABLE 0x80 /* Use FPEXC for FP exception enables */
+# define PR_FP_EXC_DIV 0x010000 /* floating point divide by zero */
+# define PR_FP_EXC_OVF 0x020000 /* floating point overflow */
+# define PR_FP_EXC_UND 0x040000 /* floating point underflow */
+# define PR_FP_EXC_RES 0x080000 /* floating point inexact result */
+# define PR_FP_EXC_INV 0x100000 /* floating point invalid operation */
+# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE 3 /* precise exception mode */
+
+/* Get/set whether we use statistical process timing or accurate timestamp
+ * based process timing */
+#define PR_GET_TIMING 13
+#define PR_SET_TIMING 14
+# define PR_TIMING_STATISTICAL 0 /* Normal, traditional,
+ statistical process timing */
+# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based
+ process timing */
+
+#define PR_SET_NAME 15 /* Set process name */
+#define PR_GET_NAME 16 /* Get process name */
+
+/* Get/set process endian */
+#define PR_GET_ENDIAN 19
+#define PR_SET_ENDIAN 20
+# define PR_ENDIAN_BIG 0
+# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
+# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
+
+/* Get/set process seccomp mode */
+#define PR_GET_SECCOMP 21
+#define PR_SET_SECCOMP 22
+
+/* Get/set the capability bounding set (as per security/commoncap.c) */
+#define PR_CAPBSET_READ 23
+#define PR_CAPBSET_DROP 24
+
+/* Get/set the process' ability to use the timestamp counter instruction */
+#define PR_GET_TSC 25
+#define PR_SET_TSC 26
+# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
+# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
+
+/* Get/set securebits (as per security/commoncap.c) */
+#define PR_GET_SECUREBITS 27
+#define PR_SET_SECUREBITS 28
+
+/*
+ * Get/set the timerslack as used by poll/select/nanosleep
+ * A value of 0 means "use default"
+ */
+#define PR_SET_TIMERSLACK 29
+#define PR_GET_TIMERSLACK 30
+
+#define PR_TASK_PERF_EVENTS_DISABLE 31
+#define PR_TASK_PERF_EVENTS_ENABLE 32
+
+/*
+ * Set early/late kill mode for hwpoison memory corruption.
+ * This influences when the process gets killed on a memory corruption.
+ */
+#define PR_MCE_KILL 33
+# define PR_MCE_KILL_CLEAR 0
+# define PR_MCE_KILL_SET 1
+
+# define PR_MCE_KILL_LATE 0
+# define PR_MCE_KILL_EARLY 1
+# define PR_MCE_KILL_DEFAULT 2
+
+#define PR_MCE_KILL_GET 34
+
+/*
+ * Tune up process memory map specifics.
+ */
+#define PR_SET_MM 35
+# define PR_SET_MM_START_CODE 1
+# define PR_SET_MM_END_CODE 2
+# define PR_SET_MM_START_DATA 3
+# define PR_SET_MM_END_DATA 4
+# define PR_SET_MM_START_STACK 5
+# define PR_SET_MM_START_BRK 6
+# define PR_SET_MM_BRK 7
+# define PR_SET_MM_ARG_START 8
+# define PR_SET_MM_ARG_END 9
+# define PR_SET_MM_ENV_START 10
+# define PR_SET_MM_ENV_END 11
+# define PR_SET_MM_AUXV 12
+# define PR_SET_MM_EXE_FILE 13
+# define PR_SET_MM_MAP 14
+# define PR_SET_MM_MAP_SIZE 15
+
+/*
+ * This structure provides new memory descriptor
+ * map which mostly modifies /proc/pid/stat[m]
+ * output for a task. This mostly done in a
+ * sake of checkpoint/restore functionality.
+ */
+struct prctl_mm_map {
+ __u64 start_code; /* code section bounds */
+ __u64 end_code;
+ __u64 start_data; /* data section bounds */
+ __u64 end_data;
+ __u64 start_brk; /* heap for brk() syscall */
+ __u64 brk;
+ __u64 start_stack; /* stack starts at */
+ __u64 arg_start; /* command line arguments bounds */
+ __u64 arg_end;
+ __u64 env_start; /* environment variables bounds */
+ __u64 env_end;
+ __u64 *auxv; /* auxiliary vector */
+ __u32 auxv_size; /* vector size */
+ __u32 exe_fd; /* /proc/$pid/exe link file */
+};
+
+/*
+ * Set specific pid that is allowed to ptrace the current task.
+ * A value of 0 mean "no process".
+ */
+#define PR_SET_PTRACER 0x59616d61
+# define PR_SET_PTRACER_ANY ((unsigned long)-1)
+
+#define PR_SET_CHILD_SUBREAPER 36
+#define PR_GET_CHILD_SUBREAPER 37
+
+/*
+ * If no_new_privs is set, then operations that grant new privileges (i.e.
+ * execve) will either fail or not grant them. This affects suid/sgid,
+ * file capabilities, and LSMs.
+ *
+ * Operations that merely manipulate or drop existing privileges (setresuid,
+ * capset, etc.) will still work. Drop those privileges if you want them gone.
+ *
+ * Changing LSM security domain is considered a new privilege. So, for example,
+ * asking selinux for a specific new context (e.g. with runcon) will result
+ * in execve returning -EPERM.
+ *
+ * See Documentation/prctl/no_new_privs.txt for more details.
+ */
+#define PR_SET_NO_NEW_PRIVS 38
+#define PR_GET_NO_NEW_PRIVS 39
+
+#define PR_GET_TID_ADDRESS 40
+
+#define PR_SET_THP_DISABLE 41
+#define PR_GET_THP_DISABLE 42
+
+/*
+ * Tell the kernel to start/stop helping userspace manage bounds tables.
+ */
+#define PR_MPX_ENABLE_MANAGEMENT 43
+#define PR_MPX_DISABLE_MANAGEMENT 44
+
+#define PR_SET_FP_MODE 45
+#define PR_GET_FP_MODE 46
+# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
+# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
+
+/* Control the ambient capability set */
+#define PR_CAP_AMBIENT 47
+# define PR_CAP_AMBIENT_IS_SET 1
+# define PR_CAP_AMBIENT_RAISE 2
+# define PR_CAP_AMBIENT_LOWER 3
+# define PR_CAP_AMBIENT_CLEAR_ALL 4
+
+#endif /* _LINUX_PRCTL_H */
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 25e677344728..2811fcf684cb 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -325,6 +325,10 @@ include::itrace.txt[]
Set the maximum number of program blocks to print with brstackasm for
each sample.
+--per-event-dump::
+ Create per event files with a "perf.data.EVENT.dump" name instead of
+ printing to stdout, useful, for instance, for generating flamegraphs.
+
--inline::
If a callgraph address belongs to an inlined function, the inline stack
will be printed. Each entry has function name and file/line. Enabled by
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 5f7408118a2d..68cf1360a3f3 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -420,6 +420,13 @@ sndrv_pcm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
$(sndrv_pcm_ioctl_array): $(sndrv_pcm_hdr_dir)/asound.h $(sndrv_pcm_ioctl_tbl)
$(Q)$(SHELL) '$(sndrv_pcm_ioctl_tbl)' $(sndrv_pcm_hdr_dir) > $@
+kcmp_type_array := $(beauty_outdir)/kcmp_type_array.c
+kcmp_hdr_dir := $(srctree)/tools/include/uapi/linux/
+kcmp_type_tbl := $(srctree)/tools/perf/trace/beauty/kcmp_type.sh
+
+$(kcmp_type_array): $(kcmp_hdr_dir)/kcmp.h $(kcmp_type_tbl)
+ $(Q)$(SHELL) '$(kcmp_type_tbl)' $(kcmp_hdr_dir) > $@
+
kvm_ioctl_array := $(beauty_ioctl_outdir)/kvm_ioctl_array.c
kvm_hdr_dir := $(srctree)/tools/include/uapi/linux
kvm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/kvm_ioctl.sh
@@ -448,6 +455,13 @@ madvise_behavior_tbl := $(srctree)/tools/perf/trace/beauty/madvise_behavior.sh
$(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl)
$(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_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
+
+$(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl)
+ $(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@
+
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST)
@@ -546,10 +560,12 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
$(pkey_alloc_access_rights_array) \
$(sndrv_pcm_ioctl_array) \
$(sndrv_ctl_ioctl_array) \
+ $(kcmp_type_array) \
$(kvm_ioctl_array) \
$(vhost_virtio_ioctl_array) \
$(madvise_behavior_array) \
- $(perf_ioctl_array)
+ $(perf_ioctl_array) \
+ $(prctl_option_array)
$(OUTPUT)%.o: %.c prepare FORCE
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
@@ -828,8 +844,10 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
$(OUTPUT)$(sndrv_ctl_ioctl_array) \
$(OUTPUT)$(sndrv_pcm_ioctl_array) \
$(OUTPUT)$(kvm_ioctl_array) \
+ $(OUTPUT)$(kcmp_type_array) \
$(OUTPUT)$(vhost_virtio_ioctl_array) \
- $(OUTPUT)$(perf_ioctl_array)
+ $(OUTPUT)$(perf_ioctl_array) \
+ $(OUTPUT)$(prctl_option_array)
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
#
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index c38373195c4a..2d5c87578f83 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -356,7 +356,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
}
if (total_nr_samples == 0) {
- ui__error("The %s file has no samples!\n", session->file->path);
+ ui__error("The %s file has no samples!\n", session->data->file.path);
goto out;
}
@@ -400,7 +400,7 @@ int cmd_annotate(int argc, const char **argv)
.ordering_requires_timestamps = true,
},
};
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
struct option options[] = {
@@ -410,7 +410,7 @@ int cmd_annotate(int argc, const char **argv)
"only consider symbols in these dsos"),
OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
"symbol to annotate"),
- OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+ OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('q', "quiet", &quiet, "do now show any message"),
@@ -482,9 +482,9 @@ int cmd_annotate(int argc, const char **argv)
if (quiet)
perf_quiet_option();
- file.path = input_name;
+ data.file.path = input_name;
- annotate.session = perf_session__new(&file, false, &annotate.tool);
+ annotate.session = perf_session__new(&data, false, &annotate.tool);
if (annotate.session == NULL)
return -1;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index e3eb6240ced0..cb2453b29365 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -311,7 +311,7 @@ int cmd_buildid_cache(int argc, const char **argv)
*kcore_filename = NULL;
char sbuf[STRERR_BUFSIZE];
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
struct perf_session *session = NULL;
@@ -352,10 +352,10 @@ int cmd_buildid_cache(int argc, const char **argv)
nsi = nsinfo__new(ns_id);
if (missing_filename) {
- file.path = missing_filename;
- file.force = force;
+ data.file.path = missing_filename;
+ data.force = force;
- session = perf_session__new(&file, false, NULL);
+ session = perf_session__new(&data, false, NULL);
if (session == NULL)
return -1;
}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index fdaca16e0c74..00099a830b0d 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -50,10 +50,12 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
static int perf_session__list_build_ids(bool force, bool with_hits)
{
struct perf_session *session;
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = force,
};
symbol__elf_init();
@@ -63,7 +65,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
if (filename__fprintf_build_id(input_name, stdout) > 0)
goto out;
- session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
+ session = perf_session__new(&data, false, &build_id__mark_dso_hit_ops);
if (session == NULL)
return -1;
@@ -71,7 +73,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
* We take all buildids when the file contains AUX area tracing data
* because we do not decode the trace because it would take too long.
*/
- if (!perf_data_file__is_pipe(&file) &&
+ if (!perf_data__is_pipe(&data) &&
perf_header__has_feat(&session->header, HEADER_AUXTRACE))
with_hits = false;
@@ -79,7 +81,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
* in pipe-mode, the only way to get the buildids is to parse
* the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
*/
- if (with_hits || perf_data_file__is_pipe(&file))
+ if (with_hits || perf_data__is_pipe(&data))
perf_session__process_events(session);
perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index bb1ee22bd221..9590fdcc6484 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -2523,7 +2523,7 @@ static int perf_c2c__report(int argc, const char **argv)
{
struct perf_session *session;
struct ui_progress prog;
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
@@ -2572,8 +2572,8 @@ static int perf_c2c__report(int argc, const char **argv)
if (!input_name || !strlen(input_name))
input_name = "perf.data";
- file.path = input_name;
- file.force = symbol_conf.force;
+ data.file.path = input_name;
+ data.force = symbol_conf.force;
err = setup_display(display);
if (err)
@@ -2591,7 +2591,7 @@ static int perf_c2c__report(int argc, const char **argv)
goto out;
}
- session = perf_session__new(&file, 0, &c2c.tool);
+ session = perf_session__new(&data, 0, &c2c.tool);
if (session == NULL) {
pr_debug("No memory for session\n");
goto out;
@@ -2611,7 +2611,7 @@ static int perf_c2c__report(int argc, const char **argv)
goto out_session;
/* No pipe support at the moment. */
- if (perf_data_file__is_pipe(session->file)) {
+ if (perf_data__is_pipe(session->data)) {
pr_debug("No pipe support at the moment.\n");
goto out_session;
}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0cd4cf6a344b..67570e6417e5 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -47,7 +47,7 @@ struct diff_hpp_fmt {
struct data__file {
struct perf_session *session;
- struct perf_data_file file;
+ struct perf_data data;
int idx;
struct hists *hists;
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
@@ -707,7 +707,7 @@ static void data__fprintf(void)
data__for_each_file(i, d)
fprintf(stdout, "# [%d] %s %s\n",
- d->idx, d->file.path,
+ d->idx, d->data.file.path,
!d->idx ? "(Baseline)" : "");
fprintf(stdout, "#\n");
@@ -776,16 +776,16 @@ static int __cmd_diff(void)
int ret = -EINVAL, i;
data__for_each_file(i, d) {
- d->session = perf_session__new(&d->file, false, &tool);
+ d->session = perf_session__new(&d->data, false, &tool);
if (!d->session) {
- pr_err("Failed to open %s\n", d->file.path);
+ pr_err("Failed to open %s\n", d->data.file.path);
ret = -1;
goto out_delete;
}
ret = perf_session__process_events(d->session);
if (ret) {
- pr_err("Failed to process %s\n", d->file.path);
+ pr_err("Failed to process %s\n", d->data.file.path);
goto out_delete;
}
@@ -1286,11 +1286,11 @@ static int data_init(int argc, const char **argv)
return -ENOMEM;
data__for_each_file(i, d) {
- struct perf_data_file *file = &d->file;
+ struct perf_data *data = &d->data;
- file->path = use_default ? defaults[i] : argv[i];
- file->mode = PERF_DATA_MODE_READ,
- file->force = force,
+ data->file.path = use_default ? defaults[i] : argv[i];
+ data->mode = PERF_DATA_MODE_READ,
+ data->force = force,
d->idx = i;
}
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 6d210e40d611..93b85dc857b6 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -21,14 +21,16 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
{
struct perf_session *session;
struct perf_evsel *pos;
- struct perf_data_file file = {
- .path = file_name,
- .mode = PERF_DATA_MODE_READ,
- .force = details->force,
+ struct perf_data data = {
+ .file = {
+ .path = file_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = details->force,
};
bool has_tracepoint = false;
- session = perf_session__new(&file, 0, NULL);
+ session = perf_session__new(&data, 0, NULL);
if (session == NULL)
return -1;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 2b8032908fb2..91e65093d3c2 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -35,7 +35,7 @@ struct perf_inject {
bool strip;
bool jit_mode;
const char *input_name;
- struct perf_data_file output;
+ struct perf_data output;
u64 bytes_written;
u64 aux_id;
struct list_head samples;
@@ -52,7 +52,7 @@ static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
{
ssize_t size;
- size = perf_data_file__write(&inject->output, buf, sz);
+ size = perf_data__write(&inject->output, buf, sz);
if (size < 0)
return -errno;
@@ -145,7 +145,7 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
if (!inject->output.is_pipe) {
off_t offset;
- offset = lseek(inject->output.fd, 0, SEEK_CUR);
+ offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
if (offset == -1)
return -errno;
ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
@@ -154,11 +154,11 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
return ret;
}
- if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
+ if (perf_data__is_pipe(session->data) || !session->one_mmap) {
ret = output_bytes(inject, event, event->header.size);
if (ret < 0)
return ret;
- ret = copy_bytes(inject, perf_data_file__fd(session->file),
+ ret = copy_bytes(inject, perf_data__fd(session->data),
event->auxtrace.size);
} else {
ret = output_bytes(inject, event,
@@ -637,8 +637,8 @@ static int __cmd_inject(struct perf_inject *inject)
{
int ret = -EINVAL;
struct perf_session *session = inject->session;
- struct perf_data_file *file_out = &inject->output;
- int fd = perf_data_file__fd(file_out);
+ struct perf_data *data_out = &inject->output;
+ int fd = perf_data__fd(data_out);
u64 output_data_offset;
signal(SIGINT, sig_handler);
@@ -693,14 +693,14 @@ static int __cmd_inject(struct perf_inject *inject)
if (!inject->itrace_synth_opts.set)
auxtrace_index__free(&session->auxtrace_index);
- if (!file_out->is_pipe)
+ if (!data_out->is_pipe)
lseek(fd, output_data_offset, SEEK_SET);
ret = perf_session__process_events(session);
if (ret)
return ret;
- if (!file_out->is_pipe) {
+ if (!data_out->is_pipe) {
if (inject->build_ids)
perf_header__set_feat(&session->header,
HEADER_BUILD_ID);
@@ -775,11 +775,13 @@ int cmd_inject(int argc, const char **argv)
.input_name = "-",
.samples = LIST_HEAD_INIT(inject.samples),
.output = {
- .path = "-",
- .mode = PERF_DATA_MODE_WRITE,
+ .file = {
+ .path = "-",
+ },
+ .mode = PERF_DATA_MODE_WRITE,
},
};
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
int ret;
@@ -789,7 +791,7 @@ int cmd_inject(int argc, const char **argv)
"Inject build-ids into the output stream"),
OPT_STRING('i', "input", &inject.input_name, "file",
"input file name"),
- OPT_STRING('o', "output", &inject.output.path, "file",
+ OPT_STRING('o', "output", &inject.output.file.path, "file",
"output file name"),
OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
"Merge sched-stat and sched-switch for getting events "
@@ -801,7 +803,7 @@ int cmd_inject(int argc, const char **argv)
"be more verbose (show build ids, etc)"),
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
"kallsyms pathname"),
- OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+ OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
NULL, "opts", "Instruction Tracing options",
itrace_parse_synth_opts),
@@ -829,15 +831,15 @@ int cmd_inject(int argc, const char **argv)
return -1;
}
- if (perf_data_file__open(&inject.output)) {
+ if (perf_data__open(&inject.output)) {
perror("failed to create output file");
return -1;
}
inject.tool.ordered_events = inject.sched_stat;
- file.path = inject.input_name;
- inject.session = perf_session__new(&file, true, &inject.tool);
+ data.file.path = inject.input_name;
+ inject.session = perf_session__new(&data, true, &inject.tool);
if (inject.session == NULL)
return -1;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index d8f25ef8157b..abcab75cc5b9 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1893,7 +1893,7 @@ int cmd_kmem(int argc, const char **argv)
{
const char * const default_slab_sort = "frag,hit,bytes";
const char * const default_page_sort = "bytes,hit";
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
const struct option kmem_options[] = {
@@ -1909,7 +1909,7 @@ int cmd_kmem(int argc, const char **argv)
"page, order, migtype, gfp", parse_sort_opt),
OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
- OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+ OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator",
parse_slab_opt),
OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
@@ -1949,9 +1949,9 @@ int cmd_kmem(int argc, const char **argv)
return __cmd_record(argc, argv);
}
- file.path = input_name;
+ data.file.path = input_name;
- kmem_session = session = perf_session__new(&file, false, &perf_kmem);
+ kmem_session = session = perf_session__new(&data, false, &perf_kmem);
if (session == NULL)
return -1;
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 721f4f91291a..0af4c092b471 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1067,10 +1067,12 @@ static int read_events(struct perf_kvm_stat *kvm)
.namespaces = perf_event__process_namespaces,
.ordered_events = true,
};
- struct perf_data_file file = {
- .path = kvm->file_name,
- .mode = PERF_DATA_MODE_READ,
- .force = kvm->force,
+ struct perf_data file = {
+ .file = {
+ .path = kvm->file_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = kvm->force,
};
kvm->tool = eops;
@@ -1358,7 +1360,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
"perf kvm stat live [<options>]",
NULL
};
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_WRITE,
};
@@ -1432,7 +1434,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
/*
* perf session
*/
- kvm->session = perf_session__new(&file, false, &kvm->tool);
+ kvm->session = perf_session__new(&data, false, &kvm->tool);
if (kvm->session == NULL) {
err = -1;
goto out;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ff98652484a7..81af29400b64 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -864,13 +864,15 @@ static int __cmd_report(bool display_info)
.namespaces = perf_event__process_namespaces,
.ordered_events = true,
};
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = force,
};
- session = perf_session__new(&file, false, &eops);
+ session = perf_session__new(&data, false, &eops);
if (!session) {
pr_err("Initializing perf session failed\n");
return -1;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 6940490bc3f9..f09fd1a1b813 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -236,13 +236,15 @@ static int process_sample_event(struct perf_tool *tool,
static int report_raw_events(struct perf_mem *mem)
{
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = mem->force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = mem->force,
};
int ret;
- struct perf_session *session = perf_session__new(&file, false,
+ struct perf_session *session = perf_session__new(&data, false,
&mem->tool);
if (session == NULL)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a6cbf1640269..f4d9fc54b382 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -66,7 +66,7 @@ struct record {
struct perf_tool tool;
struct record_opts opts;
u64 bytes_written;
- struct perf_data_file file;
+ struct perf_data data;
struct auxtrace_record *itr;
struct perf_evlist *evlist;
struct perf_session *session;
@@ -107,7 +107,7 @@ static bool switch_output_time(struct record *rec)
static int record__write(struct record *rec, void *bf, size_t size)
{
- if (perf_data_file__write(rec->session->file, bf, size) < 0) {
+ if (perf_data__write(rec->session->data, bf, size) < 0) {
pr_err("failed to write perf data, error: %m\n");
return -1;
}
@@ -173,13 +173,13 @@ static int record__process_auxtrace(struct perf_tool *tool,
size_t len1, void *data2, size_t len2)
{
struct record *rec = container_of(tool, struct record, tool);
- struct perf_data_file *file = &rec->file;
+ struct perf_data *data = &rec->data;
size_t padding;
u8 pad[8] = {0};
- if (!perf_data_file__is_pipe(file)) {
+ if (!perf_data__is_pipe(data)) {
off_t file_offset;
- int fd = perf_data_file__fd(file);
+ int fd = perf_data__fd(data);
int err;
file_offset = lseek(fd, 0, SEEK_CUR);
@@ -398,10 +398,10 @@ static int process_sample_event(struct perf_tool *tool,
static int process_buildids(struct record *rec)
{
- struct perf_data_file *file = &rec->file;
+ struct perf_data *data = &rec->data;
struct perf_session *session = rec->session;
- if (file->size == 0)
+ if (data->size == 0)
return 0;
/*
@@ -544,14 +544,14 @@ static void record__init_features(struct record *rec)
static void
record__finish_output(struct record *rec)
{
- struct perf_data_file *file = &rec->file;
- int fd = perf_data_file__fd(file);
+ struct perf_data *data = &rec->data;
+ int fd = perf_data__fd(data);
- if (file->is_pipe)
+ if (data->is_pipe)
return;
rec->session->header.data_size += rec->bytes_written;
- file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
+ data->size = lseek(perf_data__fd(data), 0, SEEK_CUR);
if (!rec->no_buildid) {
process_buildids(rec);
@@ -590,7 +590,7 @@ static int record__synthesize(struct record *rec, bool tail);
static int
record__switch_output(struct record *rec, bool at_exit)
{
- struct perf_data_file *file = &rec->file;
+ struct perf_data *data = &rec->data;
int fd, err;
/* Same Size: "2015122520103046"*/
@@ -608,7 +608,7 @@ record__switch_output(struct record *rec, bool at_exit)
return -EINVAL;
}
- fd = perf_data_file__switch(file, timestamp,
+ fd = perf_data__switch(data, timestamp,
rec->session->header.data_offset,
at_exit);
if (fd >= 0 && !at_exit) {
@@ -618,7 +618,7 @@ record__switch_output(struct record *rec, bool at_exit)
if (!quiet)
fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
- file->path, timestamp);
+ data->file.path, timestamp);
/* Output tracking events */
if (!at_exit) {
@@ -693,16 +693,16 @@ static int record__synthesize(struct record *rec, bool tail)
{
struct perf_session *session = rec->session;
struct machine *machine = &session->machines.host;
- struct perf_data_file *file = &rec->file;
+ struct perf_data *data = &rec->data;
struct record_opts *opts = &rec->opts;
struct perf_tool *tool = &rec->tool;
- int fd = perf_data_file__fd(file);
+ int fd = perf_data__fd(data);
int err = 0;
if (rec->opts.tail_synthesize != tail)
return 0;
- if (file->is_pipe) {
+ if (data->is_pipe) {
err = perf_event__synthesize_features(
tool, session, rec->evlist, process_synthesized_event);
if (err < 0) {
@@ -781,7 +781,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
struct machine *machine;
struct perf_tool *tool = &rec->tool;
struct record_opts *opts = &rec->opts;
- struct perf_data_file *file = &rec->file;
+ struct perf_data *data = &rec->data;
struct perf_session *session;
bool disabled = false, draining = false;
int fd;
@@ -807,20 +807,20 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
signal(SIGUSR2, SIG_IGN);
}
- session = perf_session__new(file, false, tool);
+ session = perf_session__new(data, false, tool);
if (session == NULL) {
pr_err("Perf session creation failed.\n");
return -1;
}
- fd = perf_data_file__fd(file);
+ fd = perf_data__fd(data);
rec->session = session;
record__init_features(rec);
if (forks) {
err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
- argv, file->is_pipe,
+ argv, data->is_pipe,
workload_exec_failed_signal);
if (err < 0) {
pr_err("Couldn't run the workload!\n");
@@ -856,7 +856,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
if (!rec->evlist->nr_groups)
perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
- if (file->is_pipe) {
+ if (data->is_pipe) {
err = perf_header__write_pipe(fd);
if (err < 0)
goto out_child;
@@ -1117,8 +1117,8 @@ out_child:
samples[0] = '\0';
fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
- perf_data_file__size(file) / 1024.0 / 1024.0,
- file->path, postfix, samples);
+ perf_data__size(data) / 1024.0 / 1024.0,
+ data->file.path, postfix, samples);
}
out_delete_session:
@@ -1482,7 +1482,7 @@ static struct option __record_options[] = {
OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
"list of cpus to monitor"),
OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
- OPT_STRING('o', "output", &record.file.path, "file",
+ OPT_STRING('o', "output", &record.data.file.path, "file",
"output file name"),
OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
&record.opts.no_inherit_set,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f9dff652dcbd..3c2d9d4932f3 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -257,7 +257,7 @@ static int report__setup_sample_type(struct report *rep)
{
struct perf_session *session = rep->session;
u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
- bool is_pipe = perf_data_file__is_pipe(session->file);
+ bool is_pipe = perf_data__is_pipe(session->data);
if (session->itrace_synth_opts->callchain ||
(!is_pipe &&
@@ -568,7 +568,7 @@ static int __cmd_report(struct report *rep)
int ret;
struct perf_session *session = rep->session;
struct perf_evsel *pos;
- struct perf_data_file *file = session->file;
+ struct perf_data *data = session->data;
signal(SIGINT, sig_handler);
@@ -637,7 +637,7 @@ static int __cmd_report(struct report *rep)
rep->nr_entries += evsel__hists(pos)->nr_entries;
if (rep->nr_entries == 0) {
- ui__error("The %s file has no samples!\n", file->path);
+ ui__error("The %s file has no samples!\n", data->file.path);
return 0;
}
@@ -879,7 +879,7 @@ int cmd_report(int argc, const char **argv)
"Show inline function"),
OPT_END()
};
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
int ret = hists__init();
@@ -940,11 +940,11 @@ int cmd_report(int argc, const char **argv)
input_name = "perf.data";
}
- file.path = input_name;
- file.force = symbol_conf.force;
+ data.file.path = input_name;
+ data.force = symbol_conf.force;
repeat:
- session = perf_session__new(&file, false, &report.tool);
+ session = perf_session__new(&data, false, &report.tool);
if (session == NULL)
return -1;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b7e8812ee80c..47e54348b5ed 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1700,14 +1700,16 @@ static int perf_sched__read_events(struct perf_sched *sched)
{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
};
struct perf_session *session;
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = sched->force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = sched->force,
};
int rc = -1;
- session = perf_session__new(&file, false, &sched->tool);
+ session = perf_session__new(&data, false, &sched->tool);
if (session == NULL) {
pr_debug("No Memory for session\n");
return -1;
@@ -2902,10 +2904,12 @@ static int perf_sched__timehist(struct perf_sched *sched)
const struct perf_evsel_str_handler migrate_handlers[] = {
{ "sched:sched_migrate_task", timehist_migrate_task_event, },
};
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = sched->force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = sched->force,
};
struct perf_session *session;
@@ -2930,7 +2934,7 @@ static int perf_sched__timehist(struct perf_sched *sched)
symbol_conf.use_callchain = sched->show_callchain;
- session = perf_session__new(&file, false, &sched->tool);
+ session = perf_session__new(&data, false, &sched->tool);
if (session == NULL)
return -ENOMEM;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index a3add2cd7856..89975e30c0ba 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -210,6 +210,51 @@ static struct {
},
};
+struct perf_evsel_script {
+ char *filename;
+ FILE *fp;
+ u64 samples;
+};
+
+static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel,
+ struct perf_data *data)
+{
+ struct perf_evsel_script *es = malloc(sizeof(*es));
+
+ if (es != NULL) {
+ if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0)
+ goto out_free;
+ es->fp = fopen(es->filename, "w");
+ if (es->fp == NULL)
+ goto out_free_filename;
+ es->samples = 0;
+ }
+
+ return es;
+out_free_filename:
+ zfree(&es->filename);
+out_free:
+ free(es);
+ return NULL;
+}
+
+static void perf_evsel_script__delete(struct perf_evsel_script *es)
+{
+ zfree(&es->filename);
+ fclose(es->fp);
+ es->fp = NULL;
+ free(es);
+}
+
+static int perf_evsel_script__fprintf(struct perf_evsel_script *es, FILE *fp)
+{
+ struct stat st;
+
+ fstat(fileno(es->fp), &st);
+ return fprintf(fp, "[ perf script: Wrote %.3f MB %s (%" PRIu64 " samples) ]\n",
+ st.st_size / 1024.0 / 1024.0, es->filename, es->samples);
+}
+
static inline int output_type(unsigned int type)
{
switch (type) {
@@ -769,27 +814,26 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
* but the exit is not. Let the caller patch it up.
*/
if (kernel != machine__kernel_ip(machine, end)) {
- printf("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n",
- start, end);
+ pr_debug("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", start, end);
return -ENXIO;
}
memset(&al, 0, sizeof(al));
if (end - start > MAXBB - MAXINSN) {
if (last)
- printf("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
+ pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
else
- printf("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
+ pr_debug("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
return 0;
}
thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al);
if (!al.map || !al.map->dso) {
- printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
+ pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
return 0;
}
if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) {
- printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
+ pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
return 0;
}
@@ -802,7 +846,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
*is64bit = al.map->dso->is_64_bit;
if (len <= 0)
- printf("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
+ pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
start, end);
return len;
}
@@ -1393,6 +1437,7 @@ struct perf_script {
bool show_switch_events;
bool show_namespace_events;
bool allocated;
+ bool per_event_dump;
struct cpu_map *cpus;
struct thread_map *threads;
int name_width;
@@ -1439,15 +1484,18 @@ static void process_event(struct perf_script *script,
struct thread *thread = al->thread;
struct perf_event_attr *attr = &evsel->attr;
unsigned int type = output_type(attr->type);
- FILE *fp = stdout;
+ struct perf_evsel_script *es = evsel->priv;
+ FILE *fp = es->fp;
if (output[type].fields == 0)
return;
+ ++es->samples;
+
perf_sample__fprintf_start(sample, thread, evsel, fp);
if (PRINT_FIELD(PERIOD))
- printf("%10" PRIu64 " ", sample->period);
+ fprintf(fp, "%10" PRIu64 " ", sample->period);
if (PRINT_FIELD(EVNAME)) {
const char *evname = perf_evsel__name(evsel);
@@ -1455,8 +1503,7 @@ static void process_event(struct perf_script *script,
if (!script->name_width)
script->name_width = perf_evlist__max_name_len(script->session->evlist);
- printf("%*s: ", script->name_width,
- evname ? evname : "[unknown]");
+ fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]");
}
if (print_flags)
@@ -1467,9 +1514,10 @@ static void process_event(struct perf_script *script,
return;
}
- if (PRINT_FIELD(TRACE))
- event_format__print(evsel->tp_format, sample->cpu,
- sample->raw_data, sample->raw_size);
+ if (PRINT_FIELD(TRACE)) {
+ event_format__fprintf(evsel->tp_format, sample->cpu,
+ sample->raw_data, sample->raw_size, fp);
+ }
if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
perf_sample__fprintf_synth(sample, evsel, fp);
@@ -1513,8 +1561,8 @@ static void process_event(struct perf_script *script,
perf_sample__fprintf_insn(sample, attr, thread, machine, fp);
if (PRINT_FIELD(PHYS_ADDR))
- printf("%16" PRIx64, sample->phys_addr);
- printf("\n");
+ fprintf(fp, "%16" PRIx64, sample->phys_addr);
+ fprintf(fp, "\n");
}
static struct scripting_ops *scripting_ops;
@@ -1888,6 +1936,65 @@ static void sig_handler(int sig __maybe_unused)
session_done = 1;
}
+static void perf_script__fclose_per_event_dump(struct perf_script *script)
+{
+ struct perf_evlist *evlist = script->session->evlist;
+ struct perf_evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (!evsel->priv)
+ break;
+ perf_evsel_script__delete(evsel->priv);
+ evsel->priv = NULL;
+ }
+}
+
+static int perf_script__fopen_per_event_dump(struct perf_script *script)
+{
+ struct perf_evsel *evsel;
+
+ evlist__for_each_entry(script->session->evlist, evsel) {
+ evsel->priv = perf_evsel_script__new(evsel, script->session->data);
+ if (evsel->priv == NULL)
+ goto out_err_fclose;
+ }
+
+ return 0;
+
+out_err_fclose:
+ perf_script__fclose_per_event_dump(script);
+ return -1;
+}
+
+static int perf_script__setup_per_event_dump(struct perf_script *script)
+{
+ struct perf_evsel *evsel;
+ static struct perf_evsel_script es_stdout;
+
+ if (script->per_event_dump)
+ return perf_script__fopen_per_event_dump(script);
+
+ es_stdout.fp = stdout;
+
+ evlist__for_each_entry(script->session->evlist, evsel)
+ evsel->priv = &es_stdout;
+
+ return 0;
+}
+
+static void perf_script__exit_per_event_dump_stats(struct perf_script *script)
+{
+ struct perf_evsel *evsel;
+
+ evlist__for_each_entry(script->session->evlist, evsel) {
+ struct perf_evsel_script *es = evsel->priv;
+
+ perf_evsel_script__fprintf(es, stdout);
+ perf_evsel_script__delete(es);
+ evsel->priv = NULL;
+ }
+}
+
static int __cmd_script(struct perf_script *script)
{
int ret;
@@ -1909,8 +2016,16 @@ static int __cmd_script(struct perf_script *script)
if (script->show_namespace_events)
script->tool.namespaces = process_namespaces_event;
+ if (perf_script__setup_per_event_dump(script)) {
+ pr_err("Couldn't create the per event dump files\n");
+ return -1;
+ }
+
ret = perf_session__process_events(script->session);
+ if (script->per_event_dump)
+ perf_script__exit_per_event_dump_stats(script);
+
if (debug_mode)
pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -2475,14 +2590,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
DIR *scripts_dir, *lang_dir;
struct perf_session *session;
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
};
char *temp;
int i = 0;
- session = perf_session__new(&file, false, NULL);
+ session = perf_session__new(&data, false, NULL);
if (!session)
return -1;
@@ -2760,7 +2877,7 @@ int cmd_script(int argc, const char **argv)
.ordering_requires_timestamps = true,
},
};
- struct perf_data_file file = {
+ struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
const struct option options[] = {
@@ -2828,6 +2945,8 @@ int cmd_script(int argc, const char **argv)
"Show context switch events (if recorded)"),
OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
"Show namespace 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"),
OPT_INTEGER(0, "max-blocks", &max_blocks,
"Maximum number of code blocks to dump with brstackinsn"),
@@ -2865,8 +2984,8 @@ int cmd_script(int argc, const char **argv)
argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- file.path = input_name;
- file.force = symbol_conf.force;
+ data.file.path = input_name;
+ data.force = symbol_conf.force;
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
@@ -3033,7 +3152,7 @@ int cmd_script(int argc, const char **argv)
if (!script_name)
setup_pager();
- session = perf_session__new(&file, false, &script.tool);
+ session = perf_session__new(&data, false, &script.tool);
if (session == NULL)
return -1;
@@ -3089,7 +3208,7 @@ int cmd_script(int argc, const char **argv)
goto out_delete;
}
- input = open(file.path, O_RDONLY); /* input_name */
+ input = open(data.file.path, O_RDONLY); /* input_name */
if (input < 0) {
err = -errno;
perror("failed to open file");
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index dd525417880a..59af5a8419e2 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -175,7 +175,7 @@ static int print_free_counters_hint;
struct perf_stat {
bool record;
- struct perf_data_file file;
+ struct perf_data data;
struct perf_session *session;
u64 bytes_written;
struct perf_tool tool;
@@ -253,7 +253,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
* by attr->sample_type != 0, and we can't run it on
* stat sessions.
*/
- if (!(STAT_RECORD && perf_stat.file.is_pipe))
+ if (!(STAT_RECORD && perf_stat.data.is_pipe))
attr->sample_type = PERF_SAMPLE_IDENTIFIER;
/*
@@ -295,7 +295,7 @@ static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
{
- if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
+ if (perf_data__write(&perf_stat.data, event, event->header.size) < 0) {
pr_err("failed to write perf data, error: %m\n");
return -1;
}
@@ -628,7 +628,7 @@ static int __run_perf_stat(int argc, const char **argv)
size_t l;
int status = 0;
const bool forks = (argc > 0);
- bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
+ bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false;
struct perf_evsel_config_term *err_term;
if (interval) {
@@ -719,10 +719,10 @@ try_again:
}
if (STAT_RECORD) {
- int err, fd = perf_data_file__fd(&perf_stat.file);
+ int err, fd = perf_data__fd(&perf_stat.data);
if (is_pipe) {
- err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
+ err = perf_header__write_pipe(perf_data__fd(&perf_stat.data));
} else {
err = perf_session__write_header(perf_stat.session, evsel_list,
fd, false);
@@ -845,7 +845,7 @@ static void print_noise(struct perf_evsel *evsel, double avg)
if (run_count == 1)
return;
- ps = evsel->priv;
+ ps = evsel->stats;
print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
}
@@ -1267,8 +1267,7 @@ static void aggr_update_shadow(void)
continue;
val += perf_counts(counter->counts, cpu, 0)->val;
}
- val = val * counter->scale;
- perf_stat__update_shadow_stats(counter, &val,
+ perf_stat__update_shadow_stats(counter, val,
first_shadow_cpu(counter, id));
}
}
@@ -1432,7 +1431,7 @@ static void counter_aggr_cb(struct perf_evsel *counter, void *data,
bool first __maybe_unused)
{
struct caggr_data *cd = data;
- struct perf_stat_evsel *ps = counter->priv;
+ struct perf_stat_evsel *ps = counter->stats;
cd->avg += avg_stats(&ps->res_stats[0]);
cd->avg_enabled += avg_stats(&ps->res_stats[1]);
@@ -1696,7 +1695,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
char buf[64], *prefix = NULL;
/* Do not print anything if we record to the pipe. */
- if (STAT_RECORD && perf_stat.file.is_pipe)
+ if (STAT_RECORD && perf_stat.data.is_pipe)
return;
if (interval)
@@ -2406,20 +2405,20 @@ static void init_features(struct perf_session *session)
static int __cmd_record(int argc, const char **argv)
{
struct perf_session *session;
- struct perf_data_file *file = &perf_stat.file;
+ struct perf_data *data = &perf_stat.data;
argc = parse_options(argc, argv, stat_options, stat_record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (output_name)
- file->path = output_name;
+ data->file.path = output_name;
if (run_count != 1 || forever) {
pr_err("Cannot use -r option with perf stat record.\n");
return -1;
}
- session = perf_session__new(file, false, NULL);
+ session = perf_session__new(data, false, NULL);
if (session == NULL) {
pr_err("Perf session creation failed.\n");
return -1;
@@ -2477,7 +2476,7 @@ int process_stat_config_event(struct perf_tool *tool,
if (st->aggr_mode != AGGR_UNSET)
stat_config.aggr_mode = st->aggr_mode;
- if (perf_stat.file.is_pipe)
+ if (perf_stat.data.is_pipe)
perf_stat_init_aggr_mode();
else
perf_stat_init_aggr_mode_file(st);
@@ -2585,10 +2584,10 @@ static int __cmd_report(int argc, const char **argv)
input_name = "perf.data";
}
- perf_stat.file.path = input_name;
- perf_stat.file.mode = PERF_DATA_MODE_READ;
+ perf_stat.data.file.path = input_name;
+ perf_stat.data.mode = PERF_DATA_MODE_READ;
- session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
+ session = perf_session__new(&perf_stat.data, false, &perf_stat.tool);
if (session == NULL)
return -1;
@@ -2859,7 +2858,7 @@ int cmd_stat(int argc, const char **argv)
* records, but the need to suppress the kptr_restrict messages in older
* tools remain -acme
*/
- int fd = perf_data_file__fd(&perf_stat.file);
+ int fd = perf_data__fd(&perf_stat.data);
int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
process_synthesized_event,
&perf_stat.session->machines.host);
@@ -2873,7 +2872,7 @@ int cmd_stat(int argc, const char **argv)
pr_err("failed to write stat round event\n");
}
- if (!perf_stat.file.is_pipe) {
+ if (!perf_stat.data.is_pipe) {
perf_stat.session->header.data_size += perf_stat.bytes_written;
perf_session__write_header(perf_stat.session, evsel_list, fd, true);
}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 01de01ca14f2..813698a9b8c7 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1601,13 +1601,15 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
{ "syscalls:sys_exit_pselect6", process_exit_poll },
{ "syscalls:sys_exit_select", process_exit_poll },
};
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = tchart->force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = tchart->force,
};
- struct perf_session *session = perf_session__new(&file, false,
+ struct perf_session *session = perf_session__new(&data, false,
&tchart->tool);
int ret = -EINVAL;
@@ -1617,7 +1619,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
symbol__init(&session->header.env);
(void)perf_header__process_sections(&session->header,
- perf_data_file__fd(session->file),
+ perf_data__fd(session->data),
tchart,
process_header);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 8b23982dd9f2..505b871fdc82 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -578,7 +578,6 @@ static struct syscall_fmt {
} syscall_fmts[] = {
{ .name = "access",
.arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
- { .name = "arch_prctl", .alias = "prctl", },
{ .name = "bpf",
.arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
{ .name = "brk", .hexret = true,
@@ -634,6 +633,12 @@ static struct syscall_fmt {
#else
[2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
#endif
+ { .name = "kcmp", .nr_args = 5,
+ .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
+ [1] = { .name = "pid2", .scnprintf = SCA_PID, },
+ [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
+ [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
+ [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
{ .name = "keyctl",
.arg = { [0] = STRARRAY(option, keyctl_options), }, },
{ .name = "kill",
@@ -703,6 +708,10 @@ static struct syscall_fmt {
[3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
{ .name = "poll", .timeout = true, },
{ .name = "ppoll", .timeout = true, },
+ { .name = "prctl", .alias = "arch_prctl",
+ .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
+ [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
+ [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
{ .name = "pread", .alias = "pread64", },
{ .name = "preadv", .alias = "pread", },
{ .name = "prlimit64",
@@ -985,6 +994,23 @@ size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
return printed;
}
+size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
+{
+ size_t printed = scnprintf(bf, size, "%d", fd);
+ struct thread *thread = machine__find_thread(trace->host, pid, pid);
+
+ if (thread) {
+ const char *path = thread__fd_path(thread, fd, trace);
+
+ if (path)
+ printed += scnprintf(bf + printed, size - printed, "<%s>", path);
+
+ thread__put(thread);
+ }
+
+ return printed;
+}
+
static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
struct syscall_arg *arg)
{
@@ -2529,10 +2555,12 @@ static int trace__replay(struct trace *trace)
const struct perf_evsel_str_handler handlers[] = {
{ "probe:vfs_getname", trace__vfs_getname, },
};
- struct perf_data_file file = {
- .path = input_name,
- .mode = PERF_DATA_MODE_READ,
- .force = trace->force,
+ struct perf_data data = {
+ .file = {
+ .path = input_name,
+ },
+ .mode = PERF_DATA_MODE_READ,
+ .force = trace->force,
};
struct perf_session *session;
struct perf_evsel *evsel;
@@ -2555,7 +2583,7 @@ static int trace__replay(struct trace *trace)
/* add tid to output */
trace->multiple_threads = true;
- session = perf_session__new(&file, false, &trace->tool);
+ session = perf_session__new(&data, false, &trace->tool);
if (session == NULL)
return -1;
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 322629423b49..a3a041b0d35e 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -4,8 +4,10 @@ HEADERS='
include/uapi/drm/drm.h
include/uapi/drm/i915_drm.h
include/uapi/linux/fcntl.h
+include/uapi/linux/kcmp.h
include/uapi/linux/kvm.h
include/uapi/linux/perf_event.h
+include/uapi/linux/prctl.h
include/uapi/linux/sched.h
include/uapi/linux/stat.h
include/uapi/linux/vhost.h
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index 19b0561fd6f6..9bbfed51f1d6 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -29,12 +29,14 @@ static int get_temp(char *path)
static int session_write_header(char *path)
{
struct perf_session *session;
- struct perf_data_file file = {
- .path = path,
- .mode = PERF_DATA_MODE_WRITE,
+ struct perf_data data = {
+ .file = {
+ .path = path,
+ },
+ .mode = PERF_DATA_MODE_WRITE,
};
- session = perf_session__new(&file, false, NULL);
+ session = perf_session__new(&data, false, NULL);
TEST_ASSERT_VAL("can't get session", session);
session->evlist = perf_evlist__new_default();
@@ -46,7 +48,7 @@ static int session_write_header(char *path)
session->header.data_size += DATA_SIZE;
TEST_ASSERT_VAL("failed to write header",
- !perf_session__write_header(session, session->evlist, file.fd, true));
+ !perf_session__write_header(session, session->evlist, data.file.fd, true));
perf_session__delete(session);
@@ -56,13 +58,15 @@ static int session_write_header(char *path)
static int check_cpu_topology(char *path, struct cpu_map *map)
{
struct perf_session *session;
- struct perf_data_file file = {
- .path = path,
- .mode = PERF_DATA_MODE_READ,
+ struct perf_data data = {
+ .file = {
+ .path = path,
+ },
+ .mode = PERF_DATA_MODE_READ,
};
int i;
- session = perf_session__new(&file, false, NULL);
+ session = perf_session__new(&data, false, NULL);
TEST_ASSERT_VAL("can't get session", session);
for (i = 0; i < session->header.env.nr_cpus_avail; i++) {
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build
index 175d633c6b49..066bbf0f4a74 100644
--- a/tools/perf/trace/beauty/Build
+++ b/tools/perf/trace/beauty/Build
@@ -3,5 +3,7 @@ libperf-y += fcntl.o
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86))
libperf-y += ioctl.o
endif
+libperf-y += kcmp.o
libperf-y += pkey_alloc.o
+libperf-y += prctl.o
libperf-y += statx.o
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
index 4b58581a6053..3f067bdab84f 100644
--- a/tools/perf/trace/beauty/beauty.h
+++ b/tools/perf/trace/beauty/beauty.h
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <sys/types.h>
struct strarray {
int offset;
@@ -26,6 +27,8 @@ size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const cha
struct trace;
struct thread;
+size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size);
+
/**
* @val: value of syscall argument being formatted
* @args: All the args, use syscall_args__val(arg, nth) to access one
@@ -78,12 +81,27 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar
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
+size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_KCMP_TYPE syscall_arg__scnprintf_kcmp_type
+
+size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx
+
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
size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg);
#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
+size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_OPTION syscall_arg__scnprintf_prctl_option
+
+size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_ARG2 syscall_arg__scnprintf_prctl_arg2
+
+size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3
+
size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg);
#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
diff --git a/tools/perf/trace/beauty/kcmp.c b/tools/perf/trace/beauty/kcmp.c
new file mode 100644
index 000000000000..f62040eb9d5c
--- /dev/null
+++ b/tools/perf/trace/beauty/kcmp.c
@@ -0,0 +1,44 @@
+/*
+ * trace/beauty/kcmp.c
+ *
+ * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "trace/beauty/beauty.h"
+#include <linux/kernel.h>
+#include <sys/types.h>
+#include <machine.h>
+#include <uapi/linux/kcmp.h>
+
+#include "trace/beauty/generated/kcmp_type_array.c"
+
+size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg)
+{
+ unsigned long fd = arg->val;
+ int type = syscall_arg__val(arg, 2);
+ pid_t pid;
+
+ if (type != KCMP_FILE)
+ return syscall_arg__scnprintf_long(bf, size, arg);
+
+ pid = syscall_arg__val(arg, arg->idx == 3 ? 0 : 1); /* idx1 -> pid1, idx2 -> pid2 */
+ return pid__scnprintf_fd(arg->trace, pid, fd, bf, size);
+}
+
+static size_t kcmp__scnprintf_type(int type, char *bf, size_t size)
+{
+ static DEFINE_STRARRAY(kcmp_types);
+ return strarray__scnprintf(&strarray__kcmp_types, bf, size, "%d", type);
+}
+
+size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg)
+{
+ unsigned long type = arg->val;
+
+ if (type != KCMP_FILE)
+ arg->mask |= (1 << 3) | (1 << 4); /* Ignore idx1 and idx2 */
+
+ return kcmp__scnprintf_type(type, bf, size);
+}
diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh
new file mode 100755
index 000000000000..40d063b8c082
--- /dev/null
+++ b/tools/perf/trace/beauty/kcmp_type.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+header_dir=$1
+
+printf "static const char *kcmp_types[] = {\n"
+regex='^[[:space:]]+(KCMP_(\w+)),'
+egrep $regex ${header_dir}/kcmp.h | grep -v KCMP_TYPES, | \
+ sed -r "s/$regex/\1 \2/g" | \
+ xargs printf "\t[%s]\t= \"%s\",\n"
+printf "};\n"
diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c
new file mode 100644
index 000000000000..246130dad6c4
--- /dev/null
+++ b/tools/perf/trace/beauty/prctl.c
@@ -0,0 +1,82 @@
+/*
+ * trace/beauty/prctl.c
+ *
+ * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "trace/beauty/beauty.h"
+#include <linux/kernel.h>
+#include <uapi/linux/prctl.h>
+
+#include "trace/beauty/generated/prctl_option_array.c"
+
+static size_t prctl__scnprintf_option(int option, char *bf, size_t size)
+{
+ static DEFINE_STRARRAY(prctl_options);
+ return strarray__scnprintf(&strarray__prctl_options, bf, size, "%d", option);
+}
+
+static size_t prctl__scnprintf_set_mm(int option, char *bf, size_t size)
+{
+ static DEFINE_STRARRAY(prctl_set_mm_options);
+ return strarray__scnprintf(&strarray__prctl_set_mm_options, bf, size, "%d", option);
+}
+
+size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg)
+{
+ int option = syscall_arg__val(arg, 0);
+
+ if (option == PR_SET_MM)
+ return prctl__scnprintf_set_mm(arg->val, bf, size);
+ /*
+ * We still don't grab the contents of pointers on entry or exit,
+ * so just print them as hex numbers
+ */
+ if (option == PR_SET_NAME)
+ return syscall_arg__scnprintf_hex(bf, size, arg);
+
+ return syscall_arg__scnprintf_long(bf, size, arg);
+}
+
+size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg)
+{
+ int option = syscall_arg__val(arg, 0);
+
+ if (option == PR_SET_MM)
+ return syscall_arg__scnprintf_hex(bf, size, arg);
+
+ return syscall_arg__scnprintf_long(bf, size, arg);
+}
+
+size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg)
+{
+ unsigned long option = arg->val;
+ enum {
+ SPO_ARG2 = (1 << 1),
+ SPO_ARG3 = (1 << 2),
+ SPO_ARG4 = (1 << 3),
+ SPO_ARG5 = (1 << 4),
+ SPO_ARG6 = (1 << 5),
+ };
+ const u8 all_but2 = SPO_ARG3 | SPO_ARG4 | SPO_ARG5 | SPO_ARG6;
+ const u8 all = SPO_ARG2 | all_but2;
+ const u8 masks[] = {
+ [PR_GET_DUMPABLE] = all,
+ [PR_SET_DUMPABLE] = all_but2,
+ [PR_SET_NAME] = all_but2,
+ [PR_GET_CHILD_SUBREAPER] = all_but2,
+ [PR_SET_CHILD_SUBREAPER] = all_but2,
+ [PR_GET_SECUREBITS] = all,
+ [PR_SET_SECUREBITS] = all_but2,
+ [PR_SET_MM] = SPO_ARG4 | SPO_ARG5 | SPO_ARG6,
+ [PR_GET_PDEATHSIG] = all,
+ [PR_SET_PDEATHSIG] = all_but2,
+ };
+
+ if (option < ARRAY_SIZE(masks))
+ arg->mask |= masks[option];
+
+ return prctl__scnprintf_option(option, bf, size);
+}
diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh
new file mode 100755
index 000000000000..0be4138fbe71
--- /dev/null
+++ b/tools/perf/trace/beauty/prctl_option.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+header_dir=$1
+
+printf "static const char *prctl_options[] = {\n"
+regex='^#define[[:space:]]+PR_([GS]ET\w+)[[:space:]]*([[:xdigit:]]+).*'
+egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
+ sed -r "s/$regex/\2 \1/g" | \
+ sort -n | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
+
+printf "static const char *prctl_set_mm_options[] = {\n"
+regex='^#[[:space:]]+define[[:space:]]+PR_SET_MM_(\w+)[[:space:]]*([[:digit:]]+).*'
+egrep $regex ${header_dir}/prctl.h | \
+ sed -r "s/$regex/\2 \1/g" | \
+ sort -n | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 5547457566a7..a33491416400 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -208,7 +208,7 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
static void *auxtrace_copy_data(u64 size, struct perf_session *session)
{
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
void *p;
ssize_t ret;
@@ -305,7 +305,7 @@ static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues,
if (session->one_mmap) {
buffer->data = buffer->data_offset - session->one_mmap_offset +
session->one_mmap_addr;
- } else if (perf_data_file__is_pipe(session->file)) {
+ } else if (perf_data__is_pipe(session->data)) {
buffer->data = auxtrace_copy_data(buffer->size, session);
if (!buffer->data)
return -ENOMEM;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3a3916934a92..837012147c7b 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1091,10 +1091,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
al->map = node->map;
al->sym = node->sym;
al->srcline = node->srcline;
- if (node->map)
- al->addr = node->map->map_ip(node->map, node->ip);
- else
- al->addr = node->ip;
+ al->addr = node->ip;
if (al->sym == NULL) {
if (hide_unresolved)
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 2346cecb8ea2..5744c12641a5 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1577,10 +1577,10 @@ int bt_convert__perf2ctf(const char *input, const char *path,
struct perf_data_convert_opts *opts)
{
struct perf_session *session;
- struct perf_data_file file = {
- .path = input,
- .mode = PERF_DATA_MODE_READ,
- .force = opts->force,
+ struct perf_data data = {
+ .file.path = input,
+ .mode = PERF_DATA_MODE_READ,
+ .force = opts->force,
};
struct convert c = {
.tool = {
@@ -1619,7 +1619,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
err = -1;
/* perf.data session */
- session = perf_session__new(&file, 0, &c.tool);
+ session = perf_session__new(&data, 0, &c.tool);
if (!session)
goto free_writer;
@@ -1650,7 +1650,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
fprintf(stderr,
"[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
- file.path, path);
+ data.file.path, path);
fprintf(stderr,
"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples",
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 1123b30e3033..f80a23d031d6 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -21,56 +21,56 @@
#endif
#endif
-static bool check_pipe(struct perf_data_file *file)
+static bool check_pipe(struct perf_data *data)
{
struct stat st;
bool is_pipe = false;
- int fd = perf_data_file__is_read(file) ?
+ int fd = perf_data__is_read(data) ?
STDIN_FILENO : STDOUT_FILENO;
- if (!file->path) {
+ if (!data->file.path) {
if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
is_pipe = true;
} else {
- if (!strcmp(file->path, "-"))
+ if (!strcmp(data->file.path, "-"))
is_pipe = true;
}
if (is_pipe)
- file->fd = fd;
+ data->file.fd = fd;
- return file->is_pipe = is_pipe;
+ return data->is_pipe = is_pipe;
}
-static int check_backup(struct perf_data_file *file)
+static int check_backup(struct perf_data *data)
{
struct stat st;
- if (!stat(file->path, &st) && st.st_size) {
+ if (!stat(data->file.path, &st) && st.st_size) {
/* TODO check errors properly */
char oldname[PATH_MAX];
snprintf(oldname, sizeof(oldname), "%s.old",
- file->path);
+ data->file.path);
unlink(oldname);
- rename(file->path, oldname);
+ rename(data->file.path, oldname);
}
return 0;
}
-static int open_file_read(struct perf_data_file *file)
+static int open_file_read(struct perf_data *data)
{
struct stat st;
int fd;
char sbuf[STRERR_BUFSIZE];
- fd = open(file->path, O_RDONLY);
+ fd = open(data->file.path, O_RDONLY);
if (fd < 0) {
int err = errno;
- pr_err("failed to open %s: %s", file->path,
+ pr_err("failed to open %s: %s", data->file.path,
str_error_r(err, sbuf, sizeof(sbuf)));
- if (err == ENOENT && !strcmp(file->path, "perf.data"))
+ if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
pr_err(" (try 'perf record' first)");
pr_err("\n");
return -err;
@@ -79,19 +79,19 @@ static int open_file_read(struct perf_data_file *file)
if (fstat(fd, &st) < 0)
goto out_close;
- if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
+ if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
pr_err("File %s not owned by current user or root (use -f to override)\n",
- file->path);
+ data->file.path);
goto out_close;
}
if (!st.st_size) {
- pr_info("zero-sized file (%s), nothing to do!\n",
- file->path);
+ pr_info("zero-sized data (%s), nothing to do!\n",
+ data->file.path);
goto out_close;
}
- file->size = st.st_size;
+ data->size = st.st_size;
return fd;
out_close:
@@ -99,49 +99,49 @@ static int open_file_read(struct perf_data_file *file)
return -1;
}
-static int open_file_write(struct perf_data_file *file)
+static int open_file_write(struct perf_data *data)
{
int fd;
char sbuf[STRERR_BUFSIZE];
- if (check_backup(file))
+ if (check_backup(data))
return -1;
- fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
+ fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
S_IRUSR|S_IWUSR);
if (fd < 0)
- pr_err("failed to open %s : %s\n", file->path,
+ pr_err("failed to open %s : %s\n", data->file.path,
str_error_r(errno, sbuf, sizeof(sbuf)));
return fd;
}
-static int open_file(struct perf_data_file *file)
+static int open_file(struct perf_data *data)
{
int fd;
- fd = perf_data_file__is_read(file) ?
- open_file_read(file) : open_file_write(file);
+ fd = perf_data__is_read(data) ?
+ open_file_read(data) : open_file_write(data);
- file->fd = fd;
+ data->file.fd = fd;
return fd < 0 ? -1 : 0;
}
-int perf_data_file__open(struct perf_data_file *file)
+int perf_data__open(struct perf_data *data)
{
- if (check_pipe(file))
+ if (check_pipe(data))
return 0;
- if (!file->path)
- file->path = "perf.data";
+ if (!data->file.path)
+ data->file.path = "perf.data";
- return open_file(file);
+ return open_file(data);
}
-void perf_data_file__close(struct perf_data_file *file)
+void perf_data__close(struct perf_data *data)
{
- close(file->fd);
+ close(data->file.fd);
}
ssize_t perf_data_file__write(struct perf_data_file *file,
@@ -150,42 +150,48 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
return writen(file->fd, buf, size);
}
-int perf_data_file__switch(struct perf_data_file *file,
+ssize_t perf_data__write(struct perf_data *data,
+ void *buf, size_t size)
+{
+ return perf_data_file__write(&data->file, buf, size);
+}
+
+int perf_data__switch(struct perf_data *data,
const char *postfix,
size_t pos, bool at_exit)
{
char *new_filepath;
int ret;
- if (check_pipe(file))
+ if (check_pipe(data))
return -EINVAL;
- if (perf_data_file__is_read(file))
+ if (perf_data__is_read(data))
return -EINVAL;
- if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0)
+ if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0)
return -ENOMEM;
/*
* Only fire a warning, don't return error, continue fill
* original file.
*/
- if (rename(file->path, new_filepath))
- pr_warning("Failed to rename %s to %s\n", file->path, new_filepath);
+ if (rename(data->file.path, new_filepath))
+ pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath);
if (!at_exit) {
- close(file->fd);
- ret = perf_data_file__open(file);
+ close(data->file.fd);
+ ret = perf_data__open(data);
if (ret < 0)
goto out;
- if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) {
+ if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
ret = -errno;
pr_debug("Failed to lseek to %zu: %s",
pos, strerror(errno));
goto out;
}
}
- ret = file->fd;
+ ret = data->file.fd;
out:
free(new_filepath);
return ret;
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index ae510ce16cb1..000c43bbb7ac 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -9,51 +9,57 @@ enum perf_data_mode {
};
struct perf_data_file {
- const char *path;
- int fd;
+ const char *path;
+ int fd;
+};
+
+struct perf_data {
+ struct perf_data_file file;
bool is_pipe;
bool force;
unsigned long size;
enum perf_data_mode mode;
};
-static inline bool perf_data_file__is_read(struct perf_data_file *file)
+static inline bool perf_data__is_read(struct perf_data *data)
{
- return file->mode == PERF_DATA_MODE_READ;
+ return data->mode == PERF_DATA_MODE_READ;
}
-static inline bool perf_data_file__is_write(struct perf_data_file *file)
+static inline bool perf_data__is_write(struct perf_data *data)
{
- return file->mode == PERF_DATA_MODE_WRITE;
+ return data->mode == PERF_DATA_MODE_WRITE;
}
-static inline int perf_data_file__is_pipe(struct perf_data_file *file)
+static inline int perf_data__is_pipe(struct perf_data *data)
{
- return file->is_pipe;
+ return data->is_pipe;
}
-static inline int perf_data_file__fd(struct perf_data_file *file)
+static inline int perf_data__fd(struct perf_data *data)
{
- return file->fd;
+ return data->file.fd;
}
-static inline unsigned long perf_data_file__size(struct perf_data_file *file)
+static inline unsigned long perf_data__size(struct perf_data *data)
{
- return file->size;
+ return data->size;
}
-int perf_data_file__open(struct perf_data_file *file);
-void perf_data_file__close(struct perf_data_file *file);
+int perf_data__open(struct perf_data *data);
+void perf_data__close(struct perf_data *data);
+ssize_t perf_data__write(struct perf_data *data,
+ void *buf, size_t size);
ssize_t perf_data_file__write(struct perf_data_file *file,
void *buf, size_t size);
/*
* If at_exit is set, only rename current perf.data to
- * perf.data.<postfix>, continue write on original file.
+ * perf.data.<postfix>, continue write on original data.
* Set at_exit when flushing the last output.
*
* Return value is fd of new output.
*/
-int perf_data_file__switch(struct perf_data_file *file,
+int perf_data__switch(struct perf_data *data,
const char *postfix,
size_t pos, bool at_exit);
#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index db658785d828..64782b19089d 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -68,6 +68,8 @@ struct perf_evsel_config_term {
} val;
};
+struct perf_stat_evsel;
+
/** struct perf_evsel - event selector
*
* @evlist - evlist this evsel is in, if it is in one.
@@ -101,6 +103,7 @@ struct perf_evsel {
const char *unit;
struct event_format *tp_format;
off_t id_offset;
+ struct perf_stat_evsel *stats;
void *priv;
u64 db_id;
struct cgroup_sel *cgrp;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 605bbd5404fb..6e59dcca9df2 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1762,7 +1762,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)
session = container_of(ff->ph, struct perf_session, header);
- if (session->file->is_pipe) {
+ if (session->data->is_pipe) {
/* Save events for reading later by print_event_desc,
* since they can't be read again in pipe mode. */
ff->events = events;
@@ -1771,7 +1771,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)
for (evsel = events; evsel->attr.size; evsel++)
perf_evlist__set_event_name(session->evlist, evsel);
- if (!session->file->is_pipe)
+ if (!session->data->is_pipe)
free_event_desc(events);
return 0;
@@ -2248,7 +2248,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
{
struct header_print_data hd;
struct perf_header *header = &session->header;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
struct stat st;
int ret, bit;
@@ -2264,7 +2264,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
perf_header__process_sections(header, fd, &hd,
perf_file_section__fprintf_info);
- if (session->file->is_pipe)
+ if (session->data->is_pipe)
return 0;
fprintf(fp, "# missing features: ");
@@ -2757,7 +2757,7 @@ static int perf_header__read_pipe(struct perf_session *session)
struct perf_pipe_file_header f_header;
if (perf_file_header__read_pipe(&f_header, header,
- perf_data_file__fd(session->file),
+ perf_data__fd(session->data),
session->repipe) < 0) {
pr_debug("incompatible file format\n");
return -EINVAL;
@@ -2860,13 +2860,13 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
int perf_session__read_header(struct perf_session *session)
{
- struct perf_data_file *file = session->file;
+ struct perf_data *data = session->data;
struct perf_header *header = &session->header;
struct perf_file_header f_header;
struct perf_file_attr f_attr;
u64 f_id;
int nr_attrs, nr_ids, i, j;
- int fd = perf_data_file__fd(file);
+ int fd = perf_data__fd(data);
session->evlist = perf_evlist__new();
if (session->evlist == NULL)
@@ -2874,7 +2874,7 @@ int perf_session__read_header(struct perf_session *session)
session->evlist->env = &header->env;
session->machines.host.env = &header->env;
- if (perf_data_file__is_pipe(file))
+ if (perf_data__is_pipe(data))
return perf_header__read_pipe(session);
if (perf_file_header__read(&f_header, header, fd) < 0)
@@ -2889,7 +2889,7 @@ int perf_session__read_header(struct perf_session *session)
if (f_header.data.size == 0) {
pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
"Was the 'perf record' command properly terminated?\n",
- file->path);
+ data->file.path);
}
nr_attrs = f_header.attrs.size / f_header.attr_size;
@@ -3397,7 +3397,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
struct perf_session *session)
{
ssize_t size_read, padding, size = event->tracing_data.size;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
off_t offset = lseek(fd, 0, SEEK_CUR);
char buf[BUFSIZ];
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index 218ee2bac9a5..5325e65f9711 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -500,7 +500,7 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
}
if (!buffer->data) {
- int fd = perf_data_file__fd(btsq->bts->session->file);
+ int fd = perf_data__fd(btsq->bts->session->data);
buffer->data = auxtrace_buffer__get_data(buffer, fd);
if (!buffer->data) {
@@ -664,10 +664,10 @@ static int intel_bts_process_auxtrace_event(struct perf_session *session,
if (!bts->data_queued) {
struct auxtrace_buffer *buffer;
off_t data_offset;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
int err;
- if (perf_data_file__is_pipe(session->file)) {
+ if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
data_offset = lseek(fd, 0, SEEK_CUR);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index b58f9fd1e2ee..23f9ba676df0 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -271,7 +271,7 @@ next:
ptq->buffer = buffer;
if (!buffer->data) {
- int fd = perf_data_file__fd(ptq->pt->session->file);
+ int fd = perf_data__fd(ptq->pt->session->data);
buffer->data = auxtrace_buffer__get_data(buffer, fd);
if (!buffer->data)
@@ -2084,10 +2084,10 @@ static int intel_pt_process_auxtrace_event(struct perf_session *session,
if (!pt->data_queued) {
struct auxtrace_buffer *buffer;
off_t data_offset;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
int err;
- if (perf_data_file__is_pipe(session->file)) {
+ if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
data_offset = lseek(fd, 0, SEEK_CUR);
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
index 3f42ee4d2a0b..961e7a8a0e17 100644
--- a/tools/perf/util/jit.h
+++ b/tools/perf/util/jit.h
@@ -3,7 +3,7 @@
#include <data.h>
-int jit_process(struct perf_session *session, struct perf_data_file *output,
+int jit_process(struct perf_session *session, struct perf_data *output,
struct machine *machine, char *filename, pid_t pid, u64 *nbytes);
int jit_inject_record(const char *filename);
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 9084930e1757..e7645098a323 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -29,7 +29,7 @@
#include "sane_ctype.h"
struct jit_buf_desc {
- struct perf_data_file *output;
+ struct perf_data *output;
struct perf_session *session;
struct machine *machine;
union jr_entry *entry;
@@ -60,8 +60,8 @@ struct debug_line_info {
struct jit_tool {
struct perf_tool tool;
- struct perf_data_file output;
- struct perf_data_file input;
+ struct perf_data output;
+ struct perf_data input;
u64 bytes_written;
};
@@ -356,7 +356,7 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
{
ssize_t size;
- size = perf_data_file__write(jd->output, event, event->header.size);
+ size = perf_data__write(jd->output, event, event->header.size);
if (size < 0)
return -1;
@@ -751,7 +751,7 @@ jit_detect(char *mmap_name, pid_t pid)
int
jit_process(struct perf_session *session,
- struct perf_data_file *output,
+ struct perf_data *output,
struct machine *machine,
char *filename,
pid_t pid,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b3fd62f7e4c9..c09b748ab599 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -32,14 +32,14 @@ static int perf_session__deliver_event(struct perf_session *session,
static int perf_session__open(struct perf_session *session)
{
- struct perf_data_file *file = session->file;
+ struct perf_data *data = session->data;
if (perf_session__read_header(session) < 0) {
pr_err("incompatible file format (rerun with -v to learn more)\n");
return -1;
}
- if (perf_data_file__is_pipe(file))
+ if (perf_data__is_pipe(data))
return 0;
if (perf_header__has_feat(&session->header, HEADER_STAT))
@@ -120,7 +120,7 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
session->tool, event->file_offset);
}
-struct perf_session *perf_session__new(struct perf_data_file *file,
+struct perf_session *perf_session__new(struct perf_data *data,
bool repipe, struct perf_tool *tool)
{
struct perf_session *session = zalloc(sizeof(*session));
@@ -134,13 +134,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
machines__init(&session->machines);
ordered_events__init(&session->ordered_events, ordered_events__deliver_event);
- if (file) {
- if (perf_data_file__open(file))
+ if (data) {
+ if (perf_data__open(data))
goto out_delete;
- session->file = file;
+ session->data = data;
- if (perf_data_file__is_read(file)) {
+ if (perf_data__is_read(data)) {
if (perf_session__open(session) < 0)
goto out_close;
@@ -148,7 +148,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
* set session attributes that are present in perf.data
* but not in pipe-mode.
*/
- if (!file->is_pipe) {
+ if (!data->is_pipe) {
perf_session__set_id_hdr_size(session);
perf_session__set_comm_exec(session);
}
@@ -157,7 +157,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
session->machines.host.env = &perf_env;
}
- if (!file || perf_data_file__is_write(file)) {
+ if (!data || perf_data__is_write(data)) {
/*
* In O_RDONLY mode this will be performed when reading the
* kernel MMAP event, in perf_event__process_mmap().
@@ -170,7 +170,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
* In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is
* processed, so perf_evlist__sample_id_all is not meaningful here.
*/
- if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps &&
+ if ((!data || !data->is_pipe) && tool && tool->ordering_requires_timestamps &&
tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
tool->ordered_events = false;
@@ -179,7 +179,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
return session;
out_close:
- perf_data_file__close(file);
+ perf_data__close(data);
out_delete:
perf_session__delete(session);
out:
@@ -201,8 +201,8 @@ void perf_session__delete(struct perf_session *session)
perf_session__delete_threads(session);
perf_env__exit(&session->header.env);
machines__exit(&session->machines);
- if (session->file)
- perf_data_file__close(session->file);
+ if (session->data)
+ perf_data__close(session->data);
free(session);
}
@@ -290,8 +290,8 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
__maybe_unused)
{
dump_printf(": unhandled!\n");
- if (perf_data_file__is_pipe(session->file))
- skipn(perf_data_file__fd(session->file), event->auxtrace.size);
+ if (perf_data__is_pipe(session->data))
+ skipn(perf_data__fd(session->data), event->auxtrace.size);
return event->auxtrace.size;
}
@@ -1349,7 +1349,7 @@ static s64 perf_session__process_user_event(struct perf_session *session,
{
struct ordered_events *oe = &session->ordered_events;
struct perf_tool *tool = session->tool;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
int err;
dump_event(session->evlist, event, file_offset, NULL);
@@ -1449,10 +1449,10 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
goto out_parse_sample;
}
- if (perf_data_file__is_pipe(session->file))
+ if (perf_data__is_pipe(session->data))
return -1;
- fd = perf_data_file__fd(session->file);
+ fd = perf_data__fd(session->data);
hdr_sz = sizeof(struct perf_event_header);
if (buf_sz < hdr_sz)
@@ -1687,7 +1687,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
{
struct ordered_events *oe = &session->ordered_events;
struct perf_tool *tool = session->tool;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
union perf_event *event;
uint32_t size, cur_size = 0;
void *buf = NULL;
@@ -1828,7 +1828,7 @@ static int __perf_session__process_events(struct perf_session *session,
{
struct ordered_events *oe = &session->ordered_events;
struct perf_tool *tool = session->tool;
- int fd = perf_data_file__fd(session->file);
+ int fd = perf_data__fd(session->data);
u64 head, page_offset, file_offset, file_pos, size;
int err, mmap_prot, mmap_flags, map_idx = 0;
size_t mmap_size;
@@ -1945,13 +1945,13 @@ out_err:
int perf_session__process_events(struct perf_session *session)
{
- u64 size = perf_data_file__size(session->file);
+ u64 size = perf_data__size(session->data);
int err;
if (perf_session__register_idle_thread(session) < 0)
return -ENOMEM;
- if (!perf_data_file__is_pipe(session->file))
+ if (!perf_data__is_pipe(session->data))
err = __perf_session__process_events(session,
session->header.data_offset,
session->header.data_size, size);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 47b5e7dbcb18..cc1c5ea53c39 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -32,13 +32,13 @@ struct perf_session {
void *one_mmap_addr;
u64 one_mmap_offset;
struct ordered_events ordered_events;
- struct perf_data_file *file;
+ struct perf_data *data;
struct perf_tool *tool;
};
struct perf_tool;
-struct perf_session *perf_session__new(struct perf_data_file *file,
+struct perf_session *perf_session__new(struct perf_data *data,
bool repipe, struct perf_tool *tool);
void perf_session__delete(struct perf_session *session);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index c143c3bc1ef8..ad1b46f1f2cf 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -10,7 +10,7 @@
#include "util/debug.h"
#include "util/callchain.h"
#include "srcline.h"
-
+#include "string2.h"
#include "symbol.h"
bool srcline_full_filename;
@@ -77,6 +77,41 @@ static char *srcline_from_fileline(const char *file, unsigned int line)
return srcline;
}
+static struct symbol *new_inline_sym(struct dso *dso,
+ struct symbol *base_sym,
+ const char *funcname)
+{
+ struct symbol *inline_sym;
+ char *demangled = NULL;
+
+ if (dso) {
+ demangled = dso__demangle_sym(dso, 0, funcname);
+ if (demangled)
+ funcname = demangled;
+ }
+
+ if (base_sym && strcmp(funcname, base_sym->name) == 0) {
+ /* reuse the real, existing symbol */
+ inline_sym = base_sym;
+ /* ensure that we don't alias an inlined symbol, which could
+ * lead to double frees in inline_node__delete
+ */
+ assert(!base_sym->inlined);
+ } else {
+ /* create a fake symbol for the inline frame */
+ inline_sym = symbol__new(base_sym ? base_sym->start : 0,
+ base_sym ? base_sym->end : 0,
+ base_sym ? base_sym->binding : 0,
+ funcname);
+ if (inline_sym)
+ inline_sym->inlined = 1;
+ }
+
+ free(demangled);
+
+ return inline_sym;
+}
+
#ifdef HAVE_LIBBFD_SUPPORT
/*
@@ -219,41 +254,6 @@ static void addr2line_cleanup(struct a2l_data *a2l)
#define MAX_INLINE_NEST 1024
-static struct symbol *new_inline_sym(struct dso *dso,
- struct symbol *base_sym,
- const char *funcname)
-{
- struct symbol *inline_sym;
- char *demangled = NULL;
-
- if (dso) {
- demangled = dso__demangle_sym(dso, 0, funcname);
- if (demangled)
- funcname = demangled;
- }
-
- if (base_sym && strcmp(funcname, base_sym->name) == 0) {
- /* reuse the real, existing symbol */
- inline_sym = base_sym;
- /* ensure that we don't alias an inlined symbol, which could
- * lead to double frees in inline_node__delete
- */
- assert(!base_sym->inlined);
- } else {
- /* create a fake symbol for the inline frame */
- inline_sym = symbol__new(base_sym ? base_sym->start : 0,
- base_sym ? base_sym->end : 0,
- base_sym ? base_sym->binding : 0,
- funcname);
- if (inline_sym)
- inline_sym->inlined = 1;
- }
-
- free(demangled);
-
- return inline_sym;
-}
-
static int inline_list__append_dso_a2l(struct dso *dso,
struct inline_node *node,
struct symbol *sym)
@@ -432,10 +432,11 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
char cmd[PATH_MAX];
struct inline_node *node;
char *filename = NULL;
- size_t len;
+ char *funcname = NULL;
+ size_t filelen, funclen;
unsigned int line_nr = 0;
- scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
+ scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64,
dso_name, addr);
fp = popen(cmd, "r");
@@ -453,23 +454,34 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
INIT_LIST_HEAD(&node->val);
node->addr = addr;
- while (getline(&filename, &len, fp) != -1) {
+ /* addr2line -f generates two lines for each inlined functions */
+ while (getline(&funcname, &funclen, fp) != -1) {
char *srcline;
+ struct symbol *inline_sym;
+
+ rtrim(funcname);
- if (filename_split(filename, &line_nr) != 1) {
- free(filename);
+ if (getline(&filename, &filelen, fp) == -1)
goto out;
- }
- srcline = srcline_from_fileline(filename, line_nr);
- if (inline_list__append(sym, srcline, node) != 0)
+ if (filename_split(filename, &line_nr) != 1)
goto out;
- filename = NULL;
+ srcline = srcline_from_fileline(filename, line_nr);
+ inline_sym = new_inline_sym(dso, sym, funcname);
+
+ if (inline_list__append(inline_sym, srcline, node) != 0) {
+ free(srcline);
+ if (inline_sym && inline_sym->inlined)
+ symbol__delete(inline_sym);
+ goto out;
+ }
}
out:
pclose(fp);
+ free(filename);
+ free(funcname);
return node;
}
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index a2c12d1ef32a..51ad03a799ec 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -178,58 +178,60 @@ void perf_stat__reset_shadow_stats(void)
* more semantic information such as miss/hit ratios,
* instruction rates, etc:
*/
-void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
+void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count,
int cpu)
{
int ctx = evsel_context(counter);
+ count *= counter->scale;
+
if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK) ||
perf_evsel__match(counter, SOFTWARE, SW_CPU_CLOCK))
- update_stats(&runtime_nsecs_stats[cpu], count[0]);
+ update_stats(&runtime_nsecs_stats[cpu], count);
else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
- update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_cycles_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
- update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TRANSACTION_START))
- update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_transaction_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, ELISION_START))
- update_stats(&runtime_elision_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_elision_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS))
- update_stats(&runtime_topdown_total_slots[ctx][cpu], count[0]);
+ update_stats(&runtime_topdown_total_slots[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED))
- update_stats(&runtime_topdown_slots_issued[ctx][cpu], count[0]);
+ update_stats(&runtime_topdown_slots_issued[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED))
- update_stats(&runtime_topdown_slots_retired[ctx][cpu], count[0]);
+ update_stats(&runtime_topdown_slots_retired[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES))
- update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu],count[0]);
+ update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES))
- update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count[0]);
+ update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count);
else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
- update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
- update_stats(&runtime_stalled_cycles_back_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_stalled_cycles_back_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
- update_stats(&runtime_branches_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_branches_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
- update_stats(&runtime_cacherefs_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_cacherefs_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
- update_stats(&runtime_l1_dcache_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_l1_dcache_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
- update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_ll_cache_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
- update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_ll_cache_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
- update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count);
else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
- update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_itlb_cache_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, SMI_NUM))
- update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_smi_num_stats[ctx][cpu], count);
else if (perf_stat_evsel__is(counter, APERF))
- update_stats(&runtime_aperf_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_aperf_stats[ctx][cpu], count);
if (counter->collect_stat) {
struct saved_value *v = saved_value_lookup(counter, cpu, true);
- update_stats(&v->stats, count[0]);
+ update_stats(&v->stats, count);
}
}
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 35e9848734d6..203f5d8d11d1 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -69,7 +69,7 @@ double rel_stddev_stats(double stddev, double avg)
bool __perf_evsel_stat__is(struct perf_evsel *evsel,
enum perf_stat_evsel_id id)
{
- struct perf_stat_evsel *ps = evsel->priv;
+ struct perf_stat_evsel *ps = evsel->stats;
return ps->id == id;
}
@@ -93,7 +93,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
void perf_stat_evsel_id_init(struct perf_evsel *evsel)
{
- struct perf_stat_evsel *ps = evsel->priv;
+ struct perf_stat_evsel *ps = evsel->stats;
int i;
/* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
@@ -109,7 +109,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
{
int i;
- struct perf_stat_evsel *ps = evsel->priv;
+ struct perf_stat_evsel *ps = evsel->stats;
for (i = 0; i < 3; i++)
init_stats(&ps->res_stats[i]);
@@ -119,8 +119,8 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
{
- evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
- if (evsel->priv == NULL)
+ evsel->stats = zalloc(sizeof(struct perf_stat_evsel));
+ if (evsel->stats == NULL)
return -ENOMEM;
perf_evsel__reset_stat_priv(evsel);
return 0;
@@ -128,11 +128,11 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
{
- struct perf_stat_evsel *ps = evsel->priv;
+ struct perf_stat_evsel *ps = evsel->stats;
if (ps)
free(ps->group_data);
- zfree(&evsel->priv);
+ zfree(&evsel->stats);
}
static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
@@ -277,7 +277,9 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel
perf_evsel__compute_deltas(evsel, cpu, thread, count);
perf_counts_values__scale(count, config->scale, NULL);
if (config->aggr_mode == AGGR_NONE)
- perf_stat__update_shadow_stats(evsel, count->values, cpu);
+ perf_stat__update_shadow_stats(evsel, count->val, cpu);
+ if (config->aggr_mode == AGGR_THREAD)
+ perf_stat__update_shadow_stats(evsel, count->val, 0);
break;
case AGGR_GLOBAL:
aggr->val += count->val;
@@ -318,9 +320,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
struct perf_evsel *counter)
{
struct perf_counts_values *aggr = &counter->counts->aggr;
- struct perf_stat_evsel *ps = counter->priv;
+ struct perf_stat_evsel *ps = counter->stats;
u64 *count = counter->counts->aggr.values;
- u64 val;
int i, ret;
aggr->val = aggr->ena = aggr->run = 0;
@@ -360,8 +361,7 @@ int perf_stat_process_counter(struct perf_stat_config *config,
/*
* Save the full runtime - to allow normalization during printout:
*/
- val = counter->scale * *count;
- perf_stat__update_shadow_stats(counter, &val, 0);
+ perf_stat__update_shadow_stats(counter, *count, 0);
return 0;
}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 47915df346fb..490b78aa7230 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -82,7 +82,7 @@ typedef void (*new_line_t )(void *ctx);
void perf_stat__init_shadow_stats(void);
void perf_stat__reset_shadow_stats(void);
-void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
+void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count,
int cpu);
struct perf_stat_output_ctx {
void *ctx;