Blame view
kernel/trace/trace_functions_graph.c
39.1 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
fb52607af tracing/function-... |
2 3 4 |
/* * * Function graph tracer. |
9005f3ebe tracing/function-... |
5 |
* Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com> |
fb52607af tracing/function-... |
6 7 8 9 |
* Mostly borrowed from function tracer which * is Copyright (c) Steven Rostedt <srostedt@redhat.com> * */ |
fb52607af tracing/function-... |
10 11 |
#include <linux/uaccess.h> #include <linux/ftrace.h> |
be7635e72 arch, ftrace: for... |
12 |
#include <linux/interrupt.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
fb52607af tracing/function-... |
14 15 16 |
#include <linux/fs.h> #include "trace.h" |
f0868d1e2 ftrace: set up tr... |
17 |
#include "trace_output.h" |
fb52607af tracing/function-... |
18 |
|
1b2f121c1 ftrace-graph: Rem... |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
static bool kill_ftrace_graph; /** * ftrace_graph_is_dead - returns true if ftrace_graph_stop() was called * * ftrace_graph_stop() is called when a severe error is detected in * the function graph tracing. This function is called by the critical * paths of function graph to keep those paths from doing any more harm. */ bool ftrace_graph_is_dead(void) { return kill_ftrace_graph; } /** * ftrace_graph_stop - set to permanently disable function graph tracincg * * In case of an error int function graph tracing, this is called * to try to keep function graph tracing from causing any more harm. * Usually this is pretty severe and this is called to try to at least * get a warning out to the user. */ void ftrace_graph_stop(void) { kill_ftrace_graph = true; |
1b2f121c1 ftrace-graph: Rem... |
44 |
} |
b304d0441 tracing: Do not t... |
45 46 |
/* When set, irq functions will be ignored */ static int ftrace_graph_skip_irqs; |
be1eca393 tracing: Fix func... |
47 |
struct fgraph_cpu_data { |
2fbcdb35a function-graph: c... |
48 49 |
pid_t last_pid; int depth; |
2bd16212b tracing: Add func... |
50 |
int depth_irq; |
be1eca393 tracing: Fix func... |
51 |
int ignore; |
f1c7f517a ftrace: Add funct... |
52 |
unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; |
be1eca393 tracing: Fix func... |
53 54 55 |
}; struct fgraph_data { |
6016ee13d perf, tracing: ad... |
56 |
struct fgraph_cpu_data __percpu *cpu_data; |
be1eca393 tracing: Fix func... |
57 58 59 60 61 62 |
/* Place to preserve last processed entry. */ struct ftrace_graph_ent_entry ent; struct ftrace_graph_ret_entry ret; int failed; int cpu; |
2fbcdb35a function-graph: c... |
63 |
}; |
287b6e68c tracing/function-... |
64 |
#define TRACE_GRAPH_INDENT 2 |
fb52607af tracing/function-... |
65 |
|
1a4144286 tracing/fgraph: H... |
66 |
unsigned int fgraph_max_depth; |
8741db532 tracing/fgraph: A... |
67 |
|
fb52607af tracing/function-... |
68 |
static struct tracer_opt trace_opts[] = { |
9005f3ebe tracing/function-... |
69 |
/* Display overruns? (for self-debug purpose) */ |
1a056155e tracing/function-... |
70 71 72 73 74 |
{ 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 tracing/function-... |
75 76 |
/* Display proc name/pid */ { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) }, |
9005f3ebe tracing/function-... |
77 78 79 80 |
/* 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 tracing: Add func... |
81 82 |
/* Display interrupts */ { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, |
607e3a292 tracing: Add func... |
83 84 |
/* Display function name after trailing } */ { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, |
555772041 tracing: Move sle... |
85 86 87 88 |
/* Include sleep time (scheduled out) between entry and return */ { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, /* Include time within nested functions */ { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) }, |
fb52607af tracing/function-... |
89 90 91 92 |
{ } /* Empty entry */ }; static struct tracer_flags tracer_flags = { |
607e3a292 tracing: Add func... |
93 |
/* Don't display overruns, proc, or tail by default */ |
9005f3ebe tracing/function-... |
94 |
.val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | |
555772041 tracing: Move sle... |
95 96 |
TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS | TRACE_GRAPH_SLEEP_TIME | TRACE_GRAPH_GRAPH_TIME, |
fb52607af tracing/function-... |
97 98 |
.opts = trace_opts }; |
1a0799a8f tracing/function-... |
99 |
static struct trace_array *graph_array; |
9005f3ebe tracing/function-... |
100 |
|
ffeb80fc3 tracing, function... |
101 102 103 104 105 106 |
/* * 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 { |
6fc84ea70 tracing: Do not u... |
107 108 109 |
FLAGS_FILL_FULL = 1 << TRACE_GRAPH_PRINT_FILL_SHIFT, FLAGS_FILL_START = 2 << TRACE_GRAPH_PRINT_FILL_SHIFT, FLAGS_FILL_END = 3 << TRACE_GRAPH_PRINT_FILL_SHIFT, |
ffeb80fc3 tracing, function... |
110 |
}; |
9d9add34e tracing: Have fun... |
111 |
static void |
983f938ae tracing: Move tra... |
112 113 |
print_graph_duration(struct trace_array *tr, unsigned long long duration, struct trace_seq *s, u32 flags); |
fb52607af tracing/function-... |
114 |
|
712406a6b tracing/function-... |
115 |
/* Add a function return address to the trace stack on thread info.*/ |
72c33b233 function_graph: M... |
116 |
static int |
392374326 function_graph: U... |
117 |
ftrace_push_return_trace(unsigned long ret, unsigned long func, |
9a7c348ba ftrace: Add retur... |
118 |
unsigned long frame_pointer, unsigned long *retp) |
712406a6b tracing/function-... |
119 |
{ |
5d1a03dc5 function-graph: m... |
120 |
unsigned long long calltime; |
712406a6b tracing/function-... |
121 |
int index; |
1b2f121c1 ftrace-graph: Rem... |
122 123 |
if (unlikely(ftrace_graph_is_dead())) return -EBUSY; |
712406a6b tracing/function-... |
124 125 |
if (!current->ret_stack) return -EBUSY; |
82310a327 function-graph: e... |
126 127 128 129 130 |
/* * We must make sure the ret_stack is tested before we read * anything else. */ smp_rmb(); |
712406a6b tracing/function-... |
131 132 133 134 135 |
/* The return trace stack is full */ if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { atomic_inc(¤t->trace_overrun); return -EBUSY; } |
29ad23b00 ftrace: Add set_g... |
136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
/* * The curr_ret_stack is an index to ftrace return stack of * current task. Its value should be in [0, FTRACE_RETFUNC_ * DEPTH) when the function graph tracer is used. To support * filtering out specific functions, it makes the index * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH) * so when it sees a negative index the ftrace will ignore * the record. And the index gets recovered when returning * from the filtered function by adding the FTRACE_NOTRACE_ * DEPTH and then it'll continue to record functions normally. * * The curr_ret_stack is initialized to -1 and get increased * in this function. So it can be less than -1 only if it was * filtered out via ftrace_graph_notrace_addr() which can be |
8434dc934 tracing: Convert ... |
150 |
* set from set_graph_notrace file in tracefs by user. |
29ad23b00 ftrace: Add set_g... |
151 152 153 |
*/ if (current->curr_ret_stack < -1) return -EBUSY; |
5d1a03dc5 function-graph: m... |
154 |
calltime = trace_clock_local(); |
712406a6b tracing/function-... |
155 |
index = ++current->curr_ret_stack; |
29ad23b00 ftrace: Add set_g... |
156 157 |
if (ftrace_graph_notrace_addr(func)) current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; |
712406a6b tracing/function-... |
158 159 160 |
barrier(); current->ret_stack[index].ret = ret; current->ret_stack[index].func = func; |
5d1a03dc5 function-graph: m... |
161 |
current->ret_stack[index].calltime = calltime; |
daa460a88 ftrace: Only allo... |
162 |
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
71e308a23 function-graph: a... |
163 |
current->ret_stack[index].fp = frame_pointer; |
daa460a88 ftrace: Only allo... |
164 |
#endif |
9a7c348ba ftrace: Add retur... |
165 166 167 |
#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR current->ret_stack[index].retp = retp; #endif |
712406a6b tracing/function-... |
168 169 |
return 0; } |
67d7bec3f function_graph: C... |
170 171 172 173 174 175 |
int function_graph_enter(unsigned long ret, unsigned long func, unsigned long frame_pointer, unsigned long *retp) { struct ftrace_graph_ent trace; trace.func = func; |
392374326 function_graph: U... |
176 |
trace.depth = ++current->curr_ret_depth; |
67d7bec3f function_graph: C... |
177 |
|
392374326 function_graph: U... |
178 179 180 |
if (ftrace_push_return_trace(ret, func, frame_pointer, retp)) goto out; |
a22ff9df7 function_graph: R... |
181 182 183 |
/* Only trace if the calling function expects to */ if (!ftrace_graph_entry(&trace)) goto out_ret; |
392374326 function_graph: U... |
184 |
return 0; |
a22ff9df7 function_graph: R... |
185 186 |
out_ret: current->curr_ret_stack--; |
392374326 function_graph: U... |
187 188 189 |
out: current->curr_ret_depth--; return -EBUSY; |
67d7bec3f function_graph: C... |
190 |
} |
712406a6b tracing/function-... |
191 |
/* Retrieve a function return address to the trace stack on thread info.*/ |
a2a16d6a3 function-graph: a... |
192 |
static void |
71e308a23 function-graph: a... |
193 194 |
ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, unsigned long frame_pointer) |
712406a6b tracing/function-... |
195 196 197 198 |
{ int index; index = current->curr_ret_stack; |
29ad23b00 ftrace: Add set_g... |
199 200 201 202 203 204 205 206 207 208 209 |
/* * A negative index here means that it's just returned from a * notrace'd function. Recover index to get an original * return address. See ftrace_push_return_trace(). * * TODO: Need to check whether the stack gets corrupted. */ if (index < 0) index += FTRACE_NOTRACE_DEPTH; if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) { |
712406a6b tracing/function-... |
210 211 212 213 214 215 |
ftrace_graph_stop(); WARN_ON(1); /* Might as well panic, otherwise we have no where to go */ *ret = (unsigned long)panic; return; } |
e4a744ef2 ftrace: Remove CO... |
216 |
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
71e308a23 function-graph: a... |
217 218 219 220 221 222 223 224 225 226 |
/* * 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. |
781d06248 ftrace: Do not te... |
227 228 229 |
* * Note, -mfentry does not use frame pointers, and this test * is not needed if CC_USING_FENTRY is set. |
71e308a23 function-graph: a... |
230 231 232 233 234 |
*/ if (unlikely(current->ret_stack[index].fp != frame_pointer)) { ftrace_graph_stop(); WARN(1, "Bad frame pointer: expected %lx, received %lx " |
b375a11a2 tracing: switch f... |
235 236 |
" from func %ps return to %lx ", |
71e308a23 function-graph: a... |
237 238 239 240 241 242 243 244 |
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 tracing/function-... |
245 246 247 248 |
*ret = current->ret_stack[index].ret; trace->func = current->ret_stack[index].func; trace->calltime = current->ret_stack[index].calltime; trace->overrun = atomic_read(¤t->trace_overrun); |
d2bcf809e function_graph: M... |
249 250 251 252 253 254 255 |
trace->depth = current->curr_ret_depth--; /* * We still want to trace interrupts coming in if * max_depth is set to 1. Make sure the decrement is * seen before ftrace_graph_return. */ barrier(); |
712406a6b tracing/function-... |
256 257 258 259 260 261 |
} /* * Send the trace to the ring-buffer. * @return the original return address. */ |
71e308a23 function-graph: a... |
262 |
unsigned long ftrace_return_to_handler(unsigned long frame_pointer) |
712406a6b tracing/function-... |
263 264 265 |
{ struct ftrace_graph_ret trace; unsigned long ret; |
71e308a23 function-graph: a... |
266 |
ftrace_pop_return_trace(&trace, &ret, frame_pointer); |
0012693ad tracing/function-... |
267 |
trace.rettime = trace_clock_local(); |
d2bcf809e function_graph: M... |
268 269 270 271 272 273 |
ftrace_graph_return(&trace); /* * The ftrace_graph_return() may still access the current * ret_stack structure, we need to make sure the update of * curr_ret_stack is after that. */ |
a2a16d6a3 function-graph: a... |
274 275 |
barrier(); current->curr_ret_stack--; |
29ad23b00 ftrace: Add set_g... |
276 277 278 279 280 281 282 283 284 |
/* * The curr_ret_stack can be less than -1 only if it was * filtered out and it's about to return from the function. * Recover the index and continue to trace normal functions. */ if (current->curr_ret_stack < -1) { current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; return ret; } |
712406a6b tracing/function-... |
285 286 287 288 289 290 291 292 293 294 |
if (unlikely(!ret)) { ftrace_graph_stop(); WARN_ON(1); /* Might as well panic. What else to do? */ ret = (unsigned long)panic; } return ret; } |
223918e32 ftrace: Add ftrac... |
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
/** * ftrace_graph_ret_addr - convert a potentially modified stack return address * to its original value * * This function can be called by stack unwinding code to convert a found stack * return address ('ret') to its original value, in case the function graph * tracer has modified it to be 'return_to_handler'. If the address hasn't * been modified, the unchanged value of 'ret' is returned. * * 'idx' is a state variable which should be initialized by the caller to zero * before the first call. * * 'retp' is a pointer to the return address on the stack. It's ignored if * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. */ #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, unsigned long ret, unsigned long *retp) { int index = task->curr_ret_stack; int i; if (ret != (unsigned long)return_to_handler) return ret; if (index < -1) index += FTRACE_NOTRACE_DEPTH; if (index < 0) return ret; for (i = 0; i <= index; i++) if (task->ret_stack[i].retp == retp) return task->ret_stack[i].ret; return ret; } #else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, unsigned long ret, unsigned long *retp) { int task_idx; if (ret != (unsigned long)return_to_handler) return ret; task_idx = task->curr_ret_stack; if (!task->ret_stack || task_idx < *idx) return ret; task_idx -= *idx; (*idx)++; return task->ret_stack[task_idx].ret; } #endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ |
62b915f10 tracing: Add grap... |
352 |
int __trace_graph_entry(struct trace_array *tr, |
1a0799a8f tracing/function-... |
353 354 355 356 |
struct ftrace_graph_ent *trace, unsigned long flags, int pc) { |
2425bcb92 tracing: Rename f... |
357 |
struct trace_event_call *call = &event_funcgraph_entry; |
1a0799a8f tracing/function-... |
358 |
struct ring_buffer_event *event; |
12883efb6 tracing: Consolid... |
359 |
struct ring_buffer *buffer = tr->trace_buffer.buffer; |
1a0799a8f tracing/function-... |
360 |
struct ftrace_graph_ent_entry *entry; |
e77405ad8 tracing: pass aro... |
361 |
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, |
1a0799a8f tracing/function-... |
362 363 364 365 366 |
sizeof(*entry), flags, pc); if (!event) return 0; entry = ring_buffer_event_data(event); entry->graph_ent = *trace; |
f306cc82a tracing: Update e... |
367 |
if (!call_filter_check_discard(call, entry, buffer, event)) |
52ffabe38 tracing: Make __b... |
368 |
trace_buffer_unlock_commit_nostack(buffer, event); |
1a0799a8f tracing/function-... |
369 370 371 |
return 1; } |
b304d0441 tracing: Do not t... |
372 373 |
static inline int ftrace_graph_ignore_irqs(void) { |
e4a3f541f tracing: Still tr... |
374 |
if (!ftrace_graph_skip_irqs || trace_recursion_test(TRACE_IRQ_BIT)) |
b304d0441 tracing: Do not t... |
375 376 377 378 |
return 0; return in_irq(); } |
1a0799a8f tracing/function-... |
379 380 381 382 383 384 385 386 387 |
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; |
345ddcc88 ftrace: Have set_... |
388 |
if (!ftrace_trace_task(tr)) |
1a0799a8f tracing/function-... |
389 |
return 0; |
1a4144286 tracing/fgraph: H... |
390 391 392 393 |
if (ftrace_graph_ignore_func(trace)) return 0; if (ftrace_graph_ignore_irqs()) |
1a0799a8f tracing/function-... |
394 |
return 0; |
29ad23b00 ftrace: Add set_g... |
395 396 397 398 399 400 401 402 403 |
/* * Do not trace a function if it's filtered by set_graph_notrace. * Make the index of ret stack negative to indicate that it should * ignore further functions. But it needs its own ret stack entry * to recover the original index in order to continue tracing after * returning from the function. */ if (ftrace_graph_notrace_addr(trace->func)) return 1; |
7fa8b7171 tracing/function_... |
404 405 406 407 408 409 |
/* * Stop here if tracing_threshold is set. We only write function return * events to the ring buffer. */ if (tracing_thresh) return 1; |
1a0799a8f tracing/function-... |
410 411 |
local_irq_save(flags); cpu = raw_smp_processor_id(); |
12883efb6 tracing: Consolid... |
412 |
data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
1a0799a8f tracing/function-... |
413 414 415 416 417 418 419 |
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 tracing/function-... |
420 421 422 423 424 425 |
atomic_dec(&data->disabled); local_irq_restore(flags); return ret; } |
0a772620a tracing: Make gra... |
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
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 tracing: Make gra... |
451 452 |
__trace_graph_function(tr, ip, flags, pc); } |
62b915f10 tracing: Add grap... |
453 |
void __trace_graph_return(struct trace_array *tr, |
1a0799a8f tracing/function-... |
454 455 456 457 |
struct ftrace_graph_ret *trace, unsigned long flags, int pc) { |
2425bcb92 tracing: Rename f... |
458 |
struct trace_event_call *call = &event_funcgraph_exit; |
1a0799a8f tracing/function-... |
459 |
struct ring_buffer_event *event; |
12883efb6 tracing: Consolid... |
460 |
struct ring_buffer *buffer = tr->trace_buffer.buffer; |
1a0799a8f tracing/function-... |
461 |
struct ftrace_graph_ret_entry *entry; |
e77405ad8 tracing: pass aro... |
462 |
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET, |
1a0799a8f tracing/function-... |
463 464 465 466 467 |
sizeof(*entry), flags, pc); if (!event) return; entry = ring_buffer_event_data(event); entry->ret = *trace; |
f306cc82a tracing: Update e... |
468 |
if (!call_filter_check_discard(call, entry, buffer, event)) |
52ffabe38 tracing: Make __b... |
469 |
trace_buffer_unlock_commit_nostack(buffer, event); |
1a0799a8f tracing/function-... |
470 471 472 473 474 475 476 477 478 479 |
} 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; |
81f966235 tracing/fgraph: F... |
480 |
ftrace_graph_addr_finish(trace); |
1a0799a8f tracing/function-... |
481 482 |
local_irq_save(flags); cpu = raw_smp_processor_id(); |
12883efb6 tracing: Consolid... |
483 |
data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
1a0799a8f tracing/function-... |
484 485 486 487 488 |
disabled = atomic_inc_return(&data->disabled); if (likely(disabled == 1)) { pc = preempt_count(); __trace_graph_return(tr, trace, flags, pc); } |
1a0799a8f tracing/function-... |
489 490 491 |
atomic_dec(&data->disabled); local_irq_restore(flags); } |
24a53652e tracing: Drop the... |
492 493 494 495 496 497 498 499 |
void set_graph_array(struct trace_array *tr) { graph_array = tr; /* Make graph_array visible before we start tracing */ smp_mb(); } |
ba1afef6a tracing: Convert ... |
500 |
static void trace_graph_thresh_return(struct ftrace_graph_ret *trace) |
0e9501735 function-graph: A... |
501 |
{ |
81f966235 tracing/fgraph: F... |
502 |
ftrace_graph_addr_finish(trace); |
0e9501735 function-graph: A... |
503 504 505 506 507 508 |
if (tracing_thresh && (trace->rettime - trace->calltime < tracing_thresh)) return; else trace_graph_return(trace); } |
fb52607af tracing/function-... |
509 510 |
static int graph_trace_init(struct trace_array *tr) { |
1a0799a8f tracing/function-... |
511 |
int ret; |
24a53652e tracing: Drop the... |
512 |
set_graph_array(tr); |
0e9501735 function-graph: A... |
513 514 |
if (tracing_thresh) ret = register_ftrace_graph(&trace_graph_thresh_return, |
7fa8b7171 tracing/function_... |
515 |
&trace_graph_entry); |
0e9501735 function-graph: A... |
516 517 518 |
else ret = register_ftrace_graph(&trace_graph_return, &trace_graph_entry); |
660c7f9be ftrace: add threa... |
519 520 521 522 523 |
if (ret) return ret; tracing_start_cmdline_record(); return 0; |
fb52607af tracing/function-... |
524 525 526 527 |
} static void graph_trace_reset(struct trace_array *tr) { |
660c7f9be ftrace: add threa... |
528 529 |
tracing_stop_cmdline_record(); unregister_ftrace_graph(); |
fb52607af tracing/function-... |
530 |
} |
ba1afef6a tracing: Convert ... |
531 |
static int graph_trace_update_thresh(struct trace_array *tr) |
6508fa761 tracing: let user... |
532 533 534 535 |
{ graph_trace_reset(tr); return graph_trace_init(tr); } |
0c9e6f639 tracing: Simplify... |
536 |
static int max_bytes_for_cpu; |
1a056155e tracing/function-... |
537 |
|
9d9add34e tracing: Have fun... |
538 |
static void print_graph_cpu(struct trace_seq *s, int cpu) |
1a056155e tracing/function-... |
539 |
{ |
d51090b34 tracing/function-... |
540 541 542 543 544 |
/* * Start with a space character - to make it stand out * to the right a bit when trace output is pasted into * email: */ |
9d9add34e tracing: Have fun... |
545 |
trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu); |
1a056155e tracing/function-... |
546 |
} |
11e84acc4 tracing/function-... |
547 |
#define TRACE_GRAPH_PROCINFO_LENGTH 14 |
9d9add34e tracing: Have fun... |
548 |
static void print_graph_proc(struct trace_seq *s, pid_t pid) |
11e84acc4 tracing/function-... |
549 |
{ |
4ca530852 tracing: protect ... |
550 |
char comm[TASK_COMM_LEN]; |
11e84acc4 tracing/function-... |
551 552 |
/* sign + log10(MAX_INT) + '\0' */ char pid_str[11]; |
4ca530852 tracing: protect ... |
553 |
int spaces = 0; |
4ca530852 tracing: protect ... |
554 555 |
int len; int i; |
11e84acc4 tracing/function-... |
556 |
|
4ca530852 tracing: protect ... |
557 |
trace_find_cmdline(pid, comm); |
11e84acc4 tracing/function-... |
558 559 560 561 562 563 564 565 566 567 |
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 */ |
9d9add34e tracing: Have fun... |
568 569 |
for (i = 0; i < spaces / 2; i++) trace_seq_putc(s, ' '); |
11e84acc4 tracing/function-... |
570 |
|
9d9add34e tracing: Have fun... |
571 |
trace_seq_printf(s, "%s-%s", comm, pid_str); |
11e84acc4 tracing/function-... |
572 573 |
/* Last spaces to align center */ |
9d9add34e tracing: Have fun... |
574 575 |
for (i = 0; i < spaces - (spaces / 2); i++) trace_seq_putc(s, ' '); |
11e84acc4 tracing/function-... |
576 |
} |
1a056155e tracing/function-... |
577 |
|
9d9add34e tracing: Have fun... |
578 |
static void print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry) |
49ff59039 tracing: add late... |
579 |
{ |
9d9add34e tracing: Have fun... |
580 581 |
trace_seq_putc(s, ' '); trace_print_lat_fmt(s, entry); |
49ff59039 tracing: add late... |
582 |
} |
287b6e68c tracing/function-... |
583 |
/* If the pid changed since the last trace, output this event */ |
9d9add34e tracing: Have fun... |
584 |
static void |
2fbcdb35a function-graph: c... |
585 |
verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) |
287b6e68c tracing/function-... |
586 |
{ |
d51090b34 tracing/function-... |
587 |
pid_t prev_pid; |
9005f3ebe tracing/function-... |
588 |
pid_t *last_pid; |
660c7f9be ftrace: add threa... |
589 |
|
2fbcdb35a function-graph: c... |
590 |
if (!data) |
9d9add34e tracing: Have fun... |
591 |
return; |
9005f3ebe tracing/function-... |
592 |
|
be1eca393 tracing: Fix func... |
593 |
last_pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid); |
9005f3ebe tracing/function-... |
594 595 |
if (*last_pid == pid) |
9d9add34e tracing: Have fun... |
596 |
return; |
fb52607af tracing/function-... |
597 |
|
9005f3ebe tracing/function-... |
598 599 |
prev_pid = *last_pid; *last_pid = pid; |
d51090b34 tracing/function-... |
600 |
|
9005f3ebe tracing/function-... |
601 |
if (prev_pid == -1) |
9d9add34e tracing: Have fun... |
602 |
return; |
d51090b34 tracing/function-... |
603 604 605 606 607 608 609 610 |
/* * Context-switch trace line: ------------------------------------------ | 1) migration/0--1 => sshd-1755 ------------------------------------------ */ |
9d9add34e tracing: Have fun... |
611 612 613 614 615 616 617 618 619 620 |
trace_seq_puts(s, " ------------------------------------------ "); print_graph_cpu(s, cpu); print_graph_proc(s, prev_pid); trace_seq_puts(s, " => "); print_graph_proc(s, pid); trace_seq_puts(s, " ------------------------------------------ "); |
287b6e68c tracing/function-... |
621 |
} |
b91facc36 tracing/function-... |
622 623 |
static struct ftrace_graph_ret_entry * get_return_for_leaf(struct trace_iterator *iter, |
83a8df618 tracing/function-... |
624 625 |
struct ftrace_graph_ent_entry *curr) { |
be1eca393 tracing: Fix func... |
626 627 |
struct fgraph_data *data = iter->private; struct ring_buffer_iter *ring_iter = NULL; |
83a8df618 tracing/function-... |
628 629 |
struct ring_buffer_event *event; struct ftrace_graph_ret_entry *next; |
be1eca393 tracing: Fix func... |
630 631 632 633 634 635 636 637 |
/* * 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 tracing/function-... |
638 |
|
6d158a813 tracing: Remove N... |
639 |
ring_iter = trace_buffer_iter(iter, iter->cpu); |
be1eca393 tracing: Fix func... |
640 641 642 643 644 645 646 647 648 |
/* 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. */ |
12883efb6 tracing: Consolid... |
649 |
ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu, |
66a8cb95e ring-buffer: Add ... |
650 |
NULL, NULL); |
12883efb6 tracing: Consolid... |
651 |
event = ring_buffer_peek(iter->trace_buffer->buffer, iter->cpu, |
66a8cb95e ring-buffer: Add ... |
652 |
NULL, NULL); |
be1eca393 tracing: Fix func... |
653 |
} |
83a8df618 tracing/function-... |
654 |
|
be1eca393 tracing: Fix func... |
655 656 657 658 |
if (!event) return NULL; next = ring_buffer_event_data(event); |
83a8df618 tracing/function-... |
659 |
|
be1eca393 tracing: Fix func... |
660 661 662 663 664 665 |
if (data) { /* * Save current and next entries for later reference * if the output fails. */ data->ent = *curr; |
575570f02 tracing: Fix an u... |
666 667 668 669 670 671 672 673 674 |
/* * 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 tracing: Fix func... |
675 676 |
} } |
83a8df618 tracing/function-... |
677 678 |
if (next->ent.type != TRACE_GRAPH_RET) |
b91facc36 tracing/function-... |
679 |
return NULL; |
83a8df618 tracing/function-... |
680 681 682 |
if (curr->ent.pid != next->ent.pid || curr->graph_ent.func != next->ret.func) |
b91facc36 tracing/function-... |
683 |
return NULL; |
83a8df618 tracing/function-... |
684 |
|
b91facc36 tracing/function-... |
685 686 687 688 689 |
/* this is a leaf, now advance the iterator */ if (ring_iter) ring_buffer_read(ring_iter, NULL); return next; |
83a8df618 tracing/function-... |
690 |
} |
9d9add34e tracing: Have fun... |
691 |
static void print_graph_abs_time(u64 t, struct trace_seq *s) |
d1f9cbd78 tracing/function-... |
692 693 694 695 696 |
{ unsigned long usecs_rem; usecs_rem = do_div(t, NSEC_PER_SEC); usecs_rem /= 1000; |
9d9add34e tracing: Have fun... |
697 698 |
trace_seq_printf(s, "%5lu.%06lu | ", (unsigned long)t, usecs_rem); |
d1f9cbd78 tracing/function-... |
699 |
} |
9d9add34e tracing: Have fun... |
700 |
static void |
d1f9cbd78 tracing/function-... |
701 |
print_graph_irq(struct trace_iterator *iter, unsigned long addr, |
d7a8d9e90 tracing: Have gra... |
702 |
enum trace_type type, int cpu, pid_t pid, u32 flags) |
f8b755ac8 tracing/function-... |
703 |
{ |
983f938ae tracing: Move tra... |
704 |
struct trace_array *tr = iter->tr; |
d1f9cbd78 tracing/function-... |
705 |
struct trace_seq *s = &iter->seq; |
678f845ed ftrace-graph: sho... |
706 |
struct trace_entry *ent = iter->ent; |
f8b755ac8 tracing/function-... |
707 708 709 |
if (addr < (unsigned long)__irqentry_text_start || addr >= (unsigned long)__irqentry_text_end) |
9d9add34e tracing: Have fun... |
710 |
return; |
f8b755ac8 tracing/function-... |
711 |
|
983f938ae tracing: Move tra... |
712 |
if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO) { |
749230b06 tracing, function... |
713 |
/* Absolute time */ |
9d9add34e tracing: Have fun... |
714 715 |
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) print_graph_abs_time(iter->ts, s); |
d1f9cbd78 tracing/function-... |
716 |
|
749230b06 tracing, function... |
717 |
/* Cpu */ |
9d9add34e tracing: Have fun... |
718 719 |
if (flags & TRACE_GRAPH_PRINT_CPU) print_graph_cpu(s, cpu); |
49ff59039 tracing: add late... |
720 |
|
749230b06 tracing, function... |
721 722 |
/* Proc */ if (flags & TRACE_GRAPH_PRINT_PROC) { |
9d9add34e tracing: Have fun... |
723 724 |
print_graph_proc(s, pid); trace_seq_puts(s, " | "); |
749230b06 tracing, function... |
725 |
} |
678f845ed ftrace-graph: sho... |
726 727 |
/* Latency format */ |
983f938ae tracing: Move tra... |
728 |
if (tr->trace_flags & TRACE_ITER_LATENCY_FMT) |
9d9add34e tracing: Have fun... |
729 |
print_graph_lat_fmt(s, ent); |
9005f3ebe tracing/function-... |
730 |
} |
f8b755ac8 tracing/function-... |
731 |
|
9005f3ebe tracing/function-... |
732 |
/* No overhead */ |
983f938ae tracing: Move tra... |
733 |
print_graph_duration(tr, 0, s, flags | FLAGS_FILL_START); |
f8b755ac8 tracing/function-... |
734 |
|
9005f3ebe tracing/function-... |
735 |
if (type == TRACE_GRAPH_ENT) |
9d9add34e tracing: Have fun... |
736 |
trace_seq_puts(s, "==========>"); |
9005f3ebe tracing/function-... |
737 |
else |
9d9add34e tracing: Have fun... |
738 |
trace_seq_puts(s, "<=========="); |
9005f3ebe tracing/function-... |
739 |
|
983f938ae tracing: Move tra... |
740 |
print_graph_duration(tr, 0, s, flags | FLAGS_FILL_END); |
9d9add34e tracing: Have fun... |
741 742 |
trace_seq_putc(s, ' '); |
f8b755ac8 tracing/function-... |
743 |
} |
83a8df618 tracing/function-... |
744 |
|
9d9add34e tracing: Have fun... |
745 |
void |
0706f1c48 tracing: adding f... |
746 |
trace_print_graph_duration(unsigned long long duration, struct trace_seq *s) |
83a8df618 tracing/function-... |
747 748 |
{ unsigned long nsecs_rem = do_div(duration, 1000); |
166d3c799 tracing/function-... |
749 |
/* log10(ULONG_MAX) + '\0' */ |
4526d0676 function_graph: F... |
750 |
char usecs_str[21]; |
166d3c799 tracing/function-... |
751 |
char nsecs_str[5]; |
9d9add34e tracing: Have fun... |
752 |
int len; |
166d3c799 tracing/function-... |
753 |
int i; |
4526d0676 function_graph: F... |
754 |
sprintf(usecs_str, "%lu", (unsigned long) duration); |
166d3c799 tracing/function-... |
755 756 |
/* Print msecs */ |
9d9add34e tracing: Have fun... |
757 |
trace_seq_printf(s, "%s", usecs_str); |
166d3c799 tracing/function-... |
758 |
|
4526d0676 function_graph: F... |
759 |
len = strlen(usecs_str); |
166d3c799 tracing/function-... |
760 761 762 |
/* Print nsecs (we don't want to exceed 7 numbers) */ if (len < 7) { |
14cae9bd2 tracing: Fix func... |
763 764 765 |
size_t slen = min_t(size_t, sizeof(nsecs_str), 8UL - len); snprintf(nsecs_str, slen, "%03lu", nsecs_rem); |
9d9add34e tracing: Have fun... |
766 |
trace_seq_printf(s, ".%s", nsecs_str); |
82c355e81 ftrace: Fix funct... |
767 |
len += strlen(nsecs_str) + 1; |
166d3c799 tracing/function-... |
768 |
} |
9d9add34e tracing: Have fun... |
769 |
trace_seq_puts(s, " us "); |
166d3c799 tracing/function-... |
770 771 |
/* Print remaining spaces to fit the row's width */ |
82c355e81 ftrace: Fix funct... |
772 |
for (i = len; i < 8; i++) |
9d9add34e tracing: Have fun... |
773 |
trace_seq_putc(s, ' '); |
0706f1c48 tracing: adding f... |
774 |
} |
9d9add34e tracing: Have fun... |
775 |
static void |
983f938ae tracing: Move tra... |
776 777 |
print_graph_duration(struct trace_array *tr, unsigned long long duration, struct trace_seq *s, u32 flags) |
0706f1c48 tracing: adding f... |
778 |
{ |
749230b06 tracing, function... |
779 |
if (!(flags & TRACE_GRAPH_PRINT_DURATION) || |
983f938ae tracing: Move tra... |
780 |
!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO)) |
9d9add34e tracing: Have fun... |
781 |
return; |
ffeb80fc3 tracing, function... |
782 783 |
/* No real adata, just filling the column with spaces */ |
6fc84ea70 tracing: Do not u... |
784 785 |
switch (flags & TRACE_GRAPH_PRINT_FILL_MASK) { case FLAGS_FILL_FULL: |
9d9add34e tracing: Have fun... |
786 787 |
trace_seq_puts(s, " | "); return; |
6fc84ea70 tracing: Do not u... |
788 |
case FLAGS_FILL_START: |
9d9add34e tracing: Have fun... |
789 790 |
trace_seq_puts(s, " "); return; |
6fc84ea70 tracing: Do not u... |
791 |
case FLAGS_FILL_END: |
9d9add34e tracing: Have fun... |
792 793 |
trace_seq_puts(s, " |"); return; |
ffeb80fc3 tracing, function... |
794 795 796 |
} /* Signal a overhead of time execution to the output */ |
8e1e1df29 tracing: Add addi... |
797 798 799 |
if (flags & TRACE_GRAPH_PRINT_OVERHEAD) trace_seq_printf(s, "%c ", trace_find_mark(duration)); else |
9d9add34e tracing: Have fun... |
800 |
trace_seq_puts(s, " "); |
0706f1c48 tracing: adding f... |
801 |
|
9d9add34e tracing: Have fun... |
802 803 |
trace_print_graph_duration(duration, s); trace_seq_puts(s, "| "); |
83a8df618 tracing/function-... |
804 |
} |
83a8df618 tracing/function-... |
805 |
/* Case of a leaf function on its call entry */ |
287b6e68c tracing/function-... |
806 |
static enum print_line_t |
83a8df618 tracing/function-... |
807 |
print_graph_entry_leaf(struct trace_iterator *iter, |
b91facc36 tracing/function-... |
808 |
struct ftrace_graph_ent_entry *entry, |
d7a8d9e90 tracing: Have gra... |
809 810 |
struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s, u32 flags) |
fb52607af tracing/function-... |
811 |
{ |
2fbcdb35a function-graph: c... |
812 |
struct fgraph_data *data = iter->private; |
983f938ae tracing: Move tra... |
813 |
struct trace_array *tr = iter->tr; |
83a8df618 tracing/function-... |
814 |
struct ftrace_graph_ret *graph_ret; |
83a8df618 tracing/function-... |
815 816 |
struct ftrace_graph_ent *call; unsigned long long duration; |
1fe4293f4 tracing: Fix miss... |
817 |
int cpu = iter->cpu; |
1a056155e tracing/function-... |
818 |
int i; |
fb52607af tracing/function-... |
819 |
|
83a8df618 tracing/function-... |
820 821 822 |
graph_ret = &ret_entry->ret; call = &entry->graph_ent; duration = graph_ret->rettime - graph_ret->calltime; |
2fbcdb35a function-graph: c... |
823 |
if (data) { |
f1c7f517a ftrace: Add funct... |
824 |
struct fgraph_cpu_data *cpu_data; |
f1c7f517a ftrace: Add funct... |
825 826 |
cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
2fbcdb35a function-graph: c... |
827 |
|
794de08a1 fgraph: Handle a ... |
828 829 830 |
/* If a graph tracer ignored set_graph_notrace */ if (call->depth < -1) call->depth += FTRACE_NOTRACE_DEPTH; |
2fbcdb35a function-graph: c... |
831 832 833 834 835 |
/* * Comments display at + 1 to depth. Since * this is a leaf function, keep the comments * equal to this depth. */ |
f1c7f517a ftrace: Add funct... |
836 837 838 |
cpu_data->depth = call->depth - 1; /* No need to keep this function around for this depth */ |
794de08a1 fgraph: Handle a ... |
839 840 |
if (call->depth < FTRACE_RETFUNC_DEPTH && !WARN_ON_ONCE(call->depth < 0)) |
f1c7f517a ftrace: Add funct... |
841 |
cpu_data->enter_funcs[call->depth] = 0; |
2fbcdb35a function-graph: c... |
842 |
} |
ffeb80fc3 tracing, function... |
843 |
/* Overhead and duration */ |
983f938ae tracing: Move tra... |
844 |
print_graph_duration(tr, duration, s, flags); |
1a056155e tracing/function-... |
845 |
|
83a8df618 tracing/function-... |
846 |
/* Function */ |
9d9add34e tracing: Have fun... |
847 848 |
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) trace_seq_putc(s, ' '); |
83a8df618 tracing/function-... |
849 |
|
9d9add34e tracing: Have fun... |
850 851 |
trace_seq_printf(s, "%ps(); ", (void *)call->func); |
83a8df618 tracing/function-... |
852 |
|
1fe4293f4 tracing: Fix miss... |
853 854 |
print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET, cpu, iter->ent->pid, flags); |
9d9add34e tracing: Have fun... |
855 |
return trace_handle_return(s); |
83a8df618 tracing/function-... |
856 857 858 |
} static enum print_line_t |
2fbcdb35a function-graph: c... |
859 860 |
print_graph_entry_nested(struct trace_iterator *iter, struct ftrace_graph_ent_entry *entry, |
d7a8d9e90 tracing: Have gra... |
861 |
struct trace_seq *s, int cpu, u32 flags) |
83a8df618 tracing/function-... |
862 |
{ |
83a8df618 tracing/function-... |
863 |
struct ftrace_graph_ent *call = &entry->graph_ent; |
2fbcdb35a function-graph: c... |
864 |
struct fgraph_data *data = iter->private; |
983f938ae tracing: Move tra... |
865 |
struct trace_array *tr = iter->tr; |
2fbcdb35a function-graph: c... |
866 867 868 |
int i; if (data) { |
f1c7f517a ftrace: Add funct... |
869 |
struct fgraph_cpu_data *cpu_data; |
2fbcdb35a function-graph: c... |
870 |
int cpu = iter->cpu; |
2fbcdb35a function-graph: c... |
871 |
|
794de08a1 fgraph: Handle a ... |
872 873 874 |
/* If a graph tracer ignored set_graph_notrace */ if (call->depth < -1) call->depth += FTRACE_NOTRACE_DEPTH; |
f1c7f517a ftrace: Add funct... |
875 876 877 878 |
cpu_data = per_cpu_ptr(data->cpu_data, cpu); cpu_data->depth = call->depth; /* Save this function pointer to see if the exit matches */ |
794de08a1 fgraph: Handle a ... |
879 880 |
if (call->depth < FTRACE_RETFUNC_DEPTH && !WARN_ON_ONCE(call->depth < 0)) |
f1c7f517a ftrace: Add funct... |
881 |
cpu_data->enter_funcs[call->depth] = call->func; |
2fbcdb35a function-graph: c... |
882 |
} |
83a8df618 tracing/function-... |
883 |
|
9005f3ebe tracing/function-... |
884 |
/* No time */ |
983f938ae tracing: Move tra... |
885 |
print_graph_duration(tr, 0, s, flags | FLAGS_FILL_FULL); |
f8b755ac8 tracing/function-... |
886 |
|
83a8df618 tracing/function-... |
887 |
/* Function */ |
9d9add34e tracing: Have fun... |
888 889 890 891 892 |
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) trace_seq_putc(s, ' '); trace_seq_printf(s, "%ps() { ", (void *)call->func); |
287b6e68c tracing/function-... |
893 |
|
9d9add34e tracing: Have fun... |
894 |
if (trace_seq_has_overflowed(s)) |
83a8df618 tracing/function-... |
895 |
return TRACE_TYPE_PARTIAL_LINE; |
b91facc36 tracing/function-... |
896 897 898 899 900 |
/* * we already consumed the current entry to check the next one * and see if this is a leaf. */ return TRACE_TYPE_NO_CONSUME; |
287b6e68c tracing/function-... |
901 |
} |
9d9add34e tracing: Have fun... |
902 |
static void |
ac5f6c968 function-graph: c... |
903 |
print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, |
d7a8d9e90 tracing: Have gra... |
904 |
int type, unsigned long addr, u32 flags) |
83a8df618 tracing/function-... |
905 |
{ |
2fbcdb35a function-graph: c... |
906 |
struct fgraph_data *data = iter->private; |
83a8df618 tracing/function-... |
907 |
struct trace_entry *ent = iter->ent; |
983f938ae tracing: Move tra... |
908 |
struct trace_array *tr = iter->tr; |
ac5f6c968 function-graph: c... |
909 |
int cpu = iter->cpu; |
83a8df618 tracing/function-... |
910 |
|
1a056155e tracing/function-... |
911 |
/* Pid */ |
9d9add34e tracing: Have fun... |
912 |
verif_pid(s, ent->pid, cpu, data); |
9005f3ebe tracing/function-... |
913 |
|
9d9add34e tracing: Have fun... |
914 |
if (type) |
ac5f6c968 function-graph: c... |
915 |
/* Interrupt */ |
9d9add34e tracing: Have fun... |
916 |
print_graph_irq(iter, addr, type, cpu, ent->pid, flags); |
83a8df618 tracing/function-... |
917 |
|
983f938ae tracing: Move tra... |
918 |
if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO)) |
9d9add34e tracing: Have fun... |
919 |
return; |
749230b06 tracing, function... |
920 |
|
9005f3ebe tracing/function-... |
921 |
/* Absolute time */ |
9d9add34e tracing: Have fun... |
922 923 |
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) print_graph_abs_time(iter->ts, s); |
9005f3ebe tracing/function-... |
924 |
|
1a056155e tracing/function-... |
925 |
/* Cpu */ |
9d9add34e tracing: Have fun... |
926 927 |
if (flags & TRACE_GRAPH_PRINT_CPU) print_graph_cpu(s, cpu); |
11e84acc4 tracing/function-... |
928 929 |
/* Proc */ |
d7a8d9e90 tracing: Have gra... |
930 |
if (flags & TRACE_GRAPH_PRINT_PROC) { |
9d9add34e tracing: Have fun... |
931 932 |
print_graph_proc(s, ent->pid); trace_seq_puts(s, " | "); |
1a056155e tracing/function-... |
933 |
} |
83a8df618 tracing/function-... |
934 |
|
49ff59039 tracing: add late... |
935 |
/* Latency format */ |
983f938ae tracing: Move tra... |
936 |
if (tr->trace_flags & TRACE_ITER_LATENCY_FMT) |
9d9add34e tracing: Have fun... |
937 |
print_graph_lat_fmt(s, ent); |
49ff59039 tracing: add late... |
938 |
|
9d9add34e tracing: Have fun... |
939 |
return; |
ac5f6c968 function-graph: c... |
940 |
} |
2bd16212b tracing: Add func... |
941 942 943 944 945 |
/* * Entry check for irq code * * returns 1 if * - we are inside irq code |
25985edce Fix common misspe... |
946 |
* - we just entered irq code |
2bd16212b tracing: Add func... |
947 948 949 950 951 952 953 954 955 956 |
* * 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 tracing: Add prop... |
957 |
int *depth_irq; |
2bd16212b tracing: Add func... |
958 |
struct fgraph_data *data = iter->private; |
2bd16212b tracing: Add func... |
959 |
|
a9d61173d tracing: Add prop... |
960 961 962 963 964 965 966 |
/* * 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 tracing: Add func... |
967 |
return 0; |
a9d61173d tracing: Add prop... |
968 |
depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); |
2bd16212b tracing: Add func... |
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
/* * 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 tracing: Add prop... |
1001 |
int *depth_irq; |
2bd16212b tracing: Add func... |
1002 |
struct fgraph_data *data = iter->private; |
2bd16212b tracing: Add func... |
1003 |
|
a9d61173d tracing: Add prop... |
1004 1005 1006 1007 1008 1009 1010 |
/* * 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 tracing: Add func... |
1011 |
return 0; |
a9d61173d tracing: Add prop... |
1012 |
depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); |
2bd16212b tracing: Add func... |
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 |
/* * 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 function-graph: c... |
1038 1039 |
static enum print_line_t print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, |
d7a8d9e90 tracing: Have gra... |
1040 |
struct trace_iterator *iter, u32 flags) |
ac5f6c968 function-graph: c... |
1041 |
{ |
be1eca393 tracing: Fix func... |
1042 |
struct fgraph_data *data = iter->private; |
ac5f6c968 function-graph: c... |
1043 1044 |
struct ftrace_graph_ent *call = &field->graph_ent; struct ftrace_graph_ret_entry *leaf_ret; |
be1eca393 tracing: Fix func... |
1045 1046 |
static enum print_line_t ret; int cpu = iter->cpu; |
ac5f6c968 function-graph: c... |
1047 |
|
2bd16212b tracing: Add func... |
1048 1049 |
if (check_irq_entry(iter, flags, call->func, call->depth)) return TRACE_TYPE_HANDLED; |
9d9add34e tracing: Have fun... |
1050 |
print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags); |
ac5f6c968 function-graph: c... |
1051 |
|
b91facc36 tracing/function-... |
1052 1053 |
leaf_ret = get_return_for_leaf(iter, field); if (leaf_ret) |
d7a8d9e90 tracing: Have gra... |
1054 |
ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags); |
83a8df618 tracing/function-... |
1055 |
else |
d7a8d9e90 tracing: Have gra... |
1056 |
ret = print_graph_entry_nested(iter, field, s, cpu, flags); |
83a8df618 tracing/function-... |
1057 |
|
be1eca393 tracing: Fix func... |
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 |
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 tracing/function-... |
1071 1072 1073 |
} static enum print_line_t |
287b6e68c tracing/function-... |
1074 |
print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, |
d7a8d9e90 tracing: Have gra... |
1075 1076 |
struct trace_entry *ent, struct trace_iterator *iter, u32 flags) |
287b6e68c tracing/function-... |
1077 |
{ |
83a8df618 tracing/function-... |
1078 |
unsigned long long duration = trace->rettime - trace->calltime; |
2fbcdb35a function-graph: c... |
1079 |
struct fgraph_data *data = iter->private; |
983f938ae tracing: Move tra... |
1080 |
struct trace_array *tr = iter->tr; |
2fbcdb35a function-graph: c... |
1081 1082 |
pid_t pid = ent->pid; int cpu = iter->cpu; |
f1c7f517a ftrace: Add funct... |
1083 |
int func_match = 1; |
2fbcdb35a function-graph: c... |
1084 |
int i; |
2bd16212b tracing: Add func... |
1085 1086 |
if (check_irq_return(iter, flags, trace->depth)) return TRACE_TYPE_HANDLED; |
2fbcdb35a function-graph: c... |
1087 |
if (data) { |
f1c7f517a ftrace: Add funct... |
1088 1089 1090 1091 |
struct fgraph_cpu_data *cpu_data; int cpu = iter->cpu; cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
2fbcdb35a function-graph: c... |
1092 1093 1094 1095 1096 1097 |
/* * 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 ftrace: Add funct... |
1098 |
cpu_data->depth = trace->depth - 1; |
794de08a1 fgraph: Handle a ... |
1099 1100 |
if (trace->depth < FTRACE_RETFUNC_DEPTH && !WARN_ON_ONCE(trace->depth < 0)) { |
f1c7f517a ftrace: Add funct... |
1101 1102 1103 1104 |
if (cpu_data->enter_funcs[trace->depth] != trace->func) func_match = 0; cpu_data->enter_funcs[trace->depth] = 0; } |
2fbcdb35a function-graph: c... |
1105 |
} |
287b6e68c tracing/function-... |
1106 |
|
9d9add34e tracing: Have fun... |
1107 |
print_graph_prologue(iter, s, 0, 0, flags); |
437f24fb8 ftrace: add cpu a... |
1108 |
|
ffeb80fc3 tracing, function... |
1109 |
/* Overhead and duration */ |
983f938ae tracing: Move tra... |
1110 |
print_graph_duration(tr, duration, s, flags); |
1a056155e tracing/function-... |
1111 |
|
83a8df618 tracing/function-... |
1112 |
/* Closing brace */ |
9d9add34e tracing: Have fun... |
1113 1114 |
for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) trace_seq_putc(s, ' '); |
287b6e68c tracing/function-... |
1115 |
|
f1c7f517a ftrace: Add funct... |
1116 1117 1118 1119 |
/* * 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 |
607e3a292 tracing: Add func... |
1120 1121 |
* belongs to, write out the function name. Always do * that if the funcgraph-tail option is enabled. |
f1c7f517a ftrace: Add funct... |
1122 |
*/ |
9d9add34e tracing: Have fun... |
1123 1124 1125 1126 1127 1128 |
if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL)) trace_seq_puts(s, "} "); else trace_seq_printf(s, "} /* %ps */ ", (void *)trace->func); |
fb52607af tracing/function-... |
1129 |
|
83a8df618 tracing/function-... |
1130 |
/* Overrun */ |
9d9add34e tracing: Have fun... |
1131 1132 1133 1134 |
if (flags & TRACE_GRAPH_PRINT_OVERRUN) trace_seq_printf(s, " (Overruns: %lu) ", trace->overrun); |
f8b755ac8 tracing/function-... |
1135 |
|
9d9add34e tracing: Have fun... |
1136 1137 |
print_graph_irq(iter, trace->func, TRACE_GRAPH_RET, cpu, pid, flags); |
f8b755ac8 tracing/function-... |
1138 |
|
9d9add34e tracing: Have fun... |
1139 |
return trace_handle_return(s); |
287b6e68c tracing/function-... |
1140 |
} |
1fd8f2a3f tracing/function-... |
1141 |
static enum print_line_t |
d7a8d9e90 tracing: Have gra... |
1142 1143 |
print_graph_comment(struct trace_seq *s, struct trace_entry *ent, struct trace_iterator *iter, u32 flags) |
1fd8f2a3f tracing/function-... |
1144 |
{ |
983f938ae tracing: Move tra... |
1145 1146 |
struct trace_array *tr = iter->tr; unsigned long sym_flags = (tr->trace_flags & TRACE_ITER_SYM_MASK); |
2fbcdb35a function-graph: c... |
1147 |
struct fgraph_data *data = iter->private; |
5087f8d2a function-graph: s... |
1148 |
struct trace_event *event; |
2fbcdb35a function-graph: c... |
1149 |
int depth = 0; |
1fd8f2a3f tracing/function-... |
1150 |
int ret; |
2fbcdb35a function-graph: c... |
1151 1152 1153 |
int i; if (data) |
be1eca393 tracing: Fix func... |
1154 |
depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth; |
9005f3ebe tracing/function-... |
1155 |
|
9d9add34e tracing: Have fun... |
1156 |
print_graph_prologue(iter, s, 0, 0, flags); |
d1f9cbd78 tracing/function-... |
1157 |
|
9005f3ebe tracing/function-... |
1158 |
/* No time */ |
983f938ae tracing: Move tra... |
1159 |
print_graph_duration(tr, 0, s, flags | FLAGS_FILL_FULL); |
1fd8f2a3f tracing/function-... |
1160 |
|
1fd8f2a3f tracing/function-... |
1161 |
/* Indentation */ |
2fbcdb35a function-graph: c... |
1162 |
if (depth > 0) |
9d9add34e tracing: Have fun... |
1163 1164 |
for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) trace_seq_putc(s, ' '); |
1fd8f2a3f tracing/function-... |
1165 1166 |
/* The comment */ |
9d9add34e tracing: Have fun... |
1167 |
trace_seq_puts(s, "/* "); |
769b0441f tracing/core: dro... |
1168 |
|
5087f8d2a function-graph: s... |
1169 |
switch (iter->ent->type) { |
613dccdf6 function_graph: H... |
1170 1171 1172 1173 1174 |
case TRACE_BPUTS: ret = trace_print_bputs_msg_only(iter); if (ret != TRACE_TYPE_HANDLED) return ret; break; |
5087f8d2a function-graph: s... |
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
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 tracing: Allow ev... |
1189 |
ret = event->funcs->trace(iter, sym_flags, event); |
5087f8d2a function-graph: s... |
1190 1191 1192 |
if (ret != TRACE_TYPE_HANDLED) return ret; } |
1fd8f2a3f tracing/function-... |
1193 |
|
5ac483784 tracing: Use trac... |
1194 1195 |
if (trace_seq_has_overflowed(s)) goto out; |
412d0bb55 tracing/function-... |
1196 |
/* Strip ending newline */ |
3a161d99c tracing: Create s... |
1197 1198 1199 1200 |
if (s->buffer[s->seq.len - 1] == ' ') { s->buffer[s->seq.len - 1] = '\0'; s->seq.len--; |
412d0bb55 tracing/function-... |
1201 |
} |
9d9add34e tracing: Have fun... |
1202 1203 |
trace_seq_puts(s, " */ "); |
5ac483784 tracing: Use trac... |
1204 |
out: |
9d9add34e tracing: Have fun... |
1205 |
return trace_handle_return(s); |
1fd8f2a3f tracing/function-... |
1206 |
} |
287b6e68c tracing/function-... |
1207 |
enum print_line_t |
321e68b09 tracing, function... |
1208 |
print_graph_function_flags(struct trace_iterator *iter, u32 flags) |
287b6e68c tracing/function-... |
1209 |
{ |
be1eca393 tracing: Fix func... |
1210 1211 |
struct ftrace_graph_ent_entry *field; struct fgraph_data *data = iter->private; |
287b6e68c tracing/function-... |
1212 |
struct trace_entry *entry = iter->ent; |
5087f8d2a function-graph: s... |
1213 |
struct trace_seq *s = &iter->seq; |
be1eca393 tracing: Fix func... |
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 |
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 tracing: Have gra... |
1229 |
ret = print_graph_entry(field, s, iter, flags); |
be1eca393 tracing: Fix func... |
1230 1231 1232 1233 1234 1235 1236 |
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 tracing/function-... |
1237 |
|
287b6e68c tracing/function-... |
1238 1239 |
switch (entry->type) { case TRACE_GRAPH_ENT: { |
38ceb592f tracing: Fix inva... |
1240 1241 1242 1243 1244 1245 |
/* * 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 tracing: Fix func... |
1246 |
struct ftrace_graph_ent_entry saved; |
287b6e68c tracing/function-... |
1247 |
trace_assign_type(field, entry); |
38ceb592f tracing: Fix inva... |
1248 |
saved = *field; |
d7a8d9e90 tracing: Have gra... |
1249 |
return print_graph_entry(&saved, s, iter, flags); |
287b6e68c tracing/function-... |
1250 1251 1252 1253 |
} case TRACE_GRAPH_RET: { struct ftrace_graph_ret_entry *field; trace_assign_type(field, entry); |
d7a8d9e90 tracing: Have gra... |
1254 |
return print_graph_return(&field->ret, s, entry, iter, flags); |
287b6e68c tracing/function-... |
1255 |
} |
62b915f10 tracing: Add grap... |
1256 1257 1258 1259 |
case TRACE_STACK: case TRACE_FN: /* dont trace stack and functions as comments */ return TRACE_TYPE_UNHANDLED; |
287b6e68c tracing/function-... |
1260 |
default: |
d7a8d9e90 tracing: Have gra... |
1261 |
return print_graph_comment(s, entry, iter, flags); |
fb52607af tracing/function-... |
1262 |
} |
5087f8d2a function-graph: s... |
1263 1264 |
return TRACE_TYPE_HANDLED; |
fb52607af tracing/function-... |
1265 |
} |
9106b6938 tracing: Add ftra... |
1266 |
static enum print_line_t |
d7a8d9e90 tracing: Have gra... |
1267 1268 |
print_graph_function(struct trace_iterator *iter) { |
321e68b09 tracing, function... |
1269 |
return print_graph_function_flags(iter, tracer_flags.val); |
d7a8d9e90 tracing: Have gra... |
1270 1271 1272 |
} static enum print_line_t |
a9a577638 tracing: Allow ev... |
1273 1274 |
print_graph_function_event(struct trace_iterator *iter, int flags, struct trace_event *event) |
9106b6938 tracing: Add ftra... |
1275 1276 1277 |
{ return print_graph_function(iter); } |
d7a8d9e90 tracing: Have gra... |
1278 |
static void print_lat_header(struct seq_file *s, u32 flags) |
49ff59039 tracing: add late... |
1279 1280 1281 1282 1283 |
{ static const char spaces[] = " " /* 16 spaces */ " " /* 4 spaces */ " "; /* 17 spaces */ int size = 0; |
d7a8d9e90 tracing: Have gra... |
1284 |
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) |
49ff59039 tracing: add late... |
1285 |
size += 16; |
d7a8d9e90 tracing: Have gra... |
1286 |
if (flags & TRACE_GRAPH_PRINT_CPU) |
49ff59039 tracing: add late... |
1287 |
size += 4; |
d7a8d9e90 tracing: Have gra... |
1288 |
if (flags & TRACE_GRAPH_PRINT_PROC) |
49ff59039 tracing: add late... |
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 |
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 tracing, function... |
1299 1300 |
seq_printf(s, "#%.*s||| / ", size, spaces); |
49ff59039 tracing: add late... |
1301 |
} |
983f938ae tracing: Move tra... |
1302 1303 |
static void __print_graph_headers_flags(struct trace_array *tr, struct seq_file *s, u32 flags) |
decbec383 tracing/function-... |
1304 |
{ |
983f938ae tracing: Move tra... |
1305 |
int lat = tr->trace_flags & TRACE_ITER_LATENCY_FMT; |
49ff59039 tracing: add late... |
1306 1307 |
if (lat) |
d7a8d9e90 tracing: Have gra... |
1308 |
print_lat_header(s, flags); |
49ff59039 tracing: add late... |
1309 |
|
decbec383 tracing/function-... |
1310 |
/* 1st line */ |
1177e4364 trace: Replace si... |
1311 |
seq_putc(s, '#'); |
d7a8d9e90 tracing: Have gra... |
1312 |
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) |
fa6f0cc75 tracing: Replace ... |
1313 |
seq_puts(s, " TIME "); |
d7a8d9e90 tracing: Have gra... |
1314 |
if (flags & TRACE_GRAPH_PRINT_CPU) |
fa6f0cc75 tracing: Replace ... |
1315 |
seq_puts(s, " CPU"); |
d7a8d9e90 tracing: Have gra... |
1316 |
if (flags & TRACE_GRAPH_PRINT_PROC) |
fa6f0cc75 tracing: Replace ... |
1317 |
seq_puts(s, " TASK/PID "); |
49ff59039 tracing: add late... |
1318 |
if (lat) |
fa6f0cc75 tracing: Replace ... |
1319 |
seq_puts(s, "||||"); |
d7a8d9e90 tracing: Have gra... |
1320 |
if (flags & TRACE_GRAPH_PRINT_DURATION) |
fa6f0cc75 tracing: Replace ... |
1321 1322 1323 |
seq_puts(s, " DURATION "); seq_puts(s, " FUNCTION CALLS "); |
decbec383 tracing/function-... |
1324 1325 |
/* 2nd line */ |
1177e4364 trace: Replace si... |
1326 |
seq_putc(s, '#'); |
d7a8d9e90 tracing: Have gra... |
1327 |
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) |
fa6f0cc75 tracing: Replace ... |
1328 |
seq_puts(s, " | "); |
d7a8d9e90 tracing: Have gra... |
1329 |
if (flags & TRACE_GRAPH_PRINT_CPU) |
fa6f0cc75 tracing: Replace ... |
1330 |
seq_puts(s, " | "); |
d7a8d9e90 tracing: Have gra... |
1331 |
if (flags & TRACE_GRAPH_PRINT_PROC) |
fa6f0cc75 tracing: Replace ... |
1332 |
seq_puts(s, " | | "); |
49ff59039 tracing: add late... |
1333 |
if (lat) |
fa6f0cc75 tracing: Replace ... |
1334 |
seq_puts(s, "||||"); |
d7a8d9e90 tracing: Have gra... |
1335 |
if (flags & TRACE_GRAPH_PRINT_DURATION) |
fa6f0cc75 tracing: Replace ... |
1336 1337 1338 |
seq_puts(s, " | | "); seq_puts(s, " | | | | "); |
decbec383 tracing/function-... |
1339 |
} |
9005f3ebe tracing/function-... |
1340 |
|
ba1afef6a tracing: Convert ... |
1341 |
static void print_graph_headers(struct seq_file *s) |
d7a8d9e90 tracing: Have gra... |
1342 1343 1344 |
{ print_graph_headers_flags(s, tracer_flags.val); } |
0a772620a tracing: Make gra... |
1345 1346 1347 |
void print_graph_headers_flags(struct seq_file *s, u32 flags) { struct trace_iterator *iter = s->private; |
983f938ae tracing: Move tra... |
1348 |
struct trace_array *tr = iter->tr; |
0a772620a tracing: Make gra... |
1349 |
|
983f938ae tracing: Move tra... |
1350 |
if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO)) |
749230b06 tracing, function... |
1351 |
return; |
983f938ae tracing: Move tra... |
1352 |
if (tr->trace_flags & TRACE_ITER_LATENCY_FMT) { |
0a772620a tracing: Make gra... |
1353 1354 1355 1356 1357 |
/* print nothing if the buffers are empty */ if (trace_empty(iter)) return; print_trace_header(s, iter); |
321e68b09 tracing, function... |
1358 |
} |
0a772620a tracing: Make gra... |
1359 |
|
983f938ae tracing: Move tra... |
1360 |
__print_graph_headers_flags(tr, s, flags); |
0a772620a tracing: Make gra... |
1361 |
} |
62b915f10 tracing: Add grap... |
1362 |
void graph_trace_open(struct trace_iterator *iter) |
9005f3ebe tracing/function-... |
1363 |
{ |
2fbcdb35a function-graph: c... |
1364 |
/* pid and depth on the last trace processed */ |
be1eca393 tracing: Fix func... |
1365 |
struct fgraph_data *data; |
ef99b88b1 tracing: Handle f... |
1366 |
gfp_t gfpflags; |
9005f3ebe tracing/function-... |
1367 |
int cpu; |
be1eca393 tracing: Fix func... |
1368 |
iter->private = NULL; |
ef99b88b1 tracing: Handle f... |
1369 1370 1371 1372 |
/* We can be called in atomic context via ftrace_dump() */ gfpflags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; data = kzalloc(sizeof(*data), gfpflags); |
2fbcdb35a function-graph: c... |
1373 |
if (!data) |
be1eca393 tracing: Fix func... |
1374 |
goto out_err; |
ef99b88b1 tracing: Handle f... |
1375 |
data->cpu_data = alloc_percpu_gfp(struct fgraph_cpu_data, gfpflags); |
be1eca393 tracing: Fix func... |
1376 1377 1378 1379 1380 1381 1382 |
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 tracing: Add func... |
1383 |
int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); |
be1eca393 tracing: Fix func... |
1384 1385 1386 |
*pid = -1; *depth = 0; *ignore = 0; |
2bd16212b tracing: Add func... |
1387 |
*depth_irq = -1; |
be1eca393 tracing: Fix func... |
1388 |
} |
9005f3ebe tracing/function-... |
1389 |
|
2fbcdb35a function-graph: c... |
1390 |
iter->private = data; |
be1eca393 tracing: Fix func... |
1391 1392 1393 1394 1395 1396 |
return; out_err_free: kfree(data); out_err: |
a395d6a7e kernel/...: conve... |
1397 1398 |
pr_warn("function graph tracer: not enough memory "); |
9005f3ebe tracing/function-... |
1399 |
} |
62b915f10 tracing: Add grap... |
1400 |
void graph_trace_close(struct trace_iterator *iter) |
9005f3ebe tracing/function-... |
1401 |
{ |
be1eca393 tracing: Fix func... |
1402 1403 1404 1405 1406 1407 |
struct fgraph_data *data = iter->private; if (data) { free_percpu(data->cpu_data); kfree(data); } |
9005f3ebe tracing/function-... |
1408 |
} |
8c1a49aed tracing: Pass tra... |
1409 1410 |
static int func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) |
b304d0441 tracing: Do not t... |
1411 1412 1413 |
{ if (bit == TRACE_GRAPH_PRINT_IRQS) ftrace_graph_skip_irqs = !set; |
555772041 tracing: Move sle... |
1414 1415 1416 1417 1418 |
if (bit == TRACE_GRAPH_SLEEP_TIME) ftrace_graph_sleep_time_control(set); if (bit == TRACE_GRAPH_GRAPH_TIME) ftrace_graph_graph_time_control(set); |
b304d0441 tracing: Do not t... |
1419 1420 |
return 0; } |
a9a577638 tracing: Allow ev... |
1421 1422 1423 |
static struct trace_event_functions graph_functions = { .trace = print_graph_function_event, }; |
9106b6938 tracing: Add ftra... |
1424 1425 |
static struct trace_event graph_trace_entry_event = { .type = TRACE_GRAPH_ENT, |
a9a577638 tracing: Allow ev... |
1426 |
.funcs = &graph_functions, |
9106b6938 tracing: Add ftra... |
1427 1428 1429 1430 |
}; static struct trace_event graph_trace_ret_event = { .type = TRACE_GRAPH_RET, |
a9a577638 tracing: Allow ev... |
1431 |
.funcs = &graph_functions |
9106b6938 tracing: Add ftra... |
1432 |
}; |
8f7689933 tracing: Add ref_... |
1433 |
static struct tracer graph_trace __tracer_data = { |
ef18012b2 tracing: remove f... |
1434 |
.name = "function_graph", |
6508fa761 tracing: let user... |
1435 |
.update_thresh = graph_trace_update_thresh, |
9005f3ebe tracing/function-... |
1436 |
.open = graph_trace_open, |
be1eca393 tracing: Fix func... |
1437 |
.pipe_open = graph_trace_open, |
9005f3ebe tracing/function-... |
1438 |
.close = graph_trace_close, |
be1eca393 tracing: Fix func... |
1439 |
.pipe_close = graph_trace_close, |
ef18012b2 tracing: remove f... |
1440 1441 |
.init = graph_trace_init, .reset = graph_trace_reset, |
decbec383 tracing/function-... |
1442 1443 |
.print_line = print_graph_function, .print_header = print_graph_headers, |
fb52607af tracing/function-... |
1444 |
.flags = &tracer_flags, |
b304d0441 tracing: Do not t... |
1445 |
.set_flag = func_graph_set_flag, |
7447dce96 tracing/function-... |
1446 1447 1448 |
#ifdef CONFIG_FTRACE_SELFTEST .selftest = trace_selftest_startup_function_graph, #endif |
fb52607af tracing/function-... |
1449 |
}; |
8741db532 tracing/fgraph: A... |
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 |
static ssize_t graph_depth_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { unsigned long val; int ret; ret = kstrtoul_from_user(ubuf, cnt, 10, &val); if (ret) return ret; |
1a4144286 tracing/fgraph: H... |
1461 |
fgraph_max_depth = val; |
8741db532 tracing/fgraph: A... |
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 |
*ppos += cnt; return cnt; } static ssize_t graph_depth_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[15]; /* More than enough to hold UINT_MAX + " "*/ int n; |
1a4144286 tracing/fgraph: H... |
1475 1476 |
n = sprintf(buf, "%d ", fgraph_max_depth); |
8741db532 tracing/fgraph: A... |
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 |
return simple_read_from_buffer(ubuf, cnt, ppos, buf, n); } static const struct file_operations graph_depth_fops = { .open = tracing_open_generic, .write = graph_depth_write, .read = graph_depth_read, .llseek = generic_file_llseek, }; |
8434dc934 tracing: Convert ... |
1487 |
static __init int init_graph_tracefs(void) |
8741db532 tracing/fgraph: A... |
1488 1489 1490 1491 |
{ struct dentry *d_tracer; d_tracer = tracing_init_dentry(); |
14a5ae40f tracing: Use IS_E... |
1492 |
if (IS_ERR(d_tracer)) |
8741db532 tracing/fgraph: A... |
1493 1494 1495 1496 1497 1498 1499 |
return 0; trace_create_file("max_graph_depth", 0644, d_tracer, NULL, &graph_depth_fops); return 0; } |
8434dc934 tracing: Convert ... |
1500 |
fs_initcall(init_graph_tracefs); |
8741db532 tracing/fgraph: A... |
1501 |
|
fb52607af tracing/function-... |
1502 1503 |
static __init int init_graph_trace(void) { |
9b130ad5b treewide: make "n... |
1504 |
max_bytes_for_cpu = snprintf(NULL, 0, "%u", nr_cpu_ids - 1); |
0c9e6f639 tracing: Simplify... |
1505 |
|
9023c9309 tracing: Rename (... |
1506 |
if (!register_trace_event(&graph_trace_entry_event)) { |
a395d6a7e kernel/...: conve... |
1507 1508 |
pr_warn("Warning: could not register graph trace events "); |
9106b6938 tracing: Add ftra... |
1509 1510 |
return 1; } |
9023c9309 tracing: Rename (... |
1511 |
if (!register_trace_event(&graph_trace_ret_event)) { |
a395d6a7e kernel/...: conve... |
1512 1513 |
pr_warn("Warning: could not register graph trace events "); |
9106b6938 tracing: Add ftra... |
1514 1515 |
return 1; } |
fb52607af tracing/function-... |
1516 1517 |
return register_tracer(&graph_trace); } |
6f4156723 tracing: Allow tr... |
1518 |
core_initcall(init_graph_trace); |