2014-01-07 12:52:16

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

hi,
adding libdw DWARF unwind support, which is part of just released
elfutils package 0.158.

We can now compile perf to have either libunwind DWARF unwind,
(which is still default) or the new one libdw unwind.

Examples:
- compile in libdw unwinder if present:
$ make NO_LIBUNWIND=1

- compile in libdw (with libdw installation directory) unwinder if present:
$ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1

- disable post dwarf unwind completely:
$ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1

Performance wise the libdw unwinder seems to be faster.
Following results are from 2GB perf.data file with 249156
samples:

The libdw unwind perf:
$ time perf report -i ~/perf.data > perf.data.ldw

real 0m35.746s
user 0m24.211s
sys 0m11.214s

The libunwind unwind perf:
$ time perf report -i ~/perf.data > perf.data.unw

real 1m41.149s
user 1m9.694s
sys 0m30.595s

In example above I've got 2206 differences (perf.data.ldw and
perf.data.unw files) in the callchains output out of the 249156
samples which is below 1%. Together with some other tips for speed
increase it's on my TODO list for future.

Git tree:
https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
perf/core_libdw_unwind

Kudos to Jan Kratochvil for helping me with the new interface.

Jean,
I haven't tested on arm.. so not sure I broke anything there.
Any chance you could test for me, and maybe make the automated
test I added work there? ;-)

thanks,
jirka


Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jan Kratochvil <[email protected]>
Cc: Jean Pihet <[email protected]>
---
Jiri Olsa (16):
perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
perf tools: Fix machine initialization
perf tools: Make perf_event__synthesize_mmap_events global
perf tests x86: Introduce perf_regs_load function
perf tests x86: Add dwarf unwind test
perf tools: Fix dwarf unwind max_stack processing
perf tools: Do not report zero address in unwind
perf tools: Add mask into struct regs_dump
perf tools: Separate libunwind code to special object
perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
perf tools: Separate perf_reg_value function in perf_regs object
perf tools: Add feature check for libdw dwarf unwind
perf tools: Add libdw DWARF post unwind support
perf tools: Setup default dwarf post unwinder
perf tests: Add NO_LIBDW_DWARF_UNWIND make test

tools/perf/Makefile.perf | 19 ++++++-
tools/perf/arch/arm/Makefile | 2 +-
tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
tools/perf/arch/x86/Makefile | 9 +++-
tools/perf/arch/x86/include/perf_regs.h | 6 +++
tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
tools/perf/builtin-inject.c | 1 -
tools/perf/builtin-record.c | 10 ++--
tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
tools/perf/config/feature-checks/Makefile | 6 ++-
tools/perf/config/feature-checks/test-all.c | 5 ++
tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
tools/perf/tests/builtin-test.c | 8 +++
tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/tests/make | 63 +++++++++++-----------
tools/perf/tests/sample-parsing.c | 17 +++---
tools/perf/tests/tests.h | 9 ++++
tools/perf/util/event.c | 12 ++---
tools/perf/util/event.h | 12 ++++-
tools/perf/util/evsel.c | 13 ++---
tools/perf/util/machine.c | 4 +-
tools/perf/util/perf_regs.c | 19 +++++++
tools/perf/util/perf_regs.h | 13 +++++
tools/perf/util/session.c | 5 +-
tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/unwind-libdw.h | 21 ++++++++
tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
tools/perf/util/unwind.h | 11 ++--
31 files changed, 849 insertions(+), 135 deletions(-)
rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
create mode 100644 tools/perf/arch/x86/tests/regs_load.S
create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
create mode 100644 tools/perf/tests/dwarf-unwind.c
create mode 100644 tools/perf/util/perf_regs.c
create mode 100644 tools/perf/util/unwind-libdw.c
create mode 100644 tools/perf/util/unwind-libdw.h
rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)


2014-01-07 12:48:01

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 02/16] perf tools: Fix machine initialization

The id_hdr_size field was not properly initialized,
setting it to zero.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/util/machine.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index a98538d..0130279 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -27,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->pid = pid;

machine->symbol_filter = NULL;
+ machine->id_hdr_size = 0;

machine->root_dir = strdup(root_dir);
if (machine->root_dir == NULL)
--
1.8.3.1

2014-01-07 12:48:11

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 01/16] perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables

Instead of explicitly adding same value into
FEATURE_CHECK_(C|LD)FLAGS-all variables we can
do that automatically.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/config/Makefile | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f2bc659..5d15b43 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -53,9 +53,6 @@ else
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
- # and the flags for the test-all case
- FEATURE_CHECK_CFLAGS-all += $(LIBUNWIND_CFLAGS)
- FEATURE_CHECK_LDFLAGS-all += $(LIBUNWIND_LDFLAGS)
endif

ifeq ($(NO_PERF_REGS),0)
@@ -152,6 +149,17 @@ CORE_FEATURE_TESTS = \
stackprotector-all \
timerfd

+# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
+# If in the future we need per-feature checks/flags for features not
+# mentioned in this list we need to refactor this ;-).
+set_test_all_flags = $(eval $(set_test_all_flags_code))
+define set_test_all_flags_code
+ FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1))
+ FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
+endef
+
+$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
+
#
# So here we detect whether test-all was rebuilt, to be able
# to skip the print-out of the long features list if the file
--
1.8.3.1

2014-01-07 12:48:20

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 03/16] perf tools: Make perf_event__synthesize_mmap_events global

Making perf_event__synthesize_mmap_events global, it's used
in following patch from test code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/util/event.c | 12 ++++++------
tools/perf/util/event.h | 7 +++++++
2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 45a76c6..1fc1c2f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -175,12 +175,12 @@ out:
return tgid;
}

-static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
- union perf_event *event,
- pid_t pid, pid_t tgid,
- perf_event__handler_t process,
- struct machine *machine,
- bool mmap_data)
+int perf_event__synthesize_mmap_events(struct perf_tool *tool,
+ union perf_event *event,
+ pid_t pid, pid_t tgid,
+ perf_event__handler_t process,
+ struct machine *machine,
+ bool mmap_data)
{
char filename[PATH_MAX];
FILE *fp;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 30fec99..faf6e21 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -266,6 +266,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
const struct perf_sample *sample,
bool swapped);

+int perf_event__synthesize_mmap_events(struct perf_tool *tool,
+ union perf_event *event,
+ pid_t pid, pid_t tgid,
+ perf_event__handler_t process,
+ struct machine *machine,
+ bool mmap_data);
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
--
1.8.3.1

2014-01-07 12:48:30

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 08/16] perf tools: Add mask into struct regs_dump

Adding mask info into struct regs_dump to make the
registers information compact.

The mask was always passed along, so logically the mask
info fits more into the struct regs_dump.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Adrian Hunter <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/arch/x86/tests/dwarf-unwind.c | 1 +
tools/perf/builtin-inject.c | 1 -
tools/perf/tests/dwarf-unwind.c | 2 +-
tools/perf/tests/sample-parsing.c | 17 ++++++++---------
tools/perf/util/event.h | 5 +++--
tools/perf/util/evsel.c | 13 +++++++------
tools/perf/util/machine.c | 3 +--
tools/perf/util/session.c | 5 +++--
tools/perf/util/unwind.c | 20 ++++++++------------
tools/perf/util/unwind.h | 2 --
10 files changed, 32 insertions(+), 37 deletions(-)

diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 371f849..b602ad9 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -53,6 +53,7 @@ int test__arch_unwind_sample(struct perf_sample *sample,
perf_regs_load(buf);
regs->abi = PERF_SAMPLE_REGS_ABI;
regs->regs = buf;
+ regs->mask = PERF_REGS_MASK;

return sample_ustack(sample, thread, buf);
}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index c9f6d74..597cf4c 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -312,7 +312,6 @@ found:
sample_sw.period = sample->period;
sample_sw.time = sample->time;
perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
- evsel->attr.sample_regs_user,
evsel->attr.read_format, &sample_sw,
false);
build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index a203c0c..f16ea28 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
}

err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
- PERF_REGS_MASK, &sample, MAX_STACK);
+ &sample, MAX_STACK);
if (err)
pr_debug("unwind failed\n");
else if (cnt != MAX_STACK) {
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 1b67720..0014d3c 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -22,8 +22,8 @@
} while (0)

static bool samples_same(const struct perf_sample *s1,
- const struct perf_sample *s2, u64 type, u64 regs_user,
- u64 read_format)
+ const struct perf_sample *s2,
+ u64 type, u64 read_format)
{
size_t i;

@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
}

if (type & PERF_SAMPLE_REGS_USER) {
- size_t sz = hweight_long(regs_user) * sizeof(u64);
+ size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);

+ COMP(user_regs.mask);
COMP(user_regs.abi);
if (s1->user_regs.abi &&
(!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.branch_stack = &branch_stack.branch_stack,
.user_regs = {
.abi = PERF_SAMPLE_REGS_ABI_64,
+ .mask = sample_regs_user,
.regs = user_regs,
},
.user_stack = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
sample.read.one.id = 99;
}

- sz = perf_event__sample_event_size(&sample, sample_type,
- sample_regs_user, read_format);
+ sz = perf_event__sample_event_size(&sample, sample_type, read_format);
bufsz = sz + 4096; /* Add a bit for overrun checking */
event = malloc(bufsz);
if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
event->header.misc = 0;
event->header.size = sz;

- err = perf_event__synthesize_sample(event, sample_type,
- sample_regs_user, read_format,
+ err = perf_event__synthesize_sample(event, sample_type, read_format,
&sample, false);
if (err) {
pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
goto out_free;
}

- if (!samples_same(&sample, &sample_out, sample_type,
- sample_regs_user, read_format)) {
+ if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
pr_debug("parsing failed for sample_type %#"PRIx64"\n",
sample_type);
goto out_free;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index faf6e21..4bf996d 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -85,6 +85,7 @@ struct sample_event {

struct regs_dump {
u64 abi;
+ u64 mask;
u64 *regs;
};

@@ -260,9 +261,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
const char *perf_event__name(unsigned int id);

size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format);
+ u64 read_format);
int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped);

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ade8d9c..8483b80 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1396,10 +1396,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array++;

if (data->user_regs.abi) {
- u64 regs_user = evsel->attr.sample_regs_user;
+ u64 mask = evsel->attr.sample_regs_user;

- sz = hweight_long(regs_user) * sizeof(u64);
+ sz = hweight_long(mask) * sizeof(u64);
OVERFLOW_CHECK(array, sz, max_size);
+ data->user_regs.mask = mask;
data->user_regs.regs = (u64 *)array;
array = (void *)array + sz;
}
@@ -1451,7 +1452,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
}

size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format)
+ u64 read_format)
{
size_t sz, result = sizeof(struct sample_event);

@@ -1517,7 +1518,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
result += sizeof(u64);
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
result += sz;
} else {
result += sizeof(u64);
@@ -1546,7 +1547,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
}

int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped)
{
@@ -1687,7 +1688,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
*array++ = sample->user_regs.abi;
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
memcpy(array, sample->user_regs.regs, sz);
array = (void *)array + sz;
} else {
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 0130279..21140b3 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1361,8 +1361,7 @@ int machine__resolve_callchain(struct machine *machine,
return 0;

return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
- thread, evsel->attr.sample_regs_user,
- sample, max_stack);
+ thread, sample, max_stack);

}

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8ffe29c..d8d957f 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
}
}

-static void regs_user__printf(struct perf_sample *sample, u64 mask)
+static void regs_user__printf(struct perf_sample *sample)
{
struct regs_dump *user_regs = &sample->user_regs;

if (user_regs->regs) {
+ u64 mask = user_regs->mask;
printf("... user regs: mask 0x%" PRIx64 "\n", mask);
regs_dump__printf(mask, user_regs->regs);
}
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
branch_stack__printf(sample);

if (sample_type & PERF_SAMPLE_REGS_USER)
- regs_user__printf(sample, evsel->attr.sample_regs_user);
+ regs_user__printf(sample);

if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 057d4cc..226586e 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -85,7 +85,6 @@ struct unwind_info {
struct perf_sample *sample;
struct machine *machine;
struct thread *thread;
- u64 sample_uregs;
};

#define dw_read(ptr, type, end) ({ \
@@ -407,16 +406,16 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
return !(size == sizeof(*data));
}

-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
- u64 sample_regs)
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
{
int i, idx = 0;
+ u64 mask = regs->mask;

- if (!(sample_regs & (1 << id)))
+ if (!(mask & (1 << id)))
return -EINVAL;

for (i = 0; i < id; i++) {
- if (sample_regs & (1 << i))
+ if (mask & (1 << i))
idx++;
}

@@ -440,8 +439,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
return 0;
}

- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
- ui->sample_uregs);
+ ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
if (ret)
return ret;

@@ -491,7 +489,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
if (id < 0)
return -EINVAL;

- ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
+ ret = reg_value(valp, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
@@ -588,13 +586,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,

int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct thread *thread,
- u64 sample_uregs, struct perf_sample *data,
- int max_stack)
+ struct perf_sample *data, int max_stack)
{
unw_word_t ip;
struct unwind_info ui = {
.sample = data,
- .sample_uregs = sample_uregs,
.thread = thread,
.machine = machine,
};
@@ -603,7 +599,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (!data->user_regs.regs)
return -EINVAL;

- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
+ ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (ret)
return ret;

diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index d5966f49..356e1d6 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -17,7 +17,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
- u64 sample_uregs,
struct perf_sample *data, int max_stack);
int unwind__arch_reg_id(int regnum);
#else
@@ -26,7 +25,6 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
void *arg __maybe_unused,
struct machine *machine __maybe_unused,
struct thread *thread __maybe_unused,
- u64 sample_uregs __maybe_unused,
struct perf_sample *data __maybe_unused,
int max_stack __maybe_unused)
{
--
1.8.3.1

2014-01-07 12:48:43

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 05/16] perf tests x86: Add dwarf unwind test

Adding dwarf unwind test, that setups live machine data over
the perf test thread and does the remote unwind.

At this moment this test fails due to bug in the max_stack
processing in unwind__get_entries function. This is fixed
in following patch.

Need to use -fno-optimize-sibling-calls for test compilation,
otherwise 'krava_*' function calls are optimized into jumps
and ommited from the stack unwind.

So far it's enable only for x86.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/Makefile.perf | 8 ++
tools/perf/arch/x86/Makefile | 1 +
tools/perf/arch/x86/include/perf_regs.h | 4 +
tools/perf/arch/x86/tests/dwarf-unwind.c | 58 +++++++++++++
tools/perf/tests/builtin-test.c | 8 ++
tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++
tools/perf/tests/tests.h | 9 ++
7 files changed, 232 insertions(+)
create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
create mode 100644 tools/perf/tests/dwarf-unwind.c

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3638b0b..eb39519 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -407,6 +407,11 @@ endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
+ifndef NO_LIBUNWIND
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
+endif
+endif

BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -654,6 +659,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
-DPYTHON='"$(PYTHON_WORD)"' \
$<

+$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
+ $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
+
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<

diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 1cbef73..948ea6c 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -5,6 +5,7 @@ endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index f3435d62..fc819ca 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -9,12 +9,16 @@ void perf_regs_load(u64 *regs);

