Kernel function graph tracing

The Linux kernel's function_graph tracer records every entry into and exit from kernel functions, letting you see the exact call tree the kernel executed on a CPU, with per-function durations. Perfetto can drive this tracer through the linux.ftrace data source and visualises the resulting calls as nested slices on the timeline, just like userspace slices.

This is a powerful way to answer "what was the kernel actually doing here?" without adding any instrumentation of your own. It is, however, a high-bandwidth feature: tracing too many functions will overwhelm the trace buffer, so it is designed to be used together with filters.

If instead you want to add your own tracepoints to the kernel, see Instrumenting the kernel with ftrace.

Requirements

TraceConfig

The relevant options live in FtraceConfig:

WARNING: Always constrain the traced set with function_filters and/or function_graph_roots. Tracing all kernel functions generates an enormous event stream that will fill the buffer in milliseconds and is rarely useful.

Example: trace the scheduler functions and everything they call, for 10 seconds.

buffers { size_kb: 65536 fill_policy: DISCARD } data_sources { config { name: "linux.ftrace" ftrace_config { symbolize_ksyms: true enable_function_graph: true # Trace these functions and all of their callees. function_graph_roots: "__schedule" # Optionally also keep a flat set of functions of interest. function_filters: "handle_mm_fault" function_graph_max_depth: 10 } } } duration_ms: 10000

Record it with tracebox:

./tracebox -c funcgraph.cfg --txt -o funcgraph.pftrace

See the system tracing guide for how to set up tracebox and the necessary permissions on Linux.

UI

Function graph calls appear as nested slices. Each kernel function entry/exit pair becomes a slice whose duration is the time spent inside that function (including callees), so the call tree reads exactly like a userspace flame chart.

You can select a slice to see the function name and duration, and use the flamegraph/aggregation features as with any other slice track.

SQL

Function graph calls are ordinary slices, so they live in the slice table and can be queried like any other slice. For example, to find the kernel functions that accounted for the most aggregate time:

SELECT name, COUNT(*) AS calls, SUM(dur) AS total_dur FROM slice JOIN track ON slice.track_id = track.id WHERE track.name = 'Funcgraph' GROUP BY name ORDER BY total_dur DESC LIMIT 20;

Troubleshooting