Skip to content

Commit 09ae723

Browse files
committed
tracing: Add trace_puts() for even faster trace_printk() tracing
The trace_printk() is extremely fast and is very handy as it can be used in any context (including NMIs!). But it still requires scanning the fmt string for parsing the args. Even the trace_bprintk() requires a scan to know what args will be saved, although it doesn't copy the format string itself. Several times trace_printk() has no args, and wastes cpu cycles scanning the fmt string. Adding trace_puts() allows the developer to use an even faster tracing method that only saves the pointer to the string in the ring buffer without doing any format parsing at all. This will help remove even more of the "Heisenbug" effect, when debugging. Also fixed up the F_printk()s for the ftrace internal bprint and print events. Cc: Thomas Gleixner <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Frederic Weisbecker <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent 153e8ed commit 09ae723

File tree

6 files changed

+214
-5
lines changed

6 files changed

+214
-5
lines changed

include/linux/kernel.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,8 @@ do { \
514514
*
515515
* This is intended as a debugging tool for the developer only.
516516
* Please refrain from leaving trace_printks scattered around in
517-
* your code.
517+
* your code. (Extra memory is used for special buffers that are
518+
* allocated when trace_printk() is used)
518519
*/
519520

520521
#define trace_printk(fmt, args...) \
@@ -537,6 +538,44 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...);
537538
extern __printf(2, 3)
538539
int __trace_printk(unsigned long ip, const char *fmt, ...);
539540

541+
/**
542+
* trace_puts - write a string into the ftrace buffer
543+
* @str: the string to record
544+
*
545+
* Note: __trace_bputs is an internal function for trace_puts and
546+
* the @ip is passed in via the trace_puts macro.
547+
*
548+
* This is similar to trace_printk() but is made for those really fast
549+
* paths that a developer wants the least amount of "Heisenbug" affects,
550+
* where the processing of the print format is still too much.
551+
*
552+
* This function allows a kernel developer to debug fast path sections
553+
* that printk is not appropriate for. By scattering in various
554+
* printk like tracing in the code, a developer can quickly see
555+
* where problems are occurring.
556+
*
557+
* This is intended as a debugging tool for the developer only.
558+
* Please refrain from leaving trace_puts scattered around in
559+
* your code. (Extra memory is used for special buffers that are
560+
* allocated when trace_puts() is used)
561+
*
562+
* Returns: 0 if nothing was written, positive # if string was.
563+
* (1 when __trace_bputs is used, strlen(str) when __trace_puts is used)
564+
*/
565+
566+
extern int __trace_bputs(unsigned long ip, const char *str);
567+
extern int __trace_puts(unsigned long ip, const char *str, int size);
568+
#define trace_puts(str) ({ \
569+
static const char *trace_printk_fmt \
570+
__attribute__((section("__trace_printk_fmt"))) = \
571+
__builtin_constant_p(str) ? str : NULL; \
572+
\
573+
if (__builtin_constant_p(str)) \
574+
__trace_bputs(_THIS_IP_, trace_printk_fmt); \
575+
else \
576+
__trace_puts(_THIS_IP_, str, strlen(str)); \
577+
})
578+
540579
extern void trace_dump_stack(void);
541580

