With this question I aim to do a survey about instrumentation techniques used by linux ftrace
.According with ftrace.txt
:
If CONFIG_DYNAMIC_FTRACE is set, the system will run withvirtually no overhead when function tracing is disabled. The waythis works is the mcount function call (placed at the start ofevery kernel function, produced by the -pg switch in gcc),starts of pointing to a simple return. (Enabling FTRACE willinclude the -pg switch in the compiling of the kernel.)
mcount
calls happens just before or just after instrumented functions' prologue (to the best of my knowledge, whether "before" or "after" depends on how glibc implements the mcount function on your specific architecture.
However, this is not enough if we use the function graph tracer
of ftrace. Such tracer is able to trace both entry and exit of the function. Using the mcount mechanism to capture the exit assembly routine of a function requires some tricky manipulation of the stack and call sequence More details on: ftrace-design.txt
.
Briefly, since the -pg compiler option only adds instrumentation for function entry, ftrace subsystem needs to adjust the register and stack conditions before returning to execute the instrumented function, so that ftrace can regain control when the function exits.
I found this process complex, especially when we need to instrument also the end of a function. In this question, I wonder why the kernel is compiled with -pg
option of gcc
instead of -finstrument-functions
option. The latter would avoid the above mentioned process of saving the return address. From GCC GNU docs (see paragraph -finstrument-functions
) I found such option more friendly than the -pg
's one. Here a little excerpt:
-finstrument-functionsGenerate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site.
void __cyg_profile_func_enter (void *this_fn, void *call_site);
void __cyg_profile_func_exit (void *this_fn, void *call_site);