Blame view

kernel/trace/trace_functions_graph.c 34.9 KB
fb52607af   Frederic Weisbecker   tracing/function-...
1
2
3
  /*
   *
   * Function graph tracer.
9005f3ebe   Frederic Weisbecker   tracing/function-...
4
   * Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
fb52607af   Frederic Weisbecker   tracing/function-...
5
6
7
8
9
10
11
   * Mostly borrowed from function tracer which
   * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
   *
   */
  #include <linux/debugfs.h>
  #include <linux/uaccess.h>
  #include <linux/ftrace.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
fb52607af   Frederic Weisbecker   tracing/function-...
13
14
15
  #include <linux/fs.h>
  
  #include "trace.h"
f0868d1e2   Steven Rostedt   ftrace: set up tr...
16
  #include "trace_output.h"
fb52607af   Frederic Weisbecker   tracing/function-...
17

b304d0441   Steven Rostedt   tracing: Do not t...
18
19
  /* When set, irq functions will be ignored */
  static int ftrace_graph_skip_irqs;
be1eca393   Jiri Olsa   tracing: Fix func...
20
  struct fgraph_cpu_data {
2fbcdb35a   Steven Rostedt   function-graph: c...
21
22
  	pid_t		last_pid;
  	int		depth;
2bd16212b   Jiri Olsa   tracing: Add func...
23
  	int		depth_irq;
be1eca393   Jiri Olsa   tracing: Fix func...
24
  	int		ignore;
f1c7f517a   Steven Rostedt   ftrace: Add funct...
25
  	unsigned long	enter_funcs[FTRACE_RETFUNC_DEPTH];
be1eca393   Jiri Olsa   tracing: Fix func...
26
27
28
  };
  
  struct fgraph_data {
6016ee13d   Namhyung Kim   perf, tracing: ad...
29
  	struct fgraph_cpu_data __percpu *cpu_data;
be1eca393   Jiri Olsa   tracing: Fix func...
30
31
32
33
34
35
  
  	/* Place to preserve last processed entry. */
  	struct ftrace_graph_ent_entry	ent;
  	struct ftrace_graph_ret_entry	ret;
  	int				failed;
  	int				cpu;
2fbcdb35a   Steven Rostedt   function-graph: c...
36
  };
287b6e68c   Frederic Weisbecker   tracing/function-...
37
  #define TRACE_GRAPH_INDENT	2
fb52607af   Frederic Weisbecker   tracing/function-...
38

1a056155e   Frederic Weisbecker   tracing/function-...
39
  /* Flag options */
fb52607af   Frederic Weisbecker   tracing/function-...
40
  #define TRACE_GRAPH_PRINT_OVERRUN	0x1
1a056155e   Frederic Weisbecker   tracing/function-...
41
42
  #define TRACE_GRAPH_PRINT_CPU		0x2
  #define TRACE_GRAPH_PRINT_OVERHEAD	0x4
11e84acc4   Frederic Weisbecker   tracing/function-...
43
  #define TRACE_GRAPH_PRINT_PROC		0x8
9005f3ebe   Frederic Weisbecker   tracing/function-...
44
  #define TRACE_GRAPH_PRINT_DURATION	0x10
9106b6938   Jiri Olsa   tracing: Add ftra...
45
  #define TRACE_GRAPH_PRINT_ABS_TIME	0x20
2bd16212b   Jiri Olsa   tracing: Add func...
46
  #define TRACE_GRAPH_PRINT_IRQS		0x40
1a056155e   Frederic Weisbecker   tracing/function-...
47

fb52607af   Frederic Weisbecker   tracing/function-...
48
  static struct tracer_opt trace_opts[] = {
9005f3ebe   Frederic Weisbecker   tracing/function-...
49
  	/* Display overruns? (for self-debug purpose) */
1a056155e   Frederic Weisbecker   tracing/function-...
50
51
52
53
54
  	{ TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
  	/* Display CPU ? */
  	{ TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
  	/* Display Overhead ? */
  	{ TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
11e84acc4   Frederic Weisbecker   tracing/function-...
55
56
  	/* Display proc name/pid */
  	{ TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
9005f3ebe   Frederic Weisbecker   tracing/function-...
57
58
59
60
  	/* Display duration of execution */
  	{ TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) },
  	/* Display absolute time of an entry */
  	{ TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) },
2bd16212b   Jiri Olsa   tracing: Add func...
61
62
  	/* Display interrupts */
  	{ TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
fb52607af   Frederic Weisbecker   tracing/function-...
63
64
65
66
  	{ } /* Empty entry */
  };
  
  static struct tracer_flags tracer_flags = {
11e84acc4   Frederic Weisbecker   tracing/function-...
67
  	/* Don't display overruns and proc by default */
9005f3ebe   Frederic Weisbecker   tracing/function-...
68
  	.val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD |
2bd16212b   Jiri Olsa   tracing: Add func...
69
  	       TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS,
fb52607af   Frederic Weisbecker   tracing/function-...
70
71
  	.opts = trace_opts
  };
1a0799a8f   Frederic Weisbecker   tracing/function-...
72
  static struct trace_array *graph_array;
9005f3ebe   Frederic Weisbecker   tracing/function-...
73

ffeb80fc3   Jiri Olsa   tracing, function...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  /*
   * DURATION column is being also used to display IRQ signs,
   * following values are used by print_graph_irq and others
   * to fill in space into DURATION column.
   */
  enum {
  	DURATION_FILL_FULL  = -1,
  	DURATION_FILL_START = -2,
  	DURATION_FILL_END   = -3,
  };
  
  static enum print_line_t
  print_graph_duration(unsigned long long duration, struct trace_seq *s,
  		     u32 flags);
fb52607af   Frederic Weisbecker   tracing/function-...
88

712406a6b   Steven Rostedt   tracing/function-...
89
90
  /* Add a function return address to the trace stack on thread info.*/
  int
71e308a23   Steven Rostedt   function-graph: a...
91
92
  ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
  			 unsigned long frame_pointer)
712406a6b   Steven Rostedt   tracing/function-...
93
  {
5d1a03dc5   Steven Rostedt   function-graph: m...
94
  	unsigned long long calltime;
712406a6b   Steven Rostedt   tracing/function-...
95
96
97
98
  	int index;
  
  	if (!current->ret_stack)
  		return -EBUSY;
82310a327   Steven Rostedt   function-graph: e...
99
100
101
102
103
  	/*
  	 * We must make sure the ret_stack is tested before we read
  	 * anything else.
  	 */
  	smp_rmb();
712406a6b   Steven Rostedt   tracing/function-...
104
105
106
107
108
  	/* The return trace stack is full */
  	if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
  		atomic_inc(&current->trace_overrun);
  		return -EBUSY;
  	}
5d1a03dc5   Steven Rostedt   function-graph: m...
109
  	calltime = trace_clock_local();
712406a6b   Steven Rostedt   tracing/function-...
110
111
112
113
  	index = ++current->curr_ret_stack;
  	barrier();
  	current->ret_stack[index].ret = ret;
  	current->ret_stack[index].func = func;
5d1a03dc5   Steven Rostedt   function-graph: m...
114
  	current->ret_stack[index].calltime = calltime;
a2a16d6a3   Steven Rostedt   function-graph: a...
115
  	current->ret_stack[index].subtime = 0;
71e308a23   Steven Rostedt   function-graph: a...
116
  	current->ret_stack[index].fp = frame_pointer;
712406a6b   Steven Rostedt   tracing/function-...
117
118
119
120
121
122
  	*depth = index;
  
  	return 0;
  }
  
  /* Retrieve a function return address to the trace stack on thread info.*/
a2a16d6a3   Steven Rostedt   function-graph: a...
123
  static void
71e308a23   Steven Rostedt   function-graph: a...
124
125
  ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,
  			unsigned long frame_pointer)
712406a6b   Steven Rostedt   tracing/function-...
126
127
128
129
130
131
132
133
134
135
136
137
  {
  	int index;
  
  	index = current->curr_ret_stack;
  
  	if (unlikely(index < 0)) {
  		ftrace_graph_stop();
  		WARN_ON(1);
  		/* Might as well panic, otherwise we have no where to go */
  		*ret = (unsigned long)panic;
  		return;
  	}
71e308a23   Steven Rostedt   function-graph: a...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  #ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
  	/*
  	 * The arch may choose to record the frame pointer used
  	 * and check it here to make sure that it is what we expect it
  	 * to be. If gcc does not set the place holder of the return
  	 * address in the frame pointer, and does a copy instead, then
  	 * the function graph trace will fail. This test detects this
  	 * case.
  	 *
  	 * Currently, x86_32 with optimize for size (-Os) makes the latest
  	 * gcc do the above.
  	 */
  	if (unlikely(current->ret_stack[index].fp != frame_pointer)) {
  		ftrace_graph_stop();
  		WARN(1, "Bad frame pointer: expected %lx, received %lx
  "
b375a11a2   Steven Rostedt   tracing: switch f...
154
155
  		     "  from func %ps return to %lx
  ",
71e308a23   Steven Rostedt   function-graph: a...
156
157
158
159
160
161
162
163
  		     current->ret_stack[index].fp,
  		     frame_pointer,
  		     (void *)current->ret_stack[index].func,
  		     current->ret_stack[index].ret);
  		*ret = (unsigned long)panic;
  		return;
  	}
  #endif
712406a6b   Steven Rostedt   tracing/function-...
164
165
166
167
168
  	*ret = current->ret_stack[index].ret;
  	trace->func = current->ret_stack[index].func;
  	trace->calltime = current->ret_stack[index].calltime;
  	trace->overrun = atomic_read(&current->trace_overrun);
  	trace->depth = index;
712406a6b   Steven Rostedt   tracing/function-...
169
170
171
172
173
174
  }
  
  /*
   * Send the trace to the ring-buffer.
   * @return the original return address.
   */