#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_X86_32_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
#else
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
(1ULL << PERF_REG_X86_ES) | \
(1ULL << PERF_REG_X86_FS) | \
(1ULL << PERF_REG_X86_GS))
#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#define PERF_REGS_MAX PERF_REG_X86_64_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#endif
#define PERF_REG_IP PERF_REG_X86_IP
#define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644
index 0000000..371f849
--- /dev/null
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -0,0 +1,58 @@
+#include <string.h>
+#include "perf_regs.h"
+#include "thread.h"
+#include "map.h"
+#include "event.h"
+#include "tests/tests.h"
+
+#define STACK_SIZE 8192
+
+static int sample_ustack(struct perf_sample *sample,
+ struct thread *thread, u64 *regs)
+{
+ struct stack_dump *stack = &sample->user_stack;
+ struct map *map;
+ unsigned long sp;
+ u64 stack_size, *buf;
+
+ buf = malloc(STACK_SIZE);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ sp = (unsigned long) regs[PERF_REG_X86_SP];
+
+ map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+ if (!map) {
+ pr_debug("failed to get stack map\n");
+ return -1;
+ }
+
+ stack_size = map->end - sp;
+ stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
+
+ memcpy(buf, (void *) sp, stack_size);
+ stack->data = (char *) buf;
+ stack->size = stack_size;
+ return 0;
+}
+
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread)
+{
+ struct regs_dump *regs = &sample->user_regs;
+ u64 *buf;
+
+ buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ perf_regs_load(buf);
+ regs->abi = PERF_SAMPLE_REGS_ABI;
+ regs->regs = buf;
+
+ return sample_ustack(sample, thread, buf);
+}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 1e67437..f5a6ffb 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -115,6 +115,14 @@ static struct test {
.desc = "Test parsing with no sample_id_all bit set",
.func = test__parse_no_sample_id_all,
},
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ {
+ .desc = "Test dwarf unwind",
+ .func = test__dwarf_unwind,
+ },
+#endif
+#endif
{
.func = NULL,
},
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644
index 0000000..a203c0c
--- /dev/null
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -0,0 +1,144 @@
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "debug.h"
+#include "machine.h"
+#include "event.h"
+#include "unwind.h"
+#include "perf_regs.h"
+#include "map.h"
+#include "thread.h"
+
+static int mmap_handler(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap_event(machine, event, NULL);
+}
+
+static int init_live_machine(struct machine *machine)
+{
+ union perf_event event;
+ pid_t pid = getpid();
+
+ return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+ mmap_handler, machine, true);
+}
+
+#define MAX_STACK 6
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+ unsigned long *cnt = (unsigned long *) arg;
+ char *symbol = entry->sym ? entry->sym->name : NULL;
+ static const char *funcs[MAX_STACK] = {
+ "test__arch_unwind_sample",
+ "unwind_thread",
+ "krava_3",
+ "krava_2",
+ "krava_1",
+ "test__dwarf_unwind"
+ };
+
+ if (*cnt >= MAX_STACK) {
+ pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
+ return -1;
+ }
+
+ if (!symbol) {
+ pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
+ entry->ip);
+ return -1;
+ }
+
+ pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
+ return strcmp((const char *) symbol, funcs[(*cnt)++]);
+}
+
+__attribute__ ((noinline))
+static int unwind_thread(struct thread *thread, struct machine *machine)
+{
+ struct perf_sample sample;
+ unsigned long cnt = 0;
+ int err = -1;
+
+ memset(&sample, 0, sizeof(sample));
+
+ if (test__arch_unwind_sample(&sample, thread)) {
+ pr_debug("failed to get unwind sample\n");
+ goto out;
+ }
+
+ err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+ PERF_REGS_MASK, &sample, MAX_STACK);
+ if (err)
+ pr_debug("unwind failed\n");
+ else if (cnt != MAX_STACK) {
+ pr_debug("got wrong number of stack entries %lu != %d\n",
+ cnt, MAX_STACK);
+ err = -1;
+ }
+
+ out:
+ free(sample.user_stack.data);
+ free(sample.user_regs.regs);
+ return err;
+}
+
+__attribute__ ((noinline))
+static int krava_3(struct thread *thread, struct machine *machine)
+{
+ return unwind_thread(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_2(struct thread *thread, struct machine *machine)
+{
+ return krava_3(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_1(struct thread *thread, struct machine *machine)
+{
+ return krava_2(thread, machine);
+}
+
+int test__dwarf_unwind(void)
+{
+ struct machines machines;
+ struct machine *machine;
+ struct thread *thread;
+ int err = -1;
+
+ machines__init(&machines);
+
+ machine = machines__find(&machines, HOST_KERNEL_ID);
+ if (!machine) {
+ pr_err("Could not get machine\n");
+ return -1;
+ }
+
+ if (init_live_machine(machine)) {
+ pr_err("Could not init machine\n");
+ goto out;
+ }
+
+ if (verbose > 1)
+ machine__fprintf(machine, stderr);
+
+ thread = machine__find_thread(machine, getpid());
+ if (!thread) {
+ pr_err("Could not get thread\n");
+ goto out;
+ }
+
+ err = krava_1(thread, machine);
+
+ out:
+ machine__delete_threads(machine);
+ machine__exit(machine);
+ machines__exit(&machines);
+ return err;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index e0ac713..8979309 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -40,5 +40,14 @@ int test__code_reading(void);
int test__sample_parsing(void);
int test__keep_tracking(void);
int test__parse_no_sample_id_all(void);
+int test__dwarf_unwind(void);

+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_LIBUNWIND_SUPPORT
+struct thread;
+struct perf_sample;
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread);
+#endif
+#endif
#endif /* TESTS_H */
--
1.8.3.1

2014-01-07 12:48:52

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 09/16] perf tools: Separate libunwind code to special object

We are going to add libdw library support to do dwarf
post unwind.

Making the code ready by moving libunwind dwarf post
unwind stuff into separate object.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/Makefile.perf | 2 +-
tools/perf/arch/arm/Makefile | 2 +-
tools/perf/arch/arm/util/unwind-libunwind.c | 48 +++
tools/perf/arch/arm/util/unwind.c | 48 ---
tools/perf/arch/x86/Makefile | 2 +-
tools/perf/arch/x86/util/unwind-libunwind.c | 111 +++++
tools/perf/arch/x86/util/unwind.c | 111 -----
tools/perf/util/unwind-libunwind.c | 611 ++++++++++++++++++++++++++++
tools/perf/util/unwind.c | 611 ----------------------------
9 files changed, 773 insertions(+), 773 deletions(-)
create mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/arm/util/unwind.c
create mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/x86/util/unwind.c
create mode 100644 tools/perf/util/unwind-libunwind.c
delete mode 100644 tools/perf/util/unwind.c

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index eb39519..29e7e2b 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -480,7 +480,7 @@ endif # NO_DWARF
endif # NO_LIBELF

ifndef NO_LIBUNWIND
- LIB_OBJS += $(OUTPUT)util/unwind.o
+ LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
endif
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o

diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index fe9b61e..67e9b3d 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
endif
diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
new file mode 100644
index 0000000..da3dc95
--- /dev/null
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -0,0 +1,48 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+int unwind__arch_reg_id(int regnum)
+{
+ switch (regnum) {
+ case UNW_ARM_R0:
+ return PERF_REG_ARM_R0;
+ case UNW_ARM_R1:
+ return PERF_REG_ARM_R1;
+ case UNW_ARM_R2:
+ return PERF_REG_ARM_R2;
+ case UNW_ARM_R3:
+ return PERF_REG_ARM_R3;
+ case UNW_ARM_R4:
+ return PERF_REG_ARM_R4;
+ case UNW_ARM_R5:
+ return PERF_REG_ARM_R5;
+ case UNW_ARM_R6:
+ return PERF_REG_ARM_R6;
+ case UNW_ARM_R7:
+ return PERF_REG_ARM_R7;
+ case UNW_ARM_R8:
+ return PERF_REG_ARM_R8;
+ case UNW_ARM_R9:
+ return PERF_REG_ARM_R9;
+ case UNW_ARM_R10:
+ return PERF_REG_ARM_R10;
+ case UNW_ARM_R11:
+ return PERF_REG_ARM_FP;
+ case UNW_ARM_R12:
+ return PERF_REG_ARM_IP;
+ case UNW_ARM_R13:
+ return PERF_REG_ARM_SP;
+ case UNW_ARM_R14:
+ return PERF_REG_ARM_LR;
+ case UNW_ARM_R15:
+ return PERF_REG_ARM_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", regnum);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind.c
deleted file mode 100644
index da3dc95..0000000
--- a/tools/perf/arch/arm/util/unwind.c
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-
-int unwind__arch_reg_id(int regnum)
-{
- switch (regnum) {
- case UNW_ARM_R0:
- return PERF_REG_ARM_R0;
- case UNW_ARM_R1:
- return PERF_REG_ARM_R1;
- case UNW_ARM_R2:
- return PERF_REG_ARM_R2;
- case UNW_ARM_R3:
- return PERF_REG_ARM_R3;
- case UNW_ARM_R4:
- return PERF_REG_ARM_R4;
- case UNW_ARM_R5:
- return PERF_REG_ARM_R5;
- case UNW_ARM_R6:
- return PERF_REG_ARM_R6;
- case UNW_ARM_R7:
- return PERF_REG_ARM_R7;
- case UNW_ARM_R8:
- return PERF_REG_ARM_R8;
- case UNW_ARM_R9:
- return PERF_REG_ARM_R9;
- case UNW_ARM_R10:
- return PERF_REG_ARM_R10;
- case UNW_ARM_R11:
- return PERF_REG_ARM_FP;
- case UNW_ARM_R12:
- return PERF_REG_ARM_IP;
- case UNW_ARM_R13:
- return PERF_REG_ARM_SP;
- case UNW_ARM_R14:
- return PERF_REG_ARM_LR;
- case UNW_ARM_R15:
- return PERF_REG_ARM_PC;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return -EINVAL;
-}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 948ea6c..4fa9be9 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,7 +3,7 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
new file mode 100644
index 0000000..456a88c
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -0,0 +1,111 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+int unwind__arch_reg_id(int regnum)
+{
+ int id;
+
+ switch (regnum) {
+ case UNW_X86_64_RAX:
+ id = PERF_REG_X86_AX;
+ break;
+ case UNW_X86_64_RDX:
+ id = PERF_REG_X86_DX;
+ break;
+ case UNW_X86_64_RCX:
+ id = PERF_REG_X86_CX;
+ break;
+ case UNW_X86_64_RBX:
+ id = PERF_REG_X86_BX;
+ break;
+ case UNW_X86_64_RSI:
+ id = PERF_REG_X86_SI;
+ break;
+ case UNW_X86_64_RDI:
+ id = PERF_REG_X86_DI;
+ break;
+ case UNW_X86_64_RBP:
+ id = PERF_REG_X86_BP;
+ break;
+ case UNW_X86_64_RSP:
+ id = PERF_REG_X86_SP;
+ break;
+ case UNW_X86_64_R8:
+ id = PERF_REG_X86_R8;
+ break;
+ case UNW_X86_64_R9:
+ id = PERF_REG_X86_R9;
+ break;
+ case UNW_X86_64_R10:
+ id = PERF_REG_X86_R10;
+ break;
+ case UNW_X86_64_R11:
+ id = PERF_REG_X86_R11;
+ break;
+ case UNW_X86_64_R12:
+ id = PERF_REG_X86_R12;
+ break;
+ case UNW_X86_64_R13:
+ id = PERF_REG_X86_R13;
+ break;
+ case UNW_X86_64_R14:
+ id = PERF_REG_X86_R14;
+ break;
+ case UNW_X86_64_R15:
+ id = PERF_REG_X86_R15;
+ break;
+ case UNW_X86_64_RIP:
+ id = PERF_REG_X86_IP;
+ break;
+ default:
+ pr_err("unwind: invalid reg id %d\n", regnum);
+ return -EINVAL;
+ }
+
+ return id;
+}
+#else
+int unwind__arch_reg_id(int regnum)
+{
+ int id;
+
+ switch (regnum) {
+ case UNW_X86_EAX:
+ id = PERF_REG_X86_AX;
+ break;
+ case UNW_X86_EDX:
+ id = PERF_REG_X86_DX;
+ break;
+ case UNW_X86_ECX:
+ id = PERF_REG_X86_CX;
+ break;
+ case UNW_X86_EBX:
+ id = PERF_REG_X86_BX;
+ break;
+ case UNW_X86_ESI:
+ id = PERF_REG_X86_SI;
+ break;
+ case UNW_X86_EDI:
+ id = PERF_REG_X86_DI;
+ break;
+ case UNW_X86_EBP:
+ id = PERF_REG_X86_BP;
+ break;
+ case UNW_X86_ESP:
+ id = PERF_REG_X86_SP;
+ break;
+ case UNW_X86_EIP:
+ id = PERF_REG_X86_IP;
+ break;
+ default:
+ pr_err("unwind: invalid reg id %d\n", regnum);
+ return -EINVAL;
+ }
+
+ return id;
+}
+#endif /* HAVE_ARCH_X86_64_SUPPORT */
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c
deleted file mode 100644
index 456a88c..0000000
--- a/tools/perf/arch/x86/util/unwind.c
+++ /dev/null
@@ -1,111 +0,0 @@
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-
-#ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
-{
- int id;
-
- switch (regnum) {
- case UNW_X86_64_RAX:
- id = PERF_REG_X86_AX;
- break;
- case UNW_X86_64_RDX:
- id = PERF_REG_X86_DX;
- break;
- case UNW_X86_64_RCX:
- id = PERF_REG_X86_CX;
- break;
- case UNW_X86_64_RBX:
- id = PERF_REG_X86_BX;
- break;
- case UNW_X86_64_RSI:
- id = PERF_REG_X86_SI;
- break;
- case UNW_X86_64_RDI:
- id = PERF_REG_X86_DI;
- break;
- case UNW_X86_64_RBP:
- id = PERF_REG_X86_BP;
- break;
- case UNW_X86_64_RSP:
- id = PERF_REG_X86_SP;
- break;
- case UNW_X86_64_R8:
- id = PERF_REG_X86_R8;
- break;
- case UNW_X86_64_R9:
- id = PERF_REG_X86_R9;
- break;
- case UNW_X86_64_R10:
- id = PERF_REG_X86_R10;
- break;
- case UNW_X86_64_R11:
- id = PERF_REG_X86_R11;
- break;
- case UNW_X86_64_R12:
- id = PERF_REG_X86_R12;
- break;
- case UNW_X86_64_R13:
- id = PERF_REG_X86_R13;
- break;
- case UNW_X86_64_R14:
- id = PERF_REG_X86_R14;
- break;
- case UNW_X86_64_R15:
- id = PERF_REG_X86_R15;
- break;
- case UNW_X86_64_RIP:
- id = PERF_REG_X86_IP;
- break;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return id;
-}
-#else
-int unwind__arch_reg_id(int regnum)
-{
- int id;
-
- switch (regnum) {
- case UNW_X86_EAX:
- id = PERF_REG_X86_AX;
- break;
- case UNW_X86_EDX:
- id = PERF_REG_X86_DX;
- break;
- case UNW_X86_ECX:
- id = PERF_REG_X86_CX;
- break;
- case UNW_X86_EBX:
- id = PERF_REG_X86_BX;
- break;
- case UNW_X86_ESI:
- id = PERF_REG_X86_SI;
- break;
- case UNW_X86_EDI:
- id = PERF_REG_X86_DI;
- break;
- case UNW_X86_EBP:
- id = PERF_REG_X86_BP;
- break;
- case UNW_X86_ESP:
- id = PERF_REG_X86_SP;
- break;
- case UNW_X86_EIP:
- id = PERF_REG_X86_IP;
- break;
- default:
- pr_err("unwind: invalid reg id %d\n", regnum);
- return -EINVAL;
- }
-
- return id;
-}
-#endif /* HAVE_ARCH_X86_64_SUPPORT */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
new file mode 100644
index 0000000..226586e
--- /dev/null
+++ b/tools/perf/util/unwind-libunwind.c
@@ -0,0 +1,611 @@
+/*
+ * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
+ *
+ * Lots of this code have been borrowed or heavily inspired from parts of
+ * the libunwind 0.99 code which are (amongst other contributors I may have
+ * forgotten):
+ *
+ * Copyright (C) 2002-2007 Hewlett-Packard Co
+ * Contributed by David Mosberger-Tang <[email protected]>
+ *
+ * And the bugs have been added by:
+ *
+ * Copyright (C) 2010, Frederic Weisbecker <[email protected]>
+ * Copyright (C) 2012, Jiri Olsa <[email protected]>
+ *
+ */
+
+#include <elf.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/list.h>
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+#include "thread.h"
+#include "session.h"
+#include "perf_regs.h"
+#include "unwind.h"
+#include "util.h"
+
+extern int
+UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+ unw_word_t ip,
+ unw_dyn_info_t *di,
+ unw_proc_info_t *pi,
+ int need_unwind_info, void *arg);
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+extern int
+UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
+ unw_word_t ip,
+ unw_word_t segbase,
+ const char *obj_name, unw_word_t start,
+ unw_word_t end);
+
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+
+#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
+#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
+
+/* Pointer-encoding formats: */
+#define DW_EH_PE_omit 0xff
+#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
+#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
+#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
+#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
+#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
+
+/* Pointer-encoding application: */
+#define DW_EH_PE_absptr 0x00 /* absolute value */
+#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
+
+/*
+ * The following are not documented by LSB v1.3, yet they are used by
+ * GCC, presumably they aren't documented by LSB since they aren't
+ * used on Linux:
+ */
+#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
+#define DW_EH_PE_aligned 0x50 /* aligned pointer */
+
+/* Flags intentionaly not handled, since they're not needed:
+ * #define DW_EH_PE_indirect 0x80
+ * #define DW_EH_PE_uleb128 0x01
+ * #define DW_EH_PE_udata2 0x02
+ * #define DW_EH_PE_sleb128 0x09
+ * #define DW_EH_PE_sdata2 0x0a
+ * #define DW_EH_PE_textrel 0x20
+ * #define DW_EH_PE_datarel 0x30
+ */
+
+struct unwind_info {
+ struct perf_sample *sample;
+ struct machine *machine;
+ struct thread *thread;
+};
+
+#define dw_read(ptr, type, end) ({ \
+ type *__p = (type *) ptr; \
+ type __v; \
+ if ((__p + 1) > (type *) end) \
+ return -EINVAL; \
+ __v = *__p++; \
+ ptr = (typeof(ptr)) __p; \
+ __v; \
+ })
+
+static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
+ u8 encoding)
+{
+ u8 *cur = *p;
+ *val = 0;
+
+ switch (encoding) {
+ case DW_EH_PE_omit:
+ *val = 0;
+ goto out;
+ case DW_EH_PE_ptr:
+ *val = dw_read(cur, unsigned long, end);
+ goto out;
+ default:
+ break;
+ }
+
+ switch (encoding & DW_EH_PE_APPL_MASK) {
+ case DW_EH_PE_absptr:
+ break;
+ case DW_EH_PE_pcrel:
+ *val = (unsigned long) cur;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((encoding & 0x07) == 0x00)
+ encoding |= DW_EH_PE_udata4;
+
+ switch (encoding & DW_EH_PE_FORMAT_MASK) {
+ case DW_EH_PE_sdata4:
+ *val += dw_read(cur, s32, end);
+ break;
+ case DW_EH_PE_udata4:
+ *val += dw_read(cur, u32, end);
+ break;
+ case DW_EH_PE_sdata8:
+ *val += dw_read(cur, s64, end);
+ break;
+ case DW_EH_PE_udata8:
+ *val += dw_read(cur, u64, end);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ out:
+ *p = cur;
+ return 0;
+}
+
+#define dw_read_encoded_value(ptr, end, enc) ({ \
+ u64 __v; \
+ if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
+ return -EINVAL; \
+ } \
+ __v; \
+ })
+
+static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
+ GElf_Shdr *shp, const char *name)
+{
+ Elf_Scn *sec = NULL;
+
+ while ((sec = elf_nextscn(elf, sec)) != NULL) {
+ char *str;
+
+ gelf_getshdr(sec, shp);
+ str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+ if (!strcmp(name, str))
+ break;
+ }
+
+ return sec;
+}
+
+static u64 elf_section_offset(int fd, const char *name)
+{
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ u64 offset = 0;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL)
+ return 0;
+
+ do {
+ if (gelf_getehdr(elf, &ehdr) == NULL)
+ break;
+
+ if (!elf_section_by_name(elf, &ehdr, &shdr, name))
+ break;
+
+ offset = shdr.sh_offset;
+ } while (0);
+
+ elf_end(elf);
+ return offset;
+}
+
+struct table_entry {
+ u32 start_ip_offset;
+ u32 fde_offset;
+};
+
+struct eh_frame_hdr {
+ unsigned char version;
+ unsigned char eh_frame_ptr_enc;
+ unsigned char fde_count_enc;
+ unsigned char table_enc;
+
+ /*
+ * The rest of the header is variable-length and consists of the
+ * following members:
+ *
+ * encoded_t eh_frame_ptr;
+ * encoded_t fde_count;
+ */
+
+ /* A single encoded pointer should not be more than 8 bytes. */
+ u64 enc[2];
+
+ /*
+ * struct {
+ * encoded_t start_ip;
+ * encoded_t fde_addr;
+ * } binary_search_table[fde_count];
+ */
+ char data[0];
+} __packed;
+
+static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
+ u64 offset, u64 *table_data, u64 *segbase,
+ u64 *fde_count)
+{
+ struct eh_frame_hdr hdr;
+ u8 *enc = (u8 *) &hdr.enc;
+ u8 *end = (u8 *) &hdr.data;
+ ssize_t r;
+
+ r = dso__data_read_offset(dso, machine, offset,
+ (u8 *) &hdr, sizeof(hdr));
+ if (r != sizeof(hdr))
+ return -EINVAL;
+
+ /* We dont need eh_frame_ptr, just skip it. */
+ dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
+
+ *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
+ *segbase = offset;
+ *table_data = (enc - (u8 *) &hdr) + offset;
+ return 0;
+}
+
+static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
+ u64 *table_data, u64 *segbase,
+ u64 *fde_count)
+{
+ int ret = -EINVAL, fd;
+ u64 offset;
+
+ fd = dso__data_fd(dso, machine);
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Check the .eh_frame section for unwinding info */
+ offset = elf_section_offset(fd, ".eh_frame_hdr");
+ close(fd);
+
+ if (offset)
+ ret = unwind_spec_ehframe(dso, machine, offset,
+ table_data, segbase,
+ fde_count);
+
+ return ret;
+}
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+static int read_unwind_spec_debug_frame(struct dso *dso,
+ struct machine *machine, u64 *offset)
+{
+ int fd = dso__data_fd(dso, machine);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Check the .debug_frame section for unwinding info */
+ *offset = elf_section_offset(fd, ".debug_frame");
+ close(fd);
+
+ if (*offset)
+ return 0;
+
+ return -EINVAL;
+}
+#endif
+
+static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
+{
+ struct addr_location al;
+
+ thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, ip, &al);
+ return al.map;
+}
+
+static int
+find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct map *map;
+ unw_dyn_info_t di;
+ u64 table_data, segbase, fde_count;
+
+ map = find_map(ip, ui);
+ if (!map || !map->dso)
+ return -EINVAL;
+
+ pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
+
+ /* Check the .eh_frame section for unwinding info */
+ if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
+ &table_data, &segbase, &fde_count)) {
+ memset(&di, 0, sizeof(di));
+ di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
+ di.start_ip = map->start;
+ di.end_ip = map->end;
+ di.u.rti.segbase = map->start + segbase;
+ di.u.rti.table_data = map->start + table_data;
+ di.u.rti.table_len = fde_count * sizeof(struct table_entry)
+ / sizeof(unw_word_t);
+ return dwarf_search_unwind_table(as, ip, &di, pi,
+ need_unwind_info, arg);
+ }
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+ /* Check the .debug_frame section for unwinding info */
+ if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
+ memset(&di, 0, sizeof(di));
+ dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
+ map->start, map->end);
+ return dwarf_search_unwind_table(as, ip, &di, pi,
+ need_unwind_info, arg);
+ }
+#endif
+
+ return -EINVAL;
+}
+
+static int access_fpreg(unw_addr_space_t __maybe_unused as,
+ unw_regnum_t __maybe_unused num,
+ unw_fpreg_t __maybe_unused *val,
+ int __maybe_unused __write,
+ void __maybe_unused *arg)
+{
+ pr_err("unwind: access_fpreg unsupported\n");
+ return -UNW_EINVAL;
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
+ unw_word_t __maybe_unused *dil_addr,
+ void __maybe_unused *arg)
+{
+ return -UNW_ENOINFO;
+}
+
+static int resume(unw_addr_space_t __maybe_unused as,
+ unw_cursor_t __maybe_unused *cu,
+ void __maybe_unused *arg)
+{
+ pr_err("unwind: resume unsupported\n");
+ return -UNW_EINVAL;
+}
+
+static int
+get_proc_name(unw_addr_space_t __maybe_unused as,
+ unw_word_t __maybe_unused addr,
+ char __maybe_unused *bufp, size_t __maybe_unused buf_len,
+ unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
+{
+ pr_err("unwind: get_proc_name unsupported\n");
+ return -UNW_EINVAL;
+}
+
+static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
+ unw_word_t *data)
+{
+ struct addr_location al;
+ ssize_t size;
+
+ thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, addr, &al);
+ if (!al.map) {
+ pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+ return -1;
+ }
+
+ if (!al.map->dso)
+ return -1;
+
+ size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+ addr, (u8 *) data, sizeof(*data));
+
+ return !(size == sizeof(*data));
+}
+
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
+{
+ int i, idx = 0;
+ u64 mask = regs->mask;
+
+ if (!(mask & (1 << id)))
+ return -EINVAL;
+
+ for (i = 0; i < id; i++) {
+ if (mask & (1 << i))
+ idx++;
+ }
+
+ *valp = regs->regs[idx];
+ return 0;
+}
+
+static int access_mem(unw_addr_space_t __maybe_unused as,
+ unw_word_t addr, unw_word_t *valp,
+ int __write, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct stack_dump *stack = &ui->sample->user_stack;
+ unw_word_t start, end;
+ int offset;
+ int ret;
+
+ /* Don't support write, probably not needed. */
+ if (__write || !stack || !ui->sample->user_regs.regs) {
+ *valp = 0;
+ return 0;
+ }
+
+ ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ if (ret)
+ return ret;
+
+ end = start + stack->size;
+
+ /* Check overflow. */
+ if (addr + sizeof(unw_word_t) < addr)
+ return -EINVAL;
+
+ if (addr < start || addr + sizeof(unw_word_t) >= end) {
+ ret = access_dso_mem(ui, addr, valp);
+ if (ret) {
+ pr_debug("unwind: access_mem %p not inside range %p-%p\n",
+ (void *)addr, (void *)start, (void *)end);
+ *valp = 0;
+ return ret;
+ }
+ return 0;
+ }
+
+ offset = addr - start;
+ *valp = *(unw_word_t *)&stack->data[offset];
+ pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
+ (void *)addr, (unsigned long)*valp, offset);
+ return 0;
+}
+
+static int access_reg(unw_addr_space_t __maybe_unused as,
+ unw_regnum_t regnum, unw_word_t *valp,
+ int __write, void *arg)
+{
+ struct unwind_info *ui = arg;
+ int id, ret;
+
+ /* Don't support write, I suspect we don't need it. */
+ if (__write) {
+ pr_err("unwind: access_reg w %d\n", regnum);
+ return 0;
+ }
+
+ if (!ui->sample->user_regs.regs) {
+ *valp = 0;
+ return 0;
+ }
+
+ id = unwind__arch_reg_id(regnum);
+ if (id < 0)
+ return -EINVAL;
+
+ ret = reg_value(valp, &ui->sample->user_regs, id);
+ if (ret) {
+ pr_err("unwind: can't read reg %d\n", regnum);
+ return ret;
+ }
+
+ pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
+ return 0;
+}
+
+static void put_unwind_info(unw_addr_space_t __maybe_unused as,
+ unw_proc_info_t *pi __maybe_unused,
+ void *arg __maybe_unused)
+{
+ pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int entry(u64 ip, struct thread *thread, struct machine *machine,
+ unwind_entry_cb_t cb, void *arg)
+{
+ struct unwind_entry e;
+ struct addr_location al;
+
+ thread__find_addr_location(thread, machine,
+ PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, ip, &al);
+
+ e.ip = ip;
+ e.map = al.map;
+ e.sym = al.sym;
+
+ pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+ al.sym ? al.sym->name : "''",
+ ip,
+ al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+ return cb(&e, arg);
+}
+
+static void display_error(int err)
+{
+ switch (err) {
+ case UNW_EINVAL:
+ pr_err("unwind: Only supports local.\n");
+ break;
+ case UNW_EUNSPEC:
+ pr_err("unwind: Unspecified error.\n");
+ break;
+ case UNW_EBADREG:
+ pr_err("unwind: Register unavailable.\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static unw_accessors_t accessors = {
+ .find_proc_info = find_proc_info,
+ .put_unwind_info = put_unwind_info,
+ .get_dyn_info_list_addr = get_dyn_info_list_addr,
+ .access_mem = access_mem,
+ .access_reg = access_reg,
+ .access_fpreg = access_fpreg,
+ .resume = resume,
+ .get_proc_name = get_proc_name,
+};
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+ void *arg, int max_stack)
+{
+ unw_addr_space_t addr_space;
+ unw_cursor_t c;
+ int ret;
+
+ addr_space = unw_create_addr_space(&accessors, 0);
+ if (!addr_space) {
+ pr_err("unwind: Can't create unwind address space.\n");
+ return -ENOMEM;
+ }
+
+ ret = unw_init_remote(&c, addr_space, ui);
+ if (ret)
+ display_error(ret);
+
+ while (!ret && (unw_step(&c) > 0) && max_stack--) {
+ unw_word_t ip;
+
+ unw_get_reg(&c, UNW_REG_IP, &ip);
+ ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
+ }
+
+ unw_destroy_addr_space(addr_space);
+ return ret;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct machine *machine, struct thread *thread,
+ struct perf_sample *data, int max_stack)
+{
+ unw_word_t ip;
+ struct unwind_info ui = {
+ .sample = data,
+ .thread = thread,
+ .machine = machine,
+ };
+ int ret;
+
+ if (!data->user_regs.regs)
+ return -EINVAL;
+
+ ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ if (ret)
+ return ret;
+
+ ret = entry(ip, thread, machine, cb, arg);
+ if (ret)
+ return -ENOMEM;
+
+ return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
+}
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
deleted file mode 100644
index 226586e..0000000
--- a/tools/perf/util/unwind.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
- *
- * Lots of this code have been borrowed or heavily inspired from parts of
- * the libunwind 0.99 code which are (amongst other contributors I may have
- * forgotten):
- *
- * Copyright (C) 2002-2007 Hewlett-Packard Co
- * Contributed by David Mosberger-Tang <[email protected]>
- *
- * And the bugs have been added by:
- *
- * Copyright (C) 2010, Frederic Weisbecker <[email protected]>
- * Copyright (C) 2012, Jiri Olsa <[email protected]>
- *
- */
-
-#include <elf.h>
-#include <gelf.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <linux/list.h>
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-#include "thread.h"
-#include "session.h"
-#include "perf_regs.h"
-#include "unwind.h"
-#include "util.h"
-
-extern int
-UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
- unw_word_t ip,
- unw_word_t segbase,
- const char *obj_name, unw_word_t start,
- unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
-#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
-
-/* Pointer-encoding formats: */
-#define DW_EH_PE_omit 0xff
-#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
-#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
-#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
-#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
-#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
-
-/* Pointer-encoding application: */
-#define DW_EH_PE_absptr 0x00 /* absolute value */
-#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
-
-/*
- * The following are not documented by LSB v1.3, yet they are used by
- * GCC, presumably they aren't documented by LSB since they aren't
- * used on Linux:
- */
-#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
-#define DW_EH_PE_aligned 0x50 /* aligned pointer */
-
-/* Flags intentionaly not handled, since they're not needed:
- * #define DW_EH_PE_indirect 0x80
- * #define DW_EH_PE_uleb128 0x01
- * #define DW_EH_PE_udata2 0x02
- * #define DW_EH_PE_sleb128 0x09
- * #define DW_EH_PE_sdata2 0x0a
- * #define DW_EH_PE_textrel 0x20
- * #define DW_EH_PE_datarel 0x30
- */
-
-struct unwind_info {
- struct perf_sample *sample;
- struct machine *machine;
- struct thread *thread;
-};
-
-#define dw_read(ptr, type, end) ({ \
- type *__p = (type *) ptr; \
- type __v; \
- if ((__p + 1) > (type *) end) \
- return -EINVAL; \
- __v = *__p++; \
- ptr = (typeof(ptr)) __p; \
- __v; \
- })
-
-static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
- u8 encoding)
-{
- u8 *cur = *p;
- *val = 0;
-
- switch (encoding) {
- case DW_EH_PE_omit:
- *val = 0;
- goto out;
- case DW_EH_PE_ptr:
- *val = dw_read(cur, unsigned long, end);
- goto out;
- default:
- break;
- }
-
- switch (encoding & DW_EH_PE_APPL_MASK) {
- case DW_EH_PE_absptr:
- break;
- case DW_EH_PE_pcrel:
- *val = (unsigned long) cur;
- break;
- default:
- return -EINVAL;
- }
-
- if ((encoding & 0x07) == 0x00)
- encoding |= DW_EH_PE_udata4;
-
- switch (encoding & DW_EH_PE_FORMAT_MASK) {
- case DW_EH_PE_sdata4:
- *val += dw_read(cur, s32, end);
- break;
- case DW_EH_PE_udata4:
- *val += dw_read(cur, u32, end);
- break;
- case DW_EH_PE_sdata8:
- *val += dw_read(cur, s64, end);
- break;
- case DW_EH_PE_udata8:
- *val += dw_read(cur, u64, end);
- break;
- default:
- return -EINVAL;
- }
-
- out:
- *p = cur;
- return 0;
-}
-
-#define dw_read_encoded_value(ptr, end, enc) ({ \
- u64 __v; \
- if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
- return -EINVAL; \
- } \
- __v; \
- })
-
-static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name)
-{
- Elf_Scn *sec = NULL;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- char *str;
-
- gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
- if (!strcmp(name, str))
- break;
- }
-
- return sec;
-}
-
-static u64 elf_section_offset(int fd, const char *name)
-{
- Elf *elf;
- GElf_Ehdr ehdr;
- GElf_Shdr shdr;
- u64 offset = 0;
-
- elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
- if (elf == NULL)
- return 0;
-
- do {
- if (gelf_getehdr(elf, &ehdr) == NULL)
- break;
-
- if (!elf_section_by_name(elf, &ehdr, &shdr, name))
- break;
-
- offset = shdr.sh_offset;
- } while (0);
-
- elf_end(elf);
- return offset;
-}
-
-struct table_entry {
- u32 start_ip_offset;
- u32 fde_offset;
-};
-
-struct eh_frame_hdr {
- unsigned char version;
- unsigned char eh_frame_ptr_enc;
- unsigned char fde_count_enc;
- unsigned char table_enc;
-
- /*
- * The rest of the header is variable-length and consists of the
- * following members:
- *
- * encoded_t eh_frame_ptr;
- * encoded_t fde_count;
- */
-
- /* A single encoded pointer should not be more than 8 bytes. */
- u64 enc[2];
-
- /*
- * struct {
- * encoded_t start_ip;
- * encoded_t fde_addr;
- * } binary_search_table[fde_count];
- */
- char data[0];
-} __packed;
-
-static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
- u64 offset, u64 *table_data, u64 *segbase,
- u64 *fde_count)
-{
- struct eh_frame_hdr hdr;
- u8 *enc = (u8 *) &hdr.enc;
- u8 *end = (u8 *) &hdr.data;
- ssize_t r;
-
- r = dso__data_read_offset(dso, machine, offset,
- (u8 *) &hdr, sizeof(hdr));
- if (r != sizeof(hdr))
- return -EINVAL;
-
- /* We dont need eh_frame_ptr, just skip it. */
- dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
-
- *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
- *segbase = offset;
- *table_data = (enc - (u8 *) &hdr) + offset;
- return 0;
-}
-
-static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
- u64 *table_data, u64 *segbase,
- u64 *fde_count)
-{
- int ret = -EINVAL, fd;
- u64 offset;
-
- fd = dso__data_fd(dso, machine);
- if (fd < 0)
- return -EINVAL;
-
- /* Check the .eh_frame section for unwinding info */
- offset = elf_section_offset(fd, ".eh_frame_hdr");
- close(fd);
-
- if (offset)
- ret = unwind_spec_ehframe(dso, machine, offset,
- table_data, segbase,
- fde_count);
-
- return ret;
-}
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-static int read_unwind_spec_debug_frame(struct dso *dso,
- struct machine *machine, u64 *offset)
-{
- int fd = dso__data_fd(dso, machine);
-
- if (fd < 0)
- return -EINVAL;
-
- /* Check the .debug_frame section for unwinding info */
- *offset = elf_section_offset(fd, ".debug_frame");
- close(fd);
-
- if (*offset)
- return 0;
-
- return -EINVAL;
-}
-#endif
-
-static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
-{
- struct addr_location al;
-
- thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
- MAP__FUNCTION, ip, &al);
- return al.map;
-}
-
-static int
-find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
- int need_unwind_info, void *arg)
-{
- struct unwind_info *ui = arg;
- struct map *map;
- unw_dyn_info_t di;
- u64 table_data, segbase, fde_count;
-
- map = find_map(ip, ui);
- if (!map || !map->dso)
- return -EINVAL;
-
- pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
-
- /* Check the .eh_frame section for unwinding info */
- if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
- &table_data, &segbase, &fde_count)) {
- memset(&di, 0, sizeof(di));
- di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
- di.start_ip = map->start;
- di.end_ip = map->end;
- di.u.rti.segbase = map->start + segbase;
- di.u.rti.table_data = map->start + table_data;
- di.u.rti.table_len = fde_count * sizeof(struct table_entry)
- / sizeof(unw_word_t);
- return dwarf_search_unwind_table(as, ip, &di, pi,
- need_unwind_info, arg);
- }
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
- /* Check the .debug_frame section for unwinding info */
- if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
- memset(&di, 0, sizeof(di));
- dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
- map->start, map->end);
- return dwarf_search_unwind_table(as, ip, &di, pi,
- need_unwind_info, arg);
- }
-#endif
-
- return -EINVAL;
-}
-
-static int access_fpreg(unw_addr_space_t __maybe_unused as,
- unw_regnum_t __maybe_unused num,
- unw_fpreg_t __maybe_unused *val,
- int __maybe_unused __write,
- void __maybe_unused *arg)
-{
- pr_err("unwind: access_fpreg unsupported\n");
- return -UNW_EINVAL;
-}
-
-static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
- unw_word_t __maybe_unused *dil_addr,
- void __maybe_unused *arg)
-{
- return -UNW_ENOINFO;
-}
-
-static int resume(unw_addr_space_t __maybe_unused as,
- unw_cursor_t __maybe_unused *cu,
- void __maybe_unused *arg)
-{
- pr_err("unwind: resume unsupported\n");
- return -UNW_EINVAL;
-}
-
-static int
-get_proc_name(unw_addr_space_t __maybe_unused as,
- unw_word_t __maybe_unused addr,
- char __maybe_unused *bufp, size_t __maybe_unused buf_len,
- unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
-{
- pr_err("unwind: get_proc_name unsupported\n");
- return -UNW_EINVAL;
-}
-
-static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
- unw_word_t *data)
-{
- struct addr_location al;
- ssize_t size;
-
- thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
- MAP__FUNCTION, addr, &al);
- if (!al.map) {
- pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
- return -1;
- }
-
- if (!al.map->dso)
- return -1;
-
- size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
- addr, (u8 *) data, sizeof(*data));
-
- return !(size == sizeof(*data));
-}
-
-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
-{
- int i, idx = 0;
- u64 mask = regs->mask;
-
- if (!(mask & (1 << id)))
- return -EINVAL;
-
- for (i = 0; i < id; i++) {
- if (mask & (1 << i))
- idx++;
- }
-
- *valp = regs->regs[idx];
- return 0;
-}
-
-static int access_mem(unw_addr_space_t __maybe_unused as,
- unw_word_t addr, unw_word_t *valp,
- int __write, void *arg)
-{
- struct unwind_info *ui = arg;
- struct stack_dump *stack = &ui->sample->user_stack;
- unw_word_t start, end;
- int offset;
- int ret;
-
- /* Don't support write, probably not needed. */
- if (__write || !stack || !ui->sample->user_regs.regs) {
- *valp = 0;
- return 0;
- }
-
- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
- if (ret)
- return ret;
-
- end = start + stack->size;
-
- /* Check overflow. */
- if (addr + sizeof(unw_word_t) < addr)
- return -EINVAL;
-
- if (addr < start || addr + sizeof(unw_word_t) >= end) {
- ret = access_dso_mem(ui, addr, valp);
- if (ret) {
- pr_debug("unwind: access_mem %p not inside range %p-%p\n",
- (void *)addr, (void *)start, (void *)end);
- *valp = 0;
- return ret;
- }
- return 0;
- }
-
- offset = addr - start;
- *valp = *(unw_word_t *)&stack->data[offset];
- pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
- (void *)addr, (unsigned long)*valp, offset);
- return 0;
-}
-
-static int access_reg(unw_addr_space_t __maybe_unused as,
- unw_regnum_t regnum, unw_word_t *valp,
- int __write, void *arg)
-{
- struct unwind_info *ui = arg;
- int id, ret;
-
- /* Don't support write, I suspect we don't need it. */
- if (__write) {
- pr_err("unwind: access_reg w %d\n", regnum);
- return 0;
- }
-
- if (!ui->sample->user_regs.regs) {
- *valp = 0;
- return 0;
- }
-
- id = unwind__arch_reg_id(regnum);
- if (id < 0)
- return -EINVAL;
-
- ret = reg_value(valp, &ui->sample->user_regs, id);
- if (ret) {
- pr_err("unwind: can't read reg %d\n", regnum);
- return ret;
- }
-
- pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
- return 0;
-}
-
-static void put_unwind_info(unw_addr_space_t __maybe_unused as,
- unw_proc_info_t *pi __maybe_unused,
- void *arg __maybe_unused)
-{
- pr_debug("unwind: put_unwind_info called\n");
-}
-
-static int entry(u64 ip, struct thread *thread, struct machine *machine,
- unwind_entry_cb_t cb, void *arg)
-{
- struct unwind_entry e;
- struct addr_location al;
-
- thread__find_addr_location(thread, machine,
- PERF_RECORD_MISC_USER,
- MAP__FUNCTION, ip, &al);
-
- e.ip = ip;
- e.map = al.map;
- e.sym = al.sym;
-
- pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
- al.sym ? al.sym->name : "''",
- ip,
- al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
-
- return cb(&e, arg);
-}
-
-static void display_error(int err)
-{
- switch (err) {
- case UNW_EINVAL:
- pr_err("unwind: Only supports local.\n");
- break;
- case UNW_EUNSPEC:
- pr_err("unwind: Unspecified error.\n");
- break;
- case UNW_EBADREG:
- pr_err("unwind: Register unavailable.\n");
- break;
- default:
- break;
- }
-}
-
-static unw_accessors_t accessors = {
- .find_proc_info = find_proc_info,
- .put_unwind_info = put_unwind_info,
- .get_dyn_info_list_addr = get_dyn_info_list_addr,
- .access_mem = access_mem,
- .access_reg = access_reg,
- .access_fpreg = access_fpreg,
- .resume = resume,
- .get_proc_name = get_proc_name,
-};
-
-static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
- void *arg, int max_stack)
-{
- unw_addr_space_t addr_space;
- unw_cursor_t c;
- int ret;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (!addr_space) {
- pr_err("unwind: Can't create unwind address space.\n");
- return -ENOMEM;
- }
-
- ret = unw_init_remote(&c, addr_space, ui);
- if (ret)
- display_error(ret);
-
- while (!ret && (unw_step(&c) > 0) && max_stack--) {
- unw_word_t ip;
-
- unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
- }
-
- unw_destroy_addr_space(addr_space);
- return ret;
-}
-
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- struct machine *machine, struct thread *thread,
- struct perf_sample *data, int max_stack)
-{
- unw_word_t ip;
- struct unwind_info ui = {
- .sample = data,
- .thread = thread,
- .machine = machine,
- };
- int ret;
-
- if (!data->user_regs.regs)
- return -EINVAL;
-
- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
- if (ret)
- return ret;
-
- ret = entry(ip, thread, machine, cb, arg);
- if (ret)
- return -ENOMEM;
-
- return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
-}
--
1.8.3.1

