Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
180b3d06 618ee783

+141 -1
+128 -1
tools/perf/builtin-inject.c
··· 27 27 #include "util/namespaces.h" 28 28 #include "util/util.h" 29 29 30 + #include <internal/lib.h> 31 + 30 32 #include <linux/err.h> 31 33 #include <subcmd/parse-options.h> 32 34 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ ··· 57 55 struct list_head samples; 58 56 struct itrace_synth_opts itrace_synth_opts; 59 57 char event_copy[PERF_SAMPLE_MAX_SIZE]; 58 + struct perf_file_section secs[HEADER_FEAT_BITS]; 60 59 }; 61 60 62 61 struct event_entry { ··· 766 763 return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM; 767 764 } 768 765 766 + static int save_section_info_cb(struct perf_file_section *section, 767 + struct perf_header *ph __maybe_unused, 768 + int feat, int fd __maybe_unused, void *data) 769 + { 770 + struct perf_inject *inject = data; 771 + 772 + inject->secs[feat] = *section; 773 + return 0; 774 + } 775 + 776 + static int save_section_info(struct perf_inject *inject) 777 + { 778 + struct perf_header *header = &inject->session->header; 779 + int fd = perf_data__fd(inject->session->data); 780 + 781 + return perf_header__process_sections(header, fd, inject, save_section_info_cb); 782 + } 783 + 784 + static bool keep_feat(int feat) 785 + { 786 + switch (feat) { 787 + /* Keep original information that describes the machine or software */ 788 + case HEADER_TRACING_DATA: 789 + case HEADER_HOSTNAME: 790 + case HEADER_OSRELEASE: 791 + case HEADER_VERSION: 792 + case HEADER_ARCH: 793 + case HEADER_NRCPUS: 794 + case HEADER_CPUDESC: 795 + case HEADER_CPUID: 796 + case HEADER_TOTAL_MEM: 797 + case HEADER_CPU_TOPOLOGY: 798 + case HEADER_NUMA_TOPOLOGY: 799 + case HEADER_PMU_MAPPINGS: 800 + case HEADER_CACHE: 801 + case HEADER_MEM_TOPOLOGY: 802 + case HEADER_CLOCKID: 803 + case HEADER_BPF_PROG_INFO: 804 + case HEADER_BPF_BTF: 805 + case HEADER_CPU_PMU_CAPS: 806 + case HEADER_CLOCK_DATA: 807 + case HEADER_HYBRID_TOPOLOGY: 808 + case HEADER_HYBRID_CPU_PMU_CAPS: 809 + return true; 810 + /* Information that can be updated */ 811 + case HEADER_BUILD_ID: 812 + case HEADER_CMDLINE: 813 + case HEADER_EVENT_DESC: 814 + case HEADER_BRANCH_STACK: 815 + case HEADER_GROUP_DESC: 816 + case HEADER_AUXTRACE: 817 + case HEADER_STAT: 818 + case HEADER_SAMPLE_TIME: 819 + case HEADER_DIR_FORMAT: 820 + case HEADER_COMPRESSED: 821 + default: 822 + return false; 823 + }; 824 + } 825 + 826 + static int read_file(int fd, u64 offs, void *buf, size_t sz) 827 + { 828 + ssize_t ret = preadn(fd, buf, sz, offs); 829 + 830 + if (ret < 0) 831 + return -errno; 832 + if ((size_t)ret != sz) 833 + return -EINVAL; 834 + return 0; 835 + } 836 + 837 + static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw) 838 + { 839 + int fd = perf_data__fd(inject->session->data); 840 + u64 offs = inject->secs[feat].offset; 841 + size_t sz = inject->secs[feat].size; 842 + void *buf = malloc(sz); 843 + int ret; 844 + 845 + if (!buf) 846 + return -ENOMEM; 847 + 848 + ret = read_file(fd, offs, buf, sz); 849 + if (ret) 850 + goto out_free; 851 + 852 + ret = fw->write(fw, buf, sz); 853 + out_free: 854 + free(buf); 855 + return ret; 856 + } 857 + 858 + struct inject_fc { 859 + struct feat_copier fc; 860 + struct perf_inject *inject; 861 + }; 862 + 863 + static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw) 864 + { 865 + struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc); 866 + struct perf_inject *inject = inj_fc->inject; 867 + int ret; 868 + 869 + if (!inject->secs[feat].offset || 870 + !keep_feat(feat)) 871 + return 0; 872 + 873 + ret = feat_copy(inject, feat, fw); 874 + if (ret < 0) 875 + return ret; 876 + 877 + return 1; /* Feature section copied */ 878 + } 879 + 769 880 static int output_fd(struct perf_inject *inject) 770 881 { 771 882 return inject->in_place_update ? -1 : perf_data__fd(&inject->output); ··· 965 848 return ret; 966 849 967 850 if (!inject->is_pipe && !inject->in_place_update) { 851 + struct inject_fc inj_fc = { 852 + .fc.copy = feat_copy_cb, 853 + .inject = inject, 854 + }; 855 + 968 856 if (inject->build_ids) 969 857 perf_header__set_feat(&session->header, 970 858 HEADER_BUILD_ID); ··· 994 872 } 995 873 session->header.data_offset = output_data_offset; 996 874 session->header.data_size = inject->bytes_written; 997 - perf_session__write_header(session, session->evlist, fd, true); 875 + perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc); 998 876 } 999 877 1000 878 return ret; ··· 1158 1036 1159 1037 if (zstd_init(&(inject.session->zstd_data), 0) < 0) 1160 1038 pr_warning("Decompression initialization failed.\n"); 1039 + 1040 + /* Save original section info before feature bits change */ 1041 + ret = save_section_info(&inject); 1042 + if (ret) 1043 + goto out_delete; 1161 1044 1162 1045 if (!data.is_pipe && inject.output.is_pipe) { 1163 1046 ret = perf_header__write_pipe(perf_data__fd(&inject.output));
+8
tools/perf/util/header.c
··· 3686 3686 return perf_session__do_write_header(session, evlist, fd, at_exit, NULL); 3687 3687 } 3688 3688 3689 + int perf_session__inject_header(struct perf_session *session, 3690 + struct evlist *evlist, 3691 + int fd, 3692 + struct feat_copier *fc) 3693 + { 3694 + return perf_session__do_write_header(session, evlist, fd, true, fc); 3695 + } 3696 + 3689 3697 static int perf_header__getbuffer64(struct perf_header *header, 3690 3698 int fd, void *buf, size_t size) 3691 3699 {
+5
tools/perf/util/header.h
··· 131 131 int (*copy)(struct feat_copier *fc, int feat, struct feat_writer *fw); 132 132 }; 133 133 134 + int perf_session__inject_header(struct perf_session *session, 135 + struct evlist *evlist, 136 + int fd, 137 + struct feat_copier *fc); 138 + 134 139 void perf_header__set_feat(struct perf_header *header, int feat); 135 140 void perf_header__clear_feat(struct perf_header *header, int feat); 136 141 bool perf_header__has_feat(const struct perf_header *header, int feat);