71e308a23   Steven Rostedt   function-graph: a...
175
  unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
712406a6b   Steven Rostedt   tracing/function-...
176
177
178
  {
  	struct ftrace_graph_ret trace;
  	unsigned long ret;
71e308a23   Steven Rostedt   function-graph: a...
179
  	ftrace_pop_return_trace(&trace, &ret, frame_pointer);
0012693ad   Frederic Weisbecker   tracing/function-...
180
  	trace.rettime = trace_clock_local();
712406a6b   Steven Rostedt   tracing/function-...
181
  	ftrace_graph_return(&trace);
a2a16d6a3   Steven Rostedt   function-graph: a...
182
183
  	barrier();
  	current->curr_ret_stack--;
712406a6b   Steven Rostedt   tracing/function-...
184
185
186
187
188
189
190
191
192
193
  
  	if (unlikely(!ret)) {
  		ftrace_graph_stop();
  		WARN_ON(1);
  		/* Might as well panic. What else to do? */
  		ret = (unsigned long)panic;
  	}
  
  	return ret;
  }
62b915f10   Jiri Olsa   tracing: Add grap...
194
  int __trace_graph_entry(struct trace_array *tr,
1a0799a8f   Frederic Weisbecker   tracing/function-...
195
196
197
198
199
200
  				struct ftrace_graph_ent *trace,
  				unsigned long flags,
  				int pc)
  {
  	struct ftrace_event_call *call = &event_funcgraph_entry;
  	struct ring_buffer_event *event;
e77405ad8   Steven Rostedt   tracing: pass aro...
201
  	struct ring_buffer *buffer = tr->buffer;
1a0799a8f   Frederic Weisbecker   tracing/function-...
202
  	struct ftrace_graph_ent_entry *entry;
dd17c8f72   Rusty Russell   percpu: remove pe...
203
  	if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
1a0799a8f   Frederic Weisbecker   tracing/function-...
204
  		return 0;
e77405ad8   Steven Rostedt   tracing: pass aro...
205
  	event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
1a0799a8f   Frederic Weisbecker   tracing/function-...
206
207
208
209
210
  					  sizeof(*entry), flags, pc);
  	if (!event)
  		return 0;
  	entry	= ring_buffer_event_data(event);
  	entry->graph_ent			= *trace;
e77405ad8   Steven Rostedt   tracing: pass aro...
211
212
  	if (!filter_current_check_discard(buffer, call, entry, event))
  		ring_buffer_unlock_commit(buffer, event);
1a0799a8f   Frederic Weisbecker   tracing/function-...
213
214
215
  
  	return 1;
  }
b304d0441   Steven Rostedt   tracing: Do not t...
216
217
  static inline int ftrace_graph_ignore_irqs(void)
  {
e4a3f541f   Steven Rostedt   tracing: Still tr...
218
  	if (!ftrace_graph_skip_irqs || trace_recursion_test(TRACE_IRQ_BIT))
b304d0441   Steven Rostedt   tracing: Do not t...
219
220
221
222
  		return 0;
  
  	return in_irq();
  }
1a0799a8f   Frederic Weisbecker   tracing/function-...
223
224
225
226
227
228
229
230
231
  int trace_graph_entry(struct ftrace_graph_ent *trace)
  {
  	struct trace_array *tr = graph_array;
  	struct trace_array_cpu *data;
  	unsigned long flags;
  	long disabled;
  	int ret;
  	int cpu;
  	int pc;
1a0799a8f   Frederic Weisbecker   tracing/function-...
232
233
  	if (!ftrace_trace_task(current))
  		return 0;
ea2c68a08   Lai Jiangshan   tracing: Simplify...
234
  	/* trace it when it is-nested-in or is a function enabled. */
b304d0441   Steven Rostedt   tracing: Do not t...
235
236
  	if (!(trace->depth || ftrace_graph_addr(trace->func)) ||
  	      ftrace_graph_ignore_irqs())
1a0799a8f   Frederic Weisbecker   tracing/function-...
237
238
239
240
241
242
243
244
245
246
247
248
  		return 0;
  
  	local_irq_save(flags);
  	cpu = raw_smp_processor_id();
  	data = tr->data[cpu];
  	disabled = atomic_inc_return(&data->disabled);
  	if (likely(disabled == 1)) {
  		pc = preempt_count();
  		ret = __trace_graph_entry(tr, trace, flags, pc);
  	} else {
  		ret = 0;
  	}
1a0799a8f   Frederic Weisbecker   tracing/function-...
249
250
251
252
253
254
  
  	atomic_dec(&data->disabled);
  	local_irq_restore(flags);
  
  	return ret;
  }
0e9501735   Tim Bird   function-graph: A...
255
256
257
258
259
260
261
  int trace_graph_thresh_entry(struct ftrace_graph_ent *trace)
  {
  	if (tracing_thresh)
  		return 1;
  	else
  		return trace_graph_entry(trace);
  }
0a772620a   Jiri Olsa   tracing: Make gra...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  static void
  __trace_graph_function(struct trace_array *tr,
  		unsigned long ip, unsigned long flags, int pc)
  {
  	u64 time = trace_clock_local();
  	struct ftrace_graph_ent ent = {
  		.func  = ip,
  		.depth = 0,
  	};
  	struct ftrace_graph_ret ret = {
  		.func     = ip,
  		.depth    = 0,
  		.calltime = time,
  		.rettime  = time,
  	};
  
  	__trace_graph_entry(tr, &ent, flags, pc);
  	__trace_graph_return(tr, &ret, flags, pc);
  }
  
  void
  trace_graph_function(struct trace_array *tr,
  		unsigned long ip, unsigned long parent_ip,
  		unsigned long flags, int pc)
  {
0a772620a   Jiri Olsa   tracing: Make gra...
287
288
  	__trace_graph_function(tr, ip, flags, pc);
  }
62b915f10   Jiri Olsa   tracing: Add grap...
289
  void __trace_graph_return(struct trace_array *tr,
1a0799a8f   Frederic Weisbecker   tracing/function-...
290
291
292
293
294
295
  				struct ftrace_graph_ret *trace,
  				unsigned long flags,
  				int pc)
  {
  	struct ftrace_event_call *call = &event_funcgraph_exit;
  	struct ring_buffer_event *event;
e77405ad8   Steven Rostedt   tracing: pass aro...
296
  	struct ring_buffer *buffer = tr->buffer;
1a0799a8f   Frederic Weisbecker   tracing/function-...
297
  	struct ftrace_graph_ret_entry *entry;
dd17c8f72   Rusty Russell   percpu: remove pe...
298
  	if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
1a0799a8f   Frederic Weisbecker   tracing/function-...
299
  		return;
e77405ad8   Steven Rostedt   tracing: pass aro...
300
  	event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET,
1a0799a8f   Frederic Weisbecker   tracing/function-...
301
302
303
304
305
  					  sizeof(*entry), flags, pc);
  	if (!event)
  		return;
  	entry	= ring_buffer_event_data(event);
  	entry->ret				= *trace;
e77405ad8   Steven Rostedt   tracing: pass aro...
306
307
  	if (!filter_current_check_discard(buffer, call, entry, event))
  		ring_buffer_unlock_commit(buffer, event);
1a0799a8f   Frederic Weisbecker   tracing/function-...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  }
  
  void trace_graph_return(struct ftrace_graph_ret *trace)
  {
  	struct trace_array *tr = graph_array;
  	struct trace_array_cpu *data;
  	unsigned long flags;
  	long disabled;
  	int cpu;
  	int pc;
  
  	local_irq_save(flags);
  	cpu = raw_smp_processor_id();
  	data = tr->data[cpu];
  	disabled = atomic_inc_return(&data->disabled);
  	if (likely(disabled == 1)) {
  		pc = preempt_count();
  		__trace_graph_return(tr, trace, flags, pc);
  	}
1a0799a8f   Frederic Weisbecker   tracing/function-...
327
328
329
  	atomic_dec(&data->disabled);
  	local_irq_restore(flags);
  }
24a53652e   Frederic Weisbecker   tracing: Drop the...
330
331
332
333
334
335
336
337
  void set_graph_array(struct trace_array *tr)
  {
  	graph_array = tr;
  
  	/* Make graph_array visible before we start tracing */
  
  	smp_mb();
  }
0e9501735   Tim Bird   function-graph: A...
338
339
340
341
342
343
344
345
  void trace_graph_thresh_return(struct ftrace_graph_ret *trace)
  {
  	if (tracing_thresh &&
  	    (trace->rettime - trace->calltime < tracing_thresh))
  		return;
  	else
  		trace_graph_return(trace);
  }
fb52607af   Frederic Weisbecker   tracing/function-...
346
347
  static int graph_trace_init(struct trace_array *tr)
  {
1a0799a8f   Frederic Weisbecker   tracing/function-...
348
  	int ret;
24a53652e   Frederic Weisbecker   tracing: Drop the...
349
  	set_graph_array(tr);
0e9501735   Tim Bird   function-graph: A...
350
351
352
353
354
355
  	if (tracing_thresh)
  		ret = register_ftrace_graph(&trace_graph_thresh_return,
  					    &trace_graph_thresh_entry);
  	else
  		ret = register_ftrace_graph(&trace_graph_return,
  					    &trace_graph_entry);
660c7f9be   Steven Rostedt   ftrace: add threa...
356
357
358
359
360
  	if (ret)
  		return ret;
  	tracing_start_cmdline_record();
  
  	return 0;
fb52607af   Frederic Weisbecker   tracing/function-...
361
362
363
364
  }
  
  static void graph_trace_reset(struct trace_array *tr)
  {
660c7f9be   Steven Rostedt   ftrace: add threa...
365
366
  	tracing_stop_cmdline_record();
  	unregister_ftrace_graph();
fb52607af   Frederic Weisbecker   tracing/function-...
367
  }