2014-01-07 12:49:02

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 10/16] perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id

Renaming unwind__arch_reg_id into libunwind__arch_reg_id,
so it's clear it's specific to libunwind.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/arch/arm/util/unwind-libunwind.c | 2 +-
tools/perf/arch/x86/util/unwind-libunwind.c | 4 ++--
tools/perf/util/unwind-libunwind.c | 2 +-
tools/perf/util/unwind.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
index da3dc95..729ed69 100644
--- a/tools/perf/arch/arm/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -4,7 +4,7 @@
#include "perf_regs.h"
#include "../../util/unwind.h"

-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
switch (regnum) {
case UNW_ARM_R0:
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 456a88c..3261f68 100644
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -5,7 +5,7 @@
#include "../../util/unwind.h"

#ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;

@@ -69,7 +69,7 @@ int unwind__arch_reg_id(int regnum)
return id;
}
#else
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;

diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 226586e..95cfb54 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -485,7 +485,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
return 0;
}

- id = unwind__arch_reg_id(regnum);
+ id = libunwind__arch_reg_id(regnum);
if (id < 0)
return -EINVAL;

diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 356e1d6..18f33b4 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -18,7 +18,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
struct perf_sample *data, int max_stack);
-int unwind__arch_reg_id(int regnum);
+int libunwind__arch_reg_id(int regnum);
#else
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
--
1.8.3.1

