Skip to content

Commit a29d5c9

Browse files
committed
perf tools: Separate accounting of contexts and real addresses in a stack trace
The perf_sample->ip_callchain->nr value includes all the entries in the ip_callchain->ip[] array, real addresses and PERF_CONTEXT_{KERNEL,USER,etc}, while what the user expects is that what is in the kernel.perf_event_max_stack sysctl or in the upcoming per event perf_event_attr.sample_max_stack knob be honoured in terms of IP addresses in the stack trace. So match the kernel support and validate chain->nr taking into account both kernel.perf_event_max_stack and kernel.perf_event_max_contexts_per_stack. Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Brendan Gregg <[email protected]> Cc: David Ahern <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: He Kuang <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Milian Wolff <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Cc: Wang Nan <[email protected]> Cc: Zefan Li <[email protected]> Link: http://lkml.kernel.org/n/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent c85b033 commit a29d5c9

File tree

4 files changed

+24
-11
lines changed

4 files changed

+24
-11
lines changed

tools/perf/perf.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ int main(int argc, const char **argv)
549549
if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
550550
sysctl_perf_event_max_stack = value;
551551

552+
if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
553+
sysctl_perf_event_max_contexts_per_stack = value;
554+
552555
cmd = extract_argv0_path(argv[0]);
553556
if (!cmd)
554557
cmd = "perf-help";

tools/perf/util/machine.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1811,9 +1811,9 @@ static int thread__resolve_callchain_sample(struct thread *thread,
18111811
{
18121812
struct branch_stack *branch = sample->branch_stack;
18131813
struct ip_callchain *chain = sample->callchain;
1814-
int chain_nr = min(max_stack, (int)chain->nr);
1814+
int chain_nr = chain->nr;
18151815
u8 cpumode = PERF_RECORD_MISC_USER;
1816-
int i, j, err;
1816+
int i, j, err, nr_entries, nr_contexts;
18171817
int skip_idx = -1;
18181818
int first_call = 0;
18191819

@@ -1828,7 +1828,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
18281828
* Based on DWARF debug information, some architectures skip
18291829
* a callchain entry saved by the kernel.
18301830
*/
1831-
if (chain->nr < sysctl_perf_event_max_stack)
1831+
if (chain_nr < sysctl_perf_event_max_stack)
18321832
skip_idx = arch_skip_callchain_idx(thread, chain);
18331833

18341834
/*
@@ -1889,12 +1889,8 @@ static int thread__resolve_callchain_sample(struct thread *thread,
18891889
}
18901890

18911891
check_calls:
1892-
if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) {
1893-
pr_warning("corrupted callchain. skipping...\n");
1894-
return 0;
1895-
}
1896-
1897-
for (i = first_call; i < chain_nr; i++) {
1892+
for (i = first_call, nr_entries = 0, nr_contexts = 0;
1893+
i < chain_nr && nr_entries < max_stack; i++) {
18981894
u64 ip;
18991895

19001896
if (callchain_param.order == ORDER_CALLEE)
@@ -1908,13 +1904,25 @@ static int thread__resolve_callchain_sample(struct thread *thread,
19081904
#endif
19091905
ip = chain->ips[j];
19101906

1907+
if (ip >= PERF_CONTEXT_MAX) {
1908+
if (++nr_contexts > sysctl_perf_event_max_contexts_per_stack)
1909+
goto out_corrupted_callchain;
1910+
} else {
1911+
if (++nr_entries > sysctl_perf_event_max_stack)
1912+
goto out_corrupted_callchain;
1913+
}
1914+
19111915
err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
19121916

19131917
if (err)
19141918
return (err < 0) ? err : 0;
19151919
}
19161920

19171921
return 0;
1922+
1923+
out_corrupted_callchain:
1924+
pr_warning("corrupted callchain. skipping...\n");
1925+
return 0;
19181926
}
19191927

19201928
static int unwind_entry(struct unwind_entry *entry, void *arg)

tools/perf/util/util.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ struct callchain_param callchain_param = {
3333
unsigned int page_size;
3434
int cacheline_size;
3535

36-
unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
36+
int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
37+
int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
3738

3839
bool test_attr__enabled;
3940

tools/perf/util/util.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ void sighandler_dump_stack(int sig);
261261

262262
extern unsigned int page_size;
263263
extern int cacheline_size;
264-
extern unsigned int sysctl_perf_event_max_stack;
264+
extern int sysctl_perf_event_max_stack;
265+
extern int sysctl_perf_event_max_contexts_per_stack;
265266

266267
struct parse_tag {
267268
char tag;

0 commit comments

Comments
 (0)