summaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-inject.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2022-05-20 16:24:02 +0300
committerArnaldo Carvalho de Melo <acme@redhat.com>2022-05-23 10:11:25 -0300
commit180b3d06263ce70dd0622681237cf5c0555d9ca0 (patch)
tree6e88610849ac0c223c75d16b8a75e0e920b42beb /tools/perf/builtin-inject.c
parent618ee7838e409513635320ca9c4c8d52c44f2dd0 (diff)
downloadlinux-180b3d06263ce70dd0622681237cf5c0555d9ca0.tar.bz2
perf inject: Keep some features sections from input file
perf inject overwrites feature sections with information from the current machine. It makes more sense to keep original information that describes the machine or software when perf record was run. Example: perf.data from "Desktop" injected on "nuc11" Before: $ perf script --header-only -i perf.data-from-desktop | head -15 # ======== # captured on : Thu May 19 09:55:50 2022 # header version : 1 # data offset : 1208 # data size : 837480 # feat offset : 838688 # hostname : Desktop # os release : 5.13.0-41-generic # perf version : 5.18.rc5.gac837f7ca7ed # arch : x86_64 # nrcpus online : 28 # nrcpus avail : 28 # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz # cpuid : GenuineIntel,6,85,4 # total memory : 65548656 kB $ perf inject -i perf.data-from-desktop -o injected-perf.data $ perf script --header-only -i injected-perf.data | head -15 # ======== # captured on : Fri May 20 15:06:55 2022 # header version : 1 # data offset : 1208 # data size : 837480 # feat offset : 838688 # hostname : nuc11 # os release : 5.17.5-local # perf version : 5.18.rc5.g0f828fdeb9af # arch : x86_64 # nrcpus online : 8 # nrcpus avail : 8 # cpudesc : 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz # cpuid : GenuineIntel,6,140,1 # total memory : 16012124 kB After: $ perf inject -i perf.data-from-desktop -o injected-perf.data $ perf script --header-only -i injected-perf.data | head -15 # ======== # captured on : Fri May 20 15:08:54 2022 # header version : 1 # data offset : 1208 # data size : 837480 # feat offset : 838688 # hostname : Desktop # os release : 5.13.0-41-generic # perf version : 5.18.rc5.gac837f7ca7ed # arch : x86_64 # nrcpus online : 28 # nrcpus avail : 28 # cpudesc : Intel(R) Core(TM) i9-9940X CPU @ 3.30GHz # cpuid : GenuineIntel,6,85,4 # total memory : 65548656 kB Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: https://lore.kernel.org/r/20220520132404.25853-4-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-inject.c')
-rw-r--r--tools/perf/builtin-inject.c129
1 files changed, 128 insertions, 1 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5b50a4abf95f..71b6eafe4c19 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -27,6 +27,8 @@
#include "util/namespaces.h"
#include "util/util.h"
+#include <internal/lib.h>
+
#include <linux/err.h>
#include <subcmd/parse-options.h>
#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
@@ -55,6 +57,7 @@ struct perf_inject {
struct list_head samples;
struct itrace_synth_opts itrace_synth_opts;
char event_copy[PERF_SAMPLE_MAX_SIZE];
+ struct perf_file_section secs[HEADER_FEAT_BITS];
};
struct event_entry {
@@ -763,6 +766,120 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
}
+static int save_section_info_cb(struct perf_file_section *section,
+ struct perf_header *ph __maybe_unused,
+ int feat, int fd __maybe_unused, void *data)
+{
+ struct perf_inject *inject = data;
+
+ inject->secs[feat] = *section;
+ return 0;
+}
+
+static int save_section_info(struct perf_inject *inject)
+{
+ struct perf_header *header = &inject->session->header;
+ int fd = perf_data__fd(inject->session->data);
+
+ return perf_header__process_sections(header, fd, inject, save_section_info_cb);
+}
+
+static bool keep_feat(int feat)
+{
+ switch (feat) {
+ /* Keep original information that describes the machine or software */
+ case HEADER_TRACING_DATA:
+ case HEADER_HOSTNAME:
+ case HEADER_OSRELEASE:
+ case HEADER_VERSION:
+ case HEADER_ARCH:
+ case HEADER_NRCPUS:
+ case HEADER_CPUDESC:
+ case HEADER_CPUID:
+ case HEADER_TOTAL_MEM:
+ case HEADER_CPU_TOPOLOGY:
+ case HEADER_NUMA_TOPOLOGY:
+ case HEADER_PMU_MAPPINGS:
+ case HEADER_CACHE:
+ case HEADER_MEM_TOPOLOGY:
+ case HEADER_CLOCKID:
+ case HEADER_BPF_PROG_INFO:
+ case HEADER_BPF_BTF:
+ case HEADER_CPU_PMU_CAPS:
+ case HEADER_CLOCK_DATA:
+ case HEADER_HYBRID_TOPOLOGY:
+ case HEADER_HYBRID_CPU_PMU_CAPS:
+ return true;
+ /* Information that can be updated */
+ case HEADER_BUILD_ID:
+ case HEADER_CMDLINE:
+ case HEADER_EVENT_DESC:
+ case HEADER_BRANCH_STACK:
+ case HEADER_GROUP_DESC:
+ case HEADER_AUXTRACE:
+ case HEADER_STAT:
+ case HEADER_SAMPLE_TIME:
+ case HEADER_DIR_FORMAT:
+ case HEADER_COMPRESSED:
+ default:
+ return false;
+ };
+}
+
+static int read_file(int fd, u64 offs, void *buf, size_t sz)
+{
+ ssize_t ret = preadn(fd, buf, sz, offs);
+
+ if (ret < 0)
+ return -errno;
+ if ((size_t)ret != sz)
+ return -EINVAL;
+ return 0;
+}
+
+static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw)
+{
+ int fd = perf_data__fd(inject->session->data);
+ u64 offs = inject->secs[feat].offset;
+ size_t sz = inject->secs[feat].size;
+ void *buf = malloc(sz);
+ int ret;
+
+ if (!buf)
+ return -ENOMEM;
+
+ ret = read_file(fd, offs, buf, sz);
+ if (ret)
+ goto out_free;
+
+ ret = fw->write(fw, buf, sz);
+out_free:
+ free(buf);
+ return ret;
+}
+
+struct inject_fc {
+ struct feat_copier fc;
+ struct perf_inject *inject;
+};
+
+static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw)
+{
+ struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc);
+ struct perf_inject *inject = inj_fc->inject;
+ int ret;
+
+ if (!inject->secs[feat].offset ||
+ !keep_feat(feat))
+ return 0;
+
+ ret = feat_copy(inject, feat, fw);
+ if (ret < 0)
+ return ret;
+
+ return 1; /* Feature section copied */
+}
+
static int output_fd(struct perf_inject *inject)
{
return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
@@ -848,6 +965,11 @@ static int __cmd_inject(struct perf_inject *inject)
return ret;
if (!inject->is_pipe && !inject->in_place_update) {
+ struct inject_fc inj_fc = {
+ .fc.copy = feat_copy_cb,
+ .inject = inject,
+ };
+
if (inject->build_ids)
perf_header__set_feat(&session->header,
HEADER_BUILD_ID);
@@ -872,7 +994,7 @@ static int __cmd_inject(struct perf_inject *inject)
}
session->header.data_offset = output_data_offset;
session->header.data_size = inject->bytes_written;
- perf_session__write_header(session, session->evlist, fd, true);
+ perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
}
return ret;
@@ -1037,6 +1159,11 @@ int cmd_inject(int argc, const char **argv)
if (zstd_init(&(inject.session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed.\n");
+ /* Save original section info before feature bits change */
+ ret = save_section_info(&inject);
+ if (ret)
+ goto out_delete;
+
if (!data.is_pipe && inject.output.is_pipe) {
ret = perf_header__write_pipe(perf_data__fd(&inject.output));
if (ret < 0) {