2014-01-07 12:49:09

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 14/16] perf tools: Add libdw DWARF post unwind support

Adding libdw DWARF post unwind support, which is part
of elfutils-devel/libdw-dev package from version 0.158.

The new code is contained in unwin-libdw.c object, and
implements unwind__get_entries unwind interface function.

New Makefile variable NO_LIBDW_DWARF_UNWIND was added to
control its compilation, and is marked as disabled now.
It's factored with the rest of the Makefile unwind build
code in the next patch.

Arch specific code was added for x86.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/Makefile.perf | 11 ++
tools/perf/arch/x86/Makefile | 3 +
tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++
tools/perf/config/Makefile | 1 +
tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++
tools/perf/util/unwind-libdw.h | 21 ++++
6 files changed, 297 insertions(+)
create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
create mode 100644 tools/perf/util/unwind-libdw.c
create mode 100644 tools/perf/util/unwind-libdw.h

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 33c8782..9b9f9d2 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -55,6 +55,12 @@ include config/utilities.mak
# Define NO_LIBAUDIT if you do not want libaudit support
#
# Define NO_LIBBIONIC if you do not want bionic support
+#
+# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
+# for dwarf backtrace post unwind.
+
+# temporarily disabled
+NO_LIBDW_DWARF_UNWIND := 1

ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -479,6 +485,11 @@ ifndef NO_DWARF
endif # NO_DWARF
endif # NO_LIBELF

+ifndef NO_LIBDW_DWARF_UNWIND
+ LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
+ LIB_H += util/unwind-libdw.h
+endif
+
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
endif
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 4fa9be9..37c4652 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -7,6 +7,9 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
+ifndef NO_LIBDW_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
+endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/arch/x86/util/unwind-libdw.c
new file mode 100644
index 0000000..c4b7217
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind-libdw.c
@@ -0,0 +1,51 @@
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct regs_dump *user_regs = &ui->sample->user_regs;
+ Dwarf_Word dwarf_regs[17];
+ unsigned nregs;
+
+#define REG(r) ({ \
+ Dwarf_Word val = 0; \
+ perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
+ val; \
+})
+
+ if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
+ dwarf_regs[0] = REG(AX);
+ dwarf_regs[1] = REG(CX);
+ dwarf_regs[2] = REG(DX);
+ dwarf_regs[3] = REG(BX);
+ dwarf_regs[4] = REG(SP);
+ dwarf_regs[5] = REG(BP);
+ dwarf_regs[6] = REG(SI);
+ dwarf_regs[7] = REG(DI);
+ dwarf_regs[8] = REG(IP);
+ nregs = 9;
+ } else {
+ dwarf_regs[0] = REG(AX);
+ dwarf_regs[1] = REG(DX);
+ dwarf_regs[2] = REG(CX);
+ dwarf_regs[3] = REG(BX);
+ dwarf_regs[4] = REG(SI);
+ dwarf_regs[5] = REG(DI);
+ dwarf_regs[6] = REG(BP);
+ dwarf_regs[7] = REG(SP);
+ dwarf_regs[8] = REG(R8);
+ dwarf_regs[9] = REG(R9);
+ dwarf_regs[10] = REG(R10);
+ dwarf_regs[11] = REG(R11);
+ dwarf_regs[12] = REG(R12);
+ dwarf_regs[13] = REG(R13);
+ dwarf_regs[14] = REG(R14);
+ dwarf_regs[15] = REG(R15);
+ dwarf_regs[16] = REG(IP);
+ nregs = 17;
+ }
+
+ return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
+}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 67de6f7..bd6096a 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -276,6 +276,7 @@ ifdef NO_LIBELF
NO_DWARF := 1
NO_DEMANGLE := 1
NO_LIBUNWIND := 1
+ NO_LIBDW_DWARF_UNWIND := 1
else
ifeq ($(feature-libelf), 0)
ifeq ($(feature-glibc), 1)
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
new file mode 100644
index 0000000..67db73e
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.c
@@ -0,0 +1,210 @@
+#include <linux/compiler.h>
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "unwind.h"
+#include "unwind-libdw.h"
+#include "machine.h"
+#include "thread.h"
+#include "types.h"
+#include "event.h"
+#include "perf_regs.h"
+
+static char *debuginfo_path;
+
+static const Dwfl_Callbacks offline_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+ .section_address = dwfl_offline_section_address,
+};
+
+static int __report_module(struct addr_location *al, u64 ip,
+ struct unwind_info *ui)
+{
+ Dwfl_Module *mod;
+ struct dso *dso = NULL;
+
+ thread__find_addr_location(ui->thread, ui->machine,
+ PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, ip, al);
+
+ if (al->map)
+ dso = al->map->dso;
+
+ if (!dso)
+ return 0;
+
+ mod = dwfl_addrmodule(ui->dwfl, ip);
+ if (!mod)
+ mod = dwfl_report_elf(ui->dwfl, dso->short_name,
+ dso->long_name, -1, al->map->start,
+ false);
+
+ return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
+}
+
+static int report_module(u64 ip, struct unwind_info *ui)
+{
+ struct addr_location al;
+
+ return __report_module(&al, ip, ui);
+}
+
+static int entry(u64 ip, struct unwind_info *ui)
+
+{
+ struct unwind_entry e;
+ struct addr_location al;
+
+ if (__report_module(&al, ip, ui))
+ return -1;
+
+ e.ip = ip;
+ e.map = al.map;
+ e.sym = al.sym;
+
+ pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+ al.sym ? al.sym->name : "''",
+ ip,
+ al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+ return ui->cb(&e, ui->arg);
+}
+
+static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
+{
+ /* We want only single thread to be processed. */
+ if (*thread_argp != NULL)
+ return 0;
+
+ *thread_argp = arg;
+ return dwfl_pid(dwfl);
+}
+
+static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
+ Dwarf_Word *data)
+{
+ struct addr_location al;
+ ssize_t size;
+
+ thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, addr, &al);
+ if (!al.map) {
+ pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+ return -1;
+ }
+
+ if (!al.map->dso)
+ return -1;
+
+ size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+ addr, (u8 *) data, sizeof(*data));
+
+ return !(size == sizeof(*data));
+}
+
+static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
+ void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct stack_dump *stack = &ui->sample->user_stack;
+ u64 start, end;
+ int offset;
+ int ret;
+
+ ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ if (ret)
+ return false;
+
+ end = start + stack->size;
+
+ /* Check overflow. */
+ if (addr + sizeof(Dwarf_Word) < addr)
+ return false;
+
+ if (addr < start || addr + sizeof(Dwarf_Word) > end) {
+ ret = access_dso_mem(ui, addr, result);
+ if (ret) {
+ pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
+ " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+ addr, start, end);
+ return false;
+ }
+ return true;
+ }
+
+ offset = addr - start;
+ *result = *(Dwarf_Word *)&stack->data[offset];
+ pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
+ addr, (unsigned long)*result, offset);
+ return true;
+}
+
+static const Dwfl_Thread_Callbacks callbacks = {
+ .next_thread = next_thread,
+ .memory_read = memory_read,
+ .set_initial_registers = libdw__arch_set_initial_registers,
+};
+
+static int
+frame_callback(Dwfl_Frame *state, void *arg)
+{
+ struct unwind_info *ui = arg;
+ Dwarf_Addr pc;
+
+ if (!dwfl_frame_pc(state, &pc, NULL)) {
+ pr_err("%s", dwfl_errmsg(-1));
+ return DWARF_CB_ABORT;
+ }
+
+ return entry(pc, ui) || !(--ui->max_stack) ?
+ DWARF_CB_ABORT : DWARF_CB_OK;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct machine *machine, struct thread *thread,
+ struct perf_sample *data,
+ int max_stack)
+{
+ struct unwind_info ui = {
+ .sample = data,
+ .thread = thread,
+ .machine = machine,
+ .cb = cb,
+ .arg = arg,
+ .max_stack = max_stack,
+ };
+ Dwarf_Word ip;
+ int err = -EINVAL;
+
+ if (!data->user_regs.regs)
+ return -EINVAL;
+
+ ui.dwfl = dwfl_begin(&offline_callbacks);
+ if (!ui.dwfl)
+ goto out;
+
+ err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ if (err)
+ goto out;
+
+ err = report_module(ip, &ui);
+ if (err)
+ goto out;
+
+ if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
+ goto out;
+
+ err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
+
+ if (err && !ui.max_stack)
+ err = 0;
+
+ out:
+ if (err)
+ pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
+
+ dwfl_end(ui.dwfl);
+ return 0;
+}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
new file mode 100644
index 0000000..417a142
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.h
@@ -0,0 +1,21 @@
+#ifndef __PERF_UNWIND_LIBDW_H
+#define __PERF_UNWIND_LIBDW_H
+
+#include <elfutils/libdwfl.h>
+#include "event.h"
+#include "thread.h"
+#include "unwind.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
+
+struct unwind_info {
+ Dwfl *dwfl;
+ struct perf_sample *sample;
+ struct machine *machine;
+ struct thread *thread;
+ unwind_entry_cb_t cb;
+ void *arg;
+ int max_stack;
+};
+
+#endif /* __PERF_UNWIND_LIBDW_H */
--
1.8.3.1

2014-01-07 12:49:15

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 15/16] perf tools: Setup default dwarf post unwinder

Factor NO_LIBDW_DWARF_UNWIND makefile variable and code
that selects default DWARf post unwinder based on detected
features (libdw and libunwind support)

If both are detected the libunwind is selected as default.
Simple 'make' will try to add:
- libunwind unwinder if present
- libdw unwinder if present
- disable dwarf unwind if non of libunwind and libdw
libraries are present

Examples:
- compile in libdw unwinder if present:
$ make NO_LIBUNWIND=1

- compile in libdw (with libdw installation directory) unwinder if present:
$ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1

- disable post dwarf unwind completely:
$ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/Makefile.perf | 5 +---
tools/perf/arch/x86/Makefile | 6 +++--
tools/perf/config/Makefile | 59 ++++++++++++++++++++++++++++++++------------
3 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9b9f9d2..d76c1f1 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -59,9 +59,6 @@ include config/utilities.mak
# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
# for dwarf backtrace post unwind.

-# temporarily disabled
-NO_LIBDW_DWARF_UNWIND := 1
-
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
@@ -413,7 +410,7 @@ endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
-ifndef NO_LIBUNWIND
+ifndef NO_DWARF_UNWIND
ifeq ($(ARCH),x86)
LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
endif
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 37c4652..1641542 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -4,12 +4,14 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
ifndef NO_LIBDW_DWARF_UNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
endif
+ifndef NO_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
+endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index bd6096a..8bcf143 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -295,6 +295,12 @@ else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
endif
else
+ ifndef NO_LIBDW_DWARF_UNWIND
+ ifneq ($(feature-libdw-dwarf-unwind),1)
+ NO_LIBDW_DWARF_UNWIND := 1
+ msg := $(warning No libdw dwarf unwind found, Please install elfutils-devel/libdw-dev >= 0.158.);
+ endif
+ endif
ifneq ($(feature-dwarf), 1)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1
@@ -330,25 +336,46 @@ endif # NO_LIBELF

ifndef NO_LIBUNWIND
ifneq ($(feature-libunwind), 1)
- msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
+ msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1);
NO_LIBUNWIND := 1
- else
- ifeq ($(ARCH),arm)
- $(call feature_check,libunwind-debug-frame)
- ifneq ($(feature-libunwind-debug-frame), 1)
- msg := $(warning No debug_frame support found in libunwind);
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- else
- # non-ARM has no dwarf_find_debug_frame() function:
+ endif
+endif
+
+dwarf-post-unwind := 1
+# setup DWARF post unwinder
+ifdef NO_LIBUNWIND
+ ifdef NO_LIBDW_DWARF_UNWIND
+ msg := $(warning Disabling post unwind, no support found.);
+ dwarf-post-unwind := 0
+ endif
+else
+ # Enable libunwind support by default.
+ ifndef NO_LIBDW_DWARF_UNWIND
+ NO_LIBDW_DWARF_UNWIND := 1
+ endif
+endif
+
+ifeq ($(dwarf-post-unwind),1)
+ CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
+else
+ NO_DWARF_UNWIND := 1
+endif
+
+ifndef NO_LIBUNWIND
+ ifeq ($(ARCH),arm)
+ $(call feature_check,libunwind-debug-frame)
+ ifneq ($(feature-libunwind-debug-frame), 1)
+ msg := $(warning No debug_frame support found in libunwind);
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
endif
-
- CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
- EXTLIBS += $(LIBUNWIND_LIBS)
- CFLAGS += $(LIBUNWIND_CFLAGS)
- LDFLAGS += $(LIBUNWIND_LDFLAGS)
- endif # ifneq ($(feature-libunwind), 1)
+ else
+ # non-ARM has no dwarf_find_debug_frame() function:
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+ endif
+ CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ EXTLIBS += $(LIBUNWIND_LIBS)
+ CFLAGS += $(LIBUNWIND_CFLAGS)
+ LDFLAGS += $(LIBUNWIND_LDFLAGS)
endif

ifndef NO_LIBAUDIT
--
1.8.3.1

2014-01-07 12:48:48

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 11/16] perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro

Introducing global macro HAVE_DWARF_UNWIND_SUPPORT to indicate
we have dwarf unwind support. Any library providing the dwarf
post unwind support will enable this macro.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/builtin-record.c | 10 +++++-----
tools/perf/config/Makefile | 2 +-
tools/perf/tests/builtin-test.c | 2 +-
tools/perf/tests/tests.h | 2 +-
tools/perf/util/unwind.h | 7 +++++--
5 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index cb00b53..349c5c0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -650,7 +650,7 @@ error:
return ret;
}

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
static int get_stack_size(char *str, unsigned long *_size)
{
char *endptr;
@@ -676,7 +676,7 @@ static int get_stack_size(char *str, unsigned long *_size)
max_size, str);
return -1;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */

int record_parse_callchain(const char *arg, struct record_opts *opts)
{
@@ -705,7 +705,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
"needed for -g fp\n");
break;

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
/* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192;
@@ -721,7 +721,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
ret = get_stack_size(tok, &size);
opts->stack_dump_size = size;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
} else {
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
@@ -808,7 +808,7 @@ static struct record record = {

#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
#else
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 5d15b43..1bc78d2 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -337,7 +337,7 @@ ifndef NO_LIBUNWIND
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
endif

- CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
EXTLIBS += $(LIBUNWIND_LIBS)
CFLAGS += $(LIBUNWIND_CFLAGS)
LDFLAGS += $(LIBUNWIND_LDFLAGS)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index f5a6ffb..b11bf8a 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -116,7 +116,7 @@ static struct test {
.func = test__parse_no_sample_id_all,
},
#if defined(__x86_64__) || defined(__i386__)
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
{
.desc = "Test dwarf unwind",
.func = test__dwarf_unwind,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 8979309..a24795c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -43,7 +43,7 @@ int test__parse_no_sample_id_all(void);
int test__dwarf_unwind(void);

#if defined(__x86_64__) || defined(__i386__)
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
struct thread;
struct perf_sample;
int test__arch_unwind_sample(struct perf_sample *sample,
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 18f33b4..b031316 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,12 +13,15 @@ struct unwind_entry {

typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
struct perf_sample *data, int max_stack);
+/* libunwind specific */
+#ifdef HAVE_LIBUNWIND_SUPPORT
int libunwind__arch_reg_id(int regnum);
+#endif
#else
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
@@ -30,5 +33,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
{
return 0;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
#endif /* __UNWIND_H */
--
1.8.3.1

2014-01-07 12:50:22

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 16/16] perf tests: Add NO_LIBDW_DWARF_UNWIND make test

Adding make test for NO_LIBDW_DWARF_UNWIND option,
plus updating minimal build test with it.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/tests/make | 63 +++++++++++++++++++++++++++------------------------
1 file changed, 33 insertions(+), 30 deletions(-)

diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index e341088..a38e6a0 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -14,41 +14,43 @@ endif
has = $(shell which $1 2>/dev/null)

# standard single make variable specified
-make_clean_all := clean all
-make_python_perf_so := python/perf.so
-make_debug := DEBUG=1
-make_no_libperl := NO_LIBPERL=1
-make_no_libpython := NO_LIBPYTHON=1
-make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1
-make_no_newt := NO_NEWT=1
-make_no_slang := NO_SLANG=1
-make_no_gtk2 := NO_GTK2=1
-make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
-make_no_demangle := NO_DEMANGLE=1
-make_no_libelf := NO_LIBELF=1
-make_no_libunwind := NO_LIBUNWIND=1
-make_no_backtrace := NO_BACKTRACE=1
-make_no_libnuma := NO_LIBNUMA=1
-make_no_libaudit := NO_LIBAUDIT=1
-make_no_libbionic := NO_LIBBIONIC=1
-make_tags := tags
-make_cscope := cscope
-make_help := help
-make_doc := doc
-make_perf_o := perf.o
-make_util_map_o := util/map.o
-make_install := install
-make_install_bin := install-bin
-make_install_doc := install-doc
-make_install_man := install-man
-make_install_html := install-html
-make_install_info := install-info
-make_install_pdf := install-pdf
+make_clean_all := clean all
+make_python_perf_so := python/perf.so
+make_debug := DEBUG=1
+make_no_libperl := NO_LIBPERL=1
+make_no_libpython := NO_LIBPYTHON=1
+make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1
+make_no_newt := NO_NEWT=1
+make_no_slang := NO_SLANG=1
+make_no_gtk2 := NO_GTK2=1
+make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
+make_no_demangle := NO_DEMANGLE=1
+make_no_libelf := NO_LIBELF=1
+make_no_libunwind := NO_LIBUNWIND=1
+make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1
+make_no_backtrace := NO_BACKTRACE=1
+make_no_libnuma := NO_LIBNUMA=1
+make_no_libaudit := NO_LIBAUDIT=1
+make_no_libbionic := NO_LIBBIONIC=1
+make_tags := tags
+make_cscope := cscope
+make_help := help
+make_doc := doc
+make_perf_o := perf.o
+make_util_map_o := util/map.o
+make_install := install
+make_install_bin := install-bin
+make_install_doc := install-doc
+make_install_man := install-man
+make_install_html := install-html
+make_install_info := install-info
+make_install_pdf := install-pdf

