perf tools: Preparation for call graph from Intel BTS
Adrian Hunter
reviewercover perf tools: Preparation for call graph from Intel BTS
Hi
As we discussed here:
http://marc.info/?l=linux-kernel&m=140509286032125&w=4
here are a 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 (41):
perf tools: Fix the value used for unknown pids
perf tools: Fix map groups of threads with unknown pids perf script: Display PERF_RECORD_MISC_COMM_EXEC flag perf record: Select comm_exec flag if supported
perf tools: Identify which comms are from exec
perf tools: Add machine__thread_exec_comm()
perf tools: Fix missing kernel map load
perf tools: Fix missing label symbols
perf tools: Fix missing GNU IFUNC symbols
perf inject: Fix build id injection
perf tools: Fix appending a callchain from a previous sample perf tools: Fix leak of 'struct thread' on error path perf tools: Add machine__kernel_ip()
perf buildid-cache: Apply force option to copying kcore perf script: Improve srcline display for BTS
perf script: Do not print dangling '=>' for BTS
perf tools: Record whether a dso is 64-bit
perf tools: Record whether a dso has data
perf tools: Do not attempt to read data from kallsyms perf tools: Let a user specify a PMU event without any config terms perf tools: Let default config be defined for a PMU perf tools: Add perf_pmu__scan_file()
perf tools: Add dsos__hit_all()
perf tools: Add cpu to struct thread
perf tools: Add ability to record the current tid for each cpu perf tools: Add ability to iterate over a dso's symbols perf session: Flag if the event stream is entirely in memory perf evlist: Pass mmap parameters in a struct
perf tools: Add feature test for __sync_val_compare_and_swap perf tools: Add option macro OPT_CALLBACK_OPTARG
perf evlist: Add perf_evlist__set_tracking_event()
perf evsel: Add 'no_aux_samples' option
perf evsel: Add 'immediate' option
perf evlist: Add 'system_wide' option
perf tools: Add id index
perf pmu: Let pmu's with no events show up on perf list perf session: Add ability to skip 4GiB or more
perf session: Add perf_session__deliver_synth_event() perf tools: Allow TSC conversion on any arch
perf tools: Move rdtsc() function
perf evlist: Add perf_evlist__enable_event_idx()
tools/perf/Makefile.perf | 2 + tools/perf/arch/x86/util/tsc.c | 31 ++-- tools/perf/arch/x86/util/tsc.h | 3 - tools/perf/builtin-buildid-cache.c | 8 +- tools/perf/builtin-inject.c | 4 + tools/perf/builtin-sched.c | 12 +- tools/perf/builtin-script.c | 26 ++- tools/perf/config/Makefile | 6 + tools/perf/config/feature-checks/Makefile | 4 + tools/perf/config/feature-checks/test-all.c | 5 + .../feature-checks/test-sync-compare-and-swap.c | 14 ++ tools/perf/tests/perf-time-to-tsc.c | 12 +- tools/perf/tests/pmu.c | 2 +- tools/perf/util/callchain.c | 2 +- tools/perf/util/comm.c | 7 +- tools/perf/util/comm.h | 6 +- tools/perf/util/dso.c | 6 +- tools/perf/util/dso.h | 2 + tools/perf/util/event.c | 17 +- tools/perf/util/event.h | 15 ++ tools/perf/util/evlist.c | 184 +++++++++++++++---- tools/perf/util/evlist.h | 5 + tools/perf/util/evsel.c | 45 ++++- tools/perf/util/evsel.h | 6 + tools/perf/util/header.c | 41 +++++ tools/perf/util/header.h | 2 + tools/perf/util/machine.c | 127 +++++++++++++- tools/perf/util/machine.h | 26 +++ tools/perf/util/map.c | 14 ++ tools/perf/util/map.h | 1 + tools/perf/util/parse-events.c | 13 +- tools/perf/util/parse-events.y | 10 ++ tools/perf/util/parse-options.h | 5 + tools/perf/util/pmu.c | 92 ++++++++-- tools/perf/util/pmu.h | 13 +- tools/perf/util/record.c | 18 +- tools/perf/util/session.c | 194 +++++++++++++++++++-- tools/perf/util/session.h | 18 ++ tools/perf/util/symbol-elf.c | 8 +- tools/perf/util/symbol-minimal.c | 22 +++ tools/perf/util/symbol.c | 20 ++- tools/perf/util/symbol.h | 4 + tools/perf/util/thread.c | 68 +++++++- tools/perf/util/thread.h | 12 +- tools/perf/util/tool.h | 3 +- tools/perf/util/tsc.c | 30 ++++ tools/perf/util/tsc.h | 12 ++ 47 files changed, 1020 insertions(+), 157 deletions(-) create mode 100644 tools/perf/config/feature-checks/test-sync-compare-and-swap.c create mode 100644 tools/perf/util/tsc.c create mode 100644 tools/perf/util/tsc.h
Regards
Adrian
Adrian Hunter
reviewerPATCH 1/41 perf tools: Fix the value used for unknown pids
The value used for unknown pids cannot be zero because that is used by the "idle" task. Use -1 instead. Also handle the unknown pid case when creating map groups.
Note that, threads with an unknown pid should not occur because fork (or synthesized) events precede the thread's existence.
--- tools/perf/builtin-sched.c | 12 ++++++------ tools/perf/util/machine.c | 6 +++--- tools/perf/util/session.c | 5 +++-- tools/perf/util/thread.c | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-sched.c +6 -6
@@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched,return -1 ; } - sched_out =machine__findnew_thread (machine,0 , prev_pid); - sched_in =machine__findnew_thread (machine,0 , next_pid); + sched_out =machine__findnew_thread (machine,-1 , prev_pid); + sched_in =machine__findnew_thread (machine,-1 , next_pid); out_events =thread_atoms_search (&sched->atom_root, sched_out, &sched->cmp_pid);if (!out_events) {
@@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched, {const u32 pid =perf_evsel__intval (evsel, sample,"pid" );const u64 runtime =perf_evsel__intval (evsel, sample,"runtime" ); -struct thread *thread =machine__findnew_thread (machine,0 , pid); +struct thread *thread =machine__findnew_thread (machine,-1 , pid);struct work_atoms *atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid);u64 timestamp = sample->time;int cpu = sample->cpu;
@@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched,struct thread *wakee;u64 timestamp = sample->time; - wakee =machine__findnew_thread (machine,0 , pid); + wakee =machine__findnew_thread (machine,-1 , pid); atoms =thread_atoms_search (&sched->atom_root, wakee, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, wakee))
@@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,if (sched->profile_cpu ==-1 )return 0 ; - migrant =machine__findnew_thread (machine,0 , pid); + migrant =machine__findnew_thread (machine,-1 , pid); atoms =thread_atoms_search (&sched->atom_root, migrant, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, migrant))
@@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,return -1 ; } - sched_in =machine__findnew_thread (machine,0 , next_pid); + sched_in =machine__findnew_thread (machine,-1 , next_pid); sched->curr_thread[this_cpu] = sched_in;
tools/perf/util/machine.c +3 -3
@@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)return -ENOMEM ;if (pid !=HOST_KERNEL_ID ) { -struct thread *thread =machine__findnew_thread (machine,0 , +struct thread *thread =machine__findnew_thread (machine,-1 , pid);char comm[64 ];
@@ -286,7 +286,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* the full rbtree: */ if (machine->last_match && machine->last_match->tid == tid) { -if (pid && pid != machine->last_match->pid_) +if (pid !=-1 && pid != machine->last_match->pid_) machine->last_match->pid_ = pid;return machine->last_match; }
@@ -297,7 +297,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid && pid != th->pid_) +if (pid !=-1 && pid != th->pid_) th->pid_ = pid;return th; }
tools/perf/util/session.c +3 -2
@@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)struct thread *perf_session__findnew (struct perf_session *session,pid_t pid) { -return machine__findnew_thread (&session->machines.host,0 , pid); +return machine__findnew_thread (&session->machines.host,-1 , pid); }static struct thread *perf_session__register_idle_thread (struct perf_session *session) { -struct thread *thread =perf_session__findnew (session,0 ); +struct thread *thread; + thread =machine__findnew_thread (&session->machines.host,0 ,0 );if (thread ==NULL ||thread__set_comm (thread,"swapper" ,0 )) {pr_err ("problem inserting idle task.\n" ); thread =NULL ;
tools/perf/util/thread.c +1 -1
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)struct thread *leader;pid_t pid = thread->pid_; -if (pid == thread->tid) { +if (pid == thread->tid || pid ==-1 ) { thread->mg =map_groups__new (); }else { leader =machine__findnew_thread (machine, pid, pid);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Fix the value used for unknown pids
perf machine: Fix the value used for unknown pids
Commit-ID: 1fcb8768636d38cb6fdfeef83a5ee596c4bd9c56 Gitweb: http://git.kernel.org/tip/1fcb8768636d38cb6fdfeef83a5ee596c4bd9c56 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:25 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:33 -0300
perf machine: Fix the value used for unknown pids
The value used for unknown pids cannot be zero because that is used by the "idle" task.
Use -1 instead. Also handle the unknown pid case when creating map groups.
Note that, threads with an unknown pid should not occur because fork (or synthesized) events precede the thread's existence.
--- tools/perf/builtin-sched.c | 12 ++++++------ tools/perf/util/machine.c | 6 +++--- tools/perf/util/session.c | 5 +++-- tools/perf/util/thread.c | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-sched.c +6 -6
@@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched,return -1 ; } - sched_out =machine__findnew_thread (machine,0 , prev_pid); - sched_in =machine__findnew_thread (machine,0 , next_pid); + sched_out =machine__findnew_thread (machine,-1 , prev_pid); + sched_in =machine__findnew_thread (machine,-1 , next_pid); out_events =thread_atoms_search (&sched->atom_root, sched_out, &sched->cmp_pid);if (!out_events) {
@@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched, {const u32 pid =perf_evsel__intval (evsel, sample,"pid" );const u64 runtime =perf_evsel__intval (evsel, sample,"runtime" ); -struct thread *thread =machine__findnew_thread (machine,0 , pid); +struct thread *thread =machine__findnew_thread (machine,-1 , pid);struct work_atoms *atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid);u64 timestamp = sample->time;int cpu = sample->cpu;
@@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched,struct thread *wakee;u64 timestamp = sample->time; - wakee =machine__findnew_thread (machine,0 , pid); + wakee =machine__findnew_thread (machine,-1 , pid); atoms =thread_atoms_search (&sched->atom_root, wakee, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, wakee))
@@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,if (sched->profile_cpu ==-1 )return 0 ; - migrant =machine__findnew_thread (machine,0 , pid); + migrant =machine__findnew_thread (machine,-1 , pid); atoms =thread_atoms_search (&sched->atom_root, migrant, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, migrant))
@@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,return -1 ; } - sched_in =machine__findnew_thread (machine,0 , next_pid); + sched_in =machine__findnew_thread (machine,-1 , next_pid); sched->curr_thread[this_cpu] = sched_in;
tools/perf/util/machine.c +3 -3
@@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)return -ENOMEM ;if (pid !=HOST_KERNEL_ID ) { -struct thread *thread =machine__findnew_thread (machine,0 , +struct thread *thread =machine__findnew_thread (machine,-1 , pid);char comm[64 ];
@@ -286,7 +286,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* the full rbtree: */ if (machine->last_match && machine->last_match->tid == tid) { -if (pid && pid != machine->last_match->pid_) +if (pid !=-1 && pid != machine->last_match->pid_) machine->last_match->pid_ = pid;return machine->last_match; }
@@ -297,7 +297,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid && pid != th->pid_) +if (pid !=-1 && pid != th->pid_) th->pid_ = pid;return th; }
tools/perf/util/session.c +3 -2
@@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)struct thread *perf_session__findnew (struct perf_session *session,pid_t pid) { -return machine__findnew_thread (&session->machines.host,0 , pid); +return machine__findnew_thread (&session->machines.host,-1 , pid); }static struct thread *perf_session__register_idle_thread (struct perf_session *session) { -struct thread *thread =perf_session__findnew (session,0 ); +struct thread *thread; + thread =machine__findnew_thread (&session->machines.host,0 ,0 );if (thread ==NULL ||thread__set_comm (thread,"swapper" ,0 )) {pr_err ("problem inserting idle task.\n" ); thread =NULL ;
tools/perf/util/thread.c +1 -1
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)struct thread *leader;pid_t pid = thread->pid_; -if (pid == thread->tid) { +if (pid == thread->tid || pid ==-1 ) { thread->mg =map_groups__new (); }else { leader =machine__findnew_thread (machine, pid, pid);
Adrian Hunter
reviewerPATCH 2/41 perf tools: Fix map groups of threads with unknown pids
In reply to Adrian HunterEvents like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.
--- tools/perf/util/machine.c | 22 ++++++++++++++++------ tools/perf/util/map.c | 14 ++++++++++++++ tools/perf/util/map.h | 1 + tools/perf/util/thread.c | 35 +++++++++++++++++++++++++++++++++++ tools/perf/util/thread.h | 1 + 5 files changed, 67 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +16 -6
@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)return ; } +static void machine__update_thread_pid (struct machine *machine, +struct thread *th,pid_t pid) +{ +if (pid != th->pid_ && pid !=-1 && th->pid_ ==-1 ) { + th->pid_ = pid; +if (thread__join_map_groups (th, machine)) +pr_err ("Failed to join map groups for %d:%d\n" , + th->pid_, th->tid); + } +} +static struct thread *__machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid,bool create)
@@ -285,10 +296,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* so most of the time we dont have to look up * the full rbtree: */ -if (machine->last_match && machine->last_match->tid == tid) { -if (pid !=-1 && pid != machine->last_match->pid_) - machine->last_match->pid_ = pid; -return machine->last_match; + th = machine->last_match; +if (th && th->tid == tid) { +machine__update_thread_pid (machine, th, pid); +return th; }while (*p !=NULL ) {
@@ -297,8 +308,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid !=-1 && pid != th->pid_) - th->pid_ = pid; +machine__update_thread_pid (machine, th, pid);return th; }
tools/perf/util/map.c +14 -0
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg) } } +bool map_groups__empty (struct map_groups *mg) +{ +int i; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +if (maps__first (&mg->maps[i])) +return false; +if (!list_empty (&mg->removed_maps[i])) +return false; + } + +return true; +} +struct map_groups *map_groups__new (void ) {struct map_groups *mg =malloc (sizeof (*mg));
tools/perf/util/map.h +1 -0
@@ -66,6 +66,7 @@ struct map_groups {struct map_groups *map_groups__new (void );void map_groups__delete (struct map_groups *mg); +bool map_groups__empty (struct map_groups *mg);static inline struct map_groups *map_groups__get (struct map_groups *mg) {
tools/perf/util/thread.c +35 -0
@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)return thread->mg ?0 :-1 ; } +int thread__join_map_groups (struct thread *thread,struct machine *machine) +{ +struct thread *leader; +pid_t pid = thread->pid_; + +if (pid == thread->tid) +return 0 ; + + leader =machine__findnew_thread (machine, pid, pid); +if (!leader) +return -ENOMEM ; + +if (!leader->mg) + leader->mg =map_groups__new (); + +if (!leader->mg) +return -ENOMEM ; + +if (thread->mg) { +/* +* Maps are created from MMAP events which provide the pid and +* tid. Consequently there never should be any maps on a thread +* with an unknown pid. Just print an error if there are. +*/ +if (!map_groups__empty (thread->mg)) +pr_err ("Discarding thread maps for %d:%d\n" , + thread->pid_, thread->tid); +map_groups__delete (thread->mg); + } + + thread->mg =map_groups__get (leader->mg); + +return 0 ; +} +struct thread *thread__new (pid_t pid,pid_t tid) {char *comm_str;
tools/perf/util/thread.h +1 -0
@@ -31,6 +31,7 @@ struct comm;struct thread *thread__new (pid_t pid,pid_t tid);int thread__init_map_groups (struct thread *thread,struct machine *machine); +int thread__join_map_groups (struct thread *thread,struct machine *machine);void thread__delete (struct thread *thread);static inline void thread__exited (struct thread *thread) {
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids
Em Mon, Jul 14, 2014 at 01:02:26PM +0300, Adrian Hunter escreveu:
Quoted 25 lines
Events like
sched_switchdo not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 22 ++++++++++++++++------ tools/perf/util/map.c | 14 ++++++++++++++ tools/perf/util/map.h | 1 + tools/perf/util/thread.c | 35 +++++++++++++++++++++++++++++++++++ tools/perf/util/thread.h | 1 + 5 files changed, 67 insertions(+), 6 deletions(-)tools/perf/util/machine.c +1
-0@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)return ; } +static void machine__update_thread_pid(struct machine *machine,
tools/perf/util/machine.c void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) · line 285
Quoted 10 lines
tools/perf/util/machine.c +10
-0+ struct thread *th, pid_t pid) +{ +if (pid != th->pid_ && pid !=-1 && th->pid_ ==-1 ) { + th->pid_ = pid; +if (thread__join_map_groups (th, machine)) +pr_err ("Failed to join map groups for %d:%d\n" , + th->pid_, th->tid); + } +} +
I think you should combine the above function with thread__join_map_groups, and I think that the method belongs to the 'machine' class, see below for further comments on this...
Quoted 90 lines
tools/perf/util/machine.c +5
-6static struct thread *__machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid,bool create)@@ -285,10 +296,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* so most of the time we dont have to look up * the full rbtree: */ -if (machine->last_match && machine->last_match->tid == tid) { -if (pid !=-1 && pid != machine->last_match->pid_) - machine->last_match->pid_ = pid; -return machine->last_match; + th = machine->last_match; +if (th && th->tid == tid) { +machine__update_thread_pid (machine, th, pid); +return th; }while (*p !=NULL ) {@@ -297,8 +308,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid !=-1 && pid != th->pid_) - th->pid_ = pid; +machine__update_thread_pid (machine, th, pid);return th; }tools/perf/util/map.c +14
-0@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg) } } +bool map_groups__empty (struct map_groups *mg) +{ +int i; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +if (maps__first (&mg->maps[i])) +return false; +if (!list_empty (&mg->removed_maps[i])) +return false; + } + +return true; +} +struct map_groups *map_groups__new (void ) {struct map_groups *mg =malloc (sizeof (*mg));tools/perf/util/map.h +1
-0@@ -66,6 +66,7 @@ struct map_groups {struct map_groups *map_groups__new (void );void map_groups__delete (struct map_groups *mg); +bool map_groups__empty (struct map_groups *mg);static inline struct map_groups *map_groups__get (struct map_groups *mg) {tools/perf/util/thread.c +17
-0@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)return thread->mg ?0 :-1 ; } +int thread__join_map_groups (struct thread *thread,struct machine *machine) +{ +struct thread *leader; +pid_t pid = thread->pid_; + +if (pid == thread->tid) +return 0 ; + + leader =machine__findnew_thread (machine, pid, pid); +if (!leader) +return -ENOMEM ; + +if (!leader->mg) + leader->mg =map_groups__new (); + +if (!leader->mg) +return -ENOMEM ;
tools/perf/util/thread.c int thread__init_map_groups(struct thread *thread, struct machine *machine) · line 53
Quoted 10 lines
tools/perf/util/thread.c +10
-0+ +if (thread->mg) { +/* +* Maps are created from MMAP events which provide the pid and +* tid. Consequently there never should be any maps on a thread +* with an unknown pid. Just print an error if there are. +*/ +if (!map_groups__empty (thread->mg)) +pr_err ("Discarding thread maps for %d:%d\n" , + thread->pid_, thread->tid);
Because there is nothing in this function (thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.
So, please consider merging this and its sole caller, machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.
Continuing to look at the other patches...
Quoted 25 lines
tools/perf/util/thread.c +8
-0+map_groups__delete (thread->mg); + } + + thread->mg =map_groups__get (leader->mg); + +return 0 ; +} +struct thread *thread__new (pid_t pid,pid_t tid) {char *comm_str;tools/perf/util/thread.h +1
-0@@ -31,6 +31,7 @@ struct comm;struct thread *thread__new (pid_t pid,pid_t tid);int thread__init_map_groups (struct thread *thread,struct machine *machine); +int thread__join_map_groups (struct thread *thread,struct machine *machine);void thread__delete (struct thread *thread);static inline void thread__exited (struct thread *thread) {Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids
Quoted 80 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:26PM +0300, Adrian Hunter escreveu:
Quoted 25 lines
Events like
sched_switchdo not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 22 ++++++++++++++++------ tools/perf/util/map.c | 14 ++++++++++++++ tools/perf/util/map.h | 1 + tools/perf/util/thread.c | 35 +++++++++++++++++++++++++++++++++++ tools/perf/util/thread.h | 1 + 5 files changed, 67 insertions(+), 6 deletions(-)tools/perf/util/machine.c +1
-0@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)return ; } +static void machine__update_thread_pid(struct machine *machine,tools/perf/util/machine.c void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) · line 285
Quoted 10 lines
tools/perf/util/machine.c +10
-0+ struct thread *th, pid_t pid) +{ +if (pid != th->pid_ && pid !=-1 && th->pid_ ==-1 ) { + th->pid_ = pid; +if (thread__join_map_groups (th, machine)) +pr_err ("Failed to join map groups for %d:%d\n" , + th->pid_, th->tid); + } +} +I think you should combine the above function with
thread__join_map_groups, and I think that the method belongs to the 'machine' class, see below for further comments on this...Quoted 25 lines
tools/perf/util/thread.c +17
-0@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)return thread->mg ?0 :-1 ; } +int thread__join_map_groups (struct thread *thread,struct machine *machine) +{ +struct thread *leader; +pid_t pid = thread->pid_; + +if (pid == thread->tid) +return 0 ; + + leader =machine__findnew_thread (machine, pid, pid); +if (!leader) +return -ENOMEM ; + +if (!leader->mg) + leader->mg =map_groups__new (); + +if (!leader->mg) +return -ENOMEM ;tools/perf/util/thread.c int thread__init_map_groups(struct thread *thread, struct machine *machine) · line 53
Quoted 10 lines
tools/perf/util/thread.c +10
-0+ +if (thread->mg) { +/* +* Maps are created from MMAP events which provide the pid and +* tid. Consequently there never should be any maps on a thread +* with an unknown pid. Just print an error if there are. +*/ +if (!map_groups__empty (thread->mg)) +pr_err ("Discarding thread maps for %d:%d\n" , + thread->pid_, thread->tid);Because there is nothing in this function (
thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.
Quoted 3 lines
So, please consider merging this and its sole caller,
machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.
You have it in your tree now. Do you want another patch to do that?
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids
Em Tue, Jul 15, 2014 at 02:33:01PM +0300, Adrian Hunter escreveu:
Quoted 10 lines · Arnaldo Carvalho de Melo
Quoted 6 lines
Because there is nothing in this function (
thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.So, please consider merging this and its sole caller,
machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.You have it in your tree now. Do you want another patch to do that?
Sorry, ended up push it together with the rest, fixed up now, removed it and added some more from your kit, please work from there.
Let me know if you find any problem with the merge process so far.
Thanks,
- Arnaldo
Adrian Hunter
reviewerPATCH v2 2/41 perf tools: Fix map groups of threads with unknown pids
Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.
--- tools/perf/util/machine.c | 57 ++++++++++++++++++++++++++++++++++++++++++----- tools/perf/util/map.c | 14 ++++++++++++ tools/perf/util/map.h | 1 + 3 files changed, 66 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +51 -6
@@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)return ; } +static void machine__update_thread_pid (struct machine *machine, +struct thread *th,pid_t pid) +{ +struct thread *leader; + +if (pid == th->pid_ || pid ==-1 || th->pid_ !=-1 ) +return ; + + th->pid_ = pid; + +if (th->pid_ == th->tid) +return ; + + leader =machine__findnew_thread (machine, th->pid_, th->pid_); +if (!leader) + goto out_err; + +if (!leader->mg) + leader->mg =map_groups__new (); + +if (!leader->mg) + goto out_err; + +if (th->mg == leader->mg) +return ; + +if (th->mg) { +/* +* Maps are created from MMAP events which provide the pid and +* tid. Consequently there never should be any maps on a thread +* with an unknown pid. Just print an error if there are. +*/ +if (!map_groups__empty (th->mg)) +pr_err ("Discarding thread maps for %d:%d\n" , + th->pid_, th->tid); +map_groups__delete (th->mg); + } + + th->mg =map_groups__get (leader->mg); + +return ; + +out_err: +pr_err ("Failed to join map groups for %d:%d\n" , th->pid_, th->tid); +} +static struct thread *__machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid,bool create)
@@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* so most of the time we dont have to look up * the full rbtree: */ -if (machine->last_match && machine->last_match->tid == tid) { -if (pid !=-1 && pid != machine->last_match->pid_) - machine->last_match->pid_ = pid; -return machine->last_match; + th = machine->last_match; +if (th && th->tid == tid) { +machine__update_thread_pid (machine, th, pid); +return th; }while (*p !=NULL ) {
@@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid !=-1 && pid != th->pid_) - th->pid_ = pid; +machine__update_thread_pid (machine, th, pid);return th; }
tools/perf/util/map.c +14 -0
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg) } } +bool map_groups__empty (struct map_groups *mg) +{ +int i; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +if (maps__first (&mg->maps[i])) +return false; +if (!list_empty (&mg->removed_maps[i])) +return false; + } + +return true; +} +struct map_groups *map_groups__new (void ) {struct map_groups *mg =malloc (sizeof (*mg));
tools/perf/util/map.h +1 -0
@@ -66,6 +66,7 @@ struct map_groups {struct map_groups *map_groups__new (void );void map_groups__delete (struct map_groups *mg); +bool map_groups__empty (struct map_groups *mg);static inline struct map_groups *map_groups__get (struct map_groups *mg) {
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Fix map groups of threads with unknown pids
perf machine: Fix map groups of threads with unknown pids
Commit-ID: 29ce36121e6738012aaf00d983d25260627f2b0d Gitweb: http://git.kernel.org/tip/29ce36121e6738012aaf00d983d25260627f2b0d Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 16 Jul 2014 11:07:13 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 17 Jul 2014 10:31:02 -0300
perf machine: Fix map groups of threads with unknown pids
Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups.
Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.
--- tools/perf/util/machine.c | 57 ++++++++++++++++++++++++++++++++++++++++++----- tools/perf/util/map.c | 14 ++++++++++++ tools/perf/util/map.h | 1 + 3 files changed, 66 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +51 -6
@@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)return ; } +static void machine__update_thread_pid (struct machine *machine, +struct thread *th,pid_t pid) +{ +struct thread *leader; + +if (pid == th->pid_ || pid ==-1 || th->pid_ !=-1 ) +return ; + + th->pid_ = pid; + +if (th->pid_ == th->tid) +return ; + + leader =machine__findnew_thread (machine, th->pid_, th->pid_); +if (!leader) + goto out_err; + +if (!leader->mg) + leader->mg =map_groups__new (); + +if (!leader->mg) + goto out_err; + +if (th->mg == leader->mg) +return ; + +if (th->mg) { +/* +* Maps are created from MMAP events which provide the pid and +* tid. Consequently there never should be any maps on a thread +* with an unknown pid. Just print an error if there are. +*/ +if (!map_groups__empty (th->mg)) +pr_err ("Discarding thread maps for %d:%d\n" , + th->pid_, th->tid); +map_groups__delete (th->mg); + } + + th->mg =map_groups__get (leader->mg); + +return ; + +out_err: +pr_err ("Failed to join map groups for %d:%d\n" , th->pid_, th->tid); +} +static struct thread *__machine__findnew_thread (struct machine *machine,pid_t pid,pid_t tid,bool create)
@@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* so most of the time we dont have to look up * the full rbtree: */ -if (machine->last_match && machine->last_match->tid == tid) { -if (pid !=-1 && pid != machine->last_match->pid_) - machine->last_match->pid_ = pid; -return machine->last_match; + th = machine->last_match; +if (th && th->tid == tid) { +machine__update_thread_pid (machine, th, pid); +return th; }while (*p !=NULL ) {
@@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,if (th->tid == tid) { machine->last_match = th; -if (pid !=-1 && pid != th->pid_) - th->pid_ = pid; +machine__update_thread_pid (machine, th, pid);return th; }
tools/perf/util/map.c +14 -0
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg) } } +bool map_groups__empty (struct map_groups *mg) +{ +int i; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +if (maps__first (&mg->maps[i])) +return false; +if (!list_empty (&mg->removed_maps[i])) +return false; + } + +return true; +} +struct map_groups *map_groups__new (void ) {struct map_groups *mg =malloc (sizeof (*mg));
tools/perf/util/map.h +1 -0
@@ -66,6 +66,7 @@ struct map_groups {struct map_groups *map_groups__new (void );void map_groups__delete (struct map_groups *mg); +bool map_groups__empty (struct map_groups *mg);static inline struct map_groups *map_groups__get (struct map_groups *mg) {
Adrian Hunter
reviewerPATCH 3/41 perf script: Display PERF_RECORD_MISC_COMM_EXEC flag
In reply to Adrian Hunter--- tools/perf/util/event.c | 9 ++++++++- tools/perf/util/evsel.c | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/event.c +8 -1
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,size_t perf_event__fprintf_comm (union perf_event *event,FILE *fp) { -return fprintf (fp,": %s:%d\n" , event->comm.comm, event->comm.tid); +const char *s; + +if (event->header.misc &PERF_RECORD_MISC_COMM_EXEC ) + s =" exec" ; +else + s ="" ; + +return fprintf (fp,"%s: %s:%d\n" , s, event->comm.comm, event->comm.tid); } int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
tools/perf/util/evsel.c +2 -1
@@ -960,6 +960,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret +=PRINT_ATTR2 (exclude_user, exclude_kernel); ret +=PRINT_ATTR2 (exclude_hv, exclude_idle); ret +=PRINT_ATTR2 (mmap, comm); + ret +=PRINT_ATTR2 (mmap2, comm_exec); ret +=PRINT_ATTR2 (freq, inherit_stat); ret +=PRINT_ATTR2 (enable_on_exec, task); ret +=PRINT_ATTR2 (watermark, precise_ip);
@@ -967,7 +968,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret +=PRINT_ATTR2 (exclude_host, exclude_guest); ret +=PRINT_ATTR2N ("excl.callchain_kern" , exclude_callchain_kernel,"excl.callchain_user" , exclude_callchain_user); - ret +=PRINT_ATTR_U32 (mmap2); ret +=PRINT_ATTR_U32 (wakeup_events); ret +=PRINT_ATTR_U32 (wakeup_watermark);
@@ -1940,6 +1940,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,if_print (mmap);if_print (mmap2);if_print (comm); +if_print (comm_exec);if_print (freq);if_print (inherit_stat);if_print (enable_on_exec);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf script: Display PERF_RECORD_MISC_COMM_EXEC flag
perf script: Display PERF_RECORD_MISC_COMM_EXEC flag
Commit-ID: 022c50d09c2c2bc31506ad16c4bcba7fb418ce34 Gitweb: http://git.kernel.org/tip/022c50d09c2c2bc31506ad16c4bcba7fb418ce34 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:27 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:34 -0300
perf script: Display PERF_RECORD_MISC_COMM_EXEC flag
--- tools/perf/util/event.c | 9 ++++++++- tools/perf/util/evsel.c | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/event.c +8 -1
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,size_t perf_event__fprintf_comm (union perf_event *event,FILE *fp) { -return fprintf (fp,": %s:%d\n" , event->comm.comm, event->comm.tid); +const char *s; + +if (event->header.misc &PERF_RECORD_MISC_COMM_EXEC ) + s =" exec" ; +else + s ="" ; + +return fprintf (fp,"%s: %s:%d\n" , s, event->comm.comm, event->comm.tid); } int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
tools/perf/util/evsel.c +2 -1
@@ -960,6 +960,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret +=PRINT_ATTR2 (exclude_user, exclude_kernel); ret +=PRINT_ATTR2 (exclude_hv, exclude_idle); ret +=PRINT_ATTR2 (mmap, comm); + ret +=PRINT_ATTR2 (mmap2, comm_exec); ret +=PRINT_ATTR2 (freq, inherit_stat); ret +=PRINT_ATTR2 (enable_on_exec, task); ret +=PRINT_ATTR2 (watermark, precise_ip);
@@ -967,7 +968,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret +=PRINT_ATTR2 (exclude_host, exclude_guest); ret +=PRINT_ATTR2N ("excl.callchain_kern" , exclude_callchain_kernel,"excl.callchain_user" , exclude_callchain_user); - ret +=PRINT_ATTR_U32 (mmap2); ret +=PRINT_ATTR_U32 (wakeup_events); ret +=PRINT_ATTR_U32 (wakeup_watermark);
@@ -1940,6 +1940,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,if_print (mmap);if_print (mmap2);if_print (comm); +if_print (comm_exec);if_print (freq);if_print (inherit_stat);if_print (enable_on_exec);
Adrian Hunter
reviewerPATCH 4/41 perf record: Select comm_exec flag if supported
In reply to Adrian HunterThe comm_exec flag on the attribute can later
be found in the perf.data file allowing a
tool to know in advance if the captured data
has the flag.
--- tools/perf/util/record.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
tools/perf/util/record.c +17 -1
@@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel) evsel->attr.sample_type |=PERF_SAMPLE_IDENTIFIER ; } +static void perf_probe_comm_exec (struct perf_evsel *evsel) +{ + evsel->attr.comm_exec =1 ; +} +bool perf_can_sample_identifier (void ) {return perf_probe_api (perf_probe_sample_identifier); } +static bool perf_can_comm_exec (void ) +{ +return perf_probe_api (perf_probe_comm_exec); +} +void perf_evlist__config (struct perf_evlist *evlist,struct record_opts *opts) {struct perf_evsel *evsel;bool use_sample_identifier = false; +bool use_comm_exec;/* * Set the evsel leader links before we configure attributes,
@@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)if (evlist->cpus->map[0 ] <0 ) opts->no_inherit = true; -evlist__for_each (evlist, evsel) + use_comm_exec =perf_can_comm_exec (); + +evlist__for_each (evlist, evsel) {perf_evsel__config (evsel, opts); +if (!evsel->idx && use_comm_exec) + evsel->attr.comm_exec =1 ; + }if (evlist->nr_entries >1 ) {struct perf_evsel *first =perf_evlist__first (evlist);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf record: Select comm_exec flag if supported
perf record: Select comm_exec flag if supported
Commit-ID: 39e09d40bea440d9cfe645b55aff251294318669 Gitweb: http://git.kernel.org/tip/39e09d40bea440d9cfe645b55aff251294318669 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:28 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:34 -0300
perf record: Select comm_exec flag if supported
The comm_exec flag on the attribute can later be found in the perf.data file allowing a tool to know in advance if the captured data has the flag.
--- tools/perf/util/record.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
tools/perf/util/record.c +17 -1
@@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel) evsel->attr.sample_type |=PERF_SAMPLE_IDENTIFIER ; } +static void perf_probe_comm_exec (struct perf_evsel *evsel) +{ + evsel->attr.comm_exec =1 ; +} +bool perf_can_sample_identifier (void ) {return perf_probe_api (perf_probe_sample_identifier); } +static bool perf_can_comm_exec (void ) +{ +return perf_probe_api (perf_probe_comm_exec); +} +void perf_evlist__config (struct perf_evlist *evlist,struct record_opts *opts) {struct perf_evsel *evsel;bool use_sample_identifier = false; +bool use_comm_exec;/* * Set the evsel leader links before we configure attributes,
@@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)if (evlist->cpus->map[0 ] <0 ) opts->no_inherit = true; -evlist__for_each (evlist, evsel) + use_comm_exec =perf_can_comm_exec (); + +evlist__for_each (evlist, evsel) {perf_evsel__config (evsel, opts); +if (!evsel->idx && use_comm_exec) + evsel->attr.comm_exec =1 ; + }if (evlist->nr_entries >1 ) {struct perf_evsel *first =perf_evlist__first (evlist);
Adrian Hunter
reviewerPATCH 5/41 perf tools: Identify which comms are from exec
In reply to Adrian Hunter--- tools/perf/util/comm.c | 7 +++++-- tools/perf/util/comm.h | 6 ++++-- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 24 +++++++++++++++++++----- tools/perf/util/thread.h | 10 +++++++++- 5 files changed, 40 insertions(+), 11 deletions(-)
tools/perf/util/comm.c +5 -2
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)return new; } -struct comm *comm__new (const char *str,u64 timestamp) +struct comm *comm__new (const char *str,u64 timestamp,bool exec) {struct comm *comm =zalloc (sizeof (*comm));
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)return NULL ; comm->start = timestamp; + comm->exec = exec; comm->comm_str =comm_str__findnew (str, &comm_str_root);if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)return comm; } -int comm__override (struct comm *comm,const char *str,u64 timestamp) +int comm__override (struct comm *comm,const char *str,u64 timestamp,bool exec) {struct comm_str *new, *old = comm->comm_str;
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)comm_str__put (old); comm->comm_str = new; comm->start = timestamp; +if (exec && !comm->exec) + comm->exec = true;return 0 ; }
tools/perf/util/comm.h +4 -2
@@ -11,11 +11,13 @@ struct comm {struct comm_str *comm_str;u64 start;struct list_head list; + bool exec; };void comm__free (struct comm *comm); -struct comm *comm__new (const char *str,u64 timestamp); +struct comm *comm__new (const char *str,u64 timestamp,bool exec);const char *comm__str (const struct comm *comm); -int comm__override (struct comm *comm,const char *str,u64 timestamp); +int comm__override (struct comm *comm,const char *str,u64 timestamp, +bool exec);#endif /* __PERF_COMM_H */
tools/perf/util/machine.c +3 -1
@@ -360,11 +360,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
@@ -76,7 +76,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;
@@ -113,19 +113,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
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Em Mon, Jul 14, 2014 at 01:02:29PM +0300, Adrian Hunter escreveu:
Quoted 40 lines
Signed-off-by Adrian Hunter <[email protected]>--- 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 +3
-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;
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 5 lines
tools/perf/util/comm.c +2
-0@@ -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;
Why do you need the !comm->exec test?
Quoted 99 lines
tools/perf/util/comm.c +0
-0return 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@@ -360,11 +360,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@@ -76,7 +76,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;@@ -113,19 +113,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 +0
-0@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread) thread->dead = true; }
tools/perf/util/thread.h static inline void thread__exited(struct thread *thread) · line 48
Quoted 10 lines
tools/perf/util/thread.h +8
-1-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); +} +
So this is nice, you leave the existing function, setting exec to false, so that you don't have to change the existing codepaths where it is not from 'exec', and provide a __ prefixed variant where 'exec' can be set.
Why not to do the same thing for comm__new() ? No uses, i.e. in all cases you will need to pass 'exec' as a variable?
I thought about doing the same thing for that machine__findnew_thread, i.e. provide a variant where tid and pid is passed and one where just the tid is passed, because the pid is unknown.
BTW, I'll update my perf/core branch with the set of patches that I merged, so that you can have where to look for a consolidated tree with the things already processed.
- Arnaldo
Quoted 8 lines
tools/perf/util/thread.h +1
-0int thread__comm_len (struct thread *thread);struct comm *thread__comm (const struct thread *thread); +struct comm *thread__exec_comm (const struct thread *thread);const char *thread__comm_str (const struct thread *thread);void thread__insert_map (struct thread *thread,struct map *map);int thread__fork (struct thread *thread,struct thread *parent,u64 timestamp);Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Quoted 40 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:29PM +0300, Adrian Hunter escreveu:
Quoted 39 lines
Signed-off-by Adrian Hunter <[email protected]>--- 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 +3
-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;
Quoted 8 lines
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 6 lines
tools/perf/util/comm.c +2
-0@@ -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;Why do you need the !comm->exec test?
Dunno
Quoted 115 lines
Quoted 100 lines
tools/perf/util/comm.c +0
-0return 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@@ -360,11 +360,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@@ -76,7 +76,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;@@ -113,19 +113,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 +0
-0@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread) thread->dead = true; }tools/perf/util/thread.h static inline void thread__exited(struct thread *thread) · line 48
Quoted 10 lines
tools/perf/util/thread.h +8
-1-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); +} +So this is nice, you leave the existing function, setting exec to false, so that you don't have to change the existing codepaths where it is not from 'exec', and provide a __ prefixed variant where 'exec' can be set.
Quoted 2 lines
Why not to do the same thing for
comm__new()? No uses, i.e. in all cases you will need to pass 'exec' as a variable?
There are only 2 comm__new() callers, and they are in files I am changing anyway.
Quoted 4 lines
I thought about doing the same thing for that
machine__findnew_thread, i.e. provide a variant where tid and pid is passed and one where just the tid is passed, because the pid is unknown.
But you don't want people using the "unknown" variant if they do know the pid, so forcing them to pass something maybe better.
Quoted 4 lines
BTW, I'll update my perf/core branch with the set of patches that I merged, so that you can have where to look for a consolidated tree with the things already processed.
Thanks!
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Quoted 8 lines
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 6 lines
tools/perf/util/comm.c +2
-0@@ -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;Why do you need the !comm->exec test?
Dunno
I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.
- Arnaldo
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 10 lines
Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:
Quoted 8 lines
Quoted 8 lines
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 6 lines
tools/perf/util/comm.c +2
-0@@ -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;Why do you need the !comm->exec test?
Quoted 4 lines
Quoted 1 line
Dunno
I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.
Also why do you need to "identify which comms are from exec", was it good for?
- Arnaldo
Adrian Hunter
reviewerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Quoted 15 lines · Arnaldo Carvalho de Melo
Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 14 lines
Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Quoted 8 lines
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 6 lines
tools/perf/util/comm.c +2
-0@@ -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;Why do you need the !comm->exec test?
Dunno
I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.
Sorry I forgot.
Quoted 3 lines
Also why do you need to "identify which comms are from exec", was it good for?
It is 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.
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 05/41] perf tools: Identify which comms are from exec
Em Wed, Jul 23, 2014 at 07:46:43PM +0300, Adrian Hunter escreveu:
Quoted 17 lines · Arnaldo Carvalho de Melo
Quoted 15 lines
Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 14 lines
Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Quoted 8 lines
tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111
Quoted 6 lines
tools/perf/util/comm.c +2
-0@@ -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;Why do you need the !comm->exec test?
Dunno
I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.
Quoted 8 lines
Sorry I forgot.
Quoted 2 lines
Also why do you need to "identify which comms are from exec", was it good for?
It is 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.
Ok, thanks, I'll add it to the patch log, as I did with some others.
I'll continue after lunch, what I have so far is in the tmp.perf/core in my tree, at git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git
- Arnaldo
Adrian Hunter
reviewerPATCH 6/41 perf tools: Add machine__thread_exec_comm()
In reply to Adrian HunterAdd machine__thread_exec_comm() to return the comm that matches the last exec, if the comm_exec flag is present, or the last comm otherwise.
--- tools/perf/util/machine.c | 26 ++++++++++++++++++++++++++ tools/perf/util/machine.h | 4 ++++ tools/perf/util/session.c | 24 +++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +26 -0
@@ -28,6 +28,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter =NULL ; machine->id_hdr_size =0 ; + machine->comm_exec = false; machine->root_dir =strdup (root_dir);if (machine->root_dir ==NULL )
@@ -172,6 +173,19 @@ void machines__set_symbol_filter(struct machines *machines, } } +void machines__set_comm_exec (struct machines *machines,bool comm_exec) +{ +struct rb_node *nd; + + machines->host.comm_exec = comm_exec; + +for (nd =rb_first (&machines->guests); nd; nd =rb_next (nd)) { + struct machine *machine = rb_entry(nd, struct machine, rb_node); + + machine->comm_exec = comm_exec; + } +} +struct machine *machines__find (struct machines *machines,pid_t pid) {struct rb_node **p = &machines->guests.rb_node;
@@ -354,6 +368,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) {
@@ -362,6 +385,9 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event event->comm.tid);bool exec = event->header.misc &PERF_RECORD_MISC_COMM_EXEC ; +if (exec) + machine->comm_exec = true; +if (dump_trace)perf_event__fprintf_comm (event, stdout);
tools/perf/util/machine.h +4 -0
@@ -24,6 +24,7 @@ struct machine {struct rb_node rb_node;pid_t pid;u16 id_hdr_size; +bool comm_exec;char *root_dir;struct rb_root threads;struct list_head dead_threads;
@@ -43,6 +44,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)struct thread *machine__find_thread (struct machine *machine,pid_t pid,pid_t tid); +struct comm *machine__thread_exec_comm (struct machine *machine, +struct thread *thread);int machine__process_comm_event (struct machine *machine,union perf_event *event,struct perf_sample *sample);
@@ -84,6 +87,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);void machines__set_symbol_filter (struct machines *machines,symbol_filter_t symbol_filter); +void machines__set_comm_exec (struct machines *machines,bool comm_exec);struct machine *machine__new_host (void );int machine__init (struct machine *machine,const char *root_dir,pid_t pid);
tools/perf/util/session.c +23 -1
@@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)machines__destroy_kernel_maps (&session->machines); } +static bool perf_session__has_comm_exec (struct perf_session *session) +{ +struct perf_evsel *evsel; + +evlist__for_each (session->evlist, evsel) { +if (evsel->attr.comm_exec) +return true; + } + +return false; +} + +static void perf_session__set_comm_exec (struct perf_session *session) +{ +bool comm_exec =perf_session__has_comm_exec (session); + +machines__set_comm_exec (&session->machines, comm_exec); +} +struct perf_session *perf_session__new (struct perf_data_file *file,bool repipe,struct perf_tool *tool) {
@@ -92,6 +111,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out_close;perf_session__set_id_hdr_size (session); +perf_session__set_comm_exec (session); } }
@@ -1006,8 +1026,10 @@ static int perf_session__process_user_event(struct perf_session *session, unionswitch (event->header.type) {case PERF_RECORD_HEADER_ATTR : err = tool->attr (tool, event, &session->evlist); -if (err ==0 ) +if (err ==0 ) {perf_session__set_id_hdr_size (session); +perf_session__set_comm_exec (session); + }return err;case PERF_RECORD_HEADER_EVENT_TYPE :/*
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 7/41 perf tools: Fix missing kernel map load
In reply to Adrian Hunterthread__find_addr_map() falls back to trying the kernel maps if the address is negative and is not found in userspace maps. As commented in the code, the kernel maps must be "loaded" before use. This patch ensures that happens under the fallback condition also.
--- tools/perf/util/event.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/event.c +1 -0
@@ -788,6 +788,7 @@ try_again: cpumode == PERF_RECORD_MISC_USER && machine && mg != &machine->kmaps) { mg = &machine->kmaps; + load_map = true; goto try_again; } }else {
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Fix missing kernel map load
perf tools: Fix missing kernel map load
Commit-ID: 1f2a7069b6e895487b1d9229f5f62799cc4ea0aa Gitweb: http://git.kernel.org/tip/1f2a7069b6e895487b1d9229f5f62799cc4ea0aa Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:31 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:34 -0300
perf tools: Fix missing kernel map load
thread__find_addr_map() falls back to trying the kernel maps if the address is negative and is not found in userspace maps. As commented in the code, the kernel maps must be "loaded" before use. This patch ensures that happens under the fallback condition also.
--- tools/perf/util/event.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/event.c +1 -0
@@ -788,6 +788,7 @@ try_again: cpumode == PERF_RECORD_MISC_USER && machine && mg != &machine->kmaps) { mg = &machine->kmaps; + load_map = true; goto try_again; } }else {
Adrian Hunter
reviewerPATCH 8/41 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
@@ -732,7 +732,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
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 08/41] perf tools: Fix missing label symbols
Em Mon, Jul 14, 2014 at 01:02:32PM +0300, Adrian Hunter escreveu:
Quoted 8 lines
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.
Would be great to have a 'perf test' entry that fail when looking for those 'label symbols', i.e. looking for one such symbol in vmlinux that we know is always there, in some written in stone area of the kernel, where this label vanishing is unlikely to happen.
Can you elaborate on the case that fails? So that I can test it here, and then after the fix, check that it indeed fixes the problem? I may well write that test myself and insert it in my branch just before this one.
- Arnaldo
Quoted 20 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/symbol-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)tools/perf/util/symbol-elf.c +1
-1@@ -732,7 +732,7 @@ int dso__load_sym(struct dso *dso, struct map *map,if (symstrs ==NULL ) goto out_elf_end; - sec_strndx =elf_getscn (elf, ehdr.e_shstrndx); + sec_strndx =elf_getscn (runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);if (sec_strndx ==NULL ) goto out_elf_end;Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 08/41] perf tools: Fix missing label symbols
Quoted 15 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:32PM +0300, Adrian Hunter escreveu:
Quoted 8 lines
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.
Would be great to have a 'perf test' entry that fail when looking for those 'label symbols', i.e. looking for one such symbol in vmlinux that we know is always there, in some written in stone area of the kernel, where this label vanishing is unlikely to happen.
Quoted 4 lines
Can you elaborate on the case that fails? So that I can test it here, and then after the fix, check that it indeed fixes the problem? I may well write that test myself and insert it in my branch just before this one.
It fails with "_start" which is a label in /lib/x86_64-linux-gnu/ld-2.17.so. It is where the program starts so it is not a function, and it is the first user space address of an exec'ed process.
If you do:
perf record --per-thread -T -e branches:u -c1 -d -- uname
Then, assuming the old BTS driver doesn't lose the data, it should be pretty much the first branch.
pref script | head
Quoted 25 lines
- Arnaldo
Quoted 20 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/symbol-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)tools/perf/util/symbol-elf.c +1
-1@@ -732,7 +732,7 @@ int dso__load_sym(struct dso *dso, struct map *map,if (symstrs ==NULL ) goto out_elf_end; - sec_strndx =elf_getscn (elf, ehdr.e_shstrndx); + sec_strndx =elf_getscn (runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);if (sec_strndx ==NULL ) goto out_elf_end;Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 9/41 perf tools: Fix missing GNU IFUNC symbols
In reply to Adrian HunterSymbols of type STT_GNU_IFUNC are functions
so accept them as such.
--- tools/perf/util/symbol-elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +2 -1
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)static inline int elf_sym__is_function (const GElf_Sym *sym) { -return elf_sym__type (sym) ==STT_FUNC && +return (elf_sym__type (sym) ==STT_FUNC || +elf_sym__type (sym) ==STT_GNU_IFUNC ) && sym->st_name !=0 && sym->st_shndx !=SHN_UNDEF ; }
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf symbols: Fix missing GNU IFUNC symbols
perf symbols: Fix missing GNU IFUNC symbols
Commit-ID: a2f3b6bf0adadcb5f9383c60aa1355e0f9cba3da Gitweb: http://git.kernel.org/tip/a2f3b6bf0adadcb5f9383c60aa1355e0f9cba3da Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:33 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:34 -0300
perf symbols: Fix missing GNU IFUNC symbols
Symbols of type STT_GNU_IFUNC are functions so accept them as such.
--- tools/perf/util/symbol-elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +2 -1
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)static inline int elf_sym__is_function (const GElf_Sym *sym) { -return elf_sym__type (sym) ==STT_FUNC && +return (elf_sym__type (sym) ==STT_FUNC || +elf_sym__type (sym) ==STT_GNU_IFUNC ) && sym->st_name !=0 && sym->st_shndx !=SHN_UNDEF ; }
Adrian Hunter
reviewerPATCH 10/41 perf inject: Fix build id injection
In reply to Adrian HunterBuild Ids won't be injected unless the build id
feature flag is set.
--- tools/perf/builtin-inject.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/builtin-inject.c +3 -0
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject) ret =perf_session__process_events (session, &inject->tool);if (!file_out->is_pipe) { +if (inject->build_ids) +perf_header__set_feat (&session->header, +HEADER_BUILD_ID ); session->header.data_size = inject->bytes_written;perf_session__write_header (session, session->evlist, file_out->fd, true); }
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf inject: Fix build id injection
perf inject: Fix build id injection
Commit-ID: e38b43c3f3fd8ebe6f558400d1647a923bc19d44 Gitweb: http://git.kernel.org/tip/e38b43c3f3fd8ebe6f558400d1647a923bc19d44 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:34 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:34 -0300
perf inject: Fix build id injection
Build Ids won't be injected unless the build id feature flag is set.
--- tools/perf/builtin-inject.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/builtin-inject.c +3 -0
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject) ret =perf_session__process_events (session, &inject->tool);if (!file_out->is_pipe) { +if (inject->build_ids) +perf_header__set_feat (&session->header, +HEADER_BUILD_ID ); session->header.data_size = inject->bytes_written;perf_session__write_header (session, session->evlist, file_out->fd, true); }
Adrian Hunter
reviewerPATCH 11/41 perf tools: Fix appending a callchain from a previous sample
In reply to Adrian Hunterhist_entry__append_callchain() must check if the sample has a callcahin or it will append the callchain from a previous sample.
--- tools/perf/util/callchain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/callchain.c +1 -1
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentint hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample) { -if (!symbol_conf.use_callchain) +if (!symbol_conf.use_callchain || sample->callchain ==NULL )return 0 ;return callchain_append (he->callchain, &callchain_cursor, sample->period); }
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf callchain: Fix appending a callchain from a previous sample
perf callchain: Fix appending a callchain from a previous sample
Commit-ID: 4d40b051b1ac41ecbc818deed27750b4c1697520 Gitweb: http://git.kernel.org/tip/4d40b051b1ac41ecbc818deed27750b4c1697520 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:35 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:35 -0300
perf callchain: Fix appending a callchain from a previous sample
hist_entry__append_callchain() must check if the sample has a callcahin or it will append the callchain from a previous sample.
--- tools/perf/util/callchain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/callchain.c +1 -1
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentint hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample) { -if (!symbol_conf.use_callchain) +if (!symbol_conf.use_callchain || sample->callchain ==NULL )return 0 ;return callchain_append (he->callchain, &callchain_cursor, sample->period); }
Adrian Hunter
reviewerPATCH 12/41 perf tools: Fix leak of 'struct thread' on error path
In reply to Adrian Hunter__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.
--- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +3 -1
@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;
tools/perf/util/thread.c +4 -2
@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; -map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }list_for_each_entry_safe (comm, tmp, &thread->comm_list, list) {list_del (&comm->list);comm__free (comm);
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path
Em Mon, Jul 14, 2014 at 01:02:36PM +0300, Adrian Hunter escreveu:
Quoted 2 lines
__machine__findnew_thread()creates a 'struct thread' but does not free it on the error path.
Ok, but that second one is a separate bug, i.e. its not fixing the described leak, please break this into two patches with separate commit messages.
- Arnaldo
Quoted 41 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-)tools/perf/util/machine.c +3
-1@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;tools/perf/util/thread.c +4
-2@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; -map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }list_for_each_entry_safe (comm, tmp, &thread->comm_list, list) {list_del (&comm->list);comm__free (comm);Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerv2 cover perf tools: Allow deletion of a thread with no map groups
Hi
Here is the patch split in two.
Regards
Adrian
Adrian Hunter
reviewerPATCH v2 1/2 perf tools: Allow deletion of a thread with no map groups
It needs to be possible to call thread__delete() on a thread with no map groups. This is needed for a subsequent patch which deletes a thread on the error path before map groups have been attached.
--- tools/perf/util/thread.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/util/thread.c +4 -2
@@ -60,8 +60,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; -map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }list_for_each_entry_safe (comm, tmp, &thread->comm_list, list) {list_del (&comm->list);comm__free (comm);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf thread: Allow deletion of a thread with no map groups
perf thread: Allow deletion of a thread with no map groups
Commit-ID: 9608b84e4dd95341b88cad646b114811f5bccbba Gitweb: http://git.kernel.org/tip/9608b84e4dd95341b88cad646b114811f5bccbba Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 16 Jul 2014 10:19:43 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 17 Jul 2014 10:32:35 -0300
perf thread: Allow deletion of a thread with no map groups
It needs to be possible to call thread__delete() on a thread with no map groups.
This is needed for a subsequent patch which deletes a thread on the error path before map groups have been attached.
--- tools/perf/util/thread.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/util/thread.c +4 -2
@@ -60,8 +60,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; -map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }list_for_each_entry_safe (comm, tmp, &thread->comm_list, list) {list_del (&comm->list);comm__free (comm);
Adrian Hunter
reviewerPATCH v2 2/2 perf tools: Fix leak of 'struct thread' on error path
In reply to Adrian Hunter__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.
--- tools/perf/util/machine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +3 -1
@@ -325,8 +325,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf machine: Fix leak of 'struct thread' on error path
perf machine: Fix leak of 'struct thread' on error path
Commit-ID: 418029b7324f8b90ac1dfbc8a44555d6905be761 Gitweb: http://git.kernel.org/tip/418029b7324f8b90ac1dfbc8a44555d6905be761 Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 16 Jul 2014 10:19:44 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 17 Jul 2014 10:34:07 -0300
perf machine: Fix leak of 'struct thread' on error path
__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path. Fix it.
--- tools/perf/util/machine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +3 -1
@@ -370,8 +370,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;
Re: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path
In reply to Adrian HunterQuoted 30 lines · Adrian Hunter
__machine__findnew_thread()creates a 'struct thread' but does not free it on the error path.Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-)tools/perf/util/machine.c +3
-1@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;tools/perf/util/thread.c +0
-0
tools/perf/util/thread.c void thread__delete(struct thread *thread) · line 101
Quoted 9 lines
tools/perf/util/thread.c +4
-2@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp; -map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }
I dont think this is ^^^ needed.. each thread has ->mg defined
jirka
Adrian Hunter
reviewerRe: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path
Quoted 34 lines · Jiri Olsa
Quoted 33 lines · Adrian Hunter
__machine__findnew_thread()creates a 'struct thread' but does not free it on the error path.Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-)tools/perf/util/machine.c +3
-1@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,* within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ -if (thread__init_map_groups (th, machine)) +if (thread__init_map_groups (th, machine)) { +thread__delete (th);return NULL ; + } }return th;tools/perf/util/thread.c +0
-0@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread) {struct comm *comm, *tmp;
Quoted 8 lines
tools/perf/util/thread.c void thread__delete(struct thread *thread) · line 101
Quoted 6 lines
tools/perf/util/thread.c +4
-2-map_groups__put (thread->mg); - thread->mg =NULL ; +if (thread->mg) { +map_groups__put (thread->mg); + thread->mg =NULL ; + }I dont think this is ^^^ needed.. each thread has ->mg defined
On the error path the thread does not yet have an mg.
Adrian Hunter
reviewerPATCH 13/41 perf tools: Add machine__kernel_ip()
In reply to Adrian HunterAdd a function to determine if an address is in
the kernel. This is based on the kernel functionkernel_ip().
--- tools/perf/util/event.c | 6 +++--- tools/perf/util/machine.c | 23 +++++++++++++++++++++++ tools/perf/util/machine.h | 17 +++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-)
tools/perf/util/event.c +3 -3
@@ -784,9 +784,9 @@ try_again:* "[vdso]" dso, but for now lets use the old trick of looking * in the whole kernel symbol list. */ -if ((long long )al->addr <0 && - cpumode ==PERF_RECORD_MISC_USER && - machine && mg != &machine->kmaps) { +if (cpumode ==PERF_RECORD_MISC_USER && machine && + mg != &machine->kmaps && +machine__kernel_ip (machine, al->addr)) { mg = &machine->kmaps; load_map = true; goto try_again;
tools/perf/util/machine.c +23 -0
@@ -29,6 +29,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter =NULL ; machine->id_hdr_size =0 ; machine->comm_exec = false; + machine->kernel_start =0 ; machine->root_dir =strdup (root_dir);if (machine->root_dir ==NULL )
@@ -1474,3 +1475,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too/* command specified */ return 0 ; } + +int machine__get_kernel_start (struct machine *machine) +{ +struct map *map =machine__kernel_map (machine,MAP__FUNCTION ); +int err =0 ; + +/* +* The only addresses above 2^63 are kernel addresses of a 64-bit +* kernel. Note that addresses are unsigned so that on a 32-bit system +* all addresses including kernel addresses are less than 2^32. In +* that case (32-bit system), if the kernel mapping is unknown, all +* addresses will be assumed to be in user space - see +* machine__kernel_ip(). +*/ + machine->kernel_start =1ULL <<63 ; +if (map) { + err =map__load (map, machine->symbol_filter); +if (map->start) + machine->kernel_start = map->start; + } +return err; +}
tools/perf/util/machine.h +17 -0
@@ -33,6 +33,7 @@ struct machine {struct list_head kernel_dsos;struct map_groups kmaps;struct map *vmlinux_maps[MAP__NR_TYPES ]; +u64 kernel_start;symbol_filter_t symbol_filter; };
@@ -42,6 +43,22 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)return machine->vmlinux_maps[type]; } +int machine__get_kernel_start (struct machine *machine); + +static inline u64 machine__kernel_start (struct machine *machine) +{ +if (!machine->kernel_start) +machine__get_kernel_start (machine); +return machine->kernel_start; +} + +static inline bool machine__kernel_ip (struct machine *machine,u64 ip) +{ +u64 kernel_start =machine__kernel_start (machine); + +return ip >= kernel_start; +} +struct thread *machine__find_thread (struct machine *machine,pid_t pid,pid_t tid); struct comm *machine__thread_exec_comm(struct machine *machine,
Signature · 1 line
1.8.3.2
Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 12 lines
tools/perf/util/machine.c +12
-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
tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 10 lines
tools/perf/util/machine.c +10
-0+* 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; +}
we just recently got machine__get_kernel_start_addr function, I think we want just one function for this
jirka
Adrian Hunter
reviewerRe: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 21 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 17 lines
tools/perf/util/machine.c +17
-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);
Quoted 8 lines
tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 5 lines
tools/perf/util/machine.c +5
-0+if (map->start) + machine->kernel_start = map->start; + } +return err; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for this
They do quite different things.
Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 31 lines · Adrian Hunter
Quoted 21 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 17 lines
tools/perf/util/machine.c +17
-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);Quoted 8 lines
tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 5 lines
tools/perf/util/machine.c +5
-0+if (map->start) + machine->kernel_start = map->start; + } +return err; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for this
Quoted 2 lines
They do quite different things.
so one of those two should have different name
jirka
Adrian Hunter
reviewerRe: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 32 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 29 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 12 lines
tools/perf/util/machine.c +12
-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 tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 10 lines
tools/perf/util/machine.c +10
-0+* 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; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for this
Quoted 4 lines
Quoted 2 lines
They do quite different things.
so one of those two should have different name
Such as?
Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 33 lines · Adrian Hunter
Quoted 32 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 29 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 12 lines
tools/perf/util/machine.c +12
-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 tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 10 lines
tools/perf/util/machine.c +10
-0+* 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; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for this
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
They do quite different things.
so one of those two should have different name
Such as?
dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name
jirka
Adrian Hunter
reviewerRe: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 37 lines · Jiri Olsa
Quoted 36 lines · Adrian Hunter
Quoted 35 lines · Jiri Olsa
Quoted 33 lines · Adrian Hunter
Quoted 21 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 17 lines
tools/perf/util/machine.c +17
-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);Quoted 8 lines
tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499
Quoted 5 lines
tools/perf/util/machine.c +5
-0+if (map->start) + machine->kernel_start = map->start; + } +return err; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for thisThey do quite different things.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
so one of those two should have different name
Such as?
dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name
How about:
machine__get_kernel_start_addr -> machine__get_running_kernel_start
Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()
Quoted 40 lines · Adrian Hunter
Quoted 39 lines · Jiri Olsa
Quoted 38 lines · Adrian Hunter
Quoted 36 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 21 lines · Jiri Olsa
On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:
SNIP
Quoted 17 lines
(quoted diff) +17
-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);Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ if (map->start) + machine->kernel_start = map->start; + } + return err; +}we just recently got
machine__get_kernel_start_addrfunction, I think we want just one function for thisQuoted 2 lines
They do quite different things.
so one of those two should have different name
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Such as?
dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name
How about:
machine__get_kernel_start_addr -> machine__get_running_kernel_start
sounds good
jirka
Adrian Hunter
reviewerPATCH 14/41 perf buildid-cache: Apply force option to copying kcore
In reply to Adrian HunterCurrently a copy of kcore is not made if there is one already with the same modules at the same addresses. Change this to make a copy anyway if the force (-f) option is also used.
--- tools/perf/builtin-buildid-cache.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
tools/perf/builtin-buildid-cache.c +5 -3
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,return ret; } -static int build_id_cache__add_kcore (const char *filename,const char *debugdir) +static int build_id_cache__add_kcore (const char *filename,const char *debugdir, +bool force) {char dir[32 ], sbuildid[BUILD_ID_SIZE *2 +1 ];char from_dir[PATH_MAX ], to_dir[PATH_MAX ];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)scnprintf (to_dir,sizeof (to_dir),"%s/[kernel.kcore]/%s" , debugdir, sbuildid); -if (!build_id_cache__kcore_existing (from_dir, to_dir,sizeof (to_dir))) { +if (!force && + !build_id_cache__kcore_existing (from_dir, to_dir,sizeof (to_dir))) {pr_debug ("same kcore found in %s\n" , to_dir);return 0 ; }
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv, }if (kcore_filename && -build_id_cache__add_kcore (kcore_filename, debugdir)) +build_id_cache__add_kcore (kcore_filename, debugdir, force))pr_warning ("Couldn't add %s\n" , kcore_filename);return ret;
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf buildid-cache: Apply force option to copying kcore
perf buildid-cache: Apply force option to copying kcore
Commit-ID: 5173fbb8a11b2857aeec9e5f4e9568d4e1b84dbd Gitweb: http://git.kernel.org/tip/5173fbb8a11b2857aeec9e5f4e9568d4e1b84dbd Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:38 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:35 -0300
perf buildid-cache: Apply force option to copying kcore
Currently a copy of kcore is not made if there is one already with the same modules at the same addresses.
Change this to make a copy anyway if the force (-f) option is also used.
--- tools/perf/builtin-buildid-cache.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
tools/perf/builtin-buildid-cache.c +5 -3
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,return ret; } -static int build_id_cache__add_kcore (const char *filename,const char *debugdir) +static int build_id_cache__add_kcore (const char *filename,const char *debugdir, +bool force) {char dir[32 ], sbuildid[BUILD_ID_SIZE *2 +1 ];char from_dir[PATH_MAX ], to_dir[PATH_MAX ];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)scnprintf (to_dir,sizeof (to_dir),"%s/[kernel.kcore]/%s" , debugdir, sbuildid); -if (!build_id_cache__kcore_existing (from_dir, to_dir,sizeof (to_dir))) { +if (!force && + !build_id_cache__kcore_existing (from_dir, to_dir,sizeof (to_dir))) {pr_debug ("same kcore found in %s\n" , to_dir);return 0 ; }
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv, }if (kcore_filename && -build_id_cache__add_kcore (kcore_filename, debugdir)) +build_id_cache__add_kcore (kcore_filename, debugdir, force))pr_warning ("Couldn't add %s\n" , kcore_filename);return ret;
Adrian Hunter
reviewerPATCH 15/41 perf script: Improve srcline display for BTS
In reply to Adrian HunterChange the order of the output to put the srcline last. e.g. old format:
4028fc main+0x2c (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0 set_program_name+0x0 (/bin/ls)
new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)
/build/buildd/coreutils-8.20/src/ls.c:1269
--- tools/perf/builtin-script.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -5
@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event, struct addr_location *al) {struct perf_event_attr *attr = &evsel->attr; +bool print_srcline_last = false;/* print branch_from information */ if (PRINT_FIELD (IP )) { -if (!symbol_conf.use_callchain) -printf (" " ); -else +unsigned int print_opts = output[attr->type].print_ip_opts; + +if (symbol_conf.use_callchain && sample->callchain) {printf ("\n" ); -perf_evsel__print_ip (evsel, sample, al, - output[attr->type].print_ip_opts, + }else { +printf (" " ); +if (print_opts &PRINT_IP_OPT_SRCLINE ) { + print_srcline_last = true; + print_opts &= ~PRINT_IP_OPT_SRCLINE ; + } + } +perf_evsel__print_ip (evsel, sample, al, print_opts,PERF_MAX_STACK_DEPTH ); }
@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event, !output[attr->type].user_set))print_sample_addr (event, sample, al->machine, thread, attr); +if (print_srcline_last) +map__fprintf_srcline (al->map, al->addr,"\n " , stdout); +printf ("\n" ); }
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 15/41] perf script: Improve srcline display for BTS
Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Change the order of the output to put the srcline last. e.g. old format:
4028fc main+0x2c (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0
set_program_name+0x0(/bin/ls)new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269
David,
Can I have your acked-by?
Adrian,
Can you elaborate on why this is an improvement?
- Arnaldo
Quoted 49 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/builtin-script.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)tools/perf/builtin-script.c +15
-5@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event, struct addr_location *al) {struct perf_event_attr *attr = &evsel->attr; +bool print_srcline_last = false;/* print branch_from information */ if (PRINT_FIELD (IP )) { -if (!symbol_conf.use_callchain) -printf (" " ); -else +unsigned int print_opts = output[attr->type].print_ip_opts; + +if (symbol_conf.use_callchain && sample->callchain) {printf ("\n" ); -perf_evsel__print_ip (evsel, sample, al, - output[attr->type].print_ip_opts, + }else { +printf (" " ); +if (print_opts &PRINT_IP_OPT_SRCLINE ) { + print_srcline_last = true; + print_opts &= ~PRINT_IP_OPT_SRCLINE ; + } + } +perf_evsel__print_ip (evsel, sample, al, print_opts,PERF_MAX_STACK_DEPTH ); }@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event, !output[attr->type].user_set))print_sample_addr (event, sample, al->machine, thread, attr); +if (print_srcline_last) +map__fprintf_srcline (al->map, al->addr,"\n " , stdout); +printf ("\n" ); }Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 15/41] perf script: Improve srcline display for BTS
Quoted 12 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:
Quoted 10 lines
Change the order of the output to put the srcline last. e.g. old format:
4028fc main+0x2c (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0
set_program_name+0x0(/bin/ls)new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269
Quoted 7 lines
David,
Can I have your acked-by?
Adrian,
Can you elaborate on why this is an improvement?
It puts the branch 'from address' and 'to address' on the same line, which is how it would be without the source line reference. So it makes it consistent and much easier to read.
Quoted 52 lines
- Arnaldo
Quoted 49 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/builtin-script.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)tools/perf/builtin-script.c +15
-6@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event, struct addr_location *al) {struct perf_event_attr *attr = &evsel->attr; +bool print_srcline_last = false;/* print branch_from information */ if (PRINT_FIELD (IP )) { -if (!symbol_conf.use_callchain) -printf (" " ); -else +unsigned int print_opts = output[attr->type].print_ip_opts; + +if (symbol_conf.use_callchain && sample->callchain) {printf ("\n" ); -perf_evsel__print_ip (evsel, sample, al, - output[attr->type].print_ip_opts, + }else { +printf (" " ); +if (print_opts &PRINT_IP_OPT_SRCLINE ) { + print_srcline_last = true; + print_opts &= ~PRINT_IP_OPT_SRCLINE ; + } + } +perf_evsel__print_ip (evsel, sample, al, print_opts,PERF_MAX_STACK_DEPTH ); }@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event, !output[attr->type].user_set))print_sample_addr (event, sample, al->machine, thread, attr); +if (print_srcline_last) +map__fprintf_srcline (al->map, al->addr,"\n " , stdout); +printf ("\n" ); } --1.8.3.2
Re: [PATCH 15/41] perf script: Improve srcline display for BTS
In reply to Arnaldo Carvalho de MeloQuoted 7 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:
Quoted 6 lines
Change the order of the output to put the srcline last. e.g. old format:
4028fc main+0x2c (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0
set_program_name+0x0(/bin/ls)
Quoted 8 lines
Quoted 4 lines
new format:
4028fc main+0x2c (/bin/ls) => 40d8a0 set_program_name+0x0 (/bin/ls)/build/buildd/coreutils-8.20/src/ls.c:1269
David,
Can I have your acked-by?
I believe Stephane is the one who wrote print_sample_bts and bts analysis pieces.
David
Adrian Hunter
reviewerPATCH 16/41 perf script: Do not print dangling '=>' for BTS
In reply to Adrian HunterWhen using:
perf record -e branches:u -c1
perf script -f ip
lines are displayed like:
ffffffff813b23d5 =>
Change so that the dangling '=>' does not appear.
--- tools/perf/builtin-script.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-script.c +3 -3
@@ -446,13 +446,13 @@ static void print_sample_bts(union perf_event *event, PERF_MAX_STACK_DEPTH); } -printf (" => " ); -/* print branch_to information */ if (PRINT_FIELD (ADDR ) || ((evsel->attr.sample_type &PERF_SAMPLE_ADDR ) && - !output[attr->type].user_set)) + !output[attr->type].user_set)) { +printf (" => " );print_sample_addr (event, sample, al->machine, thread, attr); + }if (print_srcline_last)map__fprintf_srcline (al->map, al->addr,"\n " , stdout);
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 17/41 perf tools: Record whether a dso is 64-bit
In reply to Adrian HunterAdd a flag to 'struct dso' to record if the dso is 64-bit or not. Update the flag when reading the ELF.
This is needed for instruction decoding. For example, x86 instruction decoding depends on whether or not the 64-bit instruction set is used.
--- tools/perf/util/dso.c | 1 + tools/perf/util/dso.h | 1 + tools/perf/util/symbol-elf.c | 3 +++ tools/perf/util/symbol-minimal.c | 22 ++++++++++++++++++++++ tools/perf/util/symbol.c | 1 + tools/perf/util/symbol.h | 1 + 6 files changed, 29 insertions(+)
tools/perf/util/dso.c +1 -0
@@ -703,6 +703,7 @@ struct dso *dso__new(const char *name) dso->data.fd =-1 ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; + dso->is_64_bit = (sizeof (void *) ==8 ); dso->loaded =0 ; dso->rel =0 ; dso->sorted_by_name =0 ;
tools/perf/util/dso.h +1 -0
@@ -90,6 +90,7 @@ struct dso { u8 annotate_warned:1; u8 short_name_allocated:1; u8 long_name_allocated:1; + u8 is_64_bit:1;u8 sorted_by_name;u8 loaded;u8 rel;
tools/perf/util/symbol-elf.c +3 -0
@@ -599,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, goto out_elf_end; } + ss->is_64_bit = (gelf_getclass (elf) ==ELFCLASS64 ); + ss->symtab =elf_section_by_name (elf, &ehdr, &ss->symshdr,".symtab" ,NULL );if (ss->symshdr.sh_type !=SHT_SYMTAB )
@@ -699,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,bool remap_kernel = false, adjust_kernel_syms = false; dso->symtab_type = syms_ss->type; + dso->is_64_bit = syms_ss->is_64_bit; dso->rel = syms_ss->ehdr.e_type ==ET_REL ;/*
tools/perf/util/symbol-minimal.c +22 -0
@@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,return 0 ; } +static int fd__is_64_bit (int fd) +{ +u8 e_ident[EI_NIDENT ]; + +if (lseek (fd,0 ,SEEK_SET )) +return -1 ; + +if (readn (fd, e_ident,sizeof (e_ident)) !=sizeof (e_ident)) +return -1 ; + +if (memcmp (e_ident,ELFMAG ,SELFMAG ) || + e_ident[EI_VERSION ] !=EV_CURRENT ) +return -1 ; + +return e_ident[EI_CLASS ] ==ELFCLASS64 ; +} + int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, int kmodule __maybe_unused) {unsigned char *build_id[BUILD_ID_SIZE ]; +int ret; + + ret =fd__is_64_bit (ss->fd); +if (ret >=0 ) + dso->is_64_bit = ret;if (filename__read_build_id (ss->name, build_id,BUILD_ID_SIZE ) >0 ) {dso__set_build_id (dso, build_id);
tools/perf/util/symbol.c +1 -0
@@ -1064,6 +1064,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, &is_64_bit);if (err) goto out_err; + dso->is_64_bit = is_64_bit;if (list_empty (&md.maps)) { err = -EINVAL ;
tools/perf/util/symbol.h +1 -0
@@ -215,6 +215,7 @@ struct symsrc {GElf_Shdr dynshdr;bool adjust_symbols; +bool is_64_bit;#endif };
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf symbols: Record whether a dso is 64-bit
perf symbols: Record whether a dso is 64-bit
Commit-ID: c6d8f2a4a0c5e366330a6a2a94c06b652f4ca554 Gitweb: http://git.kernel.org/tip/c6d8f2a4a0c5e366330a6a2a94c06b652f4ca554 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:41 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:35 -0300
perf symbols: Record whether a dso is 64-bit
Add a flag to 'struct dso' to record if the dso is 64-bit or not. Update the flag when reading the ELF.
This is needed for instruction decoding. For example, x86 instruction decoding depends on whether or not the 64-bit instruction set is used.
--- tools/perf/util/dso.c | 1 + tools/perf/util/dso.h | 1 + tools/perf/util/symbol-elf.c | 3 +++ tools/perf/util/symbol-minimal.c | 22 ++++++++++++++++++++++ tools/perf/util/symbol.c | 1 + tools/perf/util/symbol.h | 1 + 6 files changed, 29 insertions(+)
tools/perf/util/dso.c +1 -0
@@ -703,6 +703,7 @@ struct dso *dso__new(const char *name) dso->data.fd =-1 ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; + dso->is_64_bit = (sizeof (void *) ==8 ); dso->loaded =0 ; dso->rel =0 ; dso->sorted_by_name =0 ;
tools/perf/util/dso.h +1 -0
@@ -90,6 +90,7 @@ struct dso { u8 annotate_warned:1; u8 short_name_allocated:1; u8 long_name_allocated:1; + u8 is_64_bit:1;u8 sorted_by_name;u8 loaded;u8 rel;
tools/perf/util/symbol-elf.c +3 -0
@@ -599,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, goto out_elf_end; } + ss->is_64_bit = (gelf_getclass (elf) ==ELFCLASS64 ); + ss->symtab =elf_section_by_name (elf, &ehdr, &ss->symshdr,".symtab" ,NULL );if (ss->symshdr.sh_type !=SHT_SYMTAB )
@@ -699,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,bool remap_kernel = false, adjust_kernel_syms = false; dso->symtab_type = syms_ss->type; + dso->is_64_bit = syms_ss->is_64_bit; dso->rel = syms_ss->ehdr.e_type ==ET_REL ;/*
tools/perf/util/symbol-minimal.c +22 -0
@@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,return 0 ; } +static int fd__is_64_bit (int fd) +{ +u8 e_ident[EI_NIDENT ]; + +if (lseek (fd,0 ,SEEK_SET )) +return -1 ; + +if (readn (fd, e_ident,sizeof (e_ident)) !=sizeof (e_ident)) +return -1 ; + +if (memcmp (e_ident,ELFMAG ,SELFMAG ) || + e_ident[EI_VERSION ] !=EV_CURRENT ) +return -1 ; + +return e_ident[EI_CLASS ] ==ELFCLASS64 ; +} + int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, int kmodule __maybe_unused) {unsigned char *build_id[BUILD_ID_SIZE ]; +int ret; + + ret =fd__is_64_bit (ss->fd); +if (ret >=0 ) + dso->is_64_bit = ret;if (filename__read_build_id (ss->name, build_id,BUILD_ID_SIZE ) >0 ) {dso__set_build_id (dso, build_id);
tools/perf/util/symbol.c +1 -0
@@ -1065,6 +1065,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, &is_64_bit);if (err) goto out_err; + dso->is_64_bit = is_64_bit;if (list_empty (&md.maps)) { err = -EINVAL ;
tools/perf/util/symbol.h +1 -0
@@ -216,6 +216,7 @@ struct symsrc {GElf_Shdr dynshdr;bool adjust_symbols; +bool is_64_bit;#endif };
Adrian Hunter
reviewerPATCH 18/41 perf tools: Record whether a dso has data
In reply to Adrian HunterAdd 'data_status' to record whether a dso has data (i.e. an object file) as follows:
dso->data_status meaning ---------------------------------- 0 don't know -1 no data 1 has data
--- tools/perf/util/dso.c | 5 ++++- tools/perf/util/dso.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +4 -1
@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size) { -if (dso__data_fd (dso, machine) <0 ) +if (dso__data_fd (dso, machine) <0 ) { + dso->data.data_status =-1 ;return -1 ; + } + dso->data.data_status =1 ;return data_read_offset (dso, offset, data, size); }
tools/perf/util/dso.h +1 -0
@@ -104,6 +104,7 @@ struct dso {struct {struct rb_root cache;int fd; +int data_status;size_t file_size;struct list_head open_entry; } data;
Signature · 1 line
1.8.3.2
Re: [PATCH 18/41] perf tools: Record whether a dso has data
Quoted 8 lines · Adrian Hunter
Add '
data_status' to record whether a dso has data (i.e. an object file) as follows:dso->data_status meaning ---------------------------------- 0 don't know -1 no data 1 has data
please add enum for this
Quoted 12 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/dso.c | 5 ++++- tools/perf/util/dso.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-)tools/perf/util/dso.c +0
-0
tools/perf/util/dso.c static ssize_t data_read_offset(struct dso *dso, u64 offset, · line 563
Quoted 9 lines
tools/perf/util/dso.c +4
-1@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size) { -if (dso__data_fd (dso, machine) <0 ) +if (dso__data_fd (dso, machine) <0 ) { + dso->data.data_status =-1 ;return -1 ; + } + dso->data.data_status =1 ;
we have more callers to dso__data_fd, so I think we want to setup dso->data.data_status within dso__data_fd
jirka
Adrian Hunter
reviewercover perf tools: Fix incorrect fd error comparison
Quoted 10 lines · Adrian Hunter
Quoted 8 lines
Add '
data_status' to record whether a dso has data (i.e. an object file) as follows:dso->data_status meaning ---------------------------------- 0 don't know -1 no data 1 has dataplease add enum for this
Ok
Quoted 17 lines
Quoted 17 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/dso.c | 5 ++++- tools/perf/util/dso.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-)tools/perf/util/dso.c +0
-1@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size) { -if (dso__data_fd (dso, machine) <0 )
Quoted 8 lines
tools/perf/util/dso.c static ssize_t data_read_offset(struct dso *dso, u64 offset, · line 563
Quoted 5 lines
tools/perf/util/dso.c +4
-0+if (dso__data_fd (dso, machine) <0 ) { + dso->data.data_status =-1 ;return -1 ; + } + dso->data.data_status =1 ;we have more callers to
dso__data_fd, so I think we want to setupdso->data.data_statuswithindso__data_fd
Ok. Here are 2 patches because I noticed another thing.
Adrian Hunter (2):
perf tools: Fix incorrect fd error comparison perf tools: Record whether a dso has data
tools/perf/util/dso.c | 27 +++++++++++++++++---------- tools/perf/util/dso.h | 7 +++++++ 2 files changed, 24 insertions(+), 10 deletions(-)
Adrian Hunter
reviewerPATCH 1/2 perf tools: Fix incorrect fd error comparison
Zero is a valid fd. Error comparison should check for negative fd.
--- tools/perf/util/dso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/dso.c +1 -1
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine) {int fd =__open_dso (dso, machine); -if (fd >0 ) { +if (fd >=0 ) {dso__list_add (dso);/* * Check if we crossed the allowed number
Signature · 1 line
1.8.3.2
Re: [PATCH 1/2] perf tools: Fix incorrect fd error comparison
Quoted 4 lines · Adrian Hunter
Zero is a valid fd. Error comparison should check for negative fd.
Signed-off-by Adrian Hunter <[email protected]>
thanks,
jirka
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Fix incorrect fd error comparison
In reply to Adrian Hunterperf tools: Fix incorrect fd error comparison
Commit-ID: a6f6ae99f12e8154d5cde6e8366fc228f68d6ae5 Gitweb: http://git.kernel.org/tip/a6f6ae99f12e8154d5cde6e8366fc228f68d6ae5 Author: Adrian Hunter <[email protected]> AuthorDate: Thu, 17 Jul 2014 11:43:09 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 22 Jul 2014 10:18:57 -0300
perf tools: Fix incorrect fd error comparison
Zero is a valid fd. Error comparison should check for negative fd.
--- tools/perf/util/dso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/dso.c +1 -1
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine) {int fd =__open_dso (dso, machine); -if (fd >0 ) { +if (fd >=0 ) {dso__list_add (dso);/* * Check if we crossed the allowed number
Adrian Hunter
reviewerPATCH v2 2/2 perf tools: Record whether a dso has data
In reply to Adrian HunterAdd 'data_status' to record whether a dso has data (i.e. an object file) as follows:
dso->data_status meaning ---------------------------------- 0 don't know -1 no data 1 has data
--- tools/perf/util/dso.c | 25 ++++++++++++++++--------- tools/perf/util/dso.h | 7 +++++++ 2 files changed, 23 insertions(+), 9 deletions(-)
tools/perf/util/dso.c +16 -9
@@ -332,25 +332,28 @@ int dso__data_fd(struct dso *dso, struct machine *machine)int i =0 ;if (dso->data.fd >=0 ) -return dso->data.fd; + goto out;if (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ) { dso->data.fd =open_dso (dso, machine); -return dso->data.fd; + goto out; }do { -int fd; - dso->binary_type = binary_type_data[i++]; - fd =open_dso (dso, machine); -if (fd >=0 ) -return dso->data.fd = fd; + dso->data.fd =open_dso (dso, machine); +if (dso->data.fd >=0 ) + goto out; }while (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ); +out: +if (dso->data.fd >=0 ) + dso->data.data_status =DSO_DATA_STATUS_OK ; +else + dso->data.data_status =DSO_DATA_STATUS_ERROR ; -return -EINVAL ; +return dso->data.fd; } static void
@@ -556,8 +559,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,ssize_t dso__data_read_offset (struct dso *dso,struct machine *machine,u64 offset,u8 *data,ssize_t size) { -if (dso__data_fd (dso, machine) <0 ) +if (dso__data_fd (dso, machine) <0 ) { + dso->data.data_status =-1 ;return -1 ; + } + dso->data.data_status =1 ;return data_read_offset (dso, offset, data, size); }
@@ -701,6 +707,7 @@ struct dso *dso__new(const char *name) dso->symbols[i] = dso->symbol_names[i] =RB_ROOT ; dso->data.cache =RB_ROOT ; dso->data.fd =-1 ; + dso->data.data_status =DSO_DATA_STATUS_UNKNOWN ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->is_64_bit = (sizeof (void *) ==8 );
tools/perf/util/dso.h +7 -0
@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, }; +enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int data_status;size_t file_size;struct list_head open_entry; } data;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH v3 1/1 perf tools: Record whether a dso has data
Add 'data_status' to record whether a dso has data (i.e. an object file)
--- tools/perf/util/dso.c | 20 ++++++++++++-------- tools/perf/util/dso.h | 7 +++++++ 2 files changed, 19 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +12 -8
@@ -332,25 +332,28 @@ int dso__data_fd(struct dso *dso, struct machine *machine)int i =0 ;if (dso->data.fd >=0 ) -return dso->data.fd; + goto out;if (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ) { dso->data.fd =open_dso (dso, machine); -return dso->data.fd; + goto out; }do { -int fd; - dso->binary_type = binary_type_data[i++]; - fd =open_dso (dso, machine); -if (fd >=0 ) -return dso->data.fd = fd; + dso->data.fd =open_dso (dso, machine); +if (dso->data.fd >=0 ) + goto out; }while (dso->binary_type !=DSO_BINARY_TYPE__NOT_FOUND ); +out: +if (dso->data.fd >=0 ) + dso->data.data_status =DSO_DATA_STATUS_OK ; +else + dso->data.data_status =DSO_DATA_STATUS_ERROR ; -return -EINVAL ; +return dso->data.fd; } static void
@@ -701,6 +704,7 @@ struct dso *dso__new(const char *name) dso->symbols[i] = dso->symbol_names[i] =RB_ROOT ; dso->data.cache =RB_ROOT ; dso->data.fd =-1 ; + dso->data.data_status =DSO_DATA_STATUS_UNKNOWN ; dso->symtab_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->binary_type =DSO_BINARY_TYPE__NOT_FOUND ; dso->is_64_bit = (sizeof (void *) ==8 );
tools/perf/util/dso.h +7 -0
@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, }; +enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int data_status;size_t file_size;struct list_head open_entry; } data;
Signature · 1 line
1.8.3.2
Re: [PATCH V3] perf tools: Record whether a dso has data
Quoted 2 lines · Adrian Hunter
Add '
data_status' to record whether a dso has data (i.e. an object file)
I might have seen it in your last patsent, but forgot.. what is this data_status going to be used for?
SNIP
Quoted 18 lines
tools/perf/util/dso.h +6
-0@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, }; +enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \
tools/perf/util/dso.h struct dso { · line 113
Quoted 4 lines
tools/perf/util/dso.h +1
-0@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int data_status;
also please call it just 'status' it's already in 'data' struct
thanks,
jirka
Adrian Hunter
reviewerRe: [PATCH V3] perf tools: Record whether a dso has data
Quoted 6 lines · Jiri Olsa
Quoted 2 lines · Adrian Hunter
Add '
data_status' to record whether a dso has data (i.e. an object file)I might have seen it in your last patsent, but forgot.. what is this
data_statusgoing to be used for?
I have changed it a bit in the latest posting. It was originally for two purposes:
1. to prevent repeatedly attempting to open a file that
was not there (very time consuming if you do it millions of times)
2. to report the error exactly once
But I realized it did not meet the 2nd objective so I have added another patch that does. See "perf tools: Add dso__data_status_seen()"
Quoted 11 lines
SNIP
Quoted 8 lines
tools/perf/util/dso.h +0
-0@@ -40,6 +40,12 @@ enum dso_swap_type { DSO_SWAP__YES, };
Quoted 16 lines
Quoted 10 lines
tools/perf/util/dso.h +6
-0+enum dso_data_status { +DSO_DATA_STATUS_ERROR =-1 , +DSO_DATA_STATUS_UNKNOWN =0 , +DSO_DATA_STATUS_OK =1 , +}; +#define DSO__SWAP (dso, type, val) \ ({ \ type ____r = val; \tools/perf/util/dso.h struct dso { · line 113
Quoted 4 lines
tools/perf/util/dso.h +1
-0@@ -104,6 +110,7 @@ struct dso {struct {struct rb_root cache;int fd; +int data_status;also please call it just 'status' it's already in 'data' struct
I made that change too.
Adrian Hunter
reviewerPATCH 19/41 perf tools: Do not attempt to read data from kallsyms
In reply to Adrian HunterRecord kallsyms binary type so that tools will not attempt to read binary data from it.
--- tools/perf/util/symbol.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/symbol.c +2 -0
@@ -1663,6 +1663,7 @@ do_kallsyms:free (kallsyms_allocated_filename);if (err >0 && !dso__is_kcore (dso)) { + dso->binary_type =DSO_BINARY_TYPE__KALLSYMS ;dso__set_long_name (dso,"[kernel.kallsyms]" , false);map__fixup_start (map);map__fixup_end (map);
@@ -1710,6 +1711,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,if (err >0 )pr_debug ("Using %s for symbols\n" , kallsyms_filename);if (err >0 && !dso__is_kcore (dso)) { + dso->binary_type =DSO_BINARY_TYPE__GUEST_KALLSYMS ;machine__mmap_name (machine, path,sizeof (path));dso__set_long_name (dso,strdup (path), true);map__fixup_start (map);
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf symbols: Do not attempt to read data from kallsyms
perf symbols: Do not attempt to read data from kallsyms
Commit-ID: bdac0bcf779250e89b96d4a3f381ebaf02c2f4a9 Gitweb: http://git.kernel.org/tip/bdac0bcf779250e89b96d4a3f381ebaf02c2f4a9 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:43 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:35 -0300
perf symbols: Do not attempt to read data from kallsyms
Record kallsyms binary type so that tools will not attempt to read binary data from it.
--- tools/perf/util/symbol.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/symbol.c +2 -0
@@ -1664,6 +1664,7 @@ do_kallsyms:free (kallsyms_allocated_filename);if (err >0 && !dso__is_kcore (dso)) { + dso->binary_type =DSO_BINARY_TYPE__KALLSYMS ;dso__set_long_name (dso,"[kernel.kallsyms]" , false);map__fixup_start (map);map__fixup_end (map);
@@ -1711,6 +1712,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,if (err >0 )pr_debug ("Using %s for symbols\n" , kallsyms_filename);if (err >0 && !dso__is_kcore (dso)) { + dso->binary_type =DSO_BINARY_TYPE__GUEST_KALLSYMS ;machine__mmap_name (machine, path,sizeof (path));dso__set_long_name (dso,strdup (path), true);map__fixup_start (map);
Adrian Hunter
reviewerPATCH 20/41 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
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 10 lines · Adrian Hunter
This 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.
I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
thanks,
jirka
Adrian Hunter
reviewerRe: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 7 lines · Jiri Olsa
Quoted 6 lines · Adrian Hunter
This enables a PMU event to be specified in the form:
pmu//which is effectively the same as:
Quoted 7 lines
Quoted 4 lines
pmu/config=0/This patch is a precursor to defining
default config for a PMU.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 10 lines · Adrian Hunter
Quoted 9 lines · Jiri Olsa
Quoted 8 lines · Adrian Hunter
This enables a PMU event to be specified in the form:
pmu//which is effectively the same as:
pmu/config=0/
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
This patch is a precursor to defining
default config for a PMU.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
jirka
Adrian Hunter
reviewerRe: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 14 lines · Jiri Olsa
Quoted 13 lines · Adrian Hunter
Quoted 12 lines · Jiri Olsa
Quoted 10 lines · Adrian Hunter
This 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.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
The parser uses various tricks to decide what kind of event the event name actually is e.g. colons indicate a tracepoint.
If you are asking why the parser isn't smart enough to know the event name is a PMU name, I guess it is either to keep the namespaces separate, or because it was easier to program it that way.
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · Adrian Hunter
This 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.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//
which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/
I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
which gives the same result
thanks,
jirka
Adrian Hunter
reviewerRe: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 35 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · Adrian Hunter
This 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.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/
Quoted 8 lines
I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
which gives the same result
The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 43 lines · Adrian Hunter
Quoted 42 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · Adrian Hunter
This 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.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
Quoted 9 lines
Quoted 1 line
which gives the same result
The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.
I dont follow, could u provide some example?
why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on perf_event_attr.. and the kernel knows best what's supported in its version..
jirka
Adrian Hunter
reviewerRe: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
Quoted 54 lines · Jiri Olsa
Quoted 43 lines · Adrian Hunter
Quoted 42 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · Adrian Hunter
This 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.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
Quoted 9 lines
Quoted 1 line
which gives the same result
The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.
Quoted 1 line
I dont follow, could u provide some example?
Imagine that the 'tsc' term did not exist. Intel PT trace data would not contain TSC packets, and the decoder would not know how to decode them. Then imagine that a new version of the hardware adds 'tsc'. It is such a useful feature that we want it by default, but older versions of the tools don't know how to decode it, so the kernel cannot turn it on by default.
Quoted 5 lines
why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on
perf_event_attr.. and the kernel knows best what's supported in its version..
It is similar to why the kernel does not select mmap2 by default. The kernel doesn't know whether the tool supports it.
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
On Tue, Sep 02, 2014 at 08:39:56AM +0300, Adrian Hunter wrote:
SNIP
Quoted 29 lines
Quoted 19 lines
Quoted 9 lines
Quoted 9 lines
-e intel_pt/tsc=1,noretcomp=0/
I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
Quoted 9 lines
Quoted 1 line
which gives the same result
The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.
Quoted 1 line
I dont follow, could u provide some example?
Imagine that the 'tsc' term did not exist. Intel PT trace data would not contain TSC packets, and the decoder would not know how to decode them. Then imagine that a new version of the hardware adds 'tsc'. It is such a useful feature that we want it by default, but older versions of the tools don't know how to decode it, so the kernel cannot turn it on by default.
Quoted 1 line
Quoted 8 lines
Quoted 4 lines
why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on
perf_event_attr.. and the kernel knows best what's supported in its version..It is similar to why the kernel does not select mmap2 by default. The kernel doesn't know whether the tool supports it.
ook, could you please add some kind of this explanation to the changelog?
thanks,
jirka
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
In reply to Jiri OlsaEm Sat, Aug 30, 2014 at 10:53:10AM +0200, Jiri Olsa escreveu:
Quoted 35 lines · Adrian Hunter
Quoted 18 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 15 lines · Jiri Olsa
Quoted 14 lines · Adrian Hunter
Quoted 10 lines
This 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.I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.
right, so why do we want to parse 'pmu//' as an event string? ;-)
I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'
so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/
Quoted 8 lines
I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
which gives the same result
So you propose that we start maintaining some table of aliases that would be installed by default, etc? "krava" would not be a good name, I think (:-)), so in this case we would have something like:
defaults_intel_pt: "tsc=1,noretcomp=0" -e intel_pt/defaults_intel_pt/
Which of course gets redundant/long, so, using what Adrian suggests, we would instead not pass anything between the slashes, and that would mean "default_" concatenated with the name of the PMU used, so it would become:
-e intel_pt//
that would be equivalent to:
-e intel_pt/defaults_intel_pt/
and also to:
-e intel_pt/tsc=1,noretcomp=0/
?
I have not looked at the implementation, this is all just from the information I skimmed in this thread.
- Arnaldo
Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms
On Mon, Sep 01, 2014 at 12:51:42PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 25 lines
Quoted 5 lines
krava alias: "tsc=1,noretcomp=0"
-e intel_pt/krava/
which gives the same result
So you propose that we start maintaining some table of aliases that would be installed by default, etc? "krava" would not be a good name, I think (:-)), so in this case we would have something like:
defaults_intel_pt: "tsc=1,noretcomp=0" -e intel_pt/defaults_intel_pt/Which of course gets redundant/long, so, using what Adrian suggests, we would instead not pass anything between the slashes, and that would mean "
default_" concatenated with the name of the PMU used, so it would become:-e intel_pt//that would be equivalent to:
-e intel_pt/defaults_intel_pt/
Quoted 8 lines
and also to:
-e intel_pt/tsc=1,noretcomp=0/?
I have not looked at the implementation, this is all just from the information I skimmed in this thread.
well I meant that we already have following directory:
/sys/devices/cpu/events
for aliases.. files with format definitions (even partial) I can imagine 'default' file there doing the same job for the default format set
but I just could be missing something which is not apparent from changelog ;-)
jirka
Adrian Hunter
reviewerPATCH 21/41 perf tools: Let default config be defined for a PMU
In reply to Adrian HunterThis allows default config terms to be provided
for a PMU. So, for example, when the Intel PT
PMU is added, it will be possible to specify:
intel_pt//
which will be the same as:
intel_pt/tsc=1,noretcomp=0/
meaning that the trace should contain
TSC timestamps and perform 'return
compression'.
An important consideration of this
patch is that it must be possible
to overwrite the default values.
That has meant changing the logic
so that a zero value can replace
a non-zero value.
--- tools/perf/tests/pmu.c | 2 +- tools/perf/util/parse-events.c | 7 ++++++- tools/perf/util/pmu.c | 42 ++++++++++++++++++++++++++---------------- tools/perf/util/pmu.h | 9 ++++++++- 4 files changed, 41 insertions(+), 19 deletions(-)
tools/perf/tests/pmu.c +1 -1
@@ -152,7 +152,7 @@ int test__pmu(void)if (ret)break ; - ret =perf_pmu__config_terms (&formats, &attr, terms); + ret =perf_pmu__config_terms (&formats, &attr, terms, false);if (ret)break ;
tools/perf/util/parse-events.c +6 -1
@@ -642,7 +642,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,if (!pmu)return -EINVAL ; -memset (&attr,0 ,sizeof (attr)); +if (pmu->default_config) { +memcpy (&attr, pmu->default_config, +sizeof (struct perf_event_attr )); + }else { +memset (&attr,0 ,sizeof (attr)); + }if (!head_config) { attr.type = pmu->type;
tools/perf/util/pmu.c +26 -16
105 lines not on this page · raw message
tools/perf/util/pmu.h +8 -1
@@ -13,9 +13,12 @@ enum {#define PERF_PMU_FORMAT_BITS 64 +struct perf_event_attr ; +struct perf_pmu {char *name;__u32 type; +struct perf_event_attr *default_config;struct cpu_map *cpus;struct list_head format;struct list_head aliases;
@@ -27,7 +30,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, struct list_head *head_terms);int perf_pmu__config_terms (struct list_head *formats,struct perf_event_attr *attr, -struct list_head *head_terms); +struct list_head *head_terms, +bool zero);int perf_pmu__check_alias (struct perf_pmu *pmu,struct list_head *head_terms,const char **unit,double *scale); struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
@@ -46,4 +50,7 @@ void print_pmu_events(const char *event_glob, bool name_only);bool pmu_have_event (const char *pname,const char *name);int perf_pmu__test (void ); + +struct perf_event_attr *perf_pmu__get_default_config (struct perf_pmu *pmu); +#endif /* __PMU_H */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 22/41 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
Adrian Hunter
reviewerPATCH 23/41 perf tools: Add dsos__hit_all()
In reply to Adrian HunterAdd ability to mark all dsos as hit.
This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.
--- tools/perf/util/header.c | 41 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 2 ++ 2 files changed, 43 insertions(+)
tools/perf/util/header.c +41 -0
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,return write_padded (fd, name, name_len +1 , len); } +static int __dsos__hit_all (struct list_head *head) +{ +struct dso *pos; + +list_for_each_entry (pos, head, node) + pos->hit = true; + +return 0 ; +} + +static int machine__hit_all_dsos (struct machine *machine) +{ +int err; + + err =__dsos__hit_all (&machine->kernel_dsos); +if (err) +return err; + +return __dsos__hit_all (&machine->user_dsos); +} + +int dsos__hit_all (struct perf_session *session) +{ +struct rb_node *nd; +int err; + + err =machine__hit_all_dsos (&session->machines.host); +if (err) +return err; + +for (nd =rb_first (&session->machines.guests); nd; nd =rb_next (nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + + err =machine__hit_all_dsos (pos); +if (err) +return err; + } + +return 0 ; +} +static int __dsos__write_buildid_table (struct list_head *head,struct machine *machine,pid_t pid,u16 misc,int fd)
tools/perf/util/header.h +2 -0
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool, struct perf_session *session);bool is_perf_magic (u64 magic); +int dsos__hit_all (struct perf_session *session); +/* * arch specific callback */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 24/41 perf tools: Add cpu to struct thread
In reply to Adrian HunterTools may wish to track on which cpu a thread
is running. Add 'cpu' to struct thread for
that purpose.
This will be used to determine the cpu when
decoding a per-thread Instruction Trace.
--- tools/perf/util/thread.c | 1 + tools/perf/util/thread.h | 1 + 2 files changed, 2 insertions(+)
tools/perf/util/thread.c +1 -0
@@ -69,6 +69,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->pid_ = pid; thread->tid = tid; thread->ppid =-1 ; + thread->cpu =-1 ;INIT_LIST_HEAD (&thread->comm_list); comm_str =malloc (32 );
tools/perf/util/thread.h +1 -0
@@ -17,6 +17,7 @@ struct thread {pid_t pid_;/* Not all tools update this */ pid_t tid;pid_t ppid; +int cpu;char shortname[3 ];bool comm_set;bool dead;/* if set thread has exited */
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 24/41] perf tools: Add cpu to struct thread
Em Mon, Jul 14, 2014 at 01:02:48PM +0300, Adrian Hunter escreveu:
Quoted 6 lines
Tools may wish to track on which cpu a thread
is running. Add 'cpu' to struct thread for
that purpose.This will be used to determine the cpu when
decoding a per-thread Instruction Trace.
Humm, is this the last cpu we got some event telling the cpu was running on? Continuing looking at the patches...
- Arnaldo
Quoted 32 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/thread.c | 1 + tools/perf/util/thread.h | 1 + 2 files changed, 2 insertions(+)tools/perf/util/thread.c +1
-0@@ -69,6 +69,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->pid_ = pid; thread->tid = tid; thread->ppid =-1 ; + thread->cpu =-1 ;INIT_LIST_HEAD (&thread->comm_list); comm_str =malloc (32 );tools/perf/util/thread.h +1
-0@@ -17,6 +17,7 @@ struct thread {pid_t pid_;/* Not all tools update this */ pid_t tid;pid_t ppid; +int cpu;char shortname[3 ];bool comm_set;bool dead;/* if set thread has exited */ Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 24/41] perf tools: Add cpu to struct thread
Quoted 10 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:48PM +0300, Adrian Hunter escreveu:
Quoted 6 lines
Tools may wish to track on which cpu a thread
is running. Add 'cpu' to struct thread for
that purpose.This will be used to determine the cpu when
decoding a per-thread Instruction Trace.Humm, is this the last cpu we got some event telling the cpu was running on? Continuing looking at the patches...
Yes. Intel PT decoding uses sched_switch events to determine which task is running on which cpu. The Intel PT data comes straight from the hardware which doesn't know about linux threads.
Quoted 35 lines
- Arnaldo
Quoted 32 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/thread.c | 1 + tools/perf/util/thread.h | 1 + 2 files changed, 2 insertions(+)tools/perf/util/thread.c +1
-0@@ -69,6 +69,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->pid_ = pid; thread->tid = tid; thread->ppid =-1 ; + thread->cpu =-1 ;INIT_LIST_HEAD (&thread->comm_list); comm_str =malloc (32 );tools/perf/util/thread.h +1
-1@@ -17,6 +17,7 @@ struct thread {pid_t pid_;/* Not all tools update this */ pid_t tid;pid_t ppid; +int cpu;char shortname[3 ];bool comm_set;bool dead;/* if set thread has exited */ --1.8.3.2
Adrian Hunter
reviewerPATCH 25/41 perf tools: Add ability to record the current tid for each cpu
In reply to Adrian HunterAdd an array to struct machine to store the current tid running on each cpu. Add machine functions to get / set the tid for a cpu.
This will be used to determine the tid when decoding a per-cpu Instruction Trace.
--- tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/machine.h | 5 +++++ 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
@@ -47,6 +47,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)thread__set_comm (thread, comm,0 ); } + machine->current_tid =NULL ; +return 0 ; }
@@ -106,6 +108,7 @@ void machine__exit(struct machine *machine)dsos__delete (&machine->user_dsos);dsos__delete (&machine->kernel_dsos);zfree (&machine->root_dir); +zfree (&machine->current_tid); }void machine__delete (struct machine *machine)
@@ -1497,3 +1500,46 @@ int machine__get_kernel_start(struct machine *machine) }return err; } + +pid_t machine__get_current_tid (struct machine *machine,int cpu) +{ +if (cpu <0 || cpu >=MAX_NR_CPUS || !machine->current_tid) +return -1 ; + +return machine->current_tid[cpu]; +} + +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid) +{ +struct thread *thread; + +if (cpu <0 ) +return -EINVAL ; + +if (!machine->current_tid) { +int i; + + machine->current_tid =calloc (MAX_NR_CPUS ,sizeof (pid_t)); +if (!machine->current_tid) +return -ENOMEM ; +for (i =0 ; i <MAX_NR_CPUS ; i++) + machine->current_tid[i] =-1 ; + } + +if (cpu >=MAX_NR_CPUS ) { +pr_err ("Requested CPU %d too large. " , cpu); +pr_err ("Consider raising MAX_NR_CPUS\n" ); +return -EINVAL ; + } + + machine->current_tid[cpu] = tid; + + thread =machine__findnew_thread (machine, pid, tid); +if (!thread) +return -ENOMEM ; + + thread->cpu = cpu; + +return 0 ; +}
tools/perf/util/machine.h +5 -0
@@ -35,6 +35,7 @@ struct machine {struct map *vmlinux_maps[MAP__NR_TYPES ];u64 kernel_start;symbol_filter_t symbol_filter; +pid_t *current_tid; }; static inline
@@ -212,4 +213,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target, perf_event__process, data_mmap); } +pid_t machine__get_current_tid (struct machine *machine,int cpu); +int machine__set_current_tid (struct machine *machine,int cpu,pid_t pid, +pid_t tid); +#endif /* __PERF_MACHINE_H */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 26/41 perf tools: Add ability to iterate over a dso's symbols
In reply to Adrian HunterExpose dso__first_symbol() and dso__next_symbol() to make it possible to iterate over a dso's symbols.
--- tools/perf/util/symbol.c | 17 ++++++++++++++++- tools/perf/util/symbol.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-)
tools/perf/util/symbol.c +16 -1
@@ -341,6 +341,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)return NULL ; } +static struct symbol *symbols__next (struct symbol *sym) +{ +struct rb_node *n =rb_next (&sym->rb_node); + +if (n) + return rb_entry(n, struct symbol, rb_node); + +return NULL ; +} +struct symbol_name_rb_node {struct rb_node rb_node;struct symbol sym;
@@ -411,11 +421,16 @@ struct symbol *dso__find_symbol(struct dso *dso,return symbols__find (&dso->symbols[type], addr); } -static struct symbol *dso__first_symbol (struct dso *dso,enum map_type type) +struct symbol *dso__first_symbol (struct dso *dso,enum map_type type) {return symbols__first (&dso->symbols[type]); } +struct symbol *dso__next_symbol (struct symbol *sym) +{ +return symbols__next (sym); +} +struct symbol *dso__find_symbol_by_name (struct dso *dso,enum map_type type,const char *name) {
tools/perf/util/symbol.h +3 -0
@@ -239,6 +239,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,struct symbol *dso__find_symbol_by_name (struct dso *dso,enum map_type type,const char *name); +struct symbol *dso__first_symbol (struct dso *dso,enum map_type type); +struct symbol *dso__next_symbol (struct symbol *sym); +int filename__read_build_id (const char *filename,void *bf,size_t size);int sysfs__read_build_id (const char *filename,void *bf,size_t size); int modules__parse(const char *filename, void *arg,
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf symbols: Add ability to iterate over a dso' s symbols
perf symbols: Add ability to iterate over a dso's symbols
Commit-ID: 9c00a81b6aafc4ed375a43e7a54e6cf2d720c7c6 Gitweb: http://git.kernel.org/tip/9c00a81b6aafc4ed375a43e7a54e6cf2d720c7c6 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:50 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:35 -0300
perf symbols: Add ability to iterate over a dso's symbols
Expose dso__first_symbol() and dso__next_symbol() to make it possible to iterate over a dso's symbols.
--- tools/perf/util/symbol.c | 17 ++++++++++++++++- tools/perf/util/symbol.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-)
tools/perf/util/symbol.c +16 -1
@@ -342,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)return NULL ; } +static struct symbol *symbols__next (struct symbol *sym) +{ +struct rb_node *n =rb_next (&sym->rb_node); + +if (n) + return rb_entry(n, struct symbol, rb_node); + +return NULL ; +} +struct symbol_name_rb_node {struct rb_node rb_node;struct symbol sym;
@@ -412,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso,return symbols__find (&dso->symbols[type], addr); } -static struct symbol *dso__first_symbol (struct dso *dso,enum map_type type) +struct symbol *dso__first_symbol (struct dso *dso,enum map_type type) {return symbols__first (&dso->symbols[type]); } +struct symbol *dso__next_symbol (struct symbol *sym) +{ +return symbols__next (sym); +} +struct symbol *dso__find_symbol_by_name (struct dso *dso,enum map_type type,const char *name) {
tools/perf/util/symbol.h +3 -0
@@ -240,6 +240,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,struct symbol *dso__find_symbol_by_name (struct dso *dso,enum map_type type,const char *name); +struct symbol *dso__first_symbol (struct dso *dso,enum map_type type); +struct symbol *dso__next_symbol (struct symbol *sym); +int filename__read_build_id (const char *filename,void *bf,size_t size);int sysfs__read_build_id (const char *filename,void *bf,size_t size); int modules__parse(const char *filename, void *arg,
Adrian Hunter
reviewerPATCH 27/41 perf session: Flag if the event stream is entirely in memory
In reply to Adrian HunterFlag if the event stream is a file that has been mmapped in one go.
This is useful, for example, if a tool needs to keep an event for later reference. If the new flag is set, a pointer to the event can be retained, otherwise the event must be copied.
--- tools/perf/util/session.c | 9 ++++++++- tools/perf/util/session.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-)
tools/perf/util/session.c +8 -1
@@ -1319,8 +1319,10 @@ int __perf_session__process_events(struct perf_session *session,ui_progress__init (&prog, file_size,"Processing events..." ); mmap_size =MMAP_SIZE ; -if (mmap_size > file_size) +if (mmap_size > file_size) { mmap_size = file_size; + session->one_mmap = true; + }memset (mmaps,0 ,sizeof (mmaps));
@@ -1342,6 +1344,10 @@ remap: mmaps[map_idx] = buf; map_idx = (map_idx +1 ) & (ARRAY_SIZE (mmaps) -1 ); file_pos = file_offset + head; +if (session->one_mmap) { + session->one_mmap_addr = buf; + session->one_mmap_offset = file_offset; + } more: event =fetch_mmaped_event (session, head, mmap_size, buf);
@@ -1387,6 +1393,7 @@ out_err:ui_progress__finish ();perf_session__warn_about_errors (session, tool);perf_session_free_sample_buffers (session); + session->one_mmap = false;return err; }
tools/perf/util/session.h +3 -0
@@ -36,6 +36,9 @@ struct perf_session {struct trace_event tevent;struct events_stats stats;bool repipe; +bool one_mmap; +void *one_mmap_addr; +u64 one_mmap_offset;struct ordered_samples ordered_samples;struct perf_data_file *file; };
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf session: Flag if the event stream is entirely in memory
perf session: Flag if the event stream is entirely in memory
Commit-ID: 919d86d3a3109d7d4f0d7347f34711ee2f8e6609 Gitweb: http://git.kernel.org/tip/919d86d3a3109d7d4f0d7347f34711ee2f8e6609 Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:51 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:36 -0300
perf session: Flag if the event stream is entirely in memory
Flag if the event stream is a file that has been mmapped in one go.
This is useful, for example, if a tool needs to keep an event for later reference. If the new flag is set, a pointer to the event can be retained, otherwise the event must be copied.
--- tools/perf/util/session.c | 9 ++++++++- tools/perf/util/session.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-)
tools/perf/util/session.c +8 -1
@@ -1297,8 +1297,10 @@ int __perf_session__process_events(struct perf_session *session,ui_progress__init (&prog, file_size,"Processing events..." ); mmap_size =MMAP_SIZE ; -if (mmap_size > file_size) +if (mmap_size > file_size) { mmap_size = file_size; + session->one_mmap = true; + }memset (mmaps,0 ,sizeof (mmaps));
@@ -1320,6 +1322,10 @@ remap: mmaps[map_idx] = buf; map_idx = (map_idx +1 ) & (ARRAY_SIZE (mmaps) -1 ); file_pos = file_offset + head; +if (session->one_mmap) { + session->one_mmap_addr = buf; + session->one_mmap_offset = file_offset; + } more: event =fetch_mmaped_event (session, head, mmap_size, buf);
@@ -1365,6 +1371,7 @@ out_err:ui_progress__finish ();perf_session__warn_about_errors (session, tool);perf_session_free_sample_buffers (session); + session->one_mmap = false;return err; }
tools/perf/util/session.h +3 -0
@@ -36,6 +36,9 @@ struct perf_session {struct trace_event tevent;struct events_stats stats;bool repipe; +bool one_mmap; +void *one_mmap_addr; +u64 one_mmap_offset;struct ordered_samples ordered_samples;struct perf_data_file *file; };
Adrian Hunter
reviewerPATCH 28/41 perf evlist: Pass mmap parameters in a struct
In reply to Adrian HunterIn preparation for adding more mmap parameters, pass existing parameters in a struct.
--- tools/perf/util/evlist.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
tools/perf/util/evlist.c +26 -20
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)return evlist->mmap !=NULL ?0 : -ENOMEM ; } -static int __perf_evlist__mmap (struct perf_evlist *evlist, -int idx,int prot,int mask,int fd) +struct mmap_params { +int prot; +int mask; +}; + +static int __perf_evlist__mmap (struct perf_evlist *evlist,int idx, +struct mmap_params *mp,int fd) { evlist->mmap[idx].prev =0 ; - evlist->mmap[idx].mask = mask; - evlist->mmap[idx].base =mmap (NULL , evlist->mmap_len, prot, + evlist->mmap[idx].mask = mp->mask; + evlist->mmap[idx].base =mmap (NULL , evlist->mmap_len, mp->prot,MAP_SHARED , fd,0 );if (evlist->mmap[idx].base ==MAP_FAILED ) { pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, }static int perf_evlist__mmap_per_evsel (struct perf_evlist *evlist,int idx, -int prot,int mask,int cpu,int thread, -int *output) +struct mmap_params *mp,int cpu, +int thread,int *output) {struct perf_evsel *evsel;
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,if (*output ==-1 ) { *output = fd; -if (__perf_evlist__mmap (evlist, idx, prot, mask, - *output) <0 ) +if (__perf_evlist__mmap (evlist, idx, mp, *output) <0 )return -1 ; }else {if (ioctl (fd,PERF_EVENT_IOC_SET_OUTPUT , *output) !=0 )
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,return 0 ; } -static int perf_evlist__mmap_per_cpu (struct perf_evlist *evlist,int prot, -int mask) +static int perf_evlist__mmap_per_cpu (struct perf_evlist *evlist, +struct mmap_params *mp) {int cpu, thread;int nr_cpus =cpu_map__nr (evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,int output =-1 ;for (thread =0 ; thread < nr_threads; thread++) { -if (perf_evlist__mmap_per_evsel (evlist, cpu, prot, mask, - cpu, thread, &output)) +if (perf_evlist__mmap_per_evsel (evlist, cpu, mp, cpu, + thread, &output)) goto out_unmap; } }
@@ -677,8 +681,8 @@ out_unmap:return -1 ; } -static int perf_evlist__mmap_per_thread (struct perf_evlist *evlist,int prot, -int mask) +static int perf_evlist__mmap_per_thread (struct perf_evlist *evlist, +struct mmap_params *mp) {int thread;int nr_threads =thread_map__nr (evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,for (thread =0 ; thread < nr_threads; thread++) {int output =-1 ; -if (perf_evlist__mmap_per_evsel (evlist, thread, prot, mask,0 , - thread, &output)) +if (perf_evlist__mmap_per_evsel (evlist, thread, mp,0 , thread, + &output)) goto out_unmap; }
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,struct perf_evsel *evsel;const struct cpu_map *cpus = evlist->cpus;const struct thread_map *threads = evlist->threads; -int prot =PROT_READ | (overwrite ?0 :PROT_WRITE ), mask; +struct mmap_params mp = { + .prot =PROT_READ | (overwrite ?0 :PROT_WRITE ), + };if (evlist->mmap ==NULL &&perf_evlist__alloc_mmap (evlist) <0 )return -ENOMEM ;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, evlist->overwrite = overwrite; evlist->mmap_len =perf_evlist__mmap_size (pages);pr_debug ("mmap size %zuB\n" , evlist->mmap_len); - mask = evlist->mmap_len - page_size -1 ; + mp.mask = evlist->mmap_len - page_size -1 ;evlist__for_each (evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, }if (cpu_map__empty (cpus)) -return perf_evlist__mmap_per_thread (evlist, prot, mask); +return perf_evlist__mmap_per_thread (evlist, &mp); -return perf_evlist__mmap_per_cpu (evlist, prot, mask); +return perf_evlist__mmap_per_cpu (evlist, &mp); }int perf_evlist__create_maps (struct perf_evlist *evlist,struct target *target)
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Pass mmap parameters in a struct
perf evlist: Pass mmap parameters in a struct
Commit-ID: a8a8f3eb5de55aeaf007c18572668e8ec463547b Gitweb: http://git.kernel.org/tip/a8a8f3eb5de55aeaf007c18572668e8ec463547b Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:52 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:36 -0300
perf evlist: Pass mmap parameters in a struct
In preparation for adding more mmap parameters, pass existing parameters in a struct.
--- tools/perf/util/evlist.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
tools/perf/util/evlist.c +26 -20
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)return evlist->mmap !=NULL ?0 : -ENOMEM ; } -static int __perf_evlist__mmap (struct perf_evlist *evlist, -int idx,int prot,int mask,int fd) +struct mmap_params { +int prot; +int mask; +}; + +static int __perf_evlist__mmap (struct perf_evlist *evlist,int idx, +struct mmap_params *mp,int fd) { evlist->mmap[idx].prev =0 ; - evlist->mmap[idx].mask = mask; - evlist->mmap[idx].base =mmap (NULL , evlist->mmap_len, prot, + evlist->mmap[idx].mask = mp->mask; + evlist->mmap[idx].base =mmap (NULL , evlist->mmap_len, mp->prot,MAP_SHARED , fd,0 );if (evlist->mmap[idx].base ==MAP_FAILED ) { pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, }static int perf_evlist__mmap_per_evsel (struct perf_evlist *evlist,int idx, -int prot,int mask,int cpu,int thread, -int *output) +struct mmap_params *mp,int cpu, +int thread,int *output) {struct perf_evsel *evsel;
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,if (*output ==-1 ) { *output = fd; -if (__perf_evlist__mmap (evlist, idx, prot, mask, - *output) <0 ) +if (__perf_evlist__mmap (evlist, idx, mp, *output) <0 )return -1 ; }else {if (ioctl (fd,PERF_EVENT_IOC_SET_OUTPUT , *output) !=0 )
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,return 0 ; } -static int perf_evlist__mmap_per_cpu (struct perf_evlist *evlist,int prot, -int mask) +static int perf_evlist__mmap_per_cpu (struct perf_evlist *evlist, +struct mmap_params *mp) {int cpu, thread;int nr_cpus =cpu_map__nr (evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,int output =-1 ;for (thread =0 ; thread < nr_threads; thread++) { -if (perf_evlist__mmap_per_evsel (evlist, cpu, prot, mask, - cpu, thread, &output)) +if (perf_evlist__mmap_per_evsel (evlist, cpu, mp, cpu, + thread, &output)) goto out_unmap; } }
@@ -677,8 +681,8 @@ out_unmap:return -1 ; } -static int perf_evlist__mmap_per_thread (struct perf_evlist *evlist,int prot, -int mask) +static int perf_evlist__mmap_per_thread (struct perf_evlist *evlist, +struct mmap_params *mp) {int thread;int nr_threads =thread_map__nr (evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,for (thread =0 ; thread < nr_threads; thread++) {int output =-1 ; -if (perf_evlist__mmap_per_evsel (evlist, thread, prot, mask,0 , - thread, &output)) +if (perf_evlist__mmap_per_evsel (evlist, thread, mp,0 , thread, + &output)) goto out_unmap; }
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,struct perf_evsel *evsel;const struct cpu_map *cpus = evlist->cpus;const struct thread_map *threads = evlist->threads; -int prot =PROT_READ | (overwrite ?0 :PROT_WRITE ), mask; +struct mmap_params mp = { + .prot =PROT_READ | (overwrite ?0 :PROT_WRITE ), + };if (evlist->mmap ==NULL &&perf_evlist__alloc_mmap (evlist) <0 )return -ENOMEM ;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, evlist->overwrite = overwrite; evlist->mmap_len =perf_evlist__mmap_size (pages);pr_debug ("mmap size %zuB\n" , evlist->mmap_len); - mask = evlist->mmap_len - page_size -1 ; + mp.mask = evlist->mmap_len - page_size -1 ;evlist__for_each (evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, }if (cpu_map__empty (cpus)) -return perf_evlist__mmap_per_thread (evlist, prot, mask); +return perf_evlist__mmap_per_thread (evlist, &mp); -return perf_evlist__mmap_per_cpu (evlist, prot, mask); +return perf_evlist__mmap_per_cpu (evlist, &mp); }int perf_evlist__create_maps (struct perf_evlist *evlist,struct target *target)
Adrian Hunter
reviewerPATCH 29/41 perf tools: Add feature test for __sync_val_compare_and_swap
In reply to Adrian HunterAdd a feature test for __sync_val_compare_and_swap() and __sync_bool_compare_and_swap()
--- tools/perf/config/Makefile | 6 ++++++ tools/perf/config/feature-checks/Makefile | 4 ++++ tools/perf/config/feature-checks/test-all.c | 5 +++++ .../config/feature-checks/test-sync-compare-and-swap.c | 14 ++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tools/perf/config/feature-checks/test-sync-compare-and-swap.c
tools/perf/config/Makefile +6 -0
@@ -164,6 +164,7 @@ CORE_FEATURE_TESTS = \ backtrace \ dwarf \ fortify-source \ + sync-compare-and-swap \ glibc \ gtk2 \ gtk2-infobar \
@@ -199,6 +200,7 @@ LIB_FEATURE_TESTS = \ VF_FEATURE_TESTS = \ backtrace \ fortify-source \ + sync-compare-and-swap \ gtk2-infobar \ libelf-getphdrnum \ libelf-mmap \
@@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE) CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +ifeq ($(feature-sync-compare-and-swap), 1) + CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT +endif + ifndef NO_BIONIC $(call feature_check,bionic) ifeq ($(feature-bionic), 1)
tools/perf/config/feature-checks/Makefile +4 -0
@@ -5,6 +5,7 @@ FILES= \ test-bionic.bin \ test-dwarf.bin \ test-fortify-source.bin \ + test-sync-compare-and-swap.bin \ test-glibc.bin \ test-gtk2.bin \ test-gtk2-infobar.bin \
@@ -141,6 +142,9 @@ test-timerfd.bin: test-libdw-dwarf-unwind.bin: $(BUILD) +test-sync-compare-and-swap.bin: + $(BUILD) -Werror + -include *.d ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
@@ -89,6 +89,10 @@# include "test-libdw-dwarf-unwind.c" #undef main +#define main main_test_sync_compare_and_swap +# include "test-sync-compare-and-swap.c" +#undef main +int main (int argc,char *argv[]) {main_test_libpython ();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])main_test_timerfd ();main_test_stackprotector_all ();main_test_libdw_dwarf_unwind (); +main_test_sync_compare_and_swap (argc, argv);return 0 ; }
tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file +14 -0
@@ -0,0 +1,14 @@ +#include <stdint.h> + +volatile uint64_t x; + +int main (int argc,char *argv[]) +{ +uint64_t old, new = argc; + + argv = argv; +do { + old =__sync_val_compare_and_swap (&x,0 ,0 ); + }while (!__sync_bool_compare_and_swap (&x, old, new)); +return old == new; +}
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add feature test for __sync_val_compare_and_swap
perf tools: Add feature test for __sync_val_compare_and_swap
Commit-ID: f6d313699a9612a30fabe05bf2c9302c1408b5cf Gitweb: http://git.kernel.org/tip/f6d313699a9612a30fabe05bf2c9302c1408b5cf Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:53 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:36 -0300
perf tools: Add feature test for __sync_val_compare_and_swap
Add a feature test for __sync_val_compare_and_swap() and __sync_bool_compare_and_swap()
--- tools/perf/config/Makefile | 6 ++++++ tools/perf/config/feature-checks/Makefile | 4 ++++ tools/perf/config/feature-checks/test-all.c | 5 +++++ .../config/feature-checks/test-sync-compare-and-swap.c | 14 ++++++++++++++ 4 files changed, 29 insertions(+)
tools/perf/config/Makefile +6 -0
@@ -164,6 +164,7 @@ CORE_FEATURE_TESTS = \ backtrace \ dwarf \ fortify-source \ + sync-compare-and-swap \ glibc \ gtk2 \ gtk2-infobar \
@@ -199,6 +200,7 @@ LIB_FEATURE_TESTS = \ VF_FEATURE_TESTS = \ backtrace \ fortify-source \ + sync-compare-and-swap \ gtk2-infobar \ libelf-getphdrnum \ libelf-mmap \
@@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE) CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +ifeq ($(feature-sync-compare-and-swap), 1) + CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT +endif + ifndef NO_BIONIC $(call feature_check,bionic) ifeq ($(feature-bionic), 1)
tools/perf/config/feature-checks/Makefile +4 -0
@@ -5,6 +5,7 @@ FILES= \ test-bionic.bin \ test-dwarf.bin \ test-fortify-source.bin \ + test-sync-compare-and-swap.bin \ test-glibc.bin \ test-gtk2.bin \ test-gtk2-infobar.bin \
@@ -141,6 +142,9 @@ test-timerfd.bin: test-libdw-dwarf-unwind.bin: $(BUILD) +test-sync-compare-and-swap.bin: + $(BUILD) -Werror + -include *.d ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
@@ -89,6 +89,10 @@# include "test-libdw-dwarf-unwind.c" #undef main +#define main main_test_sync_compare_and_swap +# include "test-sync-compare-and-swap.c" +#undef main +int main (int argc,char *argv[]) {main_test_libpython ();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])main_test_timerfd ();main_test_stackprotector_all ();main_test_libdw_dwarf_unwind (); +main_test_sync_compare_and_swap (argc, argv);return 0 ; }
tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file +14 -0
@@ -0,0 +1,14 @@ +#include <stdint.h> + +volatile uint64_t x; + +int main (int argc,char *argv[]) +{ +uint64_t old, new = argc; + + argv = argv; +do { + old =__sync_val_compare_and_swap (&x,0 ,0 ); + }while (!__sync_bool_compare_and_swap (&x, old, new)); +return old == new; +}
Adrian Hunter
reviewerPATCH 30/41 perf tools: Add option macro OPT_CALLBACK_OPTARG
In reply to Adrian HunterAdd an option macro that is the same as OPT_CALLBACK except that the argument is optional and it is possible to associate additional data with it.
--- tools/perf/util/parse-options.h | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/parse-options.h +5 -0
@@ -98,6 +98,7 @@ struct option {parse_opt_cb *callback;intptr_t defval;bool *set; +void *data; };#define check_vtype (v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option { { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} +#define OPT_CALLBACK_OPTARG (s, l, v, d, a, h, f) \ + { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ + .value = (v), (a), .help = (h), .callback = (f), \ + .flags = PARSE_OPT_OPTARG, .data = (d) }/* parse_options() will filter out the processed options and leave the * non-option argments in argv[].
Signature · 1 line
1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add option macro OPT_CALLBACK_OPTARG
perf tools: Add option macro OPT_CALLBACK_OPTARG
Commit-ID: ea8e08a16a1e6566be3f775c0bd351fa52ab6b9d Gitweb: http://git.kernel.org/tip/ea8e08a16a1e6566be3f775c0bd351fa52ab6b9d Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:54 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:36 -0300
perf tools: Add option macro OPT_CALLBACK_OPTARG
Add an option macro that is the same as OPT_CALLBACK except that the argument is optional and it is possible to associate additional data with it.
--- tools/perf/util/parse-options.h | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/parse-options.h +5 -0
@@ -98,6 +98,7 @@ struct option {parse_opt_cb *callback;intptr_t defval;bool *set; +void *data; };#define check_vtype (v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option { { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} +#define OPT_CALLBACK_OPTARG (s, l, v, d, a, h, f) \ + { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ + .value = (v), (a), .help = (h), .callback = (f), \ + .flags = PARSE_OPT_OPTARG, .data = (d) }/* parse_options() will filter out the processed options and leave the * non-option argments in argv[].
Adrian Hunter
reviewerPATCH 31/41 perf evlist: Add perf_evlist__set_tracking_event()
In reply to Adrian HunterAdd a function to change which event is used to track mmap, comm and task events.
This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.
--- tools/perf/util/evlist.c | 20 ++++++++++++++++++++ tools/perf/util/evlist.h | 3 +++ 2 files changed, 23 insertions(+)
tools/perf/util/evlist.c +20 -0
@@ -1250,3 +1250,23 @@ void perf_evlist__to_front(struct perf_evlist *evlist,list_splice (&move, &evlist->entries); } + +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel) +{ +struct perf_evsel *evsel; + +if (tracking_evsel->idx ==0 ) +return 0 ; + +if (tracking_evsel->leader->nr_members >1 ) +return -EINVAL ; + +list_for_each_entry (evsel, &evlist->entries, node) { +if (evsel->idx < tracking_evsel->idx) + evsel->idx +=1 ; + } + tracking_evsel->idx =0 ; + +return 0 ; +}
tools/perf/util/evlist.h +3 -0
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,#define evlist__for_each_safe (evlist, tmp, evsel) \ __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +int perf_evlist__set_tracking_event (struct perf_evlist *evlist, +struct perf_evsel *tracking_evsel); +#endif /* __PERF_EVLIST_H */
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 32/41 perf evsel: Add 'no_aux_samples' option
In reply to Adrian HunterAdd an option to prevent additional samples being added to a selected event by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object code execution. Since sched_switch will be used only for switch information, additional sampling is wasteful.
--- tools/perf/util/evsel.c | 6 +++--- tools/perf/util/evsel.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/evsel.c +3 -3
@@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->mmap_data = track; } -if (opts->call_graph_enabled) +if (opts->call_graph_enabled && !evsel->no_aux_samples)perf_evsel__config_callgraph (evsel, opts);if (target__has_cpu (&opts->target))
@@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) target__has_cpu(&opts->target) || per_cpu))perf_evsel__set_sample_bit (evsel,TIME ); -if (opts->raw_samples) { +if (opts->raw_samples && !evsel->no_aux_samples) {perf_evsel__set_sample_bit (evsel,TIME );perf_evsel__set_sample_bit (evsel,RAW );perf_evsel__set_sample_bit (evsel,CPU );
@@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->watermark =0 ; attr->wakeup_events =1 ; } -if (opts->branch_stack) { +if (opts->branch_stack && !evsel->no_aux_samples) {perf_evsel__set_sample_bit (evsel,BRANCH_STACK ); attr->branch_sample_type = opts->branch_stack; }
tools/perf/util/evsel.h +1 -0
@@ -83,6 +83,7 @@ struct perf_evsel {int is_pos;bool supported;bool needs_swap; +bool no_aux_samples;/* 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 evsel: Add 'no_aux_samples' option
perf evsel: Add 'no_aux_samples' option
Commit-ID: 6ff1ce763921f605aaf98c7a828b7df24d6923dc Gitweb: http://git.kernel.org/tip/6ff1ce763921f605aaf98c7a828b7df24d6923dc Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:56 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:36 -0300
perf evsel: Add 'no_aux_samples' option
Add an option to prevent additional samples being added to a selected event by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object code execution. Since sched_switch will be used only for switch information, additional sampling is wasteful.
--- tools/perf/util/evsel.c | 6 +++--- tools/perf/util/evsel.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/evsel.c +3 -3
@@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->mmap_data = track; } -if (opts->call_graph_enabled) +if (opts->call_graph_enabled && !evsel->no_aux_samples)perf_evsel__config_callgraph (evsel, opts);if (target__has_cpu (&opts->target))
@@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) target__has_cpu(&opts->target) || per_cpu))perf_evsel__set_sample_bit (evsel,TIME ); -if (opts->raw_samples) { +if (opts->raw_samples && !evsel->no_aux_samples) {perf_evsel__set_sample_bit (evsel,TIME );perf_evsel__set_sample_bit (evsel,RAW );perf_evsel__set_sample_bit (evsel,CPU );
@@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->watermark =0 ; attr->wakeup_events =1 ; } -if (opts->branch_stack) { +if (opts->branch_stack && !evsel->no_aux_samples) {perf_evsel__set_sample_bit (evsel,BRANCH_STACK ); attr->branch_sample_type = opts->branch_stack; }
tools/perf/util/evsel.h +1 -0
@@ -83,6 +83,7 @@ struct perf_evsel {int is_pos;bool supported;bool needs_swap; +bool no_aux_samples;/* parse modifier helper */ int exclude_GH;int nr_members;
Adrian Hunter
reviewerPATCH 33/41 perf evsel: Add 'immediate' option
In reply to Adrian HunterAdd an option to cause a selected event to be enabled immediately when configured by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object code execution. By having sched_switch enabled immediately the first sched_switch event precedes the start of other tracing.
--- tools/perf/util/evsel.c | 5 +++++ tools/perf/util/evsel.h | 1 + 2 files changed, 6 insertions(+)
tools/perf/util/evsel.c +5 -0
@@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)if (target__none (&opts->target) &&perf_evsel__is_group_leader (evsel) && !opts->initial_delay) attr->enable_on_exec =1 ; + +if (evsel->immediate) { + attr->disabled =0 ; + attr->enable_on_exec =0 ; + } }int perf_evsel__alloc_fd (struct perf_evsel *evsel,int ncpus,int nthreads)
tools/perf/util/evsel.h +1 -0
@@ -84,6 +84,7 @@ struct perf_evsel {bool supported;bool needs_swap;bool no_aux_samples; +bool immediate;/* 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 evsel: Add 'immediate' option
perf evsel: Add 'immediate' option
Commit-ID: 2afd2bcfc3a026d6e4c2184bf41ccd74eb05758b Gitweb: http://git.kernel.org/tip/2afd2bcfc3a026d6e4c2184bf41ccd74eb05758b Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:02:57 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 16 Jul 2014 17:57:37 -0300
perf evsel: Add 'immediate' option
Add an option to cause a selected event to be enabled immediately when configured by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object code execution. By having sched_switch enabled immediately the first sched_switch event precedes the start of other tracing.
--- tools/perf/util/evsel.c | 5 +++++ tools/perf/util/evsel.h | 1 + 2 files changed, 6 insertions(+)
tools/perf/util/evsel.c +5 -0
@@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)if (target__none (&opts->target) &&perf_evsel__is_group_leader (evsel) && !opts->initial_delay) attr->enable_on_exec =1 ; + +if (evsel->immediate) { + attr->disabled =0 ; + attr->enable_on_exec =0 ; + } }int perf_evsel__alloc_fd (struct perf_evsel *evsel,int ncpus,int nthreads)
tools/perf/util/evsel.h +1 -0
@@ -84,6 +84,7 @@ struct perf_evsel {bool supported;bool needs_swap;bool no_aux_samples; +bool immediate;/* parse modifier helper */ int exclude_GH;int nr_members;
Adrian Hunter
reviewerPATCH 34/41 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
@@ -691,6 +691,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) {
@@ -709,6 +713,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),
@@ -739,6 +746,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 ;
@@ -783,6 +793,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));
@@ -871,6 +884,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++) {
@@ -993,13 +1009,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 =0 ;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) {
@@ -1021,10 +1042,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);
@@ -1094,7 +1115,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
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 34/41] perf evlist: Add 'system_wide' option
Em Mon, Jul 14, 2014 at 01:02:58PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
Add an option to cause a selected event to be opened always without a pid when configured by
perf_evsel__config().
Quoted 9 lines
This is needed when using the
sched_switchtracepoint to follow object code execution.sched_switchoccurs before the task switch and so it cannot record it in a context limited to that task. Note that also means thatsched_switchis useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.
clever, but humm, need to be judicious when allocating things like the pollfd, I think, more below...
... after going thru the whole patch, its not clear how pollfd usage takes into account the fact that some of the evsels don't have thread_map->nr entries, but just one, will continue reading...
Quoted 79 lines
Signed-off-by Adrian Hunter <[email protected]>--- 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 +19
-4@@ -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);
tools/perf/util/evlist.c int perf_evlist__enable_event(struct perf_evlist *evlist, · line 350
Quoted 10 lines
tools/perf/util/evlist.c +2
-2if (!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)
All the above seems ok, the threads (x axis) array is flat when syswide, ok.
Quoted 4 lines
tools/perf/util/evlist.c +0
-0@@ -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);
tools/perf/util/evlist.c static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) · line 369
Quoted 10 lines
tools/perf/util/evlist.c +9
-1-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; + }
But here looks tricky, will look how the evlist->pollfd is used...
tools/perf/util/evlist.c static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, · line 666
Quoted 13 lines
tools/perf/util/evlist.c +5
-1+ 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 ;
Discard after thread 0, i.e. the first, ok.
Quoted 10 lines
tools/perf/util/evlist.c +2
-0+ + fd =FD (evsel, cpu, thread);if (*output ==-1 ) { *output = fd;tools/perf/util/evsel.c +0
-0
tools/perf/util/evsel.c void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) · line 696
Quoted 6 lines
tools/perf/util/evsel.c +3
-0@@ -691,6 +691,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 ;
flatten it, ok
tools/perf/util/evsel.c static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea · line 718
Quoted 11 lines
tools/perf/util/evsel.c +4
-0+ evsel->fd =xyarray__new (ncpus, nthreads,sizeof (int ));if (evsel->fd) {@@ -709,6 +713,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea {int cpu, thread; +if (evsel->system_wide) + nthreads =1 ; +
Ditto.
tools/perf/util/evsel.c int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) · line 752
Quoted 11 lines
tools/perf/util/evsel.c +3
-0for (cpu =0 ; cpu < ncpus; cpu++) {for (thread =0 ; thread < nthreads; thread++) { int fd = FD(evsel, cpu, thread),@@ -739,6 +746,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 ));
These are per evsel, so can be flattened when we get to it,evlist->pollfd is per evlist, so mixes syswide with !syswide, that is why I'm scratching my head at this point...
Quoted 79 lines
tools/perf/util/evsel.c +16
-5if (evsel->sample_id ==NULL )return -ENOMEM ;@@ -783,6 +793,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));@@ -871,6 +884,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++) {@@ -993,13 +1009,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 =0 ;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) {@@ -1021,10 +1042,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);@@ -1094,7 +1115,7 @@ out_close:close (FD (evsel, cpu, thread));FD (evsel, cpu, thread) =-1 ; } - thread = threads->nr; + thread = nthreads; }while (--cpu >=0 );return err; }tools/perf/util/evsel.h +1
-0@@ -85,6 +85,7 @@ struct perf_evsel {bool needs_swap;bool no_aux_samples;bool immediate; +bool system_wide;/* parse modifier helper */ int exclude_GH;int nr_members;Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 34/41] perf evlist: Add 'system_wide' option
Quoted 185 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:02:58PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
Add an option to cause a selected event to be opened always without a pid when configured by
perf_evsel__config().Quoted 9 lines
This is needed when using the
sched_switchtracepoint to follow object code execution.sched_switchoccurs before the task switch and so it cannot record it in a context limited to that task. Note that also means thatsched_switchis useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.clever, but humm, need to be judicious when allocating things like the pollfd, I think, more below...
... after going thru the whole patch, its not clear how pollfd usage takes into account the fact that some of the evsels don't have
thread_map->nrentries, but just one, will continue reading...Quoted 79 lines
Signed-off-by Adrian Hunter <[email protected]>--- 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 +19
-4@@ -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);tools/perf/util/evlist.c int perf_evlist__enable_event(struct perf_evlist *evlist, · line 350
Quoted 10 lines
tools/perf/util/evlist.c +2
-2if (!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)All the above seems ok, the threads (x axis) array is flat when syswide, ok.
Quoted 4 lines
tools/perf/util/evlist.c +0
-0@@ -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);tools/perf/util/evlist.c static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) · line 369
Quoted 10 lines
tools/perf/util/evlist.c +9
-1-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; + }But here looks tricky, will look how the
evlist->pollfdis used...tools/perf/util/evlist.c static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, · line 666
Quoted 13 lines
tools/perf/util/evlist.c +5
-1+ 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 ;Discard after thread 0, i.e. the first, ok.
Quoted 10 lines
tools/perf/util/evlist.c +2
-0+ + fd =FD (evsel, cpu, thread);if (*output ==-1 ) { *output = fd;tools/perf/util/evsel.c +0
-0tools/perf/util/evsel.c void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) · line 696
Quoted 6 lines
tools/perf/util/evsel.c +3
-0@@ -691,6 +691,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 ;flatten it, ok
tools/perf/util/evsel.c static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea · line 718
Quoted 11 lines
tools/perf/util/evsel.c +4
-0+ evsel->fd =xyarray__new (ncpus, nthreads,sizeof (int ));if (evsel->fd) {@@ -709,6 +713,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea {int cpu, thread; +if (evsel->system_wide) + nthreads =1 ; +Ditto.
Quoted 5 lines
tools/perf/util/evsel.c +0
-0for (cpu =0 ; cpu < ncpus; cpu++) {for (thread =0 ; thread < nthreads; thread++) { int fd = FD(evsel, cpu, thread),@@ -739,6 +746,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
Quoted 10 lines
tools/perf/util/evsel.c int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) · line 752
Quoted 6 lines
tools/perf/util/evsel.c +3
-0int 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 ));These are per evsel, so can be flattened when we get to it,
evlist->pollfdis per evlist, so mixes syswide with !syswide, that is why I'm scratching my head at this point...
pollfd is not a 2-dimensional array. It is just a 1-dimensional array. So it just needs to be the right length.
Quoted 80 lines
Quoted 80 lines
tools/perf/util/evsel.c +16
-5if (evsel->sample_id ==NULL )return -ENOMEM ;@@ -783,6 +793,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));@@ -871,6 +884,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++) {@@ -993,13 +1009,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 =0 ;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) {@@ -1021,10 +1042,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);@@ -1094,7 +1115,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
-1@@ -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; --1.8.3.2
Re: [PATCH 34/41] perf evlist: Add 'system_wide' option
In reply to Adrian HunterQuoted 27 lines · Adrian Hunter
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_switchtracepoint to follow object code execution.sched_switchoccurs before the task switch and so it cannot record it in a context limited to that task. Note that also means thatsched_switchis useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.Signed-off-by Adrian Hunter <[email protected]>--- 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 +0
-0@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,return 0 ;
tools/perf/util/evlist.c int perf_evlist__add_newtp(struct perf_evlist *evlist, · line 275
Quoted 10 lines
tools/perf/util/evlist.c +8
-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); +}
how is 'evsel->system_wide' set?
jirka
Adrian Hunter
reviewerRe: [PATCH 34/41] perf evlist: Add 'system_wide' option
Quoted 30 lines · Jiri Olsa
Quoted 29 lines · Adrian Hunter
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_switchtracepoint to follow object code execution.sched_switchoccurs before the task switch and so it cannot record it in a context limited to that task. Note that also means thatsched_switchis useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.Signed-off-by Adrian Hunter <[email protected]>--- 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 +0
-0@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,return 0 ; }
Quoted 10 lines
tools/perf/util/evlist.c int perf_evlist__add_newtp(struct perf_evlist *evlist, · line 275
Quoted 8 lines
tools/perf/util/evlist.c +8
-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); +}how is '
evsel->system_wide' set?
Intel PT sets it for the sched_switch event.
Adrian Hunter
reviewerPATCH 35/41 perf tools: Add id index
In reply to Adrian HunterAdd an index of the event identifiers.
This is needed to queue Instruction
Trace samples according to the mmap
buffer from which they were recorded.
--- tools/perf/builtin-inject.c | 1 + tools/perf/util/event.c | 1 + tools/perf/util/event.h | 15 ++++++ tools/perf/util/evlist.c | 26 ++++++++-- tools/perf/util/evsel.h | 3 ++ tools/perf/util/session.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.h | 10 ++++ tools/perf/util/tool.h | 3 +- 8 files changed, 177 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +1 -0
@@ -419,6 +419,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .tracing_data = perf_event__repipe_op2_synth, .finished_round = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, + .id_index = perf_event__repipe_op2_synth, }, .input_name = "-", .samples = LIST_HEAD_INIT(inject.samples),
tools/perf/util/event.c +1 -0
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", + [PERF_RECORD_ID_INDEX] = "ID_INDEX", };const char *perf_event__name (unsigned int id)
tools/perf/util/event.h +15 -0
@@ -185,6 +185,7 @@ enum perf_user_event_type { /* above any possible kernel type */PERF_RECORD_HEADER_TRACING_DATA =66 ,PERF_RECORD_HEADER_BUILD_ID =67 ,PERF_RECORD_FINISHED_ROUND =68 , +PERF_RECORD_ID_INDEX =69 , PERF_RECORD_HEADER_MAX };
@@ -211,6 +212,19 @@ struct tracing_data_event {u32 size; }; +struct id_index_entry { +u64 id; +u64 idx; +u64 cpu; +u64 tid; +}; + +struct id_index_event { +struct perf_event_header header; +u64 nr; +struct id_index_entry entries[0 ]; +}; +union perf_event {struct perf_event_header header;struct mmap_event mmap;
@@ -225,6 +239,7 @@ union perf_event {struct event_type_event event_type;struct tracing_data_event tracing_data;struct build_id_event build_id; +struct id_index_event id_index; };void perf_event__print_totals (void );
tools/perf/util/evlist.c +23 -3
@@ -441,6 +441,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,return 0 ; } +static void perf_evlist__set_sid_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx,int cpu, +int thread) +{ +struct perf_sample_id *sid =SID (evsel, cpu, thread); + sid->idx = idx; +if (evlist->cpus && cpu >=0 ) + sid->cpu = evlist->cpus->map[cpu]; +else + sid->cpu =-1 ; +if (!evsel->system_wide && evlist->threads && thread >=0 ) + sid->tid = evlist->threads->map[thread]; +else + sid->tid =-1 ; +} +struct perf_sample_id *perf_evlist__id2sid (struct perf_evlist *evlist,u64 id) {struct hlist_head *head;
@@ -676,9 +692,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,return -1 ; } -if ((evsel->attr.read_format &PERF_FORMAT_ID ) && -perf_evlist__id_add_fd (evlist, evsel, cpu, thread, fd) <0 ) -return -1 ; +if (evsel->attr.read_format &PERF_FORMAT_ID ) { +if (perf_evlist__id_add_fd (evlist, evsel, cpu, thread, + fd) <0 ) +return -1 ; +perf_evlist__set_sid_idx (evlist, evsel, idx, cpu, + thread); + } }return 0 ;
tools/perf/util/evsel.h +3 -0
@@ -38,6 +38,9 @@ struct perf_sample_id {struct hlist_node node;u64 id;struct perf_evsel *evsel; +int idx; +int cpu; +pid_t tid;/* Holds total ID period value for PERF_SAMPLE_READ processing. */ u64 period;
tools/perf/util/session.c +122 -0
149 lines not on this page · raw message
tools/perf/util/session.h +10 -0
@@ -129,4 +129,14 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,extern volatile int session_done;#define session_done () (*(volatile int *)(&session_done)) + +int perf_event__process_id_index (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session); + +int perf_event__synthesize_id_index (struct perf_tool *tool, +perf_event__handler_t process, +struct perf_evlist *evlist, +struct machine *machine); +#endif /* __PERF_SESSION_H */
tools/perf/util/tool.h +2 -1
@@ -39,7 +39,8 @@ struct perf_tool {event_attr_op attr;event_op2 tracing_data;event_op2 finished_round, - build_id; + build_id, + id_index;bool ordered_samples;bool ordering_requires_timestamps; };
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 36/41 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 37/41 perf session: Add ability to skip 4GiB or more
In reply to Adrian HunterA session can be made to skip portions of the input file. Do not limit that size to 32-bits.
--- tools/perf/util/session.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
tools/perf/util/session.c +13 -7
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event, -struct perf_tool *tool,u64 file_offset) +static s64 perf_session__process_user_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {int fd =perf_data_file__fd (session->file);int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, +static s64 perf_session__process_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,union perf_event *event;uint32_t size, cur_size =0 ;void *buf =NULL ; -int skip =0 ; +s64 skip =0 ;u64 head;ssize_t err;void *p;
@@ -1313,13 +1315,13 @@ int __perf_session__process_events(struct perf_session *session, u64 file_size, struct perf_tool *tool) { int fd = perf_data_file__fd(session->file); -u64 head, page_offset, file_offset, file_pos; +u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;size_t mmap_size;char *buf, *mmaps[NUM_MMAPS ];union perf_event *event; -uint32_t size;struct ui_progress prog; +s64 skip;perf_tool__fill_defaults (tool);
@@ -1380,7 +1382,8 @@ more: size = event->header.size;if (size <sizeof (struct perf_event_header ) || -perf_session__process_event (session, event, tool, file_pos) <0 ) { + (skip =perf_session__process_event (session, event, tool, file_pos)) + <0 ) {pr_err ("%#" PRIx64" [%#x]: failed to process type: %d\n" , file_offset + head, event->header.size, event->header.type);
@@ -1388,6 +1391,9 @@ more: goto out_err; } +if (skip) + size += skip; + head += size; file_pos += size;
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 38/41 perf session: Add perf_session__deliver_synth_event()
In reply to Adrian HunterAdd a function to deliver synthesized events from
within a session.
--- tools/perf/util/session.c | 14 ++++++++++++++ tools/perf/util/session.h | 5 +++++ 2 files changed, 19 insertions(+)
tools/perf/util/session.c +14 -0
@@ -1066,6 +1066,20 @@ static s64 perf_session__process_user_event(struct perf_session *session, } } +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool) +{ +events_stats__inc (&session->stats, event->header.type); + +if (event->header.type >=PERF_RECORD_USER_TYPE_START ) +return perf_session__process_user_event (session, event, tool, +0 ); + +return perf_session_deliver_event (session, event, sample, tool,0 ); +} +static void event_swap (union perf_event *event,bool sample_id_all) {perf_event__swap_op swap;
tools/perf/util/session.h +5 -0
@@ -130,6 +130,11 @@ extern volatile int session_done;#define session_done () (*(volatile int *)(&session_done)) +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool); +int perf_event__process_id_index (struct perf_tool *tool,union perf_event *event,struct perf_session *session);
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 38/41] perf session: Add perf_session__deliver_synth_event()
Em Mon, Jul 14, 2014 at 01:03:02PM +0300, Adrian Hunter escreveu:
Quoted 2 lines
Add a function to deliver synthesized events from
within a session.
Why not put this in perf_session_deliver_event (and fix its naming, renaming it to perf_session__deliver_event)?
The way you did makes me wonder why you want to fallback to perf_session_deliver_event, i.e. would a normal event come thru a function which name implies it should be used only for synth events?
Also that events_stats__inc() looks suspicious there :-\
- Arnaldo
Quoted 49 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/session.c | 14 ++++++++++++++ tools/perf/util/session.h | 5 +++++ 2 files changed, 19 insertions(+)tools/perf/util/session.c +14
-0@@ -1066,6 +1066,20 @@ static s64 perf_session__process_user_event(struct perf_session *session, } } +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool) +{ +events_stats__inc (&session->stats, event->header.type); + +if (event->header.type >=PERF_RECORD_USER_TYPE_START ) +return perf_session__process_user_event (session, event, tool, +0 ); + +return perf_session_deliver_event (session, event, sample, tool,0 ); +} +static void event_swap (union perf_event *event,bool sample_id_all) {perf_event__swap_op swap;tools/perf/util/session.h +5
-0@@ -130,6 +130,11 @@ extern volatile int session_done;#define session_done () (*(volatile int *)(&session_done)) +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool); +int perf_event__process_id_index (struct perf_tool *tool,union perf_event *event,struct perf_session *session);Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerRe: [PATCH 38/41] perf session: Add perf_session__deliver_synth_event()
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:03:02PM +0300, Adrian Hunter escreveu:
Quoted 2 lines
Add a function to deliver synthesized events from
within a session.
Quoted 8 lines
Why not put this in
perf_session_deliver_event(and fix its naming, renaming it toperf_session__deliver_event)?The way you did makes me wonder why you want to fallback to
perf_session_deliver_event, i.e. would a normal event come thru a function which name implies it should be used only for synth events?Also that
events_stats__inc()looks suspicious there :-\
What happens is Intel PT (or Intel BTS) data is decoded which results in (mostly) branch data. So "branches" events are synthesized and injected into the event stream using perf_session__deliver_synth_event().
The structure of perf_session__deliver_synth_event() reflects the fact that "user" events (not from the kernel) are processed differently to "real" events (from the kernel or synthesized).
The synthesized branches events are then consumed by the tools just as though they came directly from the perf.data file
- so updating stats is normal.
Quoted 52 lines
- Arnaldo
Quoted 49 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/util/session.c | 14 ++++++++++++++ tools/perf/util/session.h | 5 +++++ 2 files changed, 19 insertions(+)tools/perf/util/session.c +14
-0@@ -1066,6 +1066,20 @@ static s64 perf_session__process_user_event(struct perf_session *session, } } +int perf_session__deliver_synth_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool) +{ +events_stats__inc (&session->stats, event->header.type); + +if (event->header.type >=PERF_RECORD_USER_TYPE_START ) +return perf_session__process_user_event (session, event, tool, +0 ); + +return perf_session_deliver_event (session, event, sample, tool,0 ); +} +static void event_swap (union perf_event *event,bool sample_id_all) {perf_event__swap_op swap;tools/perf/util/session.h +5
-1@@ -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); --1.8.3.2
Adrian Hunter
reviewerPATCH 39/41 perf tools: Allow TSC conversion on any arch
In reply to Adrian HunterIt is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.
--- tools/perf/Makefile.perf | 2 ++ tools/perf/arch/x86/util/tsc.c | 22 +--------------------- tools/perf/arch/x86/util/tsc.h | 3 --- tools/perf/tests/perf-time-to-tsc.c | 3 +-- tools/perf/util/tsc.c | 25 +++++++++++++++++++++++++ tools/perf/util/tsc.h | 11 +++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 tools/perf/util/tsc.c create mode 100644 tools/perf/util/tsc.h
tools/perf/Makefile.perf +2 -0
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h +LIB_H += util/tsc.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h
@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o +LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
@@ -6,29 +6,9 @@#include "../../perf.h" #include <linux/types.h> #include "../../util/debug.h" +#include "../../util/tsc.h" #include "tsc.h" -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) -{ -u64 t, quot, rem; - - t = ns - tc->time_zero; - quot = t / tc->time_mult; - rem = t % tc->time_mult; -return (quot << tc->time_shift) + - (rem << tc->time_shift) / tc->time_mult; -} - -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) -{ -u64 quot, rem; - - quot = cyc >> tc->time_shift; - rem = cyc & ((1 << tc->time_shift) -1 ); -return tc->time_zero + quot * tc->time_mult + - ((rem * tc->time_mult) >> tc->time_shift); -} -int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) {
tools/perf/arch/x86/util/tsc.h +0 -3
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc); -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); -#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
@@ -8,10 +8,9 @@#include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "tsc.h" #include "tests.h" -#include "../arch/x86/util/tsc.h" -#define CHECK__ (x) { \ while ((x) < 0) { \ pr_debug(#x " failed!\n"); \
tools/perf/util/tsc.c new file +25 -0
@@ -0,0 +1,25 @@ +#include <linux/compiler.h> +#include <linux/types.h> + +#include "tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) +{ +u64 t, quot, rem; + + t = ns - tc->time_zero; + quot = t / tc->time_mult; + rem = t % tc->time_mult; +return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) +{ +u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) -1 ); +return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +}
tools/perf/util/tsc.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __PERF_TSC_H +#define __PERF_TSC_H + +#include <linux/types.h> + +#include "../arch/x86/util/tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif
Signature · 1 line
1.8.3.2
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 39/41] perf tools: Allow TSC conversion on any arch
Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
It is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.
Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?
- Arnaldo
Quoted 145 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/Makefile.perf | 2 ++ tools/perf/arch/x86/util/tsc.c | 22 +--------------------- tools/perf/arch/x86/util/tsc.h | 3 --- tools/perf/tests/perf-time-to-tsc.c | 3 +-- tools/perf/util/tsc.c | 25 +++++++++++++++++++++++++ tools/perf/util/tsc.h | 11 +++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 tools/perf/util/tsc.c create mode 100644 tools/perf/util/tsc.htools/perf/Makefile.perf +2
-0@@ -295,6 +295,7 @@ LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h +LIB_H += util/tsc.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o +LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.otools/perf/arch/x86/util/tsc.c +1
-21@@ -6,29 +6,9 @@#include "../../perf.h" #include <linux/types.h> #include "../../util/debug.h" +#include "../../util/tsc.h" #include "tsc.h" -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) -{ -u64 t, quot, rem; - - t = ns - tc->time_zero; - quot = t / tc->time_mult; - rem = t % tc->time_mult; -return (quot << tc->time_shift) + - (rem << tc->time_shift) / tc->time_mult; -} - -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) -{ -u64 quot, rem; - - quot = cyc >> tc->time_shift; - rem = cyc & ((1 << tc->time_shift) -1 ); -return tc->time_zero + quot * tc->time_mult + - ((rem * tc->time_mult) >> tc->time_shift); -} -int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) {tools/perf/arch/x86/util/tsc.h +0
-3@@ -14,7 +14,4 @@ struct perf_event_mmap_page;int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc); -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); -#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ tools/perf/tests/perf-time-to-tsc.c +1
-2@@ -8,10 +8,9 @@#include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "tsc.h" #include "tests.h" -#include "../arch/x86/util/tsc.h" -#define CHECK__ (x) { \ while ((x) < 0) { \ pr_debug(#x " failed!\n"); \tools/perf/util/tsc.c new file +25
-0@@ -0,0 +1,25 @@ +#include <linux/compiler.h> +#include <linux/types.h> + +#include "tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) +{ +u64 t, quot, rem; + + t = ns - tc->time_zero; + quot = t / tc->time_mult; + rem = t % tc->time_mult; +return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) +{ +u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) -1 ); +return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +}tools/perf/util/tsc.h new file +11
-0@@ -0,0 +1,11 @@ +#ifndef __PERF_TSC_H +#define __PERF_TSC_H + +#include <linux/types.h> + +#include "../arch/x86/util/tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif Signature · 1 line
1.8.3.2
Peter Zijlstra
maintainerRe: [PATCH 39/41] perf tools: Allow TSC conversion on any arch
Quoted 8 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
It is possible to record a perf.data file on one architecture and process it on another. Consequently, TSC conversion functions need to be moved out of the arch directory.
Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?
So there's nothing intrinsically x86/tsc about the perf interface here, although that's currently the only one implementing this thing.
Other archs could equally expose their 'cycle' counter etc..
Adrian Hunter
reviewerRe: [PATCH 39/41] perf tools: Allow TSC conversion on any arch
In reply to Arnaldo Carvalho de MeloQuoted 8 lines · Arnaldo Carvalho de Melo
Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:
Quoted 4 lines
It is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?
Intel PT has packets that contain 7-bytes of TSC. 'perf record' adds a reference TSC to the ITRACE event so that the full TSC is known.
So this is the possibility that you record a perf.data file on x86 recording Intel PT and then take that file to another machine with a different architecture. It should still be possible to read the file there.
Quoted 148 lines
- Arnaldo
Quoted 145 lines
Signed-off-by Adrian Hunter <[email protected]>--- tools/perf/Makefile.perf | 2 ++ tools/perf/arch/x86/util/tsc.c | 22 +--------------------- tools/perf/arch/x86/util/tsc.h | 3 --- tools/perf/tests/perf-time-to-tsc.c | 3 +-- tools/perf/util/tsc.c | 25 +++++++++++++++++++++++++ tools/perf/util/tsc.h | 11 +++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-)create mode 100644
tools/perf/util/tsc.c
create mode 100644tools/perf/util/tsc.htools/perf/Makefile.perf +2
-0@@ -295,6 +295,7 @@ LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h +LIB_H += util/tsc.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o +LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.otools/perf/arch/x86/util/tsc.c +1
-21@@ -6,29 +6,9 @@#include "../../perf.h" #include <linux/types.h> #include "../../util/debug.h" +#include "../../util/tsc.h" #include "tsc.h" -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) -{ -u64 t, quot, rem; - - t = ns - tc->time_zero; - quot = t / tc->time_mult; - rem = t % tc->time_mult; -return (quot << tc->time_shift) + - (rem << tc->time_shift) / tc->time_mult; -} - -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) -{ -u64 quot, rem; - - quot = cyc >> tc->time_shift; - rem = cyc & ((1 << tc->time_shift) -1 ); -return tc->time_zero + quot * tc->time_mult + - ((rem * tc->time_mult) >> tc->time_shift); -} -int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) {tools/perf/arch/x86/util/tsc.h +0
-3@@ -14,7 +14,4 @@ struct perf_event_mmap_page;int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc); -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); -#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ tools/perf/tests/perf-time-to-tsc.c +1
-2@@ -8,10 +8,9 @@#include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "tsc.h" #include "tests.h" -#include "../arch/x86/util/tsc.h" -#define CHECK__ (x) { \ while ((x) < 0) { \ pr_debug(#x " failed!\n"); \tools/perf/util/tsc.c new file +25
-0@@ -0,0 +1,25 @@ +#include <linux/compiler.h> +#include <linux/types.h> + +#include "tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) +{ +u64 t, quot, rem; + + t = ns - tc->time_zero; + quot = t / tc->time_mult; + rem = t % tc->time_mult; +return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) +{ +u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) -1 ); +return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +}tools/perf/util/tsc.h new file +11
-1@@ -0,0 +1,11 @@ +#ifndef __PERF_TSC_H +#define __PERF_TSC_H + +#include <linux/types.h> + +#include "../arch/x86/util/tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif --1.8.3.2
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Allow TSC conversion on any arch
In reply to Adrian Hunterperf tools: Allow TSC conversion on any arch
Commit-ID: 0b437860818dc717f6a9e8a5089223a8414f5fff Gitweb: http://git.kernel.org/tip/0b437860818dc717f6a9e8a5089223a8414f5fff Author: Adrian Hunter <[email protected]> AuthorDate: Mon, 14 Jul 2014 13:03:03 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 17 Jul 2014 12:59:00 -0300
perf tools: Allow TSC conversion on any arch
It is possible to record a perf.data file on one architecture and process it on another.
Consequently, TSC conversion functions need to be moved out of the arch directory.
--- tools/perf/Makefile.perf | 2 ++ tools/perf/arch/x86/util/tsc.c | 22 +--------------------- tools/perf/arch/x86/util/tsc.h | 3 --- tools/perf/tests/perf-time-to-tsc.c | 3 +-- tools/perf/util/tsc.c | 25 +++++++++++++++++++++++++ tools/perf/util/tsc.h | 11 +++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-)
tools/perf/Makefile.perf +2 -0
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h +LIB_H += util/tsc.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h
@@ -374,6 +375,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o +LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
@@ -6,29 +6,9 @@#include "../../perf.h" #include <linux/types.h> #include "../../util/debug.h" +#include "../../util/tsc.h" #include "tsc.h" -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) -{ -u64 t, quot, rem; - - t = ns - tc->time_zero; - quot = t / tc->time_mult; - rem = t % tc->time_mult; -return (quot << tc->time_shift) + - (rem << tc->time_shift) / tc->time_mult; -} - -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) -{ -u64 quot, rem; - - quot = cyc >> tc->time_shift; - rem = cyc & ((1 << tc->time_shift) -1 ); -return tc->time_zero + quot * tc->time_mult + - ((rem * tc->time_mult) >> tc->time_shift); -} -int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) {
tools/perf/arch/x86/util/tsc.h +0 -3
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc); -u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); -u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); -#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
@@ -8,10 +8,9 @@#include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "tsc.h" #include "tests.h" -#include "../arch/x86/util/tsc.h" -#define CHECK__ (x) { \ while ((x) < 0) { \ pr_debug(#x " failed!\n"); \
tools/perf/util/tsc.c new file +25 -0
@@ -0,0 +1,25 @@ +#include <linux/compiler.h> +#include <linux/types.h> + +#include "tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc) +{ +u64 t, quot, rem; + + t = ns - tc->time_zero; + quot = t / tc->time_mult; + rem = t % tc->time_mult; +return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc) +{ +u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) -1 ); +return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +}
tools/perf/util/tsc.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __PERF_TSC_H +#define __PERF_TSC_H + +#include <linux/types.h> + +#include "../arch/x86/util/tsc.h" + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif
Adrian Hunter
reviewerPATCH 40/41 perf tools: Move rdtsc() function
In reply to Adrian HunterMove the rdtsc() function so it can
be reusued.
--- tools/perf/arch/x86/util/tsc.c | 9 +++++++++ tools/perf/tests/perf-time-to-tsc.c | 9 --------- tools/perf/util/tsc.c | 5 +++++ tools/perf/util/tsc.h | 1 + 4 files changed, 15 insertions(+), 9 deletions(-)
tools/perf/arch/x86/util/tsc.c +9 -0
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,return 0 ; } + +u64 rdtsc (void ) +{ +unsigned int low, high; + + asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); + +return low | ((u64 )high) <<32 ; +}
tools/perf/tests/perf-time-to-tsc.c +0 -9
@@ -25,15 +25,6 @@ } \ } -static u64 rdtsc (void ) -{ -unsigned int low, high; - - asmvolatile ("rdtsc" :"=a" (low),"=d" (high)); - -return low | ((u64 )high) <<32 ; -} -/** * test__perf_time_to_tsc - test converting perf time to TSC. *
tools/perf/util/tsc.c +5 -0
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)return tc->time_zero + quot * tc->time_mult + ((rem * tc->time_mult) >> tc->time_shift); } + +u64 __weak rdtsc (void ) +{ +return 0 ; +}
tools/perf/util/tsc.h +1 -0
@@ -7,5 +7,6 @@u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc);u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); +u64 rdtsc (void );#endif
Signature · 1 line
1.8.3.2
Adrian Hunter
reviewerPATCH 41/41 perf evlist: Add perf_evlist__enable_event_idx()
In reply to Adrian HunterAdd a function to enable a specific event
within a specific perf event buffer.
--- tools/perf/util/evlist.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 49 insertions(+)
tools/perf/util/evlist.c +47 -0
@@ -354,6 +354,53 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,return 0 ; } +static int perf_evlist__enable_event_cpu (struct perf_evlist *evlist, +struct perf_evsel *evsel,int cpu) +{ +int thread, err; +int nr_threads =perf_evlist__nr_threads (evlist, evsel); + +if (!evsel->fd) +return -EINVAL ; + +for (thread =0 ; thread < nr_threads; thread++) { + err =ioctl (FD (evsel, cpu, thread), +PERF_EVENT_IOC_ENABLE ,0 ); +if (err) +return err; + } +return 0 ; +} + +static int perf_evlist__enable_event_thread (struct perf_evlist *evlist, +struct perf_evsel *evsel, +int thread) +{ +int cpu, err; +int nr_cpus =cpu_map__nr (evlist->cpus); + +if (!evsel->fd) +return -EINVAL ; + +for (cpu =0 ; cpu < nr_cpus; cpu++) { + err =ioctl (FD (evsel, cpu, thread),PERF_EVENT_IOC_ENABLE ,0 ); +if (err) +return err; + } +return 0 ; +} + +int perf_evlist__enable_event_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx) +{ +bool per_cpu_mmaps = !cpu_map__empty (evlist->cpus); + +if (per_cpu_mmaps) +return perf_evlist__enable_event_cpu (evlist, evsel, idx); +else +return perf_evlist__enable_event_thread (evlist, evsel, idx); +} +static int perf_evlist__alloc_pollfd (struct perf_evlist *evlist) {int nr_cpus =cpu_map__nr (evlist->cpus);
tools/perf/util/evlist.h +2 -0
@@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel);int perf_evlist__enable_event (struct perf_evlist *evlist,struct perf_evsel *evsel); +int perf_evlist__enable_event_idx (struct perf_evlist *evlist, +struct perf_evsel *evsel,int idx);void perf_evlist__set_selected (struct perf_evlist *evlist,struct perf_evsel *evsel);
Signature · 1 line
1.8.3.2