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