perf/core improvements and fixes
Arnaldo Carvalho de Melo
maintainerFrom: Arnaldo Carvalho de Melo <[email protected]>
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit e53f6124af6516cee3063a3072767ee2717ff343:
Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2014-10-24 09:46:36 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
for you to fetch changes up to 8eeeb304ea2714962b10873f72aa7c5e24f5265f:
perf probe: Add --quiet option to suppress output result message (2014-10-27 17:16:34 -0200)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible:
* 'perf probe' --demangle typo fix and a new --quiet option (Masami Hiramatsu)
* Fix report -F (abort, in_tx, mispredict, etc) segfaults for sample.data files without branch info (Jiri Olsa)
* Don't open the DWARF info multiple times, keeping instead a dwfl handle in struct dso, greatly speeding up 'perf report' on powerpc. (Sukadev Bhattiprolu)
* Add patch that should have went in a previous patchkit to use global cache provided by libunwind (Namhyung Kim)
* Make CPUINFO_PROC an array to support different kernels, problem detected when the information reported via /proc/cpuinfo changed on ARM (Wang Nan)
* Introduce PARSE_OPT_DISABLED option flag and use it to avoid showing undersired options in tools that provides frontends to 'perf record', like sched, kvm, etc (Namhyung Kim)
Infrastructure:
* More Intel PT work, including a facility to export sample data (comms, threads, symbol names, etc) in a database friendly way, with an script to use this to create a postgresql database. (Adrian Hunter)
* Use make sure that thread->mg->machine points to the machine where the thread exists (it was being set only for the kmaps kernel modules case, do it as well for the mmaps) and use it to shorten function signatures (Arnaldo Carvalho de Melo)
----------------------------------------------------------------
Adrian Hunter (7):
perf pmu: Let pmu's with no events show up on perf list
perf tools: Build programs to copy 32-bit compatibility
perf tools: Add support for 32-bit compatibility VDSOs
perf tools: Do not attempt to run perf-read-vdso32 if it wasn't built perf tools: Add facility to export data in database-friendly way perf scripting python: Extend interface to export data in a database-friendly way perf script: Add Python script to export to postgresql
Arnaldo Carvalho de Melo (7):
perf tools: Set thread->mg.machine in all places
perf tools: A thread's machine can be found via thread->mg->machine
perf thread: Adopt resolve_callchain method from machine
perf callchains: Use thread->mg->machine
perf tests: Remove misplaced __maybe_unused
perf tests: Use thread->mg->machine
perf pmu: Add proper error handling to print_pmu_events()Jiri Olsa (7):
perf tools: Fix report -F abort for data without branch info perf tools: Fix report -F in_tx for data without branch info perf tools: Fix report -F mispredict for data without branch info perf tools: Fix report -F symbol_to for data without branch info perf tools: Fix report -F symbol_from for data without branch info perf tools: Fix report -F dso_to for data without branch info perf tools: Fix report -F dso_from for data without branch info
Masami Hiramatsu (2):
perf probe: Trivial typo fix for --demangle
perf probe: Add --quiet option to suppress output result message
Namhyung Kim (6):
perf tools: Add PARSE_OPT_DISABLED flag
perf tools: Export usage string and option table of perf record perf kvm: Print kvm specific --help output
perf tools: Add support for exclusive option
perf probe: Use PARSE_OPT_EXCLUSIVE flag
perf callchain: Use global caching provided by libunwind
Sukadev Bhattiprolu (1):
perf tools powerpc: Cache the DWARF debug info
Wang Nan (2):
perf tools: Ensure return negative value when write header error perf tools: Make CPUINFO_PROC an array to support different kernel versions
tools/perf/Makefile.perf | 40 ++- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 38 ++- tools/perf/builtin-inject.c | 3 +- tools/perf/builtin-kvm.c | 25 ++ tools/perf/builtin-probe.c | 67 ++-- tools/perf/builtin-record.c | 7 +- tools/perf/builtin-script.c | 8 +- tools/perf/builtin-timechart.c | 9 +- tools/perf/builtin-trace.c | 6 +- tools/perf/config/Makefile | 29 +- tools/perf/config/Makefile.arch | 8 + tools/perf/config/feature-checks/Makefile | 10 +- tools/perf/config/feature-checks/test-compile.c | 4 + tools/perf/perf-read-vdso.c | 34 ++ tools/perf/perf-sys.h | 30 +- tools/perf/perf.h | 3 + .../scripts/python/bin/export-to-postgresql-record | 8 + .../scripts/python/bin/export-to-postgresql-report | 24 ++ tools/perf/scripts/python/export-to-postgresql.py | 360 +++++++++++++++++++++ tools/perf/tests/code-reading.c | 13 +- tools/perf/tests/dwarf-unwind.c | 18 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/util/build-id.c | 3 +- tools/perf/util/callchain.c | 4 +- tools/perf/util/callchain.h | 6 +- tools/perf/util/comm.h | 4 + tools/perf/util/db-export.c | 270 ++++++++++++++++ tools/perf/util/db-export.h | 86 +++++ tools/perf/util/dso.h | 6 + tools/perf/util/event.c | 19 +- tools/perf/util/event.h | 1 - tools/perf/util/evsel.h | 2 + tools/perf/util/find-vdso-map.c | 30 ++ tools/perf/util/header.c | 34 +- tools/perf/util/machine.c | 55 ++-- tools/perf/util/machine.h | 17 +- tools/perf/util/map.c | 8 +- tools/perf/util/map.h | 4 +- tools/perf/util/parse-options.c | 78 ++++- tools/perf/util/parse-options.h | 4 + tools/perf/util/pmu.c | 41 ++- tools/perf/util/pmu.h | 1 + tools/perf/util/probe-event.c | 18 +- .../util/scripting-engines/trace-event-python.c | 292 ++++++++++++++++- tools/perf/util/session.c | 6 +- tools/perf/util/sort.c | 102 ++++-- tools/perf/util/thread.c | 9 +- tools/perf/util/thread.h | 6 +- tools/perf/util/unwind-libdw.c | 8 +- tools/perf/util/unwind-libunwind.c | 29 +- tools/perf/util/unwind.h | 5 +- tools/perf/util/vdso.c | 217 +++++++++++-- tools/perf/util/vdso.h | 4 +- 54 files changed, 1808 insertions(+), 309 deletions(-) create mode 100644 tools/perf/config/feature-checks/test-compile.c create mode 100644 tools/perf/perf-read-vdso.c create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-record create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-report create mode 100644 tools/perf/scripts/python/export-to-postgresql.py create mode 100644 tools/perf/util/db-export.c create mode 100644 tools/perf/util/db-export.h create mode 100644 tools/perf/util/find-vdso-map.c
Arnaldo Carvalho de Melo
maintainerPATCH 1/32 perf tools powerpc: Cache the DWARF debug info
From: Sukadev Bhattiprolu <[email protected]>
Cache the DWARF debug info for DSO so we don't have to rebuild it for each address in the DSO.
Note that dso__new() uses calloc() so don't need to set dso->dwfl to NULL.
$ /tmp/perf.orig --version perf version 3.18.rc1.gc2661b8 $ /tmp/perf.new --version perf version 3.18.rc1.g402d62 $ perf stat -e cycles,instructions /tmp/perf.orig report -g > orig
Performance counter stats for '/tmp/perf.orig report -g': 6,428,177,183 cycles # 0.000 GHz 4,176,288,391 instructions # 0.65 insns per cycle 1.840666132 seconds time elapsed $ perf stat -e cycles,instructions /tmp/perf.new report -g > new Performance counter stats for '/tmp/perf.new report -g': 305,773,142 cycles # 0.000 GHz 276,048,272 instructions # 0.90 insns per cycle 0.087693543 seconds time elapsed $ diff orig new $
Changelog[v2]:
[Arnaldo Carvalho] Cache in existing global objects rather than create
new static/globals in functions.
--- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 33 +++++++++++++++-------- tools/perf/util/dso.h | 1 + 2 files changed, 23 insertions(+), 11 deletions(-)
tools/perf/arch/powerpc/util/skip-callchain-idx.c +22 -11
@@ -145,7 +145,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)* yet used) * -1 in case of errors */ -static int check_return_addr (const char *exec_file,Dwarf_Addr pc) +static int check_return_addr (struct dso *dso,Dwarf_Addr pc) {int rc =-1 ;Dwfl *dwfl;
@@ -156,15 +156,27 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)Dwarf_Addr end = pc;bool signalp; - dwfl =dwfl_begin (&offline_callbacks); -if (!dwfl) { -pr_debug ("dwfl_begin() failed: %s\n" ,dwarf_errmsg (-1 )); -return -1 ; - } + dwfl = dso->dwfl; -if (dwfl_report_offline (dwfl,"" , exec_file,-1 ) ==NULL ) { -pr_debug ("dwfl_report_offline() failed %s\n" ,dwarf_errmsg (-1 )); - goto out; +if (!dwfl) { + dwfl =dwfl_begin (&offline_callbacks); +if (!dwfl) { +pr_debug ("dwfl_begin() failed: %s\n" ,dwarf_errmsg (-1 )); +return -1 ; + } + +if (dwfl_report_offline (dwfl,"" , dso->long_name,-1 ) ==NULL ) { +pr_debug ("dwfl_report_offline() failed %s\n" , +dwarf_errmsg (-1 )); +/* +* We normally cache the DWARF debug info and never +* call dwfl_end(). But to prevent fd leak, free in +* case of error. +*/ +dwfl_end (dwfl); + goto out; + } + dso->dwfl = dwfl; } mod =dwfl_addrmodule (dwfl, pc);
@@ -194,7 +206,6 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc) rc =check_return_reg (ra_regno, frame); out: -dwfl_end (dwfl);return rc; }
@@ -246,7 +257,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,return skip_slot; } - rc =check_return_addr (dso->long_name, ip); + rc =check_return_addr (dso, ip);pr_debug ("DSO %s, nr %" PRIx64", ip 0x%" PRIx64"rc %d\n" , dso->long_name, chain->nr, ip, rc);
tools/perf/util/dso.h +1 -0
@@ -127,6 +127,7 @@ struct dso {const char *long_name;u16 long_name_len;u16 short_name_len; +void *dwfl;/* DWARF debug info */ /* dso data file */ struct {
Signature · 1 line
1.9.3
Namhyung Kim
maintainerRe: [PATCH 01/32] perf tools powerpc: Cache the DWARF debug info
Hi Arnaldo and Sukadev,
Quoted 20 lines · Arnaldo Carvalho de Melo
From: Sukadev Bhattiprolu <[email protected]>
tools/perf/arch/powerpc/util/skip-callchain-idx.c +6
-8@@ -156,15 +156,27 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)Dwarf_Addr end = pc;bool signalp; - dwfl =dwfl_begin (&offline_callbacks); -if (!dwfl) { -pr_debug ("dwfl_begin() failed: %s\n" ,dwarf_errmsg (-1 )); -return -1 ; - } + dwfl = dso->dwfl; -if (dwfl_report_offline (dwfl,"" , exec_file,-1 ) ==NULL ) { -pr_debug ("dwfl_report_offline() failed %s\n" ,dwarf_errmsg (-1 )); - goto out; +if (!dwfl) { + dwfl =dwfl_begin (&offline_callbacks); +if (!dwfl) { +pr_debug ("dwfl_begin() failed: %s\n" ,dwarf_errmsg (-1 )); +return -1 ;
tools/perf/arch/powerpc/util/skip-callchain-idx.c static int check_return_addr(const char *exec_file, Dwarf_Addr pc) · line 175
Quoted 10 lines
tools/perf/arch/powerpc/util/skip-callchain-idx.c +10
-0+ } + +if (dwfl_report_offline (dwfl,"" , dso->long_name,-1 ) ==NULL ) { +pr_debug ("dwfl_report_offline() failed %s\n" , +dwarf_errmsg (-1 )); +/* +* We normally cache the DWARF debug info and never +* call dwfl_end(). But to prevent fd leak, free in +* case of error. +*/
Well, it can be freed when dso__delete() called at least. :)
tools/perf/arch/powerpc/util/skip-callchain-idx.c static int check_return_addr(const char *exec_file, Dwarf_Addr pc) · line 182
Quoted 7 lines
tools/perf/arch/powerpc/util/skip-callchain-idx.c +4
-0+dwfl_end (dwfl); + goto out; + } + dso->dwfl = dwfl; } mod =dwfl_addrmodule (dwfl, pc);
I don't know how dwfl_report_offline() can make it to find out a mod from pc as it's an (loaded) virtual address. Maybe I miss something or is your dso's are prelinked?
Thanks,
Namhyung
Quoted 29 lines
tools/perf/arch/powerpc/util/skip-callchain-idx.c +1
-2@@ -194,7 +206,6 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc) rc =check_return_reg (ra_regno, frame); out: -dwfl_end (dwfl);return rc; }@@ -246,7 +257,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,return skip_slot; } - rc =check_return_addr (dso->long_name, ip); + rc =check_return_addr (dso, ip);pr_debug ("DSO %s, nr %" PRIx64", ip 0x%" PRIx64"rc %d\n" , dso->long_name, chain->nr, ip, rc);tools/perf/util/dso.h +1
-0@@ -127,6 +127,7 @@ struct dso {const char *long_name;u16 long_name_len;u16 short_name_len; +void *dwfl;/* DWARF debug info */ /* dso data file */ struct {
Re: [PATCH 01/32] perf tools powerpc: Cache the DWARF debug info
Namhyung Kim [[email protected]] wrote:
| > + if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) {
| > + pr_debug("dwfl_report_offline() failed %s\n",
| > + dwarf_errmsg(-1));
| > + /*
| > + * We normally cache the DWARF debug info and never
| > + * call dwfl_end(). But to prevent fd leak, free in
| > + * case of error.
| > + */
|
| Well, it can be freed when dso__delete() called at least. :)Agree. Jiri Olsa also pointed that out. Plan to add that as a part of couple of other changes Jiri proposed.
| | | > + dwfl_end(dwfl); | > + goto out; | > + } | > + dso->dwfl = dwfl; | > } | > | > mod = dwfl_addrmodule(dwfl, pc); | | I don't know how dwfl_report_offline() can make it to find out a mod | from pc as it's an (loaded) virtual address. Maybe I miss something or | is your dso's are prelinked?
Scratching my head on this and a related issue.
The code seems to work consistently on Fedora20 and we recently noticed that it does not work on RHEL7. Maybe related to the issue you point out.
On Fedora20 objdump -D /usr/lib64/libc-2.18.so shows something like this:
00000080a7be3bf0 <.__random>:
80a7be3bf0: 7c 08 02 a6 mflr r0 80a7be3bf4: fb e1 ff f8 std r31,-8(r1) 80a7be3bf8: 60 00 00 00 nop 80a7be3bfc: 39 00 00 01 li r8,1 80a7be3c00: 3b e2 9a f0 addi r31,r2,-25872 80a7be3c04: 39 40 00 00 li r10,0 80a7be3c08: f8 01 00 10 std r0,16(r1) 80a7be3c0c: f8 21 ff 71 stdu r1,-144(r1) 80a7be3c10: 7d 20 f8 29 lwarx r9,0,r31,1 80a7be3c14: 7c 09 50 00 cmpw r9,r10 80a7be3c18: 40 82 00 0c bne 80a7be3c24 <.__random+0x34>
and my small test program (and perf) can use the addresses to correctly say if LR is relevant or not.
But on RHEL7, objdump shows addresses differently:
0000000000063870 <.__random>:
63870: 7c 08 02 a6 mflr r0 63874: fb e1 ff f8 std r31,-8(r1) 63878: 60 00 00 00 nop 6387c: 3b e2 9a e0 addi r31,r2,-25888 63880: 39 00 00 01 li r8,1 63884: 39 40 00 00 li r10,0 63888: f8 01 00 10 std r0,16(r1) 6388c: f8 21 ff 71 stdu r1,-144(r1) 63890: 7d 20 f8 29 lwarx r9,0,r31,1
and perf and my test program fail. Not sure if this is something related to the way it is built.
Sukadev
Namhyung Kim
maintainerRe: [PATCH 01/32] perf tools powerpc: Cache the DWARF debug info
Hi Sukadev,
Quoted 25 lines · Sukadev Bhattiprolu
Namhyung Kim [[email protected]] wrote:
| I don't know how dwfl_report_offline() can make it to find out a mod | from pc as it's an (loaded) virtual address. Maybe I miss something or | is your dso's are prelinked?Scratching my head on this and a related issue.
The code seems to work consistently on Fedora20 and we recently noticed that it does not work on RHEL7. Maybe related to the issue you point out.
On Fedora20 objdump -D
/usr/lib64/libc-2.18.soshows something like this:
00000080a7be3bf0<.__random>:80a7be3bf0: 7c 08 02 a6 mflr r0 80a7be3bf4: fb e1 ff f8 std r31,-8(r1) 80a7be3bf8: 60 00 00 00 nop 80a7be3bfc: 39 00 00 01 li r8,1 80a7be3c00: 3b e2 9a f0 addi r31,r2,-25872 80a7be3c04: 39 40 00 00 li r10,0 80a7be3c08: f8 01 00 10 std r0,16(r1) 80a7be3c0c: f8 21 ff 71 stdu r1,-144(r1) 80a7be3c10: 7d 20 f8 29 lwarx r9,0,r31,1 80a7be3c14: 7c 09 50 00 cmpw r9,r10 80a7be3c18: 40 82 00 0c bne 80a7be3c24 <.__random+0x34>
Quoted 2 lines
and my small test program (and perf) can use the addresses to correctly say if LR is relevant or not.
Looks like it's prelink'ed.
Quoted 14 lines
But on RHEL7, objdump shows addresses differently:
0000000000063870 <.__random>:
63870: 7c 08 02 a6 mflr r0 63874: fb e1 ff f8 std r31,-8(r1) 63878: 60 00 00 00 nop 6387c: 3b e2 9a e0 addi r31,r2,-25888 63880: 39 00 00 01 li r8,1 63884: 39 40 00 00 li r10,0 63888: f8 01 00 10 std r0,16(r1) 6388c: f8 21 ff 71 stdu r1,-144(r1) 63890: 7d 20 f8 29 lwarx r9,0,r31,1
Quoted 2 lines
and perf and my test program fail. Not sure if this is something related to the way it is built.
Then I think struct dso might not be a proper place to cache since a dso can be mapped to different locations/addresses and it has no idea about the location.
Maybe it's worth move the caching logic to a different place like struct thread as libunwind does now, and make it generic so that the arch's can also get the benefit when unwinding. A problem I can expect is that it will have thread x dso number of cache entries which can consume a lot of memory and fd IMHO.
Thanks,
Namhyung
Arnaldo Carvalho de Melo
maintainerPATCH 2/32 perf tools: Set thread->mg.machine in all places
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We were setting this only in machine__init(), i.e. for the map_groups that holds the kernel module maps, not for the one used for a thread's executable mmaps.
Now we are sure that we can obtain the machine where a thread is by going via thread->mg->machine, thus we can, in the following patch, make all codepaths that receive machine _and_ thread, drop the machine one.
--- tools/perf/util/machine.c | 5 ++--- tools/perf/util/map.c | 8 ++++---- tools/perf/util/map.h | 4 ++-- tools/perf/util/thread.c | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-)
tools/perf/util/machine.c +2 -3
@@ -21,7 +21,7 @@ static void dsos__init(struct dsos *dsos)int machine__init (struct machine *machine,const char *root_dir,pid_t pid) { -map_groups__init (&machine->kmaps); +map_groups__init (&machine->kmaps, machine);RB_CLEAR_NODE (&machine->rb_node);dsos__init (&machine->user_dsos);dsos__init (&machine->kernel_dsos);
@@ -32,7 +32,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->vdso_info =NULL ; - machine->kmaps.machine = machine; machine->pid = pid; machine->symbol_filter =NULL ;
@@ -319,7 +318,7 @@ static void machine__update_thread_pid(struct machine *machine, goto out_err;if (!leader->mg) - leader->mg =map_groups__new (); + leader->mg =map_groups__new (machine);if (!leader->mg) goto out_err;
tools/perf/util/map.c +4 -4
@@ -413,14 +413,14 @@ u64 map__objdump_2mem(struct map *map, u64 ip)return ip + map->reloc; } -void map_groups__init (struct map_groups *mg) +void map_groups__init (struct map_groups *mg,struct machine *machine) {int i;for (i =0 ; i <MAP__NR_TYPES ; ++i) { mg->maps[i] =RB_ROOT ;INIT_LIST_HEAD (&mg->removed_maps[i]); } - mg->machine =NULL ; + mg->machine = machine; mg->refcnt =1 ; }
@@ -471,12 +471,12 @@ bool map_groups__empty(struct map_groups *mg)return true; } -struct map_groups *map_groups__new (void ) +struct map_groups *map_groups__new (struct machine *machine) {struct map_groups *mg =malloc (sizeof (*mg));if (mg !=NULL ) -map_groups__init (mg); +map_groups__init (mg, machine);return mg; }
tools/perf/util/map.h +2 -2
@@ -64,7 +64,7 @@ struct map_groups {int refcnt; }; -struct map_groups *map_groups__new (void ); +struct map_groups *map_groups__new (struct machine *machine);void map_groups__delete (struct map_groups *mg);bool map_groups__empty (struct map_groups *mg);
@@ -150,7 +150,7 @@ void maps__remove(struct rb_root *maps, struct map *map);struct map *maps__find (struct rb_root *maps,u64 addr);struct map *maps__first (struct rb_root *maps);struct map *maps__next (struct map *map); -void map_groups__init (struct map_groups *mg); +void map_groups__init (struct map_groups *mg,struct machine *machine);void map_groups__exit (struct map_groups *mg);int map_groups__clone (struct map_groups *mg,struct map_groups *parent,enum map_type type);
tools/perf/util/thread.c +1 -1
@@ -15,7 +15,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)pid_t pid = thread->pid_;if (pid == thread->tid || pid ==-1 ) { - thread->mg =map_groups__new (); + thread->mg =map_groups__new (machine); }else { leader =machine__findnew_thread (machine, pid, pid);if (leader)
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 3/32 perf tools: A thread's machine can be found via thread->mg->machine
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
So stop passing both machine and thread to several thread methods, reducing function signature length.
--- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 5 ++-- tools/perf/builtin-inject.c | 3 +- tools/perf/builtin-script.c | 7 ++--- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-trace.c | 6 ++-- tools/perf/tests/code-reading.c | 3 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/util/build-id.c | 3 +- tools/perf/util/callchain.h | 6 ++-- tools/perf/util/event.c | 19 ++++++------ tools/perf/util/event.h | 1 - tools/perf/util/machine.c | 35 +++++++++-------------- tools/perf/util/thread.c | 4 +-- tools/perf/util/thread.h | 5 ++-- tools/perf/util/unwind-libdw.c | 4 +-- tools/perf/util/unwind-libunwind.c | 13 ++++----- 16 files changed, 48 insertions(+), 70 deletions(-)
tools/perf/arch/powerpc/util/skip-callchain-idx.c +2 -3
@@ -232,8 +232,7 @@ out:* index: of callchain entry that needs to be ignored (if any) * -1 if no entry needs to be ignored or in case of errors */ -int arch_skip_callchain_idx (struct machine *machine,struct thread *thread, -struct ip_callchain *chain) +int arch_skip_callchain_idx (struct thread *thread,struct ip_callchain *chain) {struct addr_location al;struct dso *dso =NULL ;
@@ -246,7 +245,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread, ip = chain->ips[2 ]; -thread__find_addr_location (thread, machine,PERF_RECORD_MISC_USER , +thread__find_addr_location (thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , ip, &al);if (al.map)
tools/perf/builtin-inject.c +1 -2
@@ -217,8 +217,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, goto repipe; } -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->ip, &al); +thread__find_addr_map (thread, cpumode,MAP__FUNCTION , sample->ip, &al);if (al.map !=NULL ) {if (!al.map->dso->hit) {
tools/perf/builtin-script.c +3 -4
@@ -379,7 +379,6 @@ static void print_sample_start(struct perf_sample *sample,static void print_sample_addr (union perf_event *event,struct perf_sample *sample, -struct machine *machine,struct thread *thread,struct perf_event_attr *attr) {
@@ -390,7 +389,7 @@ static void print_sample_addr(union perf_event *event,if (!sample_addr_correlates_sym (attr))return ; -perf_event__preprocess_sample_addr (event, sample, machine, thread, &al); +perf_event__preprocess_sample_addr (event, sample, thread, &al);if (PRINT_FIELD (SYM )) {printf (" " );
@@ -438,7 +437,7 @@ static void print_sample_bts(union perf_event *event, ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && !output[attr->type].user_set)) {printf (" => " ); -print_sample_addr (event, sample, al->machine, thread, attr); +print_sample_addr (event, sample, thread, attr); }if (print_srcline_last)
@@ -475,7 +474,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,event_format__print (evsel->tp_format, sample->cpu, sample->raw_data, sample->raw_size);if (PRINT_FIELD (ADDR )) -print_sample_addr (event, sample, al->machine, thread, attr); +print_sample_addr (event, sample, thread, attr);if (PRINT_FIELD (IP )) {if (!symbol_conf.use_callchain)
tools/perf/builtin-timechart.c +1 -1
@@ -528,7 +528,7 @@ static const char *cat_backtrace(union perf_event *event, } tal.filtered =0 ; -thread__find_addr_location (al.thread, machine, cpumode, +thread__find_addr_location (al.thread, cpumode,MAP__FUNCTION , ip, &tal);if (tal.sym)
tools/perf/builtin-trace.c +3 -3
@@ -1846,7 +1846,7 @@ static int trace__pgfault(struct trace *trace,if (trace->summary_only)return 0 ; -thread__find_addr_location (thread, trace->host, cpumode,MAP__FUNCTION , +thread__find_addr_location (thread, cpumode,MAP__FUNCTION , sample->ip, &al);trace__fprintf_entry_head (trace, thread,0 , sample->time, trace->output);
@@ -1859,11 +1859,11 @@ static int trace__pgfault(struct trace *trace,fprintf (trace->output,"] => " ); -thread__find_addr_location (thread, trace->host, cpumode,MAP__VARIABLE , +thread__find_addr_location (thread, cpumode,MAP__VARIABLE , sample->addr, &al);if (!al.map) { -thread__find_addr_location (thread, trace->host, cpumode, +thread__find_addr_location (thread, cpumode,MAP__FUNCTION , sample->addr, &al);if (al.map)
tools/perf/tests/code-reading.c +1 -2
@@ -145,8 +145,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,pr_debug ("Reading object code for memory address: %#" PRIx64"\n" , addr); -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , addr, - &al); +thread__find_addr_map (thread, cpumode,MAP__FUNCTION , addr, &al);if (!al.map || !al.map->dso) {pr_debug ("thread__find_addr_map failed\n" );return -1 ;
tools/perf/tests/mmap-thread-lookup.c +1 -1
@@ -187,7 +187,7 @@ static int mmap_events(synth_cb synth)pr_debug ("looking for map %p\n" , td->map); -thread__find_addr_map (thread, machine, +thread__find_addr_map (thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , (unsigned long ) (td->map +1 ), &al);
tools/perf/util/build-id.c +1 -2
@@ -33,8 +33,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,return -1 ; } -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->ip, &al); +thread__find_addr_map (thread, cpumode,MAP__FUNCTION , sample->ip, &al);if (al.map !=NULL ) al.map->dso->hit =1 ;
tools/perf/util/callchain.h +2 -4
@@ -184,11 +184,9 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, }#ifdef HAVE_SKIP_CALLCHAIN_IDX -extern int arch_skip_callchain_idx (struct machine *machine, -struct thread *thread,struct ip_callchain *chain); +extern int arch_skip_callchain_idx (struct thread *thread,struct ip_callchain *chain);#else -static inline int arch_skip_callchain_idx (struct machine *machine__maybe_unused , -struct thread *thread__maybe_unused , +static inline int arch_skip_callchain_idx (struct thread *thread__maybe_unused ,struct ip_callchain *chain__maybe_unused ) {return -1 ;
tools/perf/util/event.c +8 -11
@@ -730,12 +730,12 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,return machine__process_event (machine, event, sample); } -void thread__find_addr_map (struct thread *thread, -struct machine *machine,u8 cpumode, +void thread__find_addr_map (struct thread *thread,u8 cpumode,enum map_type type,u64 addr,struct addr_location *al) {struct map_groups *mg = thread->mg; +struct machine *machine = mg->machine;bool load_map = false; al->machine = machine;
@@ -806,14 +806,14 @@ try_again: } } -void thread__find_addr_location (struct thread *thread,struct machine *machine, +void thread__find_addr_location (struct thread *thread,u8 cpumode,enum map_type type,u64 addr,struct addr_location *al) { -thread__find_addr_map (thread, machine, cpumode, type, addr, al); +thread__find_addr_map (thread, cpumode, type, addr, al);if (al->map !=NULL ) al->sym =map__find_symbol (al->map, al->addr, - machine->symbol_filter); + thread->mg->machine->symbol_filter);else al->sym =NULL ; }
@@ -842,8 +842,7 @@ int perf_event__preprocess_sample(const union perf_event *event, machine->vmlinux_maps[MAP__FUNCTION] == NULL)machine__create_kernel_maps (machine); -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->ip, al); +thread__find_addr_map (thread, cpumode,MAP__FUNCTION , sample->ip, al);dump_printf (" ...... dso: %s\n" , al->map ? al->map->dso->long_name : al->level =='H' ?"[hypervisor]" :"<not found>" );
@@ -902,16 +901,14 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)void perf_event__preprocess_sample_addr (union perf_event *event,struct perf_sample *sample, -struct machine *machine,struct thread *thread,struct addr_location *al) {u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->addr, al); +thread__find_addr_map (thread, cpumode,MAP__FUNCTION , sample->addr, al);if (!al->map) -thread__find_addr_map (thread, machine, cpumode,MAP__VARIABLE , +thread__find_addr_map (thread, cpumode,MAP__VARIABLE , sample->addr, al); al->cpu = sample->cpu;
tools/perf/util/event.h +0 -1
@@ -322,7 +322,6 @@ bool is_bts_event(struct perf_event_attr *attr);bool sample_addr_correlates_sym (struct perf_event_attr *attr);void perf_event__preprocess_sample_addr (union perf_event *event,struct perf_sample *sample, -struct machine *machine,struct thread *thread,struct addr_location *al);
tools/perf/util/machine.c +14 -21
@@ -1289,7 +1289,7 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)return 0 ; } -static void ip__resolve_ams (struct machine *machine,struct thread *thread, +static void ip__resolve_ams (struct thread *thread,struct addr_map_symbol *ams,u64 ip) {
@@ -1303,7 +1303,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,* Thus, we have to try consecutively until we find a match * or else, the symbol is unknown */ -thread__find_cpumode_addr_location (thread, machine,MAP__FUNCTION , ip, &al); +thread__find_cpumode_addr_location (thread,MAP__FUNCTION , ip, &al); ams->addr = ip; ams->al_addr = al.addr;
@@ -1311,23 +1311,21 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, ams->map = al.map; } -static void ip__resolve_data (struct machine *machine,struct thread *thread, +static void ip__resolve_data (struct thread *thread,u8 m,struct addr_map_symbol *ams,u64 addr) {struct addr_location al;memset (&al,0 ,sizeof (al)); -thread__find_addr_location (thread, machine, m,MAP__VARIABLE , addr, - &al); +thread__find_addr_location (thread, m,MAP__VARIABLE , addr, &al);if (al.map ==NULL ) {/* * some shared data regions have execute bit set which puts * their mapping in the MAP__FUNCTION type array. * Check there as a fallback option before dropping the sample. */ -thread__find_addr_location (thread, machine, m,MAP__FUNCTION , addr, - &al); +thread__find_addr_location (thread, m,MAP__FUNCTION , addr, &al); } ams->addr = addr;
@@ -1344,9 +1342,8 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,if (!mi)return NULL ; -ip__resolve_ams (al->machine, al->thread, &mi->iaddr, sample->ip); -ip__resolve_data (al->machine, al->thread, al->cpumode, - &mi->daddr, sample->addr); +ip__resolve_ams (al->thread, &mi->iaddr, sample->ip); +ip__resolve_data (al->thread, al->cpumode, &mi->daddr, sample->addr); mi->data_src.val = sample->data_src;return mi;
@@ -1363,15 +1360,14 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,return NULL ;for (i =0 ; i < bs->nr; i++) { -ip__resolve_ams (al->machine, al->thread, &bi[i].to, bs->entries[i].to); -ip__resolve_ams (al->machine, al->thread, &bi[i].from, bs->entries[i].from); +ip__resolve_ams (al->thread, &bi[i].to, bs->entries[i].to); +ip__resolve_ams (al->thread, &bi[i].from, bs->entries[i].from); bi[i].flags = bs->entries[i].flags; }return bi; } -static int machine__resolve_callchain_sample(struct machine *machine, - struct thread *thread, +static int thread__resolve_callchain_sample(struct thread *thread, struct ip_callchain *chain, struct symbol **parent, struct addr_location *root_al,
@@ -1395,7 +1391,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,* Based on DWARF debug information, some architectures skip * a callchain entry saved by the kernel. */ - skip_idx =arch_skip_callchain_idx (machine, thread, chain); + skip_idx =arch_skip_callchain_idx (thread, chain);for (i =0 ; i < chain_nr; i++) {u64 ip;
@@ -1437,7 +1433,7 @@ static int machine__resolve_callchain_sample(struct machine *machine, } al.filtered =0 ; -thread__find_addr_location (thread, machine, cpumode, +thread__find_addr_location (thread, cpumode,MAP__FUNCTION , ip, &al);if (al.sym !=NULL ) { if (sort__has_parent && !*parent &&
@@ -1476,11 +1472,8 @@ int machine__resolve_callchain(struct machine *machine,struct addr_location *root_al, int max_stack) { - int ret; - - ret =machine__resolve_callchain_sample (machine, thread, - sample->callchain, parent, - root_al, max_stack); + int ret = thread__resolve_callchain_sample(thread, sample->callchain, + parent, root_al, max_stack);if (ret)return ret;
tools/perf/util/thread.c +1 -3
@@ -195,7 +195,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) }void thread__find_cpumode_addr_location (struct thread *thread, -struct machine *machine,enum map_type type,u64 addr,struct addr_location *al) {
@@ -208,8 +207,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, };for (i =0 ; i <ARRAY_SIZE (cpumodes); i++) { -thread__find_addr_location (thread, machine, cpumodes[i], type, - addr, al); +thread__find_addr_location (thread, cpumodes[i], type, addr, al);if (al->map)break ; }
tools/perf/util/thread.h +2 -3
@@ -54,16 +54,15 @@ void thread__insert_map(struct thread *thread, struct map *map);int thread__fork (struct thread *thread,struct thread *parent,u64 timestamp);size_t thread__fprintf (struct thread *thread,FILE *fp); -void thread__find_addr_map (struct thread *thread,struct machine *machine, +void thread__find_addr_map (struct thread *thread,u8 cpumode,enum map_type type,u64 addr,struct addr_location *al); -void thread__find_addr_location (struct thread *thread,struct machine *machine, +void thread__find_addr_location (struct thread *thread,u8 cpumode,enum map_type type,u64 addr,struct addr_location *al);void thread__find_cpumode_addr_location (struct thread *thread, -struct machine *machine,enum map_type type,u64 addr,struct addr_location *al);
tools/perf/util/unwind-libdw.c +2 -2
@@ -26,7 +26,7 @@ static int __report_module(struct addr_location *al, u64 ip,Dwfl_Module *mod;struct dso *dso =NULL ; -thread__find_addr_location (ui->thread, ui->machine, +thread__find_addr_location (ui->thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , ip, al);
@@ -89,7 +89,7 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,struct addr_location al;ssize_t size; -thread__find_addr_map (ui->thread, ui->machine,PERF_RECORD_MISC_USER , +thread__find_addr_map (ui->thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , addr, &al);if (!al.map) {pr_debug ("unwind: no map for %lx\n" , (unsigned long )addr);
tools/perf/util/unwind-libunwind.c +6 -7
@@ -284,7 +284,7 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui) {struct addr_location al; -thread__find_addr_map (ui->thread, ui->machine,PERF_RECORD_MISC_USER , +thread__find_addr_map (ui->thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , ip, &al);return al.map; }
@@ -374,7 +374,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,struct addr_location al;ssize_t size; -thread__find_addr_map (ui->thread, ui->machine,PERF_RECORD_MISC_USER , +thread__find_addr_map (ui->thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , addr, &al);if (!al.map) {pr_debug ("unwind: no map for %lx\n" , (unsigned long )addr);
@@ -476,14 +476,13 @@ static void put_unwind_info(unw_addr_space_t __maybe_unused as,pr_debug ("unwind: put_unwind_info called\n" ); } -static int entry (u64 ip,struct thread *thread,struct machine *machine, +static int entry (u64 ip,struct thread *thread,unwind_entry_cb_t cb,void *arg) {struct unwind_entry e;struct addr_location al; -thread__find_addr_location (thread, machine, -PERF_RECORD_MISC_USER , +thread__find_addr_location (thread,PERF_RECORD_MISC_USER ,MAP__FUNCTION , ip, &al); e.ip = ip;
@@ -574,7 +573,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,unw_word_t ip;unw_get_reg (&c,UNW_REG_IP , &ip); - ret = ip ?entry (ip, ui->thread, ui->machine, cb, arg) :0 ; + ret = ip ?entry (ip, ui->thread, cb, arg) :0 ; }return ret;
@@ -599,7 +598,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,if (ret)return ret; - ret =entry (ip, thread, machine, cb, arg); + ret =entry (ip, thread, cb, arg);if (ret)return -ENOMEM ;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 4/32 perf thread: Adopt resolve_callchain method from machine
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Shortening function signature lenght too, since a thread's machine can be obtained from thread->mg->machine, no need to pass thread, machine.
--- tools/perf/util/callchain.c | 4 ++-- tools/perf/util/machine.c | 15 +++++++-------- tools/perf/util/machine.h | 13 ++++++------- tools/perf/util/scripting-engines/trace-event-python.c | 6 +++--- tools/perf/util/session.c | 6 +++--- 5 files changed, 21 insertions(+), 23 deletions(-)
tools/perf/util/callchain.c +2 -2
@@ -754,8 +754,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentif (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || sort__has_parent) { -return machine__resolve_callchain (al->machine, evsel, al->thread, - sample, parent, al, max_stack); +return thread__resolve_callchain (al->thread, evsel, sample, + parent, al, max_stack); }return 0 ; }
tools/perf/util/machine.c +7 -8
@@ -1464,13 +1464,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) entry->map, entry->sym); } -int machine__resolve_callchain (struct machine *machine, -struct perf_evsel *evsel, -struct thread *thread, -struct perf_sample *sample, -struct symbol **parent, -struct addr_location *root_al, -int max_stack) +int thread__resolve_callchain (struct thread *thread, +struct perf_evsel *evsel, +struct perf_sample *sample, +struct symbol **parent, +struct addr_location *root_al, +int max_stack) {int ret =thread__resolve_callchain_sample (thread, sample->callchain, parent, root_al, max_stack);
@@ -1487,7 +1486,7 @@ int machine__resolve_callchain(struct machine *machine, (!sample->user_stack.size))return 0 ; -return unwind__get_entries (unwind_entry, &callchain_cursor, machine, +return unwind__get_entries (unwind_entry, &callchain_cursor, thread->mg->machine, thread, sample, max_stack); }
tools/perf/util/machine.h +6 -7
@@ -122,13 +122,12 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, struct addr_location *al);struct mem_info *sample__resolve_mem (struct perf_sample *sample,struct addr_location *al); -int machine__resolve_callchain (struct machine *machine, -struct perf_evsel *evsel, -struct thread *thread, -struct perf_sample *sample, -struct symbol **parent, -struct addr_location *root_al, -int max_stack); +int thread__resolve_callchain (struct thread *thread, +struct perf_evsel *evsel, +struct perf_sample *sample, +struct symbol **parent, +struct addr_location *root_al, +int max_stack);/* * Default guest kernel is defined by parameter --guestkallsyms
tools/perf/util/scripting-engines/trace-event-python.c +3 -3
@@ -312,9 +312,9 @@ static PyObject *python_process_callchain(struct perf_sample *sample,if (!symbol_conf.use_callchain || !sample->callchain) goto exit; -if (machine__resolve_callchain (al->machine, evsel, al->thread, - sample,NULL ,NULL , -PERF_MAX_STACK_DEPTH ) !=0 ) { +if (thread__resolve_callchain (al->thread, evsel, + sample,NULL ,NULL , +PERF_MAX_STACK_DEPTH ) !=0 ) {pr_err ("Failed to resolve callchain. Skipping\n" ); goto exit; }
tools/perf/util/session.c +3 -3
@@ -1417,9 +1417,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,if (symbol_conf.use_callchain && sample->callchain) {struct addr_location node_al; -if (machine__resolve_callchain (al->machine, evsel, al->thread, - sample,NULL ,NULL , -PERF_MAX_STACK_DEPTH ) !=0 ) { +if (thread__resolve_callchain (al->thread, evsel, + sample,NULL ,NULL , +PERF_MAX_STACK_DEPTH ) !=0 ) {if (verbose)error ("Failed to resolve callchain. Skipping\n" );return ;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 5/32 perf callchains: Use thread->mg->machine
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The unwind__get_entries() already receives the thread parameter, from where it can obtain the matching machine structure, shorten the signature.
--- tools/perf/tests/dwarf-unwind.c | 18 +++++++++--------- tools/perf/util/machine.c | 2 +- tools/perf/util/unwind-libdw.c | 4 ++-- tools/perf/util/unwind-libunwind.c | 4 ++-- tools/perf/util/unwind.h | 2 -- 5 files changed, 14 insertions(+), 16 deletions(-)
tools/perf/tests/dwarf-unwind.c +9 -9
@@ -59,7 +59,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) } __attribute__ ((noinline)) -static int unwind_thread (struct thread *thread,struct machine *machine) +static int unwind_thread (struct thread *thread) {struct perf_sample sample;unsigned long cnt =0 ;
@@ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine) goto out; } - err =unwind__get_entries (unwind_entry, &cnt, machine, thread, + err =unwind__get_entries (unwind_entry, &cnt, thread, &sample,MAX_STACK );if (err)pr_debug ("unwind failed\n" );
@@ -89,21 +89,21 @@ static int unwind_thread(struct thread *thread, struct machine *machine) } __attribute__ ((noinline)) -static int krava_3 (struct thread *thread,struct machine *machine) +static int krava_3 (struct thread *thread) { -return unwind_thread (thread, machine); +return unwind_thread (thread); } __attribute__ ((noinline)) -static int krava_2 (struct thread *thread,struct machine *machine) +static int krava_2 (struct thread *thread) { -return krava_3 (thread, machine); +return krava_3 (thread); } __attribute__ ((noinline)) -static int krava_1 (struct thread *thread,struct machine *machine) +static int krava_1 (struct thread *thread) { -return krava_2 (thread, machine); +return krava_2 (thread); }int test__dwarf_unwind (void )
@@ -137,7 +137,7 @@ int test__dwarf_unwind(void) goto out; } - err =krava_1 (thread, machine); + err =krava_1 (thread); out:machine__delete_threads (machine);
tools/perf/util/machine.c +1 -1
@@ -1486,7 +1486,7 @@ int thread__resolve_callchain(struct thread *thread, (!sample->user_stack.size))return 0 ; -return unwind__get_entries (unwind_entry, &callchain_cursor, thread->mg->machine, +return unwind__get_entries (unwind_entry, &callchain_cursor, thread, sample, max_stack); }
tools/perf/util/unwind-libdw.c +2 -2
@@ -164,14 +164,14 @@ frame_callback(Dwfl_Frame *state, void *arg) }int unwind__get_entries (unwind_entry_cb_t cb,void *arg, -struct machine *machine,struct thread *thread, +struct thread *thread,struct perf_sample *data,int max_stack) {struct unwind_info ui = { .sample = data, .thread = thread, - .machine = machine, + .machine = thread->mg->machine, .cb = cb, .arg = arg, .max_stack = max_stack,
tools/perf/util/unwind-libunwind.c +2 -2
@@ -580,14 +580,14 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, }int unwind__get_entries (unwind_entry_cb_t cb,void *arg, -struct machine *machine,struct thread *thread, +struct thread *thread,struct perf_sample *data,int max_stack) {u64 ip;struct unwind_info ui = { .sample = data, .thread = thread, - .machine = machine, + .machine = thread->mg->machine, };int ret;
tools/perf/util/unwind.h +0 -2
@@ -16,7 +16,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);#ifdef HAVE_DWARF_UNWIND_SUPPORT int unwind__get_entries (unwind_entry_cb_t cb,void *arg, -struct machine *machine,struct thread *thread,struct perf_sample *data,int max_stack);/* libunwind specific */
@@ -36,7 +35,6 @@ static inline void unwind__finish_access(struct thread *thread __maybe_unused) {static inline int unwind__get_entries (unwind_entry_cb_t cb__maybe_unused ,void *arg__maybe_unused , -struct machine *machine__maybe_unused ,struct thread *thread__maybe_unused ,struct perf_sample *data__maybe_unused ,int max_stack__maybe_unused )
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 6/32 perf tests: Remove misplaced __maybe_unused
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The 'machine' parameter is used in this function, ditch the __maybe_unused annotation, not needed.
--- tools/perf/tests/hists_filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/hists_filter.c +1 -1
@@ -43,7 +43,7 @@ static struct sample fake_samples[] = { };static int add_hist_entries (struct perf_evlist *evlist, -struct machine *machine__maybe_unused ) +struct machine *machine) {struct perf_evsel *evsel;struct addr_location al;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 7/32 perf tests: Use thread->mg->machine
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Instead of passing both thread and machine.
--- tools/perf/tests/code-reading.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
tools/perf/tests/code-reading.c +4 -6
@@ -133,8 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, }static int read_object_code (u64 addr,size_t len,u8 cpumode, -struct thread *thread,struct machine *machine, -struct state *state) +struct thread *thread,struct state *state) {struct addr_location al;unsigned char buf1[BUFSZ ];
@@ -169,8 +168,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len = al.map->end - addr;/* Read the object code using perf */ - ret_len =dso__data_read_offset (al.map->dso, machine, al.addr, buf1, - len); + ret_len =dso__data_read_offset (al.map->dso, thread->mg->machine, + al.addr, buf1, len);if (ret_len != len) {pr_debug ("dso__data_read_offset failed\n" );return -1 ;
@@ -263,8 +262,7 @@ static int process_sample_event(struct machine *machine, cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -return read_object_code (sample.ip,READLEN , cpumode, thread, machine, - state); +return read_object_code (sample.ip,READLEN , cpumode, thread, state); } static int process_event(struct machine *machine, struct perf_evlist *evlist,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 8/32 perf tools: Add PARSE_OPT_DISABLED flag
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
In some cases, we need to reuse exising options with some of them disabled. To do that, add PARSE_OPT_DISABLED flag and set_option_flag() function.
--- tools/perf/util/parse-options.c | 17 +++++++++++++++++ tools/perf/util/parse-options.h | 2 ++ 2 files changed, 19 insertions(+)
tools/perf/util/parse-options.c +17 -0
@@ -42,6 +42,8 @@ static int get_value(struct parse_opt_ctx_t *p,return opterror (opt,"takes no value" , flags);if (unset && (opt->flags &PARSE_OPT_NONEG ))return opterror (opt,"isn't available" , flags); +if (opt->flags &PARSE_OPT_DISABLED ) +return opterror (opt,"is not usable" , flags);if (!(flags &OPT_SHORT ) && p->opt) {switch (opt->type) {
@@ -509,6 +511,8 @@ static void print_option_help(const struct option *opts, int full) }if (!full && (opts->flags &PARSE_OPT_HIDDEN ))return ; +if (opts->flags &PARSE_OPT_DISABLED ) +return ; pos =fprintf (stderr," " );if (opts->short_name)
@@ -679,3 +683,16 @@ int parse_opt_verbosity_cb(const struct option *opt, }return 0 ; } + +void set_option_flag (struct option *opts,int shortopt,const char *longopt, +int flag) +{ +for (; opts->type !=OPTION_END ; opts++) { +if ((shortopt && opts->short_name == shortopt) || + (opts->long_name && longopt && + !strcmp (opts->long_name, longopt))) { + opts->flags |= flag; +break ; + } + } +}
tools/perf/util/parse-options.h +2 -0
@@ -38,6 +38,7 @@ enum parse_opt_option_flags {PARSE_OPT_NONEG =4 ,PARSE_OPT_HIDDEN =8 ,PARSE_OPT_LASTARG_DEFAULT =16 , + PARSE_OPT_DISABLED = 32, };struct option ;
@@ -211,4 +212,5 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);extern const char *parse_options_fix_filename (const char *prefix,const char *file); +void set_option_flag (struct option *opts,int sopt,const char *lopt,int flag);#endif /* __PERF_PARSE_OPTIONS_H */
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 9/32 perf tools: Export usage string and option table of perf record
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Those are shared with other builtin commands like kvm, script. So make it accessable from them. This is a preparation of later change that limiting possible options.
--- tools/perf/builtin-record.c | 7 +++++-- tools/perf/builtin-script.c | 1 - tools/perf/builtin-timechart.c | 7 ++++--- tools/perf/perf.h | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-)
tools/perf/builtin-record.c +5 -2
@@ -680,11 +680,12 @@ static int perf_record_config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static const char *const record_usage[] = { +static const char *const __record_usage[] = {"perf record [<options>] [<command>]" ,"perf record [<options>] -- <command> [<options>]" ,NULL }; +const char *const *record_usage = __record_usage;/* * XXX Ideally would be local to cmd_record() and passed to a record__new
@@ -725,7 +726,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp";* perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', * using pipes, etc. */ -const struct option record_options[] = { +struct option __record_options[] = {OPT_CALLBACK ('e' ,"event" , &record.evlist,"event" ,"event selector. use 'perf list' to list available events" , parse_events_option),
@@ -802,6 +803,8 @@ const struct option record_options[] = { OPT_END() }; +struct option *record_options = __record_options; +int cmd_record (int argc,const char **argv,const char *prefix__maybe_unused ) {int err = -ENOMEM ;
tools/perf/builtin-script.c +0 -1
@@ -23,7 +23,6 @@ static char const *generate_script_lang;static bool debug_mode;static u64 last_timestamp;static u64 nr_unordered; -extern const struct option record_options[];static bool no_callchain;static bool latency_format;static bool system_wide;
tools/perf/builtin-timechart.c +4 -3
@@ -1963,7 +1963,7 @@ int cmd_timechart(int argc, const char **argv,NULL }; -const struct option record_options[] = { +const struct option timechart_record_options[] = {OPT_BOOLEAN ('P' ,"power-only" , &tchart.power_only,"output power data only" ),OPT_BOOLEAN ('T' ,"tasks-only" , &tchart.tasks_only,"output processes data only" ),
@@ -1972,7 +1972,7 @@ int cmd_timechart(int argc, const char **argv,OPT_BOOLEAN ('g' ,"callchain" , &tchart.with_backtrace,"record callchain" ), OPT_END() }; -const char *const record_usage[] = { +const char *const timechart_record_usage[] = {"perf timechart record [<options>]" ,NULL };
@@ -1985,7 +1985,8 @@ int cmd_timechart(int argc, const char **argv, }if (argc && !strncmp (argv[0 ],"rec" ,3 )) { - argc =parse_options (argc, argv, record_options, record_usage, + argc =parse_options (argc, argv, timechart_record_options, + timechart_record_usage,PARSE_OPT_STOP_AT_NON_OPTION );if (tchart.power_only && tchart.tasks_only) {
tools/perf/perf.h +3 -0
@@ -62,4 +62,7 @@ struct record_opts { unsigned initial_delay; }; +struct option ; +extern const char *const *record_usage; +extern struct option *record_options;#endif
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 10/32 perf kvm: Print kvm specific --help output
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The 'perf kvm stat record' tool is an alias of 'perf record' with predefined kvm related options. All options that passed to 'perf kvm stat record' are processed by the 'perf record' tool. So, 'perf kvm stat record --help' prints help of usage for the 'perf record' command. There are a few options useful for 'perf kvm stat record', the rest either break kvm related output or don't change it.
Let's print safe for 'perf kvm stat record' options in addition to general 'perf record' --help output.
With this patch, new output looks like below:
$ perf kvm stat record -h
usage: perf kvm stat record [<options>]
-p, --pid <pid> record events on existing process id
-t, --tid <tid> record events on existing thread id
-r, --realtime <n> collect data with this RT SCHED_FIFO priority
--no-buffering collect data without buffering
-a, --all-cpus system-wide collection from all CPUs
-C, --cpu <cpu> list of cpus to monitor
-c, --count <n> event period to sample
-o, --output <file> output file name
-i, --no-inherit child tasks do not inherit counters -m, --mmap-pages <pages>
number of mmap data pages
-v, --verbose be more verbose (show counter open errors, etc)
-q, --quiet don't print any message
-s, --stat per thread counts
-D, --delay <n> ms to wait before starting measurement after program start
-u, --uid <user> user to profile
--per-thread use per-thread mmaps
$ perf kvm stat record -n sleep 1
Error: switch `n' is not usableusage: perf kvm stat record [<options>]
--- tools/perf/builtin-kvm.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
tools/perf/builtin-kvm.c +25 -0
@@ -1132,6 +1132,10 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)"-m" ,"1024" , "-c", "1", }; +const char *const kvm_stat_record_usage[] = { +"perf kvm stat record [<options>]" , +NULL + };const char *const *events_tp; events_tp_size =0 ;
@@ -1159,6 +1163,27 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)for (j =1 ; j < (unsigned int )argc; j++, i++) rec_argv[i] = argv[j]; +set_option_flag (record_options,'e' ,"event" ,PARSE_OPT_HIDDEN ); +set_option_flag (record_options,0 ,"filter" ,PARSE_OPT_HIDDEN ); +set_option_flag (record_options,'R' ,"raw-samples" ,PARSE_OPT_HIDDEN ); + +set_option_flag (record_options,'F' ,"freq" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,0 ,"group" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'g' ,NULL ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,0 ,"call-graph" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'d' ,"data" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'T' ,"timestamp" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'P' ,"period" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'n' ,"no-samples" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'N' ,"no-buildid-cache" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'B' ,"no-buildid" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'G' ,"cgroup" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'b' ,"branch-any" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'j' ,"branch-filter" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,'W' ,"weight" ,PARSE_OPT_DISABLED ); +set_option_flag (record_options,0 ,"transaction" ,PARSE_OPT_DISABLED ); + + record_usage = kvm_stat_record_usage;return cmd_record (i, rec_argv,NULL ); }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 11/32 perf tools: Add support for exclusive option
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Some options cannot be used at the same time. To handle such options add a new PARSE_OPT_EXCLUSIVE flag and show error message if more than one of them is used.
--- tools/perf/util/parse-options.c | 59 +++++++++++++++++++++++++++++++++-------- tools/perf/util/parse-options.h | 2 ++ 2 files changed, 50 insertions(+), 11 deletions(-)
tools/perf/util/parse-options.c +48 -11
@@ -45,6 +45,23 @@ static int get_value(struct parse_opt_ctx_t *p,if (opt->flags &PARSE_OPT_DISABLED )return opterror (opt,"is not usable" , flags); +if (opt->flags &PARSE_OPT_EXCLUSIVE ) { +if (p->excl_opt) { +char msg[128 ]; + +if (((flags &OPT_SHORT ) && p->excl_opt->short_name) || + p->excl_opt->long_name ==NULL ) { +scnprintf (msg,sizeof (msg),"cannot be used with switch `%c'" , + p->excl_opt->short_name); + }else { +scnprintf (msg,sizeof (msg),"cannot be used with %s" , + p->excl_opt->long_name); + } +opterror (opt, msg, flags); +return -3 ; + } + p->excl_opt = opt; + }if (!(flags &OPT_SHORT ) && p->opt) {switch (opt->type) {case OPTION_CALLBACK :
@@ -345,13 +362,14 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, const char * const usagestr[]) {int internal_help = !(ctx->flags &PARSE_OPT_NO_INTERNAL_HELP ); +int excl_short_opt =1 ; +const char *arg;/* we must reset ->opt, unknown short option leave it dangling */ ctx->opt =NULL ;for (; ctx->argc; ctx->argc--, ctx->argv++) { -const char *arg = ctx->argv[0 ]; - + arg = ctx->argv[0 ];if (*arg !='-' || !arg[1 ]) {if (ctx->flags &PARSE_OPT_STOP_AT_NON_OPTION )break ;
@@ -360,19 +378,21 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, }if (arg[1 ] !='-' ) { - ctx->opt = arg +1 ; + ctx->opt = ++arg;if (internal_help && *ctx->opt =='h' )return usage_with_options_internal (usagestr, options,0 );switch (parse_short_opt (ctx, options)) {case -1 : -return parse_options_usage (usagestr, options, arg +1 ,1 ); +return parse_options_usage (usagestr, options, arg,1 );case -2 : goto unknown; +case -3 : + goto exclusive;default :break ; }if (ctx->opt) -check_typos (arg +1 , options); +check_typos (arg, options);while (ctx->opt) {if (internal_help && *ctx->opt =='h' )return usage_with_options_internal (usagestr, options,0 );
@@ -389,6 +409,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, ctx->argv[0 ] =strdup (ctx->opt -1 ); *(char *)ctx->argv[0 ] ='-' ; goto unknown; +case -3 : + goto exclusive;default :break ; }
@@ -404,19 +426,23 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,break ; } -if (internal_help && !strcmp (arg +2 ,"help-all" )) + arg +=2 ; +if (internal_help && !strcmp (arg,"help-all" ))return usage_with_options_internal (usagestr, options,1 ); -if (internal_help && !strcmp (arg +2 ,"help" )) +if (internal_help && !strcmp (arg,"help" ))return usage_with_options_internal (usagestr, options,0 ); -if (!strcmp (arg +2 ,"list-opts" )) +if (!strcmp (arg,"list-opts" ))return PARSE_OPT_LIST_OPTS ; -if (!strcmp (arg +2 ,"list-cmds" )) +if (!strcmp (arg,"list-cmds" ))return PARSE_OPT_LIST_SUBCMDS ; -switch (parse_long_opt (ctx, arg +2 , options)) { +switch (parse_long_opt (ctx, arg, options)) {case -1 : -return parse_options_usage (usagestr, options, arg +2 ,0 ); +return parse_options_usage (usagestr, options, arg,0 );case -2 : goto unknown; +case -3 : + excl_short_opt =0 ; + goto exclusive;default :break ; }
@@ -428,6 +454,17 @@ unknown: ctx->opt =NULL ; }return PARSE_OPT_DONE ; + +exclusive: +parse_options_usage (usagestr, options, arg, excl_short_opt); +if ((excl_short_opt && ctx->excl_opt->short_name) || + ctx->excl_opt->long_name ==NULL ) { +char opt = ctx->excl_opt->short_name; +parse_options_usage (NULL , options, &opt,1 ); + }else { +parse_options_usage (NULL , options, ctx->excl_opt->long_name,0 ); + } +return PARSE_OPT_HELP ; }int parse_options_end (struct parse_opt_ctx_t *ctx)
tools/perf/util/parse-options.h +2 -0
@@ -39,6 +39,7 @@ enum parse_opt_option_flags {PARSE_OPT_HIDDEN =8 ,PARSE_OPT_LASTARG_DEFAULT =16 ,PARSE_OPT_DISABLED =32 , + PARSE_OPT_EXCLUSIVE = 64, };struct option ;
@@ -174,6 +175,7 @@ struct parse_opt_ctx_t {const char **out;int argc, cpidx;const char *opt; +const struct option *excl_opt;int flags; };
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 12/32 perf probe: Use PARSE_OPT_EXCLUSIVE flag
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The perf probe command has some exclusive options. Use new PARSE_OPT_EXCLUSIVE flag to simplify the code and show more compact usage.
$ perf probe -l -a foo
Error: switch `a' cannot be used with switch `l' usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
or: perf probe [<options>] --del '[GROUP:]EVENT' ...
or: perf probe --list
or: perf probe [<options>] --line 'LINEDESC'
or: perf probe [<options>] --vars 'PROBEPOINT' -a, --add <[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]>
probe point definition, where
GROUP: Group name (optional)
EVENT: Event name
FUNC: Function name
OFF: Offset from function entry (in byte)
%return: Put the probe at function return
SRC: Source code path
RL: Relative line number from function entry.
AL: Absolute line number in file.
PT: Lazy expression of line code.
ARG: Probe argument (local variable name or
kprobe-tracer argument format.)
-l, --list list up current probe events
--- tools/perf/builtin-probe.c | 54 ++++++++-------------------------------------- 1 file changed, 9 insertions(+), 45 deletions(-)
tools/perf/builtin-probe.c +9 -45
@@ -312,7 +312,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)#endif NULL }; -const struct option options[] = { +struct option options[] = {OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show parsed arguments, etc)" ), OPT_BOOLEAN('l', "list", ¶ms.list_events,
@@ -382,6 +382,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) };int ret; +set_option_flag (options,'a' ,"add" ,PARSE_OPT_EXCLUSIVE ); +set_option_flag (options,'d' ,"del" ,PARSE_OPT_EXCLUSIVE ); +set_option_flag (options,'l' ,"list" ,PARSE_OPT_EXCLUSIVE ); +#ifdef HAVE_DWARF_SUPPORT +set_option_flag (options,'L' ,"line" ,PARSE_OPT_EXCLUSIVE ); +set_option_flag (options,'V' ,"vars" ,PARSE_OPT_EXCLUSIVE ); +#endif + argc =parse_options (argc, argv, options, probe_usage,PARSE_OPT_STOP_AT_NON_OPTION );if (argc >0 ) {
@@ -409,22 +417,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name ==NULL );if (params.list_events) { -if (params.mod_events) { -pr_err (" Error: Don't use --list with --add/--del.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_lines) { -pr_err (" Error: Don't use --list with --line.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_vars) { -pr_err (" Error: Don't use --list with --vars.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_funcs) { -pr_err (" Error: Don't use --list with --funcs.\n" ); -usage_with_options (probe_usage, options); - }if (params.uprobes) {pr_warning (" Error: Don't use --list with --exec.\n" );usage_with_options (probe_usage, options);
@@ -435,19 +427,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)return ret; }if (params.show_funcs) { -if (params.nevents !=0 || params.dellist) { -pr_err (" Error: Don't use --funcs with" -" --add/--del.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_lines) { -pr_err (" Error: Don't use --funcs with --line.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_vars) { -pr_err (" Error: Don't use --funcs with --vars.\n" ); -usage_with_options (probe_usage, options); - }if (!params.filter) params.filter =strfilter__new (DEFAULT_FUNC_FILTER ,NULL );
@@ -462,16 +441,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)#ifdef HAVE_DWARF_SUPPORT if (params.show_lines) { -if (params.mod_events) { -pr_err (" Error: Don't use --line with" -" --add/--del.\n" ); -usage_with_options (probe_usage, options); - } -if (params.show_vars) { -pr_err (" Error: Don't use --line with --vars.\n" ); -usage_with_options (probe_usage, options); - } - ret =show_line_range (¶ms.line_range, params.target, params.uprobes);if (ret <0 )
@@ -479,11 +448,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)return ret; }if (params.show_vars) { -if (params.mod_events) { -pr_err (" Error: Don't use --vars with" -" --add/--del.\n" ); -usage_with_options (probe_usage, options); - }if (!params.filter) params.filter =strfilter__new (DEFAULT_VAR_FILTER ,NULL );
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 13/32 perf callchain: Use global caching provided by libunwind
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The libunwind provides two caching policy which are global and per-thread. As perf unwinds callchains in a single thread, it'd sufficient to use global caching.
This speeds up my perf report from 14s to 7s on a ~260MB data file. Although the output sometimes contains a slight difference (~0.01% in terms of number of lines printed) on callchains which were not resolved.
--- tools/perf/util/thread.c | 3 +++ tools/perf/util/unwind-libunwind.c | 12 ++++++++++++ tools/perf/util/unwind.h | 3 +++ 3 files changed, 18 insertions(+)
tools/perf/util/thread.c +3 -0
@@ -117,6 +117,9 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,if (!new)return -ENOMEM ;list_add (&new->list, &thread->comm_list); + +if (exec) +unwind__flush_access (thread); } thread->comm_set = true;
tools/perf/util/unwind-libunwind.c +12 -0
@@ -538,11 +538,23 @@ int unwind__prepare_access(struct thread *thread)return -ENOMEM ; } +unw_set_caching_policy (addr_space,UNW_CACHE_GLOBAL );thread__set_priv (thread, addr_space);return 0 ; } +void unwind__flush_access (struct thread *thread) +{ +unw_addr_space_t addr_space; + +if (callchain_param.record_mode !=CALLCHAIN_DWARF ) +return ; + + addr_space =thread__priv (thread); +unw_flush_cache (addr_space,0 ,0 ); +} +void unwind__finish_access (struct thread *thread) {unw_addr_space_t addr_space;
tools/perf/util/unwind.h +3 -0
@@ -22,6 +22,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,#ifdef HAVE_LIBUNWIND_SUPPORT int libunwind__arch_reg_id (int regnum);int unwind__prepare_access (struct thread *thread); +void unwind__flush_access (struct thread *thread);void unwind__finish_access (struct thread *thread);#else static inline int unwind__prepare_access (struct thread *thread__maybe_unused )
@@ -29,6 +30,7 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) return 0; } +static inline void unwind__flush_access (struct thread *thread__maybe_unused ) {}static inline void unwind__finish_access (struct thread *thread__maybe_unused ) {}#endif #else
@@ -47,6 +49,7 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused)return 0 ; } +static inline void unwind__flush_access (struct thread *thread__maybe_unused ) {}static inline void unwind__finish_access (struct thread *thread__maybe_unused ) {}#endif /* HAVE_DWARF_UNWIND_SUPPORT */ #endif /* __UNWIND_H */
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 14/32 perf tools: Ensure return negative value when write header error
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
When 'perf record' write headers, it calls write_xxx in tools/perf/util/header.c, and check return value. It rolls back all working only when return value is negative.
This patch ensures write_cpudesc() and write_total_mem() return negative number when error. Without this patch, headers reported by 'perf report' header is error in some platform. Following output is caputured on ARM, which doesn't contain "Processor" field in /proc/cpuinfo. See "cpudesc", "total memory" and "cmdline" field.
bash-4.2# perf record ls
...
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.001 MB perf.data (~36 samples) ] bash-4.2# perf report --stdio --header
Error:
The perf.data file has no samples!
# ========
# captured on: Fri Sep 12 10:09:10 2014 # hostname : arma15el # os release : 3.17.0+ # perf version : 3.10.53 # arch : armv7l # nrcpus online : 4 # nrcpus avail : 1 # cpudesc : (null) # total memory : 0 kB # cmdline : # event : name = cycles, type = 0, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, excl_host = 0, excl_guest = 1, precise_ip = 0 # pmu mappings: not available # ======== #
--- tools/perf/util/header.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
tools/perf/util/header.c +5 -2
@@ -605,8 +605,10 @@ static int write_cpudesc(int fd, struct perf_header *h __maybe_unused,break ; } -if (ret) +if (ret) { + ret =-1 ; goto done; + } s = buf;
@@ -950,7 +952,8 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused, n =sscanf (buf,"%*s %" PRIu64, &mem);if (n ==1 ) ret =do_write (fd, &mem,sizeof (mem)); - } + }else + ret =-1 ;free (buf);fclose (fp);return ret;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 15/32 perf pmu: Let pmu's with no events show up on perf list
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
perf list only lists PMUs with events. Add a flag to cause a PMU to be also listed separately.
--- tools/perf/util/pmu.c | 13 +++++++++++-- tools/perf/util/pmu.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-)
tools/perf/util/pmu.c +11 -2
@@ -747,15 +747,18 @@ void print_pmu_events(const char *event_glob, bool name_only) pmu =NULL ; len =0 ; -while ((pmu =perf_pmu__scan (pmu)) !=NULL ) +while ((pmu =perf_pmu__scan (pmu)) !=NULL ) {list_for_each_entry (alias, &pmu->aliases, list) len++; +if (pmu->selectable) + len++; + } aliases =malloc (sizeof (char *) * len);if (!aliases)return ; pmu =NULL ; j =0 ; -while ((pmu =perf_pmu__scan (pmu)) !=NULL ) +while ((pmu =perf_pmu__scan (pmu)) !=NULL ) {list_for_each_entry (alias, &pmu->aliases, list) {char *name =format_alias (buf,sizeof (buf), pmu, alias);bool is_cpu = !strcmp (pmu->name,"cpu" );
@@ -772,6 +775,12 @@ void print_pmu_events(const char *event_glob, bool name_only) aliases[j] =strdup (aliases[j]); j++; } +if (pmu->selectable) { +scnprintf (buf,sizeof (buf),"%s//" , pmu->name); + aliases[j] =strdup (buf); + j++; + } + } len = j;qsort (aliases, len,sizeof (char *), cmp_string);for (j =0 ; j < len; j++) {
tools/perf/util/pmu.h +1 -0
@@ -18,6 +18,7 @@ struct perf_event_attr;struct perf_pmu {char *name;__u32 type; +bool selectable;struct perf_event_attr *default_config;struct cpu_map *cpus;struct list_head format;/* HEAD struct perf_pmu_format -> list */
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 16/32 perf tools: Build programs to copy 32-bit compatibility
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
perf tools copy VDSO out of memory. However, on 64-bit machines there may be 32-bit compatibility VDOs also. To copy those requires separate 32-bit executables.
This patch adds to the build additional programs perf-read-vdso32 and perf-read-vdsox32 for 32-bit and x32 respectively.
--- tools/perf/Makefile.perf | 38 ++++++++++++++++++++++--- tools/perf/config/Makefile | 25 +++++++++++++++- tools/perf/config/Makefile.arch | 8 ++++++ tools/perf/config/feature-checks/Makefile | 10 ++++++- tools/perf/config/feature-checks/test-compile.c | 4 +++ tools/perf/perf-read-vdso.c | 34 ++++++++++++++++++++++ tools/perf/util/find-vdso-map.c | 30 +++++++++++++++++++ tools/perf/util/vdso.c | 37 ++++-------------------- 8 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 tools/perf/config/feature-checks/test-compile.c create mode 100644 tools/perf/perf-read-vdso.c create mode 100644 tools/perf/util/find-vdso-map.c
tools/perf/Makefile.perf +34 -4
@@ -60,6 +60,12 @@ include config/utilities.mak # # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support # for dwarf backtrace post unwind. +# +# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32 +# for reading the 32-bit compatibility VDSO in 64-bit mode +# +# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32 +# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +177,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) -# -# Single 'perf' binary right now: -# PROGRAMS += $(OUTPUT)perf +ifndef NO_PERF_READ_VDSO32 +PROGRAMS += $(OUTPUT)perf-read-vdso32 +endif + +ifndef NO_PERF_READ_VDSOX32 +PROGRAMS += $(OUTPUT)perf-read-vdsox32 +endif + # what 'all' will build and 'install' will install, in perfexecdir ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -253,6 +264,7 @@ LIB_H += util/event.h LIB_H += util/evsel.h LIB_H += util/evlist.h LIB_H += util/exec_cmd.h +LIB_H += util/find-vdso-map.c LIB_H += util/levenshtein.h LIB_H += util/machine.h LIB_H += util/map.h
@@ -732,6 +744,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti $(OUTPUT)perf-%: %.o $(PERFLIBS) $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) +ifndef NO_PERF_READ_VDSO32 +$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c + $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c +endif + +ifndef NO_PERF_READ_VDSOX32 +$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c + $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c +endif + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -876,6 +898,14 @@ install-bin: all install-gtk $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace' +ifndef NO_PERF_READ_VDSO32 + $(call QUIET_INSTALL, perf-read-vdso32) \ + $(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)'; +endif +ifndef NO_PERF_READ_VDSOX32 + $(call QUIET_INSTALL, perf-read-vdsox32) \ + $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)'; +endif $(call QUIET_INSTALL, libexec) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' $(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +958,7 @@ config-clean: clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) - $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf + $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean $(python-clean)
tools/perf/config/Makefile +24 -1
@@ -230,7 +230,9 @@ VF_FEATURE_TESTS = \ bionic \ liberty \ liberty-z \ - cplus-demangle + cplus-demangle \ + compile-32 \ + compile-x32 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. # If in the future we need per-feature checks/flags for features not
@@ -622,6 +624,27 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq (${IS_64_BIT}, 1) + ifndef NO_PERF_READ_VDSO32 + $(call feature_check,compile-32) + ifneq ($(feature-compile-32), 1) + NO_PERF_READ_VDSO32 := 1 + endif + endif + ifneq (${IS_X86_64}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + ifndef NO_PERF_READ_VDSOX32 + $(call feature_check,compile-x32) + ifneq ($(feature-compile-x32), 1) + NO_PERF_READ_VDSOX32 := 1 + endif + endif +else + NO_PERF_READ_VDSO32 := 1 + NO_PERF_READ_VDSOX32 := 1 +endif + # Among the variables below, these: # perfexecdir # template_dir
tools/perf/config/Makefile.arch +8 -0
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64) RAW_ARCH := x86_64 endif endif + +ifeq (${IS_X86_64}, 1) + IS_64_BIT := 1 +else ifeq ($(ARCH),x86) + IS_64_BIT := 0 +else + IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) +endif
tools/perf/config/feature-checks/Makefile +9 -1
@@ -27,7 +27,9 @@ FILES= \ test-libunwind-debug-frame.bin \ test-stackprotector-all.bin \ test-timerfd.bin \ - test-libdw-dwarf-unwind.bin + test-libdw-dwarf-unwind.bin \ + test-compile-32.bin \ + test-compile-x32.bin CC := $(CROSS_COMPILE)gcc -MD PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -131,6 +133,12 @@ test-libdw-dwarf-unwind.bin: test-sync-compare-and-swap.bin: $(BUILD) -Werror +test-compile-32.bin: + $(CC) -m32 -o $(OUTPUT)$@ test-compile.c + +test-compile-x32.bin: + $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c + -include *.d ###############################
tools/perf/config/feature-checks/test-compile.c new file +4 -0
@@ -0,0 +1,4 @@ +int main (void ) +{ +return 0 ; +}
tools/perf/perf-read-vdso.c new file +34 -0
@@ -0,0 +1,34 @@ +#include <stdio.h> +#include <string.h> + +#define VDSO__MAP_NAME "[vdso]" + +/* +* Include definition of find_vdso_map() also used in util/vdso.c for +* building perf. +*/ +#include "util/find-vdso-map.c" + +int main (void ) +{ +void *start, *end; +size_t size, written; + +if (find_vdso_map (&start, &end)) +return 1 ; + + size = end - start; + +while (size) { + written =fwrite (start,1 , size, stdout); +if (!written) +return 1 ; + start += written; + size -= written; + } + +if (fflush (stdout)) +return 1 ; + +return 0 ; +}
tools/perf/util/find-vdso-map.c new file +30 -0
@@ -0,0 +1,30 @@ +static int find_vdso_map (void **start,void **end) +{ +FILE *maps; +char line[128 ]; +int found =0 ; + + maps =fopen ("/proc/self/maps" ,"r" ); +if (!maps) { +fprintf (stderr,"vdso: cannot open maps\n" ); +return -1 ; + } + +while (!found &&fgets (line,sizeof (line), maps)) { +int m =-1 ; + +/* We care only about private r-x mappings. */ +if (2 !=sscanf (line,"%p-%p r-xp %*x %*x:%*x %*u %n" , + start, end, &m)) +continue ; +if (m <0 ) +continue ; + +if (!strncmp (&line[m],VDSO__MAP_NAME , +sizeof (VDSO__MAP_NAME ) -1 )) + found =1 ; + } + +fclose (maps); +return !found; +}
tools/perf/util/vdso.c +6 -31
@@ -15,6 +15,12 @@#include "linux/string.h" #include "debug.h" +/* +* Include definition of find_vdso_map() also used in perf-read-vdso.c for +* building perf-read-vdso32 and perf-read-vdsox32. +*/ +#include "find-vdso-map.c" +#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"struct vdso_file {
@@ -40,37 +46,6 @@ static struct vdso_info *vdso_info__new(void)return memdup (&vdso_info_init,sizeof (vdso_info_init)); } -static int find_vdso_map (void **start,void **end) -{ -FILE *maps; -char line[128 ]; -int found =0 ; - - maps =fopen ("/proc/self/maps" ,"r" ); -if (!maps) { -pr_err ("vdso: cannot open maps\n" ); -return -1 ; - } - -while (!found &&fgets (line,sizeof (line), maps)) { -int m =-1 ; - -/* We care only about private r-x mappings. */ -if (2 !=sscanf (line,"%p-%p r-xp %*x %*x:%*x %*u %n" , - start, end, &m)) -continue ; -if (m <0 ) -continue ; - -if (!strncmp (&line[m],VDSO__MAP_NAME , -sizeof (VDSO__MAP_NAME ) -1 )) - found =1 ; - } - -fclose (maps); -return !found; -} -static char *get_file (struct vdso_file *vdso_file) {char *vdso =NULL ;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 17/32 perf tools: Add support for 32-bit compatibility VDSOs
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.
In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.
Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".
However, in the 64-bit case, there also can be 32-bit compatibility VDSOs.
A previous patch added programs "perf-read-vdso32" and "perf read-vdsox32".
This patch uses those programs to read the correct VDSO for a thread and create a temporary file just as for the 64-bit VDSO.
The map name and the entry in the build-id cache are still "[vdso]" but the DSO short name becomes "[vdso32]" and "[vdsox32]" respectively.
--- tools/perf/util/vdso.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/vdso.h | 4 +- 2 files changed, 172 insertions(+), 2 deletions(-)
tools/perf/util/vdso.c +169 -1
@@ -12,6 +12,7 @@#include "util.h" #include "symbol.h" #include "machine.h" +#include "thread.h" #include "linux/string.h" #include "debug.h"
@@ -28,10 +29,15 @@ struct vdso_file {bool error;char temp_file_name[sizeof (VDSO__TEMP_FILE_NAME )];const char *dso_name; +const char *read_prog; };struct vdso_info {struct vdso_file vdso; +#if BITS_PER_LONG ==64 +struct vdso_file vdso32; +struct vdso_file vdsox32; +#endif };static struct vdso_info *vdso_info__new (void )
@@ -41,6 +47,18 @@ static struct vdso_info *vdso_info__new(void) .temp_file_name = VDSO__TEMP_FILE_NAME, .dso_name = DSO__NAME_VDSO, }, +#if BITS_PER_LONG ==64 + .vdso32 = { + .temp_file_name = VDSO__TEMP_FILE_NAME, + .dso_name = DSO__NAME_VDSO32, + .read_prog = "perf-read-vdso32", + }, + .vdsox32 = { + .temp_file_name = VDSO__TEMP_FILE_NAME, + .dso_name = DSO__NAME_VDSOX32, + .read_prog = "perf-read-vdsox32", + }, +#endif };return memdup (&vdso_info_init,sizeof (vdso_info_init));
@@ -92,6 +110,12 @@ void vdso__exit(struct machine *machine)if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); +#if BITS_PER_LONG ==64 +if (vdso_info->vdso32.found) +unlink (vdso_info->vdso32.temp_file_name); +if (vdso_info->vdsox32.found) +unlink (vdso_info->vdsox32.temp_file_name); +#endif zfree (&machine->vdso_info); }
@@ -110,6 +134,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,return dso; } +#if BITS_PER_LONG ==64 + +static enum dso_type machine__thread_dso_type (struct machine *machine, +struct thread *thread) +{ +enum dso_type dso_type =DSO__TYPE_UNKNOWN ; +struct map *map; +struct dso *dso; + + map =map_groups__first (thread->mg,MAP__FUNCTION ); +for (; map ; map =map_groups__next (map)) { + dso = map->dso; +if (!dso || dso->long_name[0 ] !='/' ) +continue ; + dso_type =dso__type (dso, machine); +if (dso_type !=DSO__TYPE_UNKNOWN ) +break ; + } + +return dso_type; +} + +static int vdso__do_copy_compat (FILE *f,int fd) +{ +char buf[4096 ]; +size_t count; + +while (1 ) { + count =fread (buf,1 ,sizeof (buf), f); +if (ferror (f)) +return -errno; +if (feof (f)) +break ; +if (count &&writen (fd, buf, count) != (ssize_t )count) +return -errno; + } + +return 0 ; +} + +static int vdso__copy_compat (const char *prog,int fd) +{ +FILE *f; +int err; + + f =popen (prog,"r" ); +if (!f) +return -errno; + + err =vdso__do_copy_compat (f, fd); + +if (pclose (f) ==-1 ) +return -errno; + +return err; +} + +static int vdso__create_compat_file (const char *prog,char *temp_name) +{ +int fd, err; + + fd =mkstemp (temp_name); +if (fd <0 ) +return -errno; + + err =vdso__copy_compat (prog, fd); + +if (close (fd) ==-1 ) +return -errno; + +return err; +} + +static const char *vdso__get_compat_file (struct vdso_file *vdso_file) +{ +int err; + +if (vdso_file->found) +return vdso_file->temp_file_name; + +if (vdso_file->error) +return NULL ; + + err =vdso__create_compat_file (vdso_file->read_prog, + vdso_file->temp_file_name); +if (err) { +pr_err ("%s failed, error %d\n" , vdso_file->read_prog, err); + vdso_file->error = true; +return NULL ; + } + + vdso_file->found = true; + +return vdso_file->temp_file_name; +} + +static struct dso *vdso__findnew_compat (struct machine *machine, +struct vdso_file *vdso_file) +{ +const char *file_name; +struct dso *dso; + + dso =dsos__find (&machine->user_dsos, vdso_file->dso_name, true); +if (dso) +return dso; + + file_name =vdso__get_compat_file (vdso_file); +if (!file_name) +return NULL ; + +return vdso__new (machine, vdso_file->dso_name, file_name); +} + +static int vdso__dso_findnew_compat (struct machine *machine, +struct thread *thread, +struct vdso_info *vdso_info, +struct dso **dso) +{ +enum dso_type dso_type; + + dso_type =machine__thread_dso_type (machine, thread); +switch (dso_type) { +case DSO__TYPE_32BIT : + *dso =vdso__findnew_compat (machine, &vdso_info->vdso32); +return 1 ; +case DSO__TYPE_X32BIT : + *dso =vdso__findnew_compat (machine, &vdso_info->vdsox32); +return 1 ; +case DSO__TYPE_UNKNOWN : +case DSO__TYPE_64BIT : +default : +return 0 ; + } +} + +#endif +struct dso *vdso__dso_findnew (struct machine *machine,struct thread *thread__maybe_unused ) {
@@ -123,6 +284,11 @@ struct dso *vdso__dso_findnew(struct machine *machine,if (!vdso_info)return NULL ; +#if BITS_PER_LONG ==64 +if (vdso__dso_findnew_compat (machine, thread, vdso_info, &dso)) +return dso; +#endif + dso =dsos__find (&machine->user_dsos,DSO__NAME_VDSO , true);if (!dso) {char *file;
@@ -139,5 +305,7 @@ struct dso *vdso__dso_findnew(struct machine *machine,bool dso__is_vdso (struct dso *dso) { -return !strcmp (dso->short_name,DSO__NAME_VDSO ); +return !strcmp (dso->short_name,DSO__NAME_VDSO ) || + !strcmp (dso->short_name,DSO__NAME_VDSO32 ) || + !strcmp (dso->short_name,DSO__NAME_VDSOX32 ); }
tools/perf/util/vdso.h +3 -1
@@ -7,7 +7,9 @@#define VDSO__MAP_NAME "[vdso]" -#define DSO__NAME_VDSO "[vdso]" +#define DSO__NAME_VDSO "[vdso]" +#define DSO__NAME_VDSO32 "[vdso32]" +#define DSO__NAME_VDSOX32 "[vdsox32]"static inline bool is_vdso_map (const char *filename) {
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 18/32 perf tools: Do not attempt to run perf-read-vdso32 if it wasn't built
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
popen() causes an error message to print if perf-read-vdso32 does not run. Avoid that by not trying to run it if it was not built. Ditto perf-read-vdsox32.
--- tools/perf/config/Makefile | 8 ++++++-- tools/perf/util/vdso.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-)
tools/perf/config/Makefile +6 -2
@@ -627,7 +627,9 @@ endif ifeq (${IS_64_BIT}, 1) ifndef NO_PERF_READ_VDSO32 $(call feature_check,compile-32) - ifneq ($(feature-compile-32), 1) + ifeq ($(feature-compile-32), 1) + CFLAGS += -DHAVE_PERF_READ_VDSO32 + else NO_PERF_READ_VDSO32 := 1 endif endif
@@ -636,7 +638,9 @@ ifeq (${IS_64_BIT}, 1) endif ifndef NO_PERF_READ_VDSOX32 $(call feature_check,compile-x32) - ifneq ($(feature-compile-x32), 1) + ifeq ($(feature-compile-x32), 1) + CFLAGS += -DHAVE_PERF_READ_VDSOX32 + else NO_PERF_READ_VDSOX32 := 1 endif endif
tools/perf/util/vdso.c +10 -0
@@ -255,6 +255,16 @@ static int vdso__dso_findnew_compat(struct machine *machine,enum dso_type dso_type; dso_type =machine__thread_dso_type (machine, thread); + +#ifndef HAVE_PERF_READ_VDSO32 +if (dso_type ==DSO__TYPE_32BIT ) +return 0 ; +#endif +#ifndef HAVE_PERF_READ_VDSOX32 +if (dso_type ==DSO__TYPE_X32BIT ) +return 0 ; +#endif +switch (dso_type) {case DSO__TYPE_32BIT : *dso =vdso__findnew_compat (machine, &vdso_info->vdso32);
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 19/32 perf tools: Make CPUINFO_PROC an array to support different kernel versions
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
After kernel 3.7 (commit b4b8f770eb10a1bccaf8aa0ec1956e2dd7ed1e0a), /proc/cpuinfo replaces 'Processor' to 'model name'.
This patch makes CPUINFO_PROC to an array and provides two choices for ARM, makes it compatible for different kernel version.
v1 -> v2: minor changes as suggested by Namhyung Kim:
- Doesn't pass @h and @evlist to __write_cpudesc;
- Coding style fix.
v2 -> v3:
- Rebase:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git perf/core
--- tools/perf/perf-sys.h | 30 +++++++++++++++--------------- tools/perf/util/header.c | 27 +++++++++++++++++++++------ 2 files changed, 36 insertions(+), 21 deletions(-)
tools/perf/perf-sys.h +15 -15
@@ -13,7 +13,7 @@#define wmb () asm volatile("lock; addl $0,0(%%esp)" ::: "memory")#define rmb () asm volatile("lock; addl $0,0(%%esp)" ::: "memory")#define cpu_relax () asm volatile("rep; nop" ::: "memory"); -#define CPUINFO_PROC "model name" +#define CPUINFO_PROC {"model name"}#ifndef __NR_perf_event_open# define __NR_perf_event_open 336#endif
@@ -30,7 +30,7 @@#define wmb () asm volatile("sfence" ::: "memory")#define rmb () asm volatile("lfence" ::: "memory")#define cpu_relax () asm volatile("rep; nop" ::: "memory"); -#define CPUINFO_PROC "model name" +#define CPUINFO_PROC {"model name"}#ifndef __NR_perf_event_open# define __NR_perf_event_open 298#endif
@@ -47,14 +47,14 @@#define mb () asm volatile ("sync" ::: "memory")#define wmb () asm volatile ("sync" ::: "memory")#define rmb () asm volatile ("sync" ::: "memory") -#define CPUINFO_PROC "cpu" +#define CPUINFO_PROC {"cpu"}#endif #ifdef __s390__#define mb () asm volatile("bcr 15,0" ::: "memory")#define wmb () asm volatile("bcr 15,0" ::: "memory")#define rmb () asm volatile("bcr 15,0" ::: "memory") -#define CPUINFO_PROC "vendor_id" +#define CPUINFO_PROC {"vendor_id"}#endif #ifdef __sh__
@@ -67,14 +67,14 @@# define wmb () asm volatile("" ::: "memory")# define rmb () asm volatile("" ::: "memory")#endif -#define CPUINFO_PROC "cpu type" +#define CPUINFO_PROC {"cpu type"}#endif #ifdef __hppa__#define mb () asm volatile("" ::: "memory")#define wmb () asm volatile("" ::: "memory")#define rmb () asm volatile("" ::: "memory") -#define CPUINFO_PROC "cpu" +#define CPUINFO_PROC {"cpu"}#endif #ifdef __sparc__
@@ -87,14 +87,14 @@#endif #define wmb () asm volatile("":::"memory")#define rmb () asm volatile("":::"memory") -#define CPUINFO_PROC "cpu" +#define CPUINFO_PROC {"cpu"}#endif #ifdef __alpha__#define mb () asm volatile("mb" ::: "memory")#define wmb () asm volatile("wmb" ::: "memory")#define rmb () asm volatile("mb" ::: "memory") -#define CPUINFO_PROC "cpu model" +#define CPUINFO_PROC {"cpu model"}#endif #ifdef __ia64__
@@ -102,7 +102,7 @@#define wmb () asm volatile ("mf" ::: "memory")#define rmb () asm volatile ("mf" ::: "memory")#define cpu_relax () asm volatile ("hint @pause" ::: "memory") -#define CPUINFO_PROC "model name" +#define CPUINFO_PROC {"model name"}#endif #ifdef __arm__
@@ -113,7 +113,7 @@#define mb () ((void(*)(void))0xffff0fa0)()#define wmb () ((void(*)(void))0xffff0fa0)()#define rmb () ((void(*)(void))0xffff0fa0)() -#define CPUINFO_PROC "Processor" +#define CPUINFO_PROC {"model name", "Processor"}#endif #ifdef __aarch64__
@@ -133,28 +133,28 @@ : "memory")#define wmb () mb()#define rmb () mb() -#define CPUINFO_PROC "cpu model" +#define CPUINFO_PROC {"cpu model"}#endif #ifdef __arc__#define mb () asm volatile("" ::: "memory")#define wmb () asm volatile("" ::: "memory")#define rmb () asm volatile("" ::: "memory") -#define CPUINFO_PROC "Processor" +#define CPUINFO_PROC {"Processor"}#endif #ifdef __metag__#define mb () asm volatile("" ::: "memory")#define wmb () asm volatile("" ::: "memory")#define rmb () asm volatile("" ::: "memory") -#define CPUINFO_PROC "CPU" +#define CPUINFO_PROC {"CPU"}#endif #ifdef __xtensa__#define mb () asm volatile("memw" ::: "memory")#define wmb () asm volatile("memw" ::: "memory")#define rmb () asm volatile("" ::: "memory") -#define CPUINFO_PROC "core ID" +#define CPUINFO_PROC {"core ID"}#endif #ifdef __tile__
@@ -162,7 +162,7 @@#define wmb () asm volatile ("mf" ::: "memory")#define rmb () asm volatile ("mf" ::: "memory")#define cpu_relax () asm volatile ("mfspr zero, PASS" ::: "memory") -#define CPUINFO_PROC "model name" +#define CPUINFO_PROC {"model name"}#endif #define barrier () asm volatile ("" ::: "memory")
tools/perf/util/header.c +21 -6
@@ -579,16 +579,12 @@ static int write_version(int fd, struct perf_header *h __maybe_unused,return do_write_string (fd, perf_version_string); } -static int write_cpudesc (int fd,struct perf_header *h__maybe_unused , -struct perf_evlist *evlist__maybe_unused ) +static int __write_cpudesc (int fd,const char *cpuinfo_proc) { -#ifndef CPUINFO_PROC -#define CPUINFO_PROC NULL -#endif FILE *file;char *buf =NULL ;char *s, *p; -const char *search =CPUINFO_PROC ; +const char *search = cpuinfo_proc;size_t len =0 ;int ret =-1 ;
@@ -640,6 +636,25 @@ done:return ret; } +static int write_cpudesc (int fd,struct perf_header *h__maybe_unused , +struct perf_evlist *evlist__maybe_unused ) +{ +#ifndef CPUINFO_PROC +#define CPUINFO_PROC {"model name", } +#endif +const char *cpuinfo_procs[] =CPUINFO_PROC ; +unsigned int i; + +for (i =0 ; i <ARRAY_SIZE (cpuinfo_procs); i++) { +int ret; + ret =__write_cpudesc (fd, cpuinfo_procs[i]); +if (ret >=0 ) +return ret; + } +return -1 ; +} + +static int write_nrcpus (int fd,struct perf_header *h__maybe_unused ,struct perf_evlist *evlist__maybe_unused ) {
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 20/32 perf pmu: Add proper error handling to print_pmu_events()
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
It was silently returning or printing "(null)" when no memory was available at various points. Fix it by checking and warning the user when that happens.
--- tools/perf/util/pmu.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-)
tools/perf/util/pmu.c +22 -10
@@ -753,9 +753,9 @@ void print_pmu_events(const char *event_glob, bool name_only)if (pmu->selectable) len++; } - aliases =malloc (sizeof (char *) * len); + aliases =zalloc (sizeof (char *) * len);if (!aliases) -return ; + goto out_enomem; pmu =NULL ; j =0 ;while ((pmu =perf_pmu__scan (pmu)) !=NULL ) {
@@ -768,16 +768,20 @@ void print_pmu_events(const char *event_glob, bool name_only) (!is_cpu &&strglobmatch (alias->name, event_glob)))) continue; - aliases[j] = name; +if (is_cpu && !name_only) - aliases[j] =format_alias_or (buf,sizeof (buf), - pmu, alias); - aliases[j] =strdup (aliases[j]); + name =format_alias_or (buf,sizeof (buf), pmu, alias); + + aliases[j] =strdup (name); +if (aliases[j] ==NULL ) + goto out_enomem; j++; }if (pmu->selectable) { -scnprintf (buf,sizeof (buf),"%s//" , pmu->name); - aliases[j] =strdup (buf); +char *s; +if (asprintf (&s,"%s//" , pmu->name) <0 ) + goto out_enomem; + aliases[j] = s; j++; } }
@@ -789,12 +793,20 @@ void print_pmu_events(const char *event_glob, bool name_only)continue ; }printf (" %-50s [Kernel PMU event]\n" , aliases[j]); -zfree (&aliases[j]); printed++; }if (printed)printf ("\n" ); -free (aliases); +out_free: +for (j =0 ; j < len; j++) +zfree (&aliases[j]); +zfree (&aliases); +return ; + +out_enomem: +printf ("FATAL: not enough memory to print PMU events\n" ); +if (aliases) + goto out_free; }bool pmu_have_event (const char *pname,const char *name)
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 21/32 perf tools: Fix report -F abort for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F abort perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
tools/perf/util/sort.c +11 -3
@@ -989,6 +989,9 @@ struct sort_entry sort_mem_dcacheline = {static int64_t sort__abort_cmp (struct hist_entry *left,struct hist_entry *right) { +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); +return left->branch_info->flags.abort != right->branch_info->flags.abort; }
@@ -996,10 +999,15 @@ sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)static int hist_entry__abort_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -static const char *out ="." ; +static const char *out ="N/A" ; + +if (he->branch_info) { +if (he->branch_info->flags.abort) + out ="A" ; +else + out ="." ; + } -if (he->branch_info->flags.abort) - out ="A" ;return repsep_snprintf (bf, size,"%-*s" , width, out); }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 22/32 perf tools: Fix report -F in_tx for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F in_tx perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
tools/perf/util/sort.c +10 -3
@@ -1021,6 +1021,9 @@ struct sort_entry sort_abort = {static int64_t sort__in_tx_cmp (struct hist_entry *left,struct hist_entry *right) { +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); +return left->branch_info->flags.in_tx != right->branch_info->flags.in_tx; }
@@ -1028,10 +1031,14 @@ sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)static int hist_entry__in_tx_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -static const char *out ="." ; +static const char *out ="N/A" ; -if (he->branch_info->flags.in_tx) - out ="T" ; +if (he->branch_info) { +if (he->branch_info->flags.in_tx) + out ="T" ; +else + out ="." ; + }return repsep_snprintf (bf, size,"%-*s" , width, out); }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 23/32 perf tools: Fix report -F mispredict for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F mispredict perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
tools/perf/util/sort.c +12 -8
@@ -471,11 +471,13 @@ struct sort_entry sort_sym_to = {static int64_t sort__mispredict_cmp (struct hist_entry *left,struct hist_entry *right) { -const unsigned char mp = left->branch_info->flags.mispred != - right->branch_info->flags.mispred; -const unsigned char p = left->branch_info->flags.predicted != - right->branch_info->flags.predicted; +unsigned char mp, p; +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); + + mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred; + p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;return mp || p; }
@@ -483,10 +485,12 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width){static const char *out ="N/A" ; -if (he->branch_info->flags.predicted) - out ="N" ; -else if (he->branch_info->flags.mispred) - out ="Y" ; +if (he->branch_info) { +if (he->branch_info->flags.predicted) + out ="N" ; +else if (he->branch_info->flags.mispred) + out ="Y" ; + }return repsep_snprintf (bf, size,"%-*.*s" , width, width, out); }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 24/32 perf tools: Fix report -F symbol_to for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F symbol_to perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
tools/perf/util/sort.c +14 -5
@@ -413,8 +413,13 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)static int64_t sort__sym_to_cmp (struct hist_entry *left,struct hist_entry *right) { -struct addr_map_symbol *to_l = &left->branch_info->to; -struct addr_map_symbol *to_r = &right->branch_info->to; +struct addr_map_symbol *to_l, *to_r; + +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); + + to_l = &left->branch_info->to; + to_r = &right->branch_info->to;if (!to_l->sym && !to_r->sym)return _sort__addr_cmp (to_l->addr, to_r->addr);
@@ -434,10 +439,14 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,static int hist_entry__sym_to_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -struct addr_map_symbol *to = &he->branch_info->to; -return _hist_entry__sym_snprintf (to->map, to->sym, to->addr, - he->level, bf, size, width); +if (he->branch_info) { +struct addr_map_symbol *to = &he->branch_info->to; + +return _hist_entry__sym_snprintf (to->map, to->sym, to->addr, + he->level, bf, size, width); + } +return repsep_snprintf (bf, size,"%-*.*s" , width, width,"N/A" ); }struct sort_entry sort_dso_from = {
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 25/32 perf tools: Fix report -F symbol_from for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F symbol_from perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
tools/perf/util/sort.c +13 -3
@@ -404,6 +404,12 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)struct addr_map_symbol *from_l = &left->branch_info->from;struct addr_map_symbol *from_r = &right->branch_info->from; +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); + + from_l = &left->branch_info->from; + from_r = &right->branch_info->from; +if (!from_l->sym && !from_r->sym)return _sort__addr_cmp (from_l->addr, from_r->addr);
@@ -430,10 +436,14 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)static int hist_entry__sym_from_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -struct addr_map_symbol *from = &he->branch_info->from; -return _hist_entry__sym_snprintf (from->map, from->sym, from->addr, - he->level, bf, size, width); +if (he->branch_info) { +struct addr_map_symbol *from = &he->branch_info->from; +return _hist_entry__sym_snprintf (from->map, from->sym, from->addr, + he->level, bf, size, width); + } + +return repsep_snprintf (bf, size,"%-*.*s" , width, width,"N/A" ); } static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 26/32 perf tools: Fix report -F dso_to for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F dso_to perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/perf/util/sort.c +8 -2
@@ -387,6 +387,9 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,static int64_t sort__dso_to_cmp (struct hist_entry *left,struct hist_entry *right) { +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); +return _sort__dso_cmp (left->branch_info->to.map, right->branch_info->to.map); }
@@ -394,8 +397,11 @@ sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)static int hist_entry__dso_to_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -return _hist_entry__dso_snprintf (he->branch_info->to.map, - bf, size, width); +if (he->branch_info) +return _hist_entry__dso_snprintf (he->branch_info->to.map, + bf, size, width); +else +return repsep_snprintf (bf, size,"%-*.*s" , width, width,"N/A" ); } static int64_t
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 27/32 perf tools: Fix report -F dso_from for data without branch info
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The branch field sorting code assumes hist_entry::branch_info is allocated, which is wrong and following perf session ends up with report segfault.
$ perf record ls $ perf report -F dso_from perf: Segmentation fault
Checking that hist_entry::branch_info is valid and display "N/A" string in snprint callback if it's not.
--- tools/perf/util/sort.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/perf/util/sort.c +8 -2
@@ -373,6 +373,9 @@ struct sort_entry sort_cpu = {static int64_t sort__dso_from_cmp (struct hist_entry *left,struct hist_entry *right) { +if (!left->branch_info || !right->branch_info) +return cmp_null (left->branch_info, right->branch_info); +return _sort__dso_cmp (left->branch_info->from.map, right->branch_info->from.map); }
@@ -380,8 +383,11 @@ sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)static int hist_entry__dso_from_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) { -return _hist_entry__dso_snprintf (he->branch_info->from.map, - bf, size, width); +if (he->branch_info) +return _hist_entry__dso_snprintf (he->branch_info->from.map, + bf, size, width); +else +return repsep_snprintf (bf, size,"%-*.*s" , width, width,"N/A" ); } static int64_t
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 28/32 perf tools: Add facility to export data in database-friendly way
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
This patch introduces an abstraction for exporting sample data in a database-friendly way. The abstraction does not implement the actual output. A subsequent patch takes this facility into use for extending the script interface.
The abstraction is needed because static data like symbols, dsos, comms etc need to be exported only once. That means allocating them a unique identifier and recording it on each structure. The member 'db_id' is used for that. 'db_id' is just a 64-bit sequence number.
Exporting centres around the db_export__sample() function which exports the associated data structures if they have not yet been allocated a db_id.
--- tools/perf/Makefile.perf | 2 + tools/perf/util/comm.h | 4 + tools/perf/util/db-export.c | 270 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/db-export.h | 86 ++++++++++++++ tools/perf/util/dso.h | 5 + tools/perf/util/evsel.h | 2 + tools/perf/util/machine.h | 4 + tools/perf/util/thread.h | 1 + 8 files changed, 374 insertions(+) create mode 100644 tools/perf/util/db-export.c create mode 100644 tools/perf/util/db-export.h
tools/perf/Makefile.perf +2 -0
@@ -258,6 +258,7 @@ LIB_H += util/annotate.h LIB_H += util/cache.h LIB_H += util/callchain.h LIB_H += util/build-id.h +LIB_H += util/db-export.h LIB_H += util/debug.h LIB_H += util/pmu.h LIB_H += util/event.h
@@ -323,6 +324,7 @@ LIB_OBJS += $(OUTPUT)util/annotate.o LIB_OBJS += $(OUTPUT)util/build-id.o LIB_OBJS += $(OUTPUT)util/config.o LIB_OBJS += $(OUTPUT)util/ctype.o +LIB_OBJS += $(OUTPUT)util/db-export.o LIB_OBJS += $(OUTPUT)util/pmu.o LIB_OBJS += $(OUTPUT)util/environment.o LIB_OBJS += $(OUTPUT)util/event.o
tools/perf/util/comm.h +4 -0
@@ -12,6 +12,10 @@ struct comm {u64 start;struct list_head list;bool exec; +union {/* Tool specific area */ +void *priv; +u64 db_id; + }; };void comm__free (struct comm *comm);
tools/perf/util/db-export.c new file +270 -0
270 lines not on this page · raw message
tools/perf/util/db-export.h new file +86 -0
86 lines not on this page · raw message
tools/perf/util/dso.h +5 -0
@@ -139,6 +139,11 @@ struct dso {struct list_head open_entry; } data; +union {/* Tool specific area */ +void *priv; +u64 db_id; + }; +char name[0 ]; };
tools/perf/util/evsel.h +2 -0
@@ -54,6 +54,7 @@ struct cgroup_sel;* @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all * is used there is an id sample appended to non-sample events +* @priv: And what is in its containing unnamed union are tool specific */ struct perf_evsel {struct list_head node;
@@ -73,6 +74,7 @@ struct perf_evsel {union {void *priv;off_t id_offset; +u64 db_id; };struct cgroup_sel *cgrp;void *handler;
tools/perf/util/machine.h +4 -0
@@ -40,6 +40,10 @@ struct machine {u64 kernel_start;symbol_filter_t symbol_filter;pid_t *current_tid; +union {/* Tool specific area */ +void *priv; +u64 db_id; + }; }; static inline
tools/perf/util/thread.h +1 -0
@@ -23,6 +23,7 @@ struct thread {bool dead;/* if set thread has exited */ struct list_head comm_list;int comm_len; +u64 db_id;void *priv; };
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 29/32 perf scripting python: Extend interface to export data in a database-friendly way
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Use the new db_export facility to export data in a database-friendly way.
A Python script selects the db_export mode by setting a global variable 'perf_db_export_mode' to True. The script then optionally implements functions to receive table rows. The functions are:
evsel_table
machine_table
thread_table
comm_table
dso_table
symbol_table
sample_table
An example script is provided in a subsequent patch.
--- .../util/scripting-engines/trace-event-python.c | 286 ++++++++++++++++++++- 1 file changed, 284 insertions(+), 2 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +284 -2
@@ -24,6 +24,7 @@#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdbool.h> #include <errno.h> #include "../../perf.h"
@@ -33,6 +34,9 @@#include "../util.h" #include "../event.h" #include "../thread.h" +#include "../comm.h" +#include "../machine.h" +#include "../db-export.h" #include "../trace-event.h" #include "../machine.h"
@@ -53,6 +57,21 @@ static int zero_flag_atom;static PyObject *main_module, *main_dict; +struct tables { +struct db_export dbe; +PyObject *evsel_handler; +PyObject *machine_handler; +PyObject *thread_handler; +PyObject *comm_handler; +PyObject *comm_thread_handler; +PyObject *dso_handler; +PyObject *symbol_handler; +PyObject *sample_handler; +bool db_export_mode; +}; + +static struct tables tables_global; + static void handler_call_die(const char *handler_name) NORETURN;static void handler_call_die (const char *handler_name) {
@@ -475,6 +494,211 @@ static void python_process_tracepoint(struct perf_sample *sample,Py_DECREF (t); } +static PyObject *tuple_new (unsigned int sz) +{ +PyObject *t; + + t =PyTuple_New (sz); +if (!t) +Py_FatalError ("couldn't create Python tuple" ); +return t; +} + +static int tuple_set_u64 (PyObject *t,unsigned int pos,u64 val) +{ +#if BITS_PER_LONG ==64 +return PyTuple_SetItem (t, pos,PyInt_FromLong (val)); +#endif +#if BITS_PER_LONG ==32 +return PyTuple_SetItem (t, pos,PyLong_FromLongLong (val)); +#endif +} + +static int tuple_set_s32 (PyObject *t,unsigned int pos,s32 val) +{ +return PyTuple_SetItem (t, pos,PyInt_FromLong (val)); +} + +static int tuple_set_string (PyObject *t,unsigned int pos,const char *s) +{ +return PyTuple_SetItem (t, pos,PyString_FromString (s)); +} + +static int python_export_evsel (struct db_export *dbe,struct perf_evsel *evsel) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (2 ); + +tuple_set_u64 (t,0 , evsel->db_id); +tuple_set_string (t,1 ,perf_evsel__name (evsel)); + +call_object (tables->evsel_handler, t,"evsel_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_machine (struct db_export *dbe, +struct machine *machine) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (3 ); + +tuple_set_u64 (t,0 , machine->db_id); +tuple_set_s32 (t,1 , machine->pid); +tuple_set_string (t,2 , machine->root_dir ? machine->root_dir :"" ); + +call_object (tables->machine_handler, t,"machine_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_thread (struct db_export *dbe,struct thread *thread, +u64 main_thread_db_id,struct machine *machine) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (5 ); + +tuple_set_u64 (t,0 , thread->db_id); +tuple_set_u64 (t,1 , machine->db_id); +tuple_set_u64 (t,2 , main_thread_db_id); +tuple_set_s32 (t,3 , thread->pid_); +tuple_set_s32 (t,4 , thread->tid); + +call_object (tables->thread_handler, t,"thread_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_comm (struct db_export *dbe,struct comm *comm) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (2 ); + +tuple_set_u64 (t,0 , comm->db_id); +tuple_set_string (t,1 ,comm__str (comm)); + +call_object (tables->comm_handler, t,"comm_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_comm_thread (struct db_export *dbe,u64 db_id, +struct comm *comm,struct thread *thread) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (3 ); + +tuple_set_u64 (t,0 , db_id); +tuple_set_u64 (t,1 , comm->db_id); +tuple_set_u64 (t,2 , thread->db_id); + +call_object (tables->comm_thread_handler, t,"comm_thread_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_dso (struct db_export *dbe,struct dso *dso, +struct machine *machine) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +char sbuild_id[BUILD_ID_SIZE *2 +1 ]; +PyObject *t; + +build_id__sprintf (dso->build_id,sizeof (dso->build_id), sbuild_id); + + t =tuple_new (5 ); + +tuple_set_u64 (t,0 , dso->db_id); +tuple_set_u64 (t,1 , machine->db_id); +tuple_set_string (t,2 , dso->short_name); +tuple_set_string (t,3 , dso->long_name); +tuple_set_string (t,4 , sbuild_id); + +call_object (tables->dso_handler, t,"dso_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_symbol (struct db_export *dbe,struct symbol *sym, +struct dso *dso) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +u64 *sym_db_id =symbol__priv (sym); +PyObject *t; + + t =tuple_new (6 ); + +tuple_set_u64 (t,0 , *sym_db_id); +tuple_set_u64 (t,1 , dso->db_id); +tuple_set_u64 (t,2 , sym->start); +tuple_set_u64 (t,3 , sym->end); +tuple_set_s32 (t,4 , sym->binding); +tuple_set_string (t,5 , sym->name); + +call_object (tables->symbol_handler, t,"symbol_table" ); + +Py_DECREF (t); + +return 0 ; +} + +static int python_export_sample (struct db_export *dbe, +struct export_sample *es) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (19 ); + +tuple_set_u64 (t,0 , es->db_id); +tuple_set_u64 (t,1 , es->evsel->db_id); +tuple_set_u64 (t,2 , es->al->machine->db_id); +tuple_set_u64 (t,3 , es->thread->db_id); +tuple_set_u64 (t,4 , es->comm_db_id); +tuple_set_u64 (t,5 , es->dso_db_id); +tuple_set_u64 (t,6 , es->sym_db_id); +tuple_set_u64 (t,7 , es->offset); +tuple_set_u64 (t,8 , es->sample->ip); +tuple_set_u64 (t,9 , es->sample->time); +tuple_set_s32 (t,10 , es->sample->cpu); +tuple_set_u64 (t,11 , es->addr_dso_db_id); +tuple_set_u64 (t,12 , es->addr_sym_db_id); +tuple_set_u64 (t,13 , es->addr_offset); +tuple_set_u64 (t,14 , es->sample->addr); +tuple_set_u64 (t,15 , es->sample->period); +tuple_set_u64 (t,16 , es->sample->weight); +tuple_set_u64 (t,17 , es->sample->transaction); +tuple_set_u64 (t,18 , es->sample->data_src); + +call_object (tables->sample_handler, t,"sample_table" ); + +Py_DECREF (t); + +return 0 ; +} + static void python_process_general_event(struct perf_sample *sample, struct perf_evsel *evsel, struct thread *thread,
@@ -551,19 +775,25 @@ exit:Py_DECREF (t); } -static void python_process_event (union perf_event *event__maybe_unused , +static void python_process_event (union perf_event *event,struct perf_sample *sample,struct perf_evsel *evsel,struct thread *thread,struct addr_location *al) { +struct tables *tables = &tables_global; +switch (evsel->attr.type) {case PERF_TYPE_TRACEPOINT :python_process_tracepoint (sample, evsel, thread, al);break ;/* Reserve for future process_hw/sw/raw APIs */ default : -python_process_general_event (sample, evsel, thread, al); +if (tables->db_export_mode) +db_export__sample (&tables->dbe, event, sample, evsel, + thread, al); +else +python_process_general_event (sample, evsel, thread, al); } }
@@ -589,11 +819,57 @@ error:return -1 ; } +#define SET_TABLE_HANDLER_ (name, handler_name, table_name) do { \ + tables->handler_name = get_handler(#table_name); \ + if (tables->handler_name) \ + tables->dbe.export_ ## name = python_export_ ## name; \ +} while (0) + +#define SET_TABLE_HANDLER (name) \ + SET_TABLE_HANDLER_(name, name ## _handler, name ## _table) + +static void set_table_handlers (struct tables *tables) +{ +const char *perf_db_export_mode ="perf_db_export_mode" ; +PyObject *db_export_mode; +int ret; + +memset (tables,0 ,sizeof (struct tables )); +if (db_export__init (&tables->dbe)) +Py_FatalError ("failed to initialize export" ); + + db_export_mode =PyDict_GetItemString (main_dict, perf_db_export_mode); +if (!db_export_mode) +return ; + + ret =PyObject_IsTrue (db_export_mode); +if (ret ==-1 ) +handler_call_die (perf_db_export_mode); +if (!ret) +return ; + + tables->db_export_mode = true; +/* +* Reserve per symbol space for symbol->db_id via symbol__priv() +*/ + symbol_conf.priv_size =sizeof (u64); + +SET_TABLE_HANDLER (evsel); +SET_TABLE_HANDLER (machine); +SET_TABLE_HANDLER (thread); +SET_TABLE_HANDLER (comm); +SET_TABLE_HANDLER (comm_thread); +SET_TABLE_HANDLER (dso); +SET_TABLE_HANDLER (symbol); +SET_TABLE_HANDLER (sample); +} +/* * Start trace script */ static int python_start_script (const char *script,int argc,const char **argv) { +struct tables *tables = &tables_global;const char **command_line;char buf[PATH_MAX ];int i, err =0 ;
@@ -632,6 +908,8 @@ static int python_start_script(const char *script, int argc, const char **argv)free (command_line); +set_table_handlers (tables); +return err; error:Py_Finalize ();
@@ -650,8 +928,12 @@ static int python_flush_script(void)*/ static int python_stop_script (void ) { +struct tables *tables = &tables_global; +try_call_object ("trace_end" ,NULL ); +db_export__exit (&tables->dbe); +Py_XDECREF (main_dict);Py_XDECREF (main_module);Py_Finalize ();
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 30/32 perf script: Add Python script to export to postgresql
In reply to Arnaldo Carvalho de MeloFrom: Adrian Hunter <[email protected]>
Add a Python script to export to a postgresql database.
The script requires the Python pyside module and the Qt PostgreSQL driver. The packages needed are probably named "python-pyside" and "libqt4-sql-psql"
The caller of the script must be able to create postgresql databases.
The script takes the database name as a parameter. The database and database tables are created. Data is written to flat files which are then imported using SQL COPY FROM.
Example:
$ perf record ls
...
$ perf script report export-to-postgresql lsdb
2014-02-14 10:55:38.631431 Creating database...
2014-02-14 10:55:39.291958 Writing to intermediate files...
2014-02-14 10:55:39.350280 Copying to database...
2014-02-14 10:55:39.358536 Removing intermediate files...
2014-02-14 10:55:39.358665 Adding primary keys
2014-02-14 10:55:39.658697 Adding foreign keys
2014-02-14 10:55:39.667412 Done
$ psql lsdb
lsdb-# \d
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+-------
public | comm_threads | table | acme
public | comms | table | acme
public | dsos | table | acme
public | machines | table | acme
public | samples | table | acme
public | samples_view | view | acme
public | selected_events | table | acme
public | symbols | table | acme
public | threads | table | acme
(9 rows)
lsdb-# \d samples
Table "public.samples"
Column | Type | Modifiers
---------------+---------+-----------
id | bigint | not null
evsel_id | bigint |
machine_id | bigint |
thread_id | bigint |
comm_id | bigint |
dso_id | bigint |
symbol_id | bigint |
sym_offset | bigint |
ip | bigint |
time | bigint |
cpu | integer |
to_dso_id | bigint |
to_symbol_id | bigint |
to_sym_offset | bigint |
to_ip | bigint |
period | bigint |
weight | bigint |
transaction | bigint |
data_src | bigint |
Indexes:
"samples_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"commfk" FOREIGN KEY (comm_id) REFERENCES comms(id)
"dsofk" FOREIGN KEY (dso_id) REFERENCES dsos(id)
"evselfk" FOREIGN KEY (evsel_id) REFERENCES selected_events(id)
"machinefk" FOREIGN KEY (machine_id) REFERENCES machines(id)
"symbolfk" FOREIGN KEY (symbol_id) REFERENCES symbols(id)
"threadfk" FOREIGN KEY (thread_id) REFERENCES threads(id)
"todsofk" FOREIGN KEY (to_dso_id) REFERENCES dsos(id)
"tosymbolfk" FOREIGN KEY (to_symbol_id) REFERENCES symbols(id) lsdb-# \d samples_view
View "public.samples_view"
Column | Type | Modifiers
-------------------+-------------------------+-----------
id | bigint | time | bigint | cpu | integer | pid | integer | tid | integer | command | character varying(16) | event | character varying(80) | ip_hex | text | symbol | character varying(2048) | sym_offset | bigint | dso_short_name | character varying(256) | to_ip_hex | text | to_symbol | character varying(2048) | to_sym_offset | bigint | to_dso_short_name | character varying(256) |
lsdb=# select * from samples_view;
id| time |cpu | pid | tid |command| event | ip_hex | symbol |sym_off| dso_name|to_ip_hex|to_symbol|to_sym_off|to_dso_name
--+------------+----+------+------+-------+--------+---------------+---------------------+-------+---------+---------+---------+----------+----------
1 |12202825015 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown 2 |12203258804 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown 3 |12203988119 | -1 | 7339 | 7339 |:17339 | cycles | fffff8104d24a |native_write_msr_safe| 10 | [kernel]| 0 | unknown | 0| unknown
My notes (which may be out-of-date) on setting up postgresql so you can create databases:
fedora:
$ sudo yum install postgresql postgresql-server python-pyside qt-postgresql
$ sudo su - postgres -c initdb
$ sudo service postgresql start
$ sudo su - postgres
$ createuser -s <your username>I used the the unix user name in createuser.
If it fails, try createuser without -s and answer the following question to allow your user to create tables:
Shall the new role be a superuser? (y/n) y
ubuntu:
$ sudo apt-get install postgresql
$ sudo su - postgres
$ createuser <your username>
Shall the new role be a superuser? (y/n) yYou may want to disable automatic startup. One way is to edit /etc/postgresql/9.3/main/start.conf. Another is to disable the init script e.g. sudo update-rc.d postgresql disable
--- .../scripts/python/bin/export-to-postgresql-record | 8 + .../scripts/python/bin/export-to-postgresql-report | 24 ++ tools/perf/scripts/python/export-to-postgresql.py | 360 +++++++++++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-record create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-report create mode 100644 tools/perf/scripts/python/export-to-postgresql.py
tools/perf/scripts/python/bin/export-to-postgresql-record new file +8 -0
@@ -0,0 +1,8 @@ +#!/bin/bash + +# +# export perf data to a postgresql database. Can cover +# perf ip samples (excluding the tracepoints). No special +# record requirements, just record what you want to export. +# +perf record $@
tools/perf/scripts/python/bin/export-to-postgresql-report new file +24 -0
@@ -0,0 +1,24 @@ +#!/bin/bash +# description: export perf data to a postgresql database +# args: [database name] [columns] +n_args=0 +for i in "$@" +do + if expr match "$i" "-" > /dev/null ; then + break + fi + n_args=$(( $n_args + 1 )) +done +if [ "$n_args" -gt 2 ] ; then + echo "usage: export-to-postgresql-report [database name] [columns]" + exit +fi +if [ "$n_args" -gt 1 ] ; then + dbname=$1 + columns=$2 + shift 2 +elif [ "$n_args" -gt 0 ] ; then + dbname=$1 + shift +fi +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns
tools/perf/scripts/python/export-to-postgresql.py new file +360 -0
360 lines not on this page · raw message
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 31/32 perf probe: Trivial typo fix for --demangle
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Replace "Disable" with "Enable", since --demangle option enables symbol demangling, not disable it.
perf probe has --demangle and --no-demangle options, but the command-line help (--help) shows only --demangle option. So it should explain about --demangle.
--- tools/perf/builtin-probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-probe.c +1 -1
@@ -375,7 +375,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)OPT_CALLBACK ('x' ,"exec" ,NULL ,"executable|path" ,"target executable name or path" , opt_set_target),OPT_BOOLEAN (0 ,"demangle" , &symbol_conf.demangle, -"Disable symbol demangling" ), +"Enable symbol demangling" ),OPT_BOOLEAN (0 ,"demangle-kernel" , &symbol_conf.demangle_kernel,"Enable kernel symbol demangling" ),OPT_END ()
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 32/32 perf probe: Add --quiet option to suppress output result message
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Add --quiet(-q) option to suppress output result message for --add, and --del options (Note that --lines/funcs/vars are not affected). This option is useful if you run the perf probe inside your scripts.
--- tools/perf/builtin-probe.c | 11 +++++++++++ tools/perf/util/probe-event.c | 18 +++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-)
tools/perf/builtin-probe.c +11 -0
@@ -55,6 +55,7 @@ static struct {bool show_funcs;bool mod_events;bool uprobes; +bool quiet;int nevents;struct perf_probe_event events[MAX_PROBES ];struct strlist *dellist;
@@ -315,6 +316,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)struct option options[] = {OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show parsed arguments, etc)" ), +OPT_BOOLEAN ('q' ,"quiet" , ¶ms.quiet, +"be quiet (do not show any mesages)" ),OPT_BOOLEAN ('l' ,"list" , ¶ms.list_events,"list up current probe events" ), OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
@@ -404,6 +407,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) } } +if (params.quiet) { +if (verbose !=0 ) { +pr_err (" Error: -v and -q are exclusive.\n" ); +return -EINVAL ; + } + verbose =-1 ; + } +if (params.max_probe_points ==0 ) params.max_probe_points =MAX_PROBES ;
tools/perf/util/probe-event.c +9 -9
@@ -1910,21 +1910,21 @@ static int show_perf_probe_event(struct perf_probe_event *pev,if (ret <0 )return ret; -printf (" %-20s (on %s" , buf, place); +pr_info (" %-20s (on %s" , buf, place);if (module) -printf (" in %s" , module); +pr_info (" in %s" , module);if (pev->nargs >0 ) { -printf (" with" ); +pr_info (" with" );for (i =0 ; i < pev->nargs; i++) { ret =synthesize_perf_probe_arg (&pev->args[i], buf,128 );if (ret <0 )break ; -printf (" %s" , buf); +pr_info (" %s" , buf); } } -printf (")\n" ); +pr_info (")\n" );free (place);return ret; }
@@ -2124,7 +2124,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, } ret =0 ; -printf ("Added new event%s\n" , (ntevs >1 ) ?"s:" :":" ); +pr_info ("Added new event%s\n" , (ntevs >1 ) ?"s:" :":" );for (i =0 ; i < ntevs; i++) { tev = &tevs[i];if (pev->event)
@@ -2179,8 +2179,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,if (ret >=0 ) {/* Show how to use the event. */ -printf ("\nYou can now use it in all perf tools, such as:\n\n" ); -printf ("\tperf record -e %s:%s -aR sleep 1\n\n" , tev->group, +pr_info ("\nYou can now use it in all perf tools, such as:\n\n" ); +pr_info ("\tperf record -e %s:%s -aR sleep 1\n\n" , tev->group, tev->event); }
@@ -2444,7 +2444,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) goto error; } -printf ("Removed event: %s\n" , ent->s); +pr_info ("Removed event: %s\n" , ent->s);return 0 ; error: pr_warning("Failed to delete event: %s\n",
Signature · 1 line
1.9.3
Quoted 19 lines · Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <[email protected]>
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit
e53f6124af6516cee3063a3072767ee2717ff343:Merge tag 'perf-urgent-for-mingo' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/urgent (2014-10-24 09:46:36 +0200)are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingofor you to fetch changes up to
8eeeb304ea2714962b10873f72aa7c5e24f5265f:
Quoted 8 lines
perf probe: Add --quiet option to suppress output result message (2014-10-27 17:16:34 -0200)
----------------------------------------------------------------
perf/core improvements and fixes:User visible:
* 'perf probe' --demangle typo fix and a new --quiet option (Masami Hiramatsu)
So the fix part would be nice to have for perf/urgent I suspect?
Quoted 2 lines
* Fix report -F (abort,
in_tx, mispredict, etc) segfaults for sample.data files without branch info (Jiri Olsa)
Ditto.
Quoted 5 lines
* Don't open the DWARF info multiple times, keeping instead a dwfl handle in struct dso, greatly speeding up 'perf report' on powerpc. (Sukadev Bhattiprolu)
* Add patch that should have went in a previous patchkit to use global cache provided by libunwind (Namhyung Kim)
Given that this is already upstream, is this a required fix for perf/urgent or can it wait and go into perf/core?
And then the remaining bits should be based on the urgent tree.
Thanks,
Ingo
Arnaldo Carvalho de Melo
maintainerEm Wed, Oct 29, 2014 at 10:11:48AM +0100, Ingo Molnar escreveu:
Quoted 13 lines · Arnaldo Carvalho de Melo
Quoted 1 line
* 'perf probe' --demangle typo fix and a new --quiet option (Masami Hiramatsu)
So the fix part would be nice to have for perf/urgent I suspect?
Quoted 2 lines
* Fix report -F (abort,
in_tx, mispredict, etc) segfaults for sample.data files without branch info (Jiri Olsa)Ditto.
Quoted 2 lines
* Don't open the DWARF info multiple times, keeping instead a dwfl handle in struct dso, greatly speeding up 'perf report' on powerpc. (Sukadev Bhattiprolu)
Quoted 7 lines
Quoted 2 lines
* Add patch that should have went in a previous patchkit to use global cache provided by libunwind (Namhyung Kim)
Given that this is already upstream, is this a required fix for perf/urgent or can it wait and go into perf/core?
And then the remaining bits should be based on the urgent tree.
Ok, did the split, I thought that those were lower prio for corner cases and it all going via the next release, but sure, if you think it can go this time, lets do it :-)
- Arnaldo