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:

FileRole
available_tracersTracers built into the kernel
current_tracerActive tracer (changing it clears the ring and snapshot buffers)
tracing_onEnable/disable writes to the ring buffer (0/1)
traceHuman-readable snapshot-style output (not a consumer)
trace_pipeStreaming consumer read for live tracing
buffer_size_kbPer-CPU buffer size in KB
available_filter_functionsFunction 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_pid restricts 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-buffer and entries-written means loss) and loads the system.
  • Options such as func_stack_trace must be enabled only after filtering; otherwise performance degrades badly.
  • function_graph costs more than function because 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 overwrite drops oldest events. Grow capacity with buffer_size_kb if 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.

References