# all the NO_* variable combined
make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
+make_minimal += NO_LIBDW_DWARF_UNWIND=1

# $(run) contains all available tests
run := make_pure
@@ -65,6 +67,7 @@ run += make_no_ui
run += make_no_demangle
run += make_no_libelf
run += make_no_libunwind
+run += make_no_libdw_dwarf_unwind
run += make_no_backtrace
run += make_no_libnuma
run += make_no_libaudit
--
1.8.3.1

2014-01-07 12:50:57

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 13/16] perf tools: Add feature check for libdw dwarf unwind

Adding feature check for libdw dwarf unwind.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/config/Makefile | 22 ++++++++++++++--------
tools/perf/config/feature-checks/Makefile | 6 +++++-
tools/perf/config/feature-checks/test-all.c | 5 +++++
.../feature-checks/test-libdw-dwarf-unwind.c | 13 +++++++++++++
4 files changed, 37 insertions(+), 9 deletions(-)
create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 1bc78d2..67de6f7 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -59,6 +59,18 @@ ifeq ($(NO_PERF_REGS),0)
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
endif

+ifndef NO_LIBELF
+ # for linking with debug library, run like:
+ # make DEBUG=1 LIBDW_DIR=/opt/libdw/
+ ifdef LIBDW_DIR
+ LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
+ LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
+
+ FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
+ FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
+ endif
+endif
+
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile

@@ -147,7 +159,8 @@ CORE_FEATURE_TESTS = \
libunwind \
on-exit \
stackprotector-all \
- timerfd
+ timerfd \
+ libdw-dwarf-unwind

# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
@@ -281,13 +294,6 @@ else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
endif
else
- # for linking with debug library, run like:
- # make DEBUG=1 LIBDW_DIR=/opt/libdw/
- ifdef LIBDW_DIR
- LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
- LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
- endif
-
ifneq ($(feature-dwarf), 1)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 7cf6fcd..100a8bb 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -26,7 +26,8 @@ FILES= \
test-libunwind-debug-frame.bin \
test-on-exit.bin \
test-stackprotector-all.bin \
- test-timerfd.bin
+ test-timerfd.bin \
+ test-libdw-dwarf-unwind.bin

CC := $(CC) -MD

@@ -140,6 +141,9 @@ test-backtrace.bin:
test-timerfd.bin:
$(BUILD)

+test-libdw-dwarf-unwind.bin:
+ $(BUILD)
+
-include *.d

###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 9b8a544..fc37eb3 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -89,6 +89,10 @@
# include "test-stackprotector-all.c"
#undef main

+#define main main_test_libdw_dwarf_unwind
+# include "test-libdw-dwarf-unwind.c"
+#undef main
+
int main(int argc, char *argv[])
{
main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
main_test_libnuma();
main_test_timerfd();
main_test_stackprotector_all();
+ main_test_libdw_dwarf_unwind();

return 0;
}
diff --git a/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
new file mode 100644
index 0000000..f676a3f
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
@@ -0,0 +1,13 @@
+
+#include <elfutils/libdwfl.h>
+
+int main(void)
+{
+ /*
+ * This function is guarded via: __nonnull_attribute__ (1, 2).
+ * Passing '1' as arguments value. This code is never executed,
+ * only compiled.
+ */
+ dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
+ return 0;
+}
--
1.8.3.1

2014-01-07 12:51:17

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 12/16] perf tools: Separate perf_reg_value function in perf_regs object

Making perf_reg_value function global (formely reg_value), because
it's going to be used globaly across all code providing the dwarf
post unwind feature.

Changing its prototype to be generic:
-int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);

Changing the valp type from libunwind specific
'unw_word_t' to u64.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/Makefile.perf | 1 +
tools/perf/util/perf_regs.c | 19 +++++++++++++++++++
tools/perf/util/perf_regs.h | 13 +++++++++++++
tools/perf/util/unwind-libunwind.c | 38 ++++++++++++--------------------------
4 files changed, 45 insertions(+), 26 deletions(-)
create mode 100644 tools/perf/util/perf_regs.c

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 29e7e2b..33c8782 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -537,6 +537,7 @@ ifeq ($(NO_PERF_REGS),0)
ifeq ($(ARCH),x86)
LIB_H += arch/x86/include/perf_regs.h
endif
+ LIB_OBJS += $(OUTPUT)util/perf_regs.o
endif

ifndef NO_LIBNUMA
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644
index 0000000..a3539ef
--- /dev/null
+++ b/tools/perf/util/perf_regs.c
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include "perf_regs.h"
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
+{
+ int i, idx = 0;
+ u64 mask = regs->mask;
+
+ if (!(mask & (1 << id)))
+ return -EINVAL;
+
+ for (i = 0; i < id; i++) {
+ if (mask & (1 << i))
+ idx++;
+ }
+
+ *valp = regs->regs[idx];
+ return 0;
+}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index a3d42cd..d6e8b6a 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,14 @@
#ifndef __PERF_REGS_H
#define __PERF_REGS_H

+#include "types.h"
+#include "event.h"
+
#ifdef HAVE_PERF_REGS_SUPPORT
#include <perf_regs.h>
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
+
#else
#define PERF_REGS_MASK 0

@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
{
return NULL;
}
+
+static inline int perf_reg_value(u64 *valp __maybe_unused,
+ struct regs_dump *regs __maybe_unused,
+ int id __maybe_unused)
+{
+ return 0;
+}
#endif /* HAVE_PERF_REGS_SUPPORT */
#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 95cfb54..cd3a330 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -406,30 +406,13 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
return !(size == sizeof(*data));
}

-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
-{
- int i, idx = 0;
- u64 mask = regs->mask;
-
- if (!(mask & (1 << id)))
- return -EINVAL;
-
- for (i = 0; i < id; i++) {
- if (mask & (1 << i))
- idx++;
- }
-
- *valp = regs->regs[idx];
- return 0;
-}
-
static int access_mem(unw_addr_space_t __maybe_unused as,
unw_word_t addr, unw_word_t *valp,
int __write, void *arg)
{
struct unwind_info *ui = arg;
struct stack_dump *stack = &ui->sample->user_stack;
- unw_word_t start, end;
+ u64 start, end;
int offset;
int ret;

@@ -439,7 +422,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
return 0;
}

- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
if (ret)
return ret;

@@ -452,8 +435,9 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
if (addr < start || addr + sizeof(unw_word_t) >= end) {
ret = access_dso_mem(ui, addr, valp);
if (ret) {
- pr_debug("unwind: access_mem %p not inside range %p-%p\n",
- (void *)addr, (void *)start, (void *)end);
+ pr_debug("unwind: access_mem %p not inside range"
+ " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+ (void *) addr, start, end);
*valp = 0;
return ret;
}
@@ -462,8 +446,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as,

offset = addr - start;
*valp = *(unw_word_t *)&stack->data[offset];
- pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
- (void *)addr, (unsigned long)*valp, offset);
+ pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+ (void *) addr, (unsigned long)*valp, offset);
return 0;
}

@@ -473,6 +457,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
{
struct unwind_info *ui = arg;
int id, ret;
+ u64 val;

/* Don't support write, I suspect we don't need it. */
if (__write) {
@@ -489,12 +474,13 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
if (id < 0)
return -EINVAL;

- ret = reg_value(valp, &ui->sample->user_regs, id);
+ ret = perf_reg_value(&val, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
}

+ *valp = (unw_word_t) val;
pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
return 0;
}
@@ -588,7 +574,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct thread *thread,
struct perf_sample *data, int max_stack)
{
- unw_word_t ip;
+ u64 ip;
struct unwind_info ui = {
.sample = data,
.thread = thread,
@@ -599,7 +585,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (!data->user_regs.regs)
return -EINVAL;

- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (ret)
return ret;

--
1.8.3.1

2014-01-07 12:51:26

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 07/16] perf tools: Do not report zero address in unwind

We are not interested in zero addresses in callchain,
do not report them.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/util/unwind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 87509d8..057d4cc 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -579,7 +579,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
unw_word_t ip;

unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = entry(ip, ui->thread, ui->machine, cb, arg);
+ ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
}

unw_destroy_addr_space(addr_space);
--
1.8.3.1

2014-01-07 12:52:20

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 04/16] perf tests x86: Introduce perf_regs_load function

Introducing perf_regs_load function, which is going
to be used for dwarf unwind test in following patches.

It takes single argument as a pointer to the regs dump
buffer and populates it with current registers values.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/arch/x86/Makefile | 1 +
tools/perf/arch/x86/include/perf_regs.h | 2 +
tools/perf/arch/x86/tests/regs_load.S | 92 +++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+)
create mode 100644 tools/perf/arch/x86/tests/regs_load.S

diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 8801fe0..1cbef73 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -4,6 +4,7 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index e84ca76..f3435d62 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -5,6 +5,8 @@
#include "../../util/types.h"
#include <asm/perf_regs.h>

+void perf_regs_load(u64 *regs);
+
#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
#else
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644
index 0000000..99167bf
--- /dev/null
+++ b/tools/perf/arch/x86/tests/regs_load.S
@@ -0,0 +1,92 @@
+
+#include <linux/linkage.h>
+
+#define AX 0
+#define BX 1 * 8
+#define CX 2 * 8
+#define DX 3 * 8
+#define SI 4 * 8
+#define DI 5 * 8
+#define BP 6 * 8
+#define SP 7 * 8
+#define IP 8 * 8
+#define FLAGS 9 * 8
+#define CS 10 * 8
+#define SS 11 * 8
+#define DS 12 * 8
+#define ES 13 * 8
+#define FS 14 * 8
+#define GS 15 * 8
+#define R8 16 * 8
+#define R9 17 * 8
+#define R10 18 * 8
+#define R11 19 * 8
+#define R12 20 * 8
+#define R13 21 * 8
+#define R14 22 * 8
+#define R15 23 * 8
+
+.text
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+ENTRY(perf_regs_load)
+ movq %rax, AX(%rdi)
+ movq %rbx, BX(%rdi)
+ movq %rcx, CX(%rdi)
+ movq %rdx, DX(%rdi)
+ movq %rsi, SI(%rdi)
+ movq %rdi, DI(%rdi)
+ movq %rbp, BP(%rdi)
+
+ leaq 8(%rsp), %rax /* exclude this call. */
+ movq %rax, SP(%rdi)
+
+ movq 0(%rsp), %rax
+ movq %rax, IP(%rdi)
+
+ movq $0, FLAGS(%rdi)
+ movq $0, CS(%rdi)
+ movq $0, SS(%rdi)
+ movq $0, DS(%rdi)
+ movq $0, ES(%rdi)
+ movq $0, FS(%rdi)
+ movq $0, GS(%rdi)
+
+ movq %r8, R8(%rdi)
+ movq %r9, R9(%rdi)
+ movq %r10, R10(%rdi)
+ movq %r11, R11(%rdi)
+ movq %r12, R12(%rdi)
+ movq %r13, R13(%rdi)
+ movq %r14, R14(%rdi)
+ movq %r15, R15(%rdi)
+ ret
+ENDPROC(perf_regs_load)
+#else
+ENTRY(perf_regs_load)
+ push %edi
+ movl 8(%esp), %edi
+ movl %eax, AX(%edi)
+ movl %ebx, BX(%edi)
+ movl %ecx, CX(%edi)
+ movl %edx, DX(%edi)
+ movl %esi, SI(%edi)
+ pop %eax
+ movl %eax, DI(%edi)
+ movl %ebp, BP(%edi)
+
+ leal 4(%esp), %eax /* exclude this call. */
+ movl %eax, SP(%edi)
+
+ movl 0(%esp), %eax
+ movl %eax, IP(%edi)
+
+ movl $0, FLAGS(%edi)
+ movl $0, CS(%edi)
+ movl $0, SS(%edi)
+ movl $0, DS(%edi)
+ movl $0, ES(%edi)
+ movl $0, FS(%edi)
+ movl $0, GS(%edi)
+ ret
+ENDPROC(perf_regs_load)
+#endif
--
1.8.3.1

2014-01-07 12:52:24

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 06/16] perf tools: Fix dwarf unwind max_stack processing

The 'unwind__get_entries' function currently returns
'max_stack + 1' entries (instead of exact max_stack
entries), because max_stack value does not get
decremented for the first entry.

This fix makes dwarf-unwind test pass.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Jean Pihet <[email protected]>
---
tools/perf/util/unwind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 0efd539..87509d8 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -611,5 +611,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (ret)
return -ENOMEM;

- return get_entries(&ui, cb, arg, max_stack);
+ return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
}
--
1.8.3.1

2014-01-07 14:14:21

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 02/16] perf tools: Fix machine initialization

Em Tue, Jan 07, 2014 at 01:47:19PM +0100, Jiri Olsa escreveu:
> The id_hdr_size field was not properly initialized,
> setting it to zero.

Humm, is there any place where 'machine' doesn't come from calloc/zalloc?

- Arnaldo

> Signed-off-by: Jiri Olsa <[email protected]>
> Cc: Corey Ashford <[email protected]>
> Cc: Frederic Weisbecker <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Namhyung Kim <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: David Ahern <[email protected]>
> Cc: Jean Pihet <[email protected]>
> ---
> tools/perf/util/machine.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index a98538d..0130279 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -27,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
> machine->pid = pid;
>
> machine->symbol_filter = NULL;
> + machine->id_hdr_size = 0;
>
> machine->root_dir = strdup(root_dir);
> if (machine->root_dir == NULL)
> --
> 1.8.3.1

2014-01-07 14:23:07

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 02/16] perf tools: Fix machine initialization

On Tue, Jan 07, 2014 at 11:14:00AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Jan 07, 2014 at 01:47:19PM +0100, Jiri Olsa escreveu:
> > The id_hdr_size field was not properly initialized,
> > setting it to zero.
>
> Humm, is there any place where 'machine' doesn't come from calloc/zalloc?

machine__new_host, but I used machine allocated on stack
in the tests/dwarf-unwind.c and I thought this was the last
member not being initialized..

now I can see vmlinux_maps array does not get initialized as well..

jirka

>
> - Arnaldo
>
> > Signed-off-by: Jiri Olsa <[email protected]>
> > Cc: Corey Ashford <[email protected]>
> > Cc: Frederic Weisbecker <[email protected]>
> > Cc: Ingo Molnar <[email protected]>
> > Cc: Namhyung Kim <[email protected]>
> > Cc: Paul Mackerras <[email protected]>
> > Cc: Peter Zijlstra <[email protected]>
> > Cc: Arnaldo Carvalho de Melo <[email protected]>
> > Cc: David Ahern <[email protected]>
> > Cc: Jean Pihet <[email protected]>
> > ---
> > tools/perf/util/machine.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> > index a98538d..0130279 100644
> > --- a/tools/perf/util/machine.c
> > +++ b/tools/perf/util/machine.c
> > @@ -27,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
> > machine->pid = pid;
> >
> > machine->symbol_filter = NULL;
> > + machine->id_hdr_size = 0;
> >
> > machine->root_dir = strdup(root_dir);
> > if (machine->root_dir == NULL)
> > --
> > 1.8.3.1

2014-01-09 15:45:08

by Jean Pihet

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

Hi Jiri,

On 7 January 2014 13:47, Jiri Olsa <[email protected]> wrote:
> hi,
> adding libdw DWARF unwind support, which is part of just released
> elfutils package 0.158.
>
> We can now compile perf to have either libunwind DWARF unwind,
> (which is still default) or the new one libdw unwind.
That is great!

> Examples:
> - compile in libdw unwinder if present:
> $ make NO_LIBUNWIND=1
>
> - compile in libdw (with libdw installation directory) unwinder if present:
> $ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1
>
> - disable post dwarf unwind completely:
> $ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1
>
> Performance wise the libdw unwinder seems to be faster.
> Following results are from 2GB perf.data file with 249156
> samples:
>
> The libdw unwind perf:
> $ time perf report -i ~/perf.data > perf.data.ldw
>
> real 0m35.746s
> user 0m24.211s
> sys 0m11.214s
>
> The libunwind unwind perf:
> $ time perf report -i ~/perf.data > perf.data.unw
>
> real 1m41.149s
> user 1m9.694s
> sys 0m30.595s
>
> In example above I've got 2206 differences (perf.data.ldw and
> perf.data.unw files) in the callchains output out of the 249156
> samples which is below 1%. Together with some other tips for speed
> increase it's on my TODO list for future.
Nice improvement!

>
> Git tree:
> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
> perf/core_libdw_unwind
>
> Kudos to Jan Kratochvil for helping me with the new interface.
>
> Jean,
> I haven't tested on arm.. so not sure I broke anything there.
> Any chance you could test for me, and maybe make the automated
> test I added work there? ;-)
Yes sure. I will review the patches and test/benchmark them on ARMv7/v8.
Let me do that after the current tasks.

>
> thanks,
> jirka

Regards,
Jean

>
>
> Signed-off-by: Jiri Olsa <[email protected]>
> Cc: Corey Ashford <[email protected]>
> Cc: Frederic Weisbecker <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Namhyung Kim <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: David Ahern <[email protected]>
> Cc: Jan Kratochvil <[email protected]>
> Cc: Jean Pihet <[email protected]>
> ---
> Jiri Olsa (16):
> perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
> perf tools: Fix machine initialization
> perf tools: Make perf_event__synthesize_mmap_events global
> perf tests x86: Introduce perf_regs_load function
> perf tests x86: Add dwarf unwind test
> perf tools: Fix dwarf unwind max_stack processing
> perf tools: Do not report zero address in unwind
> perf tools: Add mask into struct regs_dump
> perf tools: Separate libunwind code to special object
> perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
> perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
> perf tools: Separate perf_reg_value function in perf_regs object
> perf tools: Add feature check for libdw dwarf unwind
> perf tools: Add libdw DWARF post unwind support
> perf tools: Setup default dwarf post unwinder
> perf tests: Add NO_LIBDW_DWARF_UNWIND make test
>
> tools/perf/Makefile.perf | 19 ++++++-
> tools/perf/arch/arm/Makefile | 2 +-
> tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
> tools/perf/arch/x86/Makefile | 9 +++-
> tools/perf/arch/x86/include/perf_regs.h | 6 +++
> tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
> tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
> tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
> tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
> tools/perf/builtin-inject.c | 1 -
> tools/perf/builtin-record.c | 10 ++--
> tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
> tools/perf/config/feature-checks/Makefile | 6 ++-
> tools/perf/config/feature-checks/test-all.c | 5 ++
> tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
> tools/perf/tests/builtin-test.c | 8 +++
> tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
> tools/perf/tests/make | 63 +++++++++++-----------
> tools/perf/tests/sample-parsing.c | 17 +++---
> tools/perf/tests/tests.h | 9 ++++
> tools/perf/util/event.c | 12 ++---
> tools/perf/util/event.h | 12 ++++-
> tools/perf/util/evsel.c | 13 ++---
> tools/perf/util/machine.c | 4 +-
> tools/perf/util/perf_regs.c | 19 +++++++
> tools/perf/util/perf_regs.h | 13 +++++
> tools/perf/util/session.c | 5 +-
> tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> tools/perf/util/unwind-libdw.h | 21 ++++++++
> tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
> tools/perf/util/unwind.h | 11 ++--
> 31 files changed, 849 insertions(+), 135 deletions(-)
> rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
> create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
> create mode 100644 tools/perf/arch/x86/tests/regs_load.S
> create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
> rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
> create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
> create mode 100644 tools/perf/tests/dwarf-unwind.c
> create mode 100644 tools/perf/util/perf_regs.c
> create mode 100644 tools/perf/util/unwind-libdw.c
> create mode 100644 tools/perf/util/unwind-libdw.h
> rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)