0c9e6f639   Lai Jiangshan   tracing: Simplify...
368
  static int max_bytes_for_cpu;
1a056155e   Frederic Weisbecker   tracing/function-...
369
370
371
372
  
  static enum print_line_t
  print_graph_cpu(struct trace_seq *s, int cpu)
  {
1a056155e   Frederic Weisbecker   tracing/function-...
373
  	int ret;
1a056155e   Frederic Weisbecker   tracing/function-...
374

d51090b34   Ingo Molnar   tracing/function-...
375
376
377
378
379
  	/*
  	 * Start with a space character - to make it stand out
  	 * to the right a bit when trace output is pasted into
  	 * email:
  	 */
0c9e6f639   Lai Jiangshan   tracing: Simplify...
380
  	ret = trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu);
1a056155e   Frederic Weisbecker   tracing/function-...
381
  	if (!ret)
d51090b34   Ingo Molnar   tracing/function-...
382
  		return TRACE_TYPE_PARTIAL_LINE;
1a056155e   Frederic Weisbecker   tracing/function-...
383
384
  	return TRACE_TYPE_HANDLED;
  }
11e84acc4   Frederic Weisbecker   tracing/function-...
385
386
387
388
389
  #define TRACE_GRAPH_PROCINFO_LENGTH	14
  
  static enum print_line_t
  print_graph_proc(struct trace_seq *s, pid_t pid)
  {
4ca530852   Steven Rostedt   tracing: protect ...
390
  	char comm[TASK_COMM_LEN];
11e84acc4   Frederic Weisbecker   tracing/function-...
391
392
  	/* sign + log10(MAX_INT) + '\0' */
  	char pid_str[11];
4ca530852   Steven Rostedt   tracing: protect ...
393
394
395
396
  	int spaces = 0;
  	int ret;
  	int len;
  	int i;
11e84acc4   Frederic Weisbecker   tracing/function-...
397

4ca530852   Steven Rostedt   tracing: protect ...
398
  	trace_find_cmdline(pid, comm);
11e84acc4   Frederic Weisbecker   tracing/function-...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  	comm[7] = '\0';
  	sprintf(pid_str, "%d", pid);
  
  	/* 1 stands for the "-" character */
  	len = strlen(comm) + strlen(pid_str) + 1;
  
  	if (len < TRACE_GRAPH_PROCINFO_LENGTH)
  		spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
  
  	/* First spaces to align center */
  	for (i = 0; i < spaces / 2; i++) {
  		ret = trace_seq_printf(s, " ");
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
  
  	ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	/* Last spaces to align center */
  	for (i = 0; i < spaces - (spaces / 2); i++) {
  		ret = trace_seq_printf(s, " ");
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
  	return TRACE_TYPE_HANDLED;
  }
1a056155e   Frederic Weisbecker   tracing/function-...
427

49ff59039   Steven Rostedt   tracing: add late...
428
429
430
  static enum print_line_t
  print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
  {
f81c972d2   Steven Rostedt   tracing: consolid...
431
  	if (!trace_seq_putc(s, ' '))
637e7e864   Steven Rostedt   tracing: add lock...
432
  		return 0;
f81c972d2   Steven Rostedt   tracing: consolid...
433
  	return trace_print_lat_fmt(s, entry);
49ff59039   Steven Rostedt   tracing: add late...
434
  }
287b6e68c   Frederic Weisbecker   tracing/function-...
435
  /* If the pid changed since the last trace, output this event */
11e84acc4   Frederic Weisbecker   tracing/function-...
436
  static enum print_line_t
2fbcdb35a   Steven Rostedt   function-graph: c...
437
  verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
287b6e68c   Frederic Weisbecker   tracing/function-...
438
  {
d51090b34   Ingo Molnar   tracing/function-...
439
  	pid_t prev_pid;
9005f3ebe   Frederic Weisbecker   tracing/function-...
440
  	pid_t *last_pid;
d51090b34   Ingo Molnar   tracing/function-...
441
  	int ret;
660c7f9be   Steven Rostedt   ftrace: add threa...
442

2fbcdb35a   Steven Rostedt   function-graph: c...
443
  	if (!data)
9005f3ebe   Frederic Weisbecker   tracing/function-...
444
  		return TRACE_TYPE_HANDLED;
be1eca393   Jiri Olsa   tracing: Fix func...
445
  	last_pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
9005f3ebe   Frederic Weisbecker   tracing/function-...
446
447
  
  	if (*last_pid == pid)
11e84acc4   Frederic Weisbecker   tracing/function-...
448
  		return TRACE_TYPE_HANDLED;
fb52607af   Frederic Weisbecker   tracing/function-...
449

9005f3ebe   Frederic Weisbecker   tracing/function-...
450
451
  	prev_pid = *last_pid;
  	*last_pid = pid;
d51090b34   Ingo Molnar   tracing/function-...
452

9005f3ebe   Frederic Weisbecker   tracing/function-...
453
454
  	if (prev_pid == -1)
  		return TRACE_TYPE_HANDLED;
d51090b34   Ingo Molnar   tracing/function-...
455
456
457
458
459
460
461
462
463
  /*
   * Context-switch trace line:
  
   ------------------------------------------
   | 1)  migration/0--1  =>  sshd-1755
   ------------------------------------------
  
   */
  	ret = trace_seq_printf(s,
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
464
465
  		" ------------------------------------------
  ");
11e84acc4   Frederic Weisbecker   tracing/function-...
466
  	if (!ret)
810dc7326   Wenji Huang   tracing: provide ...
467
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
468
469
470
  
  	ret = print_graph_cpu(s, cpu);
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
810dc7326   Wenji Huang   tracing: provide ...
471
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
472
473
474
  
  	ret = print_graph_proc(s, prev_pid);
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
810dc7326   Wenji Huang   tracing: provide ...
475
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
476
477
478
  
  	ret = trace_seq_printf(s, " => ");
  	if (!ret)
810dc7326   Wenji Huang   tracing: provide ...
479
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
480
481
482
  
  	ret = print_graph_proc(s, pid);
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
810dc7326   Wenji Huang   tracing: provide ...
483
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
484
485
486
487
488
489
490
  
  	ret = trace_seq_printf(s,
  		"
   ------------------------------------------
  
  ");
  	if (!ret)
810dc7326   Wenji Huang   tracing: provide ...
491
  		return TRACE_TYPE_PARTIAL_LINE;
11e84acc4   Frederic Weisbecker   tracing/function-...
492

810dc7326   Wenji Huang   tracing: provide ...
493
  	return TRACE_TYPE_HANDLED;
287b6e68c   Frederic Weisbecker   tracing/function-...
494
  }
b91facc36   Frederic Weisbecker   tracing/function-...
495
496
  static struct ftrace_graph_ret_entry *
  get_return_for_leaf(struct trace_iterator *iter,
83a8df618   Frederic Weisbecker   tracing/function-...
497
498
  		struct ftrace_graph_ent_entry *curr)
  {
be1eca393   Jiri Olsa   tracing: Fix func...
499
500
  	struct fgraph_data *data = iter->private;
  	struct ring_buffer_iter *ring_iter = NULL;
83a8df618   Frederic Weisbecker   tracing/function-...
501
502
  	struct ring_buffer_event *event;
  	struct ftrace_graph_ret_entry *next;
be1eca393   Jiri Olsa   tracing: Fix func...
503
504
505
506
507
508
509
510
  	/*
  	 * If the previous output failed to write to the seq buffer,
  	 * then we just reuse the data from before.
  	 */
  	if (data && data->failed) {
  		curr = &data->ent;
  		next = &data->ret;
  	} else {
83a8df618   Frederic Weisbecker   tracing/function-...
511

be1eca393   Jiri Olsa   tracing: Fix func...
512
513
514
515
516
517
518
519
520
521
  		ring_iter = iter->buffer_iter[iter->cpu];
  
  		/* First peek to compare current entry and the next one */
  		if (ring_iter)
  			event = ring_buffer_iter_peek(ring_iter, NULL);
  		else {
  			/*
  			 * We need to consume the current entry to see
  			 * the next one.
  			 */
66a8cb95e   Steven Rostedt   ring-buffer: Add ...
522
523
  			ring_buffer_consume(iter->tr->buffer, iter->cpu,
  					    NULL, NULL);
be1eca393   Jiri Olsa   tracing: Fix func...
524
  			event = ring_buffer_peek(iter->tr->buffer, iter->cpu,
66a8cb95e   Steven Rostedt   ring-buffer: Add ...
525
  						 NULL, NULL);
be1eca393   Jiri Olsa   tracing: Fix func...
526
  		}
83a8df618   Frederic Weisbecker   tracing/function-...
527

be1eca393   Jiri Olsa   tracing: Fix func...
528
529
530
531
  		if (!event)
  			return NULL;
  
  		next = ring_buffer_event_data(event);
83a8df618   Frederic Weisbecker   tracing/function-...
532

be1eca393   Jiri Olsa   tracing: Fix func...
533
534
535
536
537
538
  		if (data) {
  			/*
  			 * Save current and next entries for later reference
  			 * if the output fails.
  			 */
  			data->ent = *curr;
575570f02   Shaohua Li   tracing: Fix an u...
539
540
541
542
543
544
545
546
547
  			/*
  			 * If the next event is not a return type, then
  			 * we only care about what type it is. Otherwise we can
  			 * safely copy the entire event.
  			 */
  			if (next->ent.type == TRACE_GRAPH_RET)
  				data->ret = *next;
  			else
  				data->ret.ent.type = next->ent.type;
be1eca393   Jiri Olsa   tracing: Fix func...
548
549
  		}
  	}
83a8df618   Frederic Weisbecker   tracing/function-...
550
551
  
  	if (next->ent.type != TRACE_GRAPH_RET)
b91facc36   Frederic Weisbecker   tracing/function-...
552
  		return NULL;
83a8df618   Frederic Weisbecker   tracing/function-...
553
554
555
  
  	if (curr->ent.pid != next->ent.pid ||
  			curr->graph_ent.func != next->ret.func)
b91facc36   Frederic Weisbecker   tracing/function-...
556
  		return NULL;
83a8df618   Frederic Weisbecker   tracing/function-...
557

b91facc36   Frederic Weisbecker   tracing/function-...
558
559
560
561
562
  	/* this is a leaf, now advance the iterator */
  	if (ring_iter)
  		ring_buffer_read(ring_iter, NULL);
  
  	return next;
83a8df618   Frederic Weisbecker   tracing/function-...
563
  }
d1f9cbd78   Frederic Weisbecker   tracing/function-...
564
565
566
567
568
569
570
571
572
573
  static int print_graph_abs_time(u64 t, struct trace_seq *s)
  {
  	unsigned long usecs_rem;
  
  	usecs_rem = do_div(t, NSEC_PER_SEC);
  	usecs_rem /= 1000;
  
  	return trace_seq_printf(s, "%5lu.%06lu |  ",
  			(unsigned long)t, usecs_rem);
  }
f8b755ac8   Frederic Weisbecker   tracing/function-...
574
  static enum print_line_t
d1f9cbd78   Frederic Weisbecker   tracing/function-...
575
  print_graph_irq(struct trace_iterator *iter, unsigned long addr,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
576
  		enum trace_type type, int cpu, pid_t pid, u32 flags)
f8b755ac8   Frederic Weisbecker   tracing/function-...
577
578
  {
  	int ret;
d1f9cbd78   Frederic Weisbecker   tracing/function-...
579
  	struct trace_seq *s = &iter->seq;
f8b755ac8   Frederic Weisbecker   tracing/function-...
580
581
582
583
  
  	if (addr < (unsigned long)__irqentry_text_start ||
  		addr >= (unsigned long)__irqentry_text_end)
  		return TRACE_TYPE_UNHANDLED;
749230b06   Jiri Olsa   tracing, function...
584
585
586
587
588
589
590
  	if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
  		/* Absolute time */
  		if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
  			ret = print_graph_abs_time(iter->ts, s);
  			if (!ret)
  				return TRACE_TYPE_PARTIAL_LINE;
  		}
d1f9cbd78   Frederic Weisbecker   tracing/function-...
591

749230b06   Jiri Olsa   tracing, function...
592
593
594
595
596
597
  		/* Cpu */
  		if (flags & TRACE_GRAPH_PRINT_CPU) {
  			ret = print_graph_cpu(s, cpu);
  			if (ret == TRACE_TYPE_PARTIAL_LINE)
  				return TRACE_TYPE_PARTIAL_LINE;
  		}
49ff59039   Steven Rostedt   tracing: add late...
598

749230b06   Jiri Olsa   tracing, function...
599
600
601
602
603
604
605
606
607
  		/* Proc */
  		if (flags & TRACE_GRAPH_PRINT_PROC) {
  			ret = print_graph_proc(s, pid);
  			if (ret == TRACE_TYPE_PARTIAL_LINE)
  				return TRACE_TYPE_PARTIAL_LINE;
  			ret = trace_seq_printf(s, " | ");
  			if (!ret)
  				return TRACE_TYPE_PARTIAL_LINE;
  		}
9005f3ebe   Frederic Weisbecker   tracing/function-...
608
  	}
f8b755ac8   Frederic Weisbecker   tracing/function-...
609

9005f3ebe   Frederic Weisbecker   tracing/function-...
610
  	/* No overhead */
ffeb80fc3   Jiri Olsa   tracing, function...
611
612
613
  	ret = print_graph_duration(DURATION_FILL_START, s, flags);
  	if (ret != TRACE_TYPE_HANDLED)
  		return ret;
f8b755ac8   Frederic Weisbecker   tracing/function-...
614

9005f3ebe   Frederic Weisbecker   tracing/function-...
615
616
617
618
619
620
621
  	if (type == TRACE_GRAPH_ENT)
  		ret = trace_seq_printf(s, "==========>");
  	else
  		ret = trace_seq_printf(s, "<==========");
  
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
ffeb80fc3   Jiri Olsa   tracing, function...
622
623
624
  	ret = print_graph_duration(DURATION_FILL_END, s, flags);
  	if (ret != TRACE_TYPE_HANDLED)
  		return ret;
9005f3ebe   Frederic Weisbecker   tracing/function-...
625
626
  	ret = trace_seq_printf(s, "
  ");
f8b755ac8   Frederic Weisbecker   tracing/function-...
627

f8b755ac8   Frederic Weisbecker   tracing/function-...
628
629
630
631
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  	return TRACE_TYPE_HANDLED;
  }
83a8df618   Frederic Weisbecker   tracing/function-...
632

0706f1c48   Steven Rostedt   tracing: adding f...
633
634
  enum print_line_t
  trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
83a8df618   Frederic Weisbecker   tracing/function-...
635
636
  {
  	unsigned long nsecs_rem = do_div(duration, 1000);
166d3c799   Frederic Weisbecker   tracing/function-...
637
638
639
640
641
642
643
644
645
  	/* log10(ULONG_MAX) + '\0' */
  	char msecs_str[21];
  	char nsecs_str[5];
  	int ret, len;
  	int i;
  
  	sprintf(msecs_str, "%lu", (unsigned long) duration);
  
  	/* Print msecs */
9005f3ebe   Frederic Weisbecker   tracing/function-...
646
  	ret = trace_seq_printf(s, "%s", msecs_str);
166d3c799   Frederic Weisbecker   tracing/function-...
647
648
649
650
651
652
653
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	len = strlen(msecs_str);
  
  	/* Print nsecs (we don't want to exceed 7 numbers) */
  	if (len < 7) {
14cae9bd2   Borislav Petkov   tracing: Fix func...
654
655
656
  		size_t slen = min_t(size_t, sizeof(nsecs_str), 8UL - len);
  
  		snprintf(nsecs_str, slen, "%03lu", nsecs_rem);
166d3c799   Frederic Weisbecker   tracing/function-...
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
  		ret = trace_seq_printf(s, ".%s", nsecs_str);
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  		len += strlen(nsecs_str);
  	}
  
  	ret = trace_seq_printf(s, " us ");
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	/* Print remaining spaces to fit the row's width */
  	for (i = len; i < 7; i++) {
  		ret = trace_seq_printf(s, " ");
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
0706f1c48   Steven Rostedt   tracing: adding f...
673
674
675
676
  	return TRACE_TYPE_HANDLED;
  }
  
  static enum print_line_t
ffeb80fc3   Jiri Olsa   tracing, function...
677
678
  print_graph_duration(unsigned long long duration, struct trace_seq *s,
  		     u32 flags)
0706f1c48   Steven Rostedt   tracing: adding f...
679
  {
ffeb80fc3   Jiri Olsa   tracing, function...
680
  	int ret = -1;
749230b06   Jiri Olsa   tracing, function...
681
682
683
  	if (!(flags & TRACE_GRAPH_PRINT_DURATION) ||
  	    !(trace_flags & TRACE_ITER_CONTEXT_INFO))
  			return TRACE_TYPE_HANDLED;
ffeb80fc3   Jiri Olsa   tracing, function...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  
  	/* No real adata, just filling the column with spaces */
  	switch (duration) {
  	case DURATION_FILL_FULL:
  		ret = trace_seq_printf(s, "              |  ");
  		return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
  	case DURATION_FILL_START:
  		ret = trace_seq_printf(s, "  ");
  		return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
  	case DURATION_FILL_END:
  		ret = trace_seq_printf(s, " |");
  		return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
  	}
  
  	/* Signal a overhead of time execution to the output */
  	if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
  		/* Duration exceeded 100 msecs */
  		if (duration > 100000ULL)
  			ret = trace_seq_printf(s, "! ");
  		/* Duration exceeded 10 msecs */
  		else if (duration > 10000ULL)
  			ret = trace_seq_printf(s, "+ ");
  	}
  
  	/*
  	 * The -1 means we either did not exceed the duration tresholds
  	 * or we dont want to print out the overhead. Either way we need
  	 * to fill out the space.
  	 */
  	if (ret == -1)
  		ret = trace_seq_printf(s, "  ");
  
  	/* Catching here any failure happenned above */
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
0706f1c48   Steven Rostedt   tracing: adding f...
719
720
721
722
  
  	ret = trace_print_graph_duration(duration, s);
  	if (ret != TRACE_TYPE_HANDLED)
  		return ret;
166d3c799   Frederic Weisbecker   tracing/function-...
723
724
725
726
  
  	ret = trace_seq_printf(s, "|  ");
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
166d3c799   Frederic Weisbecker   tracing/function-...
727

0706f1c48   Steven Rostedt   tracing: adding f...
728
  	return TRACE_TYPE_HANDLED;
83a8df618   Frederic Weisbecker   tracing/function-...
729
  }
83a8df618   Frederic Weisbecker   tracing/function-...
730
  /* Case of a leaf function on its call entry */
287b6e68c   Frederic Weisbecker   tracing/function-...
731
  static enum print_line_t
83a8df618   Frederic Weisbecker   tracing/function-...
732
  print_graph_entry_leaf(struct trace_iterator *iter,
b91facc36   Frederic Weisbecker   tracing/function-...
733
  		struct ftrace_graph_ent_entry *entry,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
734
735
  		struct ftrace_graph_ret_entry *ret_entry,
  		struct trace_seq *s, u32 flags)
fb52607af   Frederic Weisbecker   tracing/function-...
736
  {
2fbcdb35a   Steven Rostedt   function-graph: c...
737
  	struct fgraph_data *data = iter->private;
83a8df618   Frederic Weisbecker   tracing/function-...
738
  	struct ftrace_graph_ret *graph_ret;
83a8df618   Frederic Weisbecker   tracing/function-...
739
740
  	struct ftrace_graph_ent *call;
  	unsigned long long duration;
fb52607af   Frederic Weisbecker   tracing/function-...
741
  	int ret;
1a056155e   Frederic Weisbecker   tracing/function-...
742
  	int i;
fb52607af   Frederic Weisbecker   tracing/function-...
743

83a8df618   Frederic Weisbecker   tracing/function-...
744
745
746
  	graph_ret = &ret_entry->ret;
  	call = &entry->graph_ent;
  	duration = graph_ret->rettime - graph_ret->calltime;
2fbcdb35a   Steven Rostedt   function-graph: c...
747
  	if (data) {
f1c7f517a   Steven Rostedt   ftrace: Add funct...
748
  		struct fgraph_cpu_data *cpu_data;
2fbcdb35a   Steven Rostedt   function-graph: c...
749
  		int cpu = iter->cpu;
f1c7f517a   Steven Rostedt   ftrace: Add funct...
750
751
  
  		cpu_data = per_cpu_ptr(data->cpu_data, cpu);
2fbcdb35a   Steven Rostedt   function-graph: c...
752
753
754
755
756
757
  
  		/*
  		 * Comments display at + 1 to depth. Since
  		 * this is a leaf function, keep the comments
  		 * equal to this depth.
  		 */
f1c7f517a   Steven Rostedt   ftrace: Add funct...
758
759
760
761
762
  		cpu_data->depth = call->depth - 1;
  
  		/* No need to keep this function around for this depth */
  		if (call->depth < FTRACE_RETFUNC_DEPTH)
  			cpu_data->enter_funcs[call->depth] = 0;
2fbcdb35a   Steven Rostedt   function-graph: c...
763
  	}
ffeb80fc3   Jiri Olsa   tracing, function...
764
765
766
  	/* Overhead and duration */
  	ret = print_graph_duration(duration, s, flags);
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
9005f3ebe   Frederic Weisbecker   tracing/function-...
767
  		return TRACE_TYPE_PARTIAL_LINE;
1a056155e   Frederic Weisbecker   tracing/function-...
768

83a8df618   Frederic Weisbecker   tracing/function-...
769
770
771
772
773
774
  	/* Function */
  	for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
  		ret = trace_seq_printf(s, " ");
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
b375a11a2   Steven Rostedt   tracing: switch f...
775
776
  	ret = trace_seq_printf(s, "%ps();
  ", (void *)call->func);
83a8df618   Frederic Weisbecker   tracing/function-...
777
778
779
780
781
782
783
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	return TRACE_TYPE_HANDLED;
  }
  
  static enum print_line_t
2fbcdb35a   Steven Rostedt   function-graph: c...
784
785
  print_graph_entry_nested(struct trace_iterator *iter,
  			 struct ftrace_graph_ent_entry *entry,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
786
  			 struct trace_seq *s, int cpu, u32 flags)
83a8df618   Frederic Weisbecker   tracing/function-...
787
  {
83a8df618   Frederic Weisbecker   tracing/function-...
788
  	struct ftrace_graph_ent *call = &entry->graph_ent;
2fbcdb35a   Steven Rostedt   function-graph: c...
789
790
791
792
793
  	struct fgraph_data *data = iter->private;
  	int ret;
  	int i;
  
  	if (data) {
f1c7f517a   Steven Rostedt   ftrace: Add funct...
794
  		struct fgraph_cpu_data *cpu_data;
2fbcdb35a   Steven Rostedt   function-graph: c...
795
  		int cpu = iter->cpu;
2fbcdb35a   Steven Rostedt   function-graph: c...
796

f1c7f517a   Steven Rostedt   ftrace: Add funct...
797
798
799
800
801
802
  		cpu_data = per_cpu_ptr(data->cpu_data, cpu);
  		cpu_data->depth = call->depth;
  
  		/* Save this function pointer to see if the exit matches */
  		if (call->depth < FTRACE_RETFUNC_DEPTH)
  			cpu_data->enter_funcs[call->depth] = call->func;
2fbcdb35a   Steven Rostedt   function-graph: c...
803
  	}
83a8df618   Frederic Weisbecker   tracing/function-...
804

9005f3ebe   Frederic Weisbecker   tracing/function-...
805
  	/* No time */
ffeb80fc3   Jiri Olsa   tracing, function...
806
807
808
  	ret = print_graph_duration(DURATION_FILL_FULL, s, flags);
  	if (ret != TRACE_TYPE_HANDLED)
  		return ret;
f8b755ac8   Frederic Weisbecker   tracing/function-...
809

83a8df618   Frederic Weisbecker   tracing/function-...
810
  	/* Function */
287b6e68c   Frederic Weisbecker   tracing/function-...
811
812
  	for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
  		ret = trace_seq_printf(s, " ");
fb52607af   Frederic Weisbecker   tracing/function-...
813
814
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
287b6e68c   Frederic Weisbecker   tracing/function-...
815
  	}
b375a11a2   Steven Rostedt   tracing: switch f...
816
817
  	ret = trace_seq_printf(s, "%ps() {
  ", (void *)call->func);
83a8df618   Frederic Weisbecker   tracing/function-...
818
819
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
b91facc36   Frederic Weisbecker   tracing/function-...
820
821
822
823
824
  	/*
  	 * we already consumed the current entry to check the next one
  	 * and see if this is a leaf.
  	 */
  	return TRACE_TYPE_NO_CONSUME;
287b6e68c   Frederic Weisbecker   tracing/function-...
825
826
827
  }
  
  static enum print_line_t
ac5f6c968   Steven Rostedt   function-graph: c...
828
  print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
829
  		     int type, unsigned long addr, u32 flags)
83a8df618   Frederic Weisbecker   tracing/function-...
830
  {
2fbcdb35a   Steven Rostedt   function-graph: c...
831
  	struct fgraph_data *data = iter->private;
83a8df618   Frederic Weisbecker   tracing/function-...
832
  	struct trace_entry *ent = iter->ent;
ac5f6c968   Steven Rostedt   function-graph: c...
833
834
  	int cpu = iter->cpu;
  	int ret;
83a8df618   Frederic Weisbecker   tracing/function-...
835

1a056155e   Frederic Weisbecker   tracing/function-...
836
  	/* Pid */
2fbcdb35a   Steven Rostedt   function-graph: c...
837
  	if (verif_pid(s, ent->pid, cpu, data) == TRACE_TYPE_PARTIAL_LINE)
9005f3ebe   Frederic Weisbecker   tracing/function-...
838
  		return TRACE_TYPE_PARTIAL_LINE;
ac5f6c968   Steven Rostedt   function-graph: c...
839
840
  	if (type) {
  		/* Interrupt */
d7a8d9e90   Jiri Olsa   tracing: Have gra...
841
  		ret = print_graph_irq(iter, addr, type, cpu, ent->pid, flags);
ac5f6c968   Steven Rostedt   function-graph: c...
842
843
844
  		if (ret == TRACE_TYPE_PARTIAL_LINE)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
83a8df618   Frederic Weisbecker   tracing/function-...
845

749230b06   Jiri Olsa   tracing, function...
846
847
  	if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
  		return 0;
9005f3ebe   Frederic Weisbecker   tracing/function-...
848
  	/* Absolute time */
d7a8d9e90   Jiri Olsa   tracing: Have gra...
849
  	if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
9005f3ebe   Frederic Weisbecker   tracing/function-...
850
851
852
853
  		ret = print_graph_abs_time(iter->ts, s);
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
1a056155e   Frederic Weisbecker   tracing/function-...
854
  	/* Cpu */
d7a8d9e90   Jiri Olsa   tracing: Have gra...
855
  	if (flags & TRACE_GRAPH_PRINT_CPU) {
1a056155e   Frederic Weisbecker   tracing/function-...
856
  		ret = print_graph_cpu(s, cpu);
11e84acc4   Frederic Weisbecker   tracing/function-...
857
858
859
860
861
  		if (ret == TRACE_TYPE_PARTIAL_LINE)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
  
  	/* Proc */
d7a8d9e90   Jiri Olsa   tracing: Have gra...
862
  	if (flags & TRACE_GRAPH_PRINT_PROC) {
00a8bf859   Ingo Molnar   tracing/function-...
863
  		ret = print_graph_proc(s, ent->pid);
11e84acc4   Frederic Weisbecker   tracing/function-...
864
865
866
867
  		if (ret == TRACE_TYPE_PARTIAL_LINE)
  			return TRACE_TYPE_PARTIAL_LINE;
  
  		ret = trace_seq_printf(s, " | ");
1a056155e   Frederic Weisbecker   tracing/function-...
868
869
870
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
83a8df618   Frederic Weisbecker   tracing/function-...
871

49ff59039   Steven Rostedt   tracing: add late...
872
873
874
875
876
877
  	/* Latency format */
  	if (trace_flags & TRACE_ITER_LATENCY_FMT) {
  		ret = print_graph_lat_fmt(s, ent);
  		if (ret == TRACE_TYPE_PARTIAL_LINE)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
ac5f6c968   Steven Rostedt   function-graph: c...
878
879
  	return 0;
  }
2bd16212b   Jiri Olsa   tracing: Add func...
880
881
882
883
884
  /*
   * Entry check for irq code
   *
   * returns 1 if
   *  - we are inside irq code
25985edce   Lucas De Marchi   Fix common misspe...
885
   *  - we just entered irq code
2bd16212b   Jiri Olsa   tracing: Add func...
886
887
888
889
890
891
892
893
894
895
   *
   * retunns 0 if
   *  - funcgraph-interrupts option is set
   *  - we are not inside irq code
   */
  static int
  check_irq_entry(struct trace_iterator *iter, u32 flags,
  		unsigned long addr, int depth)
  {
  	int cpu = iter->cpu;
a9d61173d   Jiri Olsa   tracing: Add prop...
896
  	int *depth_irq;
2bd16212b   Jiri Olsa   tracing: Add func...
897
  	struct fgraph_data *data = iter->private;
2bd16212b   Jiri Olsa   tracing: Add func...
898

a9d61173d   Jiri Olsa   tracing: Add prop...
899
900
901
902
903
904
905
  	/*
  	 * If we are either displaying irqs, or we got called as
  	 * a graph event and private data does not exist,
  	 * then we bypass the irq check.
  	 */
  	if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
  	    (!data))
2bd16212b   Jiri Olsa   tracing: Add func...
906
  		return 0;
a9d61173d   Jiri Olsa   tracing: Add prop...
907
  	depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
2bd16212b   Jiri Olsa   tracing: Add func...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
  	/*
  	 * We are inside the irq code
  	 */
  	if (*depth_irq >= 0)
  		return 1;
  
  	if ((addr < (unsigned long)__irqentry_text_start) ||
  	    (addr >= (unsigned long)__irqentry_text_end))
  		return 0;
  
  	/*
  	 * We are entering irq code.
  	 */
  	*depth_irq = depth;
  	return 1;
  }
  
  /*
   * Return check for irq code
   *
   * returns 1 if
   *  - we are inside irq code
   *  - we just left irq code
   *
   * returns 0 if
   *  - funcgraph-interrupts option is set
   *  - we are not inside irq code
   */
  static int
  check_irq_return(struct trace_iterator *iter, u32 flags, int depth)
  {
  	int cpu = iter->cpu;
a9d61173d   Jiri Olsa   tracing: Add prop...
940
  	int *depth_irq;
2bd16212b   Jiri Olsa   tracing: Add func...
941
  	struct fgraph_data *data = iter->private;
2bd16212b   Jiri Olsa   tracing: Add func...
942

a9d61173d   Jiri Olsa   tracing: Add prop...
943
944
945
946
947
948
949
  	/*
  	 * If we are either displaying irqs, or we got called as
  	 * a graph event and private data does not exist,
  	 * then we bypass the irq check.
  	 */
  	if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
  	    (!data))
2bd16212b   Jiri Olsa   tracing: Add func...
950
  		return 0;
a9d61173d   Jiri Olsa   tracing: Add prop...
951
  	depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
2bd16212b   Jiri Olsa   tracing: Add func...
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
  	/*
  	 * We are not inside the irq code.
  	 */
  	if (*depth_irq == -1)
  		return 0;
  
  	/*
  	 * We are inside the irq code, and this is returning entry.
  	 * Let's not trace it and clear the entry depth, since
  	 * we are out of irq code.
  	 *
  	 * This condition ensures that we 'leave the irq code' once
  	 * we are out of the entry depth. Thus protecting us from
  	 * the RETURN entry loss.
  	 */
  	if (*depth_irq >= depth) {
  		*depth_irq = -1;
  		return 1;
  	}
  
  	/*
  	 * We are inside the irq code, and this is not the entry.
  	 */
  	return 1;
  }
ac5f6c968   Steven Rostedt   function-graph: c...
977
978
  static enum print_line_t
  print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
979
  			struct trace_iterator *iter, u32 flags)
ac5f6c968   Steven Rostedt   function-graph: c...
980
  {
be1eca393   Jiri Olsa   tracing: Fix func...
981
  	struct fgraph_data *data = iter->private;
ac5f6c968   Steven Rostedt   function-graph: c...
982
983
  	struct ftrace_graph_ent *call = &field->graph_ent;
  	struct ftrace_graph_ret_entry *leaf_ret;
be1eca393   Jiri Olsa   tracing: Fix func...
984
985
  	static enum print_line_t ret;
  	int cpu = iter->cpu;
ac5f6c968   Steven Rostedt   function-graph: c...
986

2bd16212b   Jiri Olsa   tracing: Add func...
987
988
  	if (check_irq_entry(iter, flags, call->func, call->depth))
  		return TRACE_TYPE_HANDLED;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
989
  	if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags))
ac5f6c968   Steven Rostedt   function-graph: c...
990
  		return TRACE_TYPE_PARTIAL_LINE;
b91facc36   Frederic Weisbecker   tracing/function-...
991
992
  	leaf_ret = get_return_for_leaf(iter, field);
  	if (leaf_ret)
d7a8d9e90   Jiri Olsa   tracing: Have gra...
993
  		ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags);
83a8df618   Frederic Weisbecker   tracing/function-...
994
  	else
d7a8d9e90   Jiri Olsa   tracing: Have gra...
995
  		ret = print_graph_entry_nested(iter, field, s, cpu, flags);
83a8df618   Frederic Weisbecker   tracing/function-...
996

be1eca393   Jiri Olsa   tracing: Fix func...
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  	if (data) {
  		/*
  		 * If we failed to write our output, then we need to make
  		 * note of it. Because we already consumed our entry.
  		 */
  		if (s->full) {
  			data->failed = 1;
  			data->cpu = cpu;
  		} else
  			data->failed = 0;
  	}
  
  	return ret;
83a8df618   Frederic Weisbecker   tracing/function-...
1010
1011
1012
  }
  
  static enum print_line_t
287b6e68c   Frederic Weisbecker   tracing/function-...
1013
  print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1014
1015
  		   struct trace_entry *ent, struct trace_iterator *iter,
  		   u32 flags)
