diff options
author | Mike Frysinger <vapier@gentoo.org> | 2010-07-20 03:13:35 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-07-21 11:00:25 -0400 |
commit | 9849ed4d72251d273524efb8b70be0be9aecb1df (patch) | |
tree | 8162927a3f8a35e543cc1937e07c2354b34a9e96 /Documentation | |
parent | ef710e100c1068d3dd5774d2b34c5485219e06ce (diff) |
tracing/documentation: Document dynamic ftracer internals
Add more details to the dynamic function tracing design implementation.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
LKML-Reference: <1279610015-10250-1-git-send-email-vapier@gentoo.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/trace/ftrace-design.txt | 153 |
1 files changed, 148 insertions, 5 deletions
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index f1f81afee8a0..dc52bd442c92 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt | |||
@@ -13,6 +13,9 @@ Note that this focuses on architecture implementation details only. If you | |||
13 | want more explanation of a feature in terms of common code, review the common | 13 | want more explanation of a feature in terms of common code, review the common |
14 | ftrace.txt file. | 14 | ftrace.txt file. |
15 | 15 | ||
16 | Ideally, everyone who wishes to retain performance while supporting tracing in | ||
17 | their kernel should make it all the way to dynamic ftrace support. | ||
18 | |||
16 | 19 | ||
17 | Prerequisites | 20 | Prerequisites |
18 | ------------- | 21 | ------------- |
@@ -215,7 +218,7 @@ An arch may pass in a unique value (frame pointer) to both the entering and | |||
215 | exiting of a function. On exit, the value is compared and if it does not | 218 | exiting of a function. On exit, the value is compared and if it does not |
216 | match, then it will panic the kernel. This is largely a sanity check for bad | 219 | match, then it will panic the kernel. This is largely a sanity check for bad |
217 | code generation with gcc. If gcc for your port sanely updates the frame | 220 | code generation with gcc. If gcc for your port sanely updates the frame |
218 | pointer under different opitmization levels, then ignore this option. | 221 | pointer under different optimization levels, then ignore this option. |
219 | 222 | ||
220 | However, adding support for it isn't terribly difficult. In your assembly code | 223 | However, adding support for it isn't terribly difficult. In your assembly code |
221 | that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument. | 224 | that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument. |
@@ -234,7 +237,7 @@ If you can't trace NMI functions, then skip this option. | |||
234 | 237 | ||
235 | 238 | ||
236 | HAVE_SYSCALL_TRACEPOINTS | 239 | HAVE_SYSCALL_TRACEPOINTS |
237 | --------------------- | 240 | ------------------------ |
238 | 241 | ||
239 | You need very few things to get the syscalls tracing in an arch. | 242 | You need very few things to get the syscalls tracing in an arch. |
240 | 243 | ||
@@ -250,12 +253,152 @@ You need very few things to get the syscalls tracing in an arch. | |||
250 | HAVE_FTRACE_MCOUNT_RECORD | 253 | HAVE_FTRACE_MCOUNT_RECORD |
251 | ------------------------- | 254 | ------------------------- |
252 | 255 | ||
253 | See scripts/recordmcount.pl for more info. | 256 | See scripts/recordmcount.pl for more info. Just fill in the arch-specific |
257 | details for how to locate the addresses of mcount call sites via objdump. | ||
258 | This option doesn't make much sense without also implementing dynamic ftrace. | ||
254 | 259 | ||
260 | |||
261 | HAVE_DYNAMIC_FTRACE | ||
262 | ------------------- | ||
263 | |||
264 | You will first need HAVE_FTRACE_MCOUNT_RECORD and HAVE_FUNCTION_TRACER, so | ||
265 | scroll your reader back up if you got over eager. | ||
266 | |||
267 | Once those are out of the way, you will need to implement: | ||
268 | - asm/ftrace.h: | ||
269 | - MCOUNT_ADDR | ||
270 | - ftrace_call_adjust() | ||
271 | - struct dyn_arch_ftrace{} | ||
272 | - asm code: | ||
273 | - mcount() (new stub) | ||
274 | - ftrace_caller() | ||
275 | - ftrace_call() | ||
276 | - ftrace_stub() | ||
277 | - C code: | ||
278 | - ftrace_dyn_arch_init() | ||
279 | - ftrace_make_nop() | ||
280 | - ftrace_make_call() | ||
281 | - ftrace_update_ftrace_func() | ||
282 | |||
283 | First you will need to fill out some arch details in your asm/ftrace.h. | ||
284 | |||
285 | Define MCOUNT_ADDR as the address of your mcount symbol similar to: | ||
286 | #define MCOUNT_ADDR ((unsigned long)mcount) | ||
287 | Since no one else will have a decl for that function, you will need to: | ||
288 | extern void mcount(void); | ||
289 | |||
290 | You will also need the helper function ftrace_call_adjust(). Most people | ||
291 | will be able to stub it out like so: | ||
292 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
293 | { | ||
294 | return addr; | ||
295 | } | ||
255 | <details to be filled> | 296 | <details to be filled> |
256 | 297 | ||
298 | Lastly you will need the custom dyn_arch_ftrace structure. If you need | ||
299 | some extra state when runtime patching arbitrary call sites, this is the | ||
300 | place. For now though, create an empty struct: | ||
301 | struct dyn_arch_ftrace { | ||
302 | /* No extra data needed */ | ||
303 | }; | ||
304 | |||
305 | With the header out of the way, we can fill out the assembly code. While we | ||
306 | did already create a mcount() function earlier, dynamic ftrace only wants a | ||
307 | stub function. This is because the mcount() will only be used during boot | ||
308 | and then all references to it will be patched out never to return. Instead, | ||
309 | the guts of the old mcount() will be used to create a new ftrace_caller() | ||
310 | function. Because the two are hard to merge, it will most likely be a lot | ||
311 | easier to have two separate definitions split up by #ifdefs. Same goes for | ||
312 | the ftrace_stub() as that will now be inlined in ftrace_caller(). | ||
313 | |||
314 | Before we get confused anymore, let's check out some pseudo code so you can | ||
315 | implement your own stuff in assembly: | ||
257 | 316 | ||
258 | HAVE_DYNAMIC_FTRACE | 317 | void mcount(void) |
259 | --------------------- | 318 | { |
319 | return; | ||
320 | } | ||
321 | |||
322 | void ftrace_caller(void) | ||
323 | { | ||
324 | /* implement HAVE_FUNCTION_TRACE_MCOUNT_TEST if you desire */ | ||
325 | |||
326 | /* save all state needed by the ABI (see paragraph above) */ | ||
327 | |||
328 | unsigned long frompc = ...; | ||
329 | unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | ||
330 | |||
331 | ftrace_call: | ||
332 | ftrace_stub(frompc, selfpc); | ||
333 | |||
334 | /* restore all state needed by the ABI */ | ||
335 | |||
336 | ftrace_stub: | ||
337 | return; | ||
338 | } | ||
339 | |||
340 | This might look a little odd at first, but keep in mind that we will be runtime | ||
341 | patching multiple things. First, only functions that we actually want to trace | ||
342 | will be patched to call ftrace_caller(). Second, since we only have one tracer | ||
343 | active at a time, we will patch the ftrace_caller() function itself to call the | ||
344 | specific tracer in question. That is the point of the ftrace_call label. | ||
345 | |||
346 | With that in mind, let's move on to the C code that will actually be doing the | ||
347 | runtime patching. You'll need a little knowledge of your arch's opcodes in | ||
348 | order to make it through the next section. | ||
349 | |||
350 | Every arch has an init callback function. If you need to do something early on | ||
351 | to initialize some state, this is the time to do that. Otherwise, this simple | ||
352 | function below should be sufficient for most people: | ||
353 | |||
354 | int __init ftrace_dyn_arch_init(void *data) | ||
355 | { | ||
356 | /* return value is done indirectly via data */ | ||
357 | *(unsigned long *)data = 0; | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | There are two functions that are used to do runtime patching of arbitrary | ||
363 | functions. The first is used to turn the mcount call site into a nop (which | ||
364 | is what helps us retain runtime performance when not tracing). The second is | ||
365 | used to turn the mcount call site into a call to an arbitrary location (but | ||
366 | typically that is ftracer_caller()). See the general function definition in | ||
367 | linux/ftrace.h for the functions: | ||
368 | ftrace_make_nop() | ||
369 | ftrace_make_call() | ||
370 | The rec->ip value is the address of the mcount call site that was collected | ||
371 | by the scripts/recordmcount.pl during build time. | ||
372 | |||
373 | The last function is used to do runtime patching of the active tracer. This | ||
374 | will be modifying the assembly code at the location of the ftrace_call symbol | ||
375 | inside of the ftrace_caller() function. So you should have sufficient padding | ||
376 | at that location to support the new function calls you'll be inserting. Some | ||
377 | people will be using a "call" type instruction while others will be using a | ||
378 | "branch" type instruction. Specifically, the function is: | ||
379 | ftrace_update_ftrace_func() | ||
380 | |||
381 | |||
382 | HAVE_DYNAMIC_FTRACE + HAVE_FUNCTION_GRAPH_TRACER | ||
383 | ------------------------------------------------ | ||
384 | |||
385 | The function grapher needs a few tweaks in order to work with dynamic ftrace. | ||
386 | Basically, you will need to: | ||
387 | - update: | ||
388 | - ftrace_caller() | ||
389 | - ftrace_graph_call() | ||
390 | - ftrace_graph_caller() | ||
391 | - implement: | ||
392 | - ftrace_enable_ftrace_graph_caller() | ||
393 | - ftrace_disable_ftrace_graph_caller() | ||
260 | 394 | ||
261 | <details to be filled> | 395 | <details to be filled> |
396 | Quick notes: | ||
397 | - add a nop stub after the ftrace_call location named ftrace_graph_call; | ||
398 | stub needs to be large enough to support a call to ftrace_graph_caller() | ||
399 | - update ftrace_graph_caller() to work with being called by the new | ||
400 | ftrace_caller() since some semantics may have changed | ||
401 | - ftrace_enable_ftrace_graph_caller() will runtime patch the | ||
402 | ftrace_graph_call location with a call to ftrace_graph_caller() | ||
403 | - ftrace_disable_ftrace_graph_caller() will runtime patch the | ||
404 | ftrace_graph_call location with nops | ||