How to Use ftrace function_graph to See Kernel Call Paths
One-line answer: Under /sys/kernel/tracing, set current_tracer to function_graph, limit symbols with set_ftrace_filter, flip tracing_on, then read trace or trace_pipe.
This is a general overview based on the kernel.org ftrace - Function Tracer document (Documentation/trace/ftrace.rst). It does not compare perf or invent board-specific logs.
Where Is the Buffer?
One-line answer: Control and output files live in tracefs at /sys/kernel/tracing. Events land in per-CPU ring buffers that you read via trace / trace_pipe and size with buffer_size_kb.
When ftrace is configured, /sys/kernel/tracing appears. Mount example:
mount -t tracefs nodev /sys/kernel/tracing
cd /sys/kernel/tracing
Before Linux 4.1, controls lived under debugfs at /sys/kernel/debug/tracing; mounting debugfs still exposes a compatibility path. The rest of the documentation assumes you are already in the ftrace directory.
Key files:
| File | Role |
|---|---|
available_tracers | Tracers built into the kernel |
current_tracer | Active tracer (changing it clears the ring and snapshot buffers) |
tracing_on | Enable/disable writes to the ring buffer (0/1) |
trace | Human-readable snapshot-style output (not a consumer) |
trace_pipe | Streaming consumer read for live tracing |
buffer_size_kb | Per-CPU buffer size in KB |
available_filter_functions | Function names you may filter on |
Turning tracing_on off stops recording but may leave tracing overhead in place. To disable tracers entirely, echo nop into current_tracer as documented.
How Do Filters Work?
One-line answer: Only names listed in available_filter_functions belong in set_ftrace_filter / set_ftrace_notrace (and graph helpers like set_graph_function). Then set function or function_graph in current_tracer.
cat available_tracers
echo function_graph > current_tracer
echo 'do_sys_open' > set_ftrace_filter
# add more names, wildcards, or indices per the Filter commands section
echo 1 > tracing_on
# reproduce the workload
echo 0 > tracing_on
cat trace
function: traces function entry (and parent) style call flow.function_graph: probes entry and exit so you get a C-like call graph with durations.set_ftrace_notrace: exclusion list; if a name is in both filter and notrace, it is not traced.set_graph_function: for the graph tracer, limit tracing to listed functions and what they call.- PID scope:
set_ftrace_pidrestricts function tracing to listed threads.
If kernel.ftrace_enabled is off, function tracers can behave like a nop—check sysctl kernel.ftrace_enabled=1 as the docs describe.
What About Overhead?
One-line answer: With dynamic ftrace, idle call sites are patched toward nops, but an active function/function_graph tracer, a wide filter, or stack options raise latency and buffer overwrite risk—narrow filters and enable tracing_on only while you need data.
Practical points from the documentation:
- Enabling function tracing without a filter fills buffers quickly (gap between
entries-in-bufferandentries-writtenmeans loss) and loads the system. - Options such as
func_stack_tracemust be enabled only after filtering; otherwise performance degrades badly. function_graphcosts more thanfunctionbecause it instruments exit as well as entry and computes durations. Timing can skew slightly if multiple instances graph the same functions.- When the buffer is full, default
overwritedrops oldest events. Grow capacity withbuffer_size_kbif needed.
Minimal teardown:
cat trace # or: cat trace_pipe
echo nop > current_tracer
echo > set_ftrace_filter
trace is non-consuming (stable when tracing is off); trace_pipe consumes what it reads.
FAQ
Q. Where are available_filter_functions and current_tracer?
A. Both under /sys/kernel/tracing/ (or the compatibility path /sys/kernel/debug/tracing/).
Q. Privileges?
A. Typically root (or CAP_SYS_ADMIN); distributions and LSMs may differ.