blob: 38283d91da5970951a9c396ce74cd314ed19d2be [file] [view] [edit]
# 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](/docs/getting-started/ftrace.md).
## Requirements
- A kernel compiled with `CONFIG_FUNCTION_GRAPH_TRACER`. You can confirm support
with:
```bash
cat /sys/kernel/tracing/available_tracers
```
The output must include `function_graph`.
- `symbolize_ksyms: true` in the ftrace config. Without it, every function shows
up as a raw hexadecimal address. See
[Symbolization: kernel symbols](/docs/learning-more/symbolization.md#ftrace)
for why kernel symbols must be resolved at record time and cannot be added
afterwards with `traceconv bundle`.
- On **Android**, function graph tracing is available only on `debuggable`
(userdebug/eng) builds, and was introduced in Android U.
- `traced_probes` must run as root (or `kptr_restrict` lowered), both to read
`/proc/kallsyms` and to control the kernel tracer.
## TraceConfig
The relevant options live in `FtraceConfig`:
- `enable_function_graph`: turns on the `function_graph` tracer.
- `function_filters`: a set of globs; only matching functions are traced.
- `function_graph_roots`: a set of globs; matching functions **and all of their
callees** are traced.
- `function_graph_max_depth`: limit how many call levels below a root are traced.
- `symbolize_ksyms`: required to get function names instead of addresses.
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.
```protobuf
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`:
```bash
./tracebox -c funcgraph.cfg --txt -o funcgraph.pftrace
```
See the [system tracing guide](/docs/getting-started/system-tracing.md) 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.
- Calls that happen while a thread is running are attached to a **Funcgraph**
track under that thread.
- Calls that happen on an idle CPU (in the `swapper` idle task) are grouped onto
a per-CPU `swapper<N> -funcgraph` track.
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:
```sql
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
- **Functions show as hex addresses** (e.g. `0xffffffff8108abcd`): you did not
set `symbolize_ksyms: true`, or `traced_probes` could not read
`/proc/kallsyms` (not root / `kptr_restrict` too high). This must be fixed at
record time; see
[Symbolization: kernel symbols](/docs/learning-more/symbolization.md#ftrace).
- **No function graph data at all**: confirm `function_graph` is in
`available_tracers`, and that your config sets at least one of
`function_filters` / `function_graph_roots`.
- **The data source was rejected**: function graph cannot run alongside another
concurrent `linux.ftrace` data source that uses a different kernel tracer, as
the kernel tracer cannot be switched mid-trace.