perf tools: More preparation for call graph from Intel BTS
Adrian Hunter
reviewercover perf tools: More preparation for call graph from Intel BTS
Hi
Here is the next selection of patches based on tip/perf/core.
They can also be found here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme
Adrian Hunter (52):
perf tools: Fix jump label always changing during tracing
perf tools: Identify which comms are from exec
perf tools: Add machine__thread_exec_comm()
perf tools: Fix missing label symbols
perf tools: Add machine__kernel_ip()
perf script: Improve srcline display for BTS
perf script: Do not print dangling '=>' for BTS
perf tools: Fix incorrect fd error comparison
perf tools: Record whether a dso has data
perf tools: Add dso__data_status_seen()
perf tools: Let a user specify a PMU event without any config terms perf tools: Let default config be defined for a PMU
perf tools: Add perf_pmu__scan_file()
perf tools: Add dsos__hit_all()
perf tools: Add cpu to struct thread
perf tools: Add ability to record the current tid for each cpu
perf evlist: Add perf_evlist__set_tracking_event()
perf evlist: Add 'system_wide' option
perf tools: Add id index
perf pmu: Let pmu's with no events show up on perf list
perf session: Add ability to skip 4GiB or more
perf session: Add perf_session__deliver_synth_event()
perf tools: Move rdtsc() function
perf evlist: Add perf_evlist__enable_event_idx()
perf session: Add perf_session__peek_event()
perf tools: Add dso__data_size()
perf tools: Add a thread stack for synthesizing call chains
perf script: Allow callchains if any event samples them
perf inject: Add --kallsyms parameter
perf tools: Expose 'addr' functions so they can be reused
perf tools: Add facility to export data in database-friendly way
perf tools: Add helpers for calling Python objects
perf tools: Extend Python script interface to export data in a database-friendly way perf tools: Add Python script to export to postgresql
perf tools: Add flags and insn_len to struct sample
perf tools: Add branch type to db export
perf tools: Add branch_type and in_tx to Python export
perf tools: Enhance the thread stack to output call/return data
perf tools: Add call information to the database export API
perf tools: Add call information to Python export
perf tools: Add 'flush' callback to scripting API
perf tools: Defer export of comms that were not 'set'
perf tools: Add perf-with-kcore script
perf tools: Pass machine to vdso__dso_findnew()
perf tools: Group VDSO global variables into a structure
perf tools: Fix the lifetime of the VDSO temporary file
perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name
perf tools: Build programs to copy 32-bit compatibility VDSOs
perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew()
perf tools: Add support for 32-bit compatibility VDSOs
tools/perf/.gitignore | 1 + tools/perf/Documentation/perf-inject.txt | 3 + tools/perf/Makefile.perf | 46 +- tools/perf/arch/x86/util/tsc.c | 9 + tools/perf/builtin-inject.c | 3 + tools/perf/builtin-script.c | 89 ++- tools/perf/config/Makefile | 21 + tools/perf/config/Makefile.arch | 8 + tools/perf/perf-read-vdso.c | 59 ++ tools/perf/perf-with-kcore.sh | 259 ++++++++ .../scripts/python/bin/export-to-postgresql-record | 8 + .../scripts/python/bin/export-to-postgresql-report | 29 + tools/perf/scripts/python/export-to-postgresql.py | 444 +++++++++++++ tools/perf/tests/perf-time-to-tsc.c | 9 - tools/perf/tests/pmu.c | 2 +- tools/perf/util/cloexec.c | 9 +- tools/perf/util/comm.c | 7 +- tools/perf/util/comm.h | 7 +- tools/perf/util/db-export.c | 426 +++++++++++++ tools/perf/util/db-export.h | 107 ++++ tools/perf/util/dso.c | 70 ++- tools/perf/util/dso.h | 26 + tools/perf/util/event.c | 49 +- tools/perf/util/event.h | 53 ++ tools/perf/util/evlist.c | 138 ++++- tools/perf/util/evlist.h | 5 + tools/perf/util/evsel.c | 31 +- tools/perf/util/evsel.h | 5 + tools/perf/util/header.c | 51 +- tools/perf/util/header.h | 2 + tools/perf/util/machine.c | 109 +++- tools/perf/util/machine.h | 30 + tools/perf/util/map.c | 9 +- tools/perf/util/map.h | 5 +- tools/perf/util/parse-events.c | 13 +- tools/perf/util/parse-events.y | 10 + tools/perf/util/pmu.c | 92 ++- tools/perf/util/pmu.h | 13 +- .../perf/util/scripting-engines/trace-event-perl.c | 6 + .../util/scripting-engines/trace-event-python.c | 511 +++++++++++++-- tools/perf/util/session.c | 237 ++++++- tools/perf/util/session.h | 20 + tools/perf/util/symbol-elf.c | 37 +- tools/perf/util/symbol-minimal.c | 21 + tools/perf/util/symbol.h | 3 + tools/perf/util/thread-stack.c | 690 +++++++++++++++++++++ tools/perf/util/thread-stack.h | 79 +++ tools/perf/util/thread.c | 28 +- tools/perf/util/thread.h | 15 +- tools/perf/util/tool.h | 3 +- tools/perf/util/trace-event-scripting.c | 7 + tools/perf/util/trace-event.h | 1 + tools/perf/util/tsc.c | 5 + tools/perf/util/tsc.h | 1 + tools/perf/util/vdso.c | 264 +++++++- tools/perf/util/vdso.h | 15 +- 56 files changed, 3961 insertions(+), 239 deletions(-) create mode 100644 tools/perf/perf-read-vdso.c create mode 100644 tools/perf/perf-with-kcore.sh 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/thread-stack.c create mode 100644 tools/perf/util/thread-stack.h
Regards
Adrian
Adrian Hunter
reviewerPATCH 1/52 perf tools: Fix jump label always changing during tracing
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.
It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.
--- tools/perf/util/cloexec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
@@ -1,3 +1,4 @@ +#include <sched.h> #include "util.h" #include "../perf.h" #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void) };int fd;int err; +int cpu =sched_getcpu (); + +if (cpu <0 ) + cpu =0 ;/* check cloexec flag */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 , + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,PERF_FLAG_FD_CLOEXEC ); err = errno;
@@ -30,7 +35,7 @@ static int perf_flag_probe(void) err, strerror(err));/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 ,0 ); + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,0 ); err = errno; if (WARN_ONCE(fd < 0,
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.
It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.
And it is ok for our purposes, as this code just needs to figure out if PERF_FLAG_FD_CLOEXEC is present, but I wonder when this kind of thing will hit again...
Anyway, I'll take this patch.
- Arnaldo
Quoted 40 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/cloexec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)tools/perf/util/cloexec.c +7
-2@@ -1,3 +1,4 @@ +#include <sched.h> #include "util.h" #include "../perf.h" #include "cloexec.h" @@ -14,9 +15,13 @@ static int perf_flag_probe(void) };int fd;int err; +int cpu =sched_getcpu (); + +if (cpu <0 ) + cpu =0 ;/* check cloexec flag */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 , + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,PERF_FLAG_FD_CLOEXEC ); err = errno;@@ -30,7 +35,7 @@ static int perf_flag_probe(void) err, strerror(err));/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 ,0 ); + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,0 ); err = errno; if (WARN_ONCE(fd < 0,Signature · 1 line
1.8.3.2
Peter Zijlstra
maintainerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 3 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
You'd better fix that, jump_labels can change any time and they're all over the frigging place.
Adrian Hunter
reviewerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Quoted 9 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 3 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
You'd better fix that,
jump_labelscan change any time and they're all over the frigging place.
Perhaps a general method is needed to be able to deal with kernel self-modifying code.
Peter Zijlstra
maintainerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Quoted 7 lines · Adrian Hunter
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 3 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
Quoted 6 lines
Quoted 3 lines
You'd better fix that,
jump_labelscan change any time and they're all over the frigging place.Perhaps a general method is needed to be able to deal with kernel self-modifying code.
I know people are looking at doing the same to userspace, is that also a problem?
Adrian Hunter
reviewerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 3 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
You'd better fix that,
jump_labelscan change any time and they're all over the frigging place.
Quoted 5 lines
Quoted 2 lines
Perhaps a general method is needed to be able to deal with kernel self-modifying code.
I know people are looking at doing the same to userspace, is that also a problem?
Yes, most significantly JIT-compiled code.
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
Em Wed, Jul 23, 2014 at 10:15:45AM +0300, Adrian Hunter escreveu:
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Adrian Hunter
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Arnaldo Carvalho de Melo
Quoted 4 lines
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 3 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
You'd better fix that,
jump_labelscan change any time and they're all over the frigging place.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Perhaps a general method is needed to be able to deal with kernel self-modifying code.
I know people are looking at doing the same to userspace, is that also a problem?
Yes, most significantly JIT-compiled code.
It would be great to figure out the parts that were patched, so as to have the original and patched lines disassembled and properly marked as such in the annotation widgets, using a different colour, and allowing to flip to/from original/patched.
I wonder if there is some place with a list of the areas that were patched or that can be patched if enabled, etc, surely there is one for ftrace stuff, etc.
- Arnaldo
Adrian Hunter
reviewerRe: [PATCH 01/52] perf tools: Fix jump label always changing during tracing
In reply to Arnaldo Carvalho de MeloQuoted 8 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:
Quoted 7 lines
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.
Quoted 7 lines
Quoted 3 lines
It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.
And it is ok for our purposes, as this code just needs to figure out if
PERF_FLAG_FD_CLOEXECis present, but I wonder when this kind of thing will hit again...
Possibly
Quoted 2 lines
Anyway, I'll take this patch.
Thanks!
Quoted 45 lines
- Arnaldo
Quoted 40 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/cloexec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)tools/perf/util/cloexec.c +7
-2@@ -1,3 +1,4 @@ +#include <sched.h> #include "util.h" #include "../perf.h" #include "cloexec.h" @@ -14,9 +15,13 @@ static int perf_flag_probe(void) };int fd;int err; +int cpu =sched_getcpu (); + +if (cpu <0 ) + cpu =0 ;/* check cloexec flag */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 , + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,PERF_FLAG_FD_CLOEXEC ); err = errno;@@ -30,7 +35,7 @@ static int perf_flag_probe(void) err, strerror(err));/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 ,0 ); + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,0 ); err = errno; if (WARN_ONCE(fd < 0,Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Fix jump label always changing during tracing
In reply to Adrian Hunterperf tools: Fix jump label always changing during tracing
Commit-ID: deaff8b659cf4d34181c087b8cdf74f1eb17b02b Gitweb: http://git.kernel.org/tip/deaff8b659cf4d34181c087b8cdf74f1eb17b02b Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:10 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:12:59 -0300
perf tools: Fix jump label always changing during tracing
Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.
The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.
It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.
--- tools/perf/util/cloexec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
@@ -1,3 +1,4 @@ +#include <sched.h> #include "util.h" #include "../perf.h" #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void) };int fd;int err; +int cpu =sched_getcpu (); + +if (cpu <0 ) + cpu =0 ;/* check cloexec flag */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 , + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,PERF_FLAG_FD_CLOEXEC ); err = errno;
@@ -30,7 +35,7 @@ static int perf_flag_probe(void) err, strerror(err));/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ - fd =sys_perf_event_open (&attr,0 ,-1 ,-1 ,0 ); + fd =sys_perf_event_open (&attr,-1 , cpu,-1 ,0 ); err = errno; if (WARN_ONCE(fd < 0,
Adrian Hunter
reviewerPATCH 2/52 perf tools: Identify which comms are from exec
In reply to Adrian Hunter--- tools/perf/util/comm.c | 7 +++++-- tools/perf/util/comm.h | 6 ++++-- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 24 +++++++++++++++++++----- tools/perf/util/thread.h | 10 +++++++++- 5 files changed, 40 insertions(+), 11 deletions(-)
tools/perf/util/comm.c +5 -2
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)return new; } -struct comm *comm__new (const char *str,u64 timestamp) +struct comm *comm__new (const char *str,u64 timestamp,bool exec) {struct comm *comm =zalloc (sizeof (*comm));
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)return NULL ; comm->start = timestamp; + comm->exec = exec; comm->comm_str =comm_str__findnew (str, &comm_str_root);if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)return comm; } -int comm__override (struct comm *comm,const char *str,u64 timestamp) +int comm__override (struct comm *comm,const char *str,u64 timestamp,bool exec) {struct comm_str *new, *old = comm->comm_str;
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)comm_str__put (old); comm->comm_str = new; comm->start = timestamp; +if (exec && !comm->exec) + comm->exec = true;return 0 ; }
tools/perf/util/comm.h +4 -2
@@ -11,11 +11,13 @@ struct comm {struct comm_str *comm_str;u64 start;struct list_head list; + bool exec; };void comm__free (struct comm *comm); -struct comm *comm__new (const char *str,u64 timestamp); +struct comm *comm__new (const char *str,u64 timestamp,bool exec);const char *comm__str (const struct comm *comm); -int comm__override (struct comm *comm,const char *str,u64 timestamp); +int comm__override (struct comm *comm,const char *str,u64 timestamp, +bool exec);#endif /* __PERF_COMM_H */
tools/perf/util/machine.c +3 -1
@@ -397,11 +397,13 @@ int machine__process_comm_event(struct machine *machine, union perf_event *eventstruct thread *thread =machine__findnew_thread (machine, event->comm.pid, event->comm.tid); +bool exec = event->header.misc &PERF_RECORD_MISC_COMM_EXEC ;if (dump_trace)perf_event__fprintf_comm (event, stdout); -if (thread ==NULL ||thread__set_comm (thread, event->comm.comm, sample->time)) { +if (thread ==NULL || +__thread__set_comm (thread, event->comm.comm, sample->time, exec)) {dump_printf ("problem processing PERF_RECORD_COMM, skipping event.\n" );return -1 ; }
tools/perf/util/thread.c +19 -5
@@ -41,7 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) goto err_thread;snprintf (comm_str,32 ,":%d" , tid); - comm =comm__new (comm_str,0 ); + comm =comm__new (comm_str,0 , false);free (comm_str);if (!comm) goto err_thread;
@@ -80,19 +80,33 @@ struct comm *thread__comm(const struct thread *thread) return list_first_entry(&thread->comm_list, struct comm, list); } +struct comm *thread__exec_comm (const struct thread *thread) +{ +struct comm *comm, *last =NULL ; + +list_for_each_entry (comm, &thread->comm_list, list) { +if (comm->exec) +return comm; + last = comm; + } + +return last; +} +/* CHECKME: time should always be 0 if event aren't ordered */ -int thread__set_comm (struct thread *thread,const char *str,u64 timestamp) +int __thread__set_comm (struct thread *thread,const char *str,u64 timestamp, +bool exec) {struct comm *new, *curr =thread__comm (thread);int err;/* Override latest entry if it had no specific time coverage */ -if (!curr->start) { - err =comm__override (curr, str, timestamp); +if (!curr->start && !curr->exec) { + err =comm__override (curr, str, timestamp, exec);if (err)return err; }else { - new =comm__new (str, timestamp); + new =comm__new (str, timestamp, exec);if (!new)return -ENOMEM ;list_add (&new->list, &thread->comm_list);
tools/perf/util/thread.h +9 -1
@@ -37,9 +37,17 @@ static inline void thread__exited(struct thread *thread) thread->dead = true; } -int thread__set_comm (struct thread *thread,const char *comm,u64 timestamp); +int __thread__set_comm (struct thread *thread,const char *comm,u64 timestamp, +bool exec); +static inline int thread__set_comm (struct thread *thread,const char *comm, +u64 timestamp) +{ +return __thread__set_comm (thread, comm, timestamp, false); +} +int thread__comm_len (struct thread *thread);struct comm *thread__comm (const struct thread *thread); +struct comm *thread__exec_comm (const struct thread *thread);const char *thread__comm_str (const struct thread *thread);void thread__insert_map (struct thread *thread,struct map *map);int thread__fork (struct thread *thread,struct thread *parent,u64 timestamp);
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 3/52 perf tools: Add machine__thread_exec_comm()
In reply to Adrian HunterAdd machine__thread_exec_comm() to return the comm that matches the last exec, if the comm_exec flag is present, or the last comm otherwise.
--- tools/perf/util/machine.c | 26 ++++++++++++++++++++++++++ tools/perf/util/machine.h | 4 ++++ tools/perf/util/session.c | 24 +++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +26 -0
@@ -28,6 +28,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter =NULL ; machine->id_hdr_size =0 ; + machine->comm_exec = false; machine->root_dir =strdup (root_dir);if (machine->root_dir ==NULL )
@@ -172,6 +173,19 @@ void machines__set_symbol_filter(struct machines *machines, } } +void machines__set_comm_exec (struct machines *machines,bool comm_exec) +{ +struct rb_node *nd; + + machines->host.comm_exec = comm_exec; + +for (nd =rb_first (&machines->guests); nd; nd =rb_next (nd)) { + struct machine *machine = rb_entry(nd, struct machine, rb_node); + + machine->comm_exec = comm_exec; + } +} +struct machine *machines__find (struct machines *machines,pid_t pid) {struct rb_node **p = &machines->guests.rb_node;
@@ -391,6 +405,15 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,return __machine__findnew_thread (machine, pid, tid, false); } +struct comm *machine__thread_exec_comm (struct machine *machine, +struct thread *thread) +{ +if (machine->comm_exec) +return thread__exec_comm (thread); +else +return thread__comm (thread); +} +int machine__process_comm_event (struct machine *machine,union perf_event *event,struct perf_sample *sample) {
@@ -399,6 +422,9 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event event->comm.tid);bool exec = event->header.misc &PERF_RECORD_MISC_COMM_EXEC ; +if (exec) + machine->comm_exec = true; +if (dump_trace)perf_event__fprintf_comm (event, stdout);
tools/perf/util/machine.h +4 -0
@@ -24,6 +24,7 @@ struct machine {struct rb_node rb_node;pid_t pid;u16 id_hdr_size; +bool comm_exec;char *root_dir;struct rb_root threads;struct list_head dead_threads;
@@ -43,6 +44,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)struct thread *machine__find_thread (struct machine *machine,pid_t pid,pid_t tid); +struct comm *machine__thread_exec_comm (struct machine *machine, +struct thread *thread);int machine__process_comm_event (struct machine *machine,union perf_event *event,struct perf_sample *sample);
@@ -84,6 +87,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);void machines__set_symbol_filter (struct machines *machines,symbol_filter_t symbol_filter); +void machines__set_comm_exec (struct machines *machines,bool comm_exec);struct machine *machine__new_host (void );int machine__init (struct machine *machine,const char *root_dir,pid_t pid);
tools/perf/util/session.c +23 -1
@@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)machines__destroy_kernel_maps (&session->machines); } +static bool perf_session__has_comm_exec (struct perf_session *session) +{ +struct perf_evsel *evsel; + +evlist__for_each (session->evlist, evsel) { +if (evsel->attr.comm_exec) +return true; + } + +return false; +} + +static void perf_session__set_comm_exec (struct perf_session *session) +{ +bool comm_exec =perf_session__has_comm_exec (session); + +machines__set_comm_exec (&session->machines, comm_exec); +} +struct perf_session *perf_session__new (struct perf_data_file *file,bool repipe,struct perf_tool *tool) {
@@ -92,6 +111,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out_close;perf_session__set_id_hdr_size (session); +perf_session__set_comm_exec (session); } }
@@ -1006,8 +1026,10 @@ static int perf_session__process_user_event(struct perf_session *session, unionswitch (event->header.type) {case PERF_RECORD_HEADER_ATTR : err = tool->attr (tool, event, &session->evlist); -if (err ==0 ) +if (err ==0 ) {perf_session__set_id_hdr_size (session); +perf_session__set_comm_exec (session); + }return err;case PERF_RECORD_HEADER_EVENT_TYPE :/*
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 4/52 perf tools: Fix missing label symbols
In reply to Adrian Hunterlabel symbols are missing because elf_sec__is_a() fails to find the section because the section strings do not match the section headers because the sections headers are from the 'runtime' object and the sections strings are from the 'symbol source' object.
Fix by getting the section strings from the 'runtime' object so that they match the section headers.
--- tools/perf/util/symbol-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +1 -1
@@ -736,7 +736,7 @@ int dso__load_sym(struct dso *dso, struct map *map,if (symstrs ==NULL ) goto out_elf_end; - sec_strndx =elf_getscn (elf, ehdr.e_shstrndx); + sec_strndx =elf_getscn (runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);if (sec_strndx ==NULL ) goto out_elf_end;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 5/52 perf tools: Add machine__kernel_ip()
In reply to Adrian HunterAdd a function to determine if an address is in
the kernel. This is based on the kernel functionkernel_ip().
--- tools/perf/util/event.c | 6 +++--- tools/perf/util/machine.c | 23 +++++++++++++++++++++++ tools/perf/util/machine.h | 17 +++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-)
tools/perf/util/event.c +3 -3
@@ -784,9 +784,9 @@ try_again:* "[vdso]" dso, but for now lets use the old trick of looking * in the whole kernel symbol list. */ -if ((long long )al->addr <0 && - cpumode ==PERF_RECORD_MISC_USER && - machine && mg != &machine->kmaps) { +if (cpumode ==PERF_RECORD_MISC_USER && machine && + mg != &machine->kmaps && +machine__kernel_ip (machine, al->addr)) { mg = &machine->kmaps; load_map = true; goto try_again;
tools/perf/util/machine.c +23 -0
@@ -29,6 +29,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter =NULL ; machine->id_hdr_size =0 ; machine->comm_exec = false; + machine->kernel_start =0 ; machine->root_dir =strdup (root_dir);if (machine->root_dir ==NULL )
@@ -1509,3 +1510,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too/* command specified */ return 0 ; } + +int machine__get_kernel_start (struct machine *machine) +{ +struct map *map =machine__kernel_map (machine,MAP__FUNCTION ); +int err =0 ; + +/* +* The only addresses above 2^63 are kernel addresses of a 64-bit +* kernel. Note that addresses are unsigned so that on a 32-bit system +* all addresses including kernel addresses are less than 2^32. In +* that case (32-bit system), if the kernel mapping is unknown, all +* addresses will be assumed to be in user space - see +* machine__kernel_ip(). +*/ + machine->kernel_start =1ULL <<63 ; +if (map) { + err =map__load (map, machine->symbol_filter); +if (map->start) + machine->kernel_start = map->start; + } +return err; +}
tools/perf/util/machine.h +17 -0
@@ -33,6 +33,7 @@ struct machine {struct list_head kernel_dsos;struct map_groups kmaps;struct map *vmlinux_maps[MAP__NR_TYPES ]; +u64 kernel_start;symbol_filter_t symbol_filter; };
@@ -42,6 +43,22 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)return machine->vmlinux_maps[type]; } +int machine__get_kernel_start (struct machine *machine); + +static inline u64 machine__kernel_start (struct machine *machine) +{ +if (!machine->kernel_start) +machine__get_kernel_start (machine); +return machine->kernel_start; +} + +static inline bool machine__kernel_ip (struct machine *machine,u64 ip) +{ +u64 kernel_start =machine__kernel_start (machine); + +return ip >= kernel_start; +} +struct thread *machine__find_thread (struct machine *machine,pid_t pid,pid_t tid); struct comm *machine__thread_exec_comm(struct machine *machine,
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 6/52 perf script: Improve srcline display for BTS
In reply to Adrian HunterChange the order of the output to put the srcline last. e.g. old format:
4028fc main+0x2c (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0 set_program_name+0x0 (/bin/ls)
new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269
--- tools/perf/builtin-script.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -5
@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event, struct addr_location *al) {struct perf_event_attr *attr = &evsel->attr; +bool print_srcline_last = false;/* print branch_from information */ if (PRINT_FIELD (IP )) { -if (!symbol_conf.use_callchain) -printf (" " ); -else +unsigned int print_opts = output[attr->type].print_ip_opts; + +if (symbol_conf.use_callchain && sample->callchain) {printf ("\n" ); -perf_evsel__print_ip (evsel, sample, al, - output[attr->type].print_ip_opts, + }else { +printf (" " ); +if (print_opts &PRINT_IP_OPT_SRCLINE ) { + print_srcline_last = true; + print_opts &= ~PRINT_IP_OPT_SRCLINE ; + } + } +perf_evsel__print_ip (evsel, sample, al, print_opts,PERF_MAX_STACK_DEPTH ); }
@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event, !output[attr->type].user_set))print_sample_addr (event, sample, al->machine, thread, attr); +if (print_srcline_last) +map__fprintf_srcline (al->map, al->addr,"\n " , stdout); +printf ("\n" ); }
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf script: Improve srcline display for BTS
perf script: Improve srcline display for BTS
Commit-ID: 8066be5fe755e95ee6a858bbcf4e6b9e933e1866 Gitweb: http://git.kernel.org/tip/8066be5fe755e95ee6a858bbcf4e6b9e933e1866 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:15 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:14:40 -0300
perf script: Improve srcline display for BTS
Change the order of the output to put the srcline last.
It puts the branch 'from address' and 'to address' on the same line, which is how it would be without the source line reference.
So it makes it consistent and much easier to read.
E.g. old format:
4028fc main+0x2c (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0 set_program_name+0x0 (/bin/ls)
new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269
--- tools/perf/builtin-script.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -5
@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event, struct addr_location *al) {struct perf_event_attr *attr = &evsel->attr; +bool print_srcline_last = false;/* print branch_from information */ if (PRINT_FIELD (IP )) { -if (!symbol_conf.use_callchain) -printf (" " ); -else +unsigned int print_opts = output[attr->type].print_ip_opts; + +if (symbol_conf.use_callchain && sample->callchain) {printf ("\n" ); -perf_evsel__print_ip (evsel, sample, al, - output[attr->type].print_ip_opts, + }else { +printf (" " ); +if (print_opts &PRINT_IP_OPT_SRCLINE ) { + print_srcline_last = true; + print_opts &= ~PRINT_IP_OPT_SRCLINE ; + } + } +perf_evsel__print_ip (evsel, sample, al, print_opts,PERF_MAX_STACK_DEPTH ); }
@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event, !output[attr->type].user_set))print_sample_addr (event, sample, al->machine, thread, attr); +if (print_srcline_last) +map__fprintf_srcline (al->map, al->addr,"\n " , stdout); +printf ("\n" ); }
Adrian Hunter
reviewerPATCH 7/52 perf script: Do not print dangling '=>' for BTS
In reply to Adrian HunterWhen using:
perf record -e branches:u -c1
perf script -f ip
lines are displayed like:
ffffffff813b23d5 =>
Change so that the dangling '=>' does not appear.
--- tools/perf/builtin-script.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-script.c +3 -3
@@ -446,13 +446,13 @@ static void print_sample_bts(union perf_event *event, PERF_MAX_STACK_DEPTH); } -printf (" => " ); -/* print branch_to information */ if (PRINT_FIELD (ADDR ) || ((evsel->attr.sample_type &PERF_SAMPLE_ADDR ) && - !output[attr->type].user_set)) + !output[attr->type].user_set)) { +printf (" => " );print_sample_addr (event, sample, al->machine, thread, attr); + }if (print_srcline_last)map__fprintf_srcline (al->map, al->addr,"\n " , stdout);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf script: Do not print dangling '=>' for BTS
perf script: Do not print dangling '=>' for BTS
Commit-ID: 578bea40058b68f83658827c2b68a596b08419fc Gitweb: http://git.kernel.org/tip/578bea40058b68f83658827c2b68a596b08419fc Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:16 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:18:00 -0300
perf script: Do not print dangling '=>' for BTS
When using:
perf record -e branches:u -c1 usleep 1
perf script -f ip
lines are displayed like:
ffffffff813b23d5 =>
Change so that the dangling '=>' does not appear.
--- tools/perf/builtin-script.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-script.c +3 -3
@@ -446,13 +446,13 @@ static void print_sample_bts(union perf_event *event, PERF_MAX_STACK_DEPTH); } -printf (" => " ); -/* print branch_to information */ if (PRINT_FIELD (ADDR ) || ((evsel->attr.sample_type &PERF_SAMPLE_ADDR ) && - !output[attr->type].user_set)) + !output[attr->type].user_set)) { +printf (" => " );print_sample_addr (event, sample, al->machine, thread, attr); + }if (print_srcline_last)map__fprintf_srcline (al->map, al->addr,"\n " , stdout);
Adrian Hunter
reviewerPATCH 8/52 perf tools: Fix incorrect fd error comparison
In reply to Adrian HunterZero is a valid fd. Error comparison should check for negative fd.
--- tools/perf/util/dso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/dso.c +1 -1
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine) {int fd =__open_dso (dso, machine); -if (fd >0 ) { +if (fd >=0 ) {dso__list_add (dso);/* * Check if we crossed the allowed number
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 9/52 perf tools: Record whether a dso has data
In reply to Adrian HunterAdd 'data.status' to record whether a dso has data (i.e. an object file). This is used to avoid repeatedly creating the file name and attempting to open a file that is not present.
--- tools/perf/util/dso.c | 23 +++++++++++++++-------- tools/perf/util/dso.h | 7 +++++++ 2 files changed, 22 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +15 -8
@@ -331,26 +331,32 @@ int dso__data_fd(struct dso *dso, struct machine *machine) };int i =0 ; +if (dso->data.status ==DSO_DATA_STATUS_ERROR ) +return -1 ; +if (dso->data.fd >=0 ) -return dso->data.fd; + goto out;if (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ) { dso->data.fd =open_dso (dso, machine); -return dso->data.fd; + goto out; }do { -int fd; - dso->binary_type = binary_type_data[i++]; - fd =open_dso (dso, machine); -if (fd >=0 ) -return dso->data.fd = fd; + dso->data.fd =open_dso (dso, machine); +if (dso->data.fd >=0 ) + goto out; }while (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ); +out: +if (dso->data.fd >=0 ) + dso->data.status =DSO_DATA_STATUS_OK ; +else + dso->data.status =DSO_DATA_STATUS_ERROR ; -return -EINVAL ; +return dso->data.fd; } static void
@@ -701,6 +707,7 @@ struct dso *dso__new(const char *name) dso->symbols[i] = dso->symbol_names[i] =RB_ROOT ; dso->data.cache =RB_ROOT ; dso->data.fd =-1 ; + dso->data.status =DSO_DATA_STATUS_UNKNOWN ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->is_64_bit = (sizeof (void *) ==8 );
tools/perf/util/dso.h +7 -0
@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, }; +enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int status;size_t file_size;struct list_head open_entry; } data;
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Record whether a dso has data
perf tools: Record whether a dso has data
Commit-ID: c27697d6dee02ef2389b6701c792a075bc9873dc Gitweb: http://git.kernel.org/tip/c27697d6dee02ef2389b6701c792a075bc9873dc Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:18 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:22:35 -0300
perf tools: Record whether a dso has data
Add 'data.status' to record whether a dso has data (i.e. an object file). This is used to avoid repeatedly creating the file name and attempting to open a file that is not present.
--- tools/perf/util/dso.c | 23 +++++++++++++++-------- tools/perf/util/dso.h | 7 +++++++ 2 files changed, 22 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +15 -8
@@ -331,26 +331,32 @@ int dso__data_fd(struct dso *dso, struct machine *machine) };int i =0 ; +if (dso->data.status ==DSO_DATA_STATUS_ERROR ) +return -1 ; +if (dso->data.fd >=0 ) -return dso->data.fd; + goto out;if (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ) { dso->data.fd =open_dso (dso, machine); -return dso->data.fd; + goto out; }do { -int fd; - dso->binary_type = binary_type_data[i++]; - fd =open_dso (dso, machine); -if (fd >=0 ) -return dso->data.fd = fd; + dso->data.fd =open_dso (dso, machine); +if (dso->data.fd >=0 ) + goto out; }while (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ); +out: +if (dso->data.fd >=0 ) + dso->data.status =DSO_DATA_STATUS_OK ; +else + dso->data.status =DSO_DATA_STATUS_ERROR ; -return -EINVAL ; +return dso->data.fd; } static void
@@ -701,6 +707,7 @@ struct dso *dso__new(const char *name) dso->symbols[i] = dso->symbol_names[i] =RB_ROOT ; dso->data.cache =RB_ROOT ; dso->data.fd =-1 ; + dso->data.status =DSO_DATA_STATUS_UNKNOWN ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->is_64_bit = (sizeof (void *) ==8 );
tools/perf/util/dso.h +7 -0
@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, }; +enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int status;size_t file_size;struct list_head open_entry; } data;
Adrian Hunter
reviewerPATCH 10/52 perf tools: Add dso__data_status_seen()
In reply to Adrian HunterAdd a function to track whether a caller has seen
the data status of a dso. This is needed to
enable callers to report the error exactly once
only per dso.
--- tools/perf/util/dso.c | 12 ++++++++++++ tools/perf/util/dso.h | 6 ++++++ 2 files changed, 18 insertions(+)
tools/perf/util/dso.c +12 -0
@@ -359,6 +359,18 @@ out:return dso->data.fd; } +bool dso__data_status_seen (struct dso *dso,enum dso_data_status_seen by) +{ +u32 flag =1 << by; + +if (dso->data.status_seen & flag) +return true; + + dso->data.status_seen |= flag; + +return false; +} +static void dso_cache__free (struct rb_root *root) {
tools/perf/util/dso.h +6 -0
@@ -46,6 +46,10 @@ enum dso_data_status { DSO_DATA_STATUS_OK = 1, }; +enum dso_data_status_seen { +DSO_DATA_STATUS_SEEN_ITRACE , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -111,6 +115,7 @@ struct dso {struct rb_root cache;int fd;int status; +u32 status_seen;size_t file_size;struct list_head open_entry; } data;
@@ -203,6 +208,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,ssize_t dso__data_read_addr (struct dso *dso,struct map *map,struct machine *machine,u64 addr,u8 *data,ssize_t size); +bool dso__data_status_seen (struct dso *dso,enum dso_data_status_seen by);struct map *dso__new_map (const char *name); struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add dso__data_status_seen()
perf tools: Add dso__data_status_seen()
Commit-ID: 288be943b5024729cd6809b61b62f727960178f3 Gitweb: http://git.kernel.org/tip/288be943b5024729cd6809b61b62f727960178f3 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:19 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:23:44 -0300
perf tools: Add dso__data_status_seen()
Add a function to track whether a caller has seen the data status of a dso. This is needed to enable callers to report the error exactly once only per dso.
--- tools/perf/util/dso.c | 12 ++++++++++++ tools/perf/util/dso.h | 6 ++++++ 2 files changed, 18 insertions(+)
tools/perf/util/dso.c +12 -0
@@ -359,6 +359,18 @@ out:return dso->data.fd; } +bool dso__data_status_seen (struct dso *dso,enum dso_data_status_seen by) +{ +u32 flag =1 << by; + +if (dso->data.status_seen & flag) +return true; + + dso->data.status_seen |= flag; + +return false; +} +static void dso_cache__free (struct rb_root *root) {
tools/perf/util/dso.h +6 -0
@@ -46,6 +46,10 @@ enum dso_data_status { DSO_DATA_STATUS_OK = 1, }; +enum dso_data_status_seen { +DSO_DATA_STATUS_SEEN_ITRACE , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -111,6 +115,7 @@ struct dso {struct rb_root cache;int fd;int status; +u32 status_seen;size_t file_size;struct list_head open_entry; } data;
@@ -203,6 +208,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,ssize_t dso__data_read_addr (struct dso *dso,struct map *map,struct machine *machine,u64 addr,u8 *data,ssize_t size); +bool dso__data_status_seen (struct dso *dso,enum dso_data_status_seen by);struct map *dso__new_map (const char *name); struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
Adrian Hunter
reviewerPATCH 11/52 perf tools: Let a user specify a PMU event without any config terms
In reply to Adrian HunterThis enables a PMU event to be specified in the form:
pmu//
which is effectively the same as:
pmu/config=0/
This patch is a precursor to defining
default config for a PMU.
--- tools/perf/util/parse-events.c | 6 ++++++ tools/perf/util/parse-events.y | 10 ++++++++++ 2 files changed, 16 insertions(+)
tools/perf/util/parse-events.c +6 -0
@@ -644,6 +644,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,memset (&attr,0 ,sizeof (attr)); +if (!head_config) { + attr.type = pmu->type; + evsel =__add_event (list, idx, &attr,NULL , pmu->cpus); +return evsel ?0 : -ENOMEM ; + } +if (perf_pmu__check_alias (pmu, head_config, &unit, &scale))return -EINVAL ;
tools/perf/util/parse-events.y +10 -0
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/' parse_events__free_terms($3); $$ = list; } +| +PE_NAME '/' '/' +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL)); + $$ = list; +} value_sym: PE_VALUE_SYM_HW
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 12/52 perf tools: Let default config be defined for a PMU
In reply to Adrian HunterThis allows default config terms to be provided
for a PMU. So, for example, when the Intel PT
PMU is added, it will be possible to specify:
intel_pt//
which will be the same as:
intel_pt/tsc=1,noretcomp=0/
meaning that the trace should contain
TSC timestamps and perform 'return
compression'.
An important consideration of this
patch is that it must be possible
to overwrite the default values.
That has meant changing the logic
so that a zero value can replace
a non-zero value.
--- tools/perf/tests/pmu.c | 2 +- tools/perf/util/parse-events.c | 7 ++++++- tools/perf/util/pmu.c | 42 ++++++++++++++++++++++++++---------------- tools/perf/util/pmu.h | 9 ++++++++- 4 files changed, 41 insertions(+), 19 deletions(-)
tools/perf/tests/pmu.c +1 -1
@@ -152,7 +152,7 @@ int test__pmu(void)if (ret)break ; - ret =perf_pmu__config_terms (&formats, &attr, terms); + ret =perf_pmu__config_terms (&formats, &attr, terms, false);if (ret)break ;
tools/perf/util/parse-events.c +6 -1
@@ -642,7 +642,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,if (!pmu)return -EINVAL ; -memset (&attr,0 ,sizeof (attr)); +if (pmu->default_config) { +memcpy (&attr, pmu->default_config, +sizeof (struct perf_event_attr )); + }else { +memset (&attr,0 ,sizeof (attr)); + }if (!head_config) { attr.type = pmu->type;
tools/perf/util/pmu.c +26 -16
105 lines not on this page · raw message
tools/perf/util/pmu.h +8 -1
@@ -13,9 +13,12 @@ enum {#define PERF_PMU_FORMAT_BITS 64 +struct perf_event_attr ; +struct perf_pmu {char *name;__u32 type; +struct perf_event_attr *default_config;struct cpu_map *cpus;struct list_head format;struct list_head aliases;
@@ -27,7 +30,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, struct list_head *head_terms);int perf_pmu__config_terms (struct list_head *formats,struct perf_event_attr *attr, -struct list_head *head_terms); +struct list_head *head_terms, +bool zero);int perf_pmu__check_alias (struct perf_pmu *pmu,struct list_head *head_terms,const char **unit,double *scale); struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
@@ -46,4 +50,7 @@ void print_pmu_events(const char *event_glob, bool name_only);bool pmu_have_event (const char *pname,const char *name);int perf_pmu__test (void ); + +struct perf_event_attr *perf_pmu__get_default_config (struct perf_pmu *pmu); +#endif /* __PMU_H */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 13/52 perf tools: Add perf_pmu__scan_file()
In reply to Adrian HunterAdd a function to scan a sysfs file within the pmu device directory.
This will be used to read capability values from the PMU 'caps' subdirectory.
--- tools/perf/util/pmu.c | 37 +++++++++++++++++++++++++++++++++++++ tools/perf/util/pmu.h | 3 +++ 2 files changed, 40 insertions(+)
tools/perf/util/pmu.c +37 -0
@@ -3,6 +3,7 @@#include <unistd.h> #include <stdio.h> #include <stdbool.h> +#include <stdarg.h> #include <dirent.h> #include <api/fs/fs.h> #include <locale.h>
@@ -804,3 +805,39 @@ bool pmu_have_event(const char *pname, const char *name) }return false; } + +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs) +return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); + +if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +} + +int perf_pmu__scan_file (struct perf_pmu *pmu,const char *name,const char *fmt, + ...) +{ +va_list args; +FILE *file; +int ret =EOF ; + +va_start (args, fmt); + file =perf_pmu__open_file (pmu, name); +if (file) { + ret =vfscanf (file, fmt, args); +fclose (file); + } +va_end (args); +return ret; +}
tools/perf/util/pmu.h +3 -0
@@ -49,6 +49,9 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);void print_pmu_events (const char *event_glob,bool name_only);bool pmu_have_event (const char *pname,const char *name); +int perf_pmu__scan_file (struct perf_pmu *pmu,const char *name,const char *fmt, + ...) __attribute__((format (scanf,3 ,4 ))); +int perf_pmu__test (void );struct perf_event_attr *perf_pmu__get_default_config (struct perf_pmu *pmu);
Signature · 1 line
1.8.3.2
Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:
SNIP
Quoted 9 lines
tools/perf/util/pmu.c +9
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs)
tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 10 lines
tools/perf/util/pmu.c +10
-0+return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); + +if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}
looks like this function could be used in pmu_cpumask and pmu_type and maybe others
jirka
Adrian Hunter
reviewerRe: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
Quoted 18 lines · Jiri Olsa
On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:
SNIP
Quoted 14 lines
tools/perf/util/pmu.c +14
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs) +return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); +
Quoted 8 lines
tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 5 lines
tools/perf/util/pmu.c +5
-0+if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}looks like this function could be used in
pmu_cpumaskandpmu_typeand maybe others
There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.
Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
Quoted 28 lines · Adrian Hunter
Quoted 18 lines · Jiri Olsa
On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:
SNIP
Quoted 14 lines
tools/perf/util/pmu.c +14
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs) +return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); +Quoted 8 lines
tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 5 lines
tools/perf/util/pmu.c +5
-0+if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}looks like this function could be used in
pmu_cpumaskandpmu_typeand maybe others
Quoted 2 lines
There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.
ook, jirka
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:
Quoted 29 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 26 lines · Adrian Hunter
SNIP
Quoted 9 lines
tools/perf/util/pmu.c +9
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs)tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 10 lines
tools/perf/util/pmu.c +10
-0+return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); + +if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}looks like this function could be used in
pmu_cpumaskandpmu_typeand maybe others
Quoted 4 lines
Quoted 2 lines
There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.
ook, jirka
Is this an Acked-by: jirka?
- Arnaldo
Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
Quoted 30 lines · Arnaldo Carvalho de Melo
Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:
Quoted 29 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 26 lines · Adrian Hunter
SNIP
Quoted 9 lines
tools/perf/util/pmu.c +9
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs)tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 10 lines
tools/perf/util/pmu.c +10
-0+return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); + +if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}looks like this function could be used in
pmu_cpumaskandpmu_typeand maybe others
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.
ook, jirka
Is this an Acked-by: jirka?
well, while perf_pmu__open_file would be handy now, perf_pmu__scan_file does now have any callers in the patchset..
I'm not sure whats our current policy one this ;-) as I've seen more functions like this over this patchset, I think we should not introduce new interface without caller
jirka
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()
Em Thu, Jul 24, 2014 at 12:06:06PM +0200, Jiri Olsa escreveu:
Quoted 36 lines · Arnaldo Carvalho de Melo
Quoted 35 lines
Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:
Quoted 33 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
SNIP
Quoted 14 lines
tools/perf/util/pmu.c +14
-0+ +static FILE *perf_pmu__open_file (struct perf_pmu *pmu,const char *name) +{ +struct stat st; +char path[PATH_MAX ]; +const char *sysfs; + + sysfs =sysfs__mountpoint (); +if (!sysfs) +return NULL ; + +snprintf (path,PATH_MAX , +"%s" EVENT_SOURCE_DEVICE_PATH "%s/%s" , sysfs, pmu->name, name); +Quoted 8 lines
tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826
Quoted 5 lines
tools/perf/util/pmu.c +5
-0+if (stat (path, &st) <0 ) +return NULL ; + +return fopen (path,"r" ); +}looks like this function could be used in
pmu_cpumaskandpmu_typeand maybe othersQuoted 2 lines
There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.
ook, jirka
Quoted 8 lines
Quoted 1 line
Is this an Acked-by: jirka?
well, while
perf_pmu__open_filewould be handy now,perf_pmu__scan_filedoes now have any callers in the patchset..I'm not sure whats our current policy one this ;-) as I've seen more functions like this over this patchset, I think we should not introduce new interface without caller
Its a huge patchkit, with some bits non trivial, reducing it s size so that the most hairy bits can stand out seems like a good approach at this point. :-)
- Arnaldo
Adrian Hunter
reviewerPATCH 14/52 perf tools: Add dsos__hit_all()
In reply to Adrian HunterAdd ability to mark all dsos as hit.
This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.
--- tools/perf/util/header.c | 41 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 2 ++ 2 files changed, 43 insertions(+)
tools/perf/util/header.c +41 -0
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,return write_padded (fd, name, name_len +1 , len); } +static int __dsos__hit_all (struct list_head *head) +{ +struct dso *pos; + +list_for_each_entry (pos, head, node) + pos->hit = true; + +return 0 ; +} + +static int machine__hit_all_dsos (struct machine *machine) +{ +int err; + + err =__dsos__hit_all (&machine->kernel_dsos); +if (err) +return err; + +return __dsos__hit_all (&machine->user_dsos); +} + +int dsos__hit_all (struct perf_session *session) +{ +struct rb_node *nd; +int err; + + err =machine__hit_all_dsos (&session->machines.host); +if (err) +return err; + +for (nd =rb_first (&session->machines.guests); nd; nd =rb_next (nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + + err =machine__hit_all_dsos (pos); +if (err) +return err; + } + +return 0 ; +} +static int __dsos__write_buildid_table (struct list_head *head,struct machine *machine,pid_t pid,u16 misc,int fd)
tools/perf/util/header.h +2 -0
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool, struct perf_session *session);bool is_perf_magic (u64 magic); +int dsos__hit_all (struct perf_session *session); +/* * arch specific callback */
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add dsos__hit_all()
perf tools: Add dsos__hit_all()
Commit-ID: 1f625b0b3dd641b74ba21640a1fea19a3dd893a2 Gitweb: http://git.kernel.org/tip/1f625b0b3dd641b74ba21640a1fea19a3dd893a2 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:23 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:25:40 -0300
perf tools: Add dsos__hit_all()
Add ability to mark all dsos as hit.
This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.
--- tools/perf/util/header.c | 41 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 2 ++ 2 files changed, 43 insertions(+)
tools/perf/util/header.c +41 -0
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,return write_padded (fd, name, name_len +1 , len); } +static int __dsos__hit_all (struct list_head *head) +{ +struct dso *pos; + +list_for_each_entry (pos, head, node) + pos->hit = true; + +return 0 ; +} + +static int machine__hit_all_dsos (struct machine *machine) +{ +int err; + + err =__dsos__hit_all (&machine->kernel_dsos); +if (err) +return err; + +return __dsos__hit_all (&machine->user_dsos); +} + +int dsos__hit_all (struct perf_session *session) +{ +struct rb_node *nd; +int err; + + err =machine__hit_all_dsos (&session->machines.host); +if (err) +return err; + +for (nd =rb_first (&session->machines.guests); nd; nd =rb_next (nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + + err =machine__hit_all_dsos (pos); +if (err) +return err; + } + +return 0 ; +} +static int __dsos__write_buildid_table (struct list_head *head,struct machine *machine,pid_t pid,u16 misc,int fd)
tools/perf/util/header.h +2 -0
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool, struct perf_session *session);bool is_perf_magic (u64 magic); +int dsos__hit_all (struct perf_session *session); +/* * arch specific callback */
Adrian Hunter
reviewerPATCH 15/52 perf tools: Add cpu to struct thread
In reply to Adrian HunterTools may wish to track on which cpu a thread
is running. Add 'cpu' to struct thread for
that purpose.
This will be used to determine the cpu when
decoding a per-thread Instruction Trace.
--- tools/perf/util/thread.c | 1 + tools/perf/util/thread.h | 1 + 2 files changed, 2 insertions(+)
tools/perf/util/thread.c +1 -0
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->pid_ = pid; thread->tid = tid; thread->ppid =-1 ; + thread->cpu =-1 ;INIT_LIST_HEAD (&thread->comm_list); comm_str =malloc (32 );
tools/perf/util/thread.h +1 -0
@@ -17,6 +17,7 @@ struct thread {pid_t pid_;/* Not all tools update this */ pid_t tid;pid_t ppid; +int cpu;char shortname[3 ];bool comm_set;bool dead;/* if set thread has exited */
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add cpu to struct thread
perf tools: Add cpu to struct thread
Commit-ID: bf49c35f630452d85c9cd7205a72df841e8d99b9 Gitweb: http://git.kernel.org/tip/bf49c35f630452d85c9cd7205a72df841e8d99b9 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:24 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:27:50 -0300
perf tools: Add cpu to struct thread
Tools may wish to track on which cpu a thread is running. Add 'cpu' to struct thread for that purpose.
This will be used to determine the cpu when decoding a per-thread Instruction Trace.
E.g: Intel PT decoding uses sched_switch events to determine which task is running on which cpu. The Intel PT data comes straight from the hardware which doesn't know about linux threads.
--- tools/perf/util/thread.c | 1 + tools/perf/util/thread.h | 1 + 2 files changed, 2 insertions(+)
tools/perf/util/thread.c +1 -0
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->pid_ = pid; thread->tid = tid; thread->ppid =-1 ; + thread->cpu =-1 ;INIT_LIST_HEAD (&thread->comm_list); comm_str =malloc (32 );
tools/perf/util/thread.h +1 -0
@@ -17,6 +17,7 @@ struct thread {pid_t pid_;/* Not all tools update this */ pid_t tid;pid_t ppid; +int cpu;char shortname[3 ];bool comm_set;bool dead;/* if set thread has exited */
Adrian Hunter
reviewerPATCH 16/52 perf tools: Add ability to record the current tid for each cpu
In reply to Adrian HunterAdd an array to struct machine to store the current tid running on each cpu. Add machine functions to get / set the tid for a cpu.
This will be used to determine the tid when decoding a per-cpu Instruction Trace.
--- tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 5 +++++ 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
@@ -47,6 +47,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)thread__set_comm (thread, comm,0 ); } + machine->current_tid =NULL ; +return 0 ; }
@@ -106,6 +108,7 @@ void machine__exit(struct machine *machine)dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos);zfree (&machine->root_dir); +zfree (&machine->current_tid); }void machine__delete (struct machine *machine)
@@ -1532,3 +1535,46 @@ int machine__get_kernel_start(struct machine *machine) }return err; } + +pid_t machine__get_current_tid (struct machine *machine,int cpu) +{ +if (cpu <0 || cpu >=MAX_NR_CPUS || !machine->current_tid) +return -1 ; + +return machine->current_tid[cpu]; +} + +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid) +{ +struct thread *thread; + +if (cpu <0 ) +return -EINVAL ; + +if (!machine->current_tid) { +int i; + + machine->current_tid =calloc (MAX_NR_CPUS ,sizeof (pid_t)); +if (!machine->current_tid) +return -ENOMEM ; +for (i =0 ; i <MAX_NR_CPUS ; i++) + machine->current_tid[i] =-1 ; + } + +if (cpu >=MAX_NR_CPUS ) { +pr_err ("Requested CPU %d too large. " , cpu); +pr_err ("Consider raising MAX_NR_CPUS\n" ); +return -EINVAL ; + } + + machine->current_tid[cpu] = tid; + + thread =machine__findnew_thread (machine, pid, tid); +if (!thread) +return -ENOMEM ; + + thread->cpu = cpu; + +return 0 ; +}
tools/perf/util/machine.h +5 -0
@@ -35,6 +35,7 @@ struct machine {struct map *vmlinux_maps[MAP__NR_TYPES ];u64 kernel_start;symbol_filter_t symbol_filter; +pid_t *current_tid; }; static inline
@@ -212,4 +213,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target, perf_event__process, data_mmap); } +pid_t machine__get_current_tid (struct machine *machine,int cpu); +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid); +#endif /* __PERF_MACHINE_H */
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 16/52] perf tools: Add ability to record the current tid for each cpu
Em Tue, Jul 22, 2014 at 04:17:25PM +0300, Adrian Hunter escreveu:
Quoted 7 lines
Add an array to struct machine to store the current tid running on each cpu. Add machine functions to get / set the tid for a cpu.
This will be used to determine the tid when decoding a per-cpu Instruction Trace.
Most machines don't have MAX_NR_CPUS cpus, but then this per-machine struct cost will be suffered only by tools that use this new facility, so it wouldn't be fair at this point to ask you to use a growing array.
See tools/perf/builtin-trace.c trace__set_fd_pathname() to see how it does for a thread fd->pathname table learn't from either reading /proc/PID/fd/ or using 'perf probe' made vfs_getname wannabe-tracepoints.
But in general, try to avoid using these FOO_MAX_BAR things :-\
- Arnaldo
Quoted 97 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 5 +++++ 2 files changed, 51 insertions(+)tools/perf/util/machine.c +46
-0@@ -47,6 +47,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)thread__set_comm (thread, comm,0 ); } + machine->current_tid =NULL ; +return 0 ; }@@ -106,6 +108,7 @@ void machine__exit(struct machine *machine)dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos);zfree (&machine->root_dir); +zfree (&machine->current_tid); }void machine__delete (struct machine *machine)@@ -1532,3 +1535,46 @@ int machine__get_kernel_start(struct machine *machine) }return err; } + +pid_t machine__get_current_tid (struct machine *machine,int cpu) +{ +if (cpu <0 || cpu >=MAX_NR_CPUS || !machine->current_tid) +return -1 ; + +return machine->current_tid[cpu]; +} + +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid) +{ +struct thread *thread; + +if (cpu <0 ) +return -EINVAL ; + +if (!machine->current_tid) { +int i; + + machine->current_tid =calloc (MAX_NR_CPUS ,sizeof (pid_t)); +if (!machine->current_tid) +return -ENOMEM ; +for (i =0 ; i <MAX_NR_CPUS ; i++) + machine->current_tid[i] =-1 ; + } + +if (cpu >=MAX_NR_CPUS ) { +pr_err ("Requested CPU %d too large. " , cpu); +pr_err ("Consider raising MAX_NR_CPUS\n" ); +return -EINVAL ; + } + + machine->current_tid[cpu] = tid; + + thread =machine__findnew_thread (machine, pid, tid); +if (!thread) +return -ENOMEM ; + + thread->cpu = cpu; + +return 0 ; +}tools/perf/util/machine.h +5
-0@@ -35,6 +35,7 @@ struct machine {struct map *vmlinux_maps[MAP__NR_TYPES ];u64 kernel_start;symbol_filter_t symbol_filter; +pid_t *current_tid; }; static inline@@ -212,4 +213,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target, perf_event__process, data_mmap); } +pid_t machine__get_current_tid (struct machine *machine,int cpu); +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid); +#endif /* __PERF_MACHINE_H */ Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Add ability to record the current tid for each cpu
In reply to Adrian Hunterperf machine: Add ability to record the current tid for each cpu
Commit-ID: b9d266baac0429f70df3f9cf751b045730d612e3 Gitweb: http://git.kernel.org/tip/b9d266baac0429f70df3f9cf751b045730d612e3 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:25 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:35:43 -0300
perf machine: Add ability to record the current tid for each cpu
Add an array to struct machine to store the current tid running on each cpu.
Add machine functions to get / set the tid for a cpu.
This will be used to determine the tid when decoding a per-cpu Instruction Trace.
--- tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 5 +++++ 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
@@ -45,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)thread__set_comm (thread, comm,0 ); } + machine->current_tid =NULL ; +return 0 ; }
@@ -104,6 +106,7 @@ void machine__exit(struct machine *machine)dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos);zfree (&machine->root_dir); +zfree (&machine->current_tid); }void machine__delete (struct machine *machine)
@@ -1481,3 +1484,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too/* command specified */ return 0 ; } + +pid_t machine__get_current_tid (struct machine *machine,int cpu) +{ +if (cpu <0 || cpu >=MAX_NR_CPUS || !machine->current_tid) +return -1 ; + +return machine->current_tid[cpu]; +} + +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid) +{ +struct thread *thread; + +if (cpu <0 ) +return -EINVAL ; + +if (!machine->current_tid) { +int i; + + machine->current_tid =calloc (MAX_NR_CPUS ,sizeof (pid_t)); +if (!machine->current_tid) +return -ENOMEM ; +for (i =0 ; i <MAX_NR_CPUS ; i++) + machine->current_tid[i] =-1 ; + } + +if (cpu >=MAX_NR_CPUS ) { +pr_err ("Requested CPU %d too large. " , cpu); +pr_err ("Consider raising MAX_NR_CPUS\n" ); +return -EINVAL ; + } + + machine->current_tid[cpu] = tid; + + thread =machine__findnew_thread (machine, pid, tid); +if (!thread) +return -ENOMEM ; + + thread->cpu = cpu; + +return 0 ; +}
tools/perf/util/machine.h +5 -0
@@ -33,6 +33,7 @@ struct machine {struct map_groups kmaps;struct map *vmlinux_maps[MAP__NR_TYPES ];symbol_filter_t symbol_filter; +pid_t *current_tid; }; static inline
@@ -191,4 +192,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target, perf_event__process, data_mmap); } +pid_t machine__get_current_tid (struct machine *machine,int cpu); +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid); +#endif /* __PERF_MACHINE_H */
Adrian Hunter
reviewerPATCH 17/52 perf evlist: Add perf_evlist__set_tracking_event()
In reply to Adrian HunterAdd a function to change which event is used to track mmap, comm and task events.
This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.
--- tools/perf/util/evlist.c | 20 ++++++++++++++++++++ tools/perf/util/evlist.h | 3 +++ 2 files changed, 23 insertions(+)
tools/perf/util/evlist.c +20 -0
@@ -1250,3 +1250,23 @@ void perf_evlist__to_front(struct perf_evlist *evlist,list_splice (&move, &evlist->entries); } + +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel) +{ +struct perf_evsel *evsel; + +if (tracking_evsel->idx ==0 ) +return 0 ; + +if (tracking_evsel->leader->nr_members >1 ) +return -EINVAL ; + +list_for_each_entry (evsel, &evlist->entries, node) { +if (evsel->idx < tracking_evsel->idx) + evsel->idx +=1 ; + } + tracking_evsel->idx =0 ; + +return 0 ; +}
tools/perf/util/evlist.h +3 -0
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,#define evlist__for_each_safe (evlist, tmp, evsel) \ __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel); +#endif /* __PERF_EVLIST_H */
Signature · 1 line
1.8.3.2
Re: [PATCH 17/52] perf evlist: Add perf_evlist__set_tracking_event()
On Tue, Jul 22, 2014 at 04:17:26PM +0300, Adrian Hunter wrote:
SNIP
Quoted 11 lines
}
tools/perf/util/evlist.c +10
-0+ +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel) +{ +struct perf_evsel *evsel; + +if (tracking_evsel->idx ==0 ) +return 0 ; + +if (tracking_evsel->leader->nr_members >1 )
tools/perf/util/evlist.c void perf_evlist__to_front(struct perf_evlist *evlist, · line 1272
Quoted 10 lines
tools/perf/util/evlist.c +10
-0+return -EINVAL ; + +list_for_each_entry (evsel, &evlist->entries, node) { +if (evsel->idx < tracking_evsel->idx) + evsel->idx +=1 ; + } + tracking_evsel->idx =0 ; + +return 0 ; +}
wouldnt it be better to add evsel->is_tracking bool for this?
jirka
Adrian Hunter
reviewerRe: [PATCH 17/52] perf evlist: Add perf_evlist__set_tracking_event()
Quoted 19 lines · Jiri Olsa
On Tue, Jul 22, 2014 at 04:17:26PM +0300, Adrian Hunter wrote:
SNIP
Quoted 15 lines
}
tools/perf/util/evlist.c +14
-0+ +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel) +{ +struct perf_evsel *evsel; + +if (tracking_evsel->idx ==0 ) +return 0 ; + +if (tracking_evsel->leader->nr_members >1 ) +return -EINVAL ; + +list_for_each_entry (evsel, &evlist->entries, node) { +if (evsel->idx < tracking_evsel->idx)
Quoted 8 lines
tools/perf/util/evlist.c void perf_evlist__to_front(struct perf_evlist *evlist, · line 1272
Quoted 6 lines
tools/perf/util/evlist.c +6
-0+ evsel->idx +=1 ; + } + tracking_evsel->idx =0 ; + +return 0 ; +}wouldnt it be better to add
evsel->is_trackingbool for this?
Yes, I will look at doing that instead.
Adrian Hunter
reviewerPATCH v2 17/52 perf evlist: Add perf_evlist__set_tracking_event()
Add a function to change which event is used to track mmap, comm and task events.
This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.
---
V2:
Changed to use evsel->tracking as suggested by Jiri
Note this patch now applies after the patch
"perf evlist: Add 'system_wide' option"
The change is reflected in the branch here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme
tools/perf/util/evlist.c | 17 +++++++++++++++++ tools/perf/util/evlist.h | 3 +++ tools/perf/util/evsel.c | 3 ++- tools/perf/util/evsel.h | 1 + tools/perf/util/record.c | 2 +- 5 files changed, 24 insertions(+), 2 deletions(-)
tools/perf/util/evlist.c +17 -0
@@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) {list_add_tail (&entry->node, &evlist->entries); entry->idx = evlist->nr_entries; + entry->tracking = !entry->idx;if (!evlist->nr_entries++)perf_evlist__set_id_pos (evlist);
@@ -1279,3 +1280,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,list_splice (&move, &evlist->entries); } + +void perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel) +{ +struct perf_evsel *evsel; + +if (tracking_evsel->tracking) +return ; + +evlist__for_each (evlist, evsel) { +if (evsel != tracking_evsel) + evsel->tracking = false; + } + + tracking_evsel->tracking = true; +}
tools/perf/util/evlist.h +3 -0
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,#define evlist__for_each_safe (evlist, tmp, evsel) \ __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +void perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel); +#endif /* __PERF_EVLIST_H */
tools/perf/util/evsel.c +2 -1
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { evsel->idx = idx; + evsel->tracking = !idx; evsel->attr = *attr; evsel->leader = evsel; evsel->unit ="" ;
@@ -561,7 +562,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) {struct perf_evsel *leader = evsel->leader;struct perf_event_attr *attr = &evsel->attr; -int track = !evsel->idx;/* only the first counter needs these */ +int track = evsel->tracking;bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; attr->sample_id_all = perf_missing_features.sample_id_all ?0 :1 ;
tools/perf/util/evsel.h +1 -0
@@ -86,6 +86,7 @@ struct perf_evsel {bool no_aux_samples;bool immediate;bool system_wide; +bool tracking;/* parse modifier helper */ int exclude_GH;int nr_members;
tools/perf/util/record.c +1 -1
@@ -106,7 +106,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)evlist__for_each (evlist, evsel) {perf_evsel__config (evsel, opts); -if (!evsel->idx && use_comm_exec) +if (evsel->tracking && use_comm_exec) evsel->attr.comm_exec =1 ; }
Signature · 1 line
1.8.3.2
Re: [PATCH V2 17/52] perf evlist: Add perf_evlist__set_tracking_event()
Quoted 10 lines · Adrian Hunter
Add a function to change which event is used to track mmap, comm and task events.
This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.
Signed-off-by Adrian Hunter <[email protected]>
thanks,
jirka
Adrian Hunter
reviewerPATCH 18/52 perf evlist: Add 'system_wide' option
In reply to Adrian HunterAdd an option to cause a selected event to be opened always without a pid when configured by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object code execution. sched_switch occurs before the task switch and so it cannot record it in a context limited to that task. Note that also means that sched_switch is useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.
--- tools/perf/util/evlist.c | 45 +++++++++++++++++++++++++++++++++++++-------- tools/perf/util/evsel.c | 31 ++++++++++++++++++++++++++----- tools/perf/util/evsel.h | 1 + 3 files changed, 64 insertions(+), 13 deletions(-)
tools/perf/util/evlist.c +37 -8
@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,return 0 ; } +static int perf_evlist__nr_threads (struct perf_evlist *evlist, +struct perf_evsel *evsel) +{ +if (evsel->system_wide) +return 1 ; +else +return thread_map__nr (evlist->threads); +} +void perf_evlist__disable (struct perf_evlist *evlist) {int cpu, thread;struct perf_evsel *pos;int nr_cpus =cpu_map__nr (evlist->cpus); -int nr_threads =thread_map__nr (evlist->threads); +int nr_threads;for (cpu =0 ; cpu < nr_cpus; cpu++) {evlist__for_each (evlist, pos) {if (!perf_evsel__is_group_leader (pos) || !pos->fd)continue ; + nr_threads =perf_evlist__nr_threads (evlist, pos);for (thread =0 ; thread < nr_threads; thread++)ioctl (FD (pos, cpu, thread),PERF_EVENT_IOC_DISABLE ,0 );
@@ -288,12 +298,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)int cpu, thread;struct perf_evsel *pos;int nr_cpus =cpu_map__nr (evlist->cpus); -int nr_threads =thread_map__nr (evlist->threads); +int nr_threads;for (cpu =0 ; cpu < nr_cpus; cpu++) {evlist__for_each (evlist, pos) {if (!perf_evsel__is_group_leader (pos) || !pos->fd)continue ; + nr_threads =perf_evlist__nr_threads (evlist, pos);for (thread =0 ; thread < nr_threads; thread++)ioctl (FD (pos, cpu, thread),PERF_EVENT_IOC_ENABLE ,0 );
@@ -305,12 +316,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel) {int cpu, thread, err; +int nr_cpus =cpu_map__nr (evlist->cpus); +int nr_threads =perf_evlist__nr_threads (evlist, evsel);if (!evsel->fd)return 0 ; -for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) { -for (thread =0 ; thread < evlist->threads->nr; thread++) { +for (cpu =0 ; cpu < nr_cpus; cpu++) { +for (thread =0 ; thread < nr_threads; thread++) { err =ioctl (FD (evsel, cpu, thread),PERF_EVENT_IOC_DISABLE ,0 );if (err)
@@ -324,12 +337,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, struct perf_evsel *evsel) {int cpu, thread, err; +int nr_cpus =cpu_map__nr (evlist->cpus); +int nr_threads =perf_evlist__nr_threads (evlist, evsel);if (!evsel->fd)return -EINVAL ; -for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) { -for (thread =0 ; thread < evlist->threads->nr; thread++) { +for (cpu =0 ; cpu < nr_cpus; cpu++) { +for (thread =0 ; thread < nr_threads; thread++) { err =ioctl (FD (evsel, cpu, thread),PERF_EVENT_IOC_ENABLE ,0 );if (err)
@@ -343,7 +358,16 @@ static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) {int nr_cpus =cpu_map__nr (evlist->cpus);int nr_threads =thread_map__nr (evlist->threads); -int nfds = nr_cpus * nr_threads * evlist->nr_entries; +int nfds =0 ; +struct perf_evsel *evsel; + +list_for_each_entry (evsel, &evlist->entries, node) { +if (evsel->system_wide) + nfds += nr_cpus; +else + nfds += nr_cpus * nr_threads; + } + evlist->pollfd =malloc (sizeof (struct pollfd ) * nfds);return evlist->pollfd !=NULL ?0 : -ENOMEM ; }
@@ -636,7 +660,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,struct perf_evsel *evsel;evlist__for_each (evlist, evsel) { -int fd =FD (evsel, cpu, thread); +int fd; + +if (evsel->system_wide && thread) +continue ; + + fd =FD (evsel, cpu, thread);if (*output ==-1 ) { *output = fd;
tools/perf/util/evsel.c +26 -5
@@ -692,6 +692,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)int perf_evsel__alloc_fd (struct perf_evsel *evsel,int ncpus,int nthreads) {int cpu, thread; + +if (evsel->system_wide) + nthreads =1 ; + evsel->fd =xyarray__new (ncpus, nthreads,sizeof (int ));if (evsel->fd) {
@@ -710,6 +714,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea {int cpu, thread; +if (evsel->system_wide) + nthreads =1 ; +for (cpu =0 ; cpu < ncpus; cpu++) {for (thread =0 ; thread < nthreads; thread++) { int fd = FD(evsel, cpu, thread),
@@ -740,6 +747,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)int perf_evsel__alloc_id (struct perf_evsel *evsel,int ncpus,int nthreads) { +if (evsel->system_wide) + nthreads =1 ; + evsel->sample_id =xyarray__new (ncpus, nthreads,sizeof (struct perf_sample_id ));if (evsel->sample_id ==NULL )return -ENOMEM ;
@@ -784,6 +794,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) {int cpu, thread; +if (evsel->system_wide) + nthreads =1 ; +for (cpu =0 ; cpu < ncpus; cpu++)for (thread =0 ; thread < nthreads; ++thread) {close (FD (evsel, cpu, thread));
@@ -872,6 +885,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,int cpu, thread;struct perf_counts_values *aggr = &evsel->counts->aggr, count; +if (evsel->system_wide) + nthreads =1 ; + aggr->val = aggr->ena = aggr->run =0 ;for (cpu =0 ; cpu < ncpus; cpu++) {
@@ -994,13 +1010,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)static int __perf_evsel__open (struct perf_evsel *evsel,struct cpu_map *cpus,struct thread_map *threads) { -int cpu, thread; +int cpu, thread, nthreads;unsigned long flags =PERF_FLAG_FD_CLOEXEC ;int pid =-1 , err;enum {NO_CHANGE ,SET_TO_MAX ,INCREASED_MAX } set_rlimit =NO_CHANGE ; +if (evsel->system_wide) + nthreads =1 ; +else + nthreads = threads->nr; +if (evsel->fd ==NULL && -perf_evsel__alloc_fd (evsel, cpus->nr, threads->nr) <0 ) +perf_evsel__alloc_fd (evsel, cpus->nr, nthreads) <0 )return -ENOMEM ;if (evsel->cgrp) {
@@ -1024,10 +1045,10 @@ retry_sample_id:for (cpu =0 ; cpu < cpus->nr; cpu++) { -for (thread =0 ; thread < threads->nr; thread++) { +for (thread =0 ; thread < nthreads; thread++) {int group_fd; -if (!evsel->cgrp) +if (!evsel->cgrp && !evsel->system_wide) pid = threads->map[thread]; group_fd =get_group_fd (evsel, cpu, thread);
@@ -1100,7 +1121,7 @@ out_close:close (FD (evsel, cpu, thread));FD (evsel, cpu, thread) =-1 ; } - thread = threads->nr; + thread = nthreads; }while (--cpu >=0 );return err; }
tools/perf/util/evsel.h +1 -0
@@ -85,6 +85,7 @@ struct perf_evsel {bool needs_swap;bool no_aux_samples;bool immediate; +bool system_wide;/* parse modifier helper */ int exclude_GH;int nr_members;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 19/52 perf tools: Add id index
In reply to Adrian HunterAdd an index of the event identifiers.
This is needed to queue Instruction
Trace samples according to the mmap
buffer from which they were recorded.
--- tools/perf/builtin-inject.c | 1 + tools/perf/util/event.c | 1 + tools/perf/util/event.h | 15 ++++++ tools/perf/util/evlist.c | 26 ++++++++-- tools/perf/util/evsel.h | 3 ++ tools/perf/util/session.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.h | 10 ++++ tools/perf/util/tool.h | 3 +- 8 files changed, 177 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +1 -0
@@ -419,6 +419,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .tracing_data = perf_event__repipe_op2_synth, .finished_round = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, + .id_index = perf_event__repipe_op2_synth, }, .input_name = "-", .samples = LIST_HEAD_INIT(inject.samples),
tools/perf/util/event.c +1 -0
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", + [PERF_RECORD_ID_INDEX] = "ID_INDEX", };const char *perf_event__name (unsigned int id)
tools/perf/util/event.h +15 -0
@@ -185,6 +185,7 @@ enum perf_user_event_type { /* above any possible kernel type */PERF_RECORD_HEADER_TRACING_DATA =66 ,PERF_RECORD_HEADER_BUILD_ID =67 ,PERF_RECORD_FINISHED_ROUND =68 , +PERF_RECORD_ID_INDEX =69 , PERF_RECORD_HEADER_MAX };
@@ -211,6 +212,19 @@ struct tracing_data_event {u32 size; }; +struct id_index_entry { +u64 id; +u64 idx; +u64 cpu; +u64 tid; +}; + +struct id_index_event { +struct perf_event_header header; +u64 nr; +struct id_index_entry entries[0 ]; +}; +union perf_event {struct perf_event_header header;struct mmap_event mmap;
@@ -225,6 +239,7 @@ union perf_event {struct event_type_event event_type;struct tracing_data_event tracing_data;struct build_id_event build_id; +struct id_index_event id_index; };void perf_event__print_totals (void );
tools/perf/util/evlist.c +23 -3
@@ -441,6 +441,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,return 0 ; } +static void perf_evlist__set_sid_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx,int cpu, +int thread) +{ +struct perf_sample_id *sid =SID (evsel, cpu, thread); + sid->idx = idx; +if (evlist->cpus && cpu >=0 ) + sid->cpu = evlist->cpus->map[cpu]; +else + sid->cpu =-1 ; +if (!evsel->system_wide && evlist->threads && thread >=0 ) + sid->tid = evlist->threads->map[thread]; +else + sid->tid =-1 ; +} +struct perf_sample_id *perf_evlist__id2sid (struct perf_evlist *evlist,u64 id) {struct hlist_head *head;
@@ -676,9 +692,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,return -1 ; } -if ((evsel->attr.read_format &PERF_FORMAT_ID ) && -perf_evlist__id_add_fd (evlist, evsel, cpu, thread, fd) <0 ) -return -1 ; +if (evsel->attr.read_format &PERF_FORMAT_ID ) { +if (perf_evlist__id_add_fd (evlist, evsel, cpu, thread, + fd) <0 ) +return -1 ; +perf_evlist__set_sid_idx (evlist, evsel, idx, cpu, + thread); + } }return 0 ;
tools/perf/util/evsel.h +3 -0
@@ -38,6 +38,9 @@ struct perf_sample_id {struct hlist_node node;u64 id;struct perf_evsel *evsel; +int idx; +int cpu; +pid_t tid;/* Holds total ID period value for PERF_SAMPLE_READ processing. */ u64 period;
tools/perf/util/session.c +122 -0
149 lines not on this page · raw message
tools/perf/util/session.h +10 -0
@@ -129,4 +129,14 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,extern volatile int session_done;#define session_done () (*(volatile int *)(&session_done)) + +int perf_event__process_id_index (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session); + +int perf_event__synthesize_id_index (struct perf_tool *tool, +perf_event__handler_t process, +struct perf_evlist *evlist, +struct machine *machine); +#endif /* __PERF_SESSION_H */
tools/perf/util/tool.h +2 -1
@@ -39,7 +39,8 @@ struct perf_tool {event_attr_op attr;event_op2 tracing_data;event_op2 finished_round, - build_id; + build_id, + id_index;bool ordered_samples;bool ordering_requires_timestamps; };
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 20/52 perf pmu: Let pmu's with no events show up on perf list
In reply to Adrian Hunterperf 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
@@ -749,15 +749,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" );
@@ -774,6 +777,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;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 21/52 perf session: Add ability to skip 4GiB or more
In reply to Adrian HunterA session can be made to skip portions of the input file. Do not limit that size to 32-bits.
--- tools/perf/util/session.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
tools/perf/util/session.c +13 -7
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event, -struct perf_tool *tool,u64 file_offset) +static s64 perf_session__process_user_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {int fd =perf_data_file__fd (session->file);int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, +static s64 perf_session__process_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,union perf_event *event;uint32_t size, cur_size =0 ;void *buf =NULL ; -int skip =0 ; +s64 skip =0 ;u64 head;ssize_t err;void *p;
@@ -1313,13 +1315,13 @@ int __perf_session__process_events(struct perf_session *session, u64 file_size, struct perf_tool *tool) { int fd = perf_data_file__fd(session->file); -u64 head, page_offset, file_offset, file_pos; +u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;size_t mmap_size;char *buf, *mmaps[NUM_MMAPS ];union perf_event *event; -uint32_t size;struct ui_progress prog; +s64 skip;perf_tool__fill_defaults (tool);
@@ -1380,7 +1382,8 @@ more: size = event->header.size;if (size <sizeof (struct perf_event_header ) || -perf_session__process_event (session, event, tool, file_pos) <0 ) { + (skip =perf_session__process_event (session, event, tool, file_pos)) + <0 ) {pr_err ("%#" PRIx64" [%#x]: failed to process type: %d\n" , file_offset + head, event->header.size, event->header.type);
@@ -1388,6 +1391,9 @@ more: goto out_err; } +if (skip) + size += skip; + head += size; file_pos += size;
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 21/52] perf session: Add ability to skip 4GiB or more
Em Tue, Jul 22, 2014 at 04:17:30PM +0300, Adrian Hunter escreveu:
Quoted 2 lines
A session can be made to skip portions of the input file. Do not limit that size to 32-bits.
Aren't there two changes here? One that is described in the changelog, another that makes the value returned by perf_session__process_event to be properly used if > 0?
Can you please split and provide relevant changeset comments?
- Arnaldo
Quoted 67 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/session.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)tools/perf/util/session.c +10
-7@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event, -struct perf_tool *tool,u64 file_offset) +static s64 perf_session__process_user_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {int fd =perf_data_file__fd (session->file);int err;@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, +static s64 perf_session__process_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset)@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,union perf_event *event;uint32_t size, cur_size =0 ;void *buf =NULL ; -int skip =0 ; +s64 skip =0 ;u64 head;ssize_t err;void *p;@@ -1313,13 +1315,13 @@ int __perf_session__process_events(struct perf_session *session, u64 file_size, struct perf_tool *tool) { int fd = perf_data_file__fd(session->file); -u64 head, page_offset, file_offset, file_pos; +u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;size_t mmap_size;char *buf, *mmaps[NUM_MMAPS ];union perf_event *event; -uint32_t size;struct ui_progress prog; +s64 skip;perf_tool__fill_defaults (tool);@@ -1380,7 +1382,8 @@ more: size = event->header.size;if (size <sizeof (struct perf_event_header ) || -perf_session__process_event (session, event, tool, file_pos) <0 ) { + (skip =perf_session__process_event (session, event, tool, file_pos)) + <0 ) {pr_err ("%#" PRIx64" [%#x]: failed to process type: %d\n" , file_offset + head, event->header.size, event->header.type);
tools/perf/util/session.c more: · line 1396
Quoted 6 lines
tools/perf/util/session.c +3
-0@@ -1388,6 +1391,9 @@ more: goto out_err; } +if (skip) + size += skip; +
I.e. the above
Quoted 5 lines
tools/perf/util/session.c +0
-0head += size; file_pos += size;Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 1/2 perf session: Add ability to 'skip' a non-piped event stream
A piped event stream may contain arbitary sized tracepoint information following a PERF_RECORD_HEADER_TRACING_DATA event. The position in the stream has to be 'skipped' to match the start of the next event.
Provide the same ability to a non-piped event stream to allow for Instruction Trace data that may also be in a non-piped event stream.
--- tools/perf/util/session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/session.c +6 -1
@@ -1320,6 +1320,7 @@ int __perf_session__process_events(struct perf_session *session,union perf_event *event;uint32_t size;struct ui_progress prog; +int skip;perf_tool__fill_defaults (tool);
@@ -1380,7 +1381,8 @@ more: size = event->header.size;if (size <sizeof (struct perf_event_header ) || -perf_session__process_event (session, event, tool, file_pos) <0 ) { + (skip =perf_session__process_event (session, event, tool, file_pos)) + <0 ) {pr_err ("%#" PRIx64" [%#x]: failed to process type: %d\n" , file_offset + head, event->header.size, event->header.type);
@@ -1388,6 +1390,9 @@ more: goto out_err; } +if (skip) + size += skip; + head += size; file_pos += size;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 2/2 perf session: Add ability to skip 4GiB or more
A session can be made to skip portions of the input file. Do not limit that size to 32-bits.
--- tools/perf/util/session.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
tools/perf/util/session.c +8 -7
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event, -struct perf_tool *tool,u64 file_offset) +static s64 perf_session__process_user_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {int fd =perf_data_file__fd (session->file);int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, +static s64 perf_session__process_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,union perf_event *event;uint32_t size, cur_size =0 ;void *buf =NULL ; -int skip =0 ; +s64 skip =0 ;u64 head;ssize_t err;void *p;
@@ -1313,14 +1315,13 @@ int __perf_session__process_events(struct perf_session *session, u64 file_size, struct perf_tool *tool) { int fd = perf_data_file__fd(session->file); -u64 head, page_offset, file_offset, file_pos; +u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;size_t mmap_size;char *buf, *mmaps[NUM_MMAPS ];union perf_event *event; -uint32_t size;struct ui_progress prog; -int skip; +s64 skip;perf_tool__fill_defaults (tool);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf session: Add ability to skip 4GiB or more
perf session: Add ability to skip 4GiB or more
Commit-ID: d5652d865ea734a13a16cf563937291a84d4364d Gitweb: http://git.kernel.org/tip/d5652d865ea734a13a16cf563937291a84d4364d Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 23 Jul 2014 22:19:58 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:07:14 -0300
perf session: Add ability to skip 4GiB or more
A session can be made to skip portions of the input file. Do not limit that size to 32-bits.
--- tools/perf/util/session.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
tools/perf/util/session.c +8 -7
@@ -994,8 +994,10 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event, -struct perf_tool *tool,u64 file_offset) +static s64 perf_session__process_user_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {int fd =perf_data_file__fd (session->file);int err;
@@ -1037,7 +1039,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, +static s64 perf_session__process_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset)
@@ -1148,7 +1150,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,union perf_event *event;uint32_t size, cur_size =0 ;void *buf =NULL ; -int skip =0 ; +s64 skip =0 ;u64 head;ssize_t err;void *p;
@@ -1277,14 +1279,13 @@ int __perf_session__process_events(struct perf_session *session, u64 file_size, struct perf_tool *tool) { int fd = perf_data_file__fd(session->file); -u64 head, page_offset, file_offset, file_pos; +u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;size_t mmap_size;char *buf, *mmaps[NUM_MMAPS ];union perf_event *event; -uint32_t size;struct ui_progress prog; -int skip; +s64 skip;perf_tool__fill_defaults (tool);
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf session: Add ability to 'skip' a non-piped event stream
In reply to Adrian Hunterperf session: Add ability to 'skip' a non-piped event stream
Commit-ID: 6f917c70998d22bda6d06cb168665068c6066cd4 Gitweb: http://git.kernel.org/tip/6f917c70998d22bda6d06cb168665068c6066cd4 Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 23 Jul 2014 22:19:57 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:00:46 -0300
perf session: Add ability to 'skip' a non-piped event stream
A piped event stream may contain arbitary sized tracepoint information following a PERF_RECORD_HEADER_TRACING_DATA event. The position in the stream has to be 'skipped' to match the start of the next event.
Provide the same ability to a non-piped event stream to allow for Instruction Trace data that may also be in a non-piped event stream.
--- tools/perf/util/session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/session.c +6 -1
@@ -1284,6 +1284,7 @@ int __perf_session__process_events(struct perf_session *session,union perf_event *event;uint32_t size;struct ui_progress prog; +int skip;perf_tool__fill_defaults (tool);
@@ -1344,7 +1345,8 @@ more: size = event->header.size;if (size <sizeof (struct perf_event_header ) || -perf_session__process_event (session, event, tool, file_pos) <0 ) { + (skip =perf_session__process_event (session, event, tool, file_pos)) + <0 ) {pr_err ("%#" PRIx64" [%#x]: failed to process type: %d\n" , file_offset + head, event->header.size, event->header.type);
@@ -1352,6 +1354,9 @@ more: goto out_err; } +if (skip) + size += skip; + head += size; file_pos += size;
Adrian Hunter
reviewerPATCH 22/52 perf session: Add perf_session__deliver_synth_event()
In reply to Adrian HunterAdd a function to deliver synthesized events from
within a session.
--- tools/perf/util/session.c | 14 ++++++++++++++ tools/perf/util/session.h | 5 +++++ 2 files changed, 19 insertions(+)
tools/perf/util/session.c +14 -0
@@ -1066,6 +1066,20 @@ static s64 perf_session__process_user_event(struct perf_session *session, } } +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool) +{ +events_stats__inc (&session->stats, event->header.type); + +if (event->header.type >=PERF_RECORD_USER_TYPE_START ) +return perf_session__process_user_event (session, event, tool, +0 ); + +return perf_session_deliver_event (session, event, sample, tool,0 ); +} +static void event_swap (union perf_event *event,bool sample_id_all) {perf_event__swap_op swap;
tools/perf/util/session.h +5 -0
@@ -130,6 +130,11 @@ extern volatile int session_done;#define session_done () (*(volatile int *)(&session_done)) +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool); +int perf_event__process_id_index (struct perf_tool *tool,union perf_event *event,struct perf_session *session);
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 23/52 perf tools: Move rdtsc() function
In reply to Adrian HunterMove the rdtsc() function so it can
be reusued.
--- tools/perf/arch/x86/util/tsc.c | 9 +++++++++ tools/perf/tests/perf-time-to-tsc.c | 9 --------- tools/perf/util/tsc.c | 5 +++++ tools/perf/util/tsc.h | 1 + 4 files changed, 15 insertions(+), 9 deletions(-)
tools/perf/arch/x86/util/tsc.c +9 -0
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,return 0 ; } + +u64 rdtsc (void ) +{ +unsigned int low, high; + + asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); + +return low | ((u64 )high) <<32 ; +}
tools/perf/tests/perf-time-to-tsc.c +0 -9
@@ -25,15 +25,6 @@ } \ } -static u64 rdtsc (void ) -{ -unsigned int low, high; - - asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); - -return low | ((u64 )high) <<32 ; -} -/** * test__perf_time_to_tsc - test converting perf time to TSC. *
tools/perf/util/tsc.c +5 -0
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)return tc->time_zero + quot * tc->time_mult + ((rem * tc->time_mult) >> tc->time_shift); } + +u64 __weak rdtsc (void ) +{ +return 0 ; +}
tools/perf/util/tsc.h +1 -0
@@ -7,5 +7,6 @@u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc);u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); +u64 rdtsc (void );#endif
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Move rdtsc() function
perf tools: Move rdtsc() function
Commit-ID: a6a69db4b686e51045771945669bba6578af67c1 Gitweb: http://git.kernel.org/tip/a6a69db4b686e51045771945669bba6578af67c1 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:32 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:48:11 -0300
perf tools: Move rdtsc() function
Move the rdtsc() function so it can be reusued.
--- tools/perf/arch/x86/util/tsc.c | 9 +++++++++ tools/perf/tests/perf-time-to-tsc.c | 9 --------- tools/perf/util/tsc.c | 5 +++++ tools/perf/util/tsc.h | 1 + 4 files changed, 15 insertions(+), 9 deletions(-)
tools/perf/arch/x86/util/tsc.c +9 -0
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,return 0 ; } + +u64 rdtsc (void ) +{ +unsigned int low, high; + + asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); + +return low | ((u64 )high) <<32 ; +}
tools/perf/tests/perf-time-to-tsc.c +0 -9
@@ -25,15 +25,6 @@ } \ } -static u64 rdtsc (void ) -{ -unsigned int low, high; - - asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); - -return low | ((u64 )high) <<32 ; -} -/** * test__perf_time_to_tsc - test converting perf time to TSC. *
tools/perf/util/tsc.c +5 -0
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)return tc->time_zero + quot * tc->time_mult + ((rem * tc->time_mult) >> tc->time_shift); } + +u64 __weak rdtsc (void ) +{ +return 0 ; +}
tools/perf/util/tsc.h +1 -0
@@ -7,5 +7,6 @@u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc);u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); +u64 rdtsc (void );#endif
Adrian Hunter
reviewerPATCH 24/52 perf evlist: Add perf_evlist__enable_event_idx()
In reply to Adrian HunterAdd a function to enable a specific event
within a specific perf event buffer.
--- tools/perf/util/evlist.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 49 insertions(+)
tools/perf/util/evlist.c +47 -0
@@ -354,6 +354,53 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,return 0 ; } +static int perf_evlist__enable_event_cpu (struct perf_evlist *evlist, +struct perf_evsel *evsel,int cpu) +{ +int thread, err; +int nr_threads =perf_evlist__nr_threads (evlist, evsel); + +if (!evsel->fd) +return -EINVAL ; + +for (thread =0 ; thread < nr_threads; thread++) { + err =ioctl (FD (evsel, cpu, thread), +PERF_EVENT_IOC_ENABLE ,0 ); +if (err) +return err; + } +return 0 ; +} + +static int perf_evlist__enable_event_thread (struct perf_evlist *evlist, +struct perf_evsel *evsel, +int thread) +{ +int cpu, err; +int nr_cpus =cpu_map__nr (evlist->cpus); + +if (!evsel->fd) +return -EINVAL ; + +for (cpu =0 ; cpu < nr_cpus; cpu++) { + err =ioctl (FD (evsel, cpu, thread),PERF_EVENT_IOC_ENABLE ,0 ); +if (err) +return err; + } +return 0 ; +} + +int perf_evlist__enable_event_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx) +{ +bool per_cpu_mmaps = !cpu_map__empty (evlist->cpus); + +if (per_cpu_mmaps) +return perf_evlist__enable_event_cpu (evlist, evsel, idx); +else +return perf_evlist__enable_event_thread (evlist, evsel, idx); +} +static int perf_evlist__alloc_pollfd (struct perf_evlist *evlist) {int nr_cpus =cpu_map__nr (evlist->cpus);
tools/perf/util/evlist.h +2 -0
@@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel);int perf_evlist__enable_event (struct perf_evlist *evlist,struct perf_evsel *evsel); +int perf_evlist__enable_event_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx);void perf_evlist__set_selected (struct perf_evlist *evlist,struct perf_evsel *evsel);
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 25/52 perf session: Add perf_session__peek_event()
In reply to Adrian HunterAdd a function to peek at other events in the
event stream.
--- tools/perf/util/session.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.h | 5 +++++ 2 files changed, 60 insertions(+)
tools/perf/util/session.c +55 -0
@@ -1089,6 +1089,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } +int perf_session__peek_event (struct perf_session *session,off_t file_offset, +void *buf,size_t buf_sz, +union perf_event **event_ptr, +struct perf_sample *sample) +{ +union perf_event *event; +size_t hdr_sz, rest; +int fd; + +if (session->one_mmap && !session->header.needs_swap) { + event = file_offset - session->one_mmap_offset + + session->one_mmap_addr; + goto out_parse_sample; + } + +if (perf_data_file__is_pipe (session->file)) +return -1 ; + + fd =perf_data_file__fd (session->file); + hdr_sz =sizeof (struct perf_event_header ); + +if (buf_sz < hdr_sz) +return -1 ; + +if (lseek (fd, file_offset,SEEK_SET ) == (off_t)-1 || +readn (fd, &buf, hdr_sz) != (ssize_t )hdr_sz) +return -1 ; + + event = (union perf_event *)buf; + +if (session->header.needs_swap) +perf_event_header__bswap (&event->header); + +if (event->header.size < hdr_sz) +return -1 ; + + rest = event->header.size - hdr_sz; + +if (readn (fd, &buf, rest) != (ssize_t )rest) +return -1 ; + +if (session->header.needs_swap) +event_swap (event,perf_evlist__sample_id_all (session->evlist)); + +out_parse_sample: + +if (sample && event->header.type <PERF_RECORD_USER_TYPE_START && +perf_evlist__parse_sample (session->evlist, event, sample)) +return -1 ; + + *event_ptr = event; + +return 0 ; +} + static s64 perf_session__process_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool,
tools/perf/util/session.h +5 -0
@@ -58,6 +58,11 @@ void perf_session__delete(struct perf_session *session);void perf_event_header__bswap (struct perf_event_header *hdr); +int perf_session__peek_event (struct perf_session *session,off_t file_offset, +void *buf,size_t buf_sz, +union perf_event **event_ptr, +struct perf_sample *sample); +int __perf_session__process_events (struct perf_session *session,u64 data_offset,u64 data_size,u64 size,struct perf_tool *tool);
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 26/52 perf tools: Add dso__data_size()
In reply to Adrian HunterAdd a function to return the dso data size, for use in estimating the size an instruction cache.
--- tools/perf/util/dso.c | 22 ++++++++++++++++++++++ tools/perf/util/dso.h | 2 ++ 2 files changed, 24 insertions(+)
tools/perf/util/dso.c +22 -0
@@ -544,6 +544,28 @@ static int data_file_size(struct dso *dso)return 0 ; } +/** +* dso__data_size - Return dso data size +* @dso: dso object +* @machine: machine object +* +* Return: dso data size +*/ +off_t dso__data_size (struct dso *dso,struct machine *machine) +{ +int fd; + + fd =dso__data_fd (dso, machine); +if (fd <0 ) +return fd; + +if (data_file_size (dso)) +return -1 ; + +/* For now just estimate dso data size is close to file size */ +return dso->data.file_size; +} +static ssize_t data_read_offset (struct dso *dso,u64 offset,u8 *data,ssize_t size) {
tools/perf/util/dso.h +2 -0
@@ -166,6 +166,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t* The dso__data_* external interface provides following functions: * dso__data_fd * dso__data_close +* dso__data_size * dso__data_read_offset * dso__data_read_addr *
@@ -203,6 +204,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type tint dso__data_fd (struct dso *dso,struct machine *machine);void dso__data_close (struct dso *dso); +off_t dso__data_size (struct dso *dso,struct machine *machine);ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size); ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add dso__data_size()
perf tools: Add dso__data_size()
Commit-ID: 6d363459d7e6e05f0afeb8e36e6de262a4964694 Gitweb: http://git.kernel.org/tip/6d363459d7e6e05f0afeb8e36e6de262a4964694 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:35 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 11:57:27 -0300
perf tools: Add dso__data_size()
Add a function to return the dso data size, for use in estimating the size an instruction cache.
--- tools/perf/util/dso.c | 22 ++++++++++++++++++++++ tools/perf/util/dso.h | 2 ++ 2 files changed, 24 insertions(+)
tools/perf/util/dso.c +22 -0
@@ -544,6 +544,28 @@ static int data_file_size(struct dso *dso)return 0 ; } +/** +* dso__data_size - Return dso data size +* @dso: dso object +* @machine: machine object +* +* Return: dso data size +*/ +off_t dso__data_size (struct dso *dso,struct machine *machine) +{ +int fd; + + fd =dso__data_fd (dso, machine); +if (fd <0 ) +return fd; + +if (data_file_size (dso)) +return -1 ; + +/* For now just estimate dso data size is close to file size */ +return dso->data.file_size; +} +static ssize_t data_read_offset (struct dso *dso,u64 offset,u8 *data,ssize_t size) {
tools/perf/util/dso.h +2 -0
@@ -166,6 +166,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t* The dso__data_* external interface provides following functions: * dso__data_fd * dso__data_close +* dso__data_size * dso__data_read_offset * dso__data_read_addr *
@@ -203,6 +204,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type tint dso__data_fd (struct dso *dso,struct machine *machine);void dso__data_close (struct dso *dso); +off_t dso__data_size (struct dso *dso,struct machine *machine);ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size); ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
Adrian Hunter
reviewerPATCH 27/52 perf tools: Add a thread stack for synthesizing call chains
In reply to Adrian HunterAdd a thread stack for synthesizing call chains from call and return events.
--- tools/perf/Makefile.perf | 2 + tools/perf/util/event.h | 26 +++++++ tools/perf/util/thread-stack.c | 151 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/thread-stack.h | 32 +++++++++ tools/perf/util/thread.c | 3 + tools/perf/util/thread.h | 3 + 6 files changed, 217 insertions(+) create mode 100644 tools/perf/util/thread-stack.c create mode 100644 tools/perf/util/thread-stack.h
tools/perf/Makefile.perf +2 -0
@@ -302,6 +302,7 @@ LIB_H += ui/util.h LIB_H += ui/ui.h LIB_H += util/data.h LIB_H += util/kvm-stat.h +LIB_H += util/thread-stack.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o
@@ -377,6 +378,7 @@ LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)util/cloexec.o +LIB_OBJS += $(OUTPUT)util/thread-stack.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/event.h +26 -0
@@ -143,6 +143,32 @@ struct branch_stack {struct branch_entry entries[0 ]; }; +enum { +PERF_FLAG_BRANCH =1ULL <<0 , +PERF_FLAG_CALL =1ULL <<1 , +PERF_FLAG_RETURN =1ULL <<2 , +PERF_FLAG_CONDITIONAL =1ULL <<3 , +PERF_FLAG_SYSCALLRET =1ULL <<4 , +PERF_FLAG_ASYNC =1ULL <<5 , +PERF_FLAG_INTERRUPT =1ULL <<6 , +PERF_FLAG_TX_ABORT =1ULL <<7 , +PERF_FLAG_TRACE_BEGIN =1ULL <<8 , +PERF_FLAG_TRACE_END =1ULL <<9 , +PERF_FLAG_IN_TX =1ULL <<10 , +}; + +#define PERF_BRANCH_MASK (\ + PERF_FLAG_BRANCH |\ + PERF_FLAG_CALL |\ + PERF_FLAG_RETURN |\ + PERF_FLAG_CONDITIONAL |\ + PERF_FLAG_SYSCALLRET |\ + PERF_FLAG_ASYNC |\ + PERF_FLAG_INTERRUPT |\ + PERF_FLAG_TX_ABORT |\ + PERF_FLAG_TRACE_BEGIN |\ + PERF_FLAG_TRACE_END) +struct perf_sample {u64 ip;u32 pid, tid;
tools/perf/util/thread-stack.c new file +151 -0
151 lines not on this page · raw message
tools/perf/util/thread-stack.h new file +32 -0
@@ -0,0 +1,32 @@ +/* +* thread-stack.h: Synthesize a thread's stack using call / return events +* Copyright (c) 2014, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +*/ + +#ifndef __PERF_THREAD_STACK_H +#define __PERF_THREAD_STACK_H + +#include <sys/types.h> + +#include <linux/types.h> + +struct thread ; +struct ip_callchain ; + +void thread_stack__event (struct thread *thread,u32 flags,u64 from_ip, +u64 to_ip,u16 insn_len,u64 trace_nr); +void thread_stack__sample (struct thread *thread,struct ip_callchain *chain, +size_t sz,u64 ip); +void thread_stack__free (struct thread *thread); + +#endif
tools/perf/util/thread.c +3 -0
@@ -4,6 +4,7 @@#include <string.h> #include "session.h" #include "thread.h" +#include "thread-stack.h" #include "util.h" #include "debug.h" #include "comm.h"
@@ -61,6 +62,8 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; +thread_stack__free (thread); +if (thread->mg) {map_groups__put (thread->mg); thread->mg =NULL ;
tools/perf/util/thread.h +3 -0
@@ -8,6 +8,8 @@#include "symbol.h" #include <strlist.h> +struct thread_stack ; + struct thread { union { struct rb_node rb_node;
@@ -25,6 +27,7 @@ struct thread {int comm_len;void *priv; +struct thread_stack *ts; };struct machine ;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 28/52 perf script: Allow callchains if any event samples them
In reply to Adrian Hunterperf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.
--- tools/perf/builtin-script.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
tools/perf/builtin-script.c +13 -4
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,if (perf_evsel__check_stype (evsel,PERF_SAMPLE_IP ,"IP" ,PERF_OUTPUT_IP ))return -EINVAL ; - -if (!no_callchain && - !(attr->sample_type &PERF_SAMPLE_CALLCHAIN )) - symbol_conf.use_callchain = false; } if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)set_print_ip_opts (&evsel->attr); } +if (!no_callchain) { +bool use_callchain = false; + +evlist__for_each (session->evlist, evsel) { +if (evsel->attr.sample_type &PERF_SAMPLE_CALLCHAIN ) { + use_callchain = true; +break ; + } + } +if (!use_callchain) + symbol_conf.use_callchain = false; + } +/* * set default for tracepoints to print symbols only * if callchains are present
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 28/52] perf script: Allow callchains if any event samples them
Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
perf script was not displaying callchains if any selected event did not have
PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not havePERF_SAMPLE_CALLCHAIN.
I wonder if some other tool gets this wrong as well, report maybe?
Perhaps we need to have this check in some perf_evlist method?
Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?
Adrian, can you, in a case like that, provide a command line that creates such combo? I.e. how to create a perf.data file with multiple events with some having callchains while some don't.
As a rule, it is better to ease reproducing behaviour you mention when fixing stuff, so that quickly others can try and go on trying to fix it.
Thanks,
- Arnaldo
Quoted 42 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/builtin-script.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)tools/perf/builtin-script.c +13
-4@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,if (perf_evsel__check_stype (evsel,PERF_SAMPLE_IP ,"IP" ,PERF_OUTPUT_IP ))return -EINVAL ; - -if (!no_callchain && - !(attr->sample_type &PERF_SAMPLE_CALLCHAIN )) - symbol_conf.use_callchain = false; } if (PRINT_FIELD(ADDR) &&@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)set_print_ip_opts (&evsel->attr); } +if (!no_callchain) { +bool use_callchain = false; + +evlist__for_each (session->evlist, evsel) { +if (evsel->attr.sample_type &PERF_SAMPLE_CALLCHAIN ) { + use_callchain = true; +break ; + } + } +if (!use_callchain) + symbol_conf.use_callchain = false; + } +/* * set default for tracepoints to print symbols only * if callchains are present Signature · 1 line
1.8.3.2
Re: [PATCH 28/52] perf script: Allow callchains if any event samples them
Quoted 8 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
perf script was not displaying callchains if any selected event did not have
PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not havePERF_SAMPLE_CALLCHAIN.I wonder if some other tool gets this wrong as well, report maybe?
perf only handles 1 sample_type so if callchains are enabled for 1 event they are enabled for all.
Perhaps Adrian's patch set changes that -- prior patch sets attempted to. I have not had time to go through the list.
David
Adrian Hunter
reviewerRe: [PATCH 28/52] perf script: Allow callchains if any event samples them
In reply to Arnaldo Carvalho de MeloQuoted 7 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
perf script was not displaying callchains if any selected event did not have
PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not havePERF_SAMPLE_CALLCHAIN.I wonder if some other tool gets this wrong as well, report maybe?
perf report was ok
Quoted 2 lines
Perhaps we need to have this check in some
perf_evlistmethod?
Possibly
Quoted 8 lines
Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?
Adrian, can you, in a case like that, provide a command line that creates such combo? I.e. how to create a perf.data file with multiple events with some having callchains while some don't.
For now, it looks like this is something that only Intel PT will do. Intel PT decoding can create "instructions" samples that look like they came from the "instructions" hardware event, and then Intel PT will optionally synthesize call chains on them as well.
Quoted 50 lines
As a rule, it is better to ease reproducing behaviour you mention when fixing stuff, so that quickly others can try and go on trying to fix it.
Thanks,
- Arnaldo
Quoted 42 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/builtin-script.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)tools/perf/builtin-script.c +13
-5@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,if (perf_evsel__check_stype (evsel,PERF_SAMPLE_IP ,"IP" ,PERF_OUTPUT_IP ))return -EINVAL ; - -if (!no_callchain && - !(attr->sample_type &PERF_SAMPLE_CALLCHAIN )) - symbol_conf.use_callchain = false; } if (PRINT_FIELD(ADDR) &&@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)set_print_ip_opts (&evsel->attr); } +if (!no_callchain) { +bool use_callchain = false; + +evlist__for_each (session->evlist, evsel) { +if (evsel->attr.sample_type &PERF_SAMPLE_CALLCHAIN ) { + use_callchain = true; +break ; + } + } +if (!use_callchain) + symbol_conf.use_callchain = false; + } +/* * set default for tracepoints to print symbols only * if callchains are present -- 1.8.3.2
Namhyung Kim
maintainerRe: [PATCH 28/52] perf script: Allow callchains if any event samples them
In reply to Arnaldo Carvalho de MeloHi Arnaldo,
Quoted 6 lines · Arnaldo Carvalho de Melo
Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
perf script was not displaying callchains if any selected event did not have
PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not havePERF_SAMPLE_CALLCHAIN.
Quoted 7 lines
I wonder if some other tool gets this wrong as well, report maybe?
Perhaps we need to have this check in some
perf_evlistmethod?Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?
The children/cumulate stuff is enabled if a combined sample type contains PERF_SAMPLE_CALLCHAIN and works only a sample actually contains callchain.
So I guess if some have it and some don't, events don't have callchain just prints real entries/samples with same children overhead value.
Thanks,
Namhyung
Adrian Hunter
reviewerPATCH 29/52 perf inject: Add --kallsyms parameter
In reply to Adrian HunterLet perf inject take --kallsyms parameter the same as perf script and perf report do. That is needed for decoding Instruction Trace data using a copy of /proc/kcore for the kernel object because the kallsyms path is used to locate that copy.
--- tools/perf/Documentation/perf-inject.txt | 3 +++ tools/perf/builtin-inject.c | 2 ++ 2 files changed, 5 insertions(+)
tools/perf/Documentation/perf-inject.txt +3 -0
@@ -41,6 +41,9 @@ OPTIONS tasks slept. sched_switch contains a callchain where a task slept and sched_stat contains a timeslice how long a task slept. +--kallsyms=<file>:: + kallsyms pathname + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
tools/perf/builtin-inject.c +2 -0
@@ -440,6 +440,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) "where and how long tasks slept"),OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show build ids, etc)" ), +OPT_STRING (0 ,"kallsyms" , &symbol_conf.kallsyms_name,"file" , +"kallsyms pathname" ),OPT_END () }; const char * const inject_usage[] = {
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf inject: Add --kallsyms parameter
perf inject: Add --kallsyms parameter
Commit-ID: a7a2b8b4ce9e0bfd085c5797d535487594a71882 Gitweb: http://git.kernel.org/tip/a7a2b8b4ce9e0bfd085c5797d535487594a71882 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:38 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Fri, 25 Jul 2014 12:08:34 -0300
perf inject: Add --kallsyms parameter
Let perf inject take --kallsyms parameter the same as perf script and perf report do.
That is needed for decoding Instruction Trace data using a copy of /proc/kcore for the kernel object because the kallsyms path is used to locate that copy.
--- tools/perf/Documentation/perf-inject.txt | 3 +++ tools/perf/builtin-inject.c | 2 ++ 2 files changed, 5 insertions(+)
tools/perf/Documentation/perf-inject.txt +3 -0
@@ -41,6 +41,9 @@ OPTIONS tasks slept. sched_switch contains a callchain where a task slept and sched_stat contains a timeslice how long a task slept. +--kallsyms=<file>:: + kallsyms pathname + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
tools/perf/builtin-inject.c +2 -0
@@ -439,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) "where and how long tasks slept"),OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show build ids, etc)" ), +OPT_STRING (0 ,"kallsyms" , &symbol_conf.kallsyms_name,"file" , +"kallsyms pathname" ),OPT_END () }; const char * const inject_usage[] = {
Adrian Hunter
reviewerPATCH 30/52 perf tools: Expose 'addr' functions so they can be reused
In reply to Adrian HunterMove some functions and functionality related to the use of 'addr' out of builtin-script so they can be reused. The moved functions are: is_bts_event() and sample_addr_correlates_sym() and a new function perf_event__preprocess_sample_addr() is created from bits of print_sample_addr(). perf_event__preprocess_sample_addr() is the equivalent of perf_event__preprocess_sample() but for 'addr' instead of 'ip'.
--- tools/perf/builtin-script.c | 34 +--------------------------------- tools/perf/util/event.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 10 ++++++++++ 3 files changed, 53 insertions(+), 33 deletions(-)
tools/perf/builtin-script.c +1 -33
@@ -367,27 +367,6 @@ static void print_sample_start(struct perf_sample *sample, } } -static bool is_bts_event (struct perf_event_attr *attr) -{ -return ((attr->type ==PERF_TYPE_HARDWARE ) && - (attr->config &PERF_COUNT_HW_BRANCH_INSTRUCTIONS ) && - (attr->sample_period ==1 )); -} - -static bool sample_addr_correlates_sym (struct perf_event_attr *attr) -{ -if ((attr->type ==PERF_TYPE_SOFTWARE ) && - ((attr->config ==PERF_COUNT_SW_PAGE_FAULTS ) || - (attr->config ==PERF_COUNT_SW_PAGE_FAULTS_MIN ) || - (attr->config ==PERF_COUNT_SW_PAGE_FAULTS_MAJ ))) -return true; - -if (is_bts_event (attr)) -return true; - -return false; -} - static void print_sample_addr(union perf_event *event, struct perf_sample *sample, struct machine *machine,
@@ -395,24 +374,13 @@ static void print_sample_addr(union perf_event *event, struct perf_event_attr *attr) {struct addr_location al; -u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ;printf ("%16" PRIx64, sample->addr);if (!sample_addr_correlates_sym (attr))return ; -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->addr, &al); -if (!al.map) -thread__find_addr_map (thread, machine, cpumode,MAP__VARIABLE , - sample->addr, &al); - - al.cpu = sample->cpu; - al.sym =NULL ; - -if (al.map) - al.sym =map__find_symbol (al.map, al.addr,NULL ); +perf_event__preprocess_sample_addr (event, sample, machine, thread, &al);if (PRINT_FIELD (SYM )) {printf (" " );
tools/perf/util/event.c +42 -0
45 lines not on this page · raw message
tools/perf/util/event.h +10 -0
@@ -329,6 +329,16 @@ int perf_event__preprocess_sample(const union perf_event *event,struct addr_location *al, struct perf_sample *sample); +struct thread ; + +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); +const char *perf_event__name (unsigned int id); size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Expose 'addr' functions so they can be reused
perf tools: Expose 'addr' functions so they can be reused
Commit-ID: 9b0d2d875d57d85fdfb35ac27f89951520a8b473 Gitweb: http://git.kernel.org/tip/9b0d2d875d57d85fdfb35ac27f89951520a8b473 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:39 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Fri, 25 Jul 2014 12:08:34 -0300
perf tools: Expose 'addr' functions so they can be reused
Move some functions and functionality related to the use of 'addr' out of builtin-script so they can be reused.
The moved functions are: is_bts_event() and sample_addr_correlates_sym() and a new function perf_event__preprocess_sample_addr() is created from bits of print_sample_addr().
perf_event__preprocess_sample_addr() is the equivalent of perf_event__preprocess_sample() but for 'addr' instead of 'ip'.
--- tools/perf/builtin-script.c | 34 +--------------------------------- tools/perf/util/event.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 10 ++++++++++ 3 files changed, 53 insertions(+), 33 deletions(-)
tools/perf/builtin-script.c +1 -33
@@ -358,27 +358,6 @@ static void print_sample_start(struct perf_sample *sample, } } -static bool is_bts_event (struct perf_event_attr *attr) -{ -return ((attr->type ==PERF_TYPE_HARDWARE ) && - (attr->config &PERF_COUNT_HW_BRANCH_INSTRUCTIONS ) && - (attr->sample_period ==1 )); -} - -static bool sample_addr_correlates_sym (struct perf_event_attr *attr) -{ -if ((attr->type ==PERF_TYPE_SOFTWARE ) && - ((attr->config ==PERF_COUNT_SW_PAGE_FAULTS ) || - (attr->config ==PERF_COUNT_SW_PAGE_FAULTS_MIN ) || - (attr->config ==PERF_COUNT_SW_PAGE_FAULTS_MAJ ))) -return true; - -if (is_bts_event (attr)) -return true; - -return false; -} - static void print_sample_addr(union perf_event *event, struct perf_sample *sample, struct machine *machine,
@@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event, struct perf_event_attr *attr) {struct addr_location al; -u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ;printf ("%16" PRIx64, sample->addr);if (!sample_addr_correlates_sym (attr))return ; -thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - sample->addr, &al); -if (!al.map) -thread__find_addr_map (thread, machine, cpumode,MAP__VARIABLE , - sample->addr, &al); - - al.cpu = sample->cpu; - al.sym =NULL ; - -if (al.map) - al.sym =map__find_symbol (al.map, al.addr,NULL ); +perf_event__preprocess_sample_addr (event, sample, machine, thread, &al);if (PRINT_FIELD (SYM )) {printf (" " );
tools/perf/util/event.c +42 -0
45 lines not on this page · raw message
tools/perf/util/event.h +10 -0
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,struct addr_location *al, struct perf_sample *sample); +struct thread ; + +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); +const char *perf_event__name (unsigned int id); size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
Adrian Hunter
reviewerPATCH 31/52 perf tools: Add facility to export data in database-friendly way
In reply to Adrian HunterThis 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 | 1 + tools/perf/util/db-export.c | 268 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/db-export.h | 86 ++++++++++++++ tools/perf/util/dso.h | 1 + tools/perf/util/evsel.h | 1 + tools/perf/util/machine.h | 1 + tools/perf/util/symbol.h | 1 + tools/perf/util/thread.h | 1 + 9 files changed, 362 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
@@ -303,6 +303,7 @@ LIB_H += ui/ui.h LIB_H += util/data.h LIB_H += util/kvm-stat.h LIB_H += util/thread-stack.h +LIB_H += util/db-export.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o
@@ -379,6 +380,7 @@ LIB_OBJS += $(OUTPUT)util/data.o LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)util/cloexec.o LIB_OBJS += $(OUTPUT)util/thread-stack.o +LIB_OBJS += $(OUTPUT)util/db-export.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/comm.h +1 -0
@@ -10,6 +10,7 @@ struct comm_str;struct comm {struct comm_str *comm_str;u64 start; +u64 db_id;struct list_head list;bool exec; };
tools/perf/util/db-export.c new file +268 -0
268 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 +1 -0
@@ -93,6 +93,7 @@ struct dso {enum dso_swap_type needs_swap;enum dso_binary_type symtab_type;enum dso_binary_type binary_type; +u64 db_id; u8 adjust_symbols:1; u8 has_build_id:1; u8 has_srcline:1;
tools/perf/util/evsel.h +1 -0
@@ -95,6 +95,7 @@ struct perf_evsel {int sample_read;struct perf_evsel *leader;char *group_name; +u64 db_id; };union u64_swap {
tools/perf/util/machine.h +1 -0
@@ -36,6 +36,7 @@ struct machine {u64 kernel_start;symbol_filter_t symbol_filter;pid_t *current_tid; +u64 db_id; }; static inline
tools/perf/util/symbol.h +1 -0
@@ -71,6 +71,7 @@ struct symbol {struct rb_node rb_node;u64 start;u64 end; +u64 db_id;u16 namelen;u8 binding;bool ignore;
tools/perf/util/thread.h +1 -0
@@ -25,6 +25,7 @@ struct thread {bool dead;/* if set thread has exited */ struct list_head comm_list;int comm_len; +u64 db_id;void *priv;struct thread_stack *ts;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 32/52 perf tools: Add helpers for calling Python objects
In reply to Adrian HunterThe Python script API repeatedly uses the same lines of code to get and call objects. Make that into helper functions instead. A side-effect is that some reference counting bugs disappear because the new call_object() function always decrements the reference count of 'retval'.
--- .../util/scripting-engines/trace-event-python.c | 114 +++++++++------------ 1 file changed, 47 insertions(+), 67 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +47 -67
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObjPy_DECREF (val); } +static PyObject *get_handler (const char *handler_name) +{ +PyObject *handler; + + handler =PyDict_GetItemString (main_dict, handler_name); +if (handler && !PyCallable_Check (handler)) +return NULL ; +return handler; +} + +static void call_object (PyObject *handler,PyObject *args,const char *die_msg) +{ +PyObject *retval; + + retval =PyObject_CallObject (handler, args); +if (retval ==NULL ) +handler_call_die (die_msg); +Py_DECREF (retval); +} + +static void try_call_object (const char *handler_name,PyObject *args) +{ +PyObject *handler; + + handler =get_handler (handler_name); +if (handler) +call_object (handler, args, handler_name); +} + static void define_value(enum print_arg_type field_type, const char *ev_name, const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type, const char *field_str) {const char *handler_name ="define_flag_value" ; -PyObject *handler, *t, *retval; +PyObject *t;unsigned long long value;unsigned n =0 ;
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,PyTuple_SetItem (t, n++,PyInt_FromLong (value));PyTuple_SetItem (t, n++,PyString_FromString (field_str)); - handler =PyDict_GetItemString (main_dict, handler_name); -if (handler &&PyCallable_Check (handler)) { - retval =PyObject_CallObject (handler, t); -if (retval ==NULL ) -handler_call_die (handler_name); -Py_DECREF (retval); - } +try_call_object (handler_name, t);Py_DECREF (t); }
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type, const char *delim) {const char *handler_name ="define_flag_field" ; -PyObject *handler, *t, *retval; +PyObject *t;unsigned n =0 ;if (field_type ==PRINT_SYMBOL )
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,if (field_type ==PRINT_FLAGS )PyTuple_SetItem (t, n++,PyString_FromString (delim)); - handler =PyDict_GetItemString (main_dict, handler_name); -if (handler &&PyCallable_Check (handler)) { - retval =PyObject_CallObject (handler, t); -if (retval ==NULL ) -handler_call_die (handler_name); -Py_DECREF (retval); - } +try_call_object (handler_name, t);Py_DECREF (t); }
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *context, *t, *obj, *callchain; + PyObject *handler, *context, *t, *obj, *callchain;PyObject *dict =NULL ;static char handler_name[256 ];struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,sprintf (handler_name,"%s__%s" , event->system, event->name); - handler =PyDict_GetItemString (main_dict, handler_name); -if (handler && !PyCallable_Check (handler)) - handler =NULL ; + handler =get_handler (handler_name);if (!handler) { dict =PyDict_New ();if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,Py_FatalError ("error resizing Python tuple" );if (handler) { - retval =PyObject_CallObject (handler, t); -if (retval ==NULL ) -handler_call_die (handler_name); -Py_DECREF (retval); +call_object (handler, t, handler_name); }else { - handler =PyDict_GetItemString (main_dict,"trace_unhandled" ); -if (handler &&PyCallable_Check (handler)) { - - retval =PyObject_CallObject (handler, t); -if (retval ==NULL ) -handler_call_die ("trace_unhandled" ); -Py_DECREF (retval); - } +try_call_object ("trace_unhandled" , t);Py_DECREF (dict); }
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; + PyObject *handler, *t, *dict, *callchain, *dict_sample;static char handler_name[64 ];unsigned n =0 ;
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,snprintf (handler_name,sizeof (handler_name),"%s" ,"process_event" ); - handler =PyDict_GetItemString (main_dict, handler_name); -if (!handler || !PyCallable_Check (handler)) + handler =get_handler (handler_name); +if (!handler) goto exit;pydict_set_item_string_decref (dict,"ev_name" ,PyString_FromString (perf_evsel__name (evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,if (_PyTuple_Resize (&t, n) ==-1 )Py_FatalError ("error resizing Python tuple" ); - retval =PyObject_CallObject (handler, t); -if (retval ==NULL ) -handler_call_die (handler_name); -Py_DECREF (retval); +call_object (handler, t, handler_name); exit:Py_DECREF (dict);Py_DECREF (t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,static int run_start_sub (void ) { -PyObject *handler, *retval; -int err =0 ; - main_module =PyImport_AddModule ("__main__" );if (main_module ==NULL )return -1 ;Py_INCREF (main_module); main_dict =PyModule_GetDict (main_module); -if (main_dict ==NULL ) { - err =-1 ; +if (main_dict ==NULL ) goto error; - }Py_INCREF (main_dict); - handler =PyDict_GetItemString (main_dict,"trace_begin" ); -if (handler ==NULL || !PyCallable_Check (handler)) - goto out; +try_call_object ("trace_begin" ,NULL ); - retval =PyObject_CallObject (handler,NULL ); -if (retval ==NULL ) -handler_call_die ("trace_begin" ); +return 0 ; -Py_DECREF (retval); -return err; error:Py_XDECREF (main_dict);Py_XDECREF (main_module); -out: -return err; +return -1 ; }/*
@@ -654,23 +644,13 @@ error:*/ static int python_stop_script (void ) { -PyObject *handler, *retval; -int err =0 ; +try_call_object ("trace_end" ,NULL ); - handler =PyDict_GetItemString (main_dict,"trace_end" ); -if (handler ==NULL || !PyCallable_Check (handler)) - goto out; - - retval =PyObject_CallObject (handler,NULL ); -if (retval ==NULL ) -handler_call_die ("trace_end" ); -Py_DECREF (retval); -out:Py_XDECREF (main_dict);Py_XDECREF (main_module);Py_Finalize (); -return err; +return 0 ; }static int python_generate_script (struct pevent *pevent,const char *outfile)
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 33/52 perf tools: Extend Python script interface to export data in a database-friendly way
In reply to Adrian HunterUse 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 | 281 ++++++++++++++++++++- 1 file changed, 279 insertions(+), 2 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +279 -2
@@ -24,6 +24,7 @@#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdbool.h> #include <errno.h> #include "../../perf.h"
@@ -32,6 +33,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"
@@ -52,6 +56,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) {
@@ -474,6 +493,210 @@ 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); +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,
@@ -550,19 +773,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); } }
@@ -588,11 +817,53 @@ 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; + +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 ;
@@ -631,6 +902,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 ();
@@ -644,8 +917,12 @@ error:*/ 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.8.3.2
Adrian Hunter
reviewerPATCH 34/52 perf tools: Add Python script to export to postgresql
In reply to Adrian HunterAdd a Python script to export to a postgresql database. The script requires the Python psycopg2 module. 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=# select * from samples_view;
id | time | cpu | pid | tid | command | event | ip_hex | symbol | sym_offset | dso_short_name | to_ip_hex | to_symbol | to_sym_offset | to_dso_short_name
----+-----------------+-----+-------+-------+---------+--------+------------------+------------------------------+------------+-------------------+-----------+-----------+---------------+-------------------
1 | 592112202825015 | -1 | 17339 | 17339 | :17339 | cycles | ffffffff8104d24a | native_write_msr_safe | 10 | [kernel.kallsyms] | 0 | unknown | 0 | unknown 2 | 592112203258804 | -1 | 17339 | 17339 | :17339 | cycles | ffffffff8104d24a | native_write_msr_safe | 10 | [kernel.kallsyms] | 0 | unknown | 0 | unknown 3 | 592112203988119 | -1 | 17339 | 17339 | :17339 | cycles | ffffffff8104d24a | native_write_msr_safe | 10 | [kernel.kallsyms] | 0 | unknown | 0 | unknown
--- .../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.8.3.2
Adrian Hunter
reviewerPATCH 35/52 perf tools: Add flags and insn_len to struct sample
In reply to Adrian HunterAdd flags and insn_len to struct sample. The flags will be used to export branch type and transaction status. insn_len is preparation for pairing calls and returns because the return address equals the call address plus the instruction length (insn_len).
--- tools/perf/util/event.h | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/event.h +2 -0
@@ -182,6 +182,8 @@ struct perf_sample {u32 cpu;u32 raw_size;u64 data_src; +u32 flags; +u16 insn_len;void *raw_data;struct ip_callchain *callchain;struct branch_stack *branch_stack;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 36/52 perf tools: Add branch type to db export
In reply to Adrian HunterAdd the ability to export branch types through the database export facility.
--- tools/perf/util/db-export.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/db-export.h | 6 ++++++ 2 files changed, 54 insertions(+)
tools/perf/util/db-export.c +48 -0
@@ -205,6 +205,15 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,return 0 ; } +int db_export__branch_type (struct db_export *dbe,u32 branch_type, +const char *name) +{ +if (dbe->export_branch_type) +return dbe->export_branch_type (dbe, branch_type, name); + +return 0 ; +} +int db_export__sample (struct db_export *dbe,union perf_event *event,struct perf_sample *sample,struct perf_evsel *evsel,struct thread *thread,struct addr_location *al)
@@ -266,3 +275,42 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,return 0 ; } + +static struct { +u32 branch_type; +const char *name; +} branch_types[] = { + {0 ,"no branch" }, + {PERF_FLAG_BRANCH |PERF_FLAG_CALL ,"call" }, + {PERF_FLAG_BRANCH |PERF_FLAG_RETURN ,"return" }, + {PERF_FLAG_BRANCH |PERF_FLAG_CONDITIONAL ,"conditional jump" }, + {PERF_FLAG_BRANCH ,"unconditional jump" }, + {PERF_FLAG_BRANCH |PERF_FLAG_CALL |PERF_FLAG_INTERRUPT , +"software interrupt" }, + {PERF_FLAG_BRANCH |PERF_FLAG_RETURN |PERF_FLAG_INTERRUPT , +"return from interrupt" }, + {PERF_FLAG_BRANCH |PERF_FLAG_CALL |PERF_FLAG_SYSCALLRET , +"system call" }, + {PERF_FLAG_BRANCH |PERF_FLAG_RETURN |PERF_FLAG_SYSCALLRET , +"return from system call" }, + {PERF_FLAG_BRANCH |PERF_FLAG_ASYNC ,"asynchronous branch" }, + {PERF_FLAG_BRANCH |PERF_FLAG_CALL |PERF_FLAG_ASYNC | +PERF_FLAG_INTERRUPT ,"hardware interrupt" }, + {PERF_FLAG_BRANCH |PERF_FLAG_TX_ABORT ,"transaction abort" }, + {PERF_FLAG_BRANCH |PERF_FLAG_TRACE_BEGIN ,"trace begin" }, + {PERF_FLAG_BRANCH |PERF_FLAG_TRACE_END ,"trace end" }, + {0 ,NULL } +}; + +int db_export__branch_types (struct db_export *dbe) +{ +int i, err =0 ; + +for (i =0 ; branch_types[i].name ; i++) { + err =db_export__branch_type (dbe, branch_types[i].branch_type, + branch_types[i].name); +if (err) +break ; + } +return err; +}
tools/perf/util/db-export.h +6 -0
@@ -54,6 +54,8 @@ struct db_export { struct machine *machine);int (*export_symbol)(struct db_export *dbe,struct symbol *sym,struct dso *dso); +int (*export_branch_type)(struct db_export *dbe,u32 branch_type, +const char *name);int (*export_sample)(struct db_export *dbe,struct export_sample *es);u64 evsel_last_db_id;u64 machine_last_db_id;
@@ -79,8 +81,12 @@ int db_export__dso(struct db_export *dbe, struct dso *dso, struct machine *machine);int db_export__symbol (struct db_export *dbe,struct symbol *sym,struct dso *dso); +int db_export__branch_type (struct db_export *dbe,u32 branch_type, +const char *name);int db_export__sample (struct db_export *dbe,union perf_event *event,struct perf_sample *sample,struct perf_evsel *evsel,struct thread *thread,struct addr_location *al); +int db_export__branch_types (struct db_export *dbe); +#endif
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 37/52 perf tools: Add branch_type and in_tx to Python export
In reply to Adrian HunterAdd branch_type and in_tx to Python db export and
the export-to-postgresql.py script.
--- tools/perf/scripts/python/export-to-postgresql.py | 32 ++++++++++++++++++---- .../util/scripting-engines/trace-event-python.c | 30 +++++++++++++++++++- 2 files changed, 55 insertions(+), 7 deletions(-)
tools/perf/scripts/python/export-to-postgresql.py +26 -6
@@ -123,6 +123,10 @@ do_query(query, 'CREATE TABLE symbols (' 'sym_end bigint,' 'binding integer,' 'name varchar(2048))') +do_query(query, 'CREATE TABLE branch_types (' + 'id integer NOT NULL,' + 'name varchar(80))') + if branches: do_query(query, 'CREATE TABLE samples (' 'id bigint NOT NULL,'
@@ -139,7 +143,9 @@ if branches: 'to_dso_id bigint,' 'to_symbol_id bigint,' 'to_sym_offset bigint,' - 'to_ip bigint)') + 'to_ip bigint,' + 'branch_type integer,' + 'in_tx boolean)') else: do_query(query, 'CREATE TABLE samples (' 'id bigint NOT NULL,'
@@ -160,7 +166,9 @@ else: 'period bigint,' 'weight bigint,' 'transaction bigint,' - 'data_src bigint)') + 'data_src bigint,' + 'branch_type integer,' + 'in_tx boolean)') do_query(query, 'CREATE VIEW samples_view AS ' 'SELECT '
@@ -178,7 +186,9 @@ do_query(query, 'CREATE VIEW samples_view AS ' 'to_hex(to_ip) AS to_ip_hex,' '(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,' 'to_sym_offset,' - '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name' + '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,' + '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,' + 'in_tx' ' FROM samples')
@@ -234,6 +244,7 @@ comm_file = open_output_file("comm_table.bin") comm_thread_file = open_output_file("comm_thread_table.bin") dso_file = open_output_file("dso_table.bin") symbol_file = open_output_file("symbol_table.bin") +branch_type_file = open_output_file("branch_type_table.bin") sample_file = open_output_file("sample_table.bin") def trace_begin():
@@ -257,6 +268,7 @@ def trace_end(): copy_output_file(comm_thread_file, "comm_threads") copy_output_file(dso_file, "dsos") copy_output_file(symbol_file, "symbols") + copy_output_file(branch_type_file, "branch_types") copy_output_file(sample_file, "samples") print datetime.datetime.today(), "Removing intermediate files..."
@@ -267,6 +279,7 @@ def trace_end(): remove_output_file(comm_thread_file) remove_output_file(dso_file) remove_output_file(symbol_file) + remove_output_file(branch_type_file) remove_output_file(sample_file) os.rmdir(output_dir_name) print datetime.datetime.today(), "Adding primary keys"
@@ -277,6 +290,7 @@ def trace_end(): do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') + do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') print datetime.datetime.today(), "Adding foreign keys"
@@ -352,9 +366,15 @@ def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name) symbol_file.write(value) -def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, *x): +def branch_type_table(branch_type, name, *x): + n = len(name) + fmt = "!hiii" + str(n) + "s" + value = struct.pack(fmt, 2, 4, branch_type, n, name) + branch_type_file.write(value) + +def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x): if branches: - value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiq", 15, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip) + value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx) else: - value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiq", 19, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src) + value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx) sample_file.write(value)
tools/perf/util/scripting-engines/trace-event-python.c +29 -1
@@ -65,6 +65,7 @@ struct tables {PyObject *comm_thread_handler;PyObject *dso_handler;PyObject *symbol_handler; +PyObject *branch_type_handler;PyObject *sample_handler;bool db_export_mode; };
@@ -662,13 +663,31 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,return 0 ; } +static int python_export_branch_type (struct db_export *dbe,u32 branch_type, +const char *name) +{ + struct tables *tables = container_of(dbe, struct tables, dbe); +PyObject *t; + + t =tuple_new (2 ); + +tuple_set_s32 (t,0 , branch_type); +tuple_set_string (t,1 , name); + +call_object (tables->branch_type_handler, t,"branch_type_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 ); + t =tuple_new (21 );tuple_set_u64 (t,0 , es->db_id);tuple_set_u64 (t,1 , es->evsel->db_id);
@@ -689,6 +708,8 @@ static int python_export_sample(struct db_export *dbe,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); +tuple_set_s32 (t,19 , es->sample->flags &PERF_BRANCH_MASK ); +tuple_set_s32 (t,20 , !!(es->sample->flags &PERF_FLAG_IN_TX ));call_object (tables->sample_handler, t,"sample_table" );
@@ -855,6 +876,7 @@ static void set_table_handlers(struct tables *tables)SET_TABLE_HANDLER (comm_thread);SET_TABLE_HANDLER (dso);SET_TABLE_HANDLER (symbol); +SET_TABLE_HANDLER (branch_type);SET_TABLE_HANDLER (sample); }
@@ -904,6 +926,12 @@ static int python_start_script(const char *script, int argc, const char **argv)set_table_handlers (tables); +if (tables->db_export_mode) { + err =db_export__branch_types (&tables->dbe); +if (err) + goto error; + } +return err; error:Py_Finalize ();
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 38/52 perf tools: Enhance the thread stack to output call/return data
In reply to Adrian HunterEnhance the thread stack to output detailed information about paired calls and returns.
--- tools/perf/util/thread-stack.c | 547 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/thread-stack.h | 47 ++++ 2 files changed, 590 insertions(+), 4 deletions(-)
tools/perf/util/thread-stack.c +543 -4
@@ -13,15 +13,48 @@* */ +#include <linux/rbtree.h> +#include <linux/list.h> #include "thread.h" #include "event.h" +#include "machine.h" #include "util.h" +#include "debug.h" +#include "symbol.h" +#include "comm.h" #include "thread-stack.h" -#define STACK_GROWTH 4096 +#define CALL_PATH_BLOCK_SHIFT 8 +#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT) +#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1) + +struct call_path_block { +struct call_path cp[CALL_PATH_BLOCK_SIZE ]; +struct list_head node; +}; + +struct call_path_root { +struct call_path call_path; +struct list_head blocks; +size_t next; +size_t sz; +}; + +struct call_return_processor { +struct call_path_root *cpr; +int (*process)(struct call_return *cr,void *data); +void *data; +}; + +#define STACK_GROWTH 2048struct thread_stack_entry {u64 ret_addr; +u64 timestamp; +u64 ref; +u64 branch_count; +struct call_path *cp; +bool no_call; };struct thread_stack {
@@ -29,6 +62,11 @@ struct thread_stack {size_t cnt;size_t sz;u64 trace_nr; +u64 branch_count; +u64 kernel_start; +u64 last_time; +struct call_return_processor *crp; +struct comm *comm; };static void thread_stack__grow (struct thread_stack *ts)
@@ -45,7 +83,8 @@ static void thread_stack__grow(struct thread_stack *ts) } } -static struct thread_stack *thread_stack__new (void ) +static struct thread_stack *thread_stack__new (struct thread *thread, +struct call_return_processor *crp) {struct thread_stack *ts;
@@ -59,6 +98,12 @@ static struct thread_stack *thread_stack__new(void)return NULL ; } +if (thread->mg && thread->mg->machine) + ts->kernel_start =machine__kernel_start (thread->mg->machine); +else + ts->kernel_start =1ULL <<63 ; + ts->crp = crp; +return ts; }
@@ -92,6 +137,64 @@ static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr) } } +static bool thread_stack__in_kernel (struct thread_stack *ts) +{ +if (!ts->cnt) +return false; + +return ts->stack[ts->cnt -1 ].cp->in_kernel; +} + +static int thread_stack__call_return (struct thread *thread, +struct thread_stack *ts,size_t idx, +u64 timestamp,u64 ref,bool no_return) +{ +struct call_return_processor *crp = ts->crp; +struct thread_stack_entry *tse; +struct call_return cr = { + .thread = thread, + .comm = ts->comm, + .db_id =0 , + }; + + tse = &ts->stack[idx]; + cr.cp = tse->cp; + cr.call_time = tse->timestamp; + cr.return_time = timestamp; + cr.branch_count = ts->branch_count - tse->branch_count; + cr.call_ref = tse->ref; + cr.return_ref = ref; +if (tse->no_call) + cr.flags |=CALL_RETURN_NO_CALL ; +if (no_return) + cr.flags |=CALL_RETURN_NO_RETURN ; + +return crp->process (&cr, crp->data); +} + +static int thread_stack__flush (struct thread *thread,struct thread_stack *ts) +{ +struct call_return_processor *crp = ts->crp; +int err; + +if (!crp) { + ts->cnt =0 ; +return 0 ; + } + +while (ts->cnt) { + err =thread_stack__call_return (thread, ts, --ts->cnt, + ts->last_time,0 , true); +if (err) { +pr_err ("Error flushing thread stack!\n" ); + ts->cnt =0 ; +return err; + } + } + +return 0 ; +} +void thread_stack__event (struct thread *thread,u32 flags,u64 from_ip,u64 to_ip,u16 insn_len,u64 trace_nr) {
@@ -99,17 +202,22 @@ void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,return ;if (!thread->ts) { - thread->ts =thread_stack__new (); + thread->ts =thread_stack__new (thread,NULL );if (!thread->ts)return ; thread->ts->trace_nr = trace_nr; }if (trace_nr != thread->ts->trace_nr) { +if (thread->ts->trace_nr) +thread_stack__flush (thread, thread->ts); thread->ts->trace_nr = trace_nr; - thread->ts->cnt =0 ; } +/* Stop here if thread_stack__process() is in use */ +if (thread->ts->crp) +return ; +if (flags &PERF_FLAG_CALL ) {u64 ret_addr;
@@ -126,9 +234,22 @@ void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, } } +void thread_stack__set_trace_nr (struct thread *thread,u64 trace_nr) +{ +if (!thread || !thread->ts) +return ; + +if (trace_nr != thread->ts->trace_nr) { +if (thread->ts->trace_nr) +thread_stack__flush (thread, thread->ts); + thread->ts->trace_nr = trace_nr; + } +} +void thread_stack__free (struct thread *thread) {if (thread->ts) { +thread_stack__flush (thread, thread->ts);zfree (&thread->ts->stack);zfree (&thread->ts); }
@@ -149,3 +270,421 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,for (i =1 ; i < chain->nr; i++) chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; } + +static void call_path__init (struct call_path *cp,struct call_path *parent, +struct symbol *sym,u64 ip,bool in_kernel) +{ + cp->parent = parent; + cp->sym = sym; + cp->ip = sym ?0 : ip; + cp->db_id =0 ; + cp->in_kernel = in_kernel; +RB_CLEAR_NODE (&cp->rb_node); + cp->children =RB_ROOT ; +} + +static struct call_path_root *call_path_root__new (void ) +{ +struct call_path_root *cpr; + + cpr =zalloc (sizeof (struct call_path_root )); +if (!cpr) +return NULL ; +call_path__init (&cpr->call_path,NULL ,NULL ,0 , false); +INIT_LIST_HEAD (&cpr->blocks); +return cpr; +} + +static void call_path_root__free (struct call_path_root *cpr) +{ +struct call_path_block *pos, *n; + +list_for_each_entry_safe (pos, n, &cpr->blocks, node) { +list_del (&pos->node); +free (pos); + } +free (cpr); +} + +static struct call_path *call_path__new (struct call_path_root *cpr, +struct call_path *parent, +struct symbol *sym,u64 ip, +bool in_kernel) +{ +struct call_path_block *cpb; +struct call_path *cp; +size_t n; + +if (cpr->next < cpr->sz) { + cpb = list_last_entry(&cpr->blocks, struct call_path_block, + node); + }else { + cpb =zalloc (sizeof (struct call_path_block )); +if (!cpb) +return NULL ; +list_add_tail (&cpb->node, &cpr->blocks); + cpr->sz +=CALL_PATH_BLOCK_SIZE ; + } + + n = cpr->next++ &CALL_PATH_BLOCK_MASK ; + cp = &cpb->cp[n]; + +call_path__init (cp, parent, sym, ip, in_kernel); + +return cp; +} + +static struct call_path *call_path__findnew (struct call_path_root *cpr, +struct call_path *parent, +struct symbol *sym,u64 ip,u64 ks) +{ +struct rb_node **p; +struct rb_node *node_parent =NULL ; +struct call_path *cp; +bool in_kernel = ip >= ks; + +if (sym) + ip =0 ; + +if (!parent) +return call_path__new (cpr, parent, sym, ip, in_kernel); + + p = &parent->children.rb_node; +while (*p !=NULL ) { + node_parent = *p; + cp = rb_entry(node_parent, struct call_path, rb_node); + +if (cp->sym == sym && cp->ip == ip) +return cp; + +if (sym < cp->sym || (sym == cp->sym && ip < cp->ip)) + p = &(*p)->rb_left; +else + p = &(*p)->rb_right; + } + + cp =call_path__new (cpr, parent, sym, ip, in_kernel); +if (!cp) +return NULL ; + +rb_link_node (&cp->rb_node, node_parent, p); +rb_insert_color (&cp->rb_node, &parent->children); + +return cp; +} + +struct call_return_processor * +call_return_processor__new (int (*process)(struct call_return *cr,void *data), +void *data) +{ +struct call_return_processor *crp; + + crp =zalloc (sizeof (struct call_return_processor )); +if (!crp) +return NULL ; + crp->cpr =call_path_root__new (); +if (!crp->cpr) + goto out_free; + crp->process = process; + crp->data = data; +return crp; + +out_free: +free (crp); +return NULL ; +} + +void call_return_processor__free (struct call_return_processor *crp) +{ +if (crp) { +call_path_root__free (crp->cpr); +free (crp); + } +} + +static int thread_stack__push_cp (struct thread_stack *ts,u64 ret_addr, +u64 timestamp,u64 ref,struct call_path *cp, +bool no_call) +{ +struct thread_stack_entry *tse; + +if (ts->cnt == ts->sz) { +thread_stack__grow (ts); +if (ts->cnt == ts->sz) +return -ENOMEM ; + } + + tse = &ts->stack[ts->cnt++]; + tse->ret_addr = ret_addr; + tse->timestamp = timestamp; + tse->ref = ref; + tse->branch_count = ts->branch_count; + tse->cp = cp; + tse->no_call = no_call; + +return 0 ; +} + +static int thread_stack__pop_cp (struct thread *thread,struct thread_stack *ts, +u64 ret_addr,u64 timestamp,u64 ref, +struct symbol *sym) +{ +int err; + +if (!ts->cnt) +return 1 ; + +if (ts->cnt ==1 ) { +struct thread_stack_entry *tse = &ts->stack[0 ]; + +if (tse->cp->sym == sym) +return thread_stack__call_return (thread, ts, --ts->cnt, + timestamp, ref, false); + } + +if (ts->stack[ts->cnt -1 ].ret_addr == ret_addr) { +return thread_stack__call_return (thread, ts, --ts->cnt, + timestamp, ref, false); + }else { +size_t i = ts->cnt -1 ; + +while (i--) { +if (ts->stack[i].ret_addr != ret_addr) +continue ; + i +=1 ; +while (ts->cnt > i) { + err =thread_stack__call_return (thread, ts, + --ts->cnt, + timestamp, ref, + true); +if (err) +return err; + } +return thread_stack__call_return (thread, ts, --ts->cnt, + timestamp, ref, false); + } + } + +return 1 ; +} + +static int thread_stack__bottom (struct thread *thread,struct thread_stack *ts, +struct perf_sample *sample, +struct addr_location *from_al, +struct addr_location *to_al,u64 ref) +{ +struct call_path_root *cpr = ts->crp->cpr; +struct call_path *cp; +struct symbol *sym; +u64 ip; + +if (sample->ip) { + ip = sample->ip; + sym = from_al->sym; + }else if (sample->addr) { + ip = sample->addr; + sym = to_al->sym; + }else { +return 0 ; + } + + cp =call_path__findnew (cpr, &cpr->call_path, sym, ip, + ts->kernel_start); +if (!cp) +return -ENOMEM ; + +return thread_stack__push_cp (thread->ts, ip, sample->time, ref, cp, + true); +} + +static int thread_stack__no_call_return (struct thread *thread, +struct thread_stack *ts, +struct perf_sample *sample, +struct addr_location *from_al, +struct addr_location *to_al,u64 ref) +{ +struct call_path_root *cpr = ts->crp->cpr; +struct call_path *cp, *parent; +u64 ks = ts->kernel_start; +int err; + +if (sample->ip >= ks && sample->addr < ks) { +/* Return to userspace, so pop all kernel addresses */ +while (thread_stack__in_kernel (ts)) { + err =thread_stack__call_return (thread, ts, --ts->cnt, + sample->time, ref, + true); +if (err) +return err; + } + +/* If the stack is empty, push the userspace address */ +if (!ts->cnt) { + cp =call_path__findnew (cpr, &cpr->call_path, + to_al->sym, sample->addr, + ts->kernel_start); +if (!cp) +return -ENOMEM ; +return thread_stack__push_cp (ts,0 , sample->time, ref, + cp, true); + } + }else if (thread_stack__in_kernel (ts) && sample->ip < ks) { +/* Return to userspace, so pop all kernel addresses */ +while (thread_stack__in_kernel (ts)) { + err =thread_stack__call_return (thread, ts, --ts->cnt, + sample->time, ref, + true); +if (err) +return err; + } + } + +if (ts->cnt) + parent = ts->stack[ts->cnt -1 ].cp; +else + parent = &cpr->call_path; + +/* This 'return' had no 'call', so push and pop top of stack */ + cp =call_path__findnew (cpr, parent, from_al->sym, sample->ip, + ts->kernel_start); +if (!cp) +return -ENOMEM ; + + err =thread_stack__push_cp (ts, sample->addr, sample->time, ref, cp, + true); +if (err) +return err; + +return thread_stack__pop_cp (thread, ts, sample->addr, sample->time, ref, + to_al->sym); +} + +static int thread_stack__trace_begin (struct thread *thread, +struct thread_stack *ts,u64 timestamp, +u64 ref) +{ +struct thread_stack_entry *tse; +int err; + +if (!ts->cnt) +return 0 ; + +/* Pop trace end */ + tse = &ts->stack[ts->cnt -1 ]; +if (tse->cp->sym ==NULL && tse->cp->ip ==0 ) { + err =thread_stack__call_return (thread, ts, --ts->cnt, + timestamp, ref, false); +if (err) +return err; + } + +return 0 ; +} + +static int thread_stack__trace_end (struct thread_stack *ts, +struct perf_sample *sample,u64 ref) +{ +struct call_path_root *cpr = ts->crp->cpr; +struct call_path *cp; +u64 ret_addr; + +/* No point having 'trace end' on the bottom of the stack */ +if (!ts->cnt || (ts->cnt ==1 && ts->stack[0 ].ref == ref)) +return 0 ; + + cp =call_path__findnew (cpr, ts->stack[ts->cnt -1 ].cp,NULL ,0 , + ts->kernel_start); +if (!cp) +return -ENOMEM ; + + ret_addr = sample->ip + sample->insn_len; + +return thread_stack__push_cp (ts, ret_addr, sample->time, ref, cp, + false); +} + +int thread_stack__process (struct thread *thread,struct comm *comm, +struct perf_sample *sample, +struct addr_location *from_al, +struct addr_location *to_al,u64 ref, +struct call_return_processor *crp) +{ +struct thread_stack *ts = thread->ts; +int err =0 ; + +if (ts) { +if (!ts->crp) { +/* Supersede thread_stack__event() */ +thread_stack__free (thread); + thread->ts =thread_stack__new (thread, crp); +if (!thread->ts) +return -ENOMEM ; + ts = thread->ts; + ts->comm = comm; + } + }else { + thread->ts =thread_stack__new (thread, crp); +if (!thread->ts) +return -ENOMEM ; + ts = thread->ts; + ts->comm = comm; + } + +/* Flush stack on exec */ +if (ts->comm != comm && thread->pid_ == thread->tid) { + err =thread_stack__flush (thread, ts); +if (err) +return err; + ts->comm = comm; + } + +/* If the stack is empty, put the current symbol on the stack */ +if (!ts->cnt) { + err =thread_stack__bottom (thread, ts, sample, from_al, to_al, + ref); +if (err) +return err; + } + + ts->branch_count +=1 ; + ts->last_time = sample->time; + +if (sample->flags &PERF_FLAG_CALL ) { +struct call_path_root *cpr = ts->crp->cpr; +struct call_path *cp; +u64 ret_addr; + +if (!sample->ip || !sample->addr) +return 0 ; + + ret_addr = sample->ip + sample->insn_len; +if (ret_addr == sample->addr) +return 0 ;/* Zero-length calls are excluded */ + + cp =call_path__findnew (cpr, ts->stack[ts->cnt -1 ].cp, + to_al->sym, sample->addr, + ts->kernel_start); +if (!cp) +return -ENOMEM ; + err =thread_stack__push_cp (ts, ret_addr, sample->time, ref, + cp, false); + }else if (sample->flags &PERF_FLAG_RETURN ) { +if (!sample->ip || !sample->addr) +return 0 ; + + err =thread_stack__pop_cp (thread, ts, sample->addr, + sample->time, ref, from_al->sym); +if (err) { +if (err <0 ) +return err; + err =thread_stack__no_call_return (thread, ts, sample, + from_al, to_al, ref); + } + }else if (sample->flags &PERF_FLAG_TRACE_BEGIN ) { + err =thread_stack__trace_begin (thread, ts, sample->time, ref); + }else if (sample->flags &PERF_FLAG_TRACE_END ) { + err =thread_stack__trace_end (ts, sample, ref); + } + +return err; +}
tools/perf/util/thread-stack.h +47 -0
61 lines not on this page · raw message
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 39/52 perf tools: Add call information to the database export API
In reply to Adrian HunterMake it possible for the database export API to use the enhanced thread stack and export detailed information about paired calls and returns.
--- tools/perf/util/db-export.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/db-export.h | 12 +++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-)
tools/perf/util/db-export.c +51 -1
@@ -21,6 +21,7 @@#include "comm.h" #include "symbol.h" #include "event.h" +#include "thread-stack.h" #include "db-export.h" int db_export__init (struct db_export *dbe)
@@ -29,8 +30,10 @@ int db_export__init(struct db_export *dbe)return 0 ; } -void db_export__exit (struct db_export *dbe__maybe_unused ) +void db_export__exit (struct db_export *dbe) { +call_return_processor__free (dbe->crp); + dbe->crp =NULL ; }int db_export__evsel (struct db_export *dbe,struct perf_evsel *evsel)
@@ -268,6 +271,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, &es.addr_sym_db_id, &es.addr_offset);if (err)return err; +if (dbe->crp) { + err =thread_stack__process (thread, comm, sample, al, + &addr_al, es.db_id, + dbe->crp); +if (err) +return err; + } }if (dbe->export_sample)
@@ -314,3 +324,43 @@ int db_export__branch_types(struct db_export *dbe) }return err; } + +int db_export__call_path (struct db_export *dbe,struct call_path *cp) +{ +int err; + +if (cp->db_id) +return 0 ; + +if (cp->parent) { + err =db_export__call_path (dbe, cp->parent); +if (err) +return err; + } + + cp->db_id = ++dbe->call_path_last_db_id; + +if (dbe->export_call_path) +return dbe->export_call_path (dbe, cp); + +return 0 ; +} + +int db_export__call_return (struct db_export *dbe,struct call_return *cr) +{ +int err; + +if (cr->db_id) +return 0 ; + + err =db_export__call_path (dbe, cr->cp); +if (err) +return err; + + cr->db_id = ++dbe->call_return_last_db_id; + +if (dbe->export_call_return) +return dbe->export_call_return (dbe, cr); + +return 0 ; +}
tools/perf/util/db-export.h +12 -0
@@ -25,6 +25,9 @@ struct comm;struct dso ;struct perf_sample ;struct addr_location ; +struct call_return_processor ; +struct call_path ; +struct call_return ;struct export_sample {union perf_event *event;
@@ -57,6 +60,10 @@ struct db_export {int (*export_branch_type)(struct db_export *dbe,u32 branch_type,const char *name);int (*export_sample)(struct db_export *dbe,struct export_sample *es); +int (*export_call_path)(struct db_export *dbe,struct call_path *cp); +int (*export_call_return)(struct db_export *dbe, +struct call_return *cr); +struct call_return_processor *crp;u64 evsel_last_db_id;u64 machine_last_db_id;u64 thread_last_db_id;
@@ -65,6 +72,8 @@ struct db_export {u64 dso_last_db_id;u64 symbol_last_db_id;u64 sample_last_db_id; +u64 call_path_last_db_id; +u64 call_return_last_db_id; };int db_export__init (struct db_export *dbe);
@@ -89,4 +98,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,int db_export__branch_types (struct db_export *dbe); +int db_export__call_path (struct db_export *dbe,struct call_path *cp); +int db_export__call_return (struct db_export *dbe,struct call_return *cr); +#endif
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 40/52 perf tools: Add call information to Python export
In reply to Adrian HunterAdd the ability to export detailed information about paired calls and returns to Python db export and the export-to-postgresql.py script.
--- .../scripts/python/bin/export-to-postgresql-report | 15 ++-- tools/perf/scripts/python/export-to-postgresql.py | 66 ++++++++++++++++- .../util/scripting-engines/trace-event-python.c | 84 +++++++++++++++++++++- 3 files changed, 158 insertions(+), 7 deletions(-)
tools/perf/scripts/python/bin/export-to-postgresql-report +10 -5
@@ -1,6 +1,6 @@ #!/bin/bash # description: export perf data to a postgresql database -# args: [database name] [columns] +# args: [database name] [columns] [calls] n_args=0 for i in "$@" do
@@ -9,11 +9,16 @@ do fi n_args=$(( $n_args + 1 )) done -if [ "$n_args" -gt 2 ] ; then - echo "usage: export-to-postgresql-report [database name] [columns]" +if [ "$n_args" -gt 3 ] ; then + echo "usage: export-to-postgresql-report [database name] [columns] [calls]" exit fi -if [ "$n_args" -gt 1 ] ; then +if [ "$n_args" -gt 2 ] ; then + dbname=$1 + columns=$2 + calls=$3 + shift 3 +elif [ "$n_args" -gt 1 ] ; then dbname=$1 columns=$2 shift 2
@@ -21,4 +26,4 @@ elif [ "$n_args" -gt 0 ] ; then dbname=$1 shift fi -perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns $calls
tools/perf/scripts/python/export-to-postgresql.py +65 -1
126 lines not on this page · raw message
tools/perf/util/scripting-engines/trace-event-python.c +83 -1
120 lines not on this page · raw message
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 41/52 perf tools: Add 'flush' callback to scripting API
In reply to Adrian HunterIn order to defer some output via the scripting API, there needs to be a callback after session processing but before the session is deleted.
--- tools/perf/builtin-script.c | 12 ++++++++++++ tools/perf/util/scripting-engines/trace-event-perl.c | 6 ++++++ tools/perf/util/scripting-engines/trace-event-python.c | 6 ++++++ tools/perf/util/trace-event-scripting.c | 7 +++++++ tools/perf/util/trace-event.h | 1 + 5 files changed, 32 insertions(+)
tools/perf/builtin-script.c +12 -0
@@ -485,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused,return 0 ; } +static int default_flush_script (void ) +{ +return 0 ; +} +static int default_stop_script (void ) {return 0 ;
@@ -498,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,static struct scripting_ops default_scripting_ops = { .start_script = default_start_script, + .flush_script = default_flush_script, .stop_script = default_stop_script, .process_event = process_event, .generate_script = default_generate_script,
@@ -513,6 +519,11 @@ static void setup_scripting(void) scripting_ops = &default_scripting_ops; } +static int flush_scripting (void ) +{ +return scripting_ops->flush_script (); +} +static int cleanup_scripting (void ) {pr_debug ("\nperf script stopped\n" );
@@ -1806,6 +1817,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) err =__cmd_script (&script); +flush_scripting ();perf_session__delete (session);cleanup_scripting (); out:
tools/perf/util/scripting-engines/trace-event-perl.c +6 -0
@@ -432,6 +432,11 @@ error:return err; } +static int perl_flush_script (void ) +{ +return 0 ; +} +/* * Stop trace script */
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)struct scripting_ops perl_scripting_ops = { .name ="Perl" , .start_script = perl_start_script, + .flush_script = perl_flush_script, .stop_script = perl_stop_script, .process_event = perl_process_event, .generate_script = perl_generate_script,
tools/perf/util/scripting-engines/trace-event-python.c +6 -0
@@ -1022,6 +1022,11 @@ error:return err; } +static int python_flush_script (void ) +{ +return 0 ; +} +/* * Stop trace script */
@@ -1210,6 +1215,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)struct scripting_ops python_scripting_ops = { .name ="Python" , .start_script = python_start_script, + .flush_script = python_flush_script, .stop_script = python_stop_script, .process_event = python_process_event, .generate_script = python_generate_script,
tools/perf/util/trace-event-scripting.c +7 -0
@@ -30,6 +30,11 @@struct scripting_context *scripting_context; +static int flush_script_unsupported (void ) +{ +return 0 ; +} +static int stop_script_unsupported (void ) {return 0 ;
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *peventstruct scripting_ops python_scripting_unsupported_ops = { .name ="Python" , .start_script = python_start_script_unsupported, + .flush_script = flush_script_unsupported, .stop_script = stop_script_unsupported, .process_event = process_event_unsupported, .generate_script = python_generate_script_unsupported,
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *peventstruct scripting_ops perl_scripting_unsupported_ops = { .name ="Perl" , .start_script = perl_start_script_unsupported, + .flush_script = flush_script_unsupported, .stop_script = stop_script_unsupported, .process_event = process_event_unsupported, .generate_script = perl_generate_script_unsupported,
tools/perf/util/trace-event.h +1 -0
@@ -64,6 +64,7 @@ struct perf_session;struct scripting_ops {const char *name;int (*start_script) (const char *script,int argc,const char **argv); +int (*flush_script) (void );int (*stop_script) (void ); void (*process_event) (union perf_event *event, struct perf_sample *sample,
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 42/52 perf tools: Defer export of comms that were not 'set'
In reply to Adrian HunterTracing for a workload begins before the comm event is seen, which results in the initial comm having a string of the form ":<pid>" (e.g. ":12345"). In order to export the correct string, defer the export until the new script 'flush' callback.
--- tools/perf/util/db-export.c | 62 +++++++++++++++++++++- tools/perf/util/db-export.h | 3 ++ .../util/scripting-engines/trace-event-python.c | 4 +- 3 files changed, 67 insertions(+), 2 deletions(-)
tools/perf/util/db-export.c +61 -1
@@ -21,17 +21,74 @@#include "comm.h" #include "symbol.h" #include "event.h" +#include "util.h" #include "thread-stack.h" #include "db-export.h" +struct deferred_export { +struct list_head node; +struct comm *comm; +}; + +static int db_export__deferred (struct db_export *dbe) +{ +struct deferred_export *de; +int err; + +while (!list_empty (&dbe->deferred)) { + de = list_entry(dbe->deferred.next, struct deferred_export, + node); + err = dbe->export_comm (dbe, de->comm); +list_del (&de->node); +free (de); +if (err) +return err; + } + +return 0 ; +} + +static void db_export__free_deferred (struct db_export *dbe) +{ +struct deferred_export *de; + +while (!list_empty (&dbe->deferred)) { + de = list_entry(dbe->deferred.next, struct deferred_export, + node); +list_del (&de->node); +free (de); + } +} + +static int db_export__defer_comm (struct db_export *dbe,struct comm *comm) +{ +struct deferred_export *de; + + de =zalloc (sizeof (struct deferred_export )); +if (!de) +return -ENOMEM ; + + de->comm = comm; +list_add_tail (&de->node, &dbe->deferred); + +return 0 ; +} +int db_export__init (struct db_export *dbe) {memset (dbe,0 ,sizeof (struct db_export )); +INIT_LIST_HEAD (&dbe->deferred);return 0 ; } +int db_export__flush (struct db_export *dbe) +{ +return db_export__deferred (dbe); +} +void db_export__exit (struct db_export *dbe) { +db_export__free_deferred (dbe);call_return_processor__free (dbe->crp); dbe->crp =NULL ; }
@@ -115,7 +172,10 @@ int db_export__comm(struct db_export *dbe, struct comm *comm, comm->db_id = ++dbe->comm_last_db_id;if (dbe->export_comm) { - err = dbe->export_comm (dbe, comm); +if (main_thread->comm_set) + err = dbe->export_comm (dbe, comm); +else + err =db_export__defer_comm (dbe, comm);if (err)return err; }
tools/perf/util/db-export.h +3 -0
@@ -17,6 +17,7 @@#define __PERF_DB_EXPORT_H#include <linux/types.h> +#include <linux/list.h> struct perf_evsel ;struct machine ;
@@ -74,9 +75,11 @@ struct db_export {u64 sample_last_db_id;u64 call_path_last_db_id;u64 call_return_last_db_id; +struct list_head deferred; };int db_export__init (struct db_export *dbe); +int db_export__flush (struct db_export *dbe);void db_export__exit (struct db_export *dbe);int db_export__evsel (struct db_export *dbe,struct perf_evsel *evsel);int db_export__machine (struct db_export *dbe,struct machine *machine);
tools/perf/util/scripting-engines/trace-event-python.c +3 -1
@@ -1024,7 +1024,9 @@ error:static int python_flush_script (void ) { -return 0 ; +struct tables *tables = &tables_global; + +return db_export__flush (&tables->dbe); }/*
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 43/52 perf tools: Add perf-with-kcore script
In reply to Adrian HunterDecoding an Intel PT trace of the kernel requires an accurate kernel object image. This is provided by making a copy of kcore. However the copy needs to be made under the same conditions as the original recording, and then it needs to be associated with the perf.data file. The perf-with-kcore script does that.
The script also checks the permissions on the buildid cache and can be used to fix them. That is needed for distributions where root does not have a home directory and consequently writes to the same buildid cache as the user, resulting in cached files that the user does not have access to.
Example:
$ ./perf-with-kcore
Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]
<perf sub-command> can be record, script, report or inject
or: perf-with-kcore fix_buildid_cache_permissions
$ ./perf-with-kcore record pt_uname -e intel_pt// -- uname
Recording
Using /home/ahunter/bin/perf
perf version 3.15.rc3.g4549ba
/home/ahunter/bin/perf record -o pt_uname/perf.data -e intel_pt// -- uname
Linux
[ perf record: Woken up 3 times to write data ]
[ perf record: Captured and wrote 0.023 MB pt_uname/perf.data ]
Copying kcore
[sudo] password for ahunter:
Done
$ tools/perf/perf-with-kcore.sh script pt_uname | head
Using /home/ahunter/bin/perf
perf version 3.15.rc3.g4549ba
/home/ahunter/bin/perf script -i pt_uname/perf.data --kallsyms=pt_uname/kcore_dir/kallsyms
swapper 0 [002] 161533.969666: sched:sched_switch: swapper/2:0 [120] R ==> perf:11316 [120]
:11315 11315 [003] 161533.969704: sched:sched_switch: perf:11315 [120] S ==> swapper/3:0 [120]
:11316 11316 [002] 161533.969783: sched:sched_switch: perf:11316 [120] R ==> migration/2:33 [0]
:33 33 [002] 161533.969791: sched:sched_switch: migration/2:33 [0] S ==> swapper/2:0 [120]
swapper 0 [003] 161533.969792: sched:sched_switch: swapper/3:0 [120] R ==> perf:11316 [120]
:11316 11316 [003] 161533.970062: branches: 0 [unknown] ([unknown]) => ffffffff810532fa native_write_msr_safe ([kernel.kallsyms])
:11316 11316 [003] 161533.970062: branches: ffffffff810532fd native_write_msr_safe ([kernel.kallsyms]) => ffffffff81035b31 pt_config_start ([kernel.kallsyms])--- tools/perf/.gitignore | 1 + tools/perf/Makefile.perf | 5 +- tools/perf/perf-with-kcore.sh | 259 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 tools/perf/perf-with-kcore.sh
tools/perf/.gitignore +1 -0
@@ -15,6 +15,7 @@ perf.data perf.data.old output.svg perf-archive +perf-with-kcore tags TAGS cscope*
tools/perf/Makefile.perf +4 -1
@@ -126,6 +126,7 @@ PYRF_OBJS = SCRIPT_SH = SCRIPT_SH += perf-archive.sh +SCRIPT_SH += perf-with-kcore.sh grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1))
@@ -879,6 +880,8 @@ install-bin: all install-gtk $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' $(call QUIET_INSTALL, perf-archive) \ $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' + $(call QUIET_INSTALL, perf-with-kcore) \ + $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' ifndef NO_LIBPERL $(call QUIET_INSTALL, perl-scripts) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -924,7 +927,7 @@ config-clean: @$(MAKE) -C config/feature-checks clean >/dev/null clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean - $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) + $(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-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
tools/perf/perf-with-kcore.sh new file +259 -0
259 lines not on this page · raw message
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 44/52 perf tools: Pass machine to vdso__dso_findnew()
In reply to Adrian HunterThis is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.
--- tools/perf/util/machine.c | 4 ++-- tools/perf/util/map.c | 7 ++++--- tools/perf/util/map.h | 2 +- tools/perf/util/vdso.c | 7 ++++--- tools/perf/util/vdso.h | 4 +++- 5 files changed, 14 insertions(+), 10 deletions(-)
tools/perf/util/machine.c +2 -2
@@ -1124,7 +1124,7 @@ int machine__process_mmap2_event(struct machine *machine,else type =MAP__FUNCTION ; - map = map__new(&machine->user_dsos, event->mmap2.start, + map = map__new(machine, event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, event->mmap2.pid, event->mmap2.maj, event->mmap2.min, event->mmap2.ino,
@@ -1174,7 +1174,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *eventelse type =MAP__FUNCTION ; - map = map__new(&machine->user_dsos, event->mmap.start, + map = map__new(machine, event->mmap.start, event->mmap.len, event->mmap.pgoff, event->mmap.pid, 0, 0, 0, 0, 0, 0, event->mmap.filename,
tools/perf/util/map.c +4 -3
@@ -13,6 +13,7 @@#include "build-id.h" #include "util.h" #include "debug.h" +#include "machine.h" #include <linux/string.h> const char *map_type__name[MAP__NR_TYPES ] = {
@@ -137,7 +138,7 @@ void map__init(struct map *map, enum map_type type, map->erange_warned = false; } -struct map *map__new (struct list_head *dsos__list,u64 start,u64 len, +struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type)
@@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,if (vdso) { pgoff =0 ; - dso =vdso__dso_findnew (dsos__list); + dso =vdso__dso_findnew (machine); }else - dso =__dsos__findnew (dsos__list, filename); + dso =__dsos__findnew (&machine->user_dsos, filename);if (dso ==NULL ) goto out_delete;
tools/perf/util/map.h +1 -1
@@ -119,7 +119,7 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);void map__init (struct map *map,enum map_type type,u64 start,u64 end,u64 pgoff,struct dso *dso); -struct map *map__new (struct list_head *dsos__list,u64 start,u64 len, +struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type);
tools/perf/util/vdso.c +4 -3
@@ -11,6 +11,7 @@#include "vdso.h" #include "util.h" #include "symbol.h" +#include "machine.h" #include "linux/string.h" #include "debug.h"
@@ -90,9 +91,9 @@ void vdso__exit(void)unlink (vdso_file); } -struct dso *vdso__dso_findnew (struct list_head *head) +struct dso *vdso__dso_findnew (struct machine *machine) { -struct dso *dso =dsos__find (head,VDSO__MAP_NAME , true); +struct dso *dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true);if (!dso) {char *file;
@@ -103,7 +104,7 @@ struct dso *vdso__dso_findnew(struct list_head *head) dso =dso__new (VDSO__MAP_NAME );if (dso !=NULL ) { -dsos__add (head, dso); +dsos__add (&machine->user_dsos, dso);dso__set_long_name (dso, file, false); } }
tools/perf/util/vdso.h +3 -1
@@ -12,7 +12,9 @@ static inline bool is_vdso_map(const char *filename) return !strcmp(filename, VDSO__MAP_NAME); } -struct dso *vdso__dso_findnew (struct list_head *head); +struct machine ; + +struct dso *vdso__dso_findnew (struct machine *machine);void vdso__exit (void );#endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Pass machine to vdso__dso_findnew()
perf tools: Pass machine to vdso__dso_findnew()
Commit-ID: 2a03068c5cfa104768703cbefa2e23a6353f8de5 Gitweb: http://git.kernel.org/tip/2a03068c5cfa104768703cbefa2e23a6353f8de5 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:53 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 16:45:50 -0300
perf tools: Pass machine to vdso__dso_findnew()
This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.
--- tools/perf/util/machine.c | 4 ++-- tools/perf/util/map.c | 7 ++++--- tools/perf/util/map.h | 2 +- tools/perf/util/vdso.c | 7 ++++--- tools/perf/util/vdso.h | 4 +++- 5 files changed, 14 insertions(+), 10 deletions(-)
tools/perf/util/machine.c +2 -2
@@ -1095,7 +1095,7 @@ int machine__process_mmap2_event(struct machine *machine,else type =MAP__FUNCTION ; - map = map__new(&machine->user_dsos, event->mmap2.start, + map = map__new(machine, event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, event->mmap2.pid, event->mmap2.maj, event->mmap2.min, event->mmap2.ino,
@@ -1145,7 +1145,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *eventelse type =MAP__FUNCTION ; - map = map__new(&machine->user_dsos, event->mmap.start, + map = map__new(machine, event->mmap.start, event->mmap.len, event->mmap.pgoff, event->mmap.pid, 0, 0, 0, 0, 0, 0, event->mmap.filename,
tools/perf/util/map.c +4 -3
@@ -13,6 +13,7 @@#include "build-id.h" #include "util.h" #include "debug.h" +#include "machine.h" #include <linux/string.h> const char *map_type__name[MAP__NR_TYPES ] = {
@@ -137,7 +138,7 @@ void map__init(struct map *map, enum map_type type, map->erange_warned = false; } -struct map *map__new (struct list_head *dsos__list,u64 start,u64 len, +struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type)
@@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,if (vdso) { pgoff =0 ; - dso =vdso__dso_findnew (dsos__list); + dso =vdso__dso_findnew (machine); }else - dso =__dsos__findnew (dsos__list, filename); + dso =__dsos__findnew (&machine->user_dsos, filename);if (dso ==NULL ) goto out_delete;
tools/perf/util/map.h +1 -1
@@ -119,7 +119,7 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);void map__init (struct map *map,enum map_type type,u64 start,u64 end,u64 pgoff,struct dso *dso); -struct map *map__new (struct list_head *dsos__list,u64 start,u64 len, +struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type);
tools/perf/util/vdso.c +4 -3
@@ -11,6 +11,7 @@#include "vdso.h" #include "util.h" #include "symbol.h" +#include "machine.h" #include "linux/string.h" #include "debug.h"
@@ -90,9 +91,9 @@ void vdso__exit(void)unlink (vdso_file); } -struct dso *vdso__dso_findnew (struct list_head *head) +struct dso *vdso__dso_findnew (struct machine *machine) { -struct dso *dso =dsos__find (head,VDSO__MAP_NAME , true); +struct dso *dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true);if (!dso) {char *file;
@@ -103,7 +104,7 @@ struct dso *vdso__dso_findnew(struct list_head *head) dso =dso__new (VDSO__MAP_NAME );if (dso !=NULL ) { -dsos__add (head, dso); +dsos__add (&machine->user_dsos, dso);dso__set_long_name (dso, file, false); } }
tools/perf/util/vdso.h +3 -1
@@ -12,7 +12,9 @@ static inline bool is_vdso_map(const char *filename) return !strcmp(filename, VDSO__MAP_NAME); } -struct dso *vdso__dso_findnew (struct list_head *head); +struct machine ; + +struct dso *vdso__dso_findnew (struct machine *machine);void vdso__exit (void );#endif /* __PERF_VDSO__ */
Adrian Hunter
reviewerPATCH 45/52 perf tools: Group VDSO global variables into a structure
In reply to Adrian HunterThis is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.
Also allowance is made for the later addition of
support for compat VDSOs.
--- tools/perf/util/vdso.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-)
tools/perf/util/vdso.c +32 -12
@@ -15,8 +15,27 @@#include "linux/string.h" #include "debug.h" -static bool vdso_found; -static char vdso_file[] ="/tmp/perf-vdso.so-XXXXXX" ; +#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" + +struct vdso_file { +bool found; +bool error; +char temp_file_name[sizeof (VDSO__TEMP_FILE_NAME )]; +const char *dso_name; +}; + +struct vdso_info { +struct vdso_file vdso; +}; + +static struct vdso_info vdso_info_ = { + .vdso = { + .temp_file_name =VDSO__TEMP_FILE_NAME , + .dso_name =VDSO__MAP_NAME , + }, +}; + +static struct vdso_info *vdso_info = &vdso_info_;static int find_vdso_map (void **start,void **end) {
@@ -49,7 +68,7 @@ static int find_vdso_map(void **start, void **end)return !found; } -static char *get_file (void ) +static char *get_file (struct vdso_file *vdso_file) {char *vdso =NULL ;char *buf =NULL ;
@@ -57,10 +76,10 @@ static char *get_file(void)size_t size;int fd; -if (vdso_found) -return vdso_file; +if (vdso_file->found) +return vdso_file->temp_file_name; -if (find_vdso_map (&start, &end)) +if (vdso_file->error ||find_vdso_map (&start, &end))return NULL ; size = end - start;
@@ -69,26 +88,27 @@ static char *get_file(void)if (!buf)return NULL ; - fd =mkstemp (vdso_file); + fd =mkstemp (vdso_file->temp_file_name);if (fd <0 ) goto out;if (size == (size_t )write (fd, buf, size)) - vdso = vdso_file; + vdso = vdso_file->temp_file_name;close (fd); out:free (buf); - vdso_found = (vdso !=NULL ); + vdso_file->found = (vdso !=NULL ); + vdso_file->error = !vdso_file->found;return vdso; }void vdso__exit (void ) { -if (vdso_found) -unlink (vdso_file); +if (vdso_info->vdso.found) +unlink (vdso_info->vdso.temp_file_name); }struct dso *vdso__dso_findnew (struct machine *machine)
@@ -98,7 +118,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!dso) {char *file; - file =get_file (); + file =get_file (&vdso_info->vdso);if (!file)return NULL ;
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Group VDSO global variables into a structure
perf tools: Group VDSO global variables into a structure
Commit-ID: 30f4f815a45d0b148d17afb0d5a5575ae2ba4309 Gitweb: http://git.kernel.org/tip/30f4f815a45d0b148d17afb0d5a5575ae2ba4309 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:54 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:11:26 -0300
perf tools: Group VDSO global variables into a structure
This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.
Also allowance is made for the later addition of support for compat VDSOs.
--- tools/perf/util/vdso.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-)
tools/perf/util/vdso.c +32 -12
@@ -15,8 +15,27 @@#include "linux/string.h" #include "debug.h" -static bool vdso_found; -static char vdso_file[] ="/tmp/perf-vdso.so-XXXXXX" ; +#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" + +struct vdso_file { +bool found; +bool error; +char temp_file_name[sizeof (VDSO__TEMP_FILE_NAME )]; +const char *dso_name; +}; + +struct vdso_info { +struct vdso_file vdso; +}; + +static struct vdso_info vdso_info_ = { + .vdso = { + .temp_file_name =VDSO__TEMP_FILE_NAME , + .dso_name =VDSO__MAP_NAME , + }, +}; + +static struct vdso_info *vdso_info = &vdso_info_;static int find_vdso_map (void **start,void **end) {
@@ -49,7 +68,7 @@ static int find_vdso_map(void **start, void **end)return !found; } -static char *get_file (void ) +static char *get_file (struct vdso_file *vdso_file) {char *vdso =NULL ;char *buf =NULL ;
@@ -57,10 +76,10 @@ static char *get_file(void)size_t size;int fd; -if (vdso_found) -return vdso_file; +if (vdso_file->found) +return vdso_file->temp_file_name; -if (find_vdso_map (&start, &end)) +if (vdso_file->error ||find_vdso_map (&start, &end))return NULL ; size = end - start;
@@ -69,26 +88,27 @@ static char *get_file(void)if (!buf)return NULL ; - fd =mkstemp (vdso_file); + fd =mkstemp (vdso_file->temp_file_name);if (fd <0 ) goto out;if (size == (size_t )write (fd, buf, size)) - vdso = vdso_file; + vdso = vdso_file->temp_file_name;close (fd); out:free (buf); - vdso_found = (vdso !=NULL ); + vdso_file->found = (vdso !=NULL ); + vdso_file->error = !vdso_file->found;return vdso; }void vdso__exit (void ) { -if (vdso_found) -unlink (vdso_file); +if (vdso_info->vdso.found) +unlink (vdso_info->vdso.temp_file_name); }struct dso *vdso__dso_findnew (struct machine *machine)
@@ -98,7 +118,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!dso) {char *file; - file =get_file (); + file =get_file (&vdso_info->vdso);if (!file)return NULL ;
Adrian Hunter
reviewerPATCH 46/52 perf tools: Fix the lifetime of the VDSO temporary file
In reply to Adrian HunterThe VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session. Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.
--- tools/perf/util/machine.c | 2 ++ tools/perf/util/machine.h | 3 +++ tools/perf/util/session.c | 2 -- tools/perf/util/vdso.c | 39 +++++++++++++++++++++++++++++---------- tools/perf/util/vdso.h | 2 +- 5 files changed, 35 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +2 -0
@@ -8,6 +8,7 @@#include "sort.h" #include "strlist.h" #include "thread.h" +#include "vdso.h" #include <stdbool.h> #include <symbol/kallsyms.h> #include "unwind.h"
@@ -107,6 +108,7 @@ void machine__exit(struct machine *machine)map_groups__exit (&machine->kmaps);dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos); +vdso__exit (machine);zfree (&machine->root_dir);zfree (&machine->current_tid); }
tools/perf/util/machine.h +3 -0
@@ -20,6 +20,8 @@ union perf_event;extern const char *ref_reloc_sym_names[]; +struct vdso_info ; +struct machine {struct rb_node rb_node;pid_t pid;
@@ -29,6 +31,7 @@ struct machine {struct rb_root threads;struct list_head dead_threads;struct thread *last_match; +struct vdso_info *vdso_info;struct list_head user_dsos;struct list_head kernel_dsos;struct map_groups kmaps;
tools/perf/util/session.c +0 -2
@@ -14,7 +14,6 @@#include "util.h" #include "cpumap.h" #include "perf_regs.h" -#include "vdso.h" static int perf_session__open (struct perf_session *session) {
@@ -176,7 +175,6 @@ void perf_session__delete(struct perf_session *session)if (session->file)perf_data_file__close (session->file);free (session); -vdso__exit (); } static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
@@ -28,14 +28,17 @@ struct vdso_info {struct vdso_file vdso; }; -static struct vdso_info vdso_info_ = { - .vdso = { - .temp_file_name =VDSO__TEMP_FILE_NAME , - .dso_name =VDSO__MAP_NAME , - }, -}; - -static struct vdso_info *vdso_info = &vdso_info_; +static struct vdso_info *vdso_info__new (void ) +{ +static const struct vdso_info vdso_info_init = { + .vdso = { + .temp_file_name =VDSO__TEMP_FILE_NAME , + .dso_name =VDSO__MAP_NAME , + }, + }; + +return memdup (&vdso_info_init,sizeof (vdso_info_init)); +}static int find_vdso_map (void **start,void **end) {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)return vdso; } -void vdso__exit (void ) +void vdso__exit (struct machine *machine) { +struct vdso_info *vdso_info = machine->vdso_info; + +if (!vdso_info) +return ; +if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); + +zfree (&machine->vdso_info); }struct dso *vdso__dso_findnew (struct machine *machine) { -struct dso *dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true); +struct vdso_info *vdso_info; +struct dso *dso; + +if (!machine->vdso_info) + machine->vdso_info =vdso_info__new (); + + vdso_info = machine->vdso_info; +if (!vdso_info) +return NULL ; + dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true);if (!dso) {char *file;
tools/perf/util/vdso.h +1 -1
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)struct machine ;struct dso *vdso__dso_findnew (struct machine *machine); -void vdso__exit (void ); +void vdso__exit (struct machine *machine);#endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH v2 46/52 perf tools: Fix the lifetime of the VDSO temporary file
The VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session. Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.
---
V2:
Initialize vdso_info to NULL in machine_init()
The change is reflected in the branch here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme
tools/perf/util/machine.c | 4 ++++ tools/perf/util/machine.h | 3 +++ tools/perf/util/session.c | 2 -- tools/perf/util/vdso.c | 39 +++++++++++++++++++++++++++++---------- tools/perf/util/vdso.h | 2 +- 5 files changed, 37 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +4 -0
@@ -8,6 +8,7 @@#include "sort.h" #include "strlist.h" #include "thread.h" +#include "vdso.h" #include <stdbool.h> #include <symbol/kallsyms.h> #include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)INIT_LIST_HEAD (&machine->dead_threads); machine->last_match =NULL ; + machine->vdso_info =NULL ; + machine->kmaps.machine = machine; machine->pid = pid;
@@ -107,6 +110,7 @@ void machine__exit(struct machine *machine)map_groups__exit (&machine->kmaps);dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos); +vdso__exit (machine);zfree (&machine->root_dir);zfree (&machine->current_tid); }
tools/perf/util/machine.h +3 -0
@@ -20,6 +20,8 @@ union perf_event;extern const char *ref_reloc_sym_names[]; +struct vdso_info ; +struct machine {struct rb_node rb_node;pid_t pid;
@@ -29,6 +31,7 @@ struct machine {struct rb_root threads;struct list_head dead_threads;struct thread *last_match; +struct vdso_info *vdso_info;struct list_head user_dsos;struct list_head kernel_dsos;struct map_groups kmaps;
tools/perf/util/session.c +0 -2
@@ -14,7 +14,6 @@#include "util.h" #include "cpumap.h" #include "perf_regs.h" -#include "vdso.h" static int perf_session__open (struct perf_session *session) {
@@ -176,7 +175,6 @@ void perf_session__delete(struct perf_session *session)if (session->file)perf_data_file__close (session->file);free (session); -vdso__exit (); } static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
@@ -28,14 +28,17 @@ struct vdso_info {struct vdso_file vdso; }; -static struct vdso_info vdso_info_ = { - .vdso = { - .temp_file_name =VDSO__TEMP_FILE_NAME , - .dso_name =VDSO__MAP_NAME , - }, -}; - -static struct vdso_info *vdso_info = &vdso_info_; +static struct vdso_info *vdso_info__new (void ) +{ +static const struct vdso_info vdso_info_init = { + .vdso = { + .temp_file_name =VDSO__TEMP_FILE_NAME , + .dso_name =VDSO__MAP_NAME , + }, + }; + +return memdup (&vdso_info_init,sizeof (vdso_info_init)); +}static int find_vdso_map (void **start,void **end) {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)return vdso; } -void vdso__exit (void ) +void vdso__exit (struct machine *machine) { +struct vdso_info *vdso_info = machine->vdso_info; + +if (!vdso_info) +return ; +if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); + +zfree (&machine->vdso_info); }struct dso *vdso__dso_findnew (struct machine *machine) { -struct dso *dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true); +struct vdso_info *vdso_info; +struct dso *dso; + +if (!machine->vdso_info) + machine->vdso_info =vdso_info__new (); + + vdso_info = machine->vdso_info; +if (!vdso_info) +return NULL ; + dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true);if (!dso) {char *file;
tools/perf/util/vdso.h +1 -1
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)struct machine ;struct dso *vdso__dso_findnew (struct machine *machine); -void vdso__exit (void ); +void vdso__exit (struct machine *machine);#endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Fix the lifetime of the VDSO temporary file
perf machine: Fix the lifetime of the VDSO temporary file
Commit-ID: d027b64001b21328cc92d35c6444e1a7a926ea76 Gitweb: http://git.kernel.org/tip/d027b64001b21328cc92d35c6444e1a7a926ea76 Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 23 Jul 2014 14:23:00 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:14:39 -0300
perf machine: Fix the lifetime of the VDSO temporary file
The VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session.
Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.
--- tools/perf/util/machine.c | 4 ++++ tools/perf/util/machine.h | 3 +++ tools/perf/util/session.c | 2 -- tools/perf/util/vdso.c | 39 +++++++++++++++++++++++++++++---------- tools/perf/util/vdso.h | 2 +- 5 files changed, 37 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +4 -0
@@ -8,6 +8,7 @@#include "sort.h" #include "strlist.h" #include "thread.h" +#include "vdso.h" #include <stdbool.h> #include <symbol/kallsyms.h> #include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)INIT_LIST_HEAD (&machine->dead_threads); machine->last_match =NULL ; + machine->vdso_info =NULL ; + machine->kmaps.machine = machine; machine->pid = pid;
@@ -105,6 +108,7 @@ void machine__exit(struct machine *machine)map_groups__exit (&machine->kmaps);dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos); +vdso__exit (machine);zfree (&machine->root_dir);zfree (&machine->current_tid); }
tools/perf/util/machine.h +3 -0
@@ -20,6 +20,8 @@ union perf_event;extern const char *ref_reloc_sym_names[]; +struct vdso_info ; +struct machine {struct rb_node rb_node;pid_t pid;
@@ -28,6 +30,7 @@ struct machine {struct rb_root threads;struct list_head dead_threads;struct thread *last_match; +struct vdso_info *vdso_info;struct list_head user_dsos;struct list_head kernel_dsos;struct map_groups kmaps;
tools/perf/util/session.c +0 -2
@@ -14,7 +14,6 @@#include "util.h" #include "cpumap.h" #include "perf_regs.h" -#include "vdso.h" static int perf_session__open (struct perf_session *session) {
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)if (session->file)perf_data_file__close (session->file);free (session); -vdso__exit (); } static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
@@ -28,14 +28,17 @@ struct vdso_info {struct vdso_file vdso; }; -static struct vdso_info vdso_info_ = { - .vdso = { - .temp_file_name =VDSO__TEMP_FILE_NAME , - .dso_name =VDSO__MAP_NAME , - }, -}; - -static struct vdso_info *vdso_info = &vdso_info_; +static struct vdso_info *vdso_info__new (void ) +{ +static const struct vdso_info vdso_info_init = { + .vdso = { + .temp_file_name =VDSO__TEMP_FILE_NAME , + .dso_name =VDSO__MAP_NAME , + }, + }; + +return memdup (&vdso_info_init,sizeof (vdso_info_init)); +}static int find_vdso_map (void **start,void **end) {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)return vdso; } -void vdso__exit (void ) +void vdso__exit (struct machine *machine) { +struct vdso_info *vdso_info = machine->vdso_info; + +if (!vdso_info) +return ; +if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); + +zfree (&machine->vdso_info); }struct dso *vdso__dso_findnew (struct machine *machine) { -struct dso *dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true); +struct vdso_info *vdso_info; +struct dso *dso; + +if (!machine->vdso_info) + machine->vdso_info =vdso_info__new (); + + vdso_info = machine->vdso_info; +if (!vdso_info) +return NULL ; + dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true);if (!dso) {char *file;
tools/perf/util/vdso.h +1 -1
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)struct machine ;struct dso *vdso__dso_findnew (struct machine *machine); -void vdso__exit (void ); +void vdso__exit (struct machine *machine);#endif /* __PERF_VDSO__ */
Adrian Hunter
reviewerPATCH 47/52 perf tools: Add vdso__new()
In reply to Adrian HunterThis is preparation for adding support for
compat VDSOs.
--- tools/perf/util/vdso.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/util/vdso.c +15 -5
@@ -121,6 +121,20 @@ void vdso__exit(struct machine *machine)zfree (&machine->vdso_info); } +static struct dso *vdso__new (struct machine *machine,const char *short_name, +const char *long_name) +{ +struct dso *dso; + + dso =dso__new (short_name); +if (dso !=NULL ) { +dsos__add (&machine->user_dsos, dso); +dso__set_long_name (dso, long_name, false); + } + +return dso; +} +struct dso *vdso__dso_findnew (struct machine *machine) {struct vdso_info *vdso_info;
@@ -141,11 +155,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!file)return NULL ; - dso =dso__new (VDSO__MAP_NAME ); -if (dso !=NULL ) { -dsos__add (&machine->user_dsos, dso); -dso__set_long_name (dso, file, false); - } + dso =vdso__new (machine,VDSO__MAP_NAME , file); }return dso;
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add vdso__new()
perf tools: Add vdso__new()
Commit-ID: 4f71f2a0abe8b2a76669a4608a62f5020a64205a Gitweb: http://git.kernel.org/tip/4f71f2a0abe8b2a76669a4608a62f5020a64205a Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:56 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:34:47 -0300
perf tools: Add vdso__new()
This is preparation for adding support for compat VDSOs.
--- tools/perf/util/vdso.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/util/vdso.c +15 -5
@@ -121,6 +121,20 @@ void vdso__exit(struct machine *machine)zfree (&machine->vdso_info); } +static struct dso *vdso__new (struct machine *machine,const char *short_name, +const char *long_name) +{ +struct dso *dso; + + dso =dso__new (short_name); +if (dso !=NULL ) { +dsos__add (&machine->user_dsos, dso); +dso__set_long_name (dso, long_name, false); + } + +return dso; +} +struct dso *vdso__dso_findnew (struct machine *machine) {struct vdso_info *vdso_info;
@@ -141,11 +155,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!file)return NULL ; - dso =dso__new (VDSO__MAP_NAME ); -if (dso !=NULL ) { -dsos__add (&machine->user_dsos, dso); -dso__set_long_name (dso, file, false); - } + dso =vdso__new (machine,VDSO__MAP_NAME , file); }return dso;
Adrian Hunter
reviewerPATCH 48/52 perf tools: Separate the VDSO map name from the VDSO dso name
In reply to Adrian HunterThis is in preparation for supporting 32-bit compatibility VDSOs.
--- tools/perf/util/header.c | 10 +++++----- tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/vdso.c | 11 ++++++++--- tools/perf/util/vdso.h | 6 ++++++ 4 files changed, 20 insertions(+), 9 deletions(-)
tools/perf/util/header.c +5 -5
@@ -256,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,if (!pos->hit)continue ; -if (is_vdso_map (pos->short_name)) { - name = (char *)VDSO__MAP_NAME ; - name_len =sizeof (VDSO__MAP_NAME ) +1 ; +if (dso__is_vdso (pos)) { + name = pos->short_name; + name_len = pos->short_name_len +1 ; }else if (dso__is_kcore (pos)) {machine__mmap_name (machine, nm,sizeof (nm)); name = nm;
@@ -339,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, len =scnprintf (filename, size,"%s%s%s" , debugdir, slash ?"/" :"" , - is_vdso ?VDSO__MAP_NAME : realname); + is_vdso ?DSO__NAME_VDSO : realname);if (mkdir_p (filename,0755 )) goto out_free;
@@ -427,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, const char *debugdir) {bool is_kallsyms = dso->kernel && dso->long_name[0 ] !='/' ; -bool is_vdso =is_vdso_map (dso->short_name); +bool is_vdso =dso__is_vdso (dso);const char *name = dso->long_name;char nm[PATH_MAX ];
tools/perf/util/symbol-elf.c +1 -1
@@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,GElf_Shdr shdr; ss->adjust_symbols = (ehdr.e_type ==ET_EXEC || ehdr.e_type ==ET_REL || -is_vdso_map (dso->short_name) || +dso__is_vdso (dso) ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL );
tools/perf/util/vdso.c +8 -3
@@ -33,7 +33,7 @@ static struct vdso_info *vdso_info__new(void)static const struct vdso_info vdso_info_init = { .vdso = { .temp_file_name =VDSO__TEMP_FILE_NAME , - .dso_name =VDSO__MAP_NAME , + .dso_name =DSO__NAME_VDSO , }, };
@@ -147,7 +147,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!vdso_info)return NULL ; - dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true); + dso =dsos__find (&machine->user_dsos,DSO__NAME_VDSO , true);if (!dso) {char *file;
@@ -155,8 +155,13 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!file)return NULL ; - dso =vdso__new (machine,VDSO__MAP_NAME , file); + dso =vdso__new (machine,DSO__NAME_VDSO , file); }return dso; } + +bool dso__is_vdso (struct dso *dso) +{ +return !strcmp (dso->short_name,DSO__NAME_VDSO ); +}
tools/perf/util/vdso.h +6 -0
@@ -7,11 +7,17 @@#define VDSO__MAP_NAME "[vdso]" +#define DSO__NAME_VDSO "[vdso]" +static inline bool is_vdso_map (const char *filename) {return !strcmp (filename,VDSO__MAP_NAME ); } +struct dso ; + +bool dso__is_vdso (struct dso *dso); +struct machine ;struct dso *vdso__dso_findnew (struct machine *machine);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Separate the VDSO map name from the VDSO dso name
perf tools: Separate the VDSO map name from the VDSO dso name
Commit-ID: 51682dc744c3db89e515ac47a4c1f7003fd81d20 Gitweb: http://git.kernel.org/tip/51682dc744c3db89e515ac47a4c1f7003fd81d20 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:57 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:36:32 -0300
perf tools: Separate the VDSO map name from the VDSO dso name
This is in preparation for supporting 32-bit compatibility VDSOs.
--- tools/perf/util/header.c | 10 +++++----- tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/vdso.c | 11 ++++++++--- tools/perf/util/vdso.h | 6 ++++++ 4 files changed, 20 insertions(+), 9 deletions(-)
tools/perf/util/header.c +5 -5
@@ -256,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,if (!pos->hit)continue ; -if (is_vdso_map (pos->short_name)) { - name = (char *)VDSO__MAP_NAME ; - name_len =sizeof (VDSO__MAP_NAME ) +1 ; +if (dso__is_vdso (pos)) { + name = pos->short_name; + name_len = pos->short_name_len +1 ; }else if (dso__is_kcore (pos)) {machine__mmap_name (machine, nm,sizeof (nm)); name = nm;
@@ -339,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, len =scnprintf (filename, size,"%s%s%s" , debugdir, slash ?"/" :"" , - is_vdso ?VDSO__MAP_NAME : realname); + is_vdso ?DSO__NAME_VDSO : realname);if (mkdir_p (filename,0755 )) goto out_free;
@@ -427,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, const char *debugdir) {bool is_kallsyms = dso->kernel && dso->long_name[0 ] !='/' ; -bool is_vdso =is_vdso_map (dso->short_name); +bool is_vdso =dso__is_vdso (dso);const char *name = dso->long_name;char nm[PATH_MAX ];
tools/perf/util/symbol-elf.c +1 -1
@@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,GElf_Shdr shdr; ss->adjust_symbols = (ehdr.e_type ==ET_EXEC || ehdr.e_type ==ET_REL || -is_vdso_map (dso->short_name) || +dso__is_vdso (dso) ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL );
tools/perf/util/vdso.c +8 -3
@@ -33,7 +33,7 @@ static struct vdso_info *vdso_info__new(void)static const struct vdso_info vdso_info_init = { .vdso = { .temp_file_name =VDSO__TEMP_FILE_NAME , - .dso_name =VDSO__MAP_NAME , + .dso_name =DSO__NAME_VDSO , }, };
@@ -147,7 +147,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!vdso_info)return NULL ; - dso =dsos__find (&machine->user_dsos,VDSO__MAP_NAME , true); + dso =dsos__find (&machine->user_dsos,DSO__NAME_VDSO , true);if (!dso) {char *file;
@@ -155,8 +155,13 @@ struct dso *vdso__dso_findnew(struct machine *machine)if (!file)return NULL ; - dso =vdso__new (machine,VDSO__MAP_NAME , file); + dso =vdso__new (machine,DSO__NAME_VDSO , file); }return dso; } + +bool dso__is_vdso (struct dso *dso) +{ +return !strcmp (dso->short_name,DSO__NAME_VDSO ); +}
tools/perf/util/vdso.h +6 -0
@@ -7,11 +7,17 @@#define VDSO__MAP_NAME "[vdso]" +#define DSO__NAME_VDSO "[vdso]" +static inline bool is_vdso_map (const char *filename) {return !strcmp (filename,VDSO__MAP_NAME ); } +struct dso ; + +bool dso__is_vdso (struct dso *dso); +struct machine ;struct dso *vdso__dso_findnew (struct machine *machine);
Adrian Hunter
reviewerPATCH 49/52 perf tools: Build programs to copy 32-bit compatibility VDSOs
In reply to Adrian Hunterperf 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 | 37 +++++++++++++++++++++++--- tools/perf/config/Makefile | 21 +++++++++++++++ tools/perf/config/Makefile.arch | 8 ++++++ tools/perf/perf-read-vdso.c | 59 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 tools/perf/perf-read-vdso.c
tools/perf/Makefile.perf +33 -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)
@@ -732,6 +743,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 + $(QUIET_CC)$(CC) -m32 -Wall -Werror -o $@ perf-read-vdso.c +endif + +ifndef NO_PERF_READ_VDSOX32 +$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c + $(QUIET_CC)$(CC) -mx32 -Wall -Werror -o $@ perf-read-vdso.c +endif + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -876,6 +897,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 +957,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 +21 -0
@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq (${IS_64_BIT}, 1) + ifndef NO_PERF_READ_VDSO32 + CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSO32 := 1 + endif + endif + ifneq (${IS_X86_64}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + ifndef NO_PERF_READ_VDSOX32 + CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 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/perf-read-vdso.c new file +59 -0
59 lines not on this page · raw message
Signature · 1 line
1.8.3.2
Re: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs
On Tue, Jul 22, 2014 at 04:17:58PM +0300, Adrian Hunter wrote:
SNIP
Quoted 13 lines
index 1f67aa0..45ab040 100644
tools/perf/config/Makefile +6
-0@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq (${IS_64_BIT}, 1) + ifndef NO_PERF_READ_VDSO32 + CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSO32 := 1 + endif
tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622
Quoted 10 lines
tools/perf/config/Makefile +10
-0+ endif + ifneq (${IS_X86_64}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + ifndef NO_PERF_READ_VDSOX32 + CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + endif
please move those check into feature config code under config/features/..
SNIP
Quoted 27 lines
tools/perf/config/Makefile +26
-0+++ b/tools/perf/perf-read-vdso.c@@ -0,0 +1,59 @@ +#include <stdio.h> +#include <string.h> + +#define VDSO__MAP_NAME "[vdso]" + +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)
tools/perf/config/Makefile line 35
Quoted 10 lines
tools/perf/config/Makefile +10
-0+ continue; + + if (!strncmp(&line[m], VDSO__MAP_NAME, + sizeof(VDSO__MAP_NAME) - 1)) + found = 1; + } + + fclose(maps); + return !found; +}
hum, any easy way to use/share find_vdso_map from vdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple
jirka
Adrian Hunter
reviewerRe: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs
Quoted 21 lines · Jiri Olsa
On Tue, Jul 22, 2014 at 04:17:58PM +0300, Adrian Hunter wrote:
SNIP
Quoted 17 lines
index 1f67aa0..45ab040 100644
tools/perf/config/Makefile +10
-0@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq (${IS_64_BIT}, 1) + ifndef NO_PERF_READ_VDSO32 + CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSO32 := 1 + endif + endif + ifneq (${IS_X86_64}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif
Quoted 8 lines
tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622
Quoted 6 lines
tools/perf/config/Makefile +6
-0+ ifndef NO_PERF_READ_VDSOX32 + CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + endifplease move those check into feature config code under config/features/..
I will look at doing that.
Quoted 36 lines
SNIP
Quoted 33 lines
+++
b/tools/perf/perf-read-vdso.ctools/perf/config/Makefile +31
-0@@ -0,0 +1,59 @@ +#include <stdio.h> +#include <string.h> + +#define VDSO__MAP_NAME "[vdso]" + +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; + }
Quoted 8 lines
tools/perf/config/Makefile line 35
Quoted 4 lines
tools/perf/config/Makefile +4
-0+ + fclose(maps); + return !found; +}hum, any easy way to use/share
find_vdso_mapfromvdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple
Would have to create another source file and include it. I am not sure it is worth it. Maybe Arnaldo can decide?
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs
Em Wed, Jul 23, 2014 at 04:55:03PM +0300, Adrian Hunter escreveu:
Quoted 31 lines · Jiri Olsa
Quoted 21 lines · Adrian Hunter
SNIP
Quoted 17 lines
index 1f67aa0..45ab040 100644
tools/perf/config/Makefile +10
-0@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq (${IS_64_BIT}, 1) + ifndef NO_PERF_READ_VDSO32 + CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSO32 := 1 + endif + endif + ifneq (${IS_X86_64}, 1) + NO_PERF_READ_VDSOX32 := 1 + endifQuoted 8 lines
tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622
Quoted 6 lines
tools/perf/config/Makefile +6
-0+ ifndef NO_PERF_READ_VDSOX32 + CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0) + ifneq (${CAN_DO}, 1) + NO_PERF_READ_VDSOX32 := 1 + endif + endifplease move those check into feature config code under config/features/..
Quoted 1 line
I will look at doing that.
Ok, probably this can be done in a follow up patch, Jiri?
Quoted 43 lines
Quoted 34 lines
SNIP
Quoted 33 lines
+++
b/tools/perf/perf-read-vdso.ctools/perf/config/Makefile +31
-0@@ -0,0 +1,59 @@ +#include <stdio.h> +#include <string.h> + +#define VDSO__MAP_NAME "[vdso]" + +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; + }Quoted 8 lines
tools/perf/config/Makefile line 35
Quoted 4 lines
tools/perf/config/Makefile +4
-0+ + fclose(maps); + return !found; +}hum, any easy way to use/share
find_vdso_mapfromvdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple
Quoted 2 lines
Would have to create another source file and include it. I am not sure it is worth it. Maybe Arnaldo can decide?
I think it is, either do direct sourcing with #include or add it to a linking list for the binaries that use it.
- Arnaldo
Adrian Hunter
reviewerPATCH 1/1 perf tools: Build programs to copy 32-bit compatibility VDSOs
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.
---
V2:
Move -m32/-mx32 checks under config/features/
Put duplicated find_vdso_map() function into a separate source file and #include it
Support static build of perf-read-vdso32 and perf-read-vdsox32
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)
@@ -305,6 +316,7 @@ LIB_H += util/data.h LIB_H += util/kvm-stat.h LIB_H += util/thread-stack.h LIB_H += util/db-export.h +LIB_H += util/find-vdso-map.c LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o
@@ -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 $(findstring -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 $(findstring -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
@@ -211,7 +211,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
@@ -604,6 +606,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
@@ -145,6 +147,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.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH] perf tools: Build programs to copy 32-bit compatibility VDSOs
Em Thu, Jul 24, 2014 at 01:05:54PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
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.
Signed-off-by Adrian Hunter <[email protected]>---
Quoted 8 lines
V2:
Move -m32/-mx32 checks under config/features/Put duplicated
find_vdso_map()function into a separate source file and #include itSupport static build of perf-read-vdso32 and perf-read-vdsox32
Haven't tested, but from quick look seems OK, Jiri?
- Arnaldo
Quoted 330 lines
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.ctools/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)@@ -305,6 +316,7 @@ LIB_H += util/data.h LIB_H += util/kvm-stat.h LIB_H += util/thread-stack.h LIB_H += util/db-export.h +LIB_H += util/find-vdso-map.c LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o@@ -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 $(findstring -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 $(findstring -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@@ -211,7 +211,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@@ -604,6 +606,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_dirtools/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) +endiftools/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@@ -145,6 +147,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.8.3.2
Adrian Hunter
reviewerPATCH 50/52 perf tools: Add dso__type()
In reply to Adrian Hunterdso__type() determines wheather a dso is 32-bit,
x32 (32-bit with 64-bit registers) or 64-bit.dso__type() will be used to determine the VDSO
a program maps.
--- tools/perf/util/dso.c | 11 +++++++++++ tools/perf/util/dso.h | 10 ++++++++++ tools/perf/util/symbol-elf.c | 33 +++++++++++++++++++++++++++++++++ tools/perf/util/symbol-minimal.c | 21 +++++++++++++++++++++ tools/perf/util/symbol.h | 2 ++ 5 files changed, 77 insertions(+)
tools/perf/util/dso.c +11 -0
@@ -940,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)return ret; } + +enum dso_type dso__type (struct dso *dso,struct machine *machine) +{ +int fd; + + fd =dso__data_fd (dso, machine); +if (fd <0 ) +return DSO__TYPE_UNKNOWN ; + +return dso__type_fd (fd); +}
tools/perf/util/dso.h +10 -0
@@ -5,6 +5,7 @@#include <linux/rbtree.h> #include <stdbool.h> #include <linux/types.h> +#include <linux/bitops.h> #include "map.h" #include "build-id.h"
@@ -50,6 +51,13 @@ enum dso_data_status_seen { DSO_DATA_STATUS_SEEN_ITRACE, }; +enum dso_type { +DSO__TYPE_UNKNOWN , +DSO__TYPE_64BIT , +DSO__TYPE_32BIT , +DSO__TYPE_X32BIT , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -246,4 +254,6 @@ static inline bool dso__is_kcore(struct dso *dso)void dso__free_a2l (struct dso *dso); +enum dso_type dso__type (struct dso *dso,struct machine *machine); +#endif /* __PERF_DSO */
tools/perf/util/symbol-elf.c +33 -0
@@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,return err; } +enum dso_type dso__type_fd (int fd) +{ +enum dso_type dso_type =DSO__TYPE_UNKNOWN ; +GElf_Ehdr ehdr; +Elf_Kind ek; +Elf *elf; + + elf =elf_begin (fd,PERF_ELF_C_READ_MMAP ,NULL ); +if (elf ==NULL ) + goto out; + + ek =elf_kind (elf); +if (ek !=ELF_K_ELF ) + goto out_end; + +if (gelf_getclass (elf) ==ELFCLASS64 ) { + dso_type =DSO__TYPE_64BIT ; + goto out_end; + } + +if (gelf_getehdr (elf, &ehdr) ==NULL ) + goto out_end; + +if (ehdr.e_machine ==EM_X86_64 ) + dso_type =DSO__TYPE_X32BIT ; +else + dso_type =DSO__TYPE_32BIT ; +out_end: +elf_end (elf); +out: +return dso_type; +} +static int copy_bytes (int from,off_t from_offs,int to,off_t to_offs,u64 len) {ssize_t r;
tools/perf/util/symbol-minimal.c +21 -0
@@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd)return e_ident[EI_CLASS ] ==ELFCLASS64 ; } +enum dso_type dso__type_fd (int fd) +{ +Elf64_Ehdr ehdr; +int ret; + + ret =fd__is_64_bit (fd); +if (ret <0 ) +return DSO__TYPE_UNKNOWN ; + +if (ret) +return DSO__TYPE_64BIT ; + +if (readn (fd, &ehdr,sizeof (ehdr)) !=sizeof (ehdr)) +return DSO__TYPE_UNKNOWN ; + +if (ehdr.e_machine ==EM_X86_64 ) +return DSO__TYPE_X32BIT ; + +return DSO__TYPE_32BIT ; +} + int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused,
tools/perf/util/symbol.h +2 -0
@@ -244,6 +244,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,struct symbol *dso__first_symbol (struct dso *dso,enum map_type type);struct symbol *dso__next_symbol (struct symbol *sym); +enum dso_type dso__type_fd (int fd); +int filename__read_build_id (const char *filename,void *bf,size_t size);int sysfs__read_build_id (const char *filename,void *bf,size_t size); int modules__parse(const char *filename, void *arg,
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add dso__type()
perf tools: Add dso__type()
Commit-ID: 2b5b8bb27b9ec899cfba686dabec113ea0d4cbda Gitweb: http://git.kernel.org/tip/2b5b8bb27b9ec899cfba686dabec113ea0d4cbda Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:17:59 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:36:36 -0300
perf tools: Add dso__type()
dso__type() determines wheather a dso is 32-bit, x32 (32-bit with 64-bit registers) or 64-bit.
dso__type() will be used to determine the VDSO a program maps.
--- tools/perf/util/dso.c | 11 +++++++++++ tools/perf/util/dso.h | 10 ++++++++++ tools/perf/util/symbol-elf.c | 33 +++++++++++++++++++++++++++++++++ tools/perf/util/symbol-minimal.c | 21 +++++++++++++++++++++ tools/perf/util/symbol.h | 2 ++ 5 files changed, 77 insertions(+)
tools/perf/util/dso.c +11 -0
@@ -940,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)return ret; } + +enum dso_type dso__type (struct dso *dso,struct machine *machine) +{ +int fd; + + fd =dso__data_fd (dso, machine); +if (fd <0 ) +return DSO__TYPE_UNKNOWN ; + +return dso__type_fd (fd); +}
tools/perf/util/dso.h +10 -0
@@ -5,6 +5,7 @@#include <linux/rbtree.h> #include <stdbool.h> #include <linux/types.h> +#include <linux/bitops.h> #include "map.h" #include "build-id.h"
@@ -50,6 +51,13 @@ enum dso_data_status_seen { DSO_DATA_STATUS_SEEN_ITRACE, }; +enum dso_type { +DSO__TYPE_UNKNOWN , +DSO__TYPE_64BIT , +DSO__TYPE_32BIT , +DSO__TYPE_X32BIT , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -245,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)void dso__free_a2l (struct dso *dso); +enum dso_type dso__type (struct dso *dso,struct machine *machine); +#endif /* __PERF_DSO */
tools/perf/util/symbol-elf.c +33 -0
@@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,return err; } +enum dso_type dso__type_fd (int fd) +{ +enum dso_type dso_type =DSO__TYPE_UNKNOWN ; +GElf_Ehdr ehdr; +Elf_Kind ek; +Elf *elf; + + elf =elf_begin (fd,PERF_ELF_C_READ_MMAP ,NULL ); +if (elf ==NULL ) + goto out; + + ek =elf_kind (elf); +if (ek !=ELF_K_ELF ) + goto out_end; + +if (gelf_getclass (elf) ==ELFCLASS64 ) { + dso_type =DSO__TYPE_64BIT ; + goto out_end; + } + +if (gelf_getehdr (elf, &ehdr) ==NULL ) + goto out_end; + +if (ehdr.e_machine ==EM_X86_64 ) + dso_type =DSO__TYPE_X32BIT ; +else + dso_type =DSO__TYPE_32BIT ; +out_end: +elf_end (elf); +out: +return dso_type; +} +static int copy_bytes (int from,off_t from_offs,int to,off_t to_offs,u64 len) {ssize_t r;
tools/perf/util/symbol-minimal.c +21 -0
@@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd)return e_ident[EI_CLASS ] ==ELFCLASS64 ; } +enum dso_type dso__type_fd (int fd) +{ +Elf64_Ehdr ehdr; +int ret; + + ret =fd__is_64_bit (fd); +if (ret <0 ) +return DSO__TYPE_UNKNOWN ; + +if (ret) +return DSO__TYPE_64BIT ; + +if (readn (fd, &ehdr,sizeof (ehdr)) !=sizeof (ehdr)) +return DSO__TYPE_UNKNOWN ; + +if (ehdr.e_machine ==EM_X86_64 ) +return DSO__TYPE_X32BIT ; + +return DSO__TYPE_32BIT ; +} + int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused,
tools/perf/util/symbol.h +2 -0
@@ -243,6 +243,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,struct symbol *dso__first_symbol (struct dso *dso,enum map_type type);struct symbol *dso__next_symbol (struct symbol *sym); +enum dso_type dso__type_fd (int fd); +int filename__read_build_id (const char *filename,void *bf,size_t size);int sysfs__read_build_id (const char *filename,void *bf,size_t size); int modules__parse(const char *filename, void *arg,
Adrian Hunter
reviewerPATCH 51/52 perf tools: Add thread parameter to vdso__dso_findnew()
In reply to Adrian HunterThe thread will be needed to determine the VDSO
type.
--- tools/perf/util/machine.c | 4 ++-- tools/perf/util/map.c | 4 ++-- tools/perf/util/map.h | 3 ++- tools/perf/util/vdso.c | 3 ++- tools/perf/util/vdso.h | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-)
tools/perf/util/machine.c +2 -2
@@ -1133,7 +1133,7 @@ int machine__process_mmap2_event(struct machine *machine, event->mmap2.ino_generation, event->mmap2.prot, event->mmap2.flags, - event->mmap2.filename, type); + event->mmap2.filename, type, thread);if (map ==NULL ) goto out_problem;
@@ -1180,7 +1180,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event event->mmap.len, event->mmap.pgoff, event->mmap.pid,0 ,0 ,0 ,0 ,0 ,0 , event->mmap.filename, - type); + type, thread);if (map ==NULL ) goto out_problem;
tools/perf/util/map.c +2 -2
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename, -enum map_type type) +enum map_type type,struct thread *thread) {struct map *map =malloc (sizeof (*map));
@@ -174,7 +174,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,if (vdso) { pgoff =0 ; - dso =vdso__dso_findnew (machine); + dso =vdso__dso_findnew (machine, thread); }else dso =__dsos__findnew (&machine->user_dsos, filename);
tools/perf/util/map.h +2 -1
@@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);u64 map__objdump_2mem (struct map *map,u64 ip);struct symbol ; +struct thread ;/* map__for_each_symbol - iterate over the symbols in the given map *
@@ -122,7 +123,7 @@ void map__init(struct map *map, enum map_type type,struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags, -char *filename,enum map_type type); +char *filename,enum map_type type,struct thread *thread);struct map *map__new2 (u64 start,struct dso *dso,enum map_type type);void map__delete (struct map *map);struct map *map__clone (struct map *map);
tools/perf/util/vdso.c +2 -1
@@ -135,7 +135,8 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,return dso; } -struct dso *vdso__dso_findnew (struct machine *machine) +struct dso *vdso__dso_findnew (struct machine *machine, +struct thread *thread__maybe_unused ) {struct vdso_info *vdso_info;struct dso *dso;
tools/perf/util/vdso.h +2 -1
@@ -19,8 +19,9 @@ struct dso;bool dso__is_vdso (struct dso *dso);struct machine ; +struct thread ; -struct dso *vdso__dso_findnew (struct machine *machine); +struct dso *vdso__dso_findnew (struct machine *machine,struct thread *thread);void vdso__exit (struct machine *machine);#endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add thread parameter to vdso__dso_findnew()
perf tools: Add thread parameter to vdso__dso_findnew()
Commit-ID: 5835eddab6f162b38e9a6a5447a2c3a128637956 Gitweb: http://git.kernel.org/tip/5835eddab6f162b38e9a6a5447a2c3a128637956 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 22 Jul 2014 16:18:00 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 23 Jul 2014 17:37:26 -0300
perf tools: Add thread parameter to vdso__dso_findnew()
The thread will be needed to determine the VDSO type.
--- tools/perf/util/machine.c | 4 ++-- tools/perf/util/map.c | 4 ++-- tools/perf/util/map.h | 3 ++- tools/perf/util/vdso.c | 3 ++- tools/perf/util/vdso.h | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-)
tools/perf/util/machine.c +2 -2
@@ -1106,7 +1106,7 @@ int machine__process_mmap2_event(struct machine *machine, event->mmap2.ino_generation, event->mmap2.prot, event->mmap2.flags, - event->mmap2.filename, type); + event->mmap2.filename, type, thread);if (map ==NULL ) goto out_problem;
@@ -1153,7 +1153,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event event->mmap.len, event->mmap.pgoff, event->mmap.pid,0 ,0 ,0 ,0 ,0 ,0 , event->mmap.filename, - type); + type, thread);if (map ==NULL ) goto out_problem;
tools/perf/util/map.c +2 -2
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename, -enum map_type type) +enum map_type type,struct thread *thread) {struct map *map =malloc (sizeof (*map));
@@ -174,7 +174,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,if (vdso) { pgoff =0 ; - dso =vdso__dso_findnew (machine); + dso =vdso__dso_findnew (machine, thread); }else dso =__dsos__findnew (&machine->user_dsos, filename);
tools/perf/util/map.h +2 -1
@@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);u64 map__objdump_2mem (struct map *map,u64 ip);struct symbol ; +struct thread ;/* map__for_each_symbol - iterate over the symbols in the given map *
@@ -122,7 +123,7 @@ void map__init(struct map *map, enum map_type type,struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags, -char *filename,enum map_type type); +char *filename,enum map_type type,struct thread *thread);struct map *map__new2 (u64 start,struct dso *dso,enum map_type type);void map__delete (struct map *map);struct map *map__clone (struct map *map);
tools/perf/util/vdso.c +2 -1
@@ -135,7 +135,8 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,return dso; } -struct dso *vdso__dso_findnew (struct machine *machine) +struct dso *vdso__dso_findnew (struct machine *machine, +struct thread *thread__maybe_unused ) {struct vdso_info *vdso_info;struct dso *dso;
tools/perf/util/vdso.h +2 -1
@@ -19,8 +19,9 @@ struct dso;bool dso__is_vdso (struct dso *dso);struct machine ; +struct thread ; -struct dso *vdso__dso_findnew (struct machine *machine); +struct dso *vdso__dso_findnew (struct machine *machine,struct thread *thread);void vdso__exit (struct machine *machine);#endif /* __PERF_VDSO__ */
Adrian Hunter
reviewerPATCH 52/52 perf tools: Add support for 32-bit compatibility VDSOs
In reply to Adrian Hunter'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"
@@ -22,10 +23,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 )
@@ -35,6 +41,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));
@@ -117,6 +135,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->vdso.temp_file_name); +if (vdso_info->vdsox32.found) +unlink (vdso_info->vdso.temp_file_name); +#endif zfree (&machine->vdso_info); }
@@ -135,6 +159,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 ) {
@@ -148,6 +309,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;
@@ -164,5 +330,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.8.3.2
Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
Quoted 4 lines · Adrian Hunter
'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.
SNIP
Quoted 13 lines
tools/perf/util/vdso.c +6
-0if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); +#if BITS_PER_LONG ==64 +if (vdso_info->vdso32.found) +unlink (vdso_info->vdso.temp_file_name); +if (vdso_info->vdsox32.found) +unlink (vdso_info->vdso.temp_file_name); +#endif zfree (&machine->vdso_info); }
tools/perf/util/vdso.c static struct dso *vdso__new(struct machine *machine, const char *short_name, · line 162
Quoted 4 lines
tools/perf/util/vdso.c +1
-0@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,return dso; } +#if BITS_PER_LONG ==64
Does this define mean all 64 archs? Do we want other than x86 in here? (all of its instances)
jirka
Quoted 20 lines
tools/perf/util/vdso.c +20
-0+ +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; +}
SNIP
Adrian Hunter
reviewerRe: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
Quoted 24 lines · Jiri Olsa
Quoted 4 lines · Adrian Hunter
'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.
SNIP
Quoted 16 lines
tools/perf/util/vdso.c +6
-0if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); +#if BITS_PER_LONG ==64 +if (vdso_info->vdso32.found) +unlink (vdso_info->vdso.temp_file_name); +if (vdso_info->vdsox32.found) +unlink (vdso_info->vdso.temp_file_name); +#endif zfree (&machine->vdso_info); }@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,return dso; }
Quoted 4 lines
Review static struct dso *vdso__new(struct machine *machine, const char *short_name, · line 162
Quoted 1 line
(quoted diff) +1
-0+#if BITS_PER_LONG == 64Does this define mean all 64 archs? Do we want other than x86 in here? (all of its instances)
Any 64-bit arch can have 32-bit compatibility VDSOs. This should be OK for other arches too.
Quoted 27 lines
jirka
Quoted 20 lines
tools/perf/util/vdso.c +20
-0+ +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; +}SNIP
Namhyung Kim
maintainerRe: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
Hi Adrian,
Quoted 10 lines · Adrian Hunter
Quoted 9 lines · Jiri Olsa
Quoted 4 lines · Adrian Hunter
'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.
SNIP
Quoted 1 line
Quoted 8 lines
Quoted 8 lines
tools/perf/util/vdso.c void vdso__exit(struct machine *machine) · line 143
Quoted 8 lines
tools/perf/util/vdso.c +6
-0if (vdso_info->vdso.found)unlink (vdso_info->vdso.temp_file_name); +#if BITS_PER_LONG ==64 +if (vdso_info->vdso32.found) +unlink (vdso_info->vdso.temp_file_name); +if (vdso_info->vdsox32.found) +unlink (vdso_info->vdso.temp_file_name); +#endif
Looks like copy-and-paste errors. Did you mean below?
#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
^^^
Thanks,
Namhyung
Adrian Hunter
reviewerPATCH v2 52/52 perf tools: Add support for 32-bit compatibility VDSOs
'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.
---
V2:
Fix copy-and-paste errors spotted by Namhyung (Thank you!)
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"
@@ -22,10 +23,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 )
@@ -35,6 +41,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));
@@ -117,6 +135,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); }
@@ -135,6 +159,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 ) {
@@ -148,6 +309,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;
@@ -164,5 +330,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.8.3.2
Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
In reply to Adrian HunterQuoted 9 lines · Adrian Hunter
'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.
Quoted 7 lines
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]".
heya,
I reviewed vdso changes:
perf tools: Pass machine to vdso__dso_findnew() perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew() perf tools: Add support for 32-bit compatibility VDSOs
apart from small comments for above patches:
Arnaldo,
I can handle those if needed, please let me know
thanks,
jirka
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
Em Wed, Jul 23, 2014 at 03:05:25PM +0200, Jiri Olsa escreveu:
Quoted 31 lines · Adrian Hunter
Quoted 9 lines
'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.
Quoted 7 lines
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]".
heya,
I reviewed vdso changes:perf tools: Pass machine to
vdso__dso_findnew()perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Addvdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Adddso__type()
perf tools: Add thread parameter tovdso__dso_findnew()perf tools: Add support for 32-bit compatibility VDSOs
Quoted 6 lines
apart from small comments for above patches:
Acked-by Jiri Olsa <[email protected]>Arnaldo,
I can handle those if needed, please let me know
I can take those after I go thru them, will add your acked-by. But since you sayd "I reviewed", wouldn't it be better to s/Acked-by/Reviewed-by/g ?
- Arnaldo
Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs
Quoted 34 lines · Arnaldo Carvalho de Melo
Em Wed, Jul 23, 2014 at 03:05:25PM +0200, Jiri Olsa escreveu:
Quoted 33 lines · Adrian Hunter
Quoted 9 lines
'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.
Quoted 7 lines
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]".
heya,
I reviewed vdso changes:perf tools: Pass machine to
vdso__dso_findnew()perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Addvdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Adddso__type()
perf tools: Add thread parameter tovdso__dso_findnew()perf tools: Add support for 32-bit compatibility VDSOsapart from small comments for above patches:
Quoted 7 lines
Quoted 4 lines
Acked-by Jiri Olsa <[email protected]>Arnaldo,
I can handle those if needed, please let me knowI can take those after I go thru them, will add your acked-by. But since you sayd "I reviewed", wouldn't it be better to s/Acked-by/Reviewed-by/g
ok, both's fine with me
jirka