blob: 962cdb24ed817b380a4ea753e4f7f501b937b4cb [file] [log] [blame]
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001/*
2 *
3 * Function graph tracer.
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08004 * Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01005 * Mostly borrowed from function tracer which
6 * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
7 *
8 */
9#include <linux/debugfs.h>
10#include <linux/uaccess.h>
11#include <linux/ftrace.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010013#include <linux/fs.h>
14
15#include "trace.h"
Steven Rostedtf0868d12008-12-23 23:24:12 -050016#include "trace_output.h"
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010017
Steven Rostedtb304d042010-09-14 18:58:33 -040018/* When set, irq functions will be ignored */
19static int ftrace_graph_skip_irqs;
20
Jiri Olsabe1eca32009-11-24 13:57:38 +010021struct fgraph_cpu_data {
Steven Rostedt2fbcdb32009-03-19 13:24:42 -040022 pid_t last_pid;
23 int depth;
Jiri Olsa2bd162122010-09-07 16:53:44 +020024 int depth_irq;
Jiri Olsabe1eca32009-11-24 13:57:38 +010025 int ignore;
Steven Rostedtf1c7f512010-02-26 17:08:16 -050026 unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH];
Jiri Olsabe1eca32009-11-24 13:57:38 +010027};
28
29struct fgraph_data {
Namhyung Kim6016ee12010-08-11 12:47:59 +090030 struct fgraph_cpu_data __percpu *cpu_data;
Jiri Olsabe1eca32009-11-24 13:57:38 +010031
32 /* Place to preserve last processed entry. */
33 struct ftrace_graph_ent_entry ent;
34 struct ftrace_graph_ret_entry ret;
35 int failed;
36 int cpu;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -040037};
38
Frederic Weisbecker287b6e62008-11-26 00:57:25 +010039#define TRACE_GRAPH_INDENT 2
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010040
Frederic Weisbecker1a056152008-11-28 00:42:46 +010041/* Flag options */
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010042#define TRACE_GRAPH_PRINT_OVERRUN 0x1
Frederic Weisbecker1a056152008-11-28 00:42:46 +010043#define TRACE_GRAPH_PRINT_CPU 0x2
44#define TRACE_GRAPH_PRINT_OVERHEAD 0x4
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +010045#define TRACE_GRAPH_PRINT_PROC 0x8
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -080046#define TRACE_GRAPH_PRINT_DURATION 0x10
Jiri Olsa9106b692010-04-02 19:01:20 +020047#define TRACE_GRAPH_PRINT_ABS_TIME 0x20
Jiri Olsa2bd162122010-09-07 16:53:44 +020048#define TRACE_GRAPH_PRINT_IRQS 0x40
Frederic Weisbecker1a056152008-11-28 00:42:46 +010049
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010050static struct tracer_opt trace_opts[] = {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -080051 /* Display overruns? (for self-debug purpose) */
Frederic Weisbecker1a056152008-11-28 00:42:46 +010052 { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
53 /* Display CPU ? */
54 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
55 /* Display Overhead ? */
56 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +010057 /* Display proc name/pid */
58 { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -080059 /* Display duration of execution */
60 { TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) },
61 /* Display absolute time of an entry */
62 { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) },
Jiri Olsa2bd162122010-09-07 16:53:44 +020063 /* Display interrupts */
64 { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010065 { } /* Empty entry */
66};
67
68static struct tracer_flags tracer_flags = {
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +010069 /* Don't display overruns and proc by default */
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -080070 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD |
Jiri Olsa2bd162122010-09-07 16:53:44 +020071 TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS,
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010072 .opts = trace_opts
73};
74
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +020075static struct trace_array *graph_array;
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -080076
Frederic Weisbeckerfb526072008-11-25 21:07:04 +010077
Steven Rostedt712406a2009-02-09 10:54:03 -080078/* Add a function return address to the trace stack on thread info.*/
79int
Steven Rostedt71e308a2009-06-18 12:45:08 -040080ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
81 unsigned long frame_pointer)
Steven Rostedt712406a2009-02-09 10:54:03 -080082{
Steven Rostedt5d1a03d2009-03-23 23:38:49 -040083 unsigned long long calltime;
Steven Rostedt712406a2009-02-09 10:54:03 -080084 int index;
85
86 if (!current->ret_stack)
87 return -EBUSY;
88
Steven Rostedt82310a32009-06-02 12:26:07 -040089 /*
90 * We must make sure the ret_stack is tested before we read
91 * anything else.
92 */
93 smp_rmb();
94
Steven Rostedt712406a2009-02-09 10:54:03 -080095 /* The return trace stack is full */
96 if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
97 atomic_inc(&current->trace_overrun);
98 return -EBUSY;
99 }
100
Steven Rostedt5d1a03d2009-03-23 23:38:49 -0400101 calltime = trace_clock_local();
102
Steven Rostedt712406a2009-02-09 10:54:03 -0800103 index = ++current->curr_ret_stack;
104 barrier();
105 current->ret_stack[index].ret = ret;
106 current->ret_stack[index].func = func;
Steven Rostedt5d1a03d2009-03-23 23:38:49 -0400107 current->ret_stack[index].calltime = calltime;
Steven Rostedta2a16d62009-03-24 23:17:58 -0400108 current->ret_stack[index].subtime = 0;
Steven Rostedt71e308a2009-06-18 12:45:08 -0400109 current->ret_stack[index].fp = frame_pointer;
Steven Rostedt712406a2009-02-09 10:54:03 -0800110 *depth = index;
111
112 return 0;
113}
114
115/* Retrieve a function return address to the trace stack on thread info.*/
Steven Rostedta2a16d62009-03-24 23:17:58 -0400116static void
Steven Rostedt71e308a2009-06-18 12:45:08 -0400117ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,
118 unsigned long frame_pointer)
Steven Rostedt712406a2009-02-09 10:54:03 -0800119{
120 int index;
121
122 index = current->curr_ret_stack;
123
124 if (unlikely(index < 0)) {
125 ftrace_graph_stop();
126 WARN_ON(1);
127 /* Might as well panic, otherwise we have no where to go */
128 *ret = (unsigned long)panic;
129 return;
130 }
131
Steven Rostedt71e308a2009-06-18 12:45:08 -0400132#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
133 /*
134 * The arch may choose to record the frame pointer used
135 * and check it here to make sure that it is what we expect it
136 * to be. If gcc does not set the place holder of the return
137 * address in the frame pointer, and does a copy instead, then
138 * the function graph trace will fail. This test detects this
139 * case.
140 *
141 * Currently, x86_32 with optimize for size (-Os) makes the latest
142 * gcc do the above.
143 */
144 if (unlikely(current->ret_stack[index].fp != frame_pointer)) {
145 ftrace_graph_stop();
146 WARN(1, "Bad frame pointer: expected %lx, received %lx\n"
Steven Rostedtb375a112009-09-17 00:05:58 -0400147 " from func %ps return to %lx\n",
Steven Rostedt71e308a2009-06-18 12:45:08 -0400148 current->ret_stack[index].fp,
149 frame_pointer,
150 (void *)current->ret_stack[index].func,
151 current->ret_stack[index].ret);
152 *ret = (unsigned long)panic;
153 return;
154 }
155#endif
156
Steven Rostedt712406a2009-02-09 10:54:03 -0800157 *ret = current->ret_stack[index].ret;
158 trace->func = current->ret_stack[index].func;
159 trace->calltime = current->ret_stack[index].calltime;
160 trace->overrun = atomic_read(&current->trace_overrun);
161 trace->depth = index;
Steven Rostedt712406a2009-02-09 10:54:03 -0800162}
163
164/*
165 * Send the trace to the ring-buffer.
166 * @return the original return address.
167 */
Steven Rostedt71e308a2009-06-18 12:45:08 -0400168unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
Steven Rostedt712406a2009-02-09 10:54:03 -0800169{
170 struct ftrace_graph_ret trace;
171 unsigned long ret;
172
Steven Rostedt71e308a2009-06-18 12:45:08 -0400173 ftrace_pop_return_trace(&trace, &ret, frame_pointer);
Frederic Weisbecker00126932009-03-05 01:49:22 +0100174 trace.rettime = trace_clock_local();
Steven Rostedt712406a2009-02-09 10:54:03 -0800175 ftrace_graph_return(&trace);
Steven Rostedta2a16d62009-03-24 23:17:58 -0400176 barrier();
177 current->curr_ret_stack--;
Steven Rostedt712406a2009-02-09 10:54:03 -0800178
179 if (unlikely(!ret)) {
180 ftrace_graph_stop();
181 WARN_ON(1);
182 /* Might as well panic. What else to do? */
183 ret = (unsigned long)panic;
184 }
185
186 return ret;
187}
188
Jiri Olsa62b915f2010-04-02 19:01:22 +0200189int __trace_graph_entry(struct trace_array *tr,
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200190 struct ftrace_graph_ent *trace,
191 unsigned long flags,
192 int pc)
193{
194 struct ftrace_event_call *call = &event_funcgraph_entry;
195 struct ring_buffer_event *event;
Steven Rostedte77405a2009-09-02 14:17:06 -0400196 struct ring_buffer *buffer = tr->buffer;
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200197 struct ftrace_graph_ent_entry *entry;
198
Rusty Russelldd17c8f2009-10-29 22:34:15 +0900199 if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200200 return 0;
201
Steven Rostedte77405a2009-09-02 14:17:06 -0400202 event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200203 sizeof(*entry), flags, pc);
204 if (!event)
205 return 0;
206 entry = ring_buffer_event_data(event);
207 entry->graph_ent = *trace;
Steven Rostedte77405a2009-09-02 14:17:06 -0400208 if (!filter_current_check_discard(buffer, call, entry, event))
209 ring_buffer_unlock_commit(buffer, event);
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200210
211 return 1;
212}
213
Steven Rostedtb304d042010-09-14 18:58:33 -0400214static inline int ftrace_graph_ignore_irqs(void)
215{
216 if (!ftrace_graph_skip_irqs)
217 return 0;
218
219 return in_irq();
220}
221
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200222int trace_graph_entry(struct ftrace_graph_ent *trace)
223{
224 struct trace_array *tr = graph_array;
225 struct trace_array_cpu *data;
226 unsigned long flags;
227 long disabled;
228 int ret;
229 int cpu;
230 int pc;
231
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200232 if (!ftrace_trace_task(current))
233 return 0;
234
Lai Jiangshanea2c68a2010-01-13 19:38:30 +0800235 /* trace it when it is-nested-in or is a function enabled. */
Steven Rostedtb304d042010-09-14 18:58:33 -0400236 if (!(trace->depth || ftrace_graph_addr(trace->func)) ||
237 ftrace_graph_ignore_irqs())
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200238 return 0;
239
240 local_irq_save(flags);
241 cpu = raw_smp_processor_id();
242 data = tr->data[cpu];
243 disabled = atomic_inc_return(&data->disabled);
244 if (likely(disabled == 1)) {
245 pc = preempt_count();
246 ret = __trace_graph_entry(tr, trace, flags, pc);
247 } else {
248 ret = 0;
249 }
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200250
251 atomic_dec(&data->disabled);
252 local_irq_restore(flags);
253
254 return ret;
255}
256
Tim Bird0e950172010-02-25 15:36:43 -0800257int trace_graph_thresh_entry(struct ftrace_graph_ent *trace)
258{
259 if (tracing_thresh)
260 return 1;
261 else
262 return trace_graph_entry(trace);
263}
264
Jiri Olsa0a772622010-09-23 14:00:52 +0200265static void
266__trace_graph_function(struct trace_array *tr,
267 unsigned long ip, unsigned long flags, int pc)
268{
269 u64 time = trace_clock_local();
270 struct ftrace_graph_ent ent = {
271 .func = ip,
272 .depth = 0,
273 };
274 struct ftrace_graph_ret ret = {
275 .func = ip,
276 .depth = 0,
277 .calltime = time,
278 .rettime = time,
279 };
280
281 __trace_graph_entry(tr, &ent, flags, pc);
282 __trace_graph_return(tr, &ret, flags, pc);
283}
284
285void
286trace_graph_function(struct trace_array *tr,
287 unsigned long ip, unsigned long parent_ip,
288 unsigned long flags, int pc)
289{
Jiri Olsa0a772622010-09-23 14:00:52 +0200290 __trace_graph_function(tr, ip, flags, pc);
291}
292
Jiri Olsa62b915f2010-04-02 19:01:22 +0200293void __trace_graph_return(struct trace_array *tr,
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200294 struct ftrace_graph_ret *trace,
295 unsigned long flags,
296 int pc)
297{
298 struct ftrace_event_call *call = &event_funcgraph_exit;
299 struct ring_buffer_event *event;
Steven Rostedte77405a2009-09-02 14:17:06 -0400300 struct ring_buffer *buffer = tr->buffer;
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200301 struct ftrace_graph_ret_entry *entry;
302
Rusty Russelldd17c8f2009-10-29 22:34:15 +0900303 if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200304 return;
305
Steven Rostedte77405a2009-09-02 14:17:06 -0400306 event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET,
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200307 sizeof(*entry), flags, pc);
308 if (!event)
309 return;
310 entry = ring_buffer_event_data(event);
311 entry->ret = *trace;
Steven Rostedte77405a2009-09-02 14:17:06 -0400312 if (!filter_current_check_discard(buffer, call, entry, event))
313 ring_buffer_unlock_commit(buffer, event);
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200314}
315
316void trace_graph_return(struct ftrace_graph_ret *trace)
317{
318 struct trace_array *tr = graph_array;
319 struct trace_array_cpu *data;
320 unsigned long flags;
321 long disabled;
322 int cpu;
323 int pc;
324
325 local_irq_save(flags);
326 cpu = raw_smp_processor_id();
327 data = tr->data[cpu];
328 disabled = atomic_inc_return(&data->disabled);
329 if (likely(disabled == 1)) {
330 pc = preempt_count();
331 __trace_graph_return(tr, trace, flags, pc);
332 }
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200333 atomic_dec(&data->disabled);
334 local_irq_restore(flags);
335}
336
Frederic Weisbecker24a53652010-01-14 08:23:15 +0100337void set_graph_array(struct trace_array *tr)
338{
339 graph_array = tr;
340
341 /* Make graph_array visible before we start tracing */
342
343 smp_mb();
344}
345
Tim Bird0e950172010-02-25 15:36:43 -0800346void trace_graph_thresh_return(struct ftrace_graph_ret *trace)
347{
348 if (tracing_thresh &&
349 (trace->rettime - trace->calltime < tracing_thresh))
350 return;
351 else
352 trace_graph_return(trace);
353}
354
Frederic Weisbeckerfb526072008-11-25 21:07:04 +0100355static int graph_trace_init(struct trace_array *tr)
356{
Frederic Weisbecker1a0799a2009-07-29 18:59:58 +0200357 int ret;
358
Frederic Weisbecker24a53652010-01-14 08:23:15 +0100359 set_graph_array(tr);
Tim Bird0e950172010-02-25 15:36:43 -0800360 if (tracing_thresh)
361 ret = register_ftrace_graph(&trace_graph_thresh_return,
362 &trace_graph_thresh_entry);
363 else
364 ret = register_ftrace_graph(&trace_graph_return,
365 &trace_graph_entry);
Steven Rostedt660c7f92008-11-26 00:16:26 -0500366 if (ret)
367 return ret;
368 tracing_start_cmdline_record();
369
370 return 0;
Frederic Weisbeckerfb526072008-11-25 21:07:04 +0100371}
372
373static void graph_trace_reset(struct trace_array *tr)
374{
Steven Rostedt660c7f92008-11-26 00:16:26 -0500375 tracing_stop_cmdline_record();
376 unregister_ftrace_graph();
Frederic Weisbeckerfb526072008-11-25 21:07:04 +0100377}
378
Lai Jiangshan0c9e6f62009-07-28 20:26:06 +0800379static int max_bytes_for_cpu;
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100380
381static enum print_line_t
382print_graph_cpu(struct trace_seq *s, int cpu)
383{
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100384 int ret;
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100385
Ingo Molnard51090b2008-11-28 09:55:16 +0100386 /*
387 * Start with a space character - to make it stand out
388 * to the right a bit when trace output is pasted into
389 * email:
390 */
Lai Jiangshan0c9e6f62009-07-28 20:26:06 +0800391 ret = trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu);
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100392 if (!ret)
Ingo Molnard51090b2008-11-28 09:55:16 +0100393 return TRACE_TYPE_PARTIAL_LINE;
394
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100395 return TRACE_TYPE_HANDLED;
396}
397
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100398#define TRACE_GRAPH_PROCINFO_LENGTH 14
399
400static enum print_line_t
401print_graph_proc(struct trace_seq *s, pid_t pid)
402{
Steven Rostedt4ca530852009-03-16 19:20:15 -0400403 char comm[TASK_COMM_LEN];
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100404 /* sign + log10(MAX_INT) + '\0' */
405 char pid_str[11];
Steven Rostedt4ca530852009-03-16 19:20:15 -0400406 int spaces = 0;
407 int ret;
408 int len;
409 int i;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100410
Steven Rostedt4ca530852009-03-16 19:20:15 -0400411 trace_find_cmdline(pid, comm);
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100412 comm[7] = '\0';
413 sprintf(pid_str, "%d", pid);
414
415 /* 1 stands for the "-" character */
416 len = strlen(comm) + strlen(pid_str) + 1;
417
418 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
419 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
420
421 /* First spaces to align center */
422 for (i = 0; i < spaces / 2; i++) {
423 ret = trace_seq_printf(s, " ");
424 if (!ret)
425 return TRACE_TYPE_PARTIAL_LINE;
426 }
427
428 ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
429 if (!ret)
430 return TRACE_TYPE_PARTIAL_LINE;
431
432 /* Last spaces to align center */
433 for (i = 0; i < spaces - (spaces / 2); i++) {
434 ret = trace_seq_printf(s, " ");
435 if (!ret)
436 return TRACE_TYPE_PARTIAL_LINE;
437 }
438 return TRACE_TYPE_HANDLED;
439}
440
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100441
Steven Rostedt49ff5902009-09-11 00:30:26 -0400442static enum print_line_t
443print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
444{
Steven Rostedtf81c9722009-09-11 14:24:13 -0400445 if (!trace_seq_putc(s, ' '))
Steven Rostedt49ff5902009-09-11 00:30:26 -0400446 return 0;
447
Steven Rostedtf81c9722009-09-11 14:24:13 -0400448 return trace_print_lat_fmt(s, entry);
Steven Rostedt49ff5902009-09-11 00:30:26 -0400449}
450
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100451/* If the pid changed since the last trace, output this event */
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100452static enum print_line_t
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400453verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100454{
Ingo Molnard51090b2008-11-28 09:55:16 +0100455 pid_t prev_pid;
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800456 pid_t *last_pid;
Ingo Molnard51090b2008-11-28 09:55:16 +0100457 int ret;
Steven Rostedt660c7f92008-11-26 00:16:26 -0500458
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400459 if (!data)
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100460 return TRACE_TYPE_HANDLED;
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100461
Jiri Olsabe1eca32009-11-24 13:57:38 +0100462 last_pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
Steven Rostedt660c7f92008-11-26 00:16:26 -0500463
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800464 if (*last_pid == pid)
465 return TRACE_TYPE_HANDLED;
466
467 prev_pid = *last_pid;
468 *last_pid = pid;
469
470 if (prev_pid == -1)
471 return TRACE_TYPE_HANDLED;
Ingo Molnard51090b2008-11-28 09:55:16 +0100472/*
473 * Context-switch trace line:
474
475 ------------------------------------------
476 | 1) migration/0--1 => sshd-1755
477 ------------------------------------------
478
479 */
480 ret = trace_seq_printf(s,
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +0100481 " ------------------------------------------\n");
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100482 if (!ret)
Wenji Huang810dc732009-02-10 01:03:05 -0500483 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100484
485 ret = print_graph_cpu(s, cpu);
486 if (ret == TRACE_TYPE_PARTIAL_LINE)
Wenji Huang810dc732009-02-10 01:03:05 -0500487 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100488
489 ret = print_graph_proc(s, prev_pid);
490 if (ret == TRACE_TYPE_PARTIAL_LINE)
Wenji Huang810dc732009-02-10 01:03:05 -0500491 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100492
493 ret = trace_seq_printf(s, " => ");
494 if (!ret)
Wenji Huang810dc732009-02-10 01:03:05 -0500495 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100496
497 ret = print_graph_proc(s, pid);
498 if (ret == TRACE_TYPE_PARTIAL_LINE)
Wenji Huang810dc732009-02-10 01:03:05 -0500499 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100500
501 ret = trace_seq_printf(s,
502 "\n ------------------------------------------\n\n");
503 if (!ret)
Wenji Huang810dc732009-02-10 01:03:05 -0500504 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100505
Wenji Huang810dc732009-02-10 01:03:05 -0500506 return TRACE_TYPE_HANDLED;
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100507}
508
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100509static struct ftrace_graph_ret_entry *
510get_return_for_leaf(struct trace_iterator *iter,
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100511 struct ftrace_graph_ent_entry *curr)
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100512{
Jiri Olsabe1eca32009-11-24 13:57:38 +0100513 struct fgraph_data *data = iter->private;
514 struct ring_buffer_iter *ring_iter = NULL;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100515 struct ring_buffer_event *event;
516 struct ftrace_graph_ret_entry *next;
517
Jiri Olsabe1eca32009-11-24 13:57:38 +0100518 /*
519 * If the previous output failed to write to the seq buffer,
520 * then we just reuse the data from before.
521 */
522 if (data && data->failed) {
523 curr = &data->ent;
524 next = &data->ret;
525 } else {
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100526
Jiri Olsabe1eca32009-11-24 13:57:38 +0100527 ring_iter = iter->buffer_iter[iter->cpu];
528
529 /* First peek to compare current entry and the next one */
530 if (ring_iter)
531 event = ring_buffer_iter_peek(ring_iter, NULL);
532 else {
533 /*
534 * We need to consume the current entry to see
535 * the next one.
536 */
Steven Rostedt66a8cb92010-03-31 13:21:56 -0400537 ring_buffer_consume(iter->tr->buffer, iter->cpu,
538 NULL, NULL);
Jiri Olsabe1eca32009-11-24 13:57:38 +0100539 event = ring_buffer_peek(iter->tr->buffer, iter->cpu,
Steven Rostedt66a8cb92010-03-31 13:21:56 -0400540 NULL, NULL);
Jiri Olsabe1eca32009-11-24 13:57:38 +0100541 }
542
543 if (!event)
544 return NULL;
545
546 next = ring_buffer_event_data(event);
547
548 if (data) {
549 /*
550 * Save current and next entries for later reference
551 * if the output fails.
552 */
553 data->ent = *curr;
Shaohua Li575570f2010-07-27 16:06:34 +0800554 /*
555 * If the next event is not a return type, then
556 * we only care about what type it is. Otherwise we can
557 * safely copy the entire event.
558 */
559 if (next->ent.type == TRACE_GRAPH_RET)
560 data->ret = *next;
561 else
562 data->ret.ent.type = next->ent.type;
Jiri Olsabe1eca32009-11-24 13:57:38 +0100563 }
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100564 }
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100565
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100566 if (next->ent.type != TRACE_GRAPH_RET)
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100567 return NULL;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100568
569 if (curr->ent.pid != next->ent.pid ||
570 curr->graph_ent.func != next->ret.func)
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100571 return NULL;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100572
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100573 /* this is a leaf, now advance the iterator */
574 if (ring_iter)
575 ring_buffer_read(ring_iter, NULL);
576
577 return next;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100578}
579
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800580/* Signal a overhead of time execution to the output */
581static int
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200582print_graph_overhead(unsigned long long duration, struct trace_seq *s,
583 u32 flags)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800584{
585 /* If duration disappear, we don't need anything */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200586 if (!(flags & TRACE_GRAPH_PRINT_DURATION))
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800587 return 1;
588
589 /* Non nested entry or return */
590 if (duration == -1)
591 return trace_seq_printf(s, " ");
592
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200593 if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800594 /* Duration exceeded 100 msecs */
595 if (duration > 100000ULL)
596 return trace_seq_printf(s, "! ");
597
598 /* Duration exceeded 10 msecs */
599 if (duration > 10000ULL)
600 return trace_seq_printf(s, "+ ");
601 }
602
603 return trace_seq_printf(s, " ");
604}
605
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +0100606static int print_graph_abs_time(u64 t, struct trace_seq *s)
607{
608 unsigned long usecs_rem;
609
610 usecs_rem = do_div(t, NSEC_PER_SEC);
611 usecs_rem /= 1000;
612
613 return trace_seq_printf(s, "%5lu.%06lu | ",
614 (unsigned long)t, usecs_rem);
615}
616
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100617static enum print_line_t
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +0100618print_graph_irq(struct trace_iterator *iter, unsigned long addr,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200619 enum trace_type type, int cpu, pid_t pid, u32 flags)
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100620{
621 int ret;
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +0100622 struct trace_seq *s = &iter->seq;
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100623
624 if (addr < (unsigned long)__irqentry_text_start ||
625 addr >= (unsigned long)__irqentry_text_end)
626 return TRACE_TYPE_UNHANDLED;
627
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +0100628 /* Absolute time */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200629 if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +0100630 ret = print_graph_abs_time(iter->ts, s);
631 if (!ret)
632 return TRACE_TYPE_PARTIAL_LINE;
633 }
634
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800635 /* Cpu */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200636 if (flags & TRACE_GRAPH_PRINT_CPU) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800637 ret = print_graph_cpu(s, cpu);
638 if (ret == TRACE_TYPE_PARTIAL_LINE)
639 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100640 }
Steven Rostedt49ff5902009-09-11 00:30:26 -0400641
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800642 /* Proc */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200643 if (flags & TRACE_GRAPH_PRINT_PROC) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800644 ret = print_graph_proc(s, pid);
645 if (ret == TRACE_TYPE_PARTIAL_LINE)
646 return TRACE_TYPE_PARTIAL_LINE;
647 ret = trace_seq_printf(s, " | ");
648 if (!ret)
649 return TRACE_TYPE_PARTIAL_LINE;
650 }
651
652 /* No overhead */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200653 ret = print_graph_overhead(-1, s, flags);
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800654 if (!ret)
655 return TRACE_TYPE_PARTIAL_LINE;
656
657 if (type == TRACE_GRAPH_ENT)
658 ret = trace_seq_printf(s, "==========>");
659 else
660 ret = trace_seq_printf(s, "<==========");
661
662 if (!ret)
663 return TRACE_TYPE_PARTIAL_LINE;
664
665 /* Don't close the duration column if haven't one */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200666 if (flags & TRACE_GRAPH_PRINT_DURATION)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800667 trace_seq_printf(s, " |");
668 ret = trace_seq_printf(s, "\n");
669
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100670 if (!ret)
671 return TRACE_TYPE_PARTIAL_LINE;
672 return TRACE_TYPE_HANDLED;
673}
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100674
Steven Rostedt0706f1c2009-03-23 23:12:58 -0400675enum print_line_t
676trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100677{
678 unsigned long nsecs_rem = do_div(duration, 1000);
Frederic Weisbecker166d3c72008-12-03 02:32:12 +0100679 /* log10(ULONG_MAX) + '\0' */
680 char msecs_str[21];
681 char nsecs_str[5];
682 int ret, len;
683 int i;
684
685 sprintf(msecs_str, "%lu", (unsigned long) duration);
686
687 /* Print msecs */
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800688 ret = trace_seq_printf(s, "%s", msecs_str);
Frederic Weisbecker166d3c72008-12-03 02:32:12 +0100689 if (!ret)
690 return TRACE_TYPE_PARTIAL_LINE;
691
692 len = strlen(msecs_str);
693
694 /* Print nsecs (we don't want to exceed 7 numbers) */
695 if (len < 7) {
Borislav Petkov14cae9b2010-09-29 10:08:23 +0200696 size_t slen = min_t(size_t, sizeof(nsecs_str), 8UL - len);
697
698 snprintf(nsecs_str, slen, "%03lu", nsecs_rem);
Frederic Weisbecker166d3c72008-12-03 02:32:12 +0100699 ret = trace_seq_printf(s, ".%s", nsecs_str);
700 if (!ret)
701 return TRACE_TYPE_PARTIAL_LINE;
702 len += strlen(nsecs_str);
703 }
704
705 ret = trace_seq_printf(s, " us ");
706 if (!ret)
707 return TRACE_TYPE_PARTIAL_LINE;
708
709 /* Print remaining spaces to fit the row's width */
710 for (i = len; i < 7; i++) {
711 ret = trace_seq_printf(s, " ");
712 if (!ret)
713 return TRACE_TYPE_PARTIAL_LINE;
714 }
Steven Rostedt0706f1c2009-03-23 23:12:58 -0400715 return TRACE_TYPE_HANDLED;
716}
717
718static enum print_line_t
719print_graph_duration(unsigned long long duration, struct trace_seq *s)
720{
721 int ret;
722
723 ret = trace_print_graph_duration(duration, s);
724 if (ret != TRACE_TYPE_HANDLED)
725 return ret;
Frederic Weisbecker166d3c72008-12-03 02:32:12 +0100726
727 ret = trace_seq_printf(s, "| ");
728 if (!ret)
729 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker166d3c72008-12-03 02:32:12 +0100730
Steven Rostedt0706f1c2009-03-23 23:12:58 -0400731 return TRACE_TYPE_HANDLED;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100732}
733
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100734/* Case of a leaf function on its call entry */
735static enum print_line_t
736print_graph_entry_leaf(struct trace_iterator *iter,
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100737 struct ftrace_graph_ent_entry *entry,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200738 struct ftrace_graph_ret_entry *ret_entry,
739 struct trace_seq *s, u32 flags)
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100740{
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400741 struct fgraph_data *data = iter->private;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100742 struct ftrace_graph_ret *graph_ret;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100743 struct ftrace_graph_ent *call;
744 unsigned long long duration;
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100745 int ret;
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100746 int i;
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100747
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100748 graph_ret = &ret_entry->ret;
749 call = &entry->graph_ent;
750 duration = graph_ret->rettime - graph_ret->calltime;
Steven Rostedt437f24fb2008-11-26 00:16:27 -0500751
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400752 if (data) {
Steven Rostedtf1c7f512010-02-26 17:08:16 -0500753 struct fgraph_cpu_data *cpu_data;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400754 int cpu = iter->cpu;
Steven Rostedtf1c7f512010-02-26 17:08:16 -0500755
756 cpu_data = per_cpu_ptr(data->cpu_data, cpu);
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400757
758 /*
759 * Comments display at + 1 to depth. Since
760 * this is a leaf function, keep the comments
761 * equal to this depth.
762 */
Steven Rostedtf1c7f512010-02-26 17:08:16 -0500763 cpu_data->depth = call->depth - 1;
764
765 /* No need to keep this function around for this depth */
766 if (call->depth < FTRACE_RETFUNC_DEPTH)
767 cpu_data->enter_funcs[call->depth] = 0;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400768 }
769
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100770 /* Overhead */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200771 ret = print_graph_overhead(duration, s, flags);
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800772 if (!ret)
773 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100774
775 /* Duration */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200776 if (flags & TRACE_GRAPH_PRINT_DURATION) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800777 ret = print_graph_duration(duration, s);
778 if (ret == TRACE_TYPE_PARTIAL_LINE)
779 return TRACE_TYPE_PARTIAL_LINE;
780 }
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100781
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100782 /* Function */
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100783 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
784 ret = trace_seq_printf(s, " ");
785 if (!ret)
786 return TRACE_TYPE_PARTIAL_LINE;
787 }
788
Steven Rostedtb375a112009-09-17 00:05:58 -0400789 ret = trace_seq_printf(s, "%ps();\n", (void *)call->func);
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100790 if (!ret)
791 return TRACE_TYPE_PARTIAL_LINE;
792
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100793 return TRACE_TYPE_HANDLED;
794}
795
796static enum print_line_t
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400797print_graph_entry_nested(struct trace_iterator *iter,
798 struct ftrace_graph_ent_entry *entry,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200799 struct trace_seq *s, int cpu, u32 flags)
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100800{
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100801 struct ftrace_graph_ent *call = &entry->graph_ent;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400802 struct fgraph_data *data = iter->private;
803 int ret;
804 int i;
805
806 if (data) {
Steven Rostedtf1c7f512010-02-26 17:08:16 -0500807 struct fgraph_cpu_data *cpu_data;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400808 int cpu = iter->cpu;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400809
Steven Rostedtf1c7f512010-02-26 17:08:16 -0500810 cpu_data = per_cpu_ptr(data->cpu_data, cpu);
811 cpu_data->depth = call->depth;
812
813 /* Save this function pointer to see if the exit matches */
814 if (call->depth < FTRACE_RETFUNC_DEPTH)
815 cpu_data->enter_funcs[call->depth] = call->func;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400816 }
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100817
818 /* No overhead */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200819 ret = print_graph_overhead(-1, s, flags);
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800820 if (!ret)
821 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100822
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800823 /* No time */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200824 if (flags & TRACE_GRAPH_PRINT_DURATION) {
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100825 ret = trace_seq_printf(s, " | ");
826 if (!ret)
827 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +0100828 }
829
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100830 /* Function */
831 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
832 ret = trace_seq_printf(s, " ");
833 if (!ret)
834 return TRACE_TYPE_PARTIAL_LINE;
835 }
836
Steven Rostedtb375a112009-09-17 00:05:58 -0400837 ret = trace_seq_printf(s, "%ps() {\n", (void *)call->func);
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100838 if (!ret)
839 return TRACE_TYPE_PARTIAL_LINE;
840
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +0100841 /*
842 * we already consumed the current entry to check the next one
843 * and see if this is a leaf.
844 */
845 return TRACE_TYPE_NO_CONSUME;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100846}
847
848static enum print_line_t
Steven Rostedtac5f6c92009-03-19 11:29:23 -0400849print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200850 int type, unsigned long addr, u32 flags)
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100851{
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400852 struct fgraph_data *data = iter->private;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +0100853 struct trace_entry *ent = iter->ent;
Steven Rostedtac5f6c92009-03-19 11:29:23 -0400854 int cpu = iter->cpu;
855 int ret;
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100856
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100857 /* Pid */
Steven Rostedt2fbcdb32009-03-19 13:24:42 -0400858 if (verif_pid(s, ent->pid, cpu, data) == TRACE_TYPE_PARTIAL_LINE)
Steven Rostedt437f24fb2008-11-26 00:16:27 -0500859 return TRACE_TYPE_PARTIAL_LINE;
860
Steven Rostedtac5f6c92009-03-19 11:29:23 -0400861 if (type) {
862 /* Interrupt */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200863 ret = print_graph_irq(iter, addr, type, cpu, ent->pid, flags);
Steven Rostedtac5f6c92009-03-19 11:29:23 -0400864 if (ret == TRACE_TYPE_PARTIAL_LINE)
865 return TRACE_TYPE_PARTIAL_LINE;
866 }
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800867
868 /* Absolute time */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200869 if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -0800870 ret = print_graph_abs_time(iter->ts, s);
871 if (!ret)
872 return TRACE_TYPE_PARTIAL_LINE;
873 }
874
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100875 /* Cpu */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200876 if (flags & TRACE_GRAPH_PRINT_CPU) {
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100877 ret = print_graph_cpu(s, cpu);
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100878 if (ret == TRACE_TYPE_PARTIAL_LINE)
879 return TRACE_TYPE_PARTIAL_LINE;
880 }
881
882 /* Proc */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +0200883 if (flags & TRACE_GRAPH_PRINT_PROC) {
Ingo Molnar00a8bf82009-02-19 13:01:37 +0100884 ret = print_graph_proc(s, ent->pid);
Frederic Weisbecker11e84ac2008-12-03 02:30:37 +0100885 if (ret == TRACE_TYPE_PARTIAL_LINE)
886 return TRACE_TYPE_PARTIAL_LINE;
887
888 ret = trace_seq_printf(s, " | ");
Frederic Weisbecker1a056152008-11-28 00:42:46 +0100889 if (!ret)
890 return TRACE_TYPE_PARTIAL_LINE;
891 }
Frederic Weisbecker287b6e62008-11-26 00:57:25 +0100892
Steven Rostedt49ff5902009-09-11 00:30:26 -0400893 /* Latency format */
894 if (trace_flags & TRACE_ITER_LATENCY_FMT) {
895 ret = print_graph_lat_fmt(s, ent);
896 if (ret == TRACE_TYPE_PARTIAL_LINE)
897 return TRACE_TYPE_PARTIAL_LINE;
898 }
899
Steven Rostedtac5f6c92009-03-19 11:29:23 -0400900 return 0;
901}
902
Jiri Olsa2bd162122010-09-07 16:53:44 +0200903/*
904 * Entry check for irq code
905 *
906 * returns 1 if
907 * - we are inside irq code
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300908 * - we just entered irq code
Jiri Olsa2bd162122010-09-07 16:53:44 +0200909 *
910 * retunns 0 if
911 * - funcgraph-interrupts option is set
912 * - we are not inside irq code
913 */
914static int
915check_irq_entry(struct trace_iterator *iter, u32 flags,
916 unsigned long addr, int depth)
917{
918 int cpu = iter->cpu;
Jiri Olsaa9d61172010-09-24 17:41:02 +0200919 int *depth_irq;
Jiri Olsa2bd162122010-09-07 16:53:44 +0200920 struct fgraph_data *data = iter->private;
Jiri Olsa2bd162122010-09-07 16:53:44 +0200921
Jiri Olsaa9d61172010-09-24 17:41:02 +0200922 /*
923 * If we are either displaying irqs, or we got called as
924 * a graph event and private data does not exist,
925 * then we bypass the irq check.
926 */
927 if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
928 (!data))
Jiri Olsa2bd162122010-09-07 16:53:44 +0200929 return 0;
930
Jiri Olsaa9d61172010-09-24 17:41:02 +0200931 depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
932
Jiri Olsa2bd162122010-09-07 16:53:44 +0200933 /*
934 * We are inside the irq code
935 */
936 if (*depth_irq >= 0)
937 return 1;
938
939 if ((addr < (unsigned long)__irqentry_text_start) ||
940 (addr >= (unsigned long)__irqentry_text_end))
941 return 0;
942
943 /*
944 * We are entering irq code.
945 */
946 *depth_irq = depth;
947 return 1;
948}
949
950/*
951 * Return check for irq code
952 *
953 * returns 1 if
954 * - we are inside irq code
955 * - we just left irq code
956 *
957 * returns 0 if
958 * - funcgraph-interrupts option is set
959 * - we are not inside irq code
960 */
961static int
962check_irq_return(struct trace_iterator *iter, u32 flags, int depth)
963{
964 int cpu = iter->cpu;
Jiri Olsaa9d61172010-09-24 17:41:02 +0200965 int *depth_irq;
Jiri Olsa2bd162122010-09-07 16:53:44 +0200966 struct fgraph_data *data = iter->private;
Jiri Olsa2bd162122010-09-07 16:53:44 +0200967
Jiri Olsaa9d61172010-09-24 17:41:02 +0200968 /*
969 * If we are either displaying irqs, or we got called as
970 * a graph event and private data does not exist,
971 * then we bypass the irq check.
972 */
973 if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
974 (!data))
Jiri Olsa2bd162122010-09-07 16:53:44 +0200975 return 0;
976
Jiri Olsaa9d61172010-09-24 17:41:02 +0200977 depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
978
Jiri Olsa2bd162122010-09-07 16:53:44 +0200979 /*
980 * We are not inside the irq code.
981 */
982 if (*depth_irq == -1)
983 return 0;
984
985 /*
986 * We are inside the irq code, and this is returning entry.
987 * Let's not trace it and clear the entry depth, since
988 * we are out of irq code.
989 *
990 * This condition ensures that we 'leave the irq code' once
991 * we are out of the entry depth. Thus protecting us from
992 * the RETURN entry loss.
993 */
994 if (*depth_irq >= depth) {
995 *depth_irq = -1;
996 return 1;
997 }
998
999 /*
1000 * We are inside the irq code, and this is not the entry.
1001 */
1002 return 1;
1003}
1004
Steven Rostedtac5f6c92009-03-19 11:29:23 -04001005static enum print_line_t
1006print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001007 struct trace_iterator *iter, u32 flags)
Steven Rostedtac5f6c92009-03-19 11:29:23 -04001008{
Jiri Olsabe1eca32009-11-24 13:57:38 +01001009 struct fgraph_data *data = iter->private;
Steven Rostedtac5f6c92009-03-19 11:29:23 -04001010 struct ftrace_graph_ent *call = &field->graph_ent;
1011 struct ftrace_graph_ret_entry *leaf_ret;
Jiri Olsabe1eca32009-11-24 13:57:38 +01001012 static enum print_line_t ret;
1013 int cpu = iter->cpu;
Steven Rostedtac5f6c92009-03-19 11:29:23 -04001014
Jiri Olsa2bd162122010-09-07 16:53:44 +02001015 if (check_irq_entry(iter, flags, call->func, call->depth))
1016 return TRACE_TYPE_HANDLED;
1017
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001018 if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags))
Steven Rostedtac5f6c92009-03-19 11:29:23 -04001019 return TRACE_TYPE_PARTIAL_LINE;
1020
Frederic Weisbeckerb91facc2009-02-06 18:30:44 +01001021 leaf_ret = get_return_for_leaf(iter, field);
1022 if (leaf_ret)
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001023 ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags);
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001024 else
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001025 ret = print_graph_entry_nested(iter, field, s, cpu, flags);
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001026
Jiri Olsabe1eca32009-11-24 13:57:38 +01001027 if (data) {
1028 /*
1029 * If we failed to write our output, then we need to make
1030 * note of it. Because we already consumed our entry.
1031 */
1032 if (s->full) {
1033 data->failed = 1;
1034 data->cpu = cpu;
1035 } else
1036 data->failed = 0;
1037 }
1038
1039 return ret;
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001040}
1041
1042static enum print_line_t
1043print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001044 struct trace_entry *ent, struct trace_iterator *iter,
1045 u32 flags)
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001046{
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001047 unsigned long long duration = trace->rettime - trace->calltime;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001048 struct fgraph_data *data = iter->private;
1049 pid_t pid = ent->pid;
1050 int cpu = iter->cpu;
Steven Rostedtf1c7f512010-02-26 17:08:16 -05001051 int func_match = 1;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001052 int ret;
1053 int i;
1054
Jiri Olsa2bd162122010-09-07 16:53:44 +02001055 if (check_irq_return(iter, flags, trace->depth))
1056 return TRACE_TYPE_HANDLED;
1057
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001058 if (data) {
Steven Rostedtf1c7f512010-02-26 17:08:16 -05001059 struct fgraph_cpu_data *cpu_data;
1060 int cpu = iter->cpu;
1061
1062 cpu_data = per_cpu_ptr(data->cpu_data, cpu);
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001063
1064 /*
1065 * Comments display at + 1 to depth. This is the
1066 * return from a function, we now want the comments
1067 * to display at the same level of the bracket.
1068 */
Steven Rostedtf1c7f512010-02-26 17:08:16 -05001069 cpu_data->depth = trace->depth - 1;
1070
1071 if (trace->depth < FTRACE_RETFUNC_DEPTH) {
1072 if (cpu_data->enter_funcs[trace->depth] != trace->func)
1073 func_match = 0;
1074 cpu_data->enter_funcs[trace->depth] = 0;
1075 }
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001076 }
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001077
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001078 if (print_graph_prologue(iter, s, 0, 0, flags))
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001079 return TRACE_TYPE_PARTIAL_LINE;
1080
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001081 /* Overhead */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001082 ret = print_graph_overhead(duration, s, flags);
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001083 if (!ret)
1084 return TRACE_TYPE_PARTIAL_LINE;
Frederic Weisbecker1a056152008-11-28 00:42:46 +01001085
1086 /* Duration */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001087 if (flags & TRACE_GRAPH_PRINT_DURATION) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001088 ret = print_graph_duration(duration, s);
1089 if (ret == TRACE_TYPE_PARTIAL_LINE)
1090 return TRACE_TYPE_PARTIAL_LINE;
1091 }
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001092
1093 /* Closing brace */
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001094 for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
1095 ret = trace_seq_printf(s, " ");
1096 if (!ret)
1097 return TRACE_TYPE_PARTIAL_LINE;
1098 }
1099
Steven Rostedtf1c7f512010-02-26 17:08:16 -05001100 /*
1101 * If the return function does not have a matching entry,
1102 * then the entry was lost. Instead of just printing
1103 * the '}' and letting the user guess what function this
1104 * belongs to, write out the function name.
1105 */
1106 if (func_match) {
1107 ret = trace_seq_printf(s, "}\n");
1108 if (!ret)
1109 return TRACE_TYPE_PARTIAL_LINE;
1110 } else {
Steven Rostedta094fe02010-03-05 20:08:58 -05001111 ret = trace_seq_printf(s, "} /* %ps */\n", (void *)trace->func);
Steven Rostedtf1c7f512010-02-26 17:08:16 -05001112 if (!ret)
1113 return TRACE_TYPE_PARTIAL_LINE;
1114 }
Frederic Weisbecker83a8df62008-11-27 01:46:33 +01001115
1116 /* Overrun */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001117 if (flags & TRACE_GRAPH_PRINT_OVERRUN) {
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001118 ret = trace_seq_printf(s, " (Overruns: %lu)\n",
1119 trace->overrun);
1120 if (!ret)
1121 return TRACE_TYPE_PARTIAL_LINE;
1122 }
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +01001123
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001124 ret = print_graph_irq(iter, trace->func, TRACE_GRAPH_RET,
1125 cpu, pid, flags);
Frederic Weisbeckerf8b755a2008-12-09 23:55:25 +01001126 if (ret == TRACE_TYPE_PARTIAL_LINE)
1127 return TRACE_TYPE_PARTIAL_LINE;
1128
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001129 return TRACE_TYPE_HANDLED;
1130}
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001131
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001132static enum print_line_t
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001133print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
1134 struct trace_iterator *iter, u32 flags)
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001135{
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001136 unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001137 struct fgraph_data *data = iter->private;
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001138 struct trace_event *event;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001139 int depth = 0;
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001140 int ret;
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001141 int i;
1142
1143 if (data)
Jiri Olsabe1eca32009-11-24 13:57:38 +01001144 depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth;
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001145
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001146 if (print_graph_prologue(iter, s, 0, 0, flags))
Frederic Weisbeckerd1f9cbd2009-02-18 04:25:25 +01001147 return TRACE_TYPE_PARTIAL_LINE;
1148
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001149 /* No overhead */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001150 ret = print_graph_overhead(-1, s, flags);
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001151 if (!ret)
1152 return TRACE_TYPE_PARTIAL_LINE;
1153
1154 /* No time */
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001155 if (flags & TRACE_GRAPH_PRINT_DURATION) {
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001156 ret = trace_seq_printf(s, " | ");
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001157 if (!ret)
1158 return TRACE_TYPE_PARTIAL_LINE;
1159 }
1160
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001161 /* Indentation */
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001162 if (depth > 0)
1163 for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) {
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001164 ret = trace_seq_printf(s, " ");
1165 if (!ret)
1166 return TRACE_TYPE_PARTIAL_LINE;
1167 }
1168
1169 /* The comment */
Frederic Weisbecker769b0442009-03-06 17:21:49 +01001170 ret = trace_seq_printf(s, "/* ");
1171 if (!ret)
1172 return TRACE_TYPE_PARTIAL_LINE;
1173
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001174 switch (iter->ent->type) {
1175 case TRACE_BPRINT:
1176 ret = trace_print_bprintk_msg_only(iter);
1177 if (ret != TRACE_TYPE_HANDLED)
1178 return ret;
1179 break;
1180 case TRACE_PRINT:
1181 ret = trace_print_printk_msg_only(iter);
1182 if (ret != TRACE_TYPE_HANDLED)
1183 return ret;
1184 break;
1185 default:
1186 event = ftrace_find_event(ent->type);
1187 if (!event)
1188 return TRACE_TYPE_UNHANDLED;
1189
Steven Rostedta9a57762010-04-22 18:46:14 -04001190 ret = event->funcs->trace(iter, sym_flags, event);
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001191 if (ret != TRACE_TYPE_HANDLED)
1192 return ret;
1193 }
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001194
Frederic Weisbecker412d0bb2008-12-24 01:43:25 +01001195 /* Strip ending newline */
1196 if (s->buffer[s->len - 1] == '\n') {
1197 s->buffer[s->len - 1] = '\0';
1198 s->len--;
1199 }
1200
Frederic Weisbecker1fd8f2a2008-12-03 23:45:11 +01001201 ret = trace_seq_printf(s, " */\n");
1202 if (!ret)
1203 return TRACE_TYPE_PARTIAL_LINE;
1204
1205 return TRACE_TYPE_HANDLED;
1206}
1207
1208
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001209enum print_line_t
Jiri Olsa0a772622010-09-23 14:00:52 +02001210__print_graph_function_flags(struct trace_iterator *iter, u32 flags)
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001211{
Jiri Olsabe1eca32009-11-24 13:57:38 +01001212 struct ftrace_graph_ent_entry *field;
1213 struct fgraph_data *data = iter->private;
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001214 struct trace_entry *entry = iter->ent;
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001215 struct trace_seq *s = &iter->seq;
Jiri Olsabe1eca32009-11-24 13:57:38 +01001216 int cpu = iter->cpu;
1217 int ret;
1218
1219 if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) {
1220 per_cpu_ptr(data->cpu_data, cpu)->ignore = 0;
1221 return TRACE_TYPE_HANDLED;
1222 }
1223
1224 /*
1225 * If the last output failed, there's a possibility we need
1226 * to print out the missing entry which would never go out.
1227 */
1228 if (data && data->failed) {
1229 field = &data->ent;
1230 iter->cpu = data->cpu;
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001231 ret = print_graph_entry(field, s, iter, flags);
Jiri Olsabe1eca32009-11-24 13:57:38 +01001232 if (ret == TRACE_TYPE_HANDLED && iter->cpu != cpu) {
1233 per_cpu_ptr(data->cpu_data, iter->cpu)->ignore = 1;
1234 ret = TRACE_TYPE_NO_CONSUME;
1235 }
1236 iter->cpu = cpu;
1237 return ret;
1238 }
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001239
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001240 switch (entry->type) {
1241 case TRACE_GRAPH_ENT: {
Lai Jiangshan38ceb592009-07-28 20:11:24 +08001242 /*
1243 * print_graph_entry() may consume the current event,
1244 * thus @field may become invalid, so we need to save it.
1245 * sizeof(struct ftrace_graph_ent_entry) is very small,
1246 * it can be safely saved at the stack.
1247 */
Jiri Olsabe1eca32009-11-24 13:57:38 +01001248 struct ftrace_graph_ent_entry saved;
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001249 trace_assign_type(field, entry);
Lai Jiangshan38ceb592009-07-28 20:11:24 +08001250 saved = *field;
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001251 return print_graph_entry(&saved, s, iter, flags);
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001252 }
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001253 case TRACE_GRAPH_RET: {
1254 struct ftrace_graph_ret_entry *field;
1255 trace_assign_type(field, entry);
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001256 return print_graph_return(&field->ret, s, entry, iter, flags);
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001257 }
Jiri Olsa62b915f2010-04-02 19:01:22 +02001258 case TRACE_STACK:
1259 case TRACE_FN:
1260 /* dont trace stack and functions as comments */
1261 return TRACE_TYPE_UNHANDLED;
1262
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001263 default:
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001264 return print_graph_comment(s, entry, iter, flags);
Frederic Weisbecker287b6e62008-11-26 00:57:25 +01001265 }
Steven Rostedt5087f8d2009-03-19 15:14:46 -04001266
1267 return TRACE_TYPE_HANDLED;
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001268}
1269
Jiri Olsa9106b692010-04-02 19:01:20 +02001270static enum print_line_t
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001271print_graph_function(struct trace_iterator *iter)
1272{
Jiri Olsa0a772622010-09-23 14:00:52 +02001273 return __print_graph_function_flags(iter, tracer_flags.val);
1274}
1275
1276enum print_line_t print_graph_function_flags(struct trace_iterator *iter,
1277 u32 flags)
1278{
1279 if (trace_flags & TRACE_ITER_LATENCY_FMT)
1280 flags |= TRACE_GRAPH_PRINT_DURATION;
1281 else
1282 flags |= TRACE_GRAPH_PRINT_ABS_TIME;
1283
1284 return __print_graph_function_flags(iter, flags);
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001285}
1286
1287static enum print_line_t
Steven Rostedta9a57762010-04-22 18:46:14 -04001288print_graph_function_event(struct trace_iterator *iter, int flags,
1289 struct trace_event *event)
Jiri Olsa9106b692010-04-02 19:01:20 +02001290{
1291 return print_graph_function(iter);
1292}
1293
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001294static void print_lat_header(struct seq_file *s, u32 flags)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001295{
1296 static const char spaces[] = " " /* 16 spaces */
1297 " " /* 4 spaces */
1298 " "; /* 17 spaces */
1299 int size = 0;
1300
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001301 if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001302 size += 16;
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001303 if (flags & TRACE_GRAPH_PRINT_CPU)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001304 size += 4;
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001305 if (flags & TRACE_GRAPH_PRINT_PROC)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001306 size += 17;
1307
1308 seq_printf(s, "#%.*s _-----=> irqs-off \n", size, spaces);
1309 seq_printf(s, "#%.*s / _----=> need-resched \n", size, spaces);
1310 seq_printf(s, "#%.*s| / _---=> hardirq/softirq \n", size, spaces);
1311 seq_printf(s, "#%.*s|| / _--=> preempt-depth \n", size, spaces);
Steven Rostedt637e7e82009-09-11 13:55:35 -04001312 seq_printf(s, "#%.*s||| / _-=> lock-depth \n", size, spaces);
1313 seq_printf(s, "#%.*s|||| / \n", size, spaces);
Steven Rostedt49ff5902009-09-11 00:30:26 -04001314}
1315
Jiri Olsa0a772622010-09-23 14:00:52 +02001316static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
Frederic Weisbeckerdecbec32008-12-08 01:56:06 +01001317{
Steven Rostedt49ff5902009-09-11 00:30:26 -04001318 int lat = trace_flags & TRACE_ITER_LATENCY_FMT;
1319
1320 if (lat)
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001321 print_lat_header(s, flags);
Steven Rostedt49ff5902009-09-11 00:30:26 -04001322
Frederic Weisbeckerdecbec32008-12-08 01:56:06 +01001323 /* 1st line */
Steven Rostedt49ff5902009-09-11 00:30:26 -04001324 seq_printf(s, "#");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001325 if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001326 seq_printf(s, " TIME ");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001327 if (flags & TRACE_GRAPH_PRINT_CPU)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001328 seq_printf(s, " CPU");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001329 if (flags & TRACE_GRAPH_PRINT_PROC)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001330 seq_printf(s, " TASK/PID ");
1331 if (lat)
Steven Rostedt637e7e82009-09-11 13:55:35 -04001332 seq_printf(s, "|||||");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001333 if (flags & TRACE_GRAPH_PRINT_DURATION)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001334 seq_printf(s, " DURATION ");
1335 seq_printf(s, " FUNCTION CALLS\n");
Frederic Weisbeckerdecbec32008-12-08 01:56:06 +01001336
1337 /* 2nd line */
Steven Rostedt49ff5902009-09-11 00:30:26 -04001338 seq_printf(s, "#");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001339 if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001340 seq_printf(s, " | ");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001341 if (flags & TRACE_GRAPH_PRINT_CPU)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001342 seq_printf(s, " | ");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001343 if (flags & TRACE_GRAPH_PRINT_PROC)
Steven Rostedt49ff5902009-09-11 00:30:26 -04001344 seq_printf(s, " | | ");
1345 if (lat)
Steven Rostedt637e7e82009-09-11 13:55:35 -04001346 seq_printf(s, "|||||");
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001347 if (flags & TRACE_GRAPH_PRINT_DURATION)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001348 seq_printf(s, " | | ");
1349 seq_printf(s, " | | | |\n");
Frederic Weisbeckerdecbec32008-12-08 01:56:06 +01001350}
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001351
Jiri Olsa62b915f2010-04-02 19:01:22 +02001352void print_graph_headers(struct seq_file *s)
Jiri Olsad7a8d9e2010-04-02 19:01:21 +02001353{
1354 print_graph_headers_flags(s, tracer_flags.val);
1355}
1356
Jiri Olsa0a772622010-09-23 14:00:52 +02001357void print_graph_headers_flags(struct seq_file *s, u32 flags)
1358{
1359 struct trace_iterator *iter = s->private;
1360
1361 if (trace_flags & TRACE_ITER_LATENCY_FMT) {
1362 /* print nothing if the buffers are empty */
1363 if (trace_empty(iter))
1364 return;
1365
1366 print_trace_header(s, iter);
1367 flags |= TRACE_GRAPH_PRINT_DURATION;
1368 } else
1369 flags |= TRACE_GRAPH_PRINT_ABS_TIME;
1370
1371 __print_graph_headers_flags(s, flags);
1372}
1373
Jiri Olsa62b915f2010-04-02 19:01:22 +02001374void graph_trace_open(struct trace_iterator *iter)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001375{
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001376 /* pid and depth on the last trace processed */
Jiri Olsabe1eca32009-11-24 13:57:38 +01001377 struct fgraph_data *data;
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001378 int cpu;
1379
Jiri Olsabe1eca32009-11-24 13:57:38 +01001380 iter->private = NULL;
1381
1382 data = kzalloc(sizeof(*data), GFP_KERNEL);
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001383 if (!data)
Jiri Olsabe1eca32009-11-24 13:57:38 +01001384 goto out_err;
1385
1386 data->cpu_data = alloc_percpu(struct fgraph_cpu_data);
1387 if (!data->cpu_data)
1388 goto out_err_free;
1389
1390 for_each_possible_cpu(cpu) {
1391 pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
1392 int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth);
1393 int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore);
Jiri Olsa2bd162122010-09-07 16:53:44 +02001394 int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
1395
Jiri Olsabe1eca32009-11-24 13:57:38 +01001396 *pid = -1;
1397 *depth = 0;
1398 *ignore = 0;
Jiri Olsa2bd162122010-09-07 16:53:44 +02001399 *depth_irq = -1;
Jiri Olsabe1eca32009-11-24 13:57:38 +01001400 }
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001401
Steven Rostedt2fbcdb32009-03-19 13:24:42 -04001402 iter->private = data;
Jiri Olsabe1eca32009-11-24 13:57:38 +01001403
1404 return;
1405
1406 out_err_free:
1407 kfree(data);
1408 out_err:
1409 pr_warning("function graph tracer: not enough memory\n");
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001410}
1411
Jiri Olsa62b915f2010-04-02 19:01:22 +02001412void graph_trace_close(struct trace_iterator *iter)
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001413{
Jiri Olsabe1eca32009-11-24 13:57:38 +01001414 struct fgraph_data *data = iter->private;
1415
1416 if (data) {
1417 free_percpu(data->cpu_data);
1418 kfree(data);
1419 }
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001420}
1421
Steven Rostedtb304d042010-09-14 18:58:33 -04001422static int func_graph_set_flag(u32 old_flags, u32 bit, int set)
1423{
1424 if (bit == TRACE_GRAPH_PRINT_IRQS)
1425 ftrace_graph_skip_irqs = !set;
1426
1427 return 0;
1428}
1429
Steven Rostedta9a57762010-04-22 18:46:14 -04001430static struct trace_event_functions graph_functions = {
1431 .trace = print_graph_function_event,
1432};
1433
Jiri Olsa9106b692010-04-02 19:01:20 +02001434static struct trace_event graph_trace_entry_event = {
1435 .type = TRACE_GRAPH_ENT,
Steven Rostedta9a57762010-04-22 18:46:14 -04001436 .funcs = &graph_functions,
Jiri Olsa9106b692010-04-02 19:01:20 +02001437};
1438
1439static struct trace_event graph_trace_ret_event = {
1440 .type = TRACE_GRAPH_RET,
Steven Rostedta9a57762010-04-22 18:46:14 -04001441 .funcs = &graph_functions
Jiri Olsa9106b692010-04-02 19:01:20 +02001442};
1443
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001444static struct tracer graph_trace __read_mostly = {
Steven Rostedtef180122009-03-10 14:10:56 -04001445 .name = "function_graph",
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001446 .open = graph_trace_open,
Jiri Olsabe1eca32009-11-24 13:57:38 +01001447 .pipe_open = graph_trace_open,
Frederic Weisbecker9005f3e2009-01-22 17:04:53 -08001448 .close = graph_trace_close,
Jiri Olsabe1eca32009-11-24 13:57:38 +01001449 .pipe_close = graph_trace_close,
Frederic Weisbecker6eaaa5d2009-02-11 02:25:00 +01001450 .wait_pipe = poll_wait_pipe,
Steven Rostedtef180122009-03-10 14:10:56 -04001451 .init = graph_trace_init,
1452 .reset = graph_trace_reset,
Frederic Weisbeckerdecbec32008-12-08 01:56:06 +01001453 .print_line = print_graph_function,
1454 .print_header = print_graph_headers,
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001455 .flags = &tracer_flags,
Steven Rostedtb304d042010-09-14 18:58:33 -04001456 .set_flag = func_graph_set_flag,
Frederic Weisbecker7447dce2009-02-07 21:33:57 +01001457#ifdef CONFIG_FTRACE_SELFTEST
1458 .selftest = trace_selftest_startup_function_graph,
1459#endif
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001460};
1461
1462static __init int init_graph_trace(void)
1463{
Lai Jiangshan0c9e6f62009-07-28 20:26:06 +08001464 max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
1465
Jiri Olsa9106b692010-04-02 19:01:20 +02001466 if (!register_ftrace_event(&graph_trace_entry_event)) {
1467 pr_warning("Warning: could not register graph trace events\n");
1468 return 1;
1469 }
1470
1471 if (!register_ftrace_event(&graph_trace_ret_event)) {
1472 pr_warning("Warning: could not register graph trace events\n");
1473 return 1;
1474 }
1475
Frederic Weisbeckerfb526072008-11-25 21:07:04 +01001476 return register_tracer(&graph_trace);
1477}
1478
1479device_initcall(init_graph_trace);