542581
/*

kernel/trace/trace.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,77 @@ void tracing_on(void)
350350
}
351351
EXPORT_SYMBOL_GPL(tracing_on);
352352

353+
/**
354+
* __trace_puts - write a constant string into the trace buffer.
355+
* @ip: The address of the caller
356+
* @str: The constant string to write
357+
* @size: The size of the string.
358+
*/
359+
int __trace_puts(unsigned long ip, const char *str, int size)
360+
{
361+
struct ring_buffer_event *event;
362+
struct ring_buffer *buffer;
363+
struct print_entry *entry;
364+
unsigned long irq_flags;
365+
int alloc;
366+
367+
alloc = sizeof(*entry) + size + 2; /* possible \n added */
368+
369+
local_save_flags(irq_flags);
370+
buffer = global_trace.trace_buffer.buffer;
371+
event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,
372+
irq_flags, preempt_count());
373+
if (!event)
374+
return 0;
375+
376+
entry = ring_buffer_event_data(event);
377+
entry->ip = ip;
378+
379+
memcpy(&entry->buf, str, size);
380+
381+
/* Add a newline if necessary */
382+
if (entry->buf[size - 1] != '\n') {
383+
entry->buf[size] = '\n';
384+
entry->buf[size + 1] = '\0';
385+
} else
386+
entry->buf[size] = '\0';
387+
388+
__buffer_unlock_commit(buffer, event);
389+
390+
return size;
391+
}
392+
EXPORT_SYMBOL_GPL(__trace_puts);
393+
394+
/**
395+
* __trace_bputs - write the pointer to a constant string into trace buffer
396+
* @ip: The address of the caller
397+
* @str: The constant string to write to the buffer to
398+
*/
399+
int __trace_bputs(unsigned long ip, const char *str)
400+
{
401+
struct ring_buffer_event *event;
402+
struct ring_buffer *buffer;
403+
struct bputs_entry *entry;
404+
unsigned long irq_flags;
405+
int size = sizeof(struct bputs_entry);
406+
407+
local_save_flags(irq_flags);
408+
buffer = global_trace.trace_buffer.buffer;
409+
event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
410+
irq_flags, preempt_count());
411+
if (!event)
412+
return 0;
413+
414+
entry = ring_buffer_event_data(event);
415+
entry->ip = ip;
416+
entry->str = str;
417+
418+
__buffer_unlock_commit(buffer, event);
419+
420+
return 1;
421+
}
422+
EXPORT_SYMBOL_GPL(__trace_bputs);
423+
353424
#ifdef CONFIG_TRACER_SNAPSHOT
354425
/**
355426
* trace_snapshot - take a snapshot of the current buffer.
@@ -2475,6 +2546,11 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
24752546
return ret;
24762547
}
24772548

2549+
if (iter->ent->type == TRACE_BPUTS &&
2550+
trace_flags & TRACE_ITER_PRINTK &&
2551+
trace_flags & TRACE_ITER_PRINTK_MSGONLY)
2552+
return trace_print_bputs_msg_only(iter);
2553+
24782554
if (iter->ent->type == TRACE_BPRINT &&
24792555
trace_flags & TRACE_ITER_PRINTK &&
24802556
trace_flags & TRACE_ITER_PRINTK_MSGONLY)

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum trace_type {
3434
TRACE_GRAPH_ENT,
3535
TRACE_USER_STACK,
3636
TRACE_BLK,
37+
TRACE_BPUTS,
3738

3839
__TRACE_LAST_TYPE,
3940
};
@@ -277,6 +278,7 @@ extern void __ftrace_bad_type(void);
277278
IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
278279
IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \
279280
IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \
281+
IF_ASSIGN(var, ent, struct bputs_entry, TRACE_BPUTS); \
280282
IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \
281283
TRACE_MMIO_RW); \
282284
IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \

kernel/trace/trace_entries.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ FTRACE_ENTRY(bprint, bprint_entry,
223223
__dynamic_array( u32, buf )
224224
),
225225

226-
F_printk("%08lx fmt:%p",
227-
__entry->ip, __entry->fmt),
226+
F_printk("%pf: %s",
227+
(void *)__entry->ip, __entry->fmt),
228228

229229
FILTER_OTHER
230230
);
@@ -238,8 +238,23 @@ FTRACE_ENTRY(print, print_entry,
238238
__dynamic_array( char, buf )
239239
),
240240

241-
F_printk("%08lx %s",
242-
__entry->ip, __entry->buf),
241+
F_printk("%pf: %s",
242+
(void *)__entry->ip, __entry->buf),
243+
244+
FILTER_OTHER
245+
);
246+
247+
FTRACE_ENTRY(bputs, bputs_entry,
248+
249+
TRACE_BPUTS,
250+
251+
F_STRUCT(
252+
__field( unsigned long, ip )
253+
__field( const char *, str )
254+
),
255+
256+
F_printk("%pf: %s",
257+
(void *)__entry->ip, __entry->str),
243258

244259
FILTER_OTHER
245260
);

kernel/trace/trace_output.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)
3737
return ret;
3838
}
3939

40+
enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter)
41+
{
42+
struct trace_seq *s = &iter->seq;
43+
struct trace_entry *entry = iter->ent;
44+
struct bputs_entry *field;
45+
int ret;
46+
47+
trace_assign_type(field, entry);
48+
49+
ret = trace_seq_puts(s, field->str);
50+
if (!ret)
51+
return TRACE_TYPE_PARTIAL_LINE;
52+
53+
return TRACE_TYPE_HANDLED;
54+
}
55+
4056
enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
4157
{
4258
struct trace_seq *s = &iter->seq;
@@ -1244,6 +1260,64 @@ static struct trace_event trace_user_stack_event = {
12441260
.funcs = &trace_user_stack_funcs,
12451261
};
12461262

1263+
/* TRACE_BPUTS */
1264+
static enum print_line_t
1265+
trace_bputs_print(struct trace_iterator *iter, int flags,
1266+
struct trace_event *event)
1267+
{
1268+
struct trace_entry *entry = iter->ent;
1269+
struct trace_seq *s = &iter->seq;
1270+
struct bputs_entry *field;
1271+
1272+
trace_assign_type(field, entry);
1273+
1274+
if (!seq_print_ip_sym(s, field->ip, flags))
1275+
goto partial;
1276+
1277+
if (!trace_seq_puts(s, ": "))
1278+
goto partial;
1279+
1280+
if (!trace_seq_puts(s, field->str))
1281+
goto partial;
1282+
1283+
return TRACE_TYPE_HANDLED;
1284+
1285+
partial:
1286+
return TRACE_TYPE_PARTIAL_LINE;
1287+
}
1288+
1289+
1290+
static enum print_line_t
1291+
trace_bputs_raw(struct trace_iterator *iter, int flags,
1292+
struct trace_event *event)
1293+
{
1294+
struct bputs_entry *field;
1295+
struct trace_seq *s = &iter->seq;
1296+
1297+
trace_assign_type(field, iter->ent);
1298+
1299+
if (!trace_seq_printf(s, ": %lx : ", field->ip))
1300+
goto partial;
1301+
1302+
if (!trace_seq_puts(s, field->str))
1303+
goto partial;
1304+
1305+
return TRACE_TYPE_HANDLED;
1306+
1307+
partial:
1308+
return TRACE_TYPE_PARTIAL_LINE;
1309+
}
1310+
1311+
static struct trace_event_functions trace_bputs_funcs = {
1312+
.trace = trace_bputs_print,
1313+
.raw = trace_bputs_raw,
1314+
};
1315+
1316+
static struct trace_event trace_bputs_event = {
1317+
.type = TRACE_BPUTS,
1318+
.funcs = &trace_bputs_funcs,
1319+
};
1320+
12471321
/* TRACE_BPRINT */
12481322
static enum print_line_t
12491323
trace_bprint_print(struct trace_iterator *iter, int flags,
@@ -1356,6 +1430,7 @@ static struct trace_event *events[] __initdata = {
13561430
&trace_wake_event,
13571431
&trace_stack_event,
13581432
&trace_user_stack_event,
1433+
&trace_bputs_event,
13591434
&trace_bprint_event,
13601435
&trace_print_event,
13611436
NULL

kernel/trace/trace_output.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <linux/trace_seq.h>
55
#include "trace.h"
66

7+
extern enum print_line_t
8+
trace_print_bputs_msg_only(struct trace_iterator *iter);
79
extern enum print_line_t
810
trace_print_bprintk_msg_only(struct trace_iterator *iter);
911
extern enum print_line_t

0 commit comments

Comments
 (0)