perf tools: Yet more preparation for call graph from Intel BTS
Adrian Hunter
reviewercover perf tools: Yet 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 (31):
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 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 evlist: Add 'system_wide' option
perf evlist: Add perf_evlist__set_tracking_event()
perf tools: Add id index
perf pmu: Let pmu's with no events show up on perf list
perf session: Add perf_session__deliver_synth_event()
perf evlist: Add perf_evlist__enable_event_idx()
perf session: Add perf_session__peek_event()
perf tools: Add a thread stack for synthesizing call chains
perf script: Allow callchains if any event samples them
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: Build programs to copy 32-bit compatibility VDSOs
perf tools: Add support for 32-bit compatibility VDSOs
tools/perf/.gitignore | 1 + tools/perf/Makefile.perf | 46 +- tools/perf/builtin-inject.c | 1 + tools/perf/builtin-script.c | 29 +- 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/pmu.c | 2 +- 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.h | 1 + tools/perf/util/event.c | 7 +- tools/perf/util/event.h | 43 ++ tools/perf/util/evlist.c | 135 +++- tools/perf/util/evlist.h | 5 + tools/perf/util/evsel.c | 34 +- tools/perf/util/evsel.h | 6 + tools/perf/util/machine.c | 53 +- tools/perf/util/machine.h | 22 + 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 +- tools/perf/util/record.c | 2 +- .../perf/util/scripting-engines/trace-event-perl.c | 6 + .../util/scripting-engines/trace-event-python.c | 511 +++++++++++++-- tools/perf/util/session.c | 215 ++++++- tools/perf/util/session.h | 20 + tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.h | 1 + tools/perf/util/thread-stack.c | 690 +++++++++++++++++++++ tools/perf/util/thread-stack.h | 79 +++ tools/perf/util/thread.c | 27 +- tools/perf/util/thread.h | 14 +- tools/perf/util/tool.h | 3 +- tools/perf/util/trace-event-scripting.c | 7 + tools/perf/util/trace-event.h | 1 + tools/perf/util/vdso.c | 170 ++++- tools/perf/util/vdso.h | 4 +- 45 files changed, 3505 insertions(+), 135 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/31 perf tools: Identify which comms are from exec
--- 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
@@ -404,11 +404,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
@@ -42,7 +42,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;
@@ -81,19 +81,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
@@ -38,9 +38,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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Identify which comms are from exec
perf tools: Identify which comms are from exec
Commit-ID: 65de51f93ebf9305ec011da59c0b5fe29429d1b9 Gitweb: http://git.kernel.org/tip/65de51f93ebf9305ec011da59c0b5fe29429d1b9 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:44 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:23:08 -0300
perf tools: Identify which comms are from exec
For grouping together all the data from a single execution, which is needed for pairing calls and returns e.g. any outstanding calls when a process exec's will never return.
--- 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 = 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
@@ -404,11 +404,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
@@ -42,7 +42,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;
@@ -81,19 +81,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
@@ -38,9 +38,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);
Adrian Hunter
reviewerPATCH 2/31 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
@@ -31,6 +31,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 )
@@ -179,6 +180,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;
@@ -398,6 +412,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) {
@@ -406,6 +429,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
@@ -26,6 +26,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;
@@ -47,6 +48,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);
@@ -88,6 +91,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
@@ -66,6 +66,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) {
@@ -91,6 +110,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); } }
@@ -1005,8 +1025,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,switch (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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Add machine__thread_exec_comm()
perf machine: Add machine__thread_exec_comm()
Commit-ID: cfe1c41405fe9a559f8b3c24c904b2bb42d4a6e8 Gitweb: http://git.kernel.org/tip/cfe1c41405fe9a559f8b3c24c904b2bb42d4a6e8 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:45 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:23:21 -0300
perf machine: Add machine__thread_exec_comm()
Add 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
@@ -31,6 +31,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 )
@@ -179,6 +180,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;
@@ -398,6 +412,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) {
@@ -406,6 +429,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
@@ -26,6 +26,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;
@@ -47,6 +48,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);
@@ -88,6 +91,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) {
@@ -90,6 +109,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); } }
@@ -866,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,switch (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 :/*
Adrian Hunter
reviewerPATCH 3/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf symbols: Fix missing label symbols
perf symbols: Fix missing label symbols
Commit-ID: f247fb8191aa7f10d3f6c987e8ef0853ae789a02 Gitweb: http://git.kernel.org/tip/f247fb8191aa7f10d3f6c987e8ef0853ae789a02 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:46 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:20:39 -0300
perf symbols: Fix missing label symbols
Label 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;
Adrian Hunter
reviewerPATCH 4/31 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
@@ -32,6 +32,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 )
@@ -1559,3 +1560,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,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
@@ -36,6 +36,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;pid_t *current_tid; };
@@ -46,6 +47,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 5/31 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 6/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Let default config be defined for a PMU
perf tools: Let default config be defined for a PMU
Commit-ID: dc0a6202421170a6d8d2c6f5176575b3f60e0f85 Gitweb: http://git.kernel.org/tip/dc0a6202421170a6d8d2c6f5176575b3f60e0f85 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:49 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 17 Sep 2014 17:08:08 -0300
perf tools: Let default config be defined for a PMU
This 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
@@ -643,7 +643,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;/* HEAD struct perf_pmu_format -> list */ struct list_head aliases;/* HEAD struct perf_pmu_alias -> list */
@@ -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 */
Adrian Hunter
reviewerPATCH 7/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add perf_pmu__scan_file()
perf tools: Add perf_pmu__scan_file()
Commit-ID: 7d4bdab5a441772bfc757d7f9eea9465ec5de0ec Gitweb: http://git.kernel.org/tip/7d4bdab5a441772bfc757d7f9eea9465ec5de0ec Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:50 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 17 Sep 2014 17:08:09 -0300
perf tools: Add perf_pmu__scan_file()
Add 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);
Adrian Hunter
reviewerPATCH 8/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Add 'system_wide' option
perf evlist: Add 'system_wide' option
Commit-ID: bf8e8f4b832972c76d64ab2e2837a48397144887 Gitweb: http://git.kernel.org/tip/bf8e8f4b832972c76d64ab2e2837a48397144887 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:51 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:21:18 -0300
perf evlist: Add 'system_wide' option
Add 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
@@ -695,6 +695,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) {
@@ -713,6 +717,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),
@@ -743,6 +750,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 ;
@@ -787,6 +797,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));
@@ -875,6 +888,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++) {
@@ -997,13 +1013,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) {
@@ -1027,10 +1048,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);
@@ -1103,7 +1124,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;
Adrian Hunter
reviewerPATCH 9/31 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 | 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Add perf_evlist__set_tracking_event( )
perf evlist: Add perf_evlist__set_tracking_event()
Commit-ID: 60b0896cc35243f515eda2085f9897e296177e45 Gitweb: http://git.kernel.org/tip/60b0896cc35243f515eda2085f9897e296177e45 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:52 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:21:32 -0300
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.
--- 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);
@@ -1295,3 +1296,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
@@ -115,7 +115,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 ; }
Adrian Hunter
reviewerPATCH 10/31 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
@@ -442,6 +442,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;
@@ -677,9 +693,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 11/31 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 12/31 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
@@ -1063,6 +1063,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 13/31 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
@@ -355,6 +355,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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Add perf_evlist__enable_event_idx()
perf evlist: Add perf_evlist__enable_event_idx()
Commit-ID: 1c65056c547141a0cb52fb8e6056f63524d2bbf2 Gitweb: http://git.kernel.org/tip/1c65056c547141a0cb52fb8e6056f63524d2bbf2 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:56 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:23:48 -0300
perf evlist: Add perf_evlist__enable_event_idx()
Add 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
@@ -355,6 +355,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);
Adrian Hunter
reviewerPATCH 14/31 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
@@ -1086,6 +1086,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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf session: Add perf_session__peek_event()
perf session: Add perf_session__peek_event()
Commit-ID: 5a52f33adf02a3e5eafdc1e597a3fe172e620bec Gitweb: http://git.kernel.org/tip/5a52f33adf02a3e5eafdc1e597a3fe172e620bec Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:57 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:21:44 -0300
perf session: Add perf_session__peek_event()
Add 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
@@ -897,6 +897,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
@@ -45,6 +45,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);
Adrian Hunter
reviewerPATCH 15/31 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 16/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf script: Allow callchains if any event samples them
perf script: Allow callchains if any event samples them
Commit-ID: 98526ee7229be8537373aebe037b74cac112d84b Gitweb: http://git.kernel.org/tip/98526ee7229be8537373aebe037b74cac112d84b Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:00:59 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:21:53 -0300
perf script: Allow callchains if any event samples them
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 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
Adrian Hunter
reviewerPATCH 17/31 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
@@ -101,6 +101,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
@@ -96,6 +96,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
@@ -39,6 +39,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 18/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf script python: Add helpers for calling Python objects
perf script python: Add helpers for calling Python objects
Commit-ID: a5563edfa1bd25d052d81f5ad7fe74ba71c3d44e Gitweb: http://git.kernel.org/tip/a5563edfa1bd25d052d81f5ad7fe74ba71c3d44e Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:01:01 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:22:01 -0300
perf script python: Add helpers for calling Python objects
The 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)
Adrian Hunter
reviewerPATCH 19/31 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 20/31 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 21/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add flags and insn_len to struct sample
perf tools: Add flags and insn_len to struct sample
Commit-ID: bf4939027decde7aaaf8b5dbeee70126d2822eb6 Gitweb: http://git.kernel.org/tip/bf4939027decde7aaaf8b5dbeee70126d2822eb6 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:01:04 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 13 Aug 2014 19:23:32 -0300
perf tools: Add 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
@@ -156,6 +156,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;
Adrian Hunter
reviewerPATCH 22/31 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 23/31 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 24/31 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 25/31 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 26/31 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 27/31 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 28/31 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 29/31 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
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add perf-with-kcore script
perf tools: Add perf-with-kcore script
Commit-ID: c501e90b4700e4f247ccdcf5ae81f9846a2ef5f9 Gitweb: http://git.kernel.org/tip/c501e90b4700e4f247ccdcf5ae81f9846a2ef5f9 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 31 Jul 2014 09:01:12 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 17 Sep 2014 17:08:08 -0300
perf tools: Add perf-with-kcore script
Decoding 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(-)
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))
@@ -878,6 +879,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'; \
@@ -923,7 +926,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
Adrian Hunter
reviewerPATCH 30/31 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
Adrian Hunter
reviewerPATCH 31/31 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
Arnaldo Carvalho de Melo
maintainerEm Thu, Jul 31, 2014 at 09:00:43AM +0300, Adrian Hunter escreveu:
Quoted 7 lines
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
Just FYI, did some processing today, what I picked I stashed on my tmp.perf/core branch, will continue.
But having something that actually uses all this stuff in 'perf test' is something I'm missing...
Things like using that set_tracking new API on a evlist with the sched_switch, using it to track, then switching it off after moving the tracking event to another event in the list, etc.
- Arnaldo
Adrian Hunter
reviewerQuoted 11 lines · Arnaldo Carvalho de Melo
Em Thu, Jul 31, 2014 at 09:00:43AM +0300, Adrian Hunter escreveu:
Quoted 7 lines
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
Just FYI, did some processing today, what I picked I stashed on my tmp.perf/core branch, will continue.
Thank you!
Quoted 7 lines
But having something that actually uses all this stuff in 'perf test' is something I'm missing...
Things like using that
set_trackingnew API on a evlist with thesched_switch, using it to track, then switching it off after moving the tracking event to another event in the list, etc.
I will look at that.