aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-03-08 21:02:34 -0500
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:35:55 -0400
commit09ae72348eccb60e304cf8ce94653f4a78fcd407 (patch)
tree28c48644f71df4752556d9f5b15efb889e57af56
parent153e8ed913b022d2003866a848af9fadc041403f (diff)
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 <tglx@linutronix.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/kernel.h41
-rw-r--r--kernel/trace/trace.c76
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_entries.h23
-rw-r--r--kernel/trace/trace_output.c75
-rw-r--r--kernel/trace/trace_output.h2
6 files changed, 214 insertions, 5 deletions
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index bc5392a326ab..a3a5574a61fc 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -514,7 +514,8 @@ do { \
514 * 514 *
515 * This is intended as a debugging tool for the developer only. 515 * This is intended as a debugging tool for the developer only.
516 * Please refrain from leaving trace_printks scattered around in 516 * 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)
518 */ 519 */
519 520
520#define trace_printk(fmt, args...) \ 521#define trace_printk(fmt, args...) \
@@ -537,6 +538,44 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...);
537extern __printf(2, 3) 538extern __printf(2, 3)
538int __trace_printk(unsigned long ip, const char *fmt, ...); 539int __trace_printk(unsigned long ip, const char *fmt, ...);
539 540
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
566extern int __trace_bputs(unsigned long ip, const char *str);
567extern 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
540extern void trace_dump_stack(void); 579extern void trace_dump_stack(void);
541 580
542/* 581/*
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4021a5e66412..5043a0c4dde0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -350,6 +350,77 @@ void tracing_on(void)
350} 350}
351EXPORT_SYMBOL_GPL(tracing_on); 351EXPORT_SYMBOL_GPL(tracing_on);
352 352
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 */
359int __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}
392EXPORT_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 */
399int __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}
422EXPORT_SYMBOL_GPL(__trace_bputs);
423
353#ifdef CONFIG_TRACER_SNAPSHOT 424#ifdef CONFIG_TRACER_SNAPSHOT
354/** 425/**
355 * trace_snapshot - take a snapshot of the current buffer. 426 * trace_snapshot - take a snapshot of the current buffer.
@@ -2475,6 +2546,11 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
2475 return ret; 2546 return ret;
2476 } 2547 }
2477 2548
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
2478 if (iter->ent->type == TRACE_BPRINT && 2554 if (iter->ent->type == TRACE_BPRINT &&
2479 trace_flags & TRACE_ITER_PRINTK && 2555 trace_flags & TRACE_ITER_PRINTK &&
2480 trace_flags & TRACE_ITER_PRINTK_MSGONLY) 2556 trace_flags & TRACE_ITER_PRINTK_MSGONLY)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 26bc71834041..d5764a8532e2 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -34,6 +34,7 @@ enum trace_type {
34 TRACE_GRAPH_ENT, 34 TRACE_GRAPH_ENT,
35 TRACE_USER_STACK, 35 TRACE_USER_STACK,
36 TRACE_BLK, 36 TRACE_BLK,
37 TRACE_BPUTS,
37 38
38 __TRACE_LAST_TYPE, 39 __TRACE_LAST_TYPE,
39}; 40};
@@ -277,6 +278,7 @@ extern void __ftrace_bad_type(void);
277 IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\ 278 IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
278 IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \ 279 IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \
279 IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \ 280 IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \
281 IF_ASSIGN(var, ent, struct bputs_entry, TRACE_BPUTS); \
280 IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \ 282 IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \
281 TRACE_MMIO_RW); \ 283 TRACE_MMIO_RW); \
282 IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \ 284 IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index 4108e1250ca2..e2d027ac66a2 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -223,8 +223,8 @@ FTRACE_ENTRY(bprint, bprint_entry,
223 __dynamic_array( u32, buf ) 223 __dynamic_array( u32, buf )
224 ), 224 ),
225 225
226 F_printk("%08lx fmt:%p", 226 F_printk("%pf: %s",
227 __entry->ip, __entry->fmt), 227 (void *)__entry->ip, __entry->fmt),
228 228
229 FILTER_OTHER 229 FILTER_OTHER
230); 230);
@@ -238,8 +238,23 @@ FTRACE_ENTRY(print, print_entry,
238 __dynamic_array( char, buf ) 238 __dynamic_array( char, buf )
239 ), 239 ),
240 240
241 F_printk("%08lx %s", 241 F_printk("%pf: %s",
242 __entry->ip, __entry->buf), 242 (void *)__entry->ip, __entry->buf),
243
244 FILTER_OTHER
245);
246
247FTRACE_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),
243 258
244 FILTER_OTHER 259 FILTER_OTHER
245); 260);
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 2edc7220d017..19f48e7edc39 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -37,6 +37,22 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)
37 return ret; 37 return ret;
38} 38}
39 39
40enum 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
40enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) 56enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
41{ 57{
42 struct trace_seq *s = &iter->seq; 58 struct trace_seq *s = &iter->seq;
@@ -1244,6 +1260,64 @@ static struct trace_event trace_user_stack_event = {
1244 .funcs = &trace_user_stack_funcs, 1260 .funcs = &trace_user_stack_funcs,
1245}; 1261};
1246 1262
1263/* TRACE_BPUTS */
1264static enum print_line_t
1265trace_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
1290static enum print_line_t
1291trace_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
1311static struct trace_event_functions trace_bputs_funcs = {
1312 .trace = trace_bputs_print,
1313 .raw = trace_bputs_raw,
1314};
1315
1316static struct trace_event trace_bputs_event = {
1317 .type = TRACE_BPUTS,
1318 .funcs = &trace_bputs_funcs,
1319};
1320
1247/* TRACE_BPRINT */ 1321/* TRACE_BPRINT */
1248static enum print_line_t 1322static enum print_line_t
1249trace_bprint_print(struct trace_iterator *iter, int flags, 1323trace_bprint_print(struct trace_iterator *iter, int flags,
@@ -1356,6 +1430,7 @@ static struct trace_event *events[] __initdata = {
1356 &trace_wake_event, 1430 &trace_wake_event,
1357 &trace_stack_event, 1431 &trace_stack_event,
1358 &trace_user_stack_event, 1432 &trace_user_stack_event,
1433 &trace_bputs_event,
1359 &trace_bprint_event, 1434 &trace_bprint_event,
1360 &trace_print_event, 1435 &trace_print_event,
1361 NULL 1436 NULL
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
index c038eba0492b..af77870de278 100644
--- a/kernel/trace/trace_output.h
+++ b/kernel/trace/trace_output.h
@@ -5,6 +5,8 @@
5#include "trace.h" 5#include "trace.h"
6 6
7extern enum print_line_t 7extern enum print_line_t
8trace_print_bputs_msg_only(struct trace_iterator *iter);
9extern enum print_line_t
8trace_print_bprintk_msg_only(struct trace_iterator *iter); 10trace_print_bprintk_msg_only(struct trace_iterator *iter);
9extern enum print_line_t 11extern enum print_line_t
10trace_print_printk_msg_only(struct trace_iterator *iter); 12trace_print_printk_msg_only(struct trace_iterator *iter);