perf tools: Various fixes
Jiri Olsa
reviewerv2 cover perf tools: Various fixes
hi,
this is v2 for original post:
http://marc.info/?t=146711345400003&r=1&w=2
v2 changes:
- keep nr_numa_nodes in patch 1
- added patch 2,3,4
thanks,
jirka
---
Jiri Olsa (4):
perf tools: Transform nodes string info to struct perf tests: Fix hist accumulation test
perf tools: Add initialized arg into unwind__prepare_access perf tools: Call unwind__prepare_access for forked thread
tools/perf/tests/hists_cumulate.c | 4 ++++ tools/perf/util/callchain.h | 1 + tools/perf/util/env.c | 5 ++++- tools/perf/util/env.h | 10 +++++++++- tools/perf/util/header.c | 76 ++++++++++++++++++++++++++-------------------------------------------------- tools/perf/util/map.c | 9 ++++++++- tools/perf/util/map.h | 2 +- tools/perf/util/thread.c | 39 ++++++++++++++++++++++++++++++++++++--- tools/perf/util/unwind-libunwind.c | 11 +++++++++-- tools/perf/util/unwind.h | 9 ++++++--- tools/perf/util/util.c | 19 +++++++++++++------ 11 files changed, 117 insertions(+), 68 deletions(-)
Jiri Olsa
reviewerPATCH v2 1/4 perf tools: Transform nodes string info to struct
Storing NUMA info within struct numa_node instead of strings. This way it's usable in future patches.
Also it turned out it's slightly less code involved than using strings.
--- tools/perf/util/env.c | 5 +++- tools/perf/util/env.h | 10 ++++++- tools/perf/util/header.c | 76 +++++++++++++++++------------------------------- 3 files changed, 39 insertions(+), 52 deletions(-)
tools/perf/util/env.c +4 -1
@@ -18,10 +18,13 @@ void perf_env__exit(struct perf_env *env)zfree (&env->cmdline_argv);zfree (&env->sibling_cores);zfree (&env->sibling_threads); -zfree (&env->numa_nodes);zfree (&env->pmu_mappings);zfree (&env->cpu); +for (i =0 ; i < env->nr_numa_nodes; i++) +cpu_map__put (env->numa_nodes[i].map); +zfree (&env->numa_nodes); +for (i =0 ; i < env->caches_cnt; i++)cpu_cache_level__free (&env->caches[i]);zfree (&env->caches);
tools/perf/util/env.h +9 -1
@@ -2,6 +2,7 @@#define __PERF_ENV_H#include <linux/types.h> +#include "cpumap.h" struct cpu_topology_map {int socket_id;
@@ -18,6 +19,13 @@ struct cpu_cache_level {char *map; }; +struct numa_node { +u32 node; +u64 mem_total; +u64 mem_free; +struct cpu_map *map; +}; +struct perf_env {char *hostname;char *os_release;
@@ -40,11 +48,11 @@ struct perf_env {const char **cmdline_argv;char *sibling_cores;char *sibling_threads; -char *numa_nodes;char *pmu_mappings;struct cpu_topology_map *cpu;struct cpu_cache_level *caches;int caches_cnt; +struct numa_node *numa_nodes; };extern struct perf_env perf_env;
tools/perf/util/header.c +26 -50
126 lines not on this page · raw message
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf header: Transform nodes string info to struct
perf header: Transform nodes string info to struct
Commit-ID: c60da22aca8755b77b7f4d4caf57ada8654db939 Gitweb: http://git.kernel.org/tip/c60da22aca8755b77b7f4d4caf57ada8654db939 Author: Jiri Olsa <[email protected]> AuthorDate: Mon, 4 Jul 2016 14:16:20 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 4 Jul 2016 19:39:01 -0300
perf header: Transform nodes string info to struct
Storing NUMA info within struct numa_node instead of strings. This way it's usable in future patches.
Also it turned out it's slightly less code involved than using strings.
--- tools/perf/util/env.c | 5 +++- tools/perf/util/env.h | 10 ++++++- tools/perf/util/header.c | 76 +++++++++++++++++------------------------------- 3 files changed, 39 insertions(+), 52 deletions(-)
tools/perf/util/env.c +4 -1
@@ -18,10 +18,13 @@ void perf_env__exit(struct perf_env *env)zfree (&env->cmdline_argv);zfree (&env->sibling_cores);zfree (&env->sibling_threads); -zfree (&env->numa_nodes);zfree (&env->pmu_mappings);zfree (&env->cpu); +for (i =0 ; i < env->nr_numa_nodes; i++) +cpu_map__put (env->numa_nodes[i].map); +zfree (&env->numa_nodes); +for (i =0 ; i < env->caches_cnt; i++)cpu_cache_level__free (&env->caches[i]);zfree (&env->caches);
tools/perf/util/env.h +9 -1
@@ -2,6 +2,7 @@#define __PERF_ENV_H#include <linux/types.h> +#include "cpumap.h" struct cpu_topology_map {int socket_id;
@@ -18,6 +19,13 @@ struct cpu_cache_level {char *map; }; +struct numa_node { +u32 node; +u64 mem_total; +u64 mem_free; +struct cpu_map *map; +}; +struct perf_env {char *hostname;char *os_release;
@@ -40,11 +48,11 @@ struct perf_env {const char **cmdline_argv;char *sibling_cores;char *sibling_threads; -char *numa_nodes;char *pmu_mappings;struct cpu_topology_map *cpu;struct cpu_cache_level *caches;int caches_cnt; +struct numa_node *numa_nodes; };extern struct perf_env perf_env;
tools/perf/util/header.c +26 -50
126 lines not on this page · raw message
Jiri Olsa
reviewerPATCH v2 2/4 perf tests: Fix hist accumulation test
In reply to Jiri OlsaUser's values from .perfconfig could overload the default callchain setup and cause this test to fail. Making sure the test is using default callchain_param values.
--- tools/perf/tests/hists_cumulate.c | 4 ++++ tools/perf/util/callchain.h | 1 + tools/perf/util/util.c | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-)
tools/perf/tests/hists_cumulate.c +4 -0
@@ -216,6 +216,8 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec/* check callchain entries */ root = &he->callchain->node.rb_root; + +TEST_ASSERT_VAL ("callchains expected" , !RB_EMPTY_ROOT (root)); cnode = rb_entry(rb_first(root), struct callchain_node, rb_node); c =0 ;
@@ -666,6 +668,8 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)perf_evsel__set_sample_bit (evsel,CALLCHAIN );setup_sorting (NULL ); + + callchain_param = callchain_param_default;callchain_register_param (&callchain_param); err =add_hist_entries (hists, machine);
tools/perf/util/callchain.h +1 -0
@@ -106,6 +106,7 @@ struct callchain_param { };extern struct callchain_param callchain_param; +extern struct callchain_param callchain_param_default;struct callchain_list {u64 ip;
tools/perf/util/util.c +13 -6
@@ -19,12 +19,19 @@#include "callchain.h" #include "strlist.h" -struct callchain_param callchain_param = { - .mode =CHAIN_GRAPH_ABS , - .min_percent =0.5 , - .order =ORDER_CALLEE , - .key =CCKEY_FUNCTION , - .value =CCVAL_PERCENT , +#define CALLCHAIN_PARAM_DEFAULT \ + .mode = CHAIN_GRAPH_ABS, \ + .min_percent = 0.5, \ + .order = ORDER_CALLEE, \ + .key = CCKEY_FUNCTION, \ + .value = CCVAL_PERCENT, \ + +struct callchain_param callchain_param = { +CALLCHAIN_PARAM_DEFAULT +}; + +struct callchain_param callchain_param_default = { +CALLCHAIN_PARAM_DEFAULT };/*
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf tests: Fix hist accumulation test
perf tests: Fix hist accumulation test
Commit-ID: 347ca878062d5fb0e16db1fae81b0994f2457efd Gitweb: http://git.kernel.org/tip/347ca878062d5fb0e16db1fae81b0994f2457efd Author: Jiri Olsa <[email protected]> AuthorDate: Mon, 4 Jul 2016 14:16:21 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 4 Jul 2016 19:39:01 -0300
perf tests: Fix hist accumulation test
User's values from .perfconfig could overload the default callchain setup and cause this test to fail. Making sure the test is using default callchain_param values.
--- tools/perf/tests/hists_cumulate.c | 4 ++++ tools/perf/util/callchain.h | 1 + tools/perf/util/util.c | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-)
tools/perf/tests/hists_cumulate.c +4 -0
@@ -216,6 +216,8 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec/* check callchain entries */ root = &he->callchain->node.rb_root; + +TEST_ASSERT_VAL ("callchains expected" , !RB_EMPTY_ROOT (root)); cnode = rb_entry(rb_first(root), struct callchain_node, rb_node); c =0 ;
@@ -666,6 +668,8 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)perf_evsel__set_sample_bit (evsel,CALLCHAIN );setup_sorting (NULL ); + + callchain_param = callchain_param_default;callchain_register_param (&callchain_param); err =add_hist_entries (hists, machine);
tools/perf/util/callchain.h +1 -0
@@ -106,6 +106,7 @@ struct callchain_param { };extern struct callchain_param callchain_param; +extern struct callchain_param callchain_param_default;struct callchain_list {u64 ip;
tools/perf/util/util.c +13 -6
@@ -19,12 +19,19 @@#include "callchain.h" #include "strlist.h" -struct callchain_param callchain_param = { - .mode =CHAIN_GRAPH_ABS , - .min_percent =0.5 , - .order =ORDER_CALLEE , - .key =CCKEY_FUNCTION , - .value =CCVAL_PERCENT , +#define CALLCHAIN_PARAM_DEFAULT \ + .mode = CHAIN_GRAPH_ABS, \ + .min_percent = 0.5, \ + .order = ORDER_CALLEE, \ + .key = CCKEY_FUNCTION, \ + .value = CCVAL_PERCENT, \ + +struct callchain_param callchain_param = { +CALLCHAIN_PARAM_DEFAULT +}; + +struct callchain_param callchain_param_default = { +CALLCHAIN_PARAM_DEFAULT };/*
Jiri Olsa
reviewerPATCH v2 3/4 perf tools: Add initialized arg into unwind__prepare_access
In reply to Jiri OlsaAdding initialized arg into unwind__prepare_access to get feedback about the initialization state.
It's not possible to get it from error code, because we return 0 even in case we don't recognize dso, which is valid.
The 'initialized' value is used in following patch to speedup unwind__prepare_access calls logic in fork path.
--- tools/perf/util/thread.c | 2 +- tools/perf/util/unwind-libunwind.c | 11 +++++++++-- tools/perf/util/unwind.h | 9 ++++++--- 3 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/util/thread.c +1 -1
@@ -202,7 +202,7 @@ int thread__insert_map(struct thread *thread, struct map *map) {int ret; - ret =unwind__prepare_access (thread, map); + ret =unwind__prepare_access (thread, map,NULL );if (ret)return ret;
tools/perf/util/unwind-libunwind.c +9 -2
@@ -14,15 +14,19 @@ static void unwind__register_ops(struct thread *thread, thread->unwind_libunwind_ops = ops; } -int unwind__prepare_access (struct thread *thread,struct map *map) +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized) {const char *arch;enum dso_type dso_type;struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; +int err;if (thread->addr_space) {pr_debug ("unwind: thread map already set, dso=%s\n" , map->dso->name); +if (initialized) + *initialized = true;return 0 ; }
@@ -51,7 +55,10 @@ int unwind__prepare_access(struct thread *thread, struct map *map) out_register:unwind__register_ops (thread, ops); -return thread->unwind_libunwind_ops->prepare_access (thread); + err = thread->unwind_libunwind_ops->prepare_access (thread); +if (initialized) + *initialized = err ? false : true; +return err; }void unwind__flush_access (struct thread *thread)
tools/perf/util/unwind.h +6 -3
@@ -42,12 +42,14 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,#endif int LIBUNWIND__ARCH_REG_ID (int regnum); -int unwind__prepare_access (struct thread *thread,struct map *map); +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized);void unwind__flush_access (struct thread *thread);void unwind__finish_access (struct thread *thread);#else static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ); {return 0 ; }
@@ -67,7 +69,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, }static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ); {return 0 ; }
Signature · 1 line
2.4.11
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 3/4] perf tools: Add initialized arg into unwind__prepare_access
Em Mon, Jul 04, 2016 at 02:16:22PM +0200, Jiri Olsa escreveu:
Quoted 92 lines
Adding initialized arg into
unwind__prepare_accessto get feedback about the initialization state.It's not possible to get it from error code, because we return 0 even in case we don't recognize dso, which is valid.
The 'initialized' value is used in following patch to speedup
unwind__prepare_accesscalls logic in fork path.Cc He Kuang <[email protected]>Signed-off-by Jiri Olsa <[email protected]>--- tools/perf/util/thread.c | 2 +- tools/perf/util/unwind-libunwind.c | 11 +++++++++-- tools/perf/util/unwind.h | 9 ++++++--- 3 files changed, 16 insertions(+), 6 deletions(-)tools/perf/util/thread.c +1
-1@@ -202,7 +202,7 @@ int thread__insert_map(struct thread *thread, struct map *map) {int ret; - ret =unwind__prepare_access (thread, map); + ret =unwind__prepare_access (thread, map,NULL );if (ret)return ret;tools/perf/util/unwind-libunwind.c +9
-2@@ -14,15 +14,19 @@ static void unwind__register_ops(struct thread *thread, thread->unwind_libunwind_ops = ops; } -int unwind__prepare_access (struct thread *thread,struct map *map) +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized) {const char *arch;enum dso_type dso_type;struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; +int err;if (thread->addr_space) {pr_debug ("unwind: thread map already set, dso=%s\n" , map->dso->name); +if (initialized) + *initialized = true;return 0 ; }@@ -51,7 +55,10 @@ int unwind__prepare_access(struct thread *thread, struct map *map) out_register:unwind__register_ops (thread, ops); -return thread->unwind_libunwind_ops->prepare_access (thread); + err = thread->unwind_libunwind_ops->prepare_access (thread); +if (initialized) + *initialized = err ? false : true; +return err; }void unwind__flush_access (struct thread *thread)tools/perf/util/unwind.h +4
-2@@ -42,12 +42,14 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,#endif int LIBUNWIND__ARCH_REG_ID (int regnum); -int unwind__prepare_access (struct thread *thread,struct map *map); +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized);void unwind__flush_access (struct thread *thread);void unwind__finish_access (struct thread *thread);#else static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ); {return 0 ; }
tools/perf/util/unwind.h unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, · line 76
Quoted 9 lines
tools/perf/util/unwind.h +2
-1@@ -67,7 +69,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, }static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ); {return 0 ; }
That extra ; breaks the build on centos5 (i.e. on an arch where the above code gets compiled:
CC /tmp/build/perf/bench/sched-pipe.o
In file included from util/machine.c:14:util/unwind.h:74: error: expected identifier or '(' before '{' token
MKDIR /tmp/build/perf/tests/
CC /tmp/build/perf/tests/parse-events.o
mv: cannot stat `/tmp/build/perf/util/.machine.o.tmp': No such file or directory make[3]: *** [/tmp/build/perf/util/machine.o] Error 1
make[3]: *** Waiting for unfinished jobs....
MKDIR /tmp/build/perf/tests/
CC /tmp/build/perf/tests/dso-data.o
make[2]: *** [util] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
make[1]: *** Waiting for unfinished jobs....
MKDIR /tmp/build/perf/tests/
Fixing it.
Quoted 2 lines
Signature · 1 line
2.4.11
Re: [PATCH 3/4] perf tools: Add initialized arg into unwind__prepare_access
On Mon, Jul 04, 2016 at 04:25:11PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 31 lines
tools/perf/util/unwind.h unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, · line 76
Quoted 11 lines
}
tools/perf/util/unwind.h +2
-1@@ -67,7 +69,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, }static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ); {return 0 ; }That extra ; breaks the build on centos5 (i.e. on an arch where the above code gets compiled:
CC
/tmp/build/perf/bench/sched-pipe.o
In file included fromutil/machine.c:14:util/unwind.h:74: error: expected identifier or '(' before '{' token
MKDIR/tmp/build/perf/tests/
CC/tmp/build/perf/tests/parse-events.o
mv: cannot stat `/tmp/build/perf/util/.machine.o.tmp': No such file or directory make[3]: *** [/tmp/build/perf/util/machine.o] Error 1
make[3]: *** Waiting for unfinished jobs....
MKDIR/tmp/build/perf/tests/
CC/tmp/build/perf/tests/dso-data.o
make[2]: *** [util] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
make[1]: *** Waiting for unfinished jobs....
MKDIR/tmp/build/perf/tests/
Quoted 1 line
Fixing it.
oops, thanks
jirka
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf unwind: Add initialized arg into unwind__prepare_access
In reply to Jiri Olsaperf unwind: Add initialized arg into unwind__prepare_access
Commit-ID: a2873325ffb21cecca8032673eb698cb4d778dc6 Gitweb: http://git.kernel.org/tip/a2873325ffb21cecca8032673eb698cb4d778dc6 Author: Jiri Olsa <[email protected]> AuthorDate: Mon, 4 Jul 2016 14:16:22 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 4 Jul 2016 20:27:12 -0300
perf unwind: Add initialized arg into unwind__prepare_access
Adding initialized arg into unwind__prepare_access to get feedback about the initialization state.
It's not possible to get it from error code, because we return 0 even in case we don't recognize dso, which is valid.
The 'initialized' value is used in following patch to speedup unwind__prepare_access calls logic in fork path.
--- tools/perf/util/thread.c | 2 +- tools/perf/util/unwind-libunwind.c | 11 +++++++++-- tools/perf/util/unwind.h | 9 ++++++--- 3 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/util/thread.c +1 -1
@@ -202,7 +202,7 @@ int thread__insert_map(struct thread *thread, struct map *map) {int ret; - ret =unwind__prepare_access (thread, map); + ret =unwind__prepare_access (thread, map,NULL );if (ret)return ret;
tools/perf/util/unwind-libunwind.c +9 -2
@@ -14,15 +14,19 @@ static void unwind__register_ops(struct thread *thread, thread->unwind_libunwind_ops = ops; } -int unwind__prepare_access (struct thread *thread,struct map *map) +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized) {const char *arch;enum dso_type dso_type;struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; +int err;if (thread->addr_space) {pr_debug ("unwind: thread map already set, dso=%s\n" , map->dso->name); +if (initialized) + *initialized = true;return 0 ; }
@@ -51,7 +55,10 @@ int unwind__prepare_access(struct thread *thread, struct map *map) out_register:unwind__register_ops (thread, ops); -return thread->unwind_libunwind_ops->prepare_access (thread); + err = thread->unwind_libunwind_ops->prepare_access (thread); +if (initialized) + *initialized = err ? false : true; +return err; }void unwind__flush_access (struct thread *thread)
tools/perf/util/unwind.h +6 -3
@@ -42,12 +42,14 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,#endif int LIBUNWIND__ARCH_REG_ID (int regnum); -int unwind__prepare_access (struct thread *thread,struct map *map); +int unwind__prepare_access (struct thread *thread,struct map *map, +bool *initialized);void unwind__flush_access (struct thread *thread);void unwind__finish_access (struct thread *thread);#else static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ) {return 0 ; }
@@ -67,7 +69,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, }static inline int unwind__prepare_access (struct thread *thread__maybe_unused , -struct map *map__maybe_unused ) +struct map *map__maybe_unused , +bool *initialized__maybe_unused ) {return 0 ; }
Jiri Olsa
reviewerPATCH v2 4/4 perf tools: Call unwind__prepare_access for forked thread
In reply to Jiri OlsaCurrently we call unwind__prepare_access for map event. In case we report fork event the thread inherits its parent's maps and unwind__prepare_access is never called for the thread.
This causes unwind__get_entries seeing uninitialized unwind_libunwind_ops and thus returning no callchain.
Adding unwind__prepare_access calls for fork even processing.
--- tools/perf/util/map.c | 9 ++++++++- tools/perf/util/map.h | 2 +- tools/perf/util/thread.c | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-)
tools/perf/util/map.c +8 -1
@@ -15,6 +15,7 @@#include "debug.h" #include "machine.h" #include <linux/string.h> +#include "unwind.h" static void __maps__insert (struct maps *maps,struct map *map);
@@ -744,9 +745,10 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,/* * XXX This should not really _copy_ te maps, but refcount them. */ -int map_groups__clone (struct map_groups *mg, +int map_groups__clone (struct thread *thread,struct map_groups *parent,enum map_type type) { +struct map_groups *mg = thread->mg;int err = -ENOMEM ;struct map *map;struct maps *maps = &parent->maps[type];
@@ -757,6 +759,11 @@ int map_groups__clone(struct map_groups *mg,struct map *new =map__clone (map);if (new ==NULL ) goto out_unlock; + + err =unwind__prepare_access (thread, new,NULL ); +if (err) + goto out_unlock; +map_groups__insert (mg, new);map__put (new); }
tools/perf/util/map.h +1 -1
@@ -194,7 +194,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp, symbol_filter_t filter);void map_groups__init (struct map_groups *mg,struct machine *machine);void map_groups__exit (struct map_groups *mg); -int map_groups__clone (struct map_groups *mg, +int map_groups__clone (struct thread *thread,struct map_groups *parent,enum map_type type);size_t map_groups__fprintf (struct map_groups *mg,FILE *fp);
tools/perf/util/thread.c +35 -2
@@ -212,6 +212,39 @@ int thread__insert_map(struct thread *thread, struct map *map)return 0 ; } +static int __thread__prepare_access (struct thread *thread) +{ +bool initialized = false; +int i, err =0 ; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +struct maps *maps = &thread->mg->maps[i]; +struct map *map; + +pthread_rwlock_rdlock (&maps->lock); + +for (map =maps__first (maps); map; map =map__next (map)) { + err =unwind__prepare_access (thread, map, &initialized); +if (err || initialized) +break ; + } + +pthread_rwlock_unlock (&maps->lock); + } + +return err; +} + +static int thread__prepare_access (struct thread *thread) +{ +int err =0 ; + +if (symbol_conf.use_callchain) + err =__thread__prepare_access (thread); + +return err; +} +static int thread__clone_map_groups (struct thread *thread,struct thread *parent) {
@@ -219,7 +252,7 @@ static int thread__clone_map_groups(struct thread *thread,/* This is new thread, we share map groups for process. */ if (thread->pid_ == parent->pid_) -return 0 ; +return thread__prepare_access (thread);if (thread->mg == parent->mg) { pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
@@ -229,7 +262,7 @@ static int thread__clone_map_groups(struct thread *thread,/* But this one is new process, copy maps. */ for (i =0 ; i <MAP__NR_TYPES ; ++i) -if (map_groups__clone (thread->mg, parent->mg, i) <0 ) +if (map_groups__clone (thread, parent->mg, i) <0 )return -ENOMEM ;return 0 ;
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf unwind: Call unwind__prepare_access for forked thread
perf unwind: Call unwind__prepare_access for forked thread
Commit-ID: 6c502584438bda63fc1a67606854fb0b300465cd Gitweb: http://git.kernel.org/tip/6c502584438bda63fc1a67606854fb0b300465cd Author: Jiri Olsa <[email protected]> AuthorDate: Mon, 4 Jul 2016 14:16:23 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 4 Jul 2016 20:27:25 -0300
perf unwind: Call unwind__prepare_access for forked thread
Currently we call unwind__prepare_access for map event. In case we report fork event the thread inherits its parent's maps and unwind__prepare_access is never called for the thread.
This causes unwind__get_entries seeing uninitialized unwind_libunwind_ops and thus returning no callchain.
Adding unwind__prepare_access calls for fork even processing.
--- tools/perf/util/map.c | 9 ++++++++- tools/perf/util/map.h | 2 +- tools/perf/util/thread.c | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-)
tools/perf/util/map.c +8 -1
@@ -15,6 +15,7 @@#include "debug.h" #include "machine.h" #include <linux/string.h> +#include "unwind.h" static void __maps__insert (struct maps *maps,struct map *map);
@@ -744,9 +745,10 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,/* * XXX This should not really _copy_ te maps, but refcount them. */ -int map_groups__clone (struct map_groups *mg, +int map_groups__clone (struct thread *thread,struct map_groups *parent,enum map_type type) { +struct map_groups *mg = thread->mg;int err = -ENOMEM ;struct map *map;struct maps *maps = &parent->maps[type];
@@ -757,6 +759,11 @@ int map_groups__clone(struct map_groups *mg,struct map *new =map__clone (map);if (new ==NULL ) goto out_unlock; + + err =unwind__prepare_access (thread, new,NULL ); +if (err) + goto out_unlock; +map_groups__insert (mg, new);map__put (new); }
tools/perf/util/map.h +1 -1
@@ -194,7 +194,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp, symbol_filter_t filter);void map_groups__init (struct map_groups *mg,struct machine *machine);void map_groups__exit (struct map_groups *mg); -int map_groups__clone (struct map_groups *mg, +int map_groups__clone (struct thread *thread,struct map_groups *parent,enum map_type type);size_t map_groups__fprintf (struct map_groups *mg,FILE *fp);
tools/perf/util/thread.c +35 -2
@@ -212,6 +212,39 @@ int thread__insert_map(struct thread *thread, struct map *map)return 0 ; } +static int __thread__prepare_access (struct thread *thread) +{ +bool initialized = false; +int i, err =0 ; + +for (i =0 ; i <MAP__NR_TYPES ; ++i) { +struct maps *maps = &thread->mg->maps[i]; +struct map *map; + +pthread_rwlock_rdlock (&maps->lock); + +for (map =maps__first (maps); map; map =map__next (map)) { + err =unwind__prepare_access (thread, map, &initialized); +if (err || initialized) +break ; + } + +pthread_rwlock_unlock (&maps->lock); + } + +return err; +} + +static int thread__prepare_access (struct thread *thread) +{ +int err =0 ; + +if (symbol_conf.use_callchain) + err =__thread__prepare_access (thread); + +return err; +} +static int thread__clone_map_groups (struct thread *thread,struct thread *parent) {
@@ -219,7 +252,7 @@ static int thread__clone_map_groups(struct thread *thread,/* This is new thread, we share map groups for process. */ if (thread->pid_ == parent->pid_) -return 0 ; +return thread__prepare_access (thread);if (thread->mg == parent->mg) { pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
@@ -229,7 +262,7 @@ static int thread__clone_map_groups(struct thread *thread,/* But this one is new process, copy maps. */ for (i =0 ; i <MAP__NR_TYPES ; ++i) -if (map_groups__clone (thread->mg, parent->mg, i) <0 ) +if (map_groups__clone (thread, parent->mg, i) <0 )return -ENOMEM ;return 0 ;