Subject: [tip:perf/core] perf machine: Fix id_hdr_size initialization

Commit-ID: 14bd6d20fef603060474701967085442b716b6a9
Gitweb: http://git.kernel.org/tip/14bd6d20fef603060474701967085442b716b6a9
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:19 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 13 Jan 2014 10:06:24 -0300

perf machine: Fix id_hdr_size initialization

The id_hdr_size field was not properly initialized, set it to zero, as
the machine struct may have come from some non zeroing allocation
routine or from the stack without any field being initialized.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/machine.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index a98538d..0130279 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -27,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->pid = pid;

machine->symbol_filter = NULL;
+ machine->id_hdr_size = 0;

machine->root_dir = strdup(root_dir);
if (machine->root_dir == NULL)

Subject: [tip:perf/core] perf tools: Automate setup of FEATURE_CHECK_(C|LD )FLAGS-all variables

Commit-ID: c4eb6c0e7aa3a5106a3382880bc41c696e72adb4
Gitweb: http://git.kernel.org/tip/c4eb6c0e7aa3a5106a3382880bc41c696e72adb4
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:18 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 13 Jan 2014 10:06:24 -0300

perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables

Instead of explicitly adding same value into
FEATURE_CHECK_(C|LD)FLAGS-all variables we can do that automatically.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/config/Makefile | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f2bc659..5d15b43 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -53,9 +53,6 @@ else
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
- # and the flags for the test-all case
- FEATURE_CHECK_CFLAGS-all += $(LIBUNWIND_CFLAGS)
- FEATURE_CHECK_LDFLAGS-all += $(LIBUNWIND_LDFLAGS)
endif

ifeq ($(NO_PERF_REGS),0)
@@ -152,6 +149,17 @@ CORE_FEATURE_TESTS = \
stackprotector-all \
timerfd

+# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
+# If in the future we need per-feature checks/flags for features not
+# mentioned in this list we need to refactor this ;-).
+set_test_all_flags = $(eval $(set_test_all_flags_code))
+define set_test_all_flags_code
+ FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1))
+ FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
+endef
+
+$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
+
#
# So here we detect whether test-all was rebuilt, to be able
# to skip the print-out of the long features list if the file

Subject: [tip:perf/core] perf tools: Make perf_event__synthesize_mmap_events global

Commit-ID: a18382b68f8bf1a8d43e3cb08b3479cb768913ea
Gitweb: http://git.kernel.org/tip/a18382b68f8bf1a8d43e3cb08b3479cb768913ea
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:20 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 13 Jan 2014 10:06:24 -0300

perf tools: Make perf_event__synthesize_mmap_events global

Making perf_event__synthesize_mmap_events global, it will be used in
following patch from test code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/event.c | 12 ++++++------
tools/perf/util/event.h | 7 +++++++
2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 45a76c6..1fc1c2f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -175,12 +175,12 @@ out:
return tgid;
}

-static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
- union perf_event *event,
- pid_t pid, pid_t tgid,
- perf_event__handler_t process,
- struct machine *machine,
- bool mmap_data)
+int perf_event__synthesize_mmap_events(struct perf_tool *tool,
+ union perf_event *event,
+ pid_t pid, pid_t tgid,
+ perf_event__handler_t process,
+ struct machine *machine,
+ bool mmap_data)
{
char filename[PATH_MAX];
FILE *fp;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 30fec99..faf6e21 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -266,6 +266,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
const struct perf_sample *sample,
bool swapped);

+int perf_event__synthesize_mmap_events(struct perf_tool *tool,
+ union perf_event *event,
+ pid_t pid, pid_t tgid,
+ perf_event__handler_t process,
+ struct machine *machine,
+ bool mmap_data);
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);

2014-01-17 12:24:59

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

ping ;-)

thanks,
jirka

On Tue, Jan 07, 2014 at 01:47:17PM +0100, Jiri Olsa wrote:
> hi,
> adding libdw DWARF unwind support, which is part of just released
> elfutils package 0.158.
>
> We can now compile perf to have either libunwind DWARF unwind,
> (which is still default) or the new one libdw unwind.
>
> Examples:
> - compile in libdw unwinder if present:
> $ make NO_LIBUNWIND=1
>
> - compile in libdw (with libdw installation directory) unwinder if present:
> $ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1
>
> - disable post dwarf unwind completely:
> $ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1
>
> Performance wise the libdw unwinder seems to be faster.
> Following results are from 2GB perf.data file with 249156
> samples:
>
> The libdw unwind perf:
> $ time perf report -i ~/perf.data > perf.data.ldw
>
> real 0m35.746s
> user 0m24.211s
> sys 0m11.214s
>
> The libunwind unwind perf:
> $ time perf report -i ~/perf.data > perf.data.unw
>
> real 1m41.149s
> user 1m9.694s
> sys 0m30.595s
>
> In example above I've got 2206 differences (perf.data.ldw and
> perf.data.unw files) in the callchains output out of the 249156
> samples which is below 1%. Together with some other tips for speed
> increase it's on my TODO list for future.
>
> Git tree:
> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
> perf/core_libdw_unwind
>
> Kudos to Jan Kratochvil for helping me with the new interface.
>
> Jean,
> I haven't tested on arm.. so not sure I broke anything there.
> Any chance you could test for me, and maybe make the automated
> test I added work there? ;-)
>
> thanks,
> jirka
>
>
> Signed-off-by: Jiri Olsa <[email protected]>
> Cc: Corey Ashford <[email protected]>
> Cc: Frederic Weisbecker <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Namhyung Kim <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: David Ahern <[email protected]>
> Cc: Jan Kratochvil <[email protected]>
> Cc: Jean Pihet <[email protected]>
> ---
> Jiri Olsa (16):
> perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
> perf tools: Fix machine initialization
> perf tools: Make perf_event__synthesize_mmap_events global
> perf tests x86: Introduce perf_regs_load function
> perf tests x86: Add dwarf unwind test
> perf tools: Fix dwarf unwind max_stack processing
> perf tools: Do not report zero address in unwind
> perf tools: Add mask into struct regs_dump
> perf tools: Separate libunwind code to special object
> perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
> perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
> perf tools: Separate perf_reg_value function in perf_regs object
> perf tools: Add feature check for libdw dwarf unwind
> perf tools: Add libdw DWARF post unwind support
> perf tools: Setup default dwarf post unwinder
> perf tests: Add NO_LIBDW_DWARF_UNWIND make test
>
> tools/perf/Makefile.perf | 19 ++++++-
> tools/perf/arch/arm/Makefile | 2 +-
> tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
> tools/perf/arch/x86/Makefile | 9 +++-
> tools/perf/arch/x86/include/perf_regs.h | 6 +++
> tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
> tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
> tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
> tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
> tools/perf/builtin-inject.c | 1 -
> tools/perf/builtin-record.c | 10 ++--
> tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
> tools/perf/config/feature-checks/Makefile | 6 ++-
> tools/perf/config/feature-checks/test-all.c | 5 ++
> tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
> tools/perf/tests/builtin-test.c | 8 +++
> tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
> tools/perf/tests/make | 63 +++++++++++-----------
> tools/perf/tests/sample-parsing.c | 17 +++---
> tools/perf/tests/tests.h | 9 ++++
> tools/perf/util/event.c | 12 ++---
> tools/perf/util/event.h | 12 ++++-
> tools/perf/util/evsel.c | 13 ++---
> tools/perf/util/machine.c | 4 +-
> tools/perf/util/perf_regs.c | 19 +++++++
> tools/perf/util/perf_regs.h | 13 +++++
> tools/perf/util/session.c | 5 +-
> tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> tools/perf/util/unwind-libdw.h | 21 ++++++++
> tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
> tools/perf/util/unwind.h | 11 ++--
> 31 files changed, 849 insertions(+), 135 deletions(-)
> rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
> create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
> create mode 100644 tools/perf/arch/x86/tests/regs_load.S
> create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
> rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
> create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
> create mode 100644 tools/perf/tests/dwarf-unwind.c
> create mode 100644 tools/perf/util/perf_regs.c
> create mode 100644 tools/perf/util/unwind-libdw.c
> create mode 100644 tools/perf/util/unwind-libdw.h
> rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)

2014-01-17 12:27:57

by Jean Pihet

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

Hi Jiri,

Let me start on it next week. Is that OK?

Thx for the reminder, I had not entirely forgotten it though ;p

Regards,
Jean

On 17 January 2014 13:24, Jiri Olsa <[email protected]> wrote:
> ping ;-)
>
> thanks,
> jirka
>
> On Tue, Jan 07, 2014 at 01:47:17PM +0100, Jiri Olsa wrote:
>> hi,
>> adding libdw DWARF unwind support, which is part of just released
>> elfutils package 0.158.
>>
>> We can now compile perf to have either libunwind DWARF unwind,
>> (which is still default) or the new one libdw unwind.
>>
>> Examples:
>> - compile in libdw unwinder if present:
>> $ make NO_LIBUNWIND=1
>>
>> - compile in libdw (with libdw installation directory) unwinder if present:
>> $ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1
>>
>> - disable post dwarf unwind completely:
>> $ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1
>>
>> Performance wise the libdw unwinder seems to be faster.
>> Following results are from 2GB perf.data file with 249156
>> samples:
>>
>> The libdw unwind perf:
>> $ time perf report -i ~/perf.data > perf.data.ldw
>>
>> real 0m35.746s
>> user 0m24.211s
>> sys 0m11.214s
>>
>> The libunwind unwind perf:
>> $ time perf report -i ~/perf.data > perf.data.unw
>>
>> real 1m41.149s
>> user 1m9.694s
>> sys 0m30.595s
>>
>> In example above I've got 2206 differences (perf.data.ldw and
>> perf.data.unw files) in the callchains output out of the 249156
>> samples which is below 1%. Together with some other tips for speed
>> increase it's on my TODO list for future.
>>
>> Git tree:
>> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
>> perf/core_libdw_unwind
>>
>> Kudos to Jan Kratochvil for helping me with the new interface.
>>
>> Jean,
>> I haven't tested on arm.. so not sure I broke anything there.
>> Any chance you could test for me, and maybe make the automated
>> test I added work there? ;-)
>>
>> thanks,
>> jirka
>>
>>
>> Signed-off-by: Jiri Olsa <[email protected]>
>> Cc: Corey Ashford <[email protected]>
>> Cc: Frederic Weisbecker <[email protected]>
>> Cc: Ingo Molnar <[email protected]>
>> Cc: Namhyung Kim <[email protected]>
>> Cc: Paul Mackerras <[email protected]>
>> Cc: Peter Zijlstra <[email protected]>
>> Cc: Arnaldo Carvalho de Melo <[email protected]>
>> Cc: David Ahern <[email protected]>
>> Cc: Jan Kratochvil <[email protected]>
>> Cc: Jean Pihet <[email protected]>
>> ---
>> Jiri Olsa (16):
>> perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
>> perf tools: Fix machine initialization
>> perf tools: Make perf_event__synthesize_mmap_events global
>> perf tests x86: Introduce perf_regs_load function
>> perf tests x86: Add dwarf unwind test
>> perf tools: Fix dwarf unwind max_stack processing
>> perf tools: Do not report zero address in unwind
>> perf tools: Add mask into struct regs_dump
>> perf tools: Separate libunwind code to special object
>> perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
>> perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
>> perf tools: Separate perf_reg_value function in perf_regs object
>> perf tools: Add feature check for libdw dwarf unwind
>> perf tools: Add libdw DWARF post unwind support
>> perf tools: Setup default dwarf post unwinder
>> perf tests: Add NO_LIBDW_DWARF_UNWIND make test
>>
>> tools/perf/Makefile.perf | 19 ++++++-
>> tools/perf/arch/arm/Makefile | 2 +-
>> tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
>> tools/perf/arch/x86/Makefile | 9 +++-
>> tools/perf/arch/x86/include/perf_regs.h | 6 +++
>> tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
>> tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
>> tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
>> tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
>> tools/perf/builtin-inject.c | 1 -
>> tools/perf/builtin-record.c | 10 ++--
>> tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
>> tools/perf/config/feature-checks/Makefile | 6 ++-
>> tools/perf/config/feature-checks/test-all.c | 5 ++
>> tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
>> tools/perf/tests/builtin-test.c | 8 +++
>> tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
>> tools/perf/tests/make | 63 +++++++++++-----------
>> tools/perf/tests/sample-parsing.c | 17 +++---
>> tools/perf/tests/tests.h | 9 ++++
>> tools/perf/util/event.c | 12 ++---
>> tools/perf/util/event.h | 12 ++++-
>> tools/perf/util/evsel.c | 13 ++---
>> tools/perf/util/machine.c | 4 +-
>> tools/perf/util/perf_regs.c | 19 +++++++
>> tools/perf/util/perf_regs.h | 13 +++++
>> tools/perf/util/session.c | 5 +-
>> tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> tools/perf/util/unwind-libdw.h | 21 ++++++++
>> tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
>> tools/perf/util/unwind.h | 11 ++--
>> 31 files changed, 849 insertions(+), 135 deletions(-)
>> rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
>> create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
>> create mode 100644 tools/perf/arch/x86/tests/regs_load.S
>> create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
>> rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
>> create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
>> create mode 100644 tools/perf/tests/dwarf-unwind.c
>> create mode 100644 tools/perf/util/perf_regs.c
>> create mode 100644 tools/perf/util/unwind-libdw.c
>> create mode 100644 tools/perf/util/unwind-libdw.h
>> rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)

2014-01-17 12:34:50

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

On Fri, Jan 17, 2014 at 01:27:53PM +0100, Jean Pihet wrote:
> Hi Jiri,
>
> Let me start on it next week. Is that OK?

great ;-) thanks

jirka

>
> Thx for the reminder, I had not entirely forgotten it though ;p
>
> Regards,
> Jean
>
> On 17 January 2014 13:24, Jiri Olsa <[email protected]> wrote:
> > ping ;-)
> >
> > thanks,
> > jirka
> >
> > On Tue, Jan 07, 2014 at 01:47:17PM +0100, Jiri Olsa wrote:
> >> hi,
> >> adding libdw DWARF unwind support, which is part of just released
> >> elfutils package 0.158.
> >>
> >> We can now compile perf to have either libunwind DWARF unwind,
> >> (which is still default) or the new one libdw unwind.
> >>
> >> Examples:
> >> - compile in libdw unwinder if present:
> >> $ make NO_LIBUNWIND=1
> >>
> >> - compile in libdw (with libdw installation directory) unwinder if present:
> >> $ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1
> >>
> >> - disable post dwarf unwind completely:
> >> $ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1
> >>
> >> Performance wise the libdw unwinder seems to be faster.
> >> Following results are from 2GB perf.data file with 249156
> >> samples:
> >>
> >> The libdw unwind perf:
> >> $ time perf report -i ~/perf.data > perf.data.ldw
> >>
> >> real 0m35.746s
> >> user 0m24.211s
> >> sys 0m11.214s
> >>
> >> The libunwind unwind perf:
> >> $ time perf report -i ~/perf.data > perf.data.unw
> >>
> >> real 1m41.149s
> >> user 1m9.694s
> >> sys 0m30.595s
> >>
> >> In example above I've got 2206 differences (perf.data.ldw and
> >> perf.data.unw files) in the callchains output out of the 249156
> >> samples which is below 1%. Together with some other tips for speed
> >> increase it's on my TODO list for future.
> >>
> >> Git tree:
> >> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
> >> perf/core_libdw_unwind
> >>
> >> Kudos to Jan Kratochvil for helping me with the new interface.
> >>
> >> Jean,
> >> I haven't tested on arm.. so not sure I broke anything there.
> >> Any chance you could test for me, and maybe make the automated
> >> test I added work there? ;-)
> >>
> >> thanks,
> >> jirka
> >>
> >>
> >> Signed-off-by: Jiri Olsa <[email protected]>
> >> Cc: Corey Ashford <[email protected]>
> >> Cc: Frederic Weisbecker <[email protected]>
> >> Cc: Ingo Molnar <[email protected]>
> >> Cc: Namhyung Kim <[email protected]>
> >> Cc: Paul Mackerras <[email protected]>
> >> Cc: Peter Zijlstra <[email protected]>
> >> Cc: Arnaldo Carvalho de Melo <[email protected]>
> >> Cc: David Ahern <[email protected]>
> >> Cc: Jan Kratochvil <[email protected]>
> >> Cc: Jean Pihet <[email protected]>
> >> ---
> >> Jiri Olsa (16):
> >> perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
> >> perf tools: Fix machine initialization
> >> perf tools: Make perf_event__synthesize_mmap_events global
> >> perf tests x86: Introduce perf_regs_load function
> >> perf tests x86: Add dwarf unwind test
> >> perf tools: Fix dwarf unwind max_stack processing
> >> perf tools: Do not report zero address in unwind
> >> perf tools: Add mask into struct regs_dump
> >> perf tools: Separate libunwind code to special object
> >> perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
> >> perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
> >> perf tools: Separate perf_reg_value function in perf_regs object
> >> perf tools: Add feature check for libdw dwarf unwind
> >> perf tools: Add libdw DWARF post unwind support
> >> perf tools: Setup default dwarf post unwinder
> >> perf tests: Add NO_LIBDW_DWARF_UNWIND make test
> >>
> >> tools/perf/Makefile.perf | 19 ++++++-
> >> tools/perf/arch/arm/Makefile | 2 +-
> >> tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
> >> tools/perf/arch/x86/Makefile | 9 +++-
> >> tools/perf/arch/x86/include/perf_regs.h | 6 +++
> >> tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
> >> tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
> >> tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
> >> tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
> >> tools/perf/builtin-inject.c | 1 -
> >> tools/perf/builtin-record.c | 10 ++--
> >> tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
> >> tools/perf/config/feature-checks/Makefile | 6 ++-
> >> tools/perf/config/feature-checks/test-all.c | 5 ++
> >> tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
> >> tools/perf/tests/builtin-test.c | 8 +++
> >> tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
> >> tools/perf/tests/make | 63 +++++++++++-----------
> >> tools/perf/tests/sample-parsing.c | 17 +++---
> >> tools/perf/tests/tests.h | 9 ++++
> >> tools/perf/util/event.c | 12 ++---
> >> tools/perf/util/event.h | 12 ++++-
> >> tools/perf/util/evsel.c | 13 ++---
> >> tools/perf/util/machine.c | 4 +-
> >> tools/perf/util/perf_regs.c | 19 +++++++
> >> tools/perf/util/perf_regs.h | 13 +++++
> >> tools/perf/util/session.c | 5 +-
> >> tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >> tools/perf/util/unwind-libdw.h | 21 ++++++++
> >> tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
> >> tools/perf/util/unwind.h | 11 ++--
> >> 31 files changed, 849 insertions(+), 135 deletions(-)
> >> rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
> >> create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
> >> create mode 100644 tools/perf/arch/x86/tests/regs_load.S
> >> create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
> >> rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
> >> create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
> >> create mode 100644 tools/perf/tests/dwarf-unwind.c
> >> create mode 100644 tools/perf/util/perf_regs.c
> >> create mode 100644 tools/perf/util/unwind-libdw.c
> >> create mode 100644 tools/perf/util/unwind-libdw.h
> >> rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)

2014-01-17 14:28:35

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

Em Fri, Jan 17, 2014 at 01:24:31PM +0100, Jiri Olsa escreveu:
> ping ;-)

I'll try and test this this afternoon to possibly get it in the next
pull req, after the one I'll do shortly

