Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 323671
b: refs/heads/master
c: 26d3302
h: refs/heads/master
i:
  323669: 5253ba9
  323667: 9940e7e
  323663: 1ca0f4b
v: v3
  • Loading branch information
Jiri Olsa authored and Arnaldo Carvalho de Melo committed Aug 11, 2012
1 parent ba89a98 commit 0e6d611
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 71ad0f5e4e361c8bca864c7d09d14b64af6bc2fc
refs/heads/master: 26d330226b9cf6208daae9b0b3697980c8fb51d8
114 changes: 112 additions & 2 deletions trunk/tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
#include <sched.h>
#include <sys/mman.h>

#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
Expand Down Expand Up @@ -732,6 +741,106 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
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 [<options>] [<command>]",
"perf record [<options>] -- <command> [<options>]",
Expand Down Expand Up @@ -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"),
Expand Down
9 changes: 8 additions & 1 deletion trunk/tools/perf/perf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -230,6 +236,7 @@ struct perf_record_opts {
u64 branch_stack;
u64 default_interval;
u64 user_interval;
u16 stack_dump_size;
};

#endif
13 changes: 12 additions & 1 deletion trunk/tools/perf/util/evsel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 0e6d611

Please sign in to comment.