xref: /aosp_15_r20/external/crosvm/docs/book/src/tracing.md (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker# Tracing
2*bb4ee6a4SAndroid Build Coastguard Worker
3*bb4ee6a4SAndroid Build Coastguard WorkerCrosvm supports tracing to allow developers to debug and diagnose problems and check performance
4*bb4ee6a4SAndroid Build Coastguard Workeroptimizations.
5*bb4ee6a4SAndroid Build Coastguard Worker
6*bb4ee6a4SAndroid Build Coastguard WorkerThe crate `cros_tracing` is used as a frontend for trace points across the crosvm codebase. It is
7*bb4ee6a4SAndroid Build Coastguard Workerdisabled by default but we can enable it with a compile-time flag. It is written to be extensible
8*bb4ee6a4SAndroid Build Coastguard Workerand support multiple backends.
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard WorkerThe currently supported backends are:
11*bb4ee6a4SAndroid Build Coastguard Worker
12*bb4ee6a4SAndroid Build Coastguard Worker- [`noop`](https://github.com/google/crosvm/blob/main/cros_tracing/src/noop.rs): No tracing is
13*bb4ee6a4SAndroid Build Coastguard Worker  enabled. All trace points are compiled out of the application so there is no performance
14*bb4ee6a4SAndroid Build Coastguard Worker  degradation. This is the default backend when no tracing flag is provided.
15*bb4ee6a4SAndroid Build Coastguard Worker- [`trace_marker`](https://crosvm.dev/doc/cros_tracing/trace_marker/index.html):
16*bb4ee6a4SAndroid Build Coastguard Worker  [ftrace](https://docs.kernel.org/trace/ftrace.html) backend to log trace events to the Linux
17*bb4ee6a4SAndroid Build Coastguard Worker  kernel. Only supported on Linux systems. Enabled by compiling crosvm with the
18*bb4ee6a4SAndroid Build Coastguard Worker  `--features trace_marker` flag. (On CrOS it is USE flag `crosvm-trace-marker`)
19*bb4ee6a4SAndroid Build Coastguard Worker
20*bb4ee6a4SAndroid Build Coastguard Worker## cros_tracing Overview
21*bb4ee6a4SAndroid Build Coastguard Worker
22*bb4ee6a4SAndroid Build Coastguard WorkerThe cros_tracing API consists of the following:
23*bb4ee6a4SAndroid Build Coastguard Worker
24*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::init()`: called at initialization time in `src/main.rs` to set up any
25*bb4ee6a4SAndroid Build Coastguard Worker  tracing-specific initialization logic (opening files, set up global state, etc).
26*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::push_descriptors!()`: a macro that needs to be called every time crosvm sets up a
27*bb4ee6a4SAndroid Build Coastguard Worker  sandbox jail before forking. It adds trace-specific file descriptors to the list of descriptors
28*bb4ee6a4SAndroid Build Coastguard Worker  allowed to be accessed inside the jail, if any.
29*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::trace_simple_print!()`: a simple macro that behaves like a log() print and sends a
30*bb4ee6a4SAndroid Build Coastguard Worker  simple message to the tracing backend. In case of the `trace_marker` backend, this will show up as
31*bb4ee6a4SAndroid Build Coastguard Worker  a message in the ftrace/print list of events.
32*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::trace_event_begin!()`: a macro that tracks a tracing context for the given category
33*bb4ee6a4SAndroid Build Coastguard Worker  and emits tracing events. It increased the counter of trace events for that context, if the
34*bb4ee6a4SAndroid Build Coastguard Worker  category is enabled.
35*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::trace_event_end!()`: the opposite of `trace_event_begin!()`. It decreases the
36*bb4ee6a4SAndroid Build Coastguard Worker  counter of currently traced events for that category, if the category is enabled.
37*bb4ee6a4SAndroid Build Coastguard Worker- `cros_tracing::trace_event!()`: a macro that returns a trace context. It records when it is first
38*bb4ee6a4SAndroid Build Coastguard Worker  executed and the given tag + state. When the returned structure goes out of scope, it is
39*bb4ee6a4SAndroid Build Coastguard Worker  automatically collected and the event is recorded. It is useful to trace entry and exit points in
40*bb4ee6a4SAndroid Build Coastguard Worker  function calls. It is equivalent to calling `trace_event_begin!()`, logging data, and then calling
41*bb4ee6a4SAndroid Build Coastguard Worker  `trace_event_end!()` before it goes out of scope. It's recommended to use `trace_event!()` rather
42*bb4ee6a4SAndroid Build Coastguard Worker  than call `trace_event_begin!()` and `trace_event_end!()` individually.
43*bb4ee6a4SAndroid Build Coastguard Worker
44*bb4ee6a4SAndroid Build Coastguard WorkerThe categories that are currently supported by cros_tracing are:
45*bb4ee6a4SAndroid Build Coastguard Worker
46*bb4ee6a4SAndroid Build Coastguard Worker- VirtioFs
47*bb4ee6a4SAndroid Build Coastguard Worker- VirtioNet
48*bb4ee6a4SAndroid Build Coastguard Worker- USB
49*bb4ee6a4SAndroid Build Coastguard Worker- gpu_display
50*bb4ee6a4SAndroid Build Coastguard Worker- VirtioBlk
51*bb4ee6a4SAndroid Build Coastguard Worker- VirtioScsi
52*bb4ee6a4SAndroid Build Coastguard Worker
53*bb4ee6a4SAndroid Build Coastguard Worker### The trace_marker Backend
54*bb4ee6a4SAndroid Build Coastguard Worker
55*bb4ee6a4SAndroid Build Coastguard WorkerThe `trace_marker` backend assumes that the host kernel has tracefs enabled and
56*bb4ee6a4SAndroid Build Coastguard Worker`/sys/kernel/tracing/trace_marker` is writable by the host when the crosvm process starts. If the
57*bb4ee6a4SAndroid Build Coastguard Workerfile cannot be accessed, tracing will not work.
58*bb4ee6a4SAndroid Build Coastguard Worker
59*bb4ee6a4SAndroid Build Coastguard Worker### Usage
60*bb4ee6a4SAndroid Build Coastguard Worker
61*bb4ee6a4SAndroid Build Coastguard WorkerFirst, we want to build crosvm with trace_marker enabled:
62*bb4ee6a4SAndroid Build Coastguard Worker
63*bb4ee6a4SAndroid Build Coastguard Worker```sh
64*bb4ee6a4SAndroid Build Coastguard Workercargo build --features trace_marker
65*bb4ee6a4SAndroid Build Coastguard Worker```
66*bb4ee6a4SAndroid Build Coastguard Worker
67*bb4ee6a4SAndroid Build Coastguard WorkerTo verify that tracing is working, first start a trace capture on the host. You can use something
68*bb4ee6a4SAndroid Build Coastguard Workerlike [trace-cmd](https://man7.org/linux/man-pages/man1/trace-cmd.1.html) or manually enable tracing
69*bb4ee6a4SAndroid Build Coastguard Workerin the system from the terminal:
70*bb4ee6a4SAndroid Build Coastguard Worker
71*bb4ee6a4SAndroid Build Coastguard Worker```sh
72*bb4ee6a4SAndroid Build Coastguard Workersudo echo 1 > /sys/kernel/tracing/tracing_on
73*bb4ee6a4SAndroid Build Coastguard Worker```
74*bb4ee6a4SAndroid Build Coastguard Worker
75*bb4ee6a4SAndroid Build Coastguard WorkerWe can check that virtiofs tracing is working by launching crosvm with a virtiofs filesystem:
76*bb4ee6a4SAndroid Build Coastguard Worker
77*bb4ee6a4SAndroid Build Coastguard Worker```sh
78*bb4ee6a4SAndroid Build Coastguard Workersudo crosvm run --disable-sandbox --shared-dir ${MOUNTPOINT}:mtdroot:type=fs -p "rootfstype=virtiofs root=mtdroot rw init=/bin/bash" ${KERNEL}
79*bb4ee6a4SAndroid Build Coastguard Worker```
80*bb4ee6a4SAndroid Build Coastguard Worker
81*bb4ee6a4SAndroid Build Coastguard WorkerWhere `${MOUNTPOINT}` is your virtiofs filesystem and `${KERNEL}` is your linux kernel.
82*bb4ee6a4SAndroid Build Coastguard Worker
83*bb4ee6a4SAndroid Build Coastguard WorkerIn another terminal, open a `cat` stream on the `/sys/kernel/tracing/trace_pipe` file to view the
84*bb4ee6a4SAndroid Build Coastguard Workertracing events in real time:
85*bb4ee6a4SAndroid Build Coastguard Worker
86*bb4ee6a4SAndroid Build Coastguard Worker```sh
87*bb4ee6a4SAndroid Build Coastguard Workersudo cat /sys/kernel/tracing/trace_pipe
88*bb4ee6a4SAndroid Build Coastguard Worker```
89*bb4ee6a4SAndroid Build Coastguard Worker
90*bb4ee6a4SAndroid Build Coastguard WorkerAs you issue virtiofs requests, you should see events showing up like:
91*bb4ee6a4SAndroid Build Coastguard Worker
92*bb4ee6a4SAndroid Build Coastguard Worker```
93*bb4ee6a4SAndroid Build Coastguard Worker<...>-3802142 [011] ..... 2179601.746212: tracing_mark_write: fuse server: handle_message: in_header=InHeader { len: 64, opcode: 18, unique: 814, nodeid: 42, uid: 0, gid: 0, pid: 0, padding: 0 }
94*bb4ee6a4SAndroid Build Coastguard Worker<...>-3802142 [011] ..... 2179601.746226: tracing_mark_write: 503 VirtioFs Enter: release - (self.tag: "mtdroot")(inode: 42)(handle: 35)
95*bb4ee6a4SAndroid Build Coastguard Worker<...>-3802142 [011] ..... 2179601.746244: tracing_mark_write: 503 VirtioFs Exit: release
96*bb4ee6a4SAndroid Build Coastguard Worker```
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker### Adding Trace Points
99*bb4ee6a4SAndroid Build Coastguard Worker
100*bb4ee6a4SAndroid Build Coastguard WorkerYou can add you own trace points by changing the code and recompiling.
101*bb4ee6a4SAndroid Build Coastguard Worker
102*bb4ee6a4SAndroid Build Coastguard WorkerIf you just need to add a simple one-off trace point, you can use `trace_simple_print!()` like this
103*bb4ee6a4SAndroid Build Coastguard Worker(taken from `devices/src/virtio/fs/worker.rs`):
104*bb4ee6a4SAndroid Build Coastguard Worker
105*bb4ee6a4SAndroid Build Coastguard Worker```rust
106*bb4ee6a4SAndroid Build Coastguard Workerpub fn process_fs_queue<F: FileSystem + Sync>(
107*bb4ee6a4SAndroid Build Coastguard Worker    mem: &GuestMemory,
108*bb4ee6a4SAndroid Build Coastguard Worker    interrupt: &Interrupt,
109*bb4ee6a4SAndroid Build Coastguard Worker    queue: &mut Queue,
110*bb4ee6a4SAndroid Build Coastguard Worker    server: &Arc<fuse::Server<F>>,
111*bb4ee6a4SAndroid Build Coastguard Worker    tube: &Arc<Mutex<Tube>>,
112*bb4ee6a4SAndroid Build Coastguard Worker    slot: u32,
113*bb4ee6a4SAndroid Build Coastguard Worker) -> Result<()> {
114*bb4ee6a4SAndroid Build Coastguard Worker    // Added simple print here
115*bb4ee6a4SAndroid Build Coastguard Worker    cros_tracing::trace_simple_print!("Hello world.");
116*bb4ee6a4SAndroid Build Coastguard Worker    let mapper = Mapper::new(Arc::clone(tube), slot);
117*bb4ee6a4SAndroid Build Coastguard Worker    while let Some(avail_desc) = queue.pop(mem) {
118*bb4ee6a4SAndroid Build Coastguard Worker        let reader =
119*bb4ee6a4SAndroid Build Coastguard Worker            Reader::new(mem.clone(), avail_desc.clone()).map_err(Error::InvalidDescriptorChain)?;
120*bb4ee6a4SAndroid Build Coastguard Worker        let writer =
121*bb4ee6a4SAndroid Build Coastguard Worker            Writer::new(mem.clone(), avail_desc.clone()).map_err(Error::InvalidDescriptorChain)?;
122*bb4ee6a4SAndroid Build Coastguard Worker
123*bb4ee6a4SAndroid Build Coastguard Worker        let total = server.handle_message(reader, writer, &mapper)?;
124*bb4ee6a4SAndroid Build Coastguard Worker
125*bb4ee6a4SAndroid Build Coastguard Worker        queue.add_used(mem, avail_desc.index, total as u32);
126*bb4ee6a4SAndroid Build Coastguard Worker        queue.trigger_interrupt();
127*bb4ee6a4SAndroid Build Coastguard Worker    }
128*bb4ee6a4SAndroid Build Coastguard Worker```
129*bb4ee6a4SAndroid Build Coastguard Worker
130*bb4ee6a4SAndroid Build Coastguard WorkerRecompile and you will see your message show up like:
131*bb4ee6a4SAndroid Build Coastguard Worker
132*bb4ee6a4SAndroid Build Coastguard Worker```
133*bb4ee6a4SAndroid Build Coastguard Worker<...>-3803691 [006] ..... 2180094.296405: tracing_mark_write: Hello world.
134*bb4ee6a4SAndroid Build Coastguard Worker```
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard WorkerSo far so good, but to get the most out of it you might want to record how long the function takes
137*bb4ee6a4SAndroid Build Coastguard Workerto run and some extra parameters. In that case you want to use `trace_event!()` instead:
138*bb4ee6a4SAndroid Build Coastguard Worker
139*bb4ee6a4SAndroid Build Coastguard Worker```rust
140*bb4ee6a4SAndroid Build Coastguard Workerpub fn process_fs_queue<F: FileSystem + Sync>(
141*bb4ee6a4SAndroid Build Coastguard Worker    mem: &GuestMemory,
142*bb4ee6a4SAndroid Build Coastguard Worker    interrupt: &Interrupt,
143*bb4ee6a4SAndroid Build Coastguard Worker    queue: &mut Queue,
144*bb4ee6a4SAndroid Build Coastguard Worker    server: &Arc<fuse::Server<F>>,
145*bb4ee6a4SAndroid Build Coastguard Worker    tube: &Arc<Mutex<Tube>>,
146*bb4ee6a4SAndroid Build Coastguard Worker    slot: u32,
147*bb4ee6a4SAndroid Build Coastguard Worker) -> Result<()> {
148*bb4ee6a4SAndroid Build Coastguard Worker    // Added trace event with slot
149*bb4ee6a4SAndroid Build Coastguard Worker    let _trace = cros_tracing::trace_event!(VirtioFs, "process_fs_queue", slot);
150*bb4ee6a4SAndroid Build Coastguard Worker    let mapper = Mapper::new(Arc::clone(tube), slot);
151*bb4ee6a4SAndroid Build Coastguard Worker    while let Some(avail_desc) = queue.pop(mem) {
152*bb4ee6a4SAndroid Build Coastguard Worker        let reader =
153*bb4ee6a4SAndroid Build Coastguard Worker            Reader::new(mem.clone(), avail_desc.clone()).map_err(Error::InvalidDescriptorChain)?;
154*bb4ee6a4SAndroid Build Coastguard Worker        let writer =
155*bb4ee6a4SAndroid Build Coastguard Worker            Writer::new(mem.clone(), avail_desc.clone()).map_err(Error::InvalidDescriptorChain)?;
156*bb4ee6a4SAndroid Build Coastguard Worker
157*bb4ee6a4SAndroid Build Coastguard Worker        let total = server.handle_message(reader, writer, &mapper)?;
158*bb4ee6a4SAndroid Build Coastguard Worker
159*bb4ee6a4SAndroid Build Coastguard Worker        queue.add_used(mem, avail_desc.index, total as u32);
160*bb4ee6a4SAndroid Build Coastguard Worker        queue.trigger_interrupt();
161*bb4ee6a4SAndroid Build Coastguard Worker    }
162*bb4ee6a4SAndroid Build Coastguard Worker```
163*bb4ee6a4SAndroid Build Coastguard Worker
164*bb4ee6a4SAndroid Build Coastguard WorkerRecompile and this will show up:
165*bb4ee6a4SAndroid Build Coastguard Worker
166*bb4ee6a4SAndroid Build Coastguard Worker```
167*bb4ee6a4SAndroid Build Coastguard Worker<...>-3805264 [017] ..... 2180567.774540: tracing_mark_write: 512 VirtioFs Enter: process_fs_queue - (slot: 0)
168*bb4ee6a4SAndroid Build Coastguard Worker<...>-3805264 [017] ..... 2180567.774551: tracing_mark_write: 512 VirtioFs Exit: process_fs_queue
169*bb4ee6a4SAndroid Build Coastguard Worker```
170*bb4ee6a4SAndroid Build Coastguard Worker
171*bb4ee6a4SAndroid Build Coastguard WorkerThe number `512` in the log corresponds to a unique identifier for that event so it's easier to
172*bb4ee6a4SAndroid Build Coastguard Workertrace which `Enter` corresponds to which `Exit`. Note how the value of `slot` also has been
173*bb4ee6a4SAndroid Build Coastguard Workerrecorded. To be able to output the state, the data type needs to support the `fmt::Debug` trait.
174*bb4ee6a4SAndroid Build Coastguard Worker
175*bb4ee6a4SAndroid Build Coastguard WorkerNOTE: The unique identifier for each event is unique only per-process. If the crosvm process forks
176*bb4ee6a4SAndroid Build Coastguard Worker(like spawning new devices) then it is possible for two events from different processes to have the
177*bb4ee6a4SAndroid Build Coastguard Workersame ID, in which case it's important to look at the recorded PID that emitted each event in the
178*bb4ee6a4SAndroid Build Coastguard Workertrace.
179*bb4ee6a4SAndroid Build Coastguard Worker
180*bb4ee6a4SAndroid Build Coastguard WorkerThe numbers like `2180567.774540` and `2180567.774551` in the example above are the timestamps for
181*bb4ee6a4SAndroid Build Coastguard Workerthat event, in `<sec>.<usec>` format. We can see that the `process_fs_queue` call took 11usec to
182*bb4ee6a4SAndroid Build Coastguard Workerexecute.
183*bb4ee6a4SAndroid Build Coastguard Worker
184*bb4ee6a4SAndroid Build Coastguard WorkerIn this last example we used the `VirtioFs` category tag. If you want to add a new category tag to
185*bb4ee6a4SAndroid Build Coastguard Worker`trace_marker`, it can be done by adding it to the the `setup_trace_marker!()` call in
186*bb4ee6a4SAndroid Build Coastguard Worker`cros_tracing/src/trace_marker.rs`:
187*bb4ee6a4SAndroid Build Coastguard Worker
188*bb4ee6a4SAndroid Build Coastguard Worker```rust
189*bb4ee6a4SAndroid Build Coastguard Worker// List of categories that can be enabled.
190*bb4ee6a4SAndroid Build Coastguard Workersetup_trace_marker!(
191*bb4ee6a4SAndroid Build Coastguard Worker    (VirtioFs, true),
192*bb4ee6a4SAndroid Build Coastguard Worker    (VirtioNet, true),
193*bb4ee6a4SAndroid Build Coastguard Worker    (USB, true),
194*bb4ee6a4SAndroid Build Coastguard Worker    (gpu_display, true),
195*bb4ee6a4SAndroid Build Coastguard Worker    (VirtioBlk, true),
196*bb4ee6a4SAndroid Build Coastguard Worker    (VirtioScsi, true),
197*bb4ee6a4SAndroid Build Coastguard Worker    (NewCategory, true)
198*bb4ee6a4SAndroid Build Coastguard Worker);
199*bb4ee6a4SAndroid Build Coastguard Worker```
200*bb4ee6a4SAndroid Build Coastguard Worker
201*bb4ee6a4SAndroid Build Coastguard WorkerIf the value is `false` then the events will not be traced. This can be useful when you just want to
202*bb4ee6a4SAndroid Build Coastguard Workertrace a specific category and don't care about the rest, you can disable them in the code and
203*bb4ee6a4SAndroid Build Coastguard Workerrecompile crosvm.
204*bb4ee6a4SAndroid Build Coastguard Worker
205*bb4ee6a4SAndroid Build Coastguard WorkerNOTE: Trace events are compile-time to reduce runtime overhead in non-tracing builds so a lot of
206*bb4ee6a4SAndroid Build Coastguard Workerchanges require recompiling and re-deploying crosvm.
207