> thanks,
> jirka
>
> On Tue, Jan 07, 2014 at 01:47:17PM +0100, Jiri Olsa wrote:
> > hi,
> > adding libdw DWARF unwind support, which is part of just released
> > elfutils package 0.158.
> >
> > We can now compile perf to have either libunwind DWARF unwind,
> > (which is still default) or the new one libdw unwind.
> >
> > Examples:
> > - compile in libdw unwinder if present:
> > $ make NO_LIBUNWIND=1
> >
> > - compile in libdw (with libdw installation directory) unwinder if present:
> > $ make LIBDW_DIR=/opt/elfutils/ NO_LIBUNWIND=1
> >
> > - disable post dwarf unwind completely:
> > $ make NO_LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1
> >
> > Performance wise the libdw unwinder seems to be faster.
> > Following results are from 2GB perf.data file with 249156
> > samples:
> >
> > The libdw unwind perf:
> > $ time perf report -i ~/perf.data > perf.data.ldw
> >
> > real 0m35.746s
> > user 0m24.211s
> > sys 0m11.214s
> >
> > The libunwind unwind perf:
> > $ time perf report -i ~/perf.data > perf.data.unw
> >
> > real 1m41.149s
> > user 1m9.694s
> > sys 0m30.595s
> >
> > In example above I've got 2206 differences (perf.data.ldw and
> > perf.data.unw files) in the callchains output out of the 249156
> > samples which is below 1%. Together with some other tips for speed
> > increase it's on my TODO list for future.
> >
> > Git tree:
> > https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
> > perf/core_libdw_unwind
> >
> > Kudos to Jan Kratochvil for helping me with the new interface.
> >
> > Jean,
> > I haven't tested on arm.. so not sure I broke anything there.
> > Any chance you could test for me, and maybe make the automated
> > test I added work there? ;-)
> >
> > thanks,
> > jirka
> >
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
> > Cc: Corey Ashford <[email protected]>
> > Cc: Frederic Weisbecker <[email protected]>
> > Cc: Ingo Molnar <[email protected]>
> > Cc: Namhyung Kim <[email protected]>
> > Cc: Paul Mackerras <[email protected]>
> > Cc: Peter Zijlstra <[email protected]>
> > Cc: Arnaldo Carvalho de Melo <[email protected]>
> > Cc: David Ahern <[email protected]>
> > Cc: Jan Kratochvil <[email protected]>
> > Cc: Jean Pihet <[email protected]>
> > ---
> > Jiri Olsa (16):
> > perf tools: Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables
> > perf tools: Fix machine initialization
> > perf tools: Make perf_event__synthesize_mmap_events global
> > perf tests x86: Introduce perf_regs_load function
> > perf tests x86: Add dwarf unwind test
> > perf tools: Fix dwarf unwind max_stack processing
> > perf tools: Do not report zero address in unwind
> > perf tools: Add mask into struct regs_dump
> > perf tools: Separate libunwind code to special object
> > perf tools: Rename unwind__arch_reg_id into libunwind__arch_reg_id
> > perf tools: Introduce HAVE_DWARF_UNWIND_SUPPORT macro
> > perf tools: Separate perf_reg_value function in perf_regs object
> > perf tools: Add feature check for libdw dwarf unwind
> > perf tools: Add libdw DWARF post unwind support
> > perf tools: Setup default dwarf post unwinder
> > perf tests: Add NO_LIBDW_DWARF_UNWIND make test
> >
> > tools/perf/Makefile.perf | 19 ++++++-
> > tools/perf/arch/arm/Makefile | 2 +-
> > tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 2 +-
> > tools/perf/arch/x86/Makefile | 9 +++-
> > tools/perf/arch/x86/include/perf_regs.h | 6 +++
> > tools/perf/arch/x86/tests/dwarf-unwind.c | 59 ++++++++++++++++++++
> > tools/perf/arch/x86/tests/regs_load.S | 92 ++++++++++++++++++++++++++++++++
> > tools/perf/arch/x86/util/unwind-libdw.c | 51 ++++++++++++++++++
> > tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 4 +-
> > tools/perf/builtin-inject.c | 1 -
> > tools/perf/builtin-record.c | 10 ++--
> > tools/perf/config/Makefile | 94 +++++++++++++++++++++++---------
> > tools/perf/config/feature-checks/Makefile | 6 ++-
> > tools/perf/config/feature-checks/test-all.c | 5 ++
> > tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c | 13 +++++
> > tools/perf/tests/builtin-test.c | 8 +++
> > tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
> > tools/perf/tests/make | 63 +++++++++++-----------
> > tools/perf/tests/sample-parsing.c | 17 +++---
> > tools/perf/tests/tests.h | 9 ++++
> > tools/perf/util/event.c | 12 ++---
> > tools/perf/util/event.h | 12 ++++-
> > tools/perf/util/evsel.c | 13 ++---
> > tools/perf/util/machine.c | 4 +-
> > tools/perf/util/perf_regs.c | 19 +++++++
> > tools/perf/util/perf_regs.h | 13 +++++
> > tools/perf/util/session.c | 5 +-
> > tools/perf/util/unwind-libdw.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > tools/perf/util/unwind-libdw.h | 21 ++++++++
> > tools/perf/util/{unwind.c => unwind-libunwind.c} | 50 ++++++-----------
> > tools/perf/util/unwind.h | 11 ++--
> > 31 files changed, 849 insertions(+), 135 deletions(-)
> > rename tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} (95%)
> > create mode 100644 tools/perf/arch/x86/tests/dwarf-unwind.c
> > create mode 100644 tools/perf/arch/x86/tests/regs_load.S
> > create mode 100644 tools/perf/arch/x86/util/unwind-libdw.c
> > rename tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} (95%)
> > create mode 100644 tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
> > create mode 100644 tools/perf/tests/dwarf-unwind.c
> > create mode 100644 tools/perf/util/perf_regs.c
> > create mode 100644 tools/perf/util/unwind-libdw.c
> > create mode 100644 tools/perf/util/unwind-libdw.h
> > rename tools/perf/util/{unwind.c => unwind-libunwind.c} (92%)

2014-01-28 13:04:36

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

On Fri, Jan 17, 2014 at 01:27:53PM +0100, Jean Pihet wrote:
> Hi Jiri,
>
> Let me start on it next week. Is that OK?
>
> Thx for the reminder, I had not entirely forgotten it though ;p
hi,
rebased patchset to latest acme's perf/core is in:
https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
perf/core_libdw_unwind

aaand ping ;-)

thanks,
jirka

2014-01-28 16:46:09

by Jean Pihet

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

Hi Jiri,

On 28 January 2014 14:04, Jiri Olsa <[email protected]> wrote:
> On Fri, Jan 17, 2014 at 01:27:53PM +0100, Jean Pihet wrote:
>> Hi Jiri,
>>
>> Let me start on it next week. Is that OK?
>>
>> Thx for the reminder, I had not entirely forgotten it though ;p
> hi,
> rebased patchset to latest acme's perf/core is in:
> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
> perf/core_libdw_unwind
Great, that was needed.

> aaand ping ;-)
I checked that the build still works ok on ARM. I am now trying with libdw.
I can give an Ack as soon as that is done, then implement the ARM specific code.

Thanks,
Jean

>
> thanks,
> jirka

2014-02-04 16:46:40

by Jean Pihet

[permalink] [raw]
Subject: Re: [PATCH 00/16] perf tools: Add libdw DWARF unwind support

Hi Jiri,

On 28 January 2014 17:46, Jean Pihet <[email protected]> wrote:
> Hi Jiri,
>
> On 28 January 2014 14:04, Jiri Olsa <[email protected]> wrote:
>> On Fri, Jan 17, 2014 at 01:27:53PM +0100, Jean Pihet wrote:
>>> Hi Jiri,
>>>
>>> Let me start on it next week. Is that OK?
>>>
>>> Thx for the reminder, I had not entirely forgotten it though ;p
>> hi,
>> rebased patchset to latest acme's perf/core is in:
>> https://git.kernel.org/cgit/linux/kernel/git/jolsa/perf.git/
>> perf/core_libdw_unwind
> Great, that was needed.
>
>> aaand ping ;-)
> I checked that the build still works ok on ARM. I am now trying with libdw.
> I can give an Ack as soon as that is done, then implement the ARM specific code.

The build with and without libunwind and libdw has been tested
succesfully on ARM, including the paths to the desired libraries.
Of course I am getting a link error on
'libdw__arch_set_initial_registers' because the ARM support is not yet
in.

Here is an ack on the series:
Acked-by: Jean Pihet <[email protected]>

Next on my plate: implement the ARM specifics.

Thanks!
Jean

>
>>
>> thanks,
>> jirka

Subject: [tip:perf/core] perf tests x86: Introduce perf_regs_load function

Commit-ID: 3c8b06f981091f91ee603768855e9739a8938296
Gitweb: http://git.kernel.org/tip/3c8b06f981091f91ee603768855e9739a8938296
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:21 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:47 -0300

perf tests x86: Introduce perf_regs_load function

Introducing perf_regs_load function, which is going to be used for dwarf
unwind test in following patches.

It takes single argument as a pointer to the regs dump buffer and
populates it with current registers values.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/arch/x86/Makefile | 1 +
tools/perf/arch/x86/include/perf_regs.h | 2 +
tools/perf/arch/x86/tests/regs_load.S | 92 +++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+)

diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 8801fe0..1cbef73 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -4,6 +4,7 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index e84ca76..f3435d62 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -5,6 +5,8 @@
#include "../../util/types.h"
#include <asm/perf_regs.h>

+void perf_regs_load(u64 *regs);
+
#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
#else
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644
index 0000000..99167bf
--- /dev/null
+++ b/tools/perf/arch/x86/tests/regs_load.S
@@ -0,0 +1,92 @@
+
+#include <linux/linkage.h>
+
+#define AX 0
+#define BX 1 * 8
+#define CX 2 * 8
+#define DX 3 * 8
+#define SI 4 * 8
+#define DI 5 * 8
+#define BP 6 * 8
+#define SP 7 * 8
+#define IP 8 * 8
+#define FLAGS 9 * 8
+#define CS 10 * 8
+#define SS 11 * 8
+#define DS 12 * 8
+#define ES 13 * 8
+#define FS 14 * 8
+#define GS 15 * 8
+#define R8 16 * 8
+#define R9 17 * 8
+#define R10 18 * 8
+#define R11 19 * 8
+#define R12 20 * 8
+#define R13 21 * 8
+#define R14 22 * 8
+#define R15 23 * 8
+
+.text
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+ENTRY(perf_regs_load)
+ movq %rax, AX(%rdi)
+ movq %rbx, BX(%rdi)
+ movq %rcx, CX(%rdi)
+ movq %rdx, DX(%rdi)
+ movq %rsi, SI(%rdi)
+ movq %rdi, DI(%rdi)
+ movq %rbp, BP(%rdi)
+
+ leaq 8(%rsp), %rax /* exclude this call. */
+ movq %rax, SP(%rdi)
+
+ movq 0(%rsp), %rax
+ movq %rax, IP(%rdi)
+
+ movq $0, FLAGS(%rdi)
+ movq $0, CS(%rdi)
+ movq $0, SS(%rdi)
+ movq $0, DS(%rdi)
+ movq $0, ES(%rdi)
+ movq $0, FS(%rdi)
+ movq $0, GS(%rdi)
+
+ movq %r8, R8(%rdi)
+ movq %r9, R9(%rdi)
+ movq %r10, R10(%rdi)
+ movq %r11, R11(%rdi)
+ movq %r12, R12(%rdi)
+ movq %r13, R13(%rdi)
+ movq %r14, R14(%rdi)
+ movq %r15, R15(%rdi)
+ ret
+ENDPROC(perf_regs_load)
+#else
+ENTRY(perf_regs_load)
+ push %edi
+ movl 8(%esp), %edi
+ movl %eax, AX(%edi)
+ movl %ebx, BX(%edi)
+ movl %ecx, CX(%edi)
+ movl %edx, DX(%edi)
+ movl %esi, SI(%edi)
+ pop %eax
+ movl %eax, DI(%edi)
+ movl %ebp, BP(%edi)
+
+ leal 4(%esp), %eax /* exclude this call. */
+ movl %eax, SP(%edi)
+
+ movl 0(%esp), %eax
+ movl %eax, IP(%edi)
+
+ movl $0, FLAGS(%edi)
+ movl $0, CS(%edi)
+ movl $0, SS(%edi)
+ movl $0, DS(%edi)
+ movl $0, ES(%edi)
+ movl $0, FS(%edi)
+ movl $0, GS(%edi)
+ ret
+ENDPROC(perf_regs_load)
+#endif

Subject: [tip:perf/core] perf tests x86: Add dwarf unwind test

Commit-ID: aa16b81fe916378ef6474530c59f719c36cd6ec4
Gitweb: http://git.kernel.org/tip/aa16b81fe916378ef6474530c59f719c36cd6ec4
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:22 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:47 -0300

perf tests x86: Add dwarf unwind test

Adding dwarf unwind test, that setups live machine data over the perf
test thread and does the remote unwind.

At this moment this test fails due to bug in the max_stack processing in
unwind__get_entries function. This is fixed in following patch.

Need to use -fno-optimize-sibling-calls for test compilation, otherwise
'krava_*' function calls are optimized into jumps and ommited from the
stack unwind.

So far it's enabled only for x86.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile.perf | 8 ++
tools/perf/arch/x86/Makefile | 1 +
tools/perf/arch/x86/include/perf_regs.h | 4 +
tools/perf/arch/x86/tests/dwarf-unwind.c | 58 +++++++++++++
tools/perf/tests/builtin-test.c | 8 ++
tools/perf/tests/dwarf-unwind.c | 144 +++++++++++++++++++++++++++++++
tools/perf/tests/tests.h | 9 ++
7 files changed, 232 insertions(+)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7257e7e..10fcf33 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -408,6 +408,11 @@ endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
+ifndef NO_LIBUNWIND
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
+endif
+endif

BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -655,6 +660,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
-DPYTHON='"$(PYTHON_WORD)"' \
$<

+$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
+ $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
+
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<

diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 1cbef73..948ea6c 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -5,6 +5,7 @@ endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index f3435d62..fc819ca 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -9,12 +9,16 @@ void perf_regs_load(u64 *regs);

