[PATCH 29/49] perf callchain: Maintain libunwind's address space in map_groups

Jiri Olsa
2018-01-09T15:37:12Z

Currently the address_space was kept in thread struct but it's more
appropriate to keep it in map_groups as it's maintained throughout
exec's with timestamps. Also we should not flush the address space
after exec since it still can be accessed when used with an indexed
data file.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Link: http://lkml.kernel.org/n/tip-hjryh6x2yfnrz8g0djhez24z@git.kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/perf/util/map.h | 5 ++++-
tools/perf/util/thread.h | 1 -
tools/perf/util/unwind-libunwind-local.c | 25 +++++++++++++------------
tools/perf/util/unwind-libunwind.c | 9 +++++----
tools/perf/util/unwind.h | 7 ++++---
5 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index a2b3e0aa0624..9b2b39f643d8 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -71,10 +71,13 @@ struct maps {

struct map_groups {
struct maps maps[MAP__NR_TYPES];
- struct machine *machine;
+ struct machine *machine;
refcount_t refcnt;
u64 timestamp;
struct list_head list;
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ void *addr_space;
+#endif
};

struct map_groups *map_groups__new(struct machine *machine);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 614e622d884f..afaa999661a5 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -41,7 +41,6 @@ struct thread {
struct thread_stack *ts;
struct nsinfo *nsinfo;
#ifdef HAVE_LIBUNWIND_SUPPORT
- void *addr_space;
struct unwind_libunwind_ops *unwind_libunwind_ops;
#endif
};
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 2b00de870185..4b5fc17e9ea3 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -629,35 +629,35 @@ static unw_accessors_t accessors = {
.get_proc_name = get_proc_name,
};

-static int _unwind__prepare_access(struct thread *thread)
+static int _unwind__prepare_access(struct map_groups *mg)
{
if (callchain_param.record_mode != CALLCHAIN_DWARF)
return 0;

- thread->addr_space = unw_create_addr_space(&accessors, 0);
- if (!thread->addr_space) {
+ mg->addr_space = unw_create_addr_space(&accessors, 0);
+ if (!mg->addr_space) {
pr_err("unwind: Can't create unwind address space.\n");
return -ENOMEM;
}

- unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL);
+ unw_set_caching_policy(mg->addr_space, UNW_CACHE_GLOBAL);
return 0;
}

-static void _unwind__flush_access(struct thread *thread)
+static void _unwind__flush_access(struct map_groups *mg)
{
if (callchain_param.record_mode != CALLCHAIN_DWARF)
return;

- unw_flush_cache(thread->addr_space, 0, 0);
+ unw_flush_cache(mg->addr_space, 0, 0);
}

-static void _unwind__finish_access(struct thread *thread)
+static void _unwind__finish_access(struct map_groups *mg)
{
if (callchain_param.record_mode != CALLCHAIN_DWARF)
return;

- unw_destroy_addr_space(thread->addr_space);
+ unw_destroy_addr_space(mg->addr_space);
}

static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
@@ -665,7 +665,6 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
{
u64 val;
unw_word_t ips[max_stack];
- unw_addr_space_t addr_space;
unw_cursor_t c;
int ret, i = 0;

@@ -681,13 +680,15 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
* unwind itself.
*/
if (max_stack - 1 > 0) {
+ struct map_groups *mg;
+
WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
- addr_space = ui->thread->addr_space;

- if (addr_space == NULL)
+ mg = thread__get_map_groups(ui->thread, ui->sample->time);
+ if (mg == NULL || mg->addr_space == NULL)
return -1;

- ret = unw_init_remote(&c, addr_space, ui);
+ ret = unw_init_remote(&c, mg->addr_space, ui);
if (ret)
display_error(ret);

diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index b029a5e9ae49..ce8408e460f2 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -18,12 +18,13 @@ static void unwind__register_ops(struct thread *thread,
int unwind__prepare_access(struct thread *thread, struct map *map,
bool *initialized)
{
+ struct map_groups *mg = thread->mg;
const char *arch;
enum dso_type dso_type;
struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops;
int err;

- if (thread->addr_space) {
+ if (mg->addr_space) {
pr_debug("unwind: thread map already set, dso=%s\n",
map->dso->name);
if (initialized)
@@ -56,7 +57,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map,
out_register:
unwind__register_ops(thread, ops);

- err = thread->unwind_libunwind_ops->prepare_access(thread);
+ err = thread->unwind_libunwind_ops->prepare_access(thread->mg);
if (initialized)
*initialized = err ? false : true;
return err;
@@ -65,13 +66,13 @@ int unwind__prepare_access(struct thread *thread, struct map *map,
void unwind__flush_access(struct thread *thread)
{
if (thread->unwind_libunwind_ops)
- thread->unwind_libunwind_ops->flush_access(thread);
+ thread->unwind_libunwind_ops->flush_access(thread->mg);
}

void unwind__finish_access(struct thread *thread)
{
if (thread->unwind_libunwind_ops)
- thread->unwind_libunwind_ops->finish_access(thread);
+ thread->unwind_libunwind_ops->finish_access(thread->mg);
}

int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 8a44a1569a21..0f18a0858904 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -9,6 +9,7 @@ struct map;
struct perf_sample;
struct symbol;
struct thread;
+struct map_groups;

struct unwind_entry {
struct map *map;
@@ -19,9 +20,9 @@ struct unwind_entry {
typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);

struct unwind_libunwind_ops {
- int (*prepare_access)(struct thread *thread);
- void (*flush_access)(struct thread *thread);
- void (*finish_access)(struct thread *thread);
+ int (*prepare_access)(struct map_groups *mg);
+ void (*flush_access)(struct map_groups *mg);
+ void (*finish_access)(struct map_groups *mg);
int (*get_entries)(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack);
--
2.13.6