static int inherit = 1;
static int force = 0;
static int append_file = 0;
+static int call_graph = 0;
static int verbose = 0;
static long samples;
int track = 1;
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+
if (freq) {
attr->sample_type |= PERF_SAMPLE_PERIOD;
attr->freq = 1;
attr->sample_freq = freq;
}
+
+ if (call_graph)
+ attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
+
attr->mmap = track;
attr->comm = track;
attr->inherit = (cpu < 0) && inherit;
"profile at this frequency"),
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
"number of mmap data pages"),
+ OPT_BOOLEAN('g', "call-graph", &call_graph,
+ "do call-graph (stack chain/backtrace) recording"),
OPT_BOOLEAN('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_END()
static int dump_trace = 0;
#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
+#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
static int verbose;
static int full_paths;
static unsigned long page_size;
static unsigned long mmap_window = 32;
+struct ip_chain_event {
+ __u16 nr;
+ __u16 hv;
+ __u16 kernel;
+ __u16 user;
+ __u64 ips[];
+};
+
struct ip_event {
struct perf_event_header header;
__u64 ip;
__u32 pid, tid;
- __u64 period;
+ unsigned char __more_data[];
};
struct mmap_event {
__u64 ip = event->ip.ip;
__u64 period = 1;
struct map *map = NULL;
+ void *more_data = event->ip.__more_data;
+ struct ip_chain_event *chain;
- if (event->header.type & PERF_SAMPLE_PERIOD)
- period = event->ip.period;
+ if (event->header.type & PERF_SAMPLE_PERIOD) {
+ period = *(__u64 *)more_data;
+ more_data += sizeof(__u64);
+ }
dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
(void *)(offset + head),
(void *)(long)ip,
(long long)period);
+ if (event->header.type & PERF_SAMPLE_CALLCHAIN) {
+ int i;
+
+ chain = (void *)more_data;
+
+ if (dump_trace) {
+ dprintf("... chain: u:%d, k:%d, nr:%d\n",
+ chain->user,
+ chain->kernel,
+ chain->nr);
+
+ for (i = 0; i < chain->nr; i++)
+ dprintf("..... %2d: %p\n", i, (void *)chain->ips[i]);
+ }
+ }
+
dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
if (thread == NULL) {
static void trace_event(event_t *event)
{
unsigned char *raw_event = (void *)event;
+ char *color = PERF_COLOR_BLUE;
int i, j;
if (!dump_trace)
return;
- dprintf(".\n. ... raw event: size %d bytes\n", event->header.size);
+ dprintf(".");
+ cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
for (i = 0; i < event->header.size; i++) {
- if ((i & 15) == 0)
- dprintf(". %04x: ", i);
+ if ((i & 15) == 0) {
+ dprintf(".");
+ cdprintf(" %04x: ", i);
+ }
- dprintf(" %02x", raw_event[i]);
+ cdprintf(" %02x", raw_event[i]);
if (((i & 15) == 15) || i == event->header.size-1) {
- dprintf(" ");
+ cdprintf(" ");
for (j = 0; j < 15-(i & 15); j++)
- dprintf(" ");
+ cdprintf(" ");
for (j = 0; j < (i & 15); j++) {
if (isprint(raw_event[i-15+j]))
- dprintf("%c", raw_event[i-15+j]);
+ cdprintf("%c", raw_event[i-15+j]);
else
- dprintf(".");
+ cdprintf(".");
}
- dprintf("\n");
+ cdprintf("\n");
}
}
dprintf(".\n");