#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_X86_32_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
#else
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
(1ULL << PERF_REG_X86_ES) | \
(1ULL << PERF_REG_X86_FS) | \
(1ULL << PERF_REG_X86_GS))
#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#define PERF_REGS_MAX PERF_REG_X86_64_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#endif
#define PERF_REG_IP PERF_REG_X86_IP
#define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644
index 0000000..371f849
--- /dev/null
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -0,0 +1,58 @@
+#include <string.h>
+#include "perf_regs.h"
+#include "thread.h"
+#include "map.h"
+#include "event.h"
+#include "tests/tests.h"
+
+#define STACK_SIZE 8192
+
+static int sample_ustack(struct perf_sample *sample,
+ struct thread *thread, u64 *regs)
+{
+ struct stack_dump *stack = &sample->user_stack;
+ struct map *map;
+ unsigned long sp;
+ u64 stack_size, *buf;
+
+ buf = malloc(STACK_SIZE);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ sp = (unsigned long) regs[PERF_REG_X86_SP];
+
+ map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+ if (!map) {
+ pr_debug("failed to get stack map\n");
+ return -1;
+ }
+
+ stack_size = map->end - sp;
+ stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
+
+ memcpy(buf, (void *) sp, stack_size);
+ stack->data = (char *) buf;
+ stack->size = stack_size;
+ return 0;
+}
+
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread)
+{
+ struct regs_dump *regs = &sample->user_regs;
+ u64 *buf;
+
+ buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ perf_regs_load(buf);
+ regs->abi = PERF_SAMPLE_REGS_ABI;
+ regs->regs = buf;
+
+ return sample_ustack(sample, thread, buf);
+}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 1e67437..f5a6ffb 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -115,6 +115,14 @@ static struct test {
.desc = "Test parsing with no sample_id_all bit set",
.func = test__parse_no_sample_id_all,
},
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ {
+ .desc = "Test dwarf unwind",
+ .func = test__dwarf_unwind,
+ },
+#endif
+#endif
{
.func = NULL,
},
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644
index 0000000..a203c0c
--- /dev/null
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -0,0 +1,144 @@
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "debug.h"
+#include "machine.h"
+#include "event.h"
+#include "unwind.h"
+#include "perf_regs.h"
+#include "map.h"
+#include "thread.h"
+
+static int mmap_handler(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap_event(machine, event, NULL);
+}
+
+static int init_live_machine(struct machine *machine)
+{
+ union perf_event event;
+ pid_t pid = getpid();
+
+ return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+ mmap_handler, machine, true);
+}
+
+#define MAX_STACK 6
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+ unsigned long *cnt = (unsigned long *) arg;
+ char *symbol = entry->sym ? entry->sym->name : NULL;
+ static const char *funcs[MAX_STACK] = {
+ "test__arch_unwind_sample",
+ "unwind_thread",
+ "krava_3",
+ "krava_2",
+ "krava_1",
+ "test__dwarf_unwind"
+ };
+
+ if (*cnt >= MAX_STACK) {
+ pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
+ return -1;
+ }
+
+ if (!symbol) {
+ pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
+ entry->ip);
+ return -1;
+ }
+
+ pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
+ return strcmp((const char *) symbol, funcs[(*cnt)++]);
+}
+
+__attribute__ ((noinline))
+static int unwind_thread(struct thread *thread, struct machine *machine)
+{
+ struct perf_sample sample;
+ unsigned long cnt = 0;
+ int err = -1;
+
+ memset(&sample, 0, sizeof(sample));
+
+ if (test__arch_unwind_sample(&sample, thread)) {
+ pr_debug("failed to get unwind sample\n");
+ goto out;
+ }
+
+ err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+ PERF_REGS_MASK, &sample, MAX_STACK);
+ if (err)
+ pr_debug("unwind failed\n");
+ else if (cnt != MAX_STACK) {
+ pr_debug("got wrong number of stack entries %lu != %d\n",
+ cnt, MAX_STACK);
+ err = -1;
+ }
+
+ out:
+ free(sample.user_stack.data);
+ free(sample.user_regs.regs);
+ return err;
+}
+
+__attribute__ ((noinline))
+static int krava_3(struct thread *thread, struct machine *machine)
+{
+ return unwind_thread(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_2(struct thread *thread, struct machine *machine)
+{
+ return krava_3(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_1(struct thread *thread, struct machine *machine)
+{
+ return krava_2(thread, machine);
+}
+
+int test__dwarf_unwind(void)
+{
+ struct machines machines;
+ struct machine *machine;
+ struct thread *thread;
+ int err = -1;
+
+ machines__init(&machines);
+
+ machine = machines__find(&machines, HOST_KERNEL_ID);
+ if (!machine) {
+ pr_err("Could not get machine\n");
+ return -1;
+ }
+
+ if (init_live_machine(machine)) {
+ pr_err("Could not init machine\n");
+ goto out;
+ }
+
+ if (verbose > 1)
+ machine__fprintf(machine, stderr);
+
+ thread = machine__find_thread(machine, getpid());
+ if (!thread) {
+ pr_err("Could not get thread\n");
+ goto out;
+ }
+
+ err = krava_1(thread, machine);
+
+ out:
+ machine__delete_threads(machine);
+ machine__exit(machine);
+ machines__exit(&machines);
+ return err;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index e0ac713..8979309 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -40,5 +40,14 @@ int test__code_reading(void);
int test__sample_parsing(void);
int test__keep_tracking(void);
int test__parse_no_sample_id_all(void);
+int test__dwarf_unwind(void);

+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_LIBUNWIND_SUPPORT
+struct thread;
+struct perf_sample;
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread);
+#endif
+#endif
#endif /* TESTS_H */

Subject: [tip:perf/core] perf tools: Fix dwarf unwind max_stack processing

Commit-ID: b42dc32d4f91e4c0f34b628fdb012eb423da9e69
Gitweb: http://git.kernel.org/tip/b42dc32d4f91e4c0f34b628fdb012eb423da9e69
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:23 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:47 -0300

perf tools: Fix dwarf unwind max_stack processing

The 'unwind__get_entries' function currently returns 'max_stack + 1'
entries (instead of exact max_stack entries), because max_stack value
does not get decremented for the first entry.

This fix makes dwarf-unwind test pass.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/unwind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 742f23b..bff3209 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -595,5 +595,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (ret)
return -ENOMEM;

- return get_entries(&ui, cb, arg, max_stack);
+ return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
}

Subject: [tip:perf/core] perf callchain: Do not report zero address in unwind

Commit-ID: 1cf0382af98f6365b01b59453fe18dffe3c73d2f
Gitweb: http://git.kernel.org/tip/1cf0382af98f6365b01b59453fe18dffe3c73d2f
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:24 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:48 -0300

perf callchain: Do not report zero address in unwind

We are not interested in zero addresses in callchain, do not report
them.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/unwind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index bff3209..3b70181 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -563,7 +563,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
unw_word_t ip;

unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = entry(ip, ui->thread, ui->machine, cb, arg);
+ ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
}

unw_destroy_addr_space(addr_space);

Subject: [tip:perf/core] perf callchain: Separate libunwind code to special object

Commit-ID: 436aa749bb193385f6a3b741ddc6bfba61770a6e
Gitweb: http://git.kernel.org/tip/436aa749bb193385f6a3b741ddc6bfba61770a6e
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:26 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:48 -0300

perf callchain: Separate libunwind code to special object

We are going to add libdw library support to do dwarf post unwind.

Making the code ready by moving libunwind dwarf post unwind stuff into
separate object.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile.perf | 2 +-
tools/perf/arch/arm/Makefile | 2 +-
tools/perf/arch/arm/util/{unwind.c => unwind-libunwind.c} | 0
tools/perf/arch/x86/Makefile | 2 +-
tools/perf/arch/x86/util/{unwind.c => unwind-libunwind.c} | 0
tools/perf/util/{unwind.c => unwind-libunwind.c} | 0
6 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 10fcf33..9ef6b33 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -481,7 +481,7 @@ endif # NO_DWARF
endif # NO_LIBELF

ifndef NO_LIBUNWIND
- LIB_OBJS += $(OUTPUT)util/unwind.o
+ LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
endif
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o

diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index fe9b61e..67e9b3d 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
endif
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
similarity index 100%
rename from tools/perf/arch/arm/util/unwind.c
rename to tools/perf/arch/arm/util/unwind-libunwind.c
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 948ea6c..4fa9be9 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,7 +3,7 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
similarity index 100%
rename from tools/perf/arch/x86/util/unwind.c
rename to tools/perf/arch/x86/util/unwind-libunwind.c
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind-libunwind.c
similarity index 100%
rename from tools/perf/util/unwind.c
rename to tools/perf/util/unwind-libunwind.c

Subject: [tip:perf/core] perf callchain: Introduce HAVE_DWARF_UNWIND_SUPPORT macro

Commit-ID: 9ff125d132001c02d32a193a9423be0690526e11
Gitweb: http://git.kernel.org/tip/9ff125d132001c02d32a193a9423be0690526e11
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:28 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:48 -0300

perf callchain: Introduce HAVE_DWARF_UNWIND_SUPPORT macro

Introducing global macro HAVE_DWARF_UNWIND_SUPPORT to indicate we have
dwarf unwind support. Any library providing the dwarf post unwind
support will enable this macro.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-record.c | 10 +++++-----
tools/perf/config/Makefile | 2 +-
tools/perf/tests/builtin-test.c | 2 +-
tools/perf/tests/tests.h | 2 +-
tools/perf/util/unwind.h | 7 +++++--
5 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 7b8f0e6..eb524f9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -649,7 +649,7 @@ error:
return ret;
}

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
static int get_stack_size(char *str, unsigned long *_size)
{
char *endptr;
@@ -675,7 +675,7 @@ static int get_stack_size(char *str, unsigned long *_size)
max_size, str);
return -1;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */

int record_parse_callchain(const char *arg, struct record_opts *opts)
{
@@ -704,7 +704,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
"needed for -g fp\n");
break;

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
/* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192;
@@ -720,7 +720,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
ret = get_stack_size(tok, &size);
opts->stack_dump_size = size;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
} else {
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
@@ -823,7 +823,7 @@ static struct record record = {

#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
#else
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index c48d449..1686583 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -338,7 +338,7 @@ ifndef NO_LIBUNWIND
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
endif

- CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
EXTLIBS += $(LIBUNWIND_LIBS)
CFLAGS += $(LIBUNWIND_CFLAGS)
LDFLAGS += $(LIBUNWIND_LDFLAGS)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index f5a6ffb..b11bf8a 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -116,7 +116,7 @@ static struct test {
.func = test__parse_no_sample_id_all,
},
#if defined(__x86_64__) || defined(__i386__)
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
{
.desc = "Test dwarf unwind",
.func = test__dwarf_unwind,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 8979309..a24795c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -43,7 +43,7 @@ int test__parse_no_sample_id_all(void);
int test__dwarf_unwind(void);

#if defined(__x86_64__) || defined(__i386__)
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
struct thread;
struct perf_sample;
int test__arch_unwind_sample(struct perf_sample *sample,
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 18f33b4..b031316 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,12 +13,15 @@ struct unwind_entry {

typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);

-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
struct perf_sample *data, int max_stack);
+/* libunwind specific */
+#ifdef HAVE_LIBUNWIND_SUPPORT
int libunwind__arch_reg_id(int regnum);
+#endif
#else
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
@@ -30,5 +33,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
{
return 0;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
#endif /* __UNWIND_H */

Subject: [tip:perf/core] perf callchain: Add mask into struct regs_dump

Commit-ID: 352ea45a7229df8f5ae83c0757f6d426ba0f41b5
Gitweb: http://git.kernel.org/tip/352ea45a7229df8f5ae83c0757f6d426ba0f41b5
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:25 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:48 -0300

perf callchain: Add mask into struct regs_dump

Adding mask info into struct regs_dump to make the registers information
compact.

The mask was always passed along, so logically the mask info fits more
into the struct regs_dump.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Adrian Hunter <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/arch/x86/tests/dwarf-unwind.c | 1 +
tools/perf/builtin-inject.c | 1 -
tools/perf/tests/dwarf-unwind.c | 2 +-
tools/perf/tests/sample-parsing.c | 17 ++++++++---------
tools/perf/util/event.h | 5 +++--
tools/perf/util/evsel.c | 13 +++++++------
tools/perf/util/machine.c | 3 +--
tools/perf/util/session.c | 5 +++--
tools/perf/util/unwind.c | 20 ++++++++------------
tools/perf/util/unwind.h | 2 --
10 files changed, 32 insertions(+), 37 deletions(-)

diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 371f849..b602ad9 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -53,6 +53,7 @@ int test__arch_unwind_sample(struct perf_sample *sample,
perf_regs_load(buf);
regs->abi = PERF_SAMPLE_REGS_ABI;
regs->regs = buf;
+ regs->mask = PERF_REGS_MASK;

return sample_ustack(sample, thread, buf);
}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b346601..3a73875 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -312,7 +312,6 @@ found:
sample_sw.period = sample->period;
sample_sw.time = sample->time;
perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
- evsel->attr.sample_regs_user,
evsel->attr.read_format, &sample_sw,
false);
build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index a203c0c..f16ea28 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
}

err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
- PERF_REGS_MASK, &sample, MAX_STACK);
+ &sample, MAX_STACK);
if (err)
pr_debug("unwind failed\n");
else if (cnt != MAX_STACK) {
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 1b67720..0014d3c 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -22,8 +22,8 @@
} while (0)

static bool samples_same(const struct perf_sample *s1,
- const struct perf_sample *s2, u64 type, u64 regs_user,
- u64 read_format)
+ const struct perf_sample *s2,
+ u64 type, u64 read_format)
{
size_t i;

@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
}

if (type & PERF_SAMPLE_REGS_USER) {
- size_t sz = hweight_long(regs_user) * sizeof(u64);
+ size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);

+ COMP(user_regs.mask);
COMP(user_regs.abi);
if (s1->user_regs.abi &&
(!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.branch_stack = &branch_stack.branch_stack,
.user_regs = {
.abi = PERF_SAMPLE_REGS_ABI_64,
+ .mask = sample_regs_user,
.regs = user_regs,
},
.user_stack = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
sample.read.one.id = 99;
}

- sz = perf_event__sample_event_size(&sample, sample_type,
- sample_regs_user, read_format);
+ sz = perf_event__sample_event_size(&sample, sample_type, read_format);
bufsz = sz + 4096; /* Add a bit for overrun checking */
event = malloc(bufsz);
if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
event->header.misc = 0;
event->header.size = sz;

- err = perf_event__synthesize_sample(event, sample_type,
- sample_regs_user, read_format,
+ err = perf_event__synthesize_sample(event, sample_type, read_format,
&sample, false);
if (err) {
pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
goto out_free;
}

- if (!samples_same(&sample, &sample_out, sample_type,
- sample_regs_user, read_format)) {
+ if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
pr_debug("parsing failed for sample_type %#"PRIx64"\n",
sample_type);
goto out_free;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 851fa06..38457d4 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -85,6 +85,7 @@ struct sample_event {

struct regs_dump {
u64 abi;
+ u64 mask;
u64 *regs;
};

@@ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
const char *perf_event__name(unsigned int id);

size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format);
+ u64 read_format);
int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped);

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8201abe..adc94dd 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1396,10 +1396,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array++;

if (data->user_regs.abi) {
- u64 regs_user = evsel->attr.sample_regs_user;
+ u64 mask = evsel->attr.sample_regs_user;

- sz = hweight_long(regs_user) * sizeof(u64);
+ sz = hweight_long(mask) * sizeof(u64);
OVERFLOW_CHECK(array, sz, max_size);
+ data->user_regs.mask = mask;
data->user_regs.regs = (u64 *)array;
array = (void *)array + sz;
}
@@ -1451,7 +1452,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
}

size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format)
+ u64 read_format)
{
size_t sz, result = sizeof(struct sample_event);

@@ -1517,7 +1518,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
result += sizeof(u64);
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
result += sz;
} else {
result += sizeof(u64);
@@ -1546,7 +1547,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
}

int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped)
{
@@ -1687,7 +1688,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
*array++ = sample->user_regs.abi;
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
memcpy(array, sample->user_regs.regs, sz);
array = (void *)array + sz;
} else {
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 6c08ab0..ac37d78 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1383,8 +1383,7 @@ int machine__resolve_callchain(struct machine *machine,
return 0;

return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
- thread, evsel->attr.sample_regs_user,
- sample, max_stack);
+ thread, sample, max_stack);

}

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5da6ce7..1d555d6 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
}
}

-static void regs_user__printf(struct perf_sample *sample, u64 mask)
+static void regs_user__printf(struct perf_sample *sample)
{
struct regs_dump *user_regs = &sample->user_regs;

if (user_regs->regs) {
+ u64 mask = user_regs->mask;
printf("... user regs: mask 0x%" PRIx64 "\n", mask);
regs_dump__printf(mask, user_regs->regs);
}
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
branch_stack__printf(sample);

if (sample_type & PERF_SAMPLE_REGS_USER)
- regs_user__printf(sample, evsel->attr.sample_regs_user);
+ regs_user__printf(sample);

if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 3b70181..720a4ca 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -86,7 +86,6 @@ struct unwind_info {
struct perf_sample *sample;
struct machine *machine;
struct thread *thread;
- u64 sample_uregs;
};

#define dw_read(ptr, type, end) ({ \
@@ -391,16 +390,16 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
return !(size == sizeof(*data));
}

-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
- u64 sample_regs)
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
{
int i, idx = 0;
+ u64 mask = regs->mask;

- if (!(sample_regs & (1 << id)))
+ if (!(mask & (1 << id)))
return -EINVAL;

for (i = 0; i < id; i++) {
- if (sample_regs & (1 << i))
+ if (mask & (1 << i))
idx++;
}

@@ -424,8 +423,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
return 0;
}

- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
- ui->sample_uregs);
+ ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
if (ret)
return ret;

@@ -475,7 +473,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
if (id < 0)
return -EINVAL;

- ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
+ ret = reg_value(valp, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
@@ -572,13 +570,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,

int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct thread *thread,
- u64 sample_uregs, struct perf_sample *data,
- int max_stack)
+ struct perf_sample *data, int max_stack)
{
unw_word_t ip;
struct unwind_info ui = {
.sample = data,
- .sample_uregs = sample_uregs,
.thread = thread,
.machine = machine,
};
@@ -587,7 +583,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (!data->user_regs.regs)
return -EINVAL;

- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
+ ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (ret)
return ret;

diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index d5966f49..356e1d6 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -17,7 +17,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
- u64 sample_uregs,
struct perf_sample *data, int max_stack);
int unwind__arch_reg_id(int regnum);
#else
@@ -26,7 +25,6 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
void *arg __maybe_unused,
struct machine *machine __maybe_unused,
struct thread *thread __maybe_unused,
- u64 sample_uregs __maybe_unused,
struct perf_sample *data __maybe_unused,
int max_stack __maybe_unused)
{

Subject: [tip:perf/core] perf callchain: Separate perf_reg_value function in perf_regs object

Commit-ID: c9b951c4d12f0b2e9a07dd459c554bc05628d092
Gitweb: http://git.kernel.org/tip/c9b951c4d12f0b2e9a07dd459c554bc05628d092
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:29 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:49 -0300

perf callchain: Separate perf_reg_value function in perf_regs object

Making perf_reg_value function global (formely reg_value), because it's
going to be used globaly across all code providing the dwarf post unwind
feature.

Changing its prototype to be generic:

-int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);

Changing the valp type from libunwind specific 'unw_word_t' to u64.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile.perf | 1 +
tools/perf/util/perf_regs.c | 19 +++++++++++++++++++
tools/perf/util/perf_regs.h | 13 +++++++++++++
tools/perf/util/unwind-libunwind.c | 38 ++++++++++++--------------------------
4 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9ef6b33..f99a392 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -538,6 +538,7 @@ ifeq ($(NO_PERF_REGS),0)
ifeq ($(ARCH),x86)
LIB_H += arch/x86/include/perf_regs.h
endif
+ LIB_OBJS += $(OUTPUT)util/perf_regs.o
endif

ifndef NO_LIBNUMA
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644
index 0000000..a3539ef
--- /dev/null
+++ b/tools/perf/util/perf_regs.c
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include "perf_regs.h"
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
+{
+ int i, idx = 0;
+ u64 mask = regs->mask;
+
+ if (!(mask & (1 << id)))
+ return -EINVAL;
+
+ for (i = 0; i < id; i++) {
+ if (mask & (1 << i))
+ idx++;
+ }
+
+ *valp = regs->regs[idx];
+ return 0;
+}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index a3d42cd..d6e8b6a 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,14 @@
#ifndef __PERF_REGS_H
#define __PERF_REGS_H

+#include "types.h"
+#include "event.h"
+
#ifdef HAVE_PERF_REGS_SUPPORT
#include <perf_regs.h>
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
+
#else
#define PERF_REGS_MASK 0

@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
{
return NULL;
}
+
+static inline int perf_reg_value(u64 *valp __maybe_unused,
+ struct regs_dump *regs __maybe_unused,
+ int id __maybe_unused)
+{
+ return 0;
+}
#endif /* HAVE_PERF_REGS_SUPPORT */
#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 79dbfbb..bd5768d 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -390,30 +390,13 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
return !(size == sizeof(*data));
}

-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
-{
- int i, idx = 0;
- u64 mask = regs->mask;
-
- if (!(mask & (1 << id)))
- return -EINVAL;
-
- for (i = 0; i < id; i++) {
- if (mask & (1 << i))
- idx++;
- }
-
- *valp = regs->regs[idx];
- return 0;
-}
-
static int access_mem(unw_addr_space_t __maybe_unused as,
unw_word_t addr, unw_word_t *valp,
int __write, void *arg)
{
struct unwind_info *ui = arg;
struct stack_dump *stack = &ui->sample->user_stack;
- unw_word_t start, end;
+ u64 start, end;
int offset;
int ret;

@@ -423,7 +406,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
return 0;
}

- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
if (ret)
return ret;

@@ -436,8 +419,9 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
if (addr < start || addr + sizeof(unw_word_t) >= end) {
ret = access_dso_mem(ui, addr, valp);
if (ret) {
- pr_debug("unwind: access_mem %p not inside range %p-%p\n",
- (void *)addr, (void *)start, (void *)end);
+ pr_debug("unwind: access_mem %p not inside range"
+ " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+ (void *) addr, start, end);
*valp = 0;
return ret;
}
@@ -446,8 +430,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as,

offset = addr - start;
*valp = *(unw_word_t *)&stack->data[offset];
- pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
- (void *)addr, (unsigned long)*valp, offset);
+ pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+ (void *) addr, (unsigned long)*valp, offset);
return 0;
}

@@ -457,6 +441,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
{
struct unwind_info *ui = arg;
int id, ret;
+ u64 val;

/* Don't support write, I suspect we don't need it. */
if (__write) {
@@ -473,12 +458,13 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
if (id < 0)
return -EINVAL;

- ret = reg_value(valp, &ui->sample->user_regs, id);
+ ret = perf_reg_value(&val, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
}

+ *valp = (unw_word_t) val;
pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
return 0;
}
@@ -572,7 +558,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct thread *thread,
struct perf_sample *data, int max_stack)
{
- unw_word_t ip;
+ u64 ip;
struct unwind_info ui = {
.sample = data,
.thread = thread,
@@ -583,7 +569,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (!data->user_regs.regs)
return -EINVAL;

- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (ret)
return ret;

Subject: [tip:perf/core] perf callchain: Rename unwind__arch_reg_id into libunwind__arch_reg_id

Commit-ID: ea3da69df959dfa1c807586c061bfcc4ec7e5e17
Gitweb: http://git.kernel.org/tip/ea3da69df959dfa1c807586c061bfcc4ec7e5e17
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 7 Jan 2014 13:47:27 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 18 Feb 2014 09:34:48 -0300

perf callchain: Rename unwind__arch_reg_id into libunwind__arch_reg_id

Renaming unwind__arch_reg_id into libunwind__arch_reg_id, so it's clear
it's specific to libunwind.

Signed-off-by: Jiri Olsa <[email protected]>
Acked-by: Jean Pihet <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/arch/arm/util/unwind-libunwind.c | 2 +-
tools/perf/arch/x86/util/unwind-libunwind.c | 4 ++--
tools/perf/util/unwind-libunwind.c | 2 +-
tools/perf/util/unwind.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
index da3dc95..729ed69 100644
--- a/tools/perf/arch/arm/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -4,7 +4,7 @@
#include "perf_regs.h"
#include "../../util/unwind.h"

-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
switch (regnum) {
case UNW_ARM_R0:
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 456a88c..3261f68 100644
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -5,7 +5,7 @@
#include "../../util/unwind.h"

#ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;

@@ -69,7 +69,7 @@ int unwind__arch_reg_id(int regnum)
return id;
}
#else
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;

diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 720a4ca..79dbfbb 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -469,7 +469,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
return 0;
}

- id = unwind__arch_reg_id(regnum);
+ id = libunwind__arch_reg_id(regnum);
if (id < 0)
return -EINVAL;

diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 356e1d6..18f33b4 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -18,7 +18,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
struct perf_sample *data, int max_stack);
-int unwind__arch_reg_id(int regnum);
+int libunwind__arch_reg_id(int regnum);
#else
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,