287b6e68c   Frederic Weisbecker   tracing/function-...
1016
  {
83a8df618   Frederic Weisbecker   tracing/function-...
1017
  	unsigned long long duration = trace->rettime - trace->calltime;
2fbcdb35a   Steven Rostedt   function-graph: c...
1018
1019
1020
  	struct fgraph_data *data = iter->private;
  	pid_t pid = ent->pid;
  	int cpu = iter->cpu;
f1c7f517a   Steven Rostedt   ftrace: Add funct...
1021
  	int func_match = 1;
2fbcdb35a   Steven Rostedt   function-graph: c...
1022
1023
  	int ret;
  	int i;
2bd16212b   Jiri Olsa   tracing: Add func...
1024
1025
  	if (check_irq_return(iter, flags, trace->depth))
  		return TRACE_TYPE_HANDLED;
2fbcdb35a   Steven Rostedt   function-graph: c...
1026
  	if (data) {
f1c7f517a   Steven Rostedt   ftrace: Add funct...
1027
1028
1029
1030
  		struct fgraph_cpu_data *cpu_data;
  		int cpu = iter->cpu;
  
  		cpu_data = per_cpu_ptr(data->cpu_data, cpu);
2fbcdb35a   Steven Rostedt   function-graph: c...
1031
1032
1033
1034
1035
1036
  
  		/*
  		 * Comments display at + 1 to depth. This is the
  		 * return from a function, we now want the comments
  		 * to display at the same level of the bracket.
  		 */
f1c7f517a   Steven Rostedt   ftrace: Add funct...
1037
1038
1039
1040
1041
1042
1043
  		cpu_data->depth = trace->depth - 1;
  
  		if (trace->depth < FTRACE_RETFUNC_DEPTH) {
  			if (cpu_data->enter_funcs[trace->depth] != trace->func)
  				func_match = 0;
  			cpu_data->enter_funcs[trace->depth] = 0;
  		}
2fbcdb35a   Steven Rostedt   function-graph: c...
1044
  	}
287b6e68c   Frederic Weisbecker   tracing/function-...
1045

d7a8d9e90   Jiri Olsa   tracing: Have gra...
1046
  	if (print_graph_prologue(iter, s, 0, 0, flags))
437f24fb8   Steven Rostedt   ftrace: add cpu a...
1047
  		return TRACE_TYPE_PARTIAL_LINE;
ffeb80fc3   Jiri Olsa   tracing, function...
1048
1049
1050
  	/* Overhead and duration */
  	ret = print_graph_duration(duration, s, flags);
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1051
  		return TRACE_TYPE_PARTIAL_LINE;
1a056155e   Frederic Weisbecker   tracing/function-...
1052

83a8df618   Frederic Weisbecker   tracing/function-...
1053
  	/* Closing brace */
287b6e68c   Frederic Weisbecker   tracing/function-...
1054
1055
  	for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
  		ret = trace_seq_printf(s, " ");
fb52607af   Frederic Weisbecker   tracing/function-...
1056
1057
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
287b6e68c   Frederic Weisbecker   tracing/function-...
1058
  	}
