Skip to content

Commit 568b329

Browse files
4astdavem330
authored andcommitted
perf: generalize perf_callchain
. avoid walking the stack when there is no room left in the buffer . generalize get_perf_callchain() to be called from bpf helper Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6b83d28 commit 568b329

File tree

8 files changed

+51
-29
lines changed

8 files changed

+51
-29
lines changed

arch/x86/include/asm/stacktrace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ print_context_stack_bp(struct thread_info *tinfo,
3737
/* Generic stack tracer with callbacks */
3838

3939
struct stacktrace_ops {
40-
void (*address)(void *data, unsigned long address, int reliable);
40+
int (*address)(void *data, unsigned long address, int reliable);
4141
/* On negative return stop dumping */
4242
int (*stack)(void *data, char *name);
4343
walk_stack_t walk_stack;

arch/x86/kernel/cpu/perf_event.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,11 +2180,11 @@ static int backtrace_stack(void *data, char *name)
21802180
return 0;
21812181
}
21822182

2183-
static void backtrace_address(void *data, unsigned long addr, int reliable)
2183+
static int backtrace_address(void *data, unsigned long addr, int reliable)
21842184
{
21852185
struct perf_callchain_entry *entry = data;
21862186

2187-
perf_callchain_store(entry, addr);
2187+
return perf_callchain_store(entry, addr);
21882188
}
21892189

21902190
static const struct stacktrace_ops backtrace_ops = {

arch/x86/kernel/dumpstack.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ print_context_stack_bp(struct thread_info *tinfo,
135135
if (!__kernel_text_address(addr))
136136
break;
137137

138-
ops->address(data, addr, 1);
138+
if (ops->address(data, addr, 1))
139+
break;
139140
frame = frame->next_frame;
140141
ret_addr = &frame->return_address;
141142
print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
@@ -154,10 +155,11 @@ static int print_trace_stack(void *data, char *name)
154155
/*
155156
* Print one address/symbol entries per line.
156157
*/
157-
static void print_trace_address(void *data, unsigned long addr, int reliable)
158+
static int print_trace_address(void *data, unsigned long addr, int reliable)
158159
{
159160
touch_nmi_watchdog();
160161
printk_stack_address(addr, reliable, data);
162+
return 0;
161163
}
162164

163165
static const struct stacktrace_ops print_trace_ops = {

arch/x86/kernel/stacktrace.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,34 @@ static int save_stack_stack(void *data, char *name)
1414
return 0;
1515
}
1616

17-
static void
17+
static int
1818
__save_stack_address(void *data, unsigned long addr, bool reliable, bool nosched)
1919
{
2020
struct stack_trace *trace = data;
2121
#ifdef CONFIG_FRAME_POINTER
2222
if (!reliable)
23-
return;
23+
return 0;
2424
#endif
2525
if (nosched && in_sched_functions(addr))
26-
return;
26+
return 0;
2727
if (trace->skip > 0) {
2828
trace->skip--;
29-
return;
29+
return 0;
3030
}
31-
if (trace->nr_entries < trace->max_entries)
31+
if (trace->nr_entries < trace->max_entries) {
3232
trace->entries[trace->nr_entries++] = addr;
33+
return 0;
34+
} else {
35+
return -1; /* no more room, stop walking the stack */
36+
}
3337
}
3438

35-
static void save_stack_address(void *data, unsigned long addr, int reliable)
39+
static int save_stack_address(void *data, unsigned long addr, int reliable)
3640
{
3741
return __save_stack_address(data, addr, reliable, false);
3842
}
3943

40-
static void
44+
static int
4145
save_stack_address_nosched(void *data, unsigned long addr, int reliable)
4246
{
4347
return __save_stack_address(data, addr, reliable, true);

arch/x86/oprofile/backtrace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ static int backtrace_stack(void *data, char *name)
2323
return 0;
2424
}
2525

26-
static void backtrace_address(void *data, unsigned long addr, int reliable)
26+
static int backtrace_address(void *data, unsigned long addr, int reliable)
2727
{
2828
unsigned int *depth = data;
2929

3030
if ((*depth)--)
3131
oprofile_add_trace(addr);
32+
return 0;
3233
}
3334

3435
static struct stacktrace_ops backtrace_ops = {

include/linux/perf_event.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,11 +964,20 @@ DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry);
964964

965965
extern void perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs);
966966
extern void perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs);
967+
extern struct perf_callchain_entry *
968+
get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
969+
bool crosstask, bool add_mark);
970+
extern int get_callchain_buffers(void);
971+
extern void put_callchain_buffers(void);
967972

968-
static inline void perf_callchain_store(struct perf_callchain_entry *entry, u64 ip)
973+
static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip)
969974
{
970-
if (entry->nr < PERF_MAX_STACK_DEPTH)
975+
if (entry->nr < PERF_MAX_STACK_DEPTH) {
971976
entry->ip[entry->nr++] = ip;
977+
return 0;
978+
} else {
979+
return -1; /* no more room, stop walking the stack */
980+
}
972981
}
973982

974983
extern int sysctl_perf_event_paranoid;

kernel/events/callchain.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,26 +159,36 @@ put_callchain_entry(int rctx)
159159
struct perf_callchain_entry *
160160
perf_callchain(struct perf_event *event, struct pt_regs *regs)
161161
{
162-
int rctx;
163-
struct perf_callchain_entry *entry;
164-
165-
int kernel = !event->attr.exclude_callchain_kernel;
166-
int user = !event->attr.exclude_callchain_user;
162+
bool kernel = !event->attr.exclude_callchain_kernel;
163+
bool user = !event->attr.exclude_callchain_user;
164+
/* Disallow cross-task user callchains. */
165+
bool crosstask = event->ctx->task && event->ctx->task != current;
167166

168167
if (!kernel && !user)
169168
return NULL;
170169

170+
return get_perf_callchain(regs, 0, kernel, user, crosstask, true);
171+
}
172+
173+
struct perf_callchain_entry *
174+
get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
175+
bool crosstask, bool add_mark)
176+
{
177+
struct perf_callchain_entry *entry;
178+
int rctx;
179+
171180
entry = get_callchain_entry(&rctx);
172181
if (rctx == -1)
173182
return NULL;
174183

175184
if (!entry)
176185
goto exit_put;
177186

178-
entry->nr = 0;
187+
entry->nr = init_nr;
179188

180189
if (kernel && !user_mode(regs)) {
181-
perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
190+
if (add_mark)
191+
perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
182192
perf_callchain_kernel(entry, regs);
183193
}
184194

@@ -191,13 +201,11 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
191201
}
192202

193203
if (regs) {
194-
/*
195-
* Disallow cross-task user callchains.
196-
*/
197-
if (event->ctx->task && event->ctx->task != current)
204+
if (crosstask)
198205
goto exit_put;
199206

200-
perf_callchain_store(entry, PERF_CONTEXT_USER);
207+
if (add_mark)
208+
perf_callchain_store(entry, PERF_CONTEXT_USER);
201209
perf_callchain_user(entry, regs);
202210
}
203211
}

kernel/events/internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,6 @@ DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user)
182182
/* Callchain handling */
183183
extern struct perf_callchain_entry *
184184
perf_callchain(struct perf_event *event, struct pt_regs *regs);
185-
extern int get_callchain_buffers(void);
186-
extern void put_callchain_buffers(void);
187185

188186
static inline int get_recursion_context(int *recursion)
189187
{

0 commit comments

Comments
 (0)