From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757682Ab2HUP4k (ORCPT ); Tue, 21 Aug 2012 11:56:40 -0400 Received: from terminus.zytor.com ([198.137.202.10]:60444 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752853Ab2HUP4h (ORCPT ); Tue, 21 Aug 2012 11:56:37 -0400 Date: Tue, 21 Aug 2012 08:55:57 -0700 From: tip-bot for Jiri Olsa Message-ID: Cc: acme@redhat.com, eranian@google.com, mingo@kernel.org, gorcunov@openvz.org, a.p.zijlstra@chello.nl, benjamin.redelings@nescent.org, jolsa@redhat.com, drepper@gmail.com, robert.richter@amd.com, fweisbec@gmail.com, tglx@linutronix.de, cjashfor@linux.vnet.ibm.com, asharma@fb.com, linux-kernel@vger.kernel.org, hpa@zytor.com, fche@redhat.com, paulus@samba.org, tzanussi@gmail.com, masami.hiramatsu.pt@hitachi.com, mingo@elte.hu Reply-To: mingo@kernel.org, eranian@google.com, acme@redhat.com, gorcunov@openvz.org, a.p.zijlstra@chello.nl, benjamin.redelings@nescent.org, jolsa@redhat.com, fweisbec@gmail.com, robert.richter@amd.com, drepper@gmail.com, tglx@linutronix.de, cjashfor@linux.vnet.ibm.com, asharma@fb.com, paulus@samba.org, linux-kernel@vger.kernel.org, hpa@zytor.com, fche@redhat.com, tzanussi@gmail.com, masami.hiramatsu.pt@hitachi.com, mingo@elte.hu In-Reply-To: <1344345647-11536-13-git-send-email-jolsa@redhat.com> References: <1344345647-11536-13-git-send-email-jolsa@redhat.com> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/core] perf tools: Support for DWARF mode callchain Git-Commit-ID: 26d330226b9cf6208daae9b0b3697980c8fb51d8 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.2.6 (terminus.zytor.com [127.0.0.1]); Tue, 21 Aug 2012 08:56:03 -0700 (PDT) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 26d330226b9cf6208daae9b0b3697980c8fb51d8 Gitweb: http://git.kernel.org/tip/26d330226b9cf6208daae9b0b3697980c8fb51d8 Author: Jiri Olsa AuthorDate: Tue, 7 Aug 2012 15:20:47 +0200 Committer: Arnaldo Carvalho de Melo CommitDate: Sat, 11 Aug 2012 15:07:18 -0300 perf tools: Support for DWARF mode callchain This patch enables perf to use the DWARF unwind code. It extends the perf record '-g' option with following arguments: 'fp' - provides framepointer based user stack backtrace 'dwarf[,size]' - provides DWARF (libunwind) based user stack backtrace. The size specifies the size of the user stack dump. If omitted it is 8192 by default. If libunwind is found during the perf build, then the 'dwarf' argument becomes available for record command. The 'fp' stays as default option in any case. Examples: (perf compiled with libunwind) perf record -g dwarf ls - provides dwarf unwind with 8192 as stack dump size perf record -g dwarf,4096 ls - provides dwarf unwind with 4096 as stack dump size perf record -g -- ls perf record -g fp ls - provides frame pointer unwind Signed-off-by: Jiri Olsa Original-patch-by: Frederic Weisbecker Cc: "Frank Ch. Eigler" Cc: Arun Sharma Cc: Benjamin Redelings Cc: Corey Ashford Cc: Cyrill Gorcunov Cc: Frank Ch. Eigler Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Masami Hiramatsu Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Robert Richter Cc: Stephane Eranian Cc: Tom Zanussi Cc: Ulrich Drepper Link: http://lkml.kernel.org/r/1344345647-11536-13-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 114 ++++++++++++++++++++++++++++++++++++++++++- tools/perf/perf.h | 9 +++- tools/perf/util/evsel.c | 13 +++++- 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4db6e1b..22dd05d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -31,6 +31,15 @@ #include #include +#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " + +#ifdef NO_LIBUNWIND_SUPPORT +static char callchain_help[] = CALLCHAIN_HELP "[fp]"; +#else +static unsigned long default_stack_dump_size = 8192; +static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; +#endif + enum write_mode_t { WRITE_FORCE, WRITE_APPEND @@ -732,6 +741,106 @@ error: return ret; } +#ifndef NO_LIBUNWIND_SUPPORT +static int get_stack_size(char *str, unsigned long *_size) +{ + char *endptr; + unsigned long size; + unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); + + size = strtoul(str, &endptr, 0); + + do { + if (*endptr) + break; + + size = round_up(size, sizeof(u64)); + if (!size || size > max_size) + break; + + *_size = size; + return 0; + + } while (0); + + pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", + max_size, str); + return -1; +} +#endif /* !NO_LIBUNWIND_SUPPORT */ + +static int +parse_callchain_opt(const struct option *opt __used, const char *arg, + int unset) +{ + struct perf_record *rec = (struct perf_record *)opt->value; + char *tok, *name, *saveptr = NULL; + char *buf; + int ret = -1; + + /* --no-call-graph */ + if (unset) + return 0; + + /* We specified default option if none is provided. */ + BUG_ON(!arg); + + /* We need buffer that we know we can write to. */ + buf = malloc(strlen(arg) + 1); + if (!buf) + return -ENOMEM; + + strcpy(buf, arg); + + tok = strtok_r((char *)buf, ",", &saveptr); + name = tok ? : (char *)buf; + + do { + /* Framepointer style */ + if (!strncmp(name, "fp", sizeof("fp"))) { + if (!strtok_r(NULL, ",", &saveptr)) { + rec->opts.call_graph = CALLCHAIN_FP; + ret = 0; + } else + pr_err("callchain: No more arguments " + "needed for -g fp\n"); + break; + +#ifndef NO_LIBUNWIND_SUPPORT + /* Dwarf style */ + } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { + ret = 0; + rec->opts.call_graph = CALLCHAIN_DWARF; + rec->opts.stack_dump_size = default_stack_dump_size; + + tok = strtok_r(NULL, ",", &saveptr); + if (tok) { + unsigned long size = 0; + + ret = get_stack_size(tok, &size); + rec->opts.stack_dump_size = size; + } + + if (!ret) + pr_debug("callchain: stack dump size %d\n", + rec->opts.stack_dump_size); +#endif /* !NO_LIBUNWIND_SUPPORT */ + } else { + pr_err("callchain: Unknown -g option " + "value: %s\n", arg); + break; + } + + } while (0); + + free(buf); + + if (!ret) + pr_debug("callchain: type %d\n", rec->opts.call_graph); + + return ret; +} + static const char * const record_usage[] = { "perf record [] []", "perf record [] -- []", @@ -803,8 +912,9 @@ const struct option record_options[] = { "number of mmap data pages"), OPT_BOOLEAN(0, "group", &record.opts.group, "put the counters into a counter group"), - OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph, - "do call-graph (stack chain/backtrace) recording"), + OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", + callchain_help, &parse_callchain_opt, + "fp"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), diff --git a/tools/perf/perf.h b/tools/perf/perf.h index f960ccb..87f4ec6 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -209,9 +209,15 @@ void pthread__unblock_sigwinch(void); #include "util/target.h" +enum perf_call_graph_mode { + CALLCHAIN_NONE, + CALLCHAIN_FP, + CALLCHAIN_DWARF +}; + struct perf_record_opts { struct perf_target target; - bool call_graph; + int call_graph; bool group; bool inherit_stat; bool no_delay; @@ -230,6 +236,7 @@ struct perf_record_opts { u64 branch_stack; u64 default_interval; u64 user_interval; + u16 stack_dump_size; }; #endif diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a2da682..9c54e8f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -17,6 +17,8 @@ #include "thread_map.h" #include "target.h" #include "../../../include/linux/hw_breakpoint.h" +#include "../../include/linux/perf_event.h" +#include "perf_regs.h" #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) @@ -368,9 +370,18 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, attr->mmap_data = track; } - if (opts->call_graph) + if (opts->call_graph) { attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + if (opts->call_graph == CALLCHAIN_DWARF) { + attr->sample_type |= PERF_SAMPLE_REGS_USER | + PERF_SAMPLE_STACK_USER; + attr->sample_regs_user = PERF_REGS_MASK; + attr->sample_stack_user = opts->stack_dump_size; + attr->exclude_callchain_user = 1; + } + } + if (perf_target__has_cpu(&opts->target)) attr->sample_type |= PERF_SAMPLE_CPU;