f1c7f517a   Steven Rostedt   ftrace: Add funct...
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  	/*
  	 * If the return function does not have a matching entry,
  	 * then the entry was lost. Instead of just printing
  	 * the '}' and letting the user guess what function this
  	 * belongs to, write out the function name.
  	 */
  	if (func_match) {
  		ret = trace_seq_printf(s, "}
  ");
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	} else {
a094fe04c   Steven Rostedt   function-graph: U...
1071
1072
  		ret = trace_seq_printf(s, "} /* %ps */
  ", (void *)trace->func);
f1c7f517a   Steven Rostedt   ftrace: Add funct...
1073
1074
1075
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
fb52607af   Frederic Weisbecker   tracing/function-...
1076

83a8df618   Frederic Weisbecker   tracing/function-...
1077
  	/* Overrun */
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1078
  	if (flags & TRACE_GRAPH_PRINT_OVERRUN) {
287b6e68c   Frederic Weisbecker   tracing/function-...
1079
1080
1081
  		ret = trace_seq_printf(s, " (Overruns: %lu)
  ",
  					trace->overrun);
fb52607af   Frederic Weisbecker   tracing/function-...
1082
1083
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
287b6e68c   Frederic Weisbecker   tracing/function-...
1084
  	}
f8b755ac8   Frederic Weisbecker   tracing/function-...
1085

d7a8d9e90   Jiri Olsa   tracing: Have gra...
1086
1087
  	ret = print_graph_irq(iter, trace->func, TRACE_GRAPH_RET,
  			      cpu, pid, flags);
f8b755ac8   Frederic Weisbecker   tracing/function-...
1088
1089
  	if (ret == TRACE_TYPE_PARTIAL_LINE)
  		return TRACE_TYPE_PARTIAL_LINE;
287b6e68c   Frederic Weisbecker   tracing/function-...
1090
1091
  	return TRACE_TYPE_HANDLED;
  }
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1092
  static enum print_line_t
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1093
1094
  print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
  		    struct trace_iterator *iter, u32 flags)
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1095
  {
5087f8d2a   Steven Rostedt   function-graph: s...
1096
  	unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
2fbcdb35a   Steven Rostedt   function-graph: c...
1097
  	struct fgraph_data *data = iter->private;
5087f8d2a   Steven Rostedt   function-graph: s...
1098
  	struct trace_event *event;
2fbcdb35a   Steven Rostedt   function-graph: c...
1099
  	int depth = 0;
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1100
  	int ret;
2fbcdb35a   Steven Rostedt   function-graph: c...
1101
1102
1103
  	int i;
  
  	if (data)
be1eca393   Jiri Olsa   tracing: Fix func...
1104
  		depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth;
9005f3ebe   Frederic Weisbecker   tracing/function-...
1105

d7a8d9e90   Jiri Olsa   tracing: Have gra...
1106
  	if (print_graph_prologue(iter, s, 0, 0, flags))
d1f9cbd78   Frederic Weisbecker   tracing/function-...
1107
  		return TRACE_TYPE_PARTIAL_LINE;
9005f3ebe   Frederic Weisbecker   tracing/function-...
1108
  	/* No time */
ffeb80fc3   Jiri Olsa   tracing, function...
1109
1110
1111
  	ret = print_graph_duration(DURATION_FILL_FULL, s, flags);
  	if (ret != TRACE_TYPE_HANDLED)
  		return ret;
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1112

1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1113
  	/* Indentation */
2fbcdb35a   Steven Rostedt   function-graph: c...
1114
1115
  	if (depth > 0)
  		for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) {
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1116
1117
1118
1119
1120
1121
  			ret = trace_seq_printf(s, " ");
  			if (!ret)
  				return TRACE_TYPE_PARTIAL_LINE;
  		}
  
  	/* The comment */
769b0441f   Frederic Weisbecker   tracing/core: dro...
1122
1123
1124
  	ret = trace_seq_printf(s, "/* ");
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
5087f8d2a   Steven Rostedt   function-graph: s...
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  	switch (iter->ent->type) {
  	case TRACE_BPRINT:
  		ret = trace_print_bprintk_msg_only(iter);
  		if (ret != TRACE_TYPE_HANDLED)
  			return ret;
  		break;
  	case TRACE_PRINT:
  		ret = trace_print_printk_msg_only(iter);
  		if (ret != TRACE_TYPE_HANDLED)
  			return ret;
  		break;
  	default:
  		event = ftrace_find_event(ent->type);
  		if (!event)
  			return TRACE_TYPE_UNHANDLED;
a9a577638   Steven Rostedt   tracing: Allow ev...
1140
  		ret = event->funcs->trace(iter, sym_flags, event);
5087f8d2a   Steven Rostedt   function-graph: s...
1141
1142
1143
  		if (ret != TRACE_TYPE_HANDLED)
  			return ret;
  	}
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1144

412d0bb55   Frederic Weisbecker   tracing/function-...
1145
1146
1147
1148
1149
1150
  	/* Strip ending newline */
  	if (s->buffer[s->len - 1] == '
  ') {
  		s->buffer[s->len - 1] = '\0';
  		s->len--;
  	}
1fd8f2a3f   Frederic Weisbecker   tracing/function-...
1151
1152
1153
1154
1155
1156
1157
  	ret = trace_seq_printf(s, " */
  ");
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	return TRACE_TYPE_HANDLED;
  }
287b6e68c   Frederic Weisbecker   tracing/function-...
1158
  enum print_line_t
321e68b09   Jiri Olsa   tracing, function...
1159
  print_graph_function_flags(struct trace_iterator *iter, u32 flags)
287b6e68c   Frederic Weisbecker   tracing/function-...
1160
  {
be1eca393   Jiri Olsa   tracing: Fix func...
1161
1162
  	struct ftrace_graph_ent_entry *field;
  	struct fgraph_data *data = iter->private;
287b6e68c   Frederic Weisbecker   tracing/function-...
1163
  	struct trace_entry *entry = iter->ent;
5087f8d2a   Steven Rostedt   function-graph: s...
1164
  	struct trace_seq *s = &iter->seq;
be1eca393   Jiri Olsa   tracing: Fix func...
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  	int cpu = iter->cpu;
  	int ret;
  
  	if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) {
  		per_cpu_ptr(data->cpu_data, cpu)->ignore = 0;
  		return TRACE_TYPE_HANDLED;
  	}
  
  	/*
  	 * If the last output failed, there's a possibility we need
  	 * to print out the missing entry which would never go out.
  	 */
  	if (data && data->failed) {
  		field = &data->ent;
  		iter->cpu = data->cpu;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1180
  		ret = print_graph_entry(field, s, iter, flags);
be1eca393   Jiri Olsa   tracing: Fix func...
1181
1182
1183
1184
1185
1186
1187
  		if (ret == TRACE_TYPE_HANDLED && iter->cpu != cpu) {
  			per_cpu_ptr(data->cpu_data, iter->cpu)->ignore = 1;
  			ret = TRACE_TYPE_NO_CONSUME;
  		}
  		iter->cpu = cpu;
  		return ret;
  	}
fb52607af   Frederic Weisbecker   tracing/function-...
1188

287b6e68c   Frederic Weisbecker   tracing/function-...
1189
1190
  	switch (entry->type) {
  	case TRACE_GRAPH_ENT: {
38ceb592f   Lai Jiangshan   tracing: Fix inva...
1191
1192
1193
1194
1195
1196
  		/*
  		 * print_graph_entry() may consume the current event,
  		 * thus @field may become invalid, so we need to save it.
  		 * sizeof(struct ftrace_graph_ent_entry) is very small,
  		 * it can be safely saved at the stack.
  		 */
be1eca393   Jiri Olsa   tracing: Fix func...
1197
  		struct ftrace_graph_ent_entry saved;
287b6e68c   Frederic Weisbecker   tracing/function-...
1198
  		trace_assign_type(field, entry);
38ceb592f   Lai Jiangshan   tracing: Fix inva...
1199
  		saved = *field;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1200
  		return print_graph_entry(&saved, s, iter, flags);
287b6e68c   Frederic Weisbecker   tracing/function-...
1201
1202
1203
1204
  	}
  	case TRACE_GRAPH_RET: {
  		struct ftrace_graph_ret_entry *field;
  		trace_assign_type(field, entry);
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1205
  		return print_graph_return(&field->ret, s, entry, iter, flags);
287b6e68c   Frederic Weisbecker   tracing/function-...
1206
  	}
62b915f10   Jiri Olsa   tracing: Add grap...
1207
1208
1209
1210
  	case TRACE_STACK:
  	case TRACE_FN:
  		/* dont trace stack and functions as comments */
  		return TRACE_TYPE_UNHANDLED;
287b6e68c   Frederic Weisbecker   tracing/function-...
1211
  	default:
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1212
  		return print_graph_comment(s, entry, iter, flags);
fb52607af   Frederic Weisbecker   tracing/function-...
1213
  	}
5087f8d2a   Steven Rostedt   function-graph: s...
1214
1215
  
  	return TRACE_TYPE_HANDLED;
fb52607af   Frederic Weisbecker   tracing/function-...
1216
  }
