perf/core improvements
Arnaldo Carvalho de Melo
maintainerHi Ingo,
Please consider pulling,
- Arnaldo
Test results at the end of this message, as usual.
The following changes since commit 2996123e7e589d78e73cfeb7e7f14d49127eb1b0:
Merge tag 'perf-core-for-mingo-4.18-20180519' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (2018-05-19 13:32:53 +0200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo-4.18-20180523
for you to fetch changes up to 22916fdb9c50e8fb303bdcedca88fd8798a85844:
perf kcore_copy: Amend the offset of sections that remap kernel text (2018-05-23 10:26:44 -0300)
----------------------------------------------------------------
perf/core improvements:
. Create extra kernel maps to help in decoding samples in x86 PTI entry
trampolines (Adrian Hunter)
. Copy x86 PTI entry trampoline sections in the kcore copy used for
annotation and intel_pt CPU traces decoding (Adrian Hunter)
- Support 'perf annotate --group' for non-explicit recorded event "groups", showing multiple columns, one for each event, just like when dealing with explicit event groups (those enclosed with {}) (Jin Yao)
----------------------------------------------------------------
Adrian Hunter (14):
perf machine: Add nr_cpus_avail()
perf machine: Workaround missing maps for x86 PTI entry trampolines perf machine: Fix map_groups__split_kallsyms() for entry trampoline symbols perf machine: Allow for extra kernel maps
perf machine: Create maps for x86 PTI entry trampolines
perf machine: Synthesize and process mmap events for x86 PTI entry trampolines perf kcore_copy: Keep phdr data in a list
perf kcore_copy: Keep a count of phdrs
perf kcore_copy: Calculate offset from phnum
perf kcore_copy: Layout sections
perf kcore_copy: Iterate phdrs
perf kcore_copy: Get rid of kernel_map
perf kcore_copy: Copy x86 PTI entry trampoline sections
perf kcore_copy: Amend the offset of sections that remap kernel text
Jin Yao (4):
perf evlist: Introduce force_leader() method
perf report: Use perf_evlist__force_leader to support '--group' perf annotate: Support '--group' option
perf annotate: Show group event string for stdio
tools/perf/arch/x86/util/Build | 2 + tools/perf/arch/x86/util/event.c | 76 +++++++++++++ tools/perf/arch/x86/util/machine.c | 103 +++++++++++++++++ tools/perf/builtin-annotate.c | 7 ++ tools/perf/builtin-report.c | 13 +-- tools/perf/util/annotate.c | 6 +- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 1 + tools/perf/util/event.c | 36 ++++-- tools/perf/util/event.h | 8 ++ tools/perf/util/evlist.c | 15 +++ tools/perf/util/evlist.h | 3 + tools/perf/util/machine.c | 175 +++++++++++++++++++++++++++-- tools/perf/util/machine.h | 23 ++++ tools/perf/util/map.c | 22 +++- tools/perf/util/map.h | 15 ++- tools/perf/util/symbol-elf.c | 219 +++++++++++++++++++++++++++++++------ tools/perf/util/symbol.c | 49 +++++++-- 18 files changed, 711 insertions(+), 75 deletions(-) create mode 100644 tools/perf/arch/x86/util/event.c create mode 100644 tools/perf/arch/x86/util/machine.c
Test results:
The first ones are container (docker) based builds of tools/perf with and without libelf support. Where clang is available, it is also used to build perf with/without libelf, and building with LIBCLANGLLVM=1 (built-in clang) with gcc and clang when clang and its devel libraries are installed.
The objtool and samples/bpf/ builds are disabled now that I'm switching from using the sources in a local volume to fetching them from a http server to build it inside the container, to make it easier to build in a container cluster. Those will come back later.
Several are cross builds, the ones with -x-ARCH and the android one, and those may not have all the features built, due to lack of multi-arch devel packages, available and being used so far on just a few, like debian:experimental-x-{arm64,mipsel}.
The 'perf test' one will perform a variety of tests exercising tools/perf/util/, tools/lib/{bpf,traceevent,etc}, as well as run perf commands with a variety of command line event specifications to then intercept the sys_perf_event syscall to check that the perf_event_attr fields are set up as expected, among a variety of other unit tests.
Then there is the 'make -C tools/perf build-test' ones, that build tools/perf/ with a variety of feature sets, exercising the build with an incomplete set of features as well as with a complete one. It is planned to have it run on each of the containers mentioned above, using some container orchestration infrastructure. Get in contact if interested in helping having this in place.
# dm 1 alpine:3.4 : Ok gcc (Alpine 5.3.0) 5.3.0 2 alpine:3.5 : Ok gcc (Alpine 6.2.1) 6.2.1 20160822 3 alpine:3.6 : Ok gcc (Alpine 6.3.0) 6.3.0 4 alpine:3.7 : Ok gcc (Alpine 6.4.0) 6.4.0 5 alpine:edge : Ok gcc (Alpine 6.4.0) 6.4.0 6 amazonlinux:1 : Ok gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) 7 amazonlinux:2 : Ok gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5) 8 android-ndk:r12b-arm : Ok arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease) 9 android-ndk:r15c-arm : Ok arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease) 10 centos:5 : Ok gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-55) 11 centos:6 : Ok gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18) 12 centos:7 : Ok gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16) 13 debian:7 : Ok gcc (Debian 4.7.2-5) 4.7.2 14 debian:8 : Ok gcc (Debian 4.9.2-10+deb8u1) 4.9.2 15 debian:9 : Ok gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 16 debian:experimental : Ok gcc (Debian 7.3.0-19) 7.3.0 17 debian:experimental-x-arm64 : Ok aarch64-linux-gnu-gcc (Debian 7.3.0-19) 7.3.0 18 debian:experimental-x-mips : Ok mips-linux-gnu-gcc (Debian 7.3.0-19) 7.3.0 19 debian:experimental-x-mips64 : Ok mips64-linux-gnuabi64-gcc (Debian 7.3.0-18) 7.3.0 20 debian:experimental-x-mipsel : Ok mipsel-linux-gnu-gcc (Debian 7.3.0-19) 7.3.0 21 fedora:20 : Ok gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7) 22 fedora:21 : Ok gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6) 23 fedora:22 : Ok gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6) 24 fedora:23 : Ok gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6) 25 fedora:24 : Ok gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1) 26 fedora:24-x-ARC-uClibc : Ok arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710 27 fedora:25 : Ok gcc (GCC) 6.4.1 20170727 (Red Hat 6.4.1-1) 28 fedora:26 : Ok gcc (GCC) 7.3.1 20180130 (Red Hat 7.3.1-2) 29 fedora:27 : Ok gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5) 30 fedora:28 : Ok gcc (GCC) 8.1.1 20180502 (Red Hat 8.1.1-1) 31 fedora:rawhide : Ok gcc (GCC) 8.0.1 20180324 (Red Hat 8.0.1-0.20) 32 gentoo-stage3-amd64:latest : Ok gcc (Gentoo 6.4.0-r1 p1.3) 6.4.0 33 mageia:5 : Ok gcc (GCC) 4.9.2 34 mageia:6 : Ok gcc (Mageia 5.5.0-1.mga6) 5.5.0 35 opensuse:42.1 : Ok gcc (SUSE Linux) 4.8.5 36 opensuse:42.2 : Ok gcc (SUSE Linux) 4.8.5 37 opensuse:42.3 : Ok gcc (SUSE Linux) 4.8.5 38 opensuse:tumbleweed : Ok gcc (SUSE Linux) 7.3.1 20180323 [gcc-7-branch revision 258812] 39 oraclelinux:6 : Ok gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18.0.7) 40 oraclelinux:7 : Ok gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28.0.1) 41 ubuntu:12.04.5 : Ok gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 42 ubuntu:14.04.4 : Ok gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 43 ubuntu:14.04.4-x-linaro-arm64 : Ok aarch64-linux-gnu-gcc (Linaro GCC 5.5-2017.10) 5.5.0 44 ubuntu:16.04 : Ok gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 45 ubuntu:16.04-x-arm : Ok arm-linux-gnueabihf-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 46 ubuntu:16.04-x-arm64 : Ok aarch64-linux-gnu-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 47 ubuntu:16.04-x-powerpc : Ok powerpc-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 48 ubuntu:16.04-x-powerpc64 : Ok powerpc64-linux-gnu-gcc (Ubuntu/IBM 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 49 ubuntu:16.04-x-powerpc64el : Ok powerpc64le-linux-gnu-gcc (Ubuntu/IBM 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 50 ubuntu:16.04-x-s390 : Ok s390x-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609 51 ubuntu:16.10 : Ok gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005 52 ubuntu:17.04 : Ok gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406 53 ubuntu:17.10 : Ok gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0 54 ubuntu:18.04 : Ok gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0 #
# uname -a Linux seventh 4.17.0-rc6-00152-ga048a07d7f45 #3 SMP Wed May 23 11:43:04 -03 2018 x86_64 x86_64 x86_64 GNU/Linux # perf --version perf version 4.17.rc5.g22916fd # git log --oneline -1 22916fdb9c50 (HEAD -> perf/core, jouet/perf/core) perf kcore_copy: Amend the offset of sections that remap kernel text # perf test 1: vmlinux symtab matches kallsyms : Ok 2: Detect openat syscall event : Ok 3: Detect openat syscall event on all cpus : Ok 4: Read samples using the mmap interface : Ok 5: Test data source output : Ok 6: Parse event definition strings : Ok 7: Simple expression parser : Ok 8: PERF_RECORD_* events & perf_sample fields : Ok 9: Parse perf pmu format : Ok 10: DSO data read : Ok 11: DSO data cache : Ok 12: DSO data reopen : Ok 13: Roundtrip evsel->name : Ok 14: Parse sched tracepoints fields : Ok 15: syscalls:sys_enter_openat event fields : Ok 16: Setup struct perf_event_attr : Ok 17: Match and link multiple hists : Ok 18: 'import perf' in python : Ok 19: Breakpoint overflow signal handler : Ok 20: Breakpoint overflow sampling : Ok 21: Breakpoint accounting : Ok 22: Number of exit events of a simple workload : Ok 23: Software clock events period values : Ok 24: Object code reading : FAILED! 25: Sample parsing : Ok 26: Use a dummy software event to keep tracking : Ok 27: Parse with no sample_id_all bit set : Ok 28: Filter hist entries : Ok 29: Lookup mmap thread : Ok 30: Share thread mg : Ok 31: Sort output of hist entries : Ok 32: Cumulate child hist entries : Ok 33: Track with sched_switch : Ok 34: Filter fds with revents mask in a fdarray : Ok 35: Add fd to a fdarray, making it autogrow : Ok 36: kmod_path__parse : Ok 37: Thread map : Ok 38: LLVM search and compile : 38.1: Basic BPF llvm compile : Ok 38.2: kbuild searching : Ok 38.3: Compile source for BPF prologue generation : Ok 38.4: Compile source for BPF relocation : Ok 39: Session topology : Ok 40: BPF filter : 40.1: Basic BPF filtering : Ok 40.2: BPF pinning : Ok 40.3: BPF prologue generation : Ok 40.4: BPF relocation checker : Ok 41: Synthesize thread map : Ok 42: Remove thread map : Ok 43: Synthesize cpu map : Ok 44: Synthesize stat config : Ok 45: Synthesize stat : Ok 46: Synthesize stat round : Ok 47: Synthesize attr update : Ok 48: Event times : Ok 49: Read backward ring buffer : Ok 50: Print cpu map : Ok 51: Probe SDT events : Ok 52: is_printable_array : Ok 53: Print bitmap : Ok 54: perf hooks : Ok 55: builtin clang support : Skip (not compiled in) 56: unit_number__scnprintf : Ok 57: mem2node : Ok 58: x86 rdpmc : Ok 59: Convert perf time to TSC : Ok 60: DWARF unwind : Ok 61: x86 instruction decoder - new instructions : Ok 62: Use vfs_getname probe to get syscall args filenames : Ok 63: Check open filename arg using perf trace + vfs_getname: Ok 64: probe libc's inet_pton & backtrace it with ping : Ok 65: Add vfs_getname probe to get syscall args filenames : Ok #
$ make -C tools/perf build-test
make: Entering directory '/home/acme/git/perf/tools/perf'
- tarpkg: ./tests/perf-targz-src-pkg .
make_perf_o_O: make perf.o
make_no_libunwind_O: make NO_LIBUNWIND=1
make_help_O: make help
make_debug_O: make DEBUG=1
make_no_libbpf_O: make NO_LIBBPF=1
make_no_auxtrace_O: make NO_AUXTRACE=1
make_no_libperl_O: make NO_LIBPERL=1
make_no_newt_O: make NO_NEWT=1
make_doc_O: make doc
make_with_babeltrace_O: make LIBBABELTRACE=1
make_minimal_O: make NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1
make_with_clangllvm_O: make LIBCLANGLLVM=1
make_tags_O: make tags
make_install_prefix_slash_O: make install prefix=/tmp/krava/
make_clean_all_O: make clean all
make_no_demangle_O: make NO_DEMANGLE=1
make_no_scripts_O: make NO_LIBPYTHON=1 NO_LIBPERL=1
make_util_map_o_O: make util/map.o
make_no_libaudit_O: make NO_LIBAUDIT=1
make_cscope_O: make cscope
make_no_gtk2_O: make NO_GTK2=1
make_no_ui_O: make NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
make_no_libpython_O: make NO_LIBPYTHON=1
make_no_libbionic_O: make NO_LIBBIONIC=1
make_install_O: make install
make_no_libnuma_O: make NO_LIBNUMA=1
make_static_O: make LDFLAGS=-static
make_install_prefix_O: make install prefix=/tmp/krava
make_no_libelf_O: make NO_LIBELF=1
make_util_pmu_bison_o_O: make util/pmu-bison.o
make_no_libdw_dwarf_unwind_O: make NO_LIBDW_DWARF_UNWIND=1
make_install_bin_O: make install-bin
make_pure_O: make
make_no_backtrace_O: make NO_BACKTRACE=1
make_no_slang_O: make NO_SLANG=1
OK
make: Leaving directory '/home/acme/git/perf/tools/perf'
$Arnaldo Carvalho de Melo
maintainerPATCH 1/18 perf evlist: Introduce force_leader() method
From: Jin Yao <[email protected]>
For non-explicit group (e.g. those created with -e '{eventA,eventB}'), 'perf report' supports a option '--group' which can enable group output.
We also need to support 'perf annotate' with the same '--group'.
Create a new function perf_evlist__force_leader() which contains common code to force setting the group leader.
--- tools/perf/util/evlist.c | 15 +++++++++++++++ tools/perf/util/evlist.h | 3 +++ 2 files changed, 18 insertions(+)
tools/perf/util/evlist.c +15 -0
@@ -1795,3 +1795,18 @@ bool perf_evlist__exclude_kernel(struct perf_evlist *evlist)return true; } + +/* +* Events in data file are not collect in groups, but we still want +* the group display. Set the artificial group and set the leader's +* forced_leader flag to notify the display code. +*/ +void perf_evlist__force_leader (struct perf_evlist *evlist) +{ +if (!evlist->nr_groups) { +struct perf_evsel *leader =perf_evlist__first (evlist); + +perf_evlist__set_leader (evlist); + leader->forced_leader = true; + } +}
tools/perf/util/evlist.h +3 -0
@@ -309,4 +309,7 @@ struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *event);bool perf_evlist__exclude_kernel (struct perf_evlist *evlist); + +void perf_evlist__force_leader (struct perf_evlist *evlist); +#endif /* __PERF_EVLIST_H */
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 2/18 perf report: Use perf_evlist__force_leader to support '--group'
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Since we created a new function perf_evlist__force_leader(), remove the old code and use that new evlist method.
--- tools/perf/builtin-report.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
tools/perf/builtin-report.c +2 -11
@@ -194,20 +194,11 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter,return err; } -/* -* Events in data file are not collect in groups, but we still want -* the group display. Set the artificial group and set the leader's -* forced_leader flag to notify the display code. -*/ static void setup_forced_leader (struct report *report,struct perf_evlist *evlist) { -if (report->group_set && !evlist->nr_groups) { -struct perf_evsel *leader =perf_evlist__first (evlist); - -perf_evlist__set_leader (evlist); - leader->forced_leader = true; - } +if (report->group_set) +perf_evlist__force_leader (evlist); } static int process_feature_event(struct perf_tool *tool,
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 3/18 perf annotate: Support '--group' option
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
With the '--group' option, even for non-explicit group, 'perf annotate' will enable the group output.
For example,
$ perf record -e cycles,branches ./div $ perf annotate main --stdio --group
: Disassembly of section .text:
:
: 00000000004004b0 <main>:
: main():
:
: return i;
: }
:
: int main(void)
: {
0.00 0.00 : 4004b0: push %rbx
: int i;
: int flag;
: volatile double x = 1212121212, y = 121212;
:
: s_randseed = time(0);
0.00 0.00 : 4004b1: xor %edi,%edi
: srand(s_randseed);
0.00 0.00 : 4004b3: mov $0x77359400,%ebx
:
: return i;
: }
:But if without --group, there is only one event reported.
$ perf annotate main --stdio
: Disassembly of section .text:
:
: 00000000004004b0 <main>:
: main():
:
: return i;
: }
:
: int main(void)
: {
0.00 : 4004b0: push %rbx
: int i;
: int flag;
: volatile double x = 1212121212, y = 121212;
:
: s_randseed = time(0);
0.00 : 4004b1: xor %edi,%edi
: srand(s_randseed);
0.00 : 4004b3: mov $0x77359400,%ebx
:
: return i;
: }--- tools/perf/builtin-annotate.c | 7 +++++++ 1 file changed, 7 insertions(+)
tools/perf/builtin-annotate.c +7 -0
@@ -45,6 +45,7 @@ struct perf_annotate {bool print_line;bool skip_missing;bool has_br_stack; +bool group_set;const char *sym_hist_filter;const char *cpu_list;DECLARE_BITMAP (cpu_bitmap,MAX_NR_CPUS );
@@ -508,6 +509,9 @@ int cmd_annotate(int argc, const char **argv) "Don't shorten the displayed pathnames"),OPT_BOOLEAN (0 ,"skip-missing" , &annotate.skip_missing,"Skip symbols that cannot be annotated" ), +OPT_BOOLEAN_SET (0 ,"group" , &symbol_conf.event_group, + &annotate.group_set, +"Show event group information together" ),OPT_STRING ('C' ,"cpu" , &annotate.cpu_list,"cpu" ,"list of cpus to profile" ), OPT_CALLBACK(0, "symfs", NULL, "directory", "Look for files with symbols relative to this directory",
@@ -570,6 +574,9 @@ int cmd_annotate(int argc, const char **argv) annotate.has_br_stack =perf_header__has_feat (&annotate.session->header,HEADER_BRANCH_STACK ); +if (annotate.group_set) +perf_evlist__force_leader (annotate.session->evlist); + ret =symbol__annotation_init ();if (ret <0 ) goto out_delete;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 4/18 perf machine: Add nr_cpus_avail()
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Add a function to return the number of the machine's available CPUs.
--- tools/perf/util/env.c | 13 +++++++++++++ tools/perf/util/env.h | 1 + tools/perf/util/machine.c | 5 +++++ tools/perf/util/machine.h | 1 + 4 files changed, 20 insertions(+)
tools/perf/util/env.c +13 -0
@@ -106,11 +106,24 @@ static int perf_env__read_arch(struct perf_env *env)return env->arch ?0 : -ENOMEM ; } +static int perf_env__read_nr_cpus_avail (struct perf_env *env) +{ +if (env->nr_cpus_avail ==0 ) + env->nr_cpus_avail =cpu__max_present_cpu (); + +return env->nr_cpus_avail ?0 : -ENOENT ; +} +const char *perf_env__raw_arch (struct perf_env *env) {return env && !perf_env__read_arch (env) ? env->arch :"unknown" ; } +int perf_env__nr_cpus_avail (struct perf_env *env) +{ +return env && !perf_env__read_nr_cpus_avail (env) ? env->nr_cpus_avail :0 ; +} +void cpu_cache_level__free (struct cpu_cache_level *cache) {free (cache->type);
tools/perf/util/env.h +1 -0
@@ -77,5 +77,6 @@ void cpu_cache_level__free(struct cpu_cache_level *cache);const char *perf_env__arch (struct perf_env *env);const char *perf_env__raw_arch (struct perf_env *env); +int perf_env__nr_cpus_avail (struct perf_env *env);#endif /* __PERF_ENV_H */
tools/perf/util/machine.c +5 -0
@@ -2305,6 +2305,11 @@ bool machine__is(struct machine *machine, const char *arch)return machine && !strcmp (perf_env__raw_arch (machine->env), arch); } +int machine__nr_cpus_avail (struct machine *machine) +{ +return machine ?perf_env__nr_cpus_avail (machine->env) :0 ; +} +int machine__get_kernel_start (struct machine *machine) {struct map *map =machine__kernel_map (machine);
tools/perf/util/machine.h +1 -0
@@ -189,6 +189,7 @@ static inline bool machine__is_host(struct machine *machine) }bool machine__is (struct machine *machine,const char *arch); +int machine__nr_cpus_avail (struct machine *machine);struct thread *__machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid);struct thread *machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid);
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 5/18 perf machine: Workaround missing maps for x86 PTI entry trampolines
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
On x86_64 the PTI entry trampolines are not in the kernel map created by perf tools. That results in the addresses having no symbols and prevents annotation. It also causes Intel PT to have decoding errors at the trampoline addresses.
Workaround that by creating maps for the trampolines.
At present the kernel does not export information revealing where the trampolines are. Until that happens, the addresses are hardcoded.
--- tools/perf/util/machine.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 3 ++ tools/perf/util/symbol.c | 12 +++--- 3 files changed, 106 insertions(+), 5 deletions(-)
tools/perf/util/machine.c +96 -0
@@ -851,6 +851,102 @@ static int machine__get_running_kernel_start(struct machine *machine,return 0 ; } +/* Kernel-space maps for symbols that are outside the main kernel map and module maps */ +struct extra_kernel_map { +u64 start; +u64 end; +u64 pgoff; +}; + +static int machine__create_extra_kernel_map (struct machine *machine, +struct dso *kernel, +struct extra_kernel_map *xm) +{ +struct kmap *kmap; +struct map *map; + + map =map__new2 (xm->start, kernel); +if (!map) +return -1 ; + + map->end = xm->end; + map->pgoff = xm->pgoff; + + kmap =map__kmap (map); + + kmap->kmaps = &machine->kmaps; + +map_groups__insert (&machine->kmaps, map); + +pr_debug2 ("Added extra kernel map %" PRIx64"-%" PRIx64"\n" , + map->start, map->end); + +map__put (map); + +return 0 ; +} + +static u64 find_entry_trampoline (struct dso *dso) +{ +/* Duplicates are removed so lookup all aliases */ +const char *syms[] = { +"_entry_trampoline" , +"__entry_trampoline_start" , +"entry_SYSCALL_64_trampoline" , + }; +struct symbol *sym =dso__first_symbol (dso); +unsigned int i; + +for (; sym; sym =dso__next_symbol (sym)) { +if (sym->binding !=STB_GLOBAL ) +continue ; +for (i =0 ; i <ARRAY_SIZE (syms); i++) { +if (!strcmp (sym->name, syms[i])) +return sym->start; + } + } + +return 0 ; +} + +/* +* These values can be used for kernels that do not have symbols for the entry +* trampolines in kallsyms. +*/ +#define X86_64_CPU_ENTRY_AREA_PER_CPU 0xfffffe0000000000ULL +#define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000 +#define X86_64_ENTRY_TRAMPOLINE 0x6000 + +/* Map x86_64 PTI entry trampolines */ +int machine__map_x86_64_entry_trampolines (struct machine *machine, +struct dso *kernel) +{ +u64 pgoff =find_entry_trampoline (kernel); +int nr_cpus_avail, cpu; + +if (!pgoff) +return 0 ; + + nr_cpus_avail =machine__nr_cpus_avail (machine); + +/* Add a 1 page map for each CPU's entry trampoline */ +for (cpu =0 ; cpu < nr_cpus_avail; cpu++) { +u64 va =X86_64_CPU_ENTRY_AREA_PER_CPU + + cpu *X86_64_CPU_ENTRY_AREA_SIZE + +X86_64_ENTRY_TRAMPOLINE ; +struct extra_kernel_map xm = { + .start = va, + .end = va + page_size, + .pgoff = pgoff, + }; + +if (machine__create_extra_kernel_map (machine, kernel, &xm) <0 ) +return -1 ; + } + +return 0 ; +} +static int __machine__create_kernel_maps (struct machine *machine,struct dso *kernel) {
tools/perf/util/machine.h +3 -0
@@ -268,4 +268,7 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,*/ char *machine__resolve_kernel_addr (void *vmachine,unsigned long long *addrp,char **modp); +int machine__map_x86_64_entry_trampolines (struct machine *machine, +struct dso *kernel); +#endif /* __PERF_MACHINE_H */
tools/perf/util/symbol.c +7 -5
@@ -1490,20 +1490,22 @@ int dso__load(struct dso *dso, struct map *map) goto out; } +if (map->groups && map->groups->machine) + machine = map->groups->machine; +else + machine =NULL ; +if (dso->kernel) {if (dso->kernel ==DSO_TYPE_KERNEL ) ret =dso__load_kernel_sym (dso, map);else if (dso->kernel ==DSO_TYPE_GUEST_KERNEL ) ret =dso__load_guest_kernel_sym (dso, map); +if (machine__is (machine,"x86_64" )) +machine__map_x86_64_entry_trampolines (machine, dso); goto out; } -if (map->groups && map->groups->machine) - machine = map->groups->machine; -else - machine =NULL ; - dso->adjust_symbols =0 ;if (perfmap) {
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 6/18 perf machine: Fix map_groups__split_kallsyms() for entry trampoline symbols
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
When kernel symbols are derived from /proc/kallsyms only (not using vmlinux or /proc/kcore) map_groups__split_kallsyms() is used. However that function makes assumptions that are not true with entry trampoline symbols. For now, remove the entry trampoline symbols at that point, as they are no longer needed at that point.
--- tools/perf/util/map.h | 8 ++++++++ tools/perf/util/symbol.c | 13 +++++++++++++ 2 files changed, 21 insertions(+)
tools/perf/util/map.h +8 -0
@@ -8,6 +8,7 @@#include <linux/rbtree.h> #include <pthread.h> #include <stdio.h> +#include <string.h> #include <stdbool.h> #include <linux/types.h> #include "rwsem.h"
@@ -239,4 +240,11 @@ static inline bool __map__is_kmodule(const struct map *map)bool map__has_symbols (const struct map *map); +#define ENTRY_TRAMPOLINE_NAME "__entry_SYSCALL_64_trampoline" + +static inline bool is_entry_trampoline (const char *name) +{ +return !strcmp (name,ENTRY_TRAMPOLINE_NAME ); +} +#endif /* __PERF_MAP_H */
tools/perf/util/symbol.c +13 -0
@@ -737,12 +737,15 @@ static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso,struct rb_root *root = &dso->symbols;struct rb_node *next =rb_first (root);int kernel_range =0 ; +bool x86_64;if (!kmaps)return -1 ; machine = kmaps->machine; + x86_64 =machine__is (machine,"x86_64" ); +while (next) {char *module;
@@ -790,6 +793,16 @@ static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso,*/ pos->start = curr_map->map_ip (curr_map, pos->start); pos->end = curr_map->map_ip (curr_map, pos->end); + }else if (x86_64 &&is_entry_trampoline (pos->name)) { +/* +* These symbols are not needed anymore since the +* trampoline maps refer to the text section and it's +* symbols instead. Avoid having to deal with +* relocations, and the assumption that the first symbol +* is the start of kernel text, by simply removing the +* symbols at this point. +*/ + goto discard_symbol; }else if (curr_map != initial_map) {char dso_name[PATH_MAX ];struct dso *ndso;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 7/18 perf machine: Allow for extra kernel maps
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Identify extra kernel maps by name so that they can be distinguished from the kernel map and module maps.
--- tools/perf/util/event.c | 2 +- tools/perf/util/machine.c | 8 ++++++-- tools/perf/util/map.c | 22 ++++++++++++++++++---- tools/perf/util/map.h | 7 ++++++- tools/perf/util/symbol.c | 7 +++---- 5 files changed, 34 insertions(+), 12 deletions(-)
tools/perf/util/event.c +1 -1
@@ -487,7 +487,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,for (pos =maps__first (maps); pos; pos =map__next (pos)) {size_t size; -if (__map__is_kernel (pos)) +if (!__map__is_kmodule (pos))continue ; size =PERF_ALIGN (pos->dso->long_name_len +1 ,sizeof (u64));
tools/perf/util/machine.c +6 -2
@@ -856,6 +856,7 @@ struct extra_kernel_map {u64 start;u64 end;u64 pgoff; +char name[KMAP_NAME_LEN ]; }; static int machine__create_extra_kernel_map(struct machine *machine,
@@ -875,11 +876,12 @@ static int machine__create_extra_kernel_map(struct machine *machine, kmap =map__kmap (map); kmap->kmaps = &machine->kmaps; +strlcpy (kmap->name, xm->name,KMAP_NAME_LEN );map_groups__insert (&machine->kmaps, map); -pr_debug2 ("Added extra kernel map %" PRIx64"-%" PRIx64"\n" , - map->start, map->end); +pr_debug2 ("Added extra kernel map %s %" PRIx64"-%" PRIx64"\n" , + kmap->name, map->start, map->end);map__put (map);
@@ -940,6 +942,8 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, .pgoff = pgoff, }; +strlcpy (xm.name,ENTRY_TRAMPOLINE_NAME ,KMAP_NAME_LEN ); +if (machine__create_extra_kernel_map (machine, kernel, &xm) <0 )return -1 ; }
tools/perf/util/map.c +18 -4
@@ -252,6 +252,13 @@ bool __map__is_kernel(const struct map *map)return machine__kernel_map (map->groups->machine) == map; } +bool __map__is_extra_kernel_map (const struct map *map) +{ +struct kmap *kmap =__map__kmap ((struct map *)map); + +return kmap && kmap->name[0 ]; +} +bool map__has_symbols (const struct map *map) {return dso__has_symbols (map->dso);
@@ -846,15 +853,22 @@ struct map *map__next(struct map *map)return NULL ; } -struct kmap *map__kmap (struct map *map) +struct kmap *__map__kmap (struct map *map) { -if (!map->dso || !map->dso->kernel) { -pr_err ("Internal error: map__kmap with a non-kernel map\n" ); +if (!map->dso || !map->dso->kernel)return NULL ; - }return (struct kmap *)(map +1 ); } +struct kmap *map__kmap (struct map *map) +{ +struct kmap *kmap =__map__kmap (map); + +if (!kmap) +pr_err ("Internal error: map__kmap with a non-kernel map\n" ); +return kmap; +} +struct map_groups *map__kmaps (struct map *map) {struct kmap *kmap =map__kmap (map);
tools/perf/util/map.h +6 -1
@@ -47,9 +47,12 @@ struct map {refcount_t refcnt; }; +#define KMAP_NAME_LEN 256 +struct kmap {struct ref_reloc_sym *ref_reloc_sym;struct map_groups *kmaps; +char name[KMAP_NAME_LEN ]; };struct maps {
@@ -76,6 +79,7 @@ static inline struct map_groups *map_groups__get(struct map_groups *mg)void map_groups__put (struct map_groups *mg); +struct kmap *__map__kmap (struct map *map);struct kmap *map__kmap (struct map *map);struct map_groups *map__kmaps (struct map *map);
@@ -232,10 +236,11 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,struct map *map_groups__find_by_name (struct map_groups *mg,const char *name);bool __map__is_kernel (const struct map *map); +bool __map__is_extra_kernel_map (const struct map *map);static inline bool __map__is_kmodule (const struct map *map) { -return !__map__is_kernel (map); +return !__map__is_kernel (map) && !__map__is_extra_kernel_map (map); }bool map__has_symbols (const struct map *map);
tools/perf/util/symbol.c +3 -4
@@ -1030,7 +1030,7 @@ struct map *map_groups__first(struct map_groups *mg)return maps__first (&mg->maps); } -static int do_validate_kcore_modules (const char *filename,struct map *map, +static int do_validate_kcore_modules (const char *filename,struct map_groups *kmaps) {struct rb_root modules =RB_ROOT ;
@@ -1046,8 +1046,7 @@ static int do_validate_kcore_modules(const char *filename, struct map *map,struct map *next =map_groups__next (old_map);struct module_info *mi; -if (old_map == map || old_map->start == map->start) { -/* The kernel map */ +if (!__map__is_kmodule (old_map)) { old_map = next;continue ; }
@@ -1104,7 +1103,7 @@ static int validate_kcore_modules(const char *kallsyms_filename, kallsyms_filename))return -EINVAL ; -if (do_validate_kcore_modules (modules_filename, map, kmaps)) +if (do_validate_kcore_modules (modules_filename, kmaps))return -EINVAL ;return 0 ;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 8/18 perf machine: Create maps for x86 PTI entry trampolines
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Create maps for x86 PTI entry trampolines, based on symbols found in kallsyms. It is also necessary to keep track of whether the trampolines have been mapped particularly when the kernel dso is kcore.
--- tools/perf/arch/x86/util/Build | 1 + tools/perf/arch/x86/util/machine.c | 103 +++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.c | 66 +++++++++++++++++------- tools/perf/util/machine.h | 19 +++++++ tools/perf/util/symbol.c | 17 ++++++ 5 files changed, 187 insertions(+), 19 deletions(-) create mode 100644 tools/perf/arch/x86/util/machine.c
tools/perf/arch/x86/util/Build +1 -0
@@ -4,6 +4,7 @@ libperf-y += pmu.o libperf-y += kvm-stat.o libperf-y += perf_regs.o libperf-y += group.o +libperf-y += machine.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
tools/perf/arch/x86/util/machine.c new file +103 -0
103 lines not on this page · raw message
tools/perf/util/machine.c +47 -19
115 lines not on this page · raw message
tools/perf/util/machine.h +19 -0
@@ -56,6 +56,7 @@ struct machine {void *priv;u64 db_id; }; +bool trampolines_mapped; };static inline struct threads *machine__threads (struct machine *machine,pid_t tid)
@@ -268,6 +269,24 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,*/ char *machine__resolve_kernel_addr (void *vmachine,unsigned long long *addrp,char **modp); +void machine__get_kallsyms_filename (struct machine *machine,char *buf, +size_t bufsz); + +int machine__create_extra_kernel_maps (struct machine *machine, +struct dso *kernel); + +/* Kernel-space maps for symbols that are outside the main kernel map and module maps */ +struct extra_kernel_map { +u64 start; +u64 end; +u64 pgoff; +char name[KMAP_NAME_LEN ]; +}; + +int machine__create_extra_kernel_map (struct machine *machine, +struct dso *kernel, +struct extra_kernel_map *xm); +int machine__map_x86_64_entry_trampolines (struct machine *machine,struct dso *kernel);
tools/perf/util/symbol.c +17 -0
@@ -1158,6 +1158,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,struct map_groups *kmaps =map__kmaps (map);struct kcore_mapfn_data md;struct map *old_map, *new_map, *replacement_map =NULL ; +struct machine *machine;bool is_64_bit;int err, fd;char kcore_filename[PATH_MAX ];
@@ -1166,6 +1167,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,if (!kmaps)return -EINVAL ; + machine = kmaps->machine; +/* This function requires that the map is the kernel map */ if (!__map__is_kernel (map))return -EINVAL ;
@@ -1209,6 +1212,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,map_groups__remove (kmaps, old_map); old_map = next; } + machine->trampolines_mapped = false;/* Find the kernel map using the '_stext' symbol */ if (!kallsyms__get_function_start (kallsyms_filename,"_stext" , &stext)) {
@@ -1245,6 +1249,19 @@ static int dso__load_kcore(struct dso *dso, struct map *map,map__put (new_map); } +if (machine__is (machine,"x86_64" )) { +u64 addr; + +/* +* If one of the corresponding symbols is there, assume the +* entry trampoline maps are too. +*/ +if (!kallsyms__get_function_start (kallsyms_filename, +ENTRY_TRAMPOLINE_NAME , + &addr)) + machine->trampolines_mapped = true; + } +/* * Set the data type and long name so that kcore can be read via * dso__data_read_addr().
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 9/18 perf machine: Synthesize and process mmap events for x86 PTI entry trampolines
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Like the kernel text, the location of x86 PTI entry trampolines must be recorded in the perf.data file. Like the kernel, synthesize a mmap event for that, and add processing for it.
--- tools/perf/arch/x86/util/Build | 1 + tools/perf/arch/x86/util/event.c | 76 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.c | 34 ++++++++++++++---- tools/perf/util/event.h | 8 +++++ tools/perf/util/machine.c | 28 +++++++++++++++ 5 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 tools/perf/arch/x86/util/event.c
tools/perf/arch/x86/util/Build +1 -0
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o libperf-y += perf_regs.o libperf-y += group.o libperf-y += machine.o +libperf-y += event.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
tools/perf/arch/x86/util/event.c new file +76 -0
76 lines not on this page · raw message
tools/perf/util/event.c +27 -7
@@ -88,10 +88,10 @@ static const char *perf_ns__name(unsigned int id)return perf_ns__names[id]; } -static int perf_tool__process_synth_event (struct perf_tool *tool, -union perf_event *event, -struct machine *machine, -perf_event__handler_t process) +int perf_tool__process_synth_event (struct perf_tool *tool, +union perf_event *event, +struct machine *machine, +perf_event__handler_t process) {struct perf_sample synth_sample = { .pid =-1 ,
@@ -888,9 +888,16 @@ int kallsyms__get_function_start(const char *kallsyms_filename,return 0 ; } -int perf_event__synthesize_kernel_mmap (struct perf_tool *tool, -perf_event__handler_t process, -struct machine *machine) +int __weak perf_event__synthesize_extra_kmaps (struct perf_tool *tool__maybe_unused , +perf_event__handler_t process__maybe_unused , +struct machine *machine__maybe_unused ) +{ +return 0 ; +} + +static int __perf_event__synthesize_kernel_mmap (struct perf_tool *tool, +perf_event__handler_t process, +struct machine *machine) {size_t size;struct map *map =machine__kernel_map (machine);
@@ -943,6 +950,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,return err; } +int perf_event__synthesize_kernel_mmap (struct perf_tool *tool, +perf_event__handler_t process, +struct machine *machine) +{ +int err; + + err =__perf_event__synthesize_kernel_mmap (tool, process, machine); +if (err <0 ) +return err; + +return perf_event__synthesize_extra_kmaps (tool, process, machine); +} + int perf_event__synthesize_thread_map2(struct perf_tool *tool, struct thread_map *threads, perf_event__handler_t process,
tools/perf/util/event.h +8 -0
@@ -750,6 +750,10 @@ int perf_event__process_exit(struct perf_tool *tool,union perf_event *event, struct perf_sample *sample, struct machine *machine); +int perf_tool__process_synth_event (struct perf_tool *tool, +union perf_event *event, +struct machine *machine, +perf_event__handler_t process); int perf_event__process(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample,
@@ -796,6 +800,10 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,bool mmap_data, unsigned int proc_map_timeout); +int perf_event__synthesize_extra_kmaps (struct perf_tool *tool, +perf_event__handler_t process, +struct machine *machine); +size_t perf_event__fprintf_comm (union perf_event *event,FILE *fp);size_t perf_event__fprintf_mmap (union perf_event *event,FILE *fp);size_t perf_event__fprintf_mmap2 (union perf_event *event,FILE *fp);
tools/perf/util/machine.c +28 -0
@@ -1387,6 +1387,32 @@ static bool machine__uses_kcore(struct machine *machine)return false; } +static bool perf_event__is_extra_kernel_mmap (struct machine *machine, +union perf_event *event) +{ +return machine__is (machine,"x86_64" ) && +is_entry_trampoline (event->mmap.filename); +} + +static int machine__process_extra_kernel_map (struct machine *machine, +union perf_event *event) +{ +struct map *kernel_map =machine__kernel_map (machine); +struct dso *kernel = kernel_map ? kernel_map->dso :NULL ; +struct extra_kernel_map xm = { + .start = event->mmap.start, + .end = event->mmap.start + event->mmap.len, + .pgoff = event->mmap.pgoff, + }; + +if (kernel ==NULL ) +return -1 ; + +strlcpy (xm.name, event->mmap.filename,KMAP_NAME_LEN ); + +return machine__create_extra_kernel_map (machine, kernel, &xm); +} +static int machine__process_kernel_mmap_event (struct machine *machine,union perf_event *event) {
@@ -1490,6 +1516,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,*/ dso__load (kernel,machine__kernel_map (machine)); } + }else if (perf_event__is_extra_kernel_mmap (machine, event)) { +return machine__process_extra_kernel_map (machine, event); }return 0 ; out_problem:
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 10/18 perf annotate: Show group event string for stdio
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
When we enable the group, for tui/stdio2, the output first line includes the group event string. While for stdio, it will show only one event.
For example,
perf record -e cycles,branches ./div
perf annotate --group --stdio
Percent | Source code & Disassembly of div for cycles (44407 samples)
......
The first line doesn't include the event 'branches'.
With this patch, it will show the correct group even string.
perf annotate --group --stdio
Percent | Source code & Disassembly of div for cycles, branches (44407 samples)
......
--- tools/perf/util/annotate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/annotate.c +5 -1
@@ -1965,6 +1965,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,u64 len;int width = symbol_conf.show_total_period ?12 :8 ;int graph_dotted_len; +char buf[512 ]; filename =strdup (dso->long_name);if (!filename)
@@ -1977,8 +1978,11 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, len =symbol__size (sym); -if (perf_evsel__is_group_event (evsel)) +if (perf_evsel__is_group_event (evsel)) { width *= evsel->nr_members; +perf_evsel__group_desc (evsel, buf,sizeof (buf)); + evsel_name = buf; + } graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", width, width, symbol_conf.show_total_period ? "Period" :
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 11/18 perf kcore_copy: Keep phdr data in a list
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Currently, kcore_copy makes 2 program headers, one for the kernel text (namely kernel_map) and one for the modules (namely modules_map). Now more program headers are needed, but treating each program header as a special case results in much more code.
Instead, in preparation to add more program headers, change to keep program header data (phdr_data) in a list.
--- tools/perf/util/symbol-elf.c | 9 +++++++++ 1 file changed, 9 insertions(+)
tools/perf/util/symbol-elf.c +9 -0
@@ -1388,6 +1388,7 @@ struct phdr_data {off_t offset;u64 addr;u64 len; +struct list_head node; };struct kcore_copy_info {
@@ -1399,6 +1400,7 @@ struct kcore_copy_info {u64 last_module_symbol;struct phdr_data kernel_map;struct phdr_data modules_map; +struct list_head phdrs; }; static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
@@ -1510,6 +1512,11 @@ static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)if (elf_read_maps (elf, true, kcore_copy__read_map, kci) <0 )return -1 ; +if (kci->kernel_map.len) +list_add_tail (&kci->kernel_map.node, &kci->phdrs); +if (kci->modules_map.len) +list_add_tail (&kci->modules_map.node, &kci->phdrs); +return 0 ; }
@@ -1678,6 +1685,8 @@ int kcore_copy(const char *from_dir, const char *to_dir)char kcore_filename[PATH_MAX ];char extract_filename[PATH_MAX ]; +INIT_LIST_HEAD (&kci.phdrs); +if (kcore_copy__copy_file (from_dir, to_dir,"kallsyms" ))return -1 ;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 12/18 perf kcore_copy: Keep a count of phdrs
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
In preparation to add more program headers, keep a count of phdrs.
--- tools/perf/util/symbol-elf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
tools/perf/util/symbol-elf.c +4 -5
@@ -1398,6 +1398,7 @@ struct kcore_copy_info {u64 last_symbol;u64 first_module;u64 last_module_symbol; +size_t phnum;struct phdr_data kernel_map;struct phdr_data modules_map;struct list_head phdrs;
@@ -1517,6 +1518,8 @@ static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)if (kci->modules_map.len)list_add_tail (&kci->modules_map.node, &kci->phdrs); + kci->phnum = !!kci->kernel_map.len + !!kci->modules_map.len; +return 0 ; }
@@ -1678,7 +1681,6 @@ int kcore_copy(const char *from_dir, const char *to_dir) {struct kcore kcore;struct kcore extract; -size_t count =2 ;int idx =0 , err =-1 ;off_t offset = page_size, sz, modules_offset =0 ;struct kcore_copy_info kci = { .stext =0 , };
@@ -1705,10 +1707,7 @@ int kcore_copy(const char *from_dir, const char *to_dir)if (kcore__init (&extract, extract_filename, kcore.elfclass, false)) goto out_kcore_close; -if (!kci.modules_map.addr) - count -=1 ; - -if (kcore__copy_hdr (&kcore, &extract, count)) +if (kcore__copy_hdr (&kcore, &extract, kci.phnum)) goto out_extract_close; if (kcore__add_phdr(&extract, idx++, offset, kci.kernel_map.addr,
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 13/18 perf kcore_copy: Calculate offset from phnum
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
In preparation to add more program headers, calculate offset from the number of phdrs.
--- tools/perf/util/symbol-elf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +5 -1
@@ -1682,7 +1682,7 @@ int kcore_copy(const char *from_dir, const char *to_dir)struct kcore kcore;struct kcore extract;int idx =0 , err =-1 ; -off_t offset = page_size, sz, modules_offset =0 ; +off_t offset, sz, modules_offset =0 ;struct kcore_copy_info kci = { .stext =0 , };char kcore_filename[PATH_MAX ];char extract_filename[PATH_MAX ];
@@ -1710,6 +1710,10 @@ int kcore_copy(const char *from_dir, const char *to_dir)if (kcore__copy_hdr (&kcore, &extract, kci.phnum)) goto out_extract_close; + offset =gelf_fsize (extract.elf,ELF_T_EHDR ,1 ,EV_CURRENT ) + +gelf_fsize (extract.elf,ELF_T_PHDR , kci.phnum,EV_CURRENT ); + offset =round_up (offset, page_size); +if (kcore__add_phdr (&extract, idx++, offset, kci.kernel_map.addr, kci.kernel_map.len)) goto out_extract_close;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 14/18 perf kcore_copy: Layout sections
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
In preparation to add more program headers, layout the relative offset of each section.
--- tools/perf/util/symbol-elf.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
tools/perf/util/symbol-elf.c +22 -3
@@ -1386,6 +1386,7 @@ static off_t kcore__write(struct kcore *kcore)struct phdr_data {off_t offset; +off_t rel;u64 addr;u64 len;struct list_head node;
@@ -1404,6 +1405,9 @@ struct kcore_copy_info {struct list_head phdrs; }; +#define kcore_copy__for_each_phdr (k, p) \ + list_for_each_entry((p), &(k)->phdrs, node) +static int kcore_copy__process_kallsyms (void *arg,const char *name,char type,u64 start) {
@@ -1518,11 +1522,21 @@ static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)if (kci->modules_map.len)list_add_tail (&kci->modules_map.node, &kci->phdrs); - kci->phnum = !!kci->kernel_map.len + !!kci->modules_map.len; -return 0 ; } +static void kcore_copy__layout (struct kcore_copy_info *kci) +{ +struct phdr_data *p; +off_t rel =0 ; + +kcore_copy__for_each_phdr (kci, p) { + p->rel = rel; + rel += p->len; + kci->phnum +=1 ; + } +} +static int kcore_copy__calc_maps (struct kcore_copy_info *kci,const char *dir,Elf *elf) {
@@ -1558,7 +1572,12 @@ static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,if (kci->first_module && !kci->last_module_symbol)return -1 ; -return kcore_copy__read_maps (kci, elf); +if (kcore_copy__read_maps (kci, elf)) +return -1 ; + +kcore_copy__layout (kci); + +return 0 ; } static int kcore_copy__copy_file(const char *from_dir, const char *to_dir,
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 15/18 perf kcore_copy: Iterate phdrs
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
In preparation to add more program headers, iterate phdrs instead of assuming there is only one for the kernel text and one for the modules.
--- tools/perf/util/symbol-elf.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
tools/perf/util/symbol-elf.c +10 -15
@@ -1701,10 +1701,11 @@ int kcore_copy(const char *from_dir, const char *to_dir)struct kcore kcore;struct kcore extract;int idx =0 , err =-1 ; -off_t offset, sz, modules_offset =0 ; +off_t offset, sz;struct kcore_copy_info kci = { .stext =0 , };char kcore_filename[PATH_MAX ];char extract_filename[PATH_MAX ]; +struct phdr_data *p;INIT_LIST_HEAD (&kci.phdrs);
@@ -1733,14 +1734,10 @@ int kcore_copy(const char *from_dir, const char *to_dir)gelf_fsize (extract.elf,ELF_T_PHDR , kci.phnum,EV_CURRENT ); offset =round_up (offset, page_size); -if (kcore__add_phdr (&extract, idx++, offset, kci.kernel_map.addr, - kci.kernel_map.len)) - goto out_extract_close; +kcore_copy__for_each_phdr (&kci, p) { +off_t offs = p->rel + offset; -if (kci.modules_map.addr) { - modules_offset = offset + kci.kernel_map.len; -if (kcore__add_phdr (&extract, idx, modules_offset, - kci.modules_map.addr, kci.modules_map.len)) +if (kcore__add_phdr (&extract, idx++, offs, p->addr, p->len)) goto out_extract_close; }
@@ -1748,14 +1745,12 @@ int kcore_copy(const char *from_dir, const char *to_dir)if (sz <0 || sz > offset) goto out_extract_close; -if (copy_bytes (kcore.fd, kci.kernel_map.offset, extract.fd, offset, - kci.kernel_map.len)) - goto out_extract_close; +kcore_copy__for_each_phdr (&kci, p) { +off_t offs = p->rel + offset; -if (modules_offset &©_bytes (kcore.fd, kci.modules_map.offset, - extract.fd, modules_offset, - kci.modules_map.len)) - goto out_extract_close; +if (copy_bytes (kcore.fd, p->offset, extract.fd, offs, p->len)) + goto out_extract_close; + }if (kcore_copy__compare_file (from_dir, to_dir,"modules" )) goto out_extract_close;
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 16/18 perf kcore_copy: Get rid of kernel_map
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
In preparation to add more program headers, get rid of kernel_map and modules_map by moving ->kernel_map and ->modules_map to newly allocated entries in the ->phdrs list.
--- tools/perf/util/symbol-elf.c | 70 ++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 18 deletions(-)
tools/perf/util/symbol-elf.c +52 -18
@@ -1400,14 +1400,47 @@ struct kcore_copy_info {u64 first_module;u64 last_module_symbol;size_t phnum; -struct phdr_data kernel_map; -struct phdr_data modules_map;struct list_head phdrs; };#define kcore_copy__for_each_phdr (k, p) \ list_for_each_entry((p), &(k)->phdrs, node) +static struct phdr_data *phdr_data__new (u64 addr,u64 len,off_t offset) +{ +struct phdr_data *p =zalloc (sizeof (*p)); + +if (p) { + p->addr = addr; + p->len = len; + p->offset = offset; + } + +return p; +} + +static struct phdr_data *kcore_copy_info__addnew (struct kcore_copy_info *kci, +u64 addr,u64 len, +off_t offset) +{ +struct phdr_data *p =phdr_data__new (addr, len, offset); + +if (p) +list_add_tail (&p->node, &kci->phdrs); + +return p; +} + +static void kcore_copy__free_phdrs (struct kcore_copy_info *kci) +{ +struct phdr_data *p, *tmp; + +list_for_each_entry_safe (p, tmp, &kci->phdrs, node) { +list_del (&p->node); +free (p); + } +} +static int kcore_copy__process_kallsyms (void *arg,const char *name,char type,u64 start) {
@@ -1487,15 +1520,18 @@ static int kcore_copy__parse_modules(struct kcore_copy_info *kci,return 0 ; } -static void kcore_copy__map (struct phdr_data *p,u64 start,u64 end,u64 pgoff, -u64 s,u64 e) +static int kcore_copy__map (struct kcore_copy_info *kci,u64 start,u64 end, +u64 pgoff,u64 s,u64 e) { -if (p->addr || s < start || s >= end) -return ; +u64 len, offset; + +if (s < start || s >= end) +return 0 ; - p->addr = s; - p->offset = (s - start) + pgoff; - p->len = e < end ? e - s : end - s; + offset = (s - start) + pgoff; + len = e < end ? e - s : end - s; + +return kcore_copy_info__addnew (kci, s, len, offset) ?0 :-1 ; }static int kcore_copy__read_map (u64 start,u64 len,u64 pgoff,void *data)
@@ -1503,11 +1539,12 @@ static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data)struct kcore_copy_info *kci = data;u64 end = start + len; -kcore_copy__map (&kci->kernel_map, start, end, pgoff, kci->stext, - kci->etext); +if (kcore_copy__map (kci, start, end, pgoff, kci->stext, kci->etext)) +return -1 ; -kcore_copy__map (&kci->modules_map, start, end, pgoff, kci->first_module, - kci->last_module_symbol); +if (kcore_copy__map (kci, start, end, pgoff, kci->first_module, + kci->last_module_symbol)) +return -1 ;return 0 ; }
@@ -1517,11 +1554,6 @@ static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)if (elf_read_maps (elf, true, kcore_copy__read_map, kci) <0 )return -1 ; -if (kci->kernel_map.len) -list_add_tail (&kci->kernel_map.node, &kci->phdrs); -if (kci->modules_map.len) -list_add_tail (&kci->modules_map.node, &kci->phdrs); -return 0 ; }
@@ -1773,6 +1805,8 @@ int kcore_copy(const char *from_dir, const char *to_dir)if (err)kcore_copy__unlink (to_dir,"kallsyms" ); +kcore_copy__free_phdrs (&kci); +return err; }
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 17/18 perf kcore_copy: Copy x86 PTI entry trampoline sections
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Identify and copy any sections for x86 PTI entry trampolines.
--- tools/perf/util/symbol-elf.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
tools/perf/util/symbol-elf.c +42 -0
@@ -1392,6 +1392,11 @@ struct phdr_data {struct list_head node; }; +struct sym_data { +u64 addr; +struct list_head node; +}; +struct kcore_copy_info {u64 stext;u64 etext;
@@ -1401,6 +1406,7 @@ struct kcore_copy_info {u64 last_module_symbol;size_t phnum;struct list_head phdrs; +struct list_head syms; };#define kcore_copy__for_each_phdr (k, p) \
@@ -1441,6 +1447,29 @@ static void kcore_copy__free_phdrs(struct kcore_copy_info *kci) } } +static struct sym_data *kcore_copy__new_sym (struct kcore_copy_info *kci, +u64 addr) +{ +struct sym_data *s =zalloc (sizeof (*s)); + +if (s) { + s->addr = addr; +list_add_tail (&s->node, &kci->syms); + } + +return s; +} + +static void kcore_copy__free_syms (struct kcore_copy_info *kci) +{ +struct sym_data *s, *tmp; + +list_for_each_entry_safe (s, tmp, &kci->syms, node) { +list_del (&s->node); +free (s); + } +} +static int kcore_copy__process_kallsyms (void *arg,const char *name,char type,u64 start) {
@@ -1471,6 +1500,9 @@ static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,return 0 ; } +if (is_entry_trampoline (name) && !kcore_copy__new_sym (kci, start)) +return -1 ; +return 0 ; }
@@ -1538,6 +1570,7 @@ static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data) {struct kcore_copy_info *kci = data;u64 end = start + len; +struct sym_data *sdat;if (kcore_copy__map (kci, start, end, pgoff, kci->stext, kci->etext))return -1 ;
@@ -1546,6 +1579,13 @@ static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data) kci->last_module_symbol))return -1 ; +list_for_each_entry (sdat, &kci->syms, node) { +u64 s =round_down (sdat->addr, page_size); + +if (kcore_copy__map (kci, start, end, pgoff, s, s + len)) +return -1 ; + } +return 0 ; }
@@ -1740,6 +1780,7 @@ int kcore_copy(const char *from_dir, const char *to_dir)struct phdr_data *p;INIT_LIST_HEAD (&kci.phdrs); +INIT_LIST_HEAD (&kci.syms);if (kcore_copy__copy_file (from_dir, to_dir,"kallsyms" ))return -1 ;
@@ -1806,6 +1847,7 @@ int kcore_copy(const char *from_dir, const char *to_dir)kcore_copy__unlink (to_dir,"kallsyms" );kcore_copy__free_phdrs (&kci); +kcore_copy__free_syms (&kci);return err; }
Signature · 1 line
2.14.3
Arnaldo Carvalho de Melo
maintainerPATCH 18/18 perf kcore_copy: Amend the offset of sections that remap kernel text
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
x86 PTI entry trampolines all map to the same physical page. If that is reflected in the program headers of /proc/kcore, then do the same for the copy of kcore.
--- tools/perf/util/symbol-elf.c | 53 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +51 -2
@@ -1390,6 +1390,7 @@ struct phdr_data {u64 addr;u64 len;struct list_head node; +struct phdr_data *remaps; };struct sym_data {
@@ -1597,16 +1598,62 @@ static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)return 0 ; } +static void kcore_copy__find_remaps (struct kcore_copy_info *kci) +{ +struct phdr_data *p, *k =NULL ; +u64 kend; + +if (!kci->stext) +return ; + +/* Find phdr that corresponds to the kernel map (contains stext) */ +kcore_copy__for_each_phdr (kci, p) { +u64 pend = p->addr + p->len -1 ; + +if (p->addr <= kci->stext && pend >= kci->stext) { + k = p; +break ; + } + } + +if (!k) +return ; + + kend = k->offset + k->len; + +/* Find phdrs that remap the kernel */ +kcore_copy__for_each_phdr (kci, p) { +u64 pend = p->offset + p->len; + +if (p == k) +continue ; + +if (p->offset >= k->offset && pend <= kend) + p->remaps = k; + } +} +static void kcore_copy__layout (struct kcore_copy_info *kci) {struct phdr_data *p;off_t rel =0 ; +kcore_copy__find_remaps (kci); +kcore_copy__for_each_phdr (kci, p) { - p->rel = rel; - rel += p->len; +if (!p->remaps) { + p->rel = rel; + rel += p->len; + } kci->phnum +=1 ; } + +kcore_copy__for_each_phdr (kci, p) { +struct phdr_data *k = p->remaps; + +if (k) + p->rel = p->offset - k->offset + k->rel; + } } static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,
@@ -1821,6 +1868,8 @@ int kcore_copy(const char *from_dir, const char *to_dir)kcore_copy__for_each_phdr (&kci, p) {off_t offs = p->rel + offset; +if (p->remaps) +continue ;if (copy_bytes (kcore.fd, p->offset, extract.fd, offs, p->len)) goto out_extract_close; }
Signature · 1 line
2.14.3
Quoted 71 lines · Arnaldo Carvalho de Melo
Hi Ingo,
Please consider pulling,
- Arnaldo
Test results at the end of this message, as usual.
The following changes since commit
2996123e7e589d78e73cfeb7e7f14d49127eb1b0:Merge tag 'perf-core-for-mingo-4.18-20180519' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/core (2018-05-19 13:32:53 +0200)are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingo-4.18-20180523for you to fetch changes up to
22916fdb9c50e8fb303bdcedca88fd8798a85844:perf
kcore_copy: Amend the offset of sections that remap kernel text (2018-05-23 10:26:44 -0300)----------------------------------------------------------------
perf/core improvements:. Create extra kernel maps to help in decoding samples in x86 PTI entry
trampolines (Adrian Hunter). Copy x86 PTI entry trampoline sections in the kcore copy used for
annotation andintel_ptCPU traces decoding (Adrian Hunter)- Support 'perf annotate --group' for non-explicit recorded event "groups", showing multiple columns, one for each event, just like when dealing with explicit event groups (those enclosed with {}) (Jin Yao)
Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Adrian Hunter (14):
perf machine: Addnr_cpus_avail()
perf machine: Workaround missing maps for x86 PTI entry trampolines perf machine: Fixmap_groups__split_kallsyms()for entry trampoline symbols perf machine: Allow for extra kernel maps
perf machine: Create maps for x86 PTI entry trampolines
perf machine: Synthesize and process mmap events for x86 PTI entry trampolines perfkcore_copy: Keep phdr data in a list
perfkcore_copy: Keep a count of phdrs
perfkcore_copy: Calculate offset from phnum
perfkcore_copy: Layout sections
perfkcore_copy: Iterate phdrs
perfkcore_copy: Get rid ofkernel_map
perfkcore_copy: Copy x86 PTI entry trampoline sections
perfkcore_copy: Amend the offset of sections that remap kernel textJin Yao (4):
perf evlist: Introduceforce_leader()method
perf report: Useperf_evlist__force_leaderto support '--group' perf annotate: Support '--group' option
perf annotate: Show group event string for stdiotools/perf/arch/x86/util/Build | 2 + tools/perf/arch/x86/util/event.c | 76 +++++++++++++ tools/perf/arch/x86/util/machine.c | 103 +++++++++++++++++ tools/perf/builtin-annotate.c | 7 ++ tools/perf/builtin-report.c | 13 +-- tools/perf/util/annotate.c | 6 +- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 1 + tools/perf/util/event.c | 36 ++++-- tools/perf/util/event.h | 8 ++ tools/perf/util/evlist.c | 15 +++ tools/perf/util/evlist.h | 3 + tools/perf/util/machine.c | 175 +++++++++++++++++++++++++++--
Quoted 8 lines
tools/perf/util/machine.h | 23 ++++ tools/perf/util/map.c | 22 +++- tools/perf/util/map.h | 15 ++- tools/perf/util/symbol-elf.c | 219 +++++++++++++++++++++++++++++++------ tools/perf/util/symbol.c | 49 +++++++-- 18 files changed, 711 insertions(+), 75 deletions(-) create mode 100644 tools/perf/arch/x86/util/event.c create mode 100644 tools/perf/arch/x86/util/machine.c
Pulled, thanks a lot Arnaldo!
Ingo