perf/core improvements and fixes
Subsystems (3)
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 e3a6a62400520452fe39740dca90a1d0b94b8f92:
Merge tag 'perf-core-for-mingo-4.12-20170324' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (2017-03-24 19:37:40 +0100)
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.12-20170327
for you to fetch changes up to 55f77128e7652e537d6c226d5b56821cdb5c22de:
perf utils: Readlink /proc/self/exe to find the perf binary (2017-03-27 15:37:54 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
New features:
- Handle inline functions in callchains (Jin Yao)
- Enable sorting by srcline as key (Milian Wolff)
Fixes:
- Fix no_size logic in addr_filter__resolve_kernel_syms() in the auxtrace code (Adrian Hunter)
- Fix some thread refcount leaks in 'perf trace' (Arnaldo Carvalho de Melo)
- Fix divide by zero when calculating percent for an event in a group in the annotate by source line code (Taeung Song)
- build-id files now aren't anymore symlinks, their parent directories are, so readlink the later (Taeung Song)
- Assorted fixes for null termination problems, mostly related to readlink, detected by valgrind (Tommi Rantala)
Infrastructure:
- Make vfs_getname probe point logic in 'perf trace' more robust wrt length of pathname (Arnaldo Carvalho de Melo)
- Remove unused 'prefix' parameter from builtins main functions (Arnaldo Carvalho de Melo)
- Show 'perf list sdt' option in man page (Ravi Bangoria)
----------------------------------------------------------------
Adrian Hunter (1):
perf auxtrace: Fix no_size logic in addr_filter__resolve_kernel_syms()
Arnaldo Carvalho de Melo (4):
perf trace: Check for vfs_getname.pathname length perf trace: Fix up error path indentation
perf trace: Fixup thread refcounting
perf tools: Remove unused 'prefix' from builtin functions
Jin Yao (5):
perf report: Refactor common code in srcline.c perf report: Find the inline stack for a given address perf report: Introduce --inline option
perf report: Show inline stack for stdio mode perf report: Show inline stack for browser mode
Milian Wolff (1):
perf report: Enable sorting by srcline as key
Ravi Bangoria (1):
perf list sdt: Show option in man page
Taeung Song (2):
perf annotate: Fix a bug following symbolic link of a build-id file perf annotate: Fix a bug of division by zero when calculating percent
Tommi Rantala (6):
perf buildid: Do not update SDT cache with null filename
perf buildid: Do not assume that readlink() returns a null terminated string perf tests: Do not assume that readlink() returns a null terminated string perf utils: use sizeof(buf) - 1 in readlink() call
perf utils: Null terminate buf in read_ftrace_printk()
perf utils: Readlink /proc/self/exe to find the perf binary
tools/perf/Documentation/perf-list.txt | 4 +- tools/perf/Documentation/perf-report.txt | 5 + tools/perf/bench/bench.h | 20 +-- tools/perf/bench/futex-hash.c | 3 +- tools/perf/bench/futex-lock-pi.c | 3 +- tools/perf/bench/futex-requeue.c | 3 +- tools/perf/bench/futex-wake-parallel.c | 3 +- tools/perf/bench/futex-wake.c | 3 +- tools/perf/bench/mem-functions.c | 4 +- tools/perf/bench/numa.c | 2 +- tools/perf/bench/sched-messaging.c | 3 +- tools/perf/bench/sched-pipe.c | 2 +- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-bench.c | 12 +- tools/perf/builtin-buildid-cache.c | 3 +- tools/perf/builtin-buildid-list.c | 3 +- tools/perf/builtin-c2c.c | 4 +- tools/perf/builtin-config.c | 2 +- tools/perf/builtin-data.c | 9 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-ftrace.c | 2 +- tools/perf/builtin-help.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kallsyms.c | 2 +- tools/perf/builtin-kmem.c | 4 +- tools/perf/builtin-kvm.c | 16 +- tools/perf/builtin-list.c | 2 +- tools/perf/builtin-lock.c | 6 +- tools/perf/builtin-mem.c | 6 +- tools/perf/builtin-probe.c | 6 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 4 +- tools/perf/builtin-sched.c | 6 +- tools/perf/builtin-script.c | 4 +- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-timechart.c | 7 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 25 ++-- tools/perf/builtin-version.c | 3 +- tools/perf/builtin.h | 58 ++++---- tools/perf/perf.c | 11 +- tools/perf/tests/builtin-test.c | 2 +- tools/perf/tests/sdt.c | 2 +- tools/perf/ui/browsers/hists.c | 181 ++++++++++++++++++++++- tools/perf/ui/stdio/hist.c | 86 ++++++++++- tools/perf/util/annotate.c | 23 ++- tools/perf/util/auxtrace.c | 4 +- tools/perf/util/build-id.c | 8 +- tools/perf/util/callchain.c | 52 ++++++- tools/perf/util/callchain.h | 3 +- tools/perf/util/header.c | 8 +- tools/perf/util/hist.c | 5 + tools/perf/util/map.c | 3 +- tools/perf/util/sort.c | 16 +- tools/perf/util/sort.h | 1 + tools/perf/util/srcline.c | 246 +++++++++++++++++++++++++++---- tools/perf/util/symbol-elf.c | 5 + tools/perf/util/symbol-minimal.c | 7 + tools/perf/util/symbol.h | 5 +- tools/perf/util/trace-event-read.c | 4 +- tools/perf/util/util.h | 20 ++- 62 files changed, 739 insertions(+), 208 deletions(-)
Test results:
The first ones are container (docker) based builds of tools/perf with and without libelf support, objtool where it is supported and samples/bpf/, ditto. Where clang is available, it is also used to build perf with/without libelf.
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 2 alpine:3.5: Ok 3 alpine:edge: Ok 4 android-ndk:r12b-arm: Ok 5 archlinux:latest: Ok 6 centos:5: Ok 7 centos:6: Ok 8 centos:7: Ok 9 debian:7: Ok 10 debian:8: Ok 11 debian:9: Ok 12 debian:experimental: Ok 13 debian:experimental-x-arm64: Ok 14 debian:experimental-x-mips: Ok 15 debian:experimental-x-mips64: Ok 16 debian:experimental-x-mipsel: Ok 17 fedora:20: Ok 18 fedora:21: Ok 19 fedora:22: Ok 20 fedora:23: Ok 21 fedora:24: Ok 22 fedora:24-x-ARC-uClibc: Ok 23 fedora:25: Ok 24 fedora:rawhide: Ok 25 mageia:5: Ok 26 opensuse:13.2: Ok 27 opensuse:42.1: Ok 28 opensuse:tumbleweed: Ok 29 ubuntu:12.04.5: Ok 30 ubuntu:14.04.4: Ok 31 ubuntu:14.04.4-x-linaro-arm64: Ok 32 ubuntu:15.10: Ok 33 ubuntu:16.04: Ok 34 ubuntu:16.04-x-arm: Ok 35 ubuntu:16.04-x-arm64: Ok 36 ubuntu:16.04-x-powerpc: Ok 37 ubuntu:16.04-x-powerpc64: Ok 38 ubuntu:16.04-x-s390: Ok 39 ubuntu:16.10: Ok 40 ubuntu:17.04: Ok # # uname -a Linux jouet 4.11.0-rc2+ #5 SMP Mon Mar 20 18:12:29 -03 2017 x86_64 x86_64 x86_64 GNU/Linux # This kernel lacks the fix by peterz for 'perf test tsc' # # 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: Parse event definition strings : Ok 6: Simple expression parser : Ok 7: PERF_RECORD_* events & perf_sample fields : Ok 8: Parse perf pmu format : Ok 9: DSO data read : Ok 10: DSO data cache : Ok 11: DSO data reopen : Ok 12: Roundtrip evsel->name : Ok 13: Parse sched tracepoints fields : Ok 14: syscalls:sys_enter_openat event fields : Ok 15: Setup struct perf_event_attr : Ok 16: Match and link multiple hists : Ok 17: 'import perf' in python : Ok 18: Breakpoint overflow signal handler : Ok 19: Breakpoint overflow sampling : Ok 20: Number of exit events of a simple workload : Ok 21: Software clock events period values : Ok 22: Object code reading : Ok 23: Sample parsing : Ok 24: Use a dummy software event to keep tracking: Ok 25: Parse with no sample_id_all bit set : Ok 26: Filter hist entries : Ok 27: Lookup mmap thread : Ok 28: Share thread mg : Ok 29: Sort output of hist entries : Ok 30: Cumulate child hist entries : Ok 31: Track with sched_switch : Ok 32: Filter fds with revents mask in a fdarray : Ok 33: Add fd to a fdarray, making it autogrow : Ok 34: kmod_path__parse : Ok 35: Thread map : Ok 36: LLVM search and compile : 36.1: Basic BPF llvm compile : Ok 36.2: kbuild searching : Ok 36.3: Compile source for BPF prologue generation: Ok 36.4: Compile source for BPF relocation : Ok 37: Session topology : Ok 38: BPF filter : 38.1: Basic BPF filtering : Ok 38.2: BPF pinning : Ok 38.3: BPF prologue generation : Ok 38.4: BPF relocation checker : Ok 39: Synthesize thread map : Ok 40: Remove thread map : Ok 41: Synthesize cpu map : Ok 42: Synthesize stat config : Ok 43: Synthesize stat : Ok 44: Synthesize stat round : Ok 45: Synthesize attr update : Ok 46: Event times : Ok 47: Read backward ring buffer : Ok 48: Print cpu map : Ok 49: Probe SDT events : Ok 50: is_printable_array : Ok 51: Print bitmap : Ok 52: perf hooks : Ok 53: builtin clang support : Skip (not compiled in) 54: unit_number__scnprintf : Ok 55: x86 rdpmc : Ok 56: Convert perf time to TSC : FAILED! 57: DWARF unwind : Ok 58: x86 instruction decoder - new instructions : Ok 59: Intel cqm nmi context read : Skip #
$ make -C tools/perf build-test
make: Entering directory '/home/acme/git/linux/tools/perf'
- tarpkg: ./tests/perf-targz-src-pkg .
make_clean_all_O: make clean all
make_util_pmu_bison_o_O: make util/pmu-bison.o
make_no_backtrace_O: make NO_BACKTRACE=1
make_install_O: make install
make_no_libaudit_O: make NO_LIBAUDIT=1
make_with_clangllvm_O: make LIBCLANGLLVM=1
make_tags_O: make tags
make_no_slang_O: make NO_SLANG=1
make_install_prefix_slash_O: make install prefix=/tmp/krava/
make_pure_O: make
make_install_prefix_O: make install prefix=/tmp/krava
make_no_demangle_O: make NO_DEMANGLE=1
make_doc_O: make doc
make_no_gtk2_O: make NO_GTK2=1
make_help_O: make help
make_static_O: make LDFLAGS=-static
make_no_libunwind_O: make NO_LIBUNWIND=1
make_util_map_o_O: make util/map.o
make_no_libpython_O: make NO_LIBPYTHON=1
make_no_libbionic_O: make NO_LIBBIONIC=1
make_no_libelf_O: make NO_LIBELF=1
make_debug_O: make DEBUG=1
make_no_scripts_O: make NO_LIBPYTHON=1 NO_LIBPERL=1
make_perf_o_O: make perf.o
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_no_auxtrace_O: make NO_AUXTRACE=1
make_no_libperl_O: make NO_LIBPERL=1
make_no_ui_O: make NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
make_no_libbpf_O: make NO_LIBBPF=1
make_no_newt_O: make NO_NEWT=1
make_no_libdw_dwarf_unwind_O: make NO_LIBDW_DWARF_UNWIND=1
make_no_libnuma_O: make NO_LIBNUMA=1
make_with_babeltrace_O: make LIBBABELTRACE=1
make_install_bin_O: make install-bin
OK
make: Leaving directory '/home/acme/git/linux/tools/perf'
$Arnaldo Carvalho de Melo
maintainerPATCH 1/20 perf trace: Check for vfs_getname.pathname length
From: Arnaldo Carvalho de Melo <[email protected]>
It shouldn't be zero, but if the 'perf probe' on getname_flags() (or elsewhere in the future we need to probe to catch the pathname for syscalls like 'open' being copied from userspace to the kernel) is misplaced somehow, then we will end up not allocating space and trying to copy the "" empty string to ttrace->filename.name, causing a segfault, fix it.
--- tools/perf/builtin-trace.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/builtin-trace.c +2 -0
@@ -1656,6 +1656,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, goto out; filename_len =strlen (filename); +if (filename_len ==0 ) + goto out;if (ttrace->filename.namelen < filename_len) {char *f =realloc (ttrace->filename.name, filename_len +1 );
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 2/20 perf trace: Fix up error path indentation
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Trivial fix removing a tab in an error path.
--- tools/perf/builtin-trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-trace.c +1 -1
@@ -1663,7 +1663,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,char *f =realloc (ttrace->filename.name, filename_len +1 );if (f ==NULL ) - goto out; + goto out; ttrace->filename.namelen = filename_len; ttrace->filename.name = f;
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 3/20 perf trace: Fixup thread refcounting
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
In trace__vfs_getname() and when checking if a thread is filtered in trace__process_sample() we were not dropping the reference obtained via machine__findnew_thread(), fix it.
--- tools/perf/builtin-trace.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
tools/perf/builtin-trace.c +12 -9
@@ -1653,17 +1653,17 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace =thread__priv (thread);if (!ttrace) - goto out; + goto out_put; filename_len =strlen (filename);if (filename_len ==0 ) - goto out; + goto out_put;if (ttrace->filename.namelen < filename_len) {char *f =realloc (ttrace->filename.name, filename_len +1 );if (f ==NULL ) - goto out; + goto out_put; ttrace->filename.namelen = filename_len; ttrace->filename.name = f;
@@ -1673,12 +1673,12 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace->filename.pending_open = true;if (!ttrace->filename.ptr) - goto out; + goto out_put; entry_str_len =strlen (ttrace->entry_str); remaining_space = trace__entry_str_size - entry_str_len -1 ;/* \0 */ if (remaining_space <=0 ) - goto out; + goto out_put;if (filename_len > (size_t )remaining_space) { filename += filename_len - remaining_space;
@@ -1692,6 +1692,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace->filename.ptr =0 ; ttrace->filename.entry_str_pos =0 ; +out_put: +thread__put (thread); out:return 0 ; }
@@ -1712,6 +1714,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs ttrace->runtime_ms += runtime_ms; trace->runtime_ms += runtime_ms; +out_put:thread__put (thread);return 0 ;
@@ -1722,8 +1725,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs (pid_t )perf_evsel__intval (evsel, sample,"pid" ), runtime, perf_evsel__intval(evsel, sample, "vruntime")); -thread__put (thread); -return 0 ; + goto out_put; } static void bpf_output__printer(enum binary_printer_ops op,
@@ -1922,7 +1924,7 @@ static int trace__process_sample(struct perf_tool *tool, thread =machine__findnew_thread (trace->host, sample->pid, sample->tid);if (thread &&thread__is_filtered (thread)) -return 0 ; + goto out;trace__set_base_time (trace, evsel, sample);
@@ -1930,7 +1932,8 @@ static int trace__process_sample(struct perf_tool *tool, ++trace->nr_events;handler (trace, evsel, event, sample); } - +out: +thread__put (thread);return err; }
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 4/20 perf auxtrace: Fix no_size logic in addr_filter__resolve_kernel_syms()
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Address filtering with kernel symbols incorrectly resulted in the error "Cannot determine size of symbol" because the no_size logic was the wrong way around.
--- tools/perf/util/auxtrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/auxtrace.c +2 -2
@@ -1826,7 +1826,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) filt->addr = start;if (filt->range && !filt->size && !filt->sym_to) { filt->size = size; - no_size = !!size; + no_size = !size; } }
@@ -1840,7 +1840,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt)if (err)return err; filt->size = start + size - filt->addr; - no_size = !!size; + no_size = !size; }/* The very last symbol in kallsyms does not imply a particular size */
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 5/20 perf list sdt: Show option in man page
In reply to Arnaldo Carvalho de MeloFrom: Ravi Bangoria <[email protected]>
Commit 40218daea1db ("perf list: Show SDT and pre-cached events") added sdt support in perf list, but it missed to update documentation.
Show sdt option in man perf-list.
--- tools/perf/Documentation/perf-list.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-list.txt +3 -1
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob] +'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob] DESCRIPTION -----------
@@ -244,6 +244,8 @@ To limit the list use: . 'pmu' to print the kernel supplied PMU events. +. 'sdt' to list all Statically Defined Tracepoint events. + . If none of the above is matched, it will apply the supplied glob to all events, printing the ones that match.
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 6/20 perf tools: Remove unused 'prefix' from builtin functions
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We got it from the git sources but never used it for anything, with the place where this would be somehow used remaining:
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
{
prefix = NULL;
if (p->option & RUN_SETUP)
prefix = NULL; /* setup_perf_directory(); */Ditch it.
--- tools/perf/bench/bench.h | 20 ++++++------ tools/perf/bench/futex-hash.c | 3 +- tools/perf/bench/futex-lock-pi.c | 3 +- tools/perf/bench/futex-requeue.c | 3 +- tools/perf/bench/futex-wake-parallel.c | 3 +- tools/perf/bench/futex-wake.c | 3 +- tools/perf/bench/mem-functions.c | 4 +-- tools/perf/bench/numa.c | 2 +- tools/perf/bench/sched-messaging.c | 3 +- tools/perf/bench/sched-pipe.c | 2 +- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-bench.c | 12 +++---- tools/perf/builtin-buildid-cache.c | 3 +- tools/perf/builtin-buildid-list.c | 3 +- tools/perf/builtin-c2c.c | 4 +-- tools/perf/builtin-config.c | 2 +- tools/perf/builtin-data.c | 9 +++--- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-ftrace.c | 2 +- tools/perf/builtin-help.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kallsyms.c | 2 +- tools/perf/builtin-kmem.c | 4 +-- tools/perf/builtin-kvm.c | 16 +++++----- tools/perf/builtin-list.c | 2 +- tools/perf/builtin-lock.c | 6 ++-- tools/perf/builtin-mem.c | 6 ++-- tools/perf/builtin-probe.c | 6 ++-- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 6 ++-- tools/perf/builtin-script.c | 4 +-- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-timechart.c | 7 ++-- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 4 +-- tools/perf/builtin-version.c | 3 +- tools/perf/builtin.h | 58 +++++++++++++++++----------------- tools/perf/perf.c | 11 ++----- tools/perf/tests/builtin-test.c | 2 +- 41 files changed, 110 insertions(+), 126 deletions(-)
tools/perf/bench/bench.h +10 -10
@@ -25,17 +25,17 @@# endif #endif -int bench_numa (int argc,const char **argv,const char *prefix); -int bench_sched_messaging (int argc,const char **argv,const char *prefix); -int bench_sched_pipe (int argc,const char **argv,const char *prefix); -int bench_mem_memcpy (int argc,const char **argv,const char *prefix); -int bench_mem_memset (int argc,const char **argv,const char *prefix); -int bench_futex_hash (int argc,const char **argv,const char *prefix); -int bench_futex_wake (int argc,const char **argv,const char *prefix); -int bench_futex_wake_parallel (int argc,const char **argv,const char *prefix); -int bench_futex_requeue (int argc,const char **argv,const char *prefix); +int bench_numa (int argc,const char **argv); +int bench_sched_messaging (int argc,const char **argv); +int bench_sched_pipe (int argc,const char **argv); +int bench_mem_memcpy (int argc,const char **argv); +int bench_mem_memset (int argc,const char **argv); +int bench_futex_hash (int argc,const char **argv); +int bench_futex_wake (int argc,const char **argv); +int bench_futex_wake_parallel (int argc,const char **argv); +int bench_futex_requeue (int argc,const char **argv);/* pi futexes */ -int bench_futex_lock_pi (int argc,const char **argv,const char *prefix); +int bench_futex_lock_pi (int argc,const char **argv);#define BENCH_FORMAT_DEFAULT_STR "default"#define BENCH_FORMAT_DEFAULT 0
tools/perf/bench/futex-hash.c +1 -2
@@ -114,8 +114,7 @@ static void print_summary(void) (int) runtime.tv_sec); } -int bench_futex_hash (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_futex_hash (int argc,const char **argv) {int ret =0 ;cpu_set_t cpu;
tools/perf/bench/futex-lock-pi.c +1 -2
@@ -140,8 +140,7 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr) } } -int bench_futex_lock_pi (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_futex_lock_pi (int argc,const char **argv) {int ret =0 ;unsigned int i;
tools/perf/bench/futex-requeue.c +1 -2
@@ -109,8 +109,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_requeue (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_futex_requeue (int argc,const char **argv) {int ret =0 ;unsigned int i, j;
tools/perf/bench/futex-wake-parallel.c +1 -2
@@ -197,8 +197,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_wake_parallel (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_futex_wake_parallel (int argc,const char **argv) {int ret =0 ;unsigned int i, j;
tools/perf/bench/futex-wake.c +1 -2
@@ -115,8 +115,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_wake (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_futex_wake (int argc,const char **argv) {int ret =0 ;unsigned int i, j;
tools/perf/bench/mem-functions.c +2 -2
@@ -284,7 +284,7 @@ static const char * const bench_mem_memcpy_usage[] = {NULL }; -int bench_mem_memcpy (int argc,const char **argv,const char *prefix__maybe_unused ) +int bench_mem_memcpy (int argc,const char **argv) {struct bench_mem_info info = { .functions = memcpy_functions,
@@ -358,7 +358,7 @@ static const struct function memset_functions[] = { { .name = NULL, } }; -int bench_mem_memset (int argc,const char **argv,const char *prefix__maybe_unused ) +int bench_mem_memset (int argc,const char **argv) {struct bench_mem_info info = { .functions = memset_functions,
tools/perf/bench/numa.c +1 -1
@@ -1767,7 +1767,7 @@ static int bench_all(void)return 0 ; } -int bench_numa (int argc,const char **argv,const char *prefix__maybe_unused ) +int bench_numa (int argc,const char **argv) {init_params (&p0,"main," , argc, argv); argc =parse_options (argc, argv, options, bench_numa_usage,0 );
tools/perf/bench/sched-messaging.c +1 -2
@@ -260,8 +260,7 @@ static const char * const bench_sched_message_usage[] = { NULL }; -int bench_sched_messaging (int argc,const char **argv, -const char *prefix__maybe_unused ) +int bench_sched_messaging (int argc,const char **argv) {unsigned int i, total_children;struct timeval start, stop, diff;
tools/perf/bench/sched-pipe.c +1 -1
@@ -76,7 +76,7 @@ static void *worker_thread(void *__tdata)return NULL ; } -int bench_sched_pipe (int argc,const char **argv,const char *prefix__maybe_unused ) +int bench_sched_pipe (int argc,const char **argv) {struct thread_data threads[2 ], *td;int pipe_1[2 ], pipe_2[2 ];
tools/perf/builtin-annotate.c +1 -1
@@ -383,7 +383,7 @@ static const char * const annotate_usage[] = {NULL }; -int cmd_annotate (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_annotate (int argc,const char **argv) {struct perf_annotate annotate = { .tool = {
tools/perf/builtin-bench.c +6 -6
@@ -25,7 +25,7 @@#include <string.h> #include <sys/prctl.h> -typedef int (*bench_fn_t )(int argc,const char **argv,const char *prefix); +typedef int (*bench_fn_t )(int argc,const char **argv);struct bench {const char *name;
@@ -155,7 +155,7 @@ static int bench_str2int(const char *str)* to something meaningful: */ static int run_bench (const char *coll_name,const char *bench_name,bench_fn_t fn, -int argc,const char **argv,const char *prefix) +int argc,const char **argv) {int size;char *name;
@@ -171,7 +171,7 @@ static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fprctl (PR_SET_NAME , name); argv[0 ] = name; - ret =fn (argc, argv, prefix); + ret =fn (argc, argv);free (name);
@@ -198,7 +198,7 @@ static void run_collection(struct collection *coll)fflush (stdout); argv[1 ] = bench->name; -run_bench (coll->name, bench->name, bench->fn,1 , argv,NULL ); +run_bench (coll->name, bench->name, bench->fn,1 , argv);printf ("\n" ); } }
@@ -211,7 +211,7 @@ static void run_all_collections(void)run_collection (coll); } -int cmd_bench (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_bench (int argc,const char **argv) {struct collection *coll;int ret =0 ;
@@ -270,7 +270,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)if (bench_format ==BENCH_FORMAT_DEFAULT )printf ("# Running '%s/%s' benchmark:\n" , coll->name, bench->name);fflush (stdout); - ret =run_bench (coll->name, bench->name, bench->fn, argc-1 , argv+1 , prefix); + ret =run_bench (coll->name, bench->name, bench->fn, argc-1 , argv+1 ); goto end; }
tools/perf/builtin-buildid-cache.c +1 -2
@@ -276,8 +276,7 @@ static int build_id_cache__update_file(const char *filename)return err; } -int cmd_buildid_cache (int argc,const char **argv, -const char *prefix__maybe_unused ) +int cmd_buildid_cache (int argc,const char **argv) {struct strlist *list;struct str_node *pos;
tools/perf/builtin-buildid-list.c +1 -2
@@ -87,8 +87,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)return 0 ; } -int cmd_buildid_list (int argc,const char **argv, -const char *prefix__maybe_unused ) +int cmd_buildid_list (int argc,const char **argv) {bool show_kernel = false;bool with_hits = false;
tools/perf/builtin-c2c.c +2 -2
@@ -2755,12 +2755,12 @@ static int perf_c2c__record(int argc, const char **argv)pr_debug ("\n" ); } - ret =cmd_record (i, rec_argv,NULL ); + ret =cmd_record (i, rec_argv);free (rec_argv);return ret; } -int cmd_c2c (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_c2c (int argc,const char **argv) { argc =parse_options (argc, argv, c2c_options, c2c_usage,PARSE_OPT_STOP_AT_NON_OPTION );
tools/perf/builtin-config.c +1 -1
@@ -154,7 +154,7 @@ static int parse_config_arg(char *arg, char **var, char **value)return 0 ; } -int cmd_config (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_config (int argc,const char **argv) {int i, ret =0 ;struct perf_config_set *set;
tools/perf/builtin-data.c +4 -5
@@ -6,7 +6,7 @@#include "data-convert.h" #include "data-convert-bt.h" -typedef int (*data_cmd_fn_t )(int argc,const char **argv,const char *prefix); +typedef int (*data_cmd_fn_t )(int argc,const char **argv);struct data_cmd {const char *name;
@@ -50,8 +50,7 @@ static const char * const data_convert_usage[] = {NULL }; -static int cmd_data_convert (int argc,const char **argv, -const char *prefix__maybe_unused ) +static int cmd_data_convert (int argc,const char **argv) {const char *to_ctf =NULL ;struct perf_data_convert_opts opts = {
@@ -98,7 +97,7 @@ static struct data_cmd data_cmds[] = { { .name = NULL, }, }; -int cmd_data (int argc,const char **argv,const char *prefix) +int cmd_data (int argc,const char **argv) {struct data_cmd *cmd;const char *cmdstr;
@@ -118,7 +117,7 @@ int cmd_data(int argc, const char **argv, const char *prefix)if (strcmp (cmd->name, cmdstr))continue ; -return cmd->fn (argc, argv, prefix); +return cmd->fn (argc, argv); }pr_err ("Unknown command: %s\n" , cmdstr);
tools/perf/builtin-diff.c +1 -1
@@ -1321,7 +1321,7 @@ static int diff__config(const char *var, const char *value,return 0 ; } -int cmd_diff (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_diff (int argc,const char **argv) {int ret =hists__init ();
tools/perf/builtin-evlist.c +1 -1
@@ -46,7 +46,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *detailsreturn 0 ; } -int cmd_evlist (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_evlist (int argc,const char **argv) {struct perf_attr_details details = { .verbose = false, };const struct option options[] = {
tools/perf/builtin-ftrace.c +1 -1
@@ -304,7 +304,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb)return -1 ; } -int cmd_ftrace (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_ftrace (int argc,const char **argv) {int ret;struct perf_ftrace ftrace = {
tools/perf/builtin-help.c +1 -1
@@ -418,7 +418,7 @@ static int show_html_page(const char *perf_cmd)return 0 ; } -int cmd_help (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_help (int argc,const char **argv) {bool show_all = false;enum help_format help_format =HELP_FORMAT_MAN ;
tools/perf/builtin-inject.c +1 -1
@@ -738,7 +738,7 @@ static int __cmd_inject(struct perf_inject *inject)return ret; } -int cmd_inject (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_inject (int argc,const char **argv) {struct perf_inject inject = { .tool = {
tools/perf/builtin-kallsyms.c +1 -1
@@ -43,7 +43,7 @@ static int __cmd_kallsyms(int argc, const char **argv)return 0 ; } -int cmd_kallsyms (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_kallsyms (int argc,const char **argv) {const struct option options[] = {OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show counter open errors, etc)" ),
tools/perf/builtin-kmem.c +2 -2
@@ -1866,7 +1866,7 @@ static int __cmd_record(int argc, const char **argv)for (j =1 ; j < (unsigned int )argc; j++, i++) rec_argv[i] = argv[j]; -return cmd_record (i, rec_argv,NULL ); +return cmd_record (i, rec_argv); }static int kmem_config (const char *var,const char *value,void *cb__maybe_unused )
@@ -1885,7 +1885,7 @@ static int kmem_config(const char *var, const char *value, void *cb __maybe_unusreturn 0 ; } -int cmd_kmem (int argc,const char **argv,const char *prefix__maybe_unused ) +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" ;
tools/perf/builtin-kvm.c +8 -8
@@ -1209,7 +1209,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)set_option_flag (record_options,0 ,"transaction" ,PARSE_OPT_DISABLED ); record_usage = kvm_stat_record_usage; -return cmd_record (i, rec_argv,NULL ); +return cmd_record (i, rec_argv); } static int
@@ -1477,7 +1477,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)#endif perf_stat: - return cmd_stat(argc, argv, NULL); + return cmd_stat(argc, argv); }#endif /* HAVE_KVM_STAT_SUPPORT */
@@ -1496,7 +1496,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)BUG_ON (i != rec_argc); -return cmd_record (i, rec_argv,NULL ); +return cmd_record (i, rec_argv); }static int __cmd_report (const char *file_name,int argc,const char **argv)
@@ -1514,7 +1514,7 @@ static int __cmd_report(const char *file_name, int argc, const char **argv)BUG_ON (i != rec_argc); -return cmd_report (i, rec_argv,NULL ); +return cmd_report (i, rec_argv); } static int
@@ -1533,10 +1533,10 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)BUG_ON (i != rec_argc); -return cmd_buildid_list (i, rec_argv,NULL ); +return cmd_buildid_list (i, rec_argv); } -int cmd_kvm (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_kvm (int argc,const char **argv) {const char *file_name =NULL ;const struct option kvm_options[] = {
@@ -1591,9 +1591,9 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)else if (!strncmp (argv[0 ],"rep" ,3 ))return __cmd_report (file_name, argc, argv);else if (!strncmp (argv[0 ],"diff" ,4 )) -return cmd_diff (argc, argv,NULL ); +return cmd_diff (argc, argv);else if (!strncmp (argv[0 ],"top" ,3 )) -return cmd_top (argc, argv,NULL ); +return cmd_top (argc, argv);else if (!strncmp (argv[0 ],"buildid-list" ,12 ))return __cmd_buildid_list (file_name, argc, argv);#ifdef HAVE_KVM_STAT_SUPPORT
tools/perf/builtin-list.c +1 -1
@@ -20,7 +20,7 @@static bool desc_flag = true;static bool details_flag; -int cmd_list (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_list (int argc,const char **argv) {int i;bool raw_dump = false;
tools/perf/builtin-lock.c +3 -3
@@ -941,12 +941,12 @@ static int __cmd_record(int argc, const char **argv)BUG_ON (i != rec_argc); - ret =cmd_record (i, rec_argv,NULL ); + ret =cmd_record (i, rec_argv);free (rec_argv);return ret; } -int cmd_lock (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_lock (int argc,const char **argv) {const struct option lock_options[] = {OPT_STRING ('i' ,"input" , &input_name,"file" ,"input file name" ),
@@ -1009,7 +1009,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) rc =__cmd_report (false); }else if (!strcmp (argv[0 ],"script" )) {/* Aliased to 'perf script' */ -return cmd_script (argc, argv, prefix); +return cmd_script (argc, argv); }else if (!strcmp (argv[0 ],"info" )) {if (argc) { argc = parse_options(argc, argv,
tools/perf/builtin-mem.c +3 -3
@@ -129,7 +129,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)pr_debug ("\n" ); } - ret =cmd_record (i, rec_argv,NULL ); + ret =cmd_record (i, rec_argv);free (rec_argv);return ret; }
@@ -256,7 +256,7 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem)for (j =1 ; j < argc; j++, i++) rep_argv[i] = argv[j]; - ret =cmd_report (i, rep_argv,NULL ); + ret =cmd_report (i, rep_argv);free (rep_argv);return ret; }
@@ -330,7 +330,7 @@ parse_mem_ops(const struct option *opt, const char *str, int unset)return ret; } -int cmd_mem (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_mem (int argc,const char **argv) {struct stat st;struct perf_mem mem = {
tools/perf/builtin-probe.c +3 -3
@@ -468,7 +468,7 @@ static int perf_del_probe_events(struct strfilter *filter)static int -__cmd_probe (int argc,const char **argv,const char *prefix__maybe_unused ) +__cmd_probe (int argc,const char **argv) {const char *const probe_usage[] = {"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]" ,
@@ -687,13 +687,13 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)return 0 ; } -int cmd_probe (int argc,const char **argv,const char *prefix) +int cmd_probe (int argc,const char **argv) {int ret; ret =init_params ();if (!ret) { - ret =__cmd_probe (argc, argv, prefix); + ret =__cmd_probe (argc, argv);cleanup_params (); }
tools/perf/builtin-record.c +1 -1
@@ -1667,7 +1667,7 @@ static struct option __record_options[] = {struct option *record_options = __record_options; -int cmd_record (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_record (int argc,const char **argv) {int err;struct record *rec = &record;
tools/perf/builtin-report.c +1 -1
@@ -681,7 +681,7 @@ const char report_callchain_help[] = "Display call graph (stack chain/backtrace)CALLCHAIN_REPORT_HELP "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT ; -int cmd_report (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_report (int argc,const char **argv) {struct perf_session *session;struct itrace_synth_opts itrace_synth_opts = { .set =0 , };
tools/perf/builtin-sched.c +3 -3
@@ -3272,10 +3272,10 @@ static int __cmd_record(int argc, const char **argv)BUG_ON (i != rec_argc); -return cmd_record (i, rec_argv,NULL ); +return cmd_record (i, rec_argv); } -int cmd_sched (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_sched (int argc,const char **argv) {const char default_sort_order[] ="avg, max, switch, runtime" ;struct perf_sched sched = {
@@ -3412,7 +3412,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)* Aliased to 'perf script' for now: */ if (!strcmp (argv[0 ],"script" )) -return cmd_script (argc, argv, prefix); +return cmd_script (argc, argv);if (!strncmp (argv[0 ],"rec" ,3 )) {return __cmd_record (argc, argv);
tools/perf/builtin-script.c +2 -2
@@ -2359,7 +2359,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,return set_maps (script); } -int cmd_script (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_script (int argc,const char **argv) {bool show_full_info = false;bool header = false;
@@ -2504,7 +2504,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)if (argc >1 && !strncmp (argv[0 ],"rec" ,strlen ("rec" ))) { rec_script_path =get_script_path (argv[1 ],RECORD_SUFFIX );if (!rec_script_path) -return cmd_record (argc, argv,NULL ); +return cmd_record (argc, argv); }if (argc >1 && !strncmp (argv[0 ],"rep" ,strlen ("rep" ))) {
tools/perf/builtin-stat.c +1 -1
@@ -2478,7 +2478,7 @@ static void setup_system_wide(int forks) } } -int cmd_stat (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_stat (int argc,const char **argv) {const char *const stat_usage[] = {"perf stat [<options>] [<command>]" ,
tools/perf/builtin-timechart.c +3 -4
@@ -1773,7 +1773,7 @@ static int timechart__io_record(int argc, const char **argv)for (i =0 ; i < (unsigned int )argc; i++) *p++ = argv[i]; -return cmd_record (rec_argc, rec_argv,NULL ); +return cmd_record (rec_argc, rec_argv); }
@@ -1864,7 +1864,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **arfor (j =0 ; j < (unsigned int )argc; j++) *p++ = argv[j]; -return cmd_record (rec_argc, rec_argv,NULL ); +return cmd_record (rec_argc, rec_argv); } static int
@@ -1917,8 +1917,7 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)return 0 ; } -int cmd_timechart (int argc,const char **argv, -const char *prefix__maybe_unused ) +int cmd_timechart (int argc,const char **argv) {struct timechart tchart = { .tool = {
tools/perf/builtin-top.c +1 -1
@@ -1075,7 +1075,7 @@ parse_percent_limit(const struct option *opt, const char *arg, const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP"\n\t\t\t\tDefault: fp,graph,0.5,caller,function" ; -int cmd_top (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_top (int argc,const char **argv) {char errbuf[BUFSIZ ];struct perf_top top = {
tools/perf/builtin-trace.c +2 -2
@@ -1993,7 +1993,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv)for (i =0 ; i < (unsigned int )argc; i++) rec_argv[j++] = argv[i]; -return cmd_record (j, rec_argv,NULL ); +return cmd_record (j, rec_argv); }static size_t trace__fprintf_thread_summary (struct trace *trace,FILE *fp);
@@ -2791,7 +2791,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str,return err; } -int cmd_trace (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_trace (int argc,const char **argv) {const char *trace_usage[] = {"perf trace [<options>] [<command>]" ,
tools/perf/builtin-version.c +1 -2
@@ -2,8 +2,7 @@#include "builtin.h" #include "perf.h" -int cmd_version (int argc__maybe_unused ,const char **argv__maybe_unused , -const char *prefix__maybe_unused ) +int cmd_version (int argc__maybe_unused ,const char **argv__maybe_unused ) {printf ("perf version %s\n" , perf_version_string);return 0 ;
tools/perf/builtin.h +29 -29
64 lines not on this page · raw message
tools/perf/perf.c +3 -8
@@ -34,7 +34,7 @@ const char *input_name;struct cmd_struct {const char *cmd; -int (*fn)(int ,const char **,const char *); +int (*fn)(int ,const char **);int option; };
@@ -339,13 +339,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) {int status;struct stat st; -const char *prefix;char sbuf[STRERR_BUFSIZE ]; - prefix =NULL ; -if (p->option &RUN_SETUP ) - prefix =NULL ;/* setup_perf_directory(); */ -if (use_browser ==-1 ) use_browser =check_browser_config (p->cmd);
@@ -356,7 +351,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)commit_pager_choice ();perf_env__set_cmdline (&perf_env, argc, argv); - status = p->fn (argc, argv, prefix); + status = p->fn (argc, argv);perf_config__exit ();exit_browser (status);perf_env__exit (&perf_env);
@@ -566,7 +561,7 @@ int main(int argc, const char **argv)#ifdef HAVE_LIBAUDIT_SUPPORT setup_path (); argv[0 ] ="trace" ; -return cmd_trace (argc, argv,NULL ); +return cmd_trace (argc, argv);#else fprintf (stderr,"trace command not available: missing audit-libs devel package at build time.\n" );
tools/perf/tests/builtin-test.c +1 -1
@@ -464,7 +464,7 @@ static int perf_test__list(int argc, const char **argv)return 0 ; } -int cmd_test (int argc,const char **argv,const char *prefix__maybe_unused ) +int cmd_test (int argc,const char **argv) {const char *test_usage[] = {"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]" ,
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 7/20 perf report: Refactor common code in srcline.c
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Introduce dso__name() and filename_split() out of existing code because these codes will be used in several places in next patch.
For filename_split(), it may also solve a potential memory leak in existing code. In existing addr2line(),
sep = strchr(filename, ':');
if (sep) {
*sep++ = '\0';
*file = filename;
*line_nr = strtoul(sep, NULL, 0);
ret = 1;
}out:
pclose(fp);
return ret;If sep is NULL, filename is not freed or returned via file.
--- tools/perf/util/srcline.c | 68 +++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 23 deletions(-)
tools/perf/util/srcline.c +45 -23
@@ -12,6 +12,24 @@bool srcline_full_filename; +static const char *dso__name (struct dso *dso) +{ +const char *dso_name; + +if (dso->symsrc_filename) + dso_name = dso->symsrc_filename; +else + dso_name = dso->long_name; + +if (dso_name[0 ] =='[' ) +return NULL ; + +if (!strncmp (dso_name,"/tmp/perf-" ,10 )) +return NULL ; + +return dso_name; +} +#ifdef HAVE_LIBBFD_SUPPORT /*
@@ -207,6 +225,27 @@ void dso__free_a2l(struct dso *dso)#else /* HAVE_LIBBFD_SUPPORT */ +static int filename_split (char *filename,unsigned int *line_nr) +{ +char *sep; + + sep =strchr (filename,'\n' ); +if (sep) + *sep ='\0' ; + +if (!strcmp (filename,"??:0" )) +return 0 ; + + sep =strchr (filename,':' ); +if (sep) { + *sep++ ='\0' ; + *line_nr =strtoul (sep,NULL ,0 ); +return 1 ; + } + +return 0 ; +} + static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr, struct dso *dso __maybe_unused,
@@ -216,7 +255,6 @@ static int addr2line(const char *dso_name, u64 addr,char cmd[PATH_MAX ];char *filename =NULL ;size_t len; -char *sep;int ret =0 ; scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
@@ -233,23 +271,14 @@ static int addr2line(const char *dso_name, u64 addr, goto out; } - sep =strchr (filename,'\n' ); -if (sep) - *sep ='\0' ; - -if (!strcmp (filename,"??:0" )) { -pr_debug ("no debugging info in %s\n" , dso_name); + ret =filename_split (filename, line_nr); +if (ret !=1 ) {free (filename); goto out; } - sep =strchr (filename,':' ); -if (sep) { - *sep++ ='\0' ; - *file = filename; - *line_nr =strtoul (sep,NULL ,0 ); - ret =1 ; - } + *file = filename; + out:pclose (fp);return ret;
@@ -278,15 +307,8 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,if (!dso->has_srcline) goto out; -if (dso->symsrc_filename) - dso_name = dso->symsrc_filename; -else - dso_name = dso->long_name; - -if (dso_name[0 ] =='[' ) - goto out; - -if (!strncmp (dso_name,"/tmp/perf-" ,10 )) + dso_name =dso__name (dso); +if (dso_name ==NULL ) goto out;if (!addr2line (dso_name, addr, &file, &line, dso, unwind_inlines))
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 8/20 perf report: Find the inline stack for a given address
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
It would be useful for perf to support a mode to query the inline stack for a given callgraph address. This would simplify finding the right code in code that does a lot of inlining.
The srcline.c has contained the code which supports to translate the address to filename:line_nr. This patch just extends the function to let it support getting the inline stacks.
It introduces the inline_list which will store the inline function result (filename:line_nr and funcname).
If BFD lib is not supported, the result is only filename:line_nr.
--- tools/perf/util/srcline.c | 167 +++++++++++++++++++++++++++++++++++++-- tools/perf/util/symbol-elf.c | 5 ++ tools/perf/util/symbol-minimal.c | 7 ++ tools/perf/util/symbol.h | 2 + tools/perf/util/util.h | 16 ++++ 5 files changed, 192 insertions(+), 5 deletions(-)
tools/perf/util/srcline.c +162 -5
@@ -7,6 +7,7 @@#include "util/dso.h" #include "util/util.h" #include "util/debug.h" +#include "util/callchain.h" #include "symbol.h"
@@ -30,6 +31,34 @@ static const char *dso__name(struct dso *dso)return dso_name; } +static int inline_list__append (char *filename,char *funcname,int line_nr, +struct inline_node *node,struct dso *dso) +{ +struct inline_list *ilist; +char *demangled; + + ilist =zalloc (sizeof (*ilist)); +if (ilist ==NULL ) +return -1 ; + + ilist->filename = filename; + ilist->line_nr = line_nr; + +if (dso !=NULL ) { + demangled =dso__demangle_sym (dso,0 , funcname); +if (demangled ==NULL ) { + ilist->funcname = funcname; + }else { + ilist->funcname = demangled; +free (funcname); + } + } + +list_add_tail (&ilist->list, &node->val); + +return 0 ; +} +#ifdef HAVE_LIBBFD_SUPPORT /*
@@ -169,9 +198,17 @@ static void addr2line_cleanup(struct a2l_data *a2l)#define MAX_INLINE_NEST 1024 +static void inline_list__reverse (struct inline_node *node) +{ +struct inline_list *ilist, *n; + +list_for_each_entry_safe_reverse (ilist, n, &node->val, list) +list_move_tail (&ilist->list, &node->val); +} +static int addr2line (const char *dso_name,u64 addr,char **file,unsigned int *line,struct dso *dso, -bool unwind_inlines) +bool unwind_inlines,struct inline_node *node) {int ret =0 ;struct a2l_data *a2l = dso->a2l;
@@ -196,8 +233,21 @@ static int addr2line(const char *dso_name, u64 addr,while (bfd_find_inliner_info (a2l->abfd, &a2l->filename, &a2l->funcname, &a2l->line) && - cnt++ <MAX_INLINE_NEST ) - ; + cnt++ <MAX_INLINE_NEST ) { + +if (node !=NULL ) { +if (inline_list__append (strdup (a2l->filename), +strdup (a2l->funcname), + a2l->line, node, + dso) !=0 ) +return 0 ; + } + } + +if ((node !=NULL ) && + (callchain_param.order !=ORDER_CALLEE )) { +inline_list__reverse (node); + } }if (a2l->found && a2l->filename) {
@@ -223,6 +273,35 @@ void dso__free_a2l(struct dso *dso) dso->a2l =NULL ; } +static struct inline_node *addr2inlines (const char *dso_name,u64 addr, +struct dso *dso) +{ +char *file =NULL ; +unsigned int line =0 ; +struct inline_node *node; + + node =zalloc (sizeof (*node)); +if (node ==NULL ) { +perror ("not enough memory for the inline node" ); +return NULL ; + } + +INIT_LIST_HEAD (&node->val); + node->addr = addr; + +if (!addr2line (dso_name, addr, &file, &line, dso, TRUE, node)) + goto out_free_inline_node; + +if (list_empty (&node->val)) + goto out_free_inline_node; + +return node; + +out_free_inline_node: +inline_node__delete (node); +return NULL ; +} +#else /* HAVE_LIBBFD_SUPPORT */ static int filename_split (char *filename,unsigned int *line_nr)
@@ -249,7 +328,8 @@ static int filename_split(char *filename, unsigned int *line_nr)static int addr2line (const char *dso_name,u64 addr,char **file,unsigned int *line_nr,struct dso *dso__maybe_unused , -bool unwind_inlines__maybe_unused ) +bool unwind_inlines__maybe_unused , +struct inline_node *node__maybe_unused ) {FILE *fp;char cmd[PATH_MAX ];
@@ -288,6 +368,58 @@ void dso__free_a2l(struct dso *dso __maybe_unused) { } +static struct inline_node *addr2inlines (const char *dso_name,u64 addr, +struct dso *dso__maybe_unused ) +{ +FILE *fp; +char cmd[PATH_MAX ]; +struct inline_node *node; +char *filename =NULL ; +size_t len; +unsigned int line_nr =0 ; + +scnprintf (cmd,sizeof (cmd),"addr2line -e %s -i %016" PRIx64, + dso_name, addr); + + fp =popen (cmd,"r" ); +if (fp ==NULL ) { +pr_err ("popen failed for %s\n" , dso_name); +return NULL ; + } + + node =zalloc (sizeof (*node)); +if (node ==NULL ) { +perror ("not enough memory for the inline node" ); + goto out; + } + +INIT_LIST_HEAD (&node->val); + node->addr = addr; + +while (getline (&filename, &len, fp) !=-1 ) { +if (filename_split (filename, &line_nr) !=1 ) { +free (filename); + goto out; + } + +if (inline_list__append (filename,NULL , line_nr, node, +NULL ) !=0 ) + goto out; + + filename =NULL ; + } + +out: +pclose (fp); + +if (list_empty (&node->val)) { +inline_node__delete (node); +return NULL ; + } + +return node; +} +#endif /* HAVE_LIBBFD_SUPPORT */ /*
@@ -311,7 +443,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,if (dso_name ==NULL ) goto out; -if (!addr2line (dso_name, addr, &file, &line, dso, unwind_inlines)) +if (!addr2line (dso_name, addr, &file, &line, dso, unwind_inlines,NULL )) goto out; if (asprintf(&srcline, "%s:%u",
@@ -351,3 +483,28 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, {return __get_srcline (dso, addr, sym, show_sym, false); } + +struct inline_node *dso__parse_addr_inlines (struct dso *dso,u64 addr) +{ +const char *dso_name; + + dso_name =dso__name (dso); +if (dso_name ==NULL ) +return NULL ; + +return addr2inlines (dso_name, addr, dso); +} + +void inline_node__delete (struct inline_node *node) +{ +struct inline_list *ilist, *tmp; + +list_for_each_entry_safe (ilist, tmp, &node->val, list) { +list_del_init (&ilist->list); +zfree (&ilist->filename); +zfree (&ilist->funcname); +free (ilist); + } + +free (node); +}
tools/perf/util/symbol-elf.c +5 -0
@@ -390,6 +390,11 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *return 0 ; } +char *dso__demangle_sym (struct dso *dso,int kmodule,char *elf_name) +{ +return demangle_sym (dso, kmodule, elf_name); +} +/* * Align offset to 4 bytes as needed for note name and descriptor data. */
tools/perf/util/symbol-minimal.c +7 -0
@@ -373,3 +373,10 @@ int kcore_copy(const char *from_dir __maybe_unused,void symbol__elf_init (void ) { } + +char *dso__demangle_sym (struct dso *dso__maybe_unused , +int kmodule__maybe_unused , +char *elf_name__maybe_unused ) +{ +return NULL ; +}
tools/perf/util/symbol.h +2 -0
@@ -305,6 +305,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,int dso__synthesize_plt_symbols (struct dso *dso,struct symsrc *ss,struct map *map); +char *dso__demangle_sym (struct dso *dso,int kmodule,char *elf_name); +void __symbols__insert (struct rb_root *symbols,struct symbol *sym,bool kernel);void symbols__insert (struct rb_root *symbols,struct symbol *sym);void symbols__fixup_duplicate (struct rb_root *symbols);
tools/perf/util/util.h +16 -0
@@ -364,4 +364,20 @@ int is_printable_array(char *p, unsigned int len);int timestamp__scnprintf_usec (u64 timestamp,char *buf,size_t sz);int unit_number__scnprintf (char *buf,size_t size,u64 n); + +struct inline_list { +char *filename; +char *funcname; +unsigned int line_nr; +struct list_head list; +}; + +struct inline_node { +u64 addr; +struct list_head val; +}; + +struct inline_node *dso__parse_addr_inlines (struct dso *dso,u64 addr); +void inline_node__delete (struct inline_node *node); +#endif /* GIT_COMPAT_UTIL_H */
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 9/20 perf report: Introduce --inline option
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
It takes some time to look for inline stack for callgraph addresses. So it provides new option "--inline" to let user decide if enable this feature.
--inline:
If a callgraph address belongs to an inlined function, the inline stack will be printed. Each entry is the inline function name or file/line.
--- tools/perf/Documentation/perf-report.txt | 4 ++++ tools/perf/builtin-report.c | 2 ++ tools/perf/util/symbol.h | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-report.txt +4 -0
@@ -430,6 +430,10 @@ include::itrace.txt[] --hierarchy:: Enable hierarchical output. +--inline:: + If a callgraph address belongs to an inlined function, the inline stack + will be printed. Each entry is function name or file/line. + include::callchain-overhead-calculation.txt[] SEE ALSO
tools/perf/builtin-report.c +2 -0
@@ -845,6 +845,8 @@ int cmd_report(int argc, const char **argv) stdio__config_color, "always"),OPT_STRING (0 ,"time" , &report.time_str,"str" ,"Time span of interest (start,stop)" ), +OPT_BOOLEAN (0 ,"inline" , &symbol_conf.inline_name, +"Show inline function" ),OPT_END () }; struct perf_data_file file = {
tools/perf/util/symbol.h +2 -1
@@ -118,7 +118,8 @@ struct symbol_conf { show_ref_callgraph, hide_unresolved, raw_trace, - report_hierarchy; + report_hierarchy, + inline_name;const char *vmlinux_name, *kallsyms_name, *source_prefix,
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 10/20 perf report: Show inline stack for stdio mode
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
If the address belongs to an inlined function, the source information back to the first non-inlined function will be printed.
For example:
1. Show inlined function name
perf report --stdio -g function --inline
0.69% 0.00% inline ld-2.23.so [.] dl_main
|
---dl_main
|
--0.56%--_dl_relocate_object
_dl_relocate_object (inline)
elf_dynamic_do_Rela (inline)2. Show the file/line information
perf report --stdio -g address --inline
0.69% 0.00% inline ld-2.23.so [.] _dl_start_user
|
---_dl_start_user .:0
_dl_start rtld.c:307
/build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline)
_dl_sysdep_start dl-sysdep.c:250
|
--0.56%--dl_main rtld.c:2076Committer tests:
# perf record --call-graph dwarf ~/bin/perf stat usleep 1
Performance counter stats for 'usleep 1':
0.443020 task-clock (msec) # 0.449 CPUs utilized
1 context-switches # 0.002 M/sec
0 cpu-migrations # 0.000 K/sec
52 page-faults # 0.117 M/sec
1,049,423 cycles # 2.369 GHz
801,456 instructions # 0.76 insn per cycle
155,609 branches # 351.246 M/sec
7,026 branch-misses # 4.52% of all branches0.000987570 seconds time elapsed
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 0.553 MB perf.data (66 samples) ]
# perf report --stdio --inline fs__get_mountpoint
<SNIP>
1.73% 0.00% perf perf [.] fs__get_mountpoint
|
---fs__get_mountpoint
fs__get_mountpoint (inline)
fs__check_mounts (inline)
__statfs
entry_SYSCALL_64
sys_statfs
SYSC_statfs
user_statfs
user_path_at_empty
filename_lookup
path_lookupat
link_path_walk
inode_permission
__inode_permission
kernfs_iop_permission
kernfs_refresh_inode
security_inode_notifysecctx
selinux_inode_notifysecctx
selinux_inode_setsecurity
security_context_to_sid
security_context_to_sid_core
string_to_context_struct
symcmp--- tools/perf/ui/stdio/hist.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-)
tools/perf/ui/stdio/hist.c +84 -1
@@ -17,6 +17,66 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)return ret; } +static size_t inline__fprintf (struct map *map,u64 ip,int left_margin, +int depth,int depth_mask,FILE *fp) +{ +struct dso *dso; +struct inline_node *node; +struct inline_list *ilist; +int ret =0 , i; + +if (map ==NULL ) +return 0 ; + + dso = map->dso; +if (dso ==NULL ) +return 0 ; + +if (dso->kernel !=DSO_TYPE_USER ) +return 0 ; + + node =dso__parse_addr_inlines (dso, +map__rip_2objdump (map, ip)); +if (node ==NULL ) +return 0 ; + +list_for_each_entry (ilist, &node->val, list) { +if ((ilist->filename !=NULL ) || (ilist->funcname !=NULL )) { + ret +=callchain__fprintf_left_margin (fp, left_margin); + +for (i =0 ; i < depth; i++) { +if (depth_mask & (1 << i)) + ret +=fprintf (fp,"|" ); +else + ret +=fprintf (fp," " ); + ret +=fprintf (fp," " ); + } + +if (callchain_param.key ==CCKEY_ADDRESS ) { +if (ilist->filename !=NULL ) + ret +=fprintf (fp,"%s:%d (inline)" , + ilist->filename, + ilist->line_nr); +else + ret +=fprintf (fp,"??" ); + }else if (ilist->funcname !=NULL ) + ret +=fprintf (fp,"%s (inline)" , + ilist->funcname); +else if (ilist->filename !=NULL ) + ret +=fprintf (fp,"%s:%d (inline)" , + ilist->filename, + ilist->line_nr); +else + ret +=fprintf (fp,"??" ); + + ret +=fprintf (fp,"\n" ); + } + } + +inline_node__delete (node); +return ret; +} +static size_t ipchain__fprintf_graph_line (FILE *fp,int depth,int depth_mask,int left_margin) {
@@ -78,6 +138,10 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,fputs (str, fp);fputc ('\n' , fp);free (alloc_str); + +if (symbol_conf.inline_name) + ret +=inline__fprintf (chain->ms.map, chain->ip, + left_margin, depth, depth_mask, fp);return ret; }
@@ -229,6 +293,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,if (!i++ && field_order ==NULL && sort_order && !prefixcmp (sort_order,"sym" ))continue ; +if (!printed) { ret +=callchain__fprintf_left_margin (fp, left_margin); ret +=fprintf (fp,"|\n" );
@@ -251,6 +316,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,if (++entries_printed == callchain_param.print_limit)break ; + +if (symbol_conf.inline_name) + ret +=inline__fprintf (chain->ms.map, + chain->ip, + left_margin, +0 ,0 , + fp); } root = &cnode->rb_root; }
@@ -529,6 +601,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, bool use_callchain) {int ret; +int callchain_ret =0 ; +int inline_ret =0 ;struct perf_hpp hpp = { .buf = bf, .size = size,
@@ -547,7 +621,16 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret =fprintf (fp,"%s\n" , bf);if (use_callchain) - ret +=hist_entry_callchain__fprintf (he, total_period,0 , fp); + callchain_ret =hist_entry_callchain__fprintf (he, total_period, +0 , fp); + +if (callchain_ret ==0 && symbol_conf.inline_name) { + inline_ret =inline__fprintf (he->ms.map, he->ip,0 ,0 ,0 , fp); + ret += inline_ret; +if (inline_ret >0 ) + ret +=fprintf (fp,"\n" ); + }else + ret += callchain_ret;return ret; }
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 11/20 perf report: Show inline stack for browser mode
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
If the address belongs to an inlined function, the source information back to the first non-inlined function will be printed.
For example:
1. Show inlined function name
perf report -g function --inline
- 0.69% 0.00% inline ld-2.23.so [.] dl_main
- dl_main
0.56% _dl_relocate_object
_dl_relocate_object (inline)
elf_dynamic_do_Rela (inline)2. Show the file/line information
perf report -g address --inline
- 0.69% 0.00% inline ld-2.23.so [.] _dl_start
_dl_start rtld.c:307
/build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline) + _dl_sysdep_start dl-sysdep.c:250
--- tools/perf/ui/browsers/hists.c | 180 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/hist.c | 5 ++ tools/perf/util/sort.h | 1 + 3 files changed, 178 insertions(+), 8 deletions(-)
tools/perf/ui/browsers/hists.c +172 -8
@@ -144,9 +144,60 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) cl->unfolded = unfold ? cl->has_children : false; } +static struct inline_node *inline_node__create (struct map *map,u64 ip) +{ +struct dso *dso; +struct inline_node *node; + +if (map ==NULL ) +return NULL ; + + dso = map->dso; +if (dso ==NULL ) +return NULL ; + +if (dso->kernel !=DSO_TYPE_USER ) +return NULL ; + + node =dso__parse_addr_inlines (dso, +map__rip_2objdump (map, ip)); + +return node; +} + +static int inline__count_rows (struct inline_node *node) +{ +struct inline_list *ilist; +int i =0 ; + +if (node ==NULL ) +return 0 ; + +list_for_each_entry (ilist, &node->val, list) { +if ((ilist->filename !=NULL ) || (ilist->funcname !=NULL )) + i++; + } + +return i; +} + +static int callchain_list__inline_rows (struct callchain_list *chain) +{ +struct inline_node *node; +int rows; + + node =inline_node__create (chain->ms.map, chain->ip); +if (node ==NULL ) +return 0 ; + + rows =inline__count_rows (node); +inline_node__delete (node); +return rows; +} +static int callchain_node__count_rows_rb_tree (struct callchain_node *node) { -int n =0 ; +int n =0 , inline_rows;struct rb_node *nd;for (nd =rb_first (&node->rb_root); nd; nd =rb_next (nd)) {
@@ -156,6 +207,13 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)list_for_each_entry (chain, &child->val, list) { ++n; + +if (symbol_conf.inline_name) { + inline_rows = +callchain_list__inline_rows (chain); + n += inline_rows; + } +/* We need this because we may not have children */ folded_sign =callchain_list__folded (chain);if (folded_sign =='+' )
@@ -207,7 +265,7 @@ static int callchain_node__count_rows(struct callchain_node *node) {struct callchain_list *chain;bool unfolded = false; -int n =0 ; +int n =0 , inline_rows;if (callchain_param.mode ==CHAIN_FLAT )return callchain_node__count_flat_rows (node);
@@ -216,6 +274,11 @@ static int callchain_node__count_rows(struct callchain_node *node)list_for_each_entry (chain, &node->val, list) { ++n; +if (symbol_conf.inline_name) { + inline_rows =callchain_list__inline_rows (chain); + n += inline_rows; + } + unfolded = chain->unfolded; }
@@ -362,6 +425,19 @@ static void hist_entry__init_have_children(struct hist_entry *he) he->init_have_children = true; } +static void hist_entry_init_inline_node (struct hist_entry *he) +{ +if (he->inline_node) +return ; + + he->inline_node =inline_node__create (he->ms.map, he->ip); + +if (he->inline_node ==NULL ) +return ; + + he->has_children = true; +} +static bool hist_browser__toggle_fold (struct hist_browser *browser) {struct hist_entry *he = browser->he_selection;
@@ -393,7 +469,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)if (he->unfolded) {if (he->leaf) - he->nr_rows =callchain__count_rows (&he->sorted_chain); +if (he->inline_node) + he->nr_rows =inline__count_rows ( + he->inline_node); +else + he->nr_rows =callchain__count_rows ( + &he->sorted_chain);else he->nr_rows =hierarchy_count_rows (browser, he, false);
@@ -753,6 +834,70 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u#define LEVEL_OFFSET_STEP 3 +static int hist_browser__show_inline (struct hist_browser *browser, +struct inline_node *node, +unsigned short row, +int offset) +{ +struct inline_list *ilist; +char buf[1024 ]; +int color, width, first_row; + + first_row = row; + width = browser->b.width - (LEVEL_OFFSET_STEP +2 ); +list_for_each_entry (ilist, &node->val, list) { +if ((ilist->filename !=NULL ) || (ilist->funcname !=NULL )) { + color =HE_COLORSET_NORMAL ; +if (ui_browser__is_current_entry (&browser->b, row)) + color =HE_COLORSET_SELECTED ; + +if (callchain_param.key ==CCKEY_ADDRESS ) { +if (ilist->filename !=NULL ) +scnprintf (buf,sizeof (buf), +"%s:%d (inline)" , + ilist->filename, + ilist->line_nr); +else +scnprintf (buf,sizeof (buf),"??" ); + }else if (ilist->funcname !=NULL ) +scnprintf (buf,sizeof (buf),"%s (inline)" , + ilist->funcname); +else if (ilist->filename !=NULL ) +scnprintf (buf,sizeof (buf), +"%s:%d (inline)" , + ilist->filename, + ilist->line_nr); +else +scnprintf (buf,sizeof (buf),"??" ); + +ui_browser__set_color (&browser->b, color); +hist_browser__gotorc (browser, row,0 ); +ui_browser__write_nstring (&browser->b," " , +LEVEL_OFFSET_STEP + offset); +ui_browser__write_nstring (&browser->b, buf, width); + row++; + } + } + +return row - first_row; +} + +static size_t show_inline_list (struct hist_browser *browser,struct map *map, +u64 ip,int row,int offset) +{ +struct inline_node *node; +int ret; + + node =inline_node__create (map, ip); +if (node ==NULL ) +return 0 ; + + ret =hist_browser__show_inline (browser, node, row, offset); + +inline_node__delete (node); +return ret; +} + static int hist_browser__show_callchain_list(struct hist_browser *browser, struct callchain_node *node, struct callchain_list *chain,
@@ -764,6 +909,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,char bf[1024 ], *alloc_str;char buf[64 ], *alloc_str2;const char *str; +int inline_rows =0 , ret =1 ;if (arg->row_offset !=0 ) { arg->row_offset--;
@@ -801,10 +947,15 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, }free (alloc_str);free (alloc_str2); -return 1 ; + +if (symbol_conf.inline_name) { + inline_rows =show_inline_list (browser, chain->ms.map, + chain->ip, row +1 , offset); + } + +return ret + inline_rows; }static bool check_percent_display (struct rb_node *node,u64 parent_total)
@@ -1228,6 +1379,12 @@ static int hist_browser__show_entry(struct hist_browser *browser, folded_sign =hist_entry__folded (entry); } +if (symbol_conf.inline_name && + (!entry->has_children)) { +hist_entry_init_inline_node (entry); + folded_sign =hist_entry__folded (entry); + } +if (row_offset ==0 ) {struct hpp_arg arg = { .b = &browser->b,
@@ -1259,7 +1416,8 @@ static int hist_browser__show_entry(struct hist_browser *browser, }if (first) { -if (symbol_conf.use_callchain) { +if (symbol_conf.use_callchain || + symbol_conf.inline_name) {ui_browser__printf (&browser->b,"%c " , folded_sign); width -=2 ; }
@@ -1301,8 +1459,14 @@ static int hist_browser__show_entry(struct hist_browser *browser, .is_current_entry = current_entry, }; - printed +=hist_browser__show_callchain (browser, entry,1 , row, - hist_browser__show_callchain_entry, &arg, +if (entry->inline_node) + printed +=hist_browser__show_inline (browser, + entry->inline_node, row,0 ); +else + printed +=hist_browser__show_callchain (browser, + entry,1 , row, + hist_browser__show_callchain_entry, + &arg, hist_browser__check_output_full); }
tools/perf/util/hist.c +5 -0
@@ -1136,6 +1136,11 @@ void hist_entry__delete(struct hist_entry *he)zfree (&he->mem_info); } +if (he->inline_node) { +inline_node__delete (he->inline_node); + he->inline_node =NULL ; + } +zfree (&he->stat_acc);free_srcline (he->srcline);if (he->srcfile && he->srcfile[0 ])
tools/perf/util/sort.h +1 -0
@@ -128,6 +128,7 @@ struct hist_entry { };char *srcline;char *srcfile; +struct inline_node *inline_node;struct symbol *parent;struct branch_info *branch_info;struct hists *hists;
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 12/20 perf report: Enable sorting by srcline as key
In reply to Arnaldo Carvalho de MeloFrom: Milian Wolff <[email protected]>
Often it is interesting to know how costly a given source line is in total. Previously, one had to build these sums manually based on all addresses that pointed to the same source line. This patch introduces srcline as a sort key, which will do the aggregation for us.
Paired with the recent addition of showing inline frames, this makes perf report much more useful for many C++ work loads.
The following shows the new feature in action. First, let's show the status quo output when we sort by address. The result contains many hist entries that generate the same output:
~~~~~~~~~~~~~~~~
$ perf report --stdio --inline -g address
# Children Self Command Shared Object Symbol
# ........ ........ ............ ................... .........................................
#
99.89% 35.34% cpp-inlining cpp-inlining [.] main
|
|--64.55%--main complex:655
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/complex:664 (inline)
| |
| |--60.31%--hypot +20
| | |
| | |--8.52%--__hypot_finite +273
| | |
| | |--7.32%--__hypot_finite +411
...
--35.34%--_start +4194346
__libc_start_main +241
|
|--6.65%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
|
|--2.70%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
|
|--1.69%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
...
~~~~~~~~~~~~~~~~With this patch and -g srcline we instead get the following output:
~~~~~~~~~~~~~~~~
$ perf report --stdio --inline -g srcline
# Children Self Command Shared Object Symbol
# ........ ........ ............ ................... .........................................
#
99.89% 35.34% cpp-inlining cpp-inlining [.] main
|
|--64.55%--main complex:655
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/complex:664 (inline)
| |
| |--64.02%--hypot
| | |
| | --59.81%--__hypot_finite
| |
| --0.53%--cabs
|
--35.34%--_start
__libc_start_main
|
|--12.48%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
...
~~~~~~~~~~~~~~~~--- tools/perf/Documentation/perf-report.txt | 1 + tools/perf/ui/browsers/hists.c | 3 +- tools/perf/ui/stdio/hist.c | 3 +- tools/perf/util/annotate.c | 3 +- tools/perf/util/callchain.c | 52 +++++++++++++++++++++++++++++--- tools/perf/util/callchain.h | 3 +- tools/perf/util/map.c | 3 +- tools/perf/util/sort.c | 16 ++++++---- tools/perf/util/srcline.c | 11 +++++-- tools/perf/util/util.h | 4 +-- 10 files changed, 78 insertions(+), 21 deletions(-)
tools/perf/Documentation/perf-report.txt +1 -0
@@ -235,6 +235,7 @@ OPTIONS sort_key can be: - function: compare on functions (default) - address: compare on individual code addresses + - srcline: compare on source filename and line number branch can be: - branch: include last branch information in callgraph when available.
tools/perf/ui/browsers/hists.c +2 -1
@@ -851,7 +851,8 @@ static int hist_browser__show_inline(struct hist_browser *browser,if (ui_browser__is_current_entry (&browser->b, row)) color =HE_COLORSET_SELECTED ; -if (callchain_param.key ==CCKEY_ADDRESS ) { +if (callchain_param.key ==CCKEY_ADDRESS || + callchain_param.key ==CCKEY_SRCLINE ) {if (ilist->filename !=NULL ) scnprintf(buf, sizeof(buf), "%s:%d (inline)",
tools/perf/ui/stdio/hist.c +2 -1
@@ -52,7 +52,8 @@ static size_t inline__fprintf(struct map *map, u64 ip, int left_margin, ret +=fprintf (fp," " ); } -if (callchain_param.key ==CCKEY_ADDRESS ) { +if (callchain_param.key ==CCKEY_ADDRESS || + callchain_param.key ==CCKEY_SRCLINE ) {if (ilist->filename !=NULL ) ret += fprintf(fp, "%s:%d (inline)", ilist->filename,
tools/perf/util/annotate.c +2 -1
@@ -1674,7 +1674,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, goto next; offset = start + i; - src_line->path =get_srcline (map->dso, offset,NULL , false); + src_line->path =get_srcline (map->dso, offset,NULL , + false, true);insert_source_line (&tmp_root, src_line); next:
tools/perf/util/callchain.c +47 -5
82 lines not on this page · raw message
tools/perf/util/callchain.h +2 -1
@@ -77,7 +77,8 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,enum chain_key {CCKEY_FUNCTION , -CCKEY_ADDRESS +CCKEY_ADDRESS , +CCKEY_SRCLINE };enum chain_value {
tools/perf/util/map.c +2 -1
@@ -405,7 +405,8 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,if (map && map->dso) { srcline =get_srcline (map->dso, -map__rip_2objdump (map, addr),NULL , true); +map__rip_2objdump (map, addr),NULL , + true, true);if (srcline !=SRCLINE_UNKNOWN ) ret =fprintf (fp,"%s%s" , prefix, srcline);free_srcline (srcline);
tools/perf/util/sort.c +10 -6
@@ -323,7 +323,7 @@ char *hist_entry__get_srcline(struct hist_entry *he)return SRCLINE_UNKNOWN ;return get_srcline (map->dso,map__rip_2objdump (map, he->ip), - he->ms.sym, true); + he->ms.sym, true, true); } static int64_t
@@ -366,7 +366,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_from =get_srcline (map->dso,map__rip_2objdump (map, left->branch_info->from.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); }if (!right->branch_info->srcline_from) {struct map *map = right->branch_info->from.map;
@@ -376,7 +377,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_from =get_srcline (map->dso,map__rip_2objdump (map, right->branch_info->from.al_addr), - right->branch_info->from.sym, true); + right->branch_info->from.sym, + true, true); }return strcmp (right->branch_info->srcline_from, left->branch_info->srcline_from); }
@@ -407,7 +409,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_to =get_srcline (map->dso,map__rip_2objdump (map, left->branch_info->to.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); }if (!right->branch_info->srcline_to) {struct map *map = right->branch_info->to.map;
@@ -417,7 +420,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_to =get_srcline (map->dso,map__rip_2objdump (map, right->branch_info->to.al_addr), - right->branch_info->to.sym, true); + right->branch_info->to.sym, + true, true); }return strcmp (right->branch_info->srcline_to, left->branch_info->srcline_to); }
@@ -448,7 +452,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e)return no_srcfile; sf =__get_srcline (map->dso,map__rip_2objdump (map, e->ip), - e->ms.sym, false, true); + e->ms.sym, false, true, true);if (!strcmp (sf,SRCLINE_UNKNOWN ))return no_srcfile; p =strchr (sf,':' );
tools/perf/util/srcline.c +8 -3
@@ -429,7 +429,7 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,#define A2L_FAIL_LIMIT 123char *__get_srcline (struct dso *dso,u64 addr,struct symbol *sym, -bool show_sym,bool unwind_inlines) +bool show_sym,bool show_addr,bool unwind_inlines) {char *file =NULL ;unsigned line =0 ;
@@ -463,6 +463,11 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, dso->has_srcline =0 ;dso__free_a2l (dso); } + +if (!show_addr) +return (show_sym && sym) ? +strndup (sym->name, sym->namelen) :NULL ; +if (sym) {if (asprintf (&srcline,"%s+%" PRIu64, show_sym ? sym->name :"" , addr - sym->start) <0 )
@@ -479,9 +484,9 @@ void free_srcline(char *srcline) }char *get_srcline (struct dso *dso,u64 addr,struct symbol *sym, -bool show_sym) +bool show_sym,bool show_addr) { -return __get_srcline (dso, addr, sym, show_sym, false); +return __get_srcline (dso, addr, sym, show_sym, show_addr, false); }struct inline_node *dso__parse_addr_inlines (struct dso *dso,u64 addr)
tools/perf/util/util.h +2 -2
@@ -287,9 +287,9 @@ struct symbol;extern bool srcline_full_filename;char *get_srcline (struct dso *dso,u64 addr,struct symbol *sym, -bool show_sym); +bool show_sym,bool show_addr);char *__get_srcline (struct dso *dso,u64 addr,struct symbol *sym, -bool show_sym,bool unwind_inlines); +bool show_sym,bool show_addr,bool unwind_inlines);void free_srcline (char *srcline);int perf_event_paranoid (void );
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 13/20 perf annotate: Fix a bug following symbolic link of a build-id file
In reply to Arnaldo Carvalho de MeloFrom: Taeung Song <[email protected]>
It is wrong way to read link name from a build-id file. Because a build-id file is not anymore a symbolic link but build-id directory of it is symbolic link, so fix it.
For example, if build-id file name gotten fromdso__build_id_filename() is as below,
/root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1/elf
To correctly read link name of build-id, use the build-id dir path that is a symbolic link, instead of the above build-id file name like below.
/root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1
--- tools/perf/util/annotate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
tools/perf/util/annotate.c +9 -1
@@ -1307,6 +1307,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil {char linkname[PATH_MAX ];char *build_id_filename; +char *build_id_path =NULL ;if (dso->symtab_type ==DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore (dso))
@@ -1322,8 +1323,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil goto fallback; } + build_id_path =strdup (filename); +if (!build_id_path) +return -1 ; + +dirname (build_id_path); +if (dso__is_kcore (dso) || -readlink (filename, linkname,sizeof (linkname)) <0 || +readlink (build_id_path, linkname,sizeof (linkname)) <0 ||strstr (linkname,DSO__NAME_KALLSYMS ) ||access (filename,R_OK )) { fallback:
@@ -1335,6 +1342,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil__symbol__join_symfs (filename, filename_size, dso->long_name); } +free (build_id_path);return 0 ; }
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 14/20 perf annotate: Fix a bug of division by zero when calculating percent
In reply to Arnaldo Carvalho de MeloFrom: Taeung Song <[email protected]>
Currently perf-annotate with --print-line can print -nan(0x8000000000000) because of division by zero when calculating percent. The division by zero happens when a sum of samples is zero in symbol__get_source_line(), so fix it.
For example:
After running 'perf record' like below,
$ perf record -e "{cycles,page-faults,branch-misses}" ./a.outBefore:
$ perf annotate --stdio -l
Sorted summary for file /home/taeung/workspace/a.out
----------------------------------------------
32.89 -nan 7.04 a.c:38
25.14 -nan 0.00 a.c:34
16.26 -nan 56.34 a.c:31
15.88 -nan 1.41 a.c:37
5.67 -nan 0.00 a.c:39
1.13 -nan 35.21 a.c:26
0.95 -nan 0.00 a.c:44
0.57 -nan 0.00 a.c:32
Percent | Source code & Disassembly of a.out for cycles (529 samples)
-----------------------------------------------------------------------------------------
:...
a.c:26 0.57 -nan 4.23 : 40081a: mov %edi,-0x24(%rbp) a.c:26 0.00 -nan 9.86 : 40081d: mov %rsi,-0x30(%rbp)
...
However, if a sum of samples is zero (e.g. 'page-faults'), skip calculating percent.
After:
$ perf annotate --stdio -l
Sorted summary for file /home/taeung/workspace/a.out
----------------------------------------------
32.89 0.00 7.04 a.c:38
25.14 0.00 0.00 a.c:34
16.26 0.00 56.34 a.c:31
15.88 0.00 1.41 a.c:37
5.67 0.00 0.00 a.c:39
1.13 0.00 35.21 a.c:26
0.95 0.00 0.00 a.c:44
0.57 0.00 0.00 a.c:32
Percent | Source code & Disassembly of old for cycles (529 samples)
-----------------------------------------------------------------------------------------
:...
a.c:26 0.57 0.00 4.23 : 40081a: mov %edi,-0x24(%rbp) a.c:26 0.00 0.00 9.86 : 40081d: mov %rsi,-0x30(%rbp)
...
--- tools/perf/util/annotate.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/annotate.c +7 -3
@@ -1671,11 +1671,15 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, src_line->nr_pcnt = nr_pcnt;for (k =0 ; k < nr_pcnt; k++) { +double percent =0.0 ; + h =annotation__histogram (notes, evidx + k); - src_line->samples[k].percent =100.0 * h->addr[i] / h->sum; +if (h->sum) + percent =100.0 * h->addr[i] / h->sum; -if (src_line->samples[k].percent > percent_max) - percent_max = src_line->samples[k].percent; +if (percent > percent_max) + percent_max = percent; + src_line->samples[k].percent = percent; }if (percent_max <=0.5 )
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 15/20 perf buildid: Do not update SDT cache with null filename
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Valgrind was complaining:
==2633== Syscall param open(filename) points to unaddressable byte(s)
==2633== at 0x5281CC0: __open_nocancel (syscall-template.S:84) ==2633== by 0x537D38: open (fcntl2.h:53) ==2633== by 0x537D38: get_sdt_note_list (symbol-elf.c:2017) ==2633== by 0x5396FD: probe_cache__scan_sdt (probe-file.c:700) ==2633== by 0x49EA2C: build_id_cache__add_sdt_cache (build-id.c:625) ==2633== by 0x49EA2C: build_id_cache__add_s (build-id.c:697) ==2633== by 0x49EE72: build_id_cache__add_b (build-id.c:717) ==2633== by 0x49EE72: dso__cache_build_id (build-id.c:782) ==2633== by 0x49F190: __dsos__cache_build_ids (build-id.c:793) ==2633== by 0x49F190: machine__cache_build_ids (build-id.c:801) ==2633== by 0x49F190: perf_session__cache_build_ids (build-id.c:815) ==2633== by 0x4CD4F2: write_build_id (header.c:165) ==2633== by 0x4D26F7: do_write_feat (header.c:2296) ==2633== by 0x4D26F7: perf_header__adds_write (header.c:2335) ==2633== by 0x4D26F7: perf_session__write_header (header.c:2414) ==2633== by 0x43B324: __cmd_record (builtin-record.c:1154) ==2633== by 0x43B324: cmd_record (builtin-record.c:1839) ==2633== by 0x455A07: __cmd_record (builtin-kmem.c:1868) ==2633== by 0x455A07: cmd_kmem (builtin-kmem.c:1944) ==2633== by 0x497150: run_builtin (perf.c:359) ==2633== by 0x428CE0: handle_internal_command (perf.c:421) ==2633== by 0x428CE0: run_argv (perf.c:467) ==2633== by 0x428CE0: main (perf.c:614)
==2633== Address 0x0 is not stack'd, malloc'd or (recently) free'd
--- tools/perf/util/build-id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/build-id.c +1 -1
@@ -690,7 +690,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, err =0 ;/* Update SDT cache : error is just warned */ -if (build_id_cache__add_sdt_cache (sbuild_id, realname) <0 ) +if (realname &&build_id_cache__add_sdt_cache (sbuild_id, realname) <0 )pr_debug4 ("Failed to update/scan SDT cache for %s\n" , realname); out_free:
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 16/20 perf buildid: Do not assume that readlink() returns a null terminated string
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Valgrind was complaining:
$ valgrind ./perf list >/dev/null ==11643== Memcheck, a memory error detector ==11643== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==11643== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==11643== Command: ./perf list ==11643== ==11643== Conditional jump or move depends on uninitialised value(s) ==11643== at 0x4C30620: rindex (vg_replace_strmem.c:199) ==11643== by 0x49DAA9: build_id_cache__origname (build-id.c:198) ==11643== by 0x49E1C7: build_id_cache__valid_id (build-id.c:222) ==11643== by 0x49E1C7: build_id_cache__list_all (build-id.c:507) ==11643== by 0x4B9C8F: print_sdt_events (parse-events.c:2067) ==11643== by 0x4BB0B3: print_events (parse-events.c:2313) ==11643== by 0x439501: cmd_list (builtin-list.c:53) ==11643== by 0x497150: run_builtin (perf.c:359) ==11643== by 0x428CE0: handle_internal_command (perf.c:421) ==11643== by 0x428CE0: run_argv (perf.c:467) ==11643== by 0x428CE0: main (perf.c:614) [...]
Additionally, a zero length result from readlink() is not very interesting.
--- tools/perf/util/build-id.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/build-id.c +5 -1
@@ -182,13 +182,17 @@ char *build_id_cache__origname(const char *sbuild_id)char buf[PATH_MAX ];char *ret =NULL , *p;size_t offs =5 ;/* == strlen("../..") */ +ssize_t len; linkname =build_id_cache__linkname (sbuild_id,NULL ,0 );if (!linkname)return NULL ; -if (readlink (linkname, buf,PATH_MAX ) <0 ) + len =readlink (linkname, buf,sizeof (buf) -1 ); +if (len <=0 ) goto out; + buf[len] ='\0' ; +/* The link should be "../..<origpath>/<sbuild_id>" */ p =strrchr (buf,'/' );/* Cut off the "/<sbuild_id>" */ if (p && (p > buf + offs)) {
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 17/20 perf tests: Do not assume that readlink() returns a null terminated string
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Ensure that the string in buf is null terminated.
--- tools/perf/tests/sdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/sdt.c +1 -1
@@ -43,7 +43,7 @@ static char *get_self_path(void) {char *buf =calloc (PATH_MAX ,sizeof (char )); -if (buf &&readlink ("/proc/self/exe" , buf,PATH_MAX ) <0 ) { +if (buf &&readlink ("/proc/self/exe" , buf,PATH_MAX -1 ) <0 ) {pr_debug ("Failed to get correct path of perf\n" );free (buf);return NULL ;
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 18/20 perf utils: use sizeof(buf) - 1 in readlink() call
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Ensure that we have space for the null byte in buf.
--- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/header.c +1 -1
@@ -378,7 +378,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,* actual atual path to perf binary */ sprintf (proc,"/proc/%d/exe" ,getpid ()); - ret =readlink (proc, buf,sizeof (buf)); + ret =readlink (proc, buf,sizeof (buf) -1 );if (ret <=0 )return -1 ;
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 19/20 perf utils: Null terminate buf in read_ftrace_printk()
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Ensure that the string that we read from the data file is null terminated.
Valgrind was complaining:
==31357== Invalid read of size 1
==31357== at 0x4EC8C1: __strtok_r_1c (string2.h:200) ==31357== by 0x4EC8C1: parse_ftrace_printk (trace-event-parse.c:161) ==31357== by 0x4F82A8: read_ftrace_printk (trace-event-read.c:204) ==31357== by 0x4F82A8: trace_report (trace-event-read.c:468) ==31357== by 0x4CD552: process_tracing_data (header.c:1576) ==31357== by 0x4D3397: perf_file_section__process (header.c:2705) ==31357== by 0x4D3397: perf_header__process_sections (header.c:2488) ==31357== by 0x4D3397: perf_session__read_header (header.c:2925) ==31357== by 0x4E71E2: perf_session__open (session.c:32) ==31357== by 0x4E71E2: perf_session__new (session.c:139) ==31357== by 0x429F5D: cmd_annotate (builtin-annotate.c:472) ==31357== by 0x497150: run_builtin (perf.c:359) ==31357== by 0x428CE0: handle_internal_command (perf.c:421) ==31357== by 0x428CE0: run_argv (perf.c:467) ==31357== by 0x428CE0: main (perf.c:614) ==31357== Address 0x8ac0efb is 0 bytes after a block of size 1,963 alloc'd ==31357== at 0x4C2DB9D: malloc (vg_replace_malloc.c:299) ==31357== by 0x4F827B: read_ftrace_printk (trace-event-read.c:195) ==31357== by 0x4F827B: trace_report (trace-event-read.c:468) ==31357== by 0x4CD552: process_tracing_data (header.c:1576) ==31357== by 0x4D3397: perf_file_section__process (header.c:2705) ==31357== by 0x4D3397: perf_header__process_sections (header.c:2488) ==31357== by 0x4D3397: perf_session__read_header (header.c:2925) ==31357== by 0x4E71E2: perf_session__open (session.c:32) ==31357== by 0x4E71E2: perf_session__new (session.c:139) ==31357== by 0x429F5D: cmd_annotate (builtin-annotate.c:472) ==31357== by 0x497150: run_builtin (perf.c:359) ==31357== by 0x428CE0: handle_internal_command (perf.c:421) ==31357== by 0x428CE0: run_argv (perf.c:467) ==31357== by 0x428CE0: main (perf.c:614)
--- tools/perf/util/trace-event-read.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/trace-event-read.c +3 -1
@@ -192,7 +192,7 @@ static int read_ftrace_printk(struct pevent *pevent)if (!size)return 0 ; - buf =malloc (size); + buf =malloc (size +1 );if (buf ==NULL )return -1 ;
@@ -201,6 +201,8 @@ static int read_ftrace_printk(struct pevent *pevent)return -1 ; } + buf[size] ='\0' ; +parse_ftrace_printk (pevent, buf, size);free (buf);
Signature · 1 line
2.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 20/20 perf utils: Readlink /proc/self/exe to find the perf binary
In reply to Arnaldo Carvalho de MeloFrom: Tommi Rantala <[email protected]>
Simplification: it is easier to open /proc/self/exe than /proc/$pid/exe.
--- tools/perf/util/header.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
tools/perf/util/header.c +2 -6
@@ -370,15 +370,11 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) {char buf[MAXPATHLEN ]; -char proc[32 ];u32 n;int i, ret; -/* -* actual atual path to perf binary -*/ -sprintf (proc,"/proc/%d/exe" ,getpid ()); - ret =readlink (proc, buf,sizeof (buf) -1 ); +/* actual path to perf binary */ + ret =readlink ("/proc/self/exe" , buf,sizeof (buf) -1 );if (ret <=0 )return -1 ;
Signature · 1 line
2.9.3
Quoted 146 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
e3a6a62400520452fe39740dca90a1d0b94b8f92:Merge tag 'perf-core-for-mingo-4.12-20170324' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/core (2017-03-24 19:37:40 +0100)are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingo-4.12-20170327for you to fetch changes up to
55f77128e7652e537d6c226d5b56821cdb5c22de:perf utils: Readlink
/proc/self/exeto find the perf binary (2017-03-27 15:37:54 -0300)----------------------------------------------------------------
perf/core improvements and fixes:New features:
- Handle inline functions in callchains (Jin Yao)
- Enable sorting by srcline as key (Milian Wolff)
Fixes:
- Fix
no_sizelogic inaddr_filter__resolve_kernel_syms()in the auxtrace code (Adrian Hunter)- Fix some thread refcount leaks in 'perf trace' (Arnaldo Carvalho de Melo)
- Fix divide by zero when calculating percent for an event in a group in the annotate by source line code (Taeung Song)
- build-id files now aren't anymore symlinks, their parent directories are, so readlink the later (Taeung Song)
- Assorted fixes for null termination problems, mostly related to readlink, detected by valgrind (Tommi Rantala)
Infrastructure:
- Make
vfs_getnameprobe point logic in 'perf trace' more robust wrt length of pathname (Arnaldo Carvalho de Melo)- Remove unused 'prefix' parameter from builtins main functions (Arnaldo Carvalho de Melo)
- Show 'perf list sdt' option in man page (Ravi Bangoria)
Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Adrian Hunter (1):
perf auxtrace: Fixno_sizelogic inaddr_filter__resolve_kernel_syms()Arnaldo Carvalho de Melo (4):
perf trace: Check for vfs_getname.pathname length perf trace: Fix up error path indentation
perf trace: Fixup thread refcounting
perf tools: Remove unused 'prefix' from builtin functionsJin Yao (5):
perf report: Refactor common code insrcline.cperf report: Find the inline stack for a given address perf report: Introduce --inline option
perf report: Show inline stack for stdio mode perf report: Show inline stack for browser modeMilian Wolff (1):
perf report: Enable sorting by srcline as keyRavi Bangoria (1):
perf list sdt: Show option in man pageTaeung Song (2):
perf annotate: Fix a bug following symbolic link of a build-id file perf annotate: Fix a bug of division by zero when calculating percentTommi Rantala (6):
perf buildid: Do not update SDT cache with null filename
perf buildid: Do not assume thatreadlink()returns a null terminated string perf tests: Do not assume thatreadlink()returns a null terminated string perf utils: use sizeof(buf) - 1 inreadlink()call
perf utils: Null terminate buf inread_ftrace_printk()
perf utils: Readlink/proc/self/exeto find the perf binarytools/perf/Documentation/perf-list.txt | 4 +- tools/perf/Documentation/perf-report.txt | 5 + tools/perf/bench/bench.h | 20 +-- tools/perf/bench/futex-hash.c | 3 +- tools/perf/bench/futex-lock-pi.c | 3 +- tools/perf/bench/futex-requeue.c | 3 +- tools/perf/bench/futex-wake-parallel.c | 3 +- tools/perf/bench/futex-wake.c | 3 +- tools/perf/bench/mem-functions.c | 4 +- tools/perf/bench/numa.c | 2 +- tools/perf/bench/sched-messaging.c | 3 +- tools/perf/bench/sched-pipe.c | 2 +- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-bench.c | 12 +- tools/perf/builtin-buildid-cache.c | 3 +- tools/perf/builtin-buildid-list.c | 3 +- tools/perf/builtin-c2c.c | 4 +- tools/perf/builtin-config.c | 2 +- tools/perf/builtin-data.c | 9 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-ftrace.c | 2 +- tools/perf/builtin-help.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kallsyms.c | 2 +- tools/perf/builtin-kmem.c | 4 +- tools/perf/builtin-kvm.c | 16 +- tools/perf/builtin-list.c | 2 +- tools/perf/builtin-lock.c | 6 +- tools/perf/builtin-mem.c | 6 +- tools/perf/builtin-probe.c | 6 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 4 +- tools/perf/builtin-sched.c | 6 +- tools/perf/builtin-script.c | 4 +- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-timechart.c | 7 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 25 ++-- tools/perf/builtin-version.c | 3 +- tools/perf/builtin.h | 58 ++++---- tools/perf/perf.c | 11 +- tools/perf/tests/builtin-test.c | 2 +- tools/perf/tests/sdt.c | 2 +- tools/perf/ui/browsers/hists.c | 181 ++++++++++++++++++++++- tools/perf/ui/stdio/hist.c | 86 ++++++++++- tools/perf/util/annotate.c | 23 ++- tools/perf/util/auxtrace.c | 4 +- tools/perf/util/build-id.c | 8 +- tools/perf/util/callchain.c | 52 ++++++- tools/perf/util/callchain.h | 3 +- tools/perf/util/header.c | 8 +- tools/perf/util/hist.c | 5 + tools/perf/util/map.c | 3 +- tools/perf/util/sort.c | 16 +-
Quoted 8 lines
tools/perf/util/sort.h | 1 + tools/perf/util/srcline.c | 246 +++++++++++++++++++++++++++---- tools/perf/util/symbol-elf.c | 5 + tools/perf/util/symbol-minimal.c | 7 + tools/perf/util/symbol.h | 5 +- tools/perf/util/trace-event-read.c | 4 +- tools/perf/util/util.h | 20 ++- 62 files changed, 739 insertions(+), 208 deletions(-)
Pulled, thanks a lot Arnaldo!
Ingo