9106b6938   Jiri Olsa   tracing: Add ftra...
1217
  static enum print_line_t
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1218
1219
  print_graph_function(struct trace_iterator *iter)
  {
321e68b09   Jiri Olsa   tracing, function...
1220
  	return print_graph_function_flags(iter, tracer_flags.val);
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1221
1222
1223
  }
  
  static enum print_line_t
a9a577638   Steven Rostedt   tracing: Allow ev...
1224
1225
  print_graph_function_event(struct trace_iterator *iter, int flags,
  			   struct trace_event *event)
9106b6938   Jiri Olsa   tracing: Add ftra...
1226
1227
1228
  {
  	return print_graph_function(iter);
  }
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1229
  static void print_lat_header(struct seq_file *s, u32 flags)
49ff59039   Steven Rostedt   tracing: add late...
1230
1231
1232
1233
1234
  {
  	static const char spaces[] = "                "	/* 16 spaces */
  		"    "					/* 4 spaces */
  		"                 ";			/* 17 spaces */
  	int size = 0;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1235
  	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
49ff59039   Steven Rostedt   tracing: add late...
1236
  		size += 16;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1237
  	if (flags & TRACE_GRAPH_PRINT_CPU)
49ff59039   Steven Rostedt   tracing: add late...
1238
  		size += 4;
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1239
  	if (flags & TRACE_GRAPH_PRINT_PROC)
49ff59039   Steven Rostedt   tracing: add late...
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  		size += 17;
  
  	seq_printf(s, "#%.*s  _-----=> irqs-off        
  ", size, spaces);
  	seq_printf(s, "#%.*s / _----=> need-resched    
  ", size, spaces);
  	seq_printf(s, "#%.*s| / _---=> hardirq/softirq 
  ", size, spaces);
  	seq_printf(s, "#%.*s|| / _--=> preempt-depth   
  ", size, spaces);
199abfab4   Jiri Olsa   tracing, function...
1250
1251
  	seq_printf(s, "#%.*s||| /                      
  ", size, spaces);
49ff59039   Steven Rostedt   tracing: add late...
1252
  }
0a772620a   Jiri Olsa   tracing: Make gra...
1253
  static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
decbec383   Frederic Weisbecker   tracing/function-...
1254
  {
49ff59039   Steven Rostedt   tracing: add late...
1255
1256
1257
  	int lat = trace_flags & TRACE_ITER_LATENCY_FMT;
  
  	if (lat)
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1258
  		print_lat_header(s, flags);
49ff59039   Steven Rostedt   tracing: add late...
1259

decbec383   Frederic Weisbecker   tracing/function-...
1260
  	/* 1st line */
49ff59039   Steven Rostedt   tracing: add late...
1261
  	seq_printf(s, "#");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1262
  	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1263
  		seq_printf(s, "     TIME       ");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1264
  	if (flags & TRACE_GRAPH_PRINT_CPU)
49ff59039   Steven Rostedt   tracing: add late...
1265
  		seq_printf(s, " CPU");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1266
  	if (flags & TRACE_GRAPH_PRINT_PROC)
49ff59039   Steven Rostedt   tracing: add late...
1267
1268
  		seq_printf(s, "  TASK/PID       ");
  	if (lat)
199abfab4   Jiri Olsa   tracing, function...
1269
  		seq_printf(s, "||||");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1270
  	if (flags & TRACE_GRAPH_PRINT_DURATION)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1271
1272
1273
  		seq_printf(s, "  DURATION   ");
  	seq_printf(s, "               FUNCTION CALLS
  ");
decbec383   Frederic Weisbecker   tracing/function-...
1274
1275
  
  	/* 2nd line */
49ff59039   Steven Rostedt   tracing: add late...
1276
  	seq_printf(s, "#");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1277
  	if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1278
  		seq_printf(s, "      |         ");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1279
  	if (flags & TRACE_GRAPH_PRINT_CPU)
49ff59039   Steven Rostedt   tracing: add late...
1280
  		seq_printf(s, " |  ");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1281
  	if (flags & TRACE_GRAPH_PRINT_PROC)
49ff59039   Steven Rostedt   tracing: add late...
1282
1283
  		seq_printf(s, "   |    |        ");
  	if (lat)
199abfab4   Jiri Olsa   tracing, function...
1284
  		seq_printf(s, "||||");
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1285
  	if (flags & TRACE_GRAPH_PRINT_DURATION)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1286
1287
1288
  		seq_printf(s, "   |   |      ");
  	seq_printf(s, "               |   |   |   |
  ");
decbec383   Frederic Weisbecker   tracing/function-...
1289
  }
9005f3ebe   Frederic Weisbecker   tracing/function-...
1290

62b915f10   Jiri Olsa   tracing: Add grap...
1291
  void print_graph_headers(struct seq_file *s)
d7a8d9e90   Jiri Olsa   tracing: Have gra...
1292
1293
1294
  {
  	print_graph_headers_flags(s, tracer_flags.val);
  }
0a772620a   Jiri Olsa   tracing: Make gra...
1295
1296
1297
  void print_graph_headers_flags(struct seq_file *s, u32 flags)
  {
  	struct trace_iterator *iter = s->private;
749230b06   Jiri Olsa   tracing, function...
1298
1299
  	if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
  		return;
0a772620a   Jiri Olsa   tracing: Make gra...
1300
1301
1302
1303
1304
1305
  	if (trace_flags & TRACE_ITER_LATENCY_FMT) {
  		/* print nothing if the buffers are empty */
  		if (trace_empty(iter))
  			return;
  
  		print_trace_header(s, iter);
321e68b09   Jiri Olsa   tracing, function...
1306
  	}
0a772620a   Jiri Olsa   tracing: Make gra...
1307
1308
1309
  
  	__print_graph_headers_flags(s, flags);
  }
62b915f10   Jiri Olsa   tracing: Add grap...
1310
  void graph_trace_open(struct trace_iterator *iter)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1311
  {
2fbcdb35a   Steven Rostedt   function-graph: c...
1312
  	/* pid and depth on the last trace processed */
be1eca393   Jiri Olsa   tracing: Fix func...
1313
  	struct fgraph_data *data;
9005f3ebe   Frederic Weisbecker   tracing/function-...
1314
  	int cpu;
be1eca393   Jiri Olsa   tracing: Fix func...
1315
1316
1317
  	iter->private = NULL;
  
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
2fbcdb35a   Steven Rostedt   function-graph: c...
1318
  	if (!data)
be1eca393   Jiri Olsa   tracing: Fix func...
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  		goto out_err;
  
  	data->cpu_data = alloc_percpu(struct fgraph_cpu_data);
  	if (!data->cpu_data)
  		goto out_err_free;
  
  	for_each_possible_cpu(cpu) {
  		pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
  		int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth);
  		int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore);
2bd16212b   Jiri Olsa   tracing: Add func...
1329
  		int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
be1eca393   Jiri Olsa   tracing: Fix func...
1330
1331
1332
  		*pid = -1;
  		*depth = 0;
  		*ignore = 0;
2bd16212b   Jiri Olsa   tracing: Add func...
1333
  		*depth_irq = -1;
be1eca393   Jiri Olsa   tracing: Fix func...
1334
  	}
9005f3ebe   Frederic Weisbecker   tracing/function-...
1335

2fbcdb35a   Steven Rostedt   function-graph: c...
1336
  	iter->private = data;
be1eca393   Jiri Olsa   tracing: Fix func...
1337
1338
1339
1340
1341
1342
1343
1344
  
  	return;
  
   out_err_free:
  	kfree(data);
   out_err:
  	pr_warning("function graph tracer: not enough memory
  ");
9005f3ebe   Frederic Weisbecker   tracing/function-...
1345
  }
62b915f10   Jiri Olsa   tracing: Add grap...
1346
  void graph_trace_close(struct trace_iterator *iter)
9005f3ebe   Frederic Weisbecker   tracing/function-...
1347
  {
be1eca393   Jiri Olsa   tracing: Fix func...
1348
1349
1350
1351
1352
1353
  	struct fgraph_data *data = iter->private;
  
  	if (data) {
  		free_percpu(data->cpu_data);
  		kfree(data);
  	}
9005f3ebe   Frederic Weisbecker   tracing/function-...
1354
  }
b304d0441   Steven Rostedt   tracing: Do not t...
1355
1356
1357
1358
1359
1360
1361
  static int func_graph_set_flag(u32 old_flags, u32 bit, int set)
  {
  	if (bit == TRACE_GRAPH_PRINT_IRQS)
  		ftrace_graph_skip_irqs = !set;
  
  	return 0;
  }
a9a577638   Steven Rostedt   tracing: Allow ev...
1362
1363
1364
  static struct trace_event_functions graph_functions = {
  	.trace		= print_graph_function_event,
  };
9106b6938   Jiri Olsa   tracing: Add ftra...
1365
1366
  static struct trace_event graph_trace_entry_event = {
  	.type		= TRACE_GRAPH_ENT,
a9a577638   Steven Rostedt   tracing: Allow ev...
1367
  	.funcs		= &graph_functions,
9106b6938   Jiri Olsa   tracing: Add ftra...
1368
1369
1370
1371
  };
  
  static struct trace_event graph_trace_ret_event = {
  	.type		= TRACE_GRAPH_RET,
a9a577638   Steven Rostedt   tracing: Allow ev...
1372
  	.funcs		= &graph_functions
9106b6938   Jiri Olsa   tracing: Add ftra...
1373
  };
fb52607af   Frederic Weisbecker   tracing/function-...
1374
  static struct tracer graph_trace __read_mostly = {
ef18012b2   Steven Rostedt   tracing: remove f...
1375
  	.name		= "function_graph",
9005f3ebe   Frederic Weisbecker   tracing/function-...
1376
  	.open		= graph_trace_open,
be1eca393   Jiri Olsa   tracing: Fix func...
1377
  	.pipe_open	= graph_trace_open,
9005f3ebe   Frederic Weisbecker   tracing/function-...
1378
  	.close		= graph_trace_close,
be1eca393   Jiri Olsa   tracing: Fix func...
1379
  	.pipe_close	= graph_trace_close,
6eaaa5d57   Frederic Weisbecker   tracing/core: use...
1380
  	.wait_pipe	= poll_wait_pipe,
ef18012b2   Steven Rostedt   tracing: remove f...
1381
1382
  	.init		= graph_trace_init,
  	.reset		= graph_trace_reset,
decbec383   Frederic Weisbecker   tracing/function-...
1383
1384
  	.print_line	= print_graph_function,
  	.print_header	= print_graph_headers,
fb52607af   Frederic Weisbecker   tracing/function-...
1385
  	.flags		= &tracer_flags,
b304d0441   Steven Rostedt   tracing: Do not t...
1386
  	.set_flag	= func_graph_set_flag,
7447dce96   Frederic Weisbecker   tracing/function-...
1387
1388
1389
  #ifdef CONFIG_FTRACE_SELFTEST
  	.selftest	= trace_selftest_startup_function_graph,
  #endif
fb52607af   Frederic Weisbecker   tracing/function-...
1390
1391
1392
1393
  };
  
  static __init int init_graph_trace(void)
  {
0c9e6f639   Lai Jiangshan   tracing: Simplify...
1394
  	max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
9106b6938   Jiri Olsa   tracing: Add ftra...
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
  	if (!register_ftrace_event(&graph_trace_entry_event)) {
  		pr_warning("Warning: could not register graph trace events
  ");
  		return 1;
  	}
  
  	if (!register_ftrace_event(&graph_trace_ret_event)) {
  		pr_warning("Warning: could not register graph trace events
  ");
  		return 1;
  	}
fb52607af   Frederic Weisbecker   tracing/function-...
1406
1407
1408
1409
  	return register_tracer(&graph_trace);
  }
  
  device_initcall(init_graph_trace);