| # Hypervisor & guest tracing |
| |
| ## Hypervisor tracing |
| |
| Starting with android14-5.15 kernel it is possible to get traces from the hypervisor. |
| |
| ### User space interface |
| |
| The user space hypervisor tracing interface is located either at /sys/kernel/tracing/hyp or at |
| /sys/kernel/debug/tracing/hyp. On the Android phones it will usually be /sys/kernel/tracing/hyp, |
| while on QEMU it will be /sys/kernel/debug/tracing/hyp. |
| |
| The user space interface is very similar to the ftrace user space interface, however there are some |
| differences, e.g.: |
| |
| * Only boot clock is supported, and there is no way for user space to change the tracing_clock. |
| * Hypervisor tracing periodically polls the data from the hypervisor, this is different from the |
| regular ftrace instance which pushes the events into the ring buffer. |
| * Resetting ring buffers (by clearing the trace file) is only supported when there are no active |
| readers. If the trace file is cleared while there are active readers, then the ring buffers will |
| be cleared after the last reader disconnects. |
| * Changing the size of the ring buffer while the tracing session is active is also not supported. |
| |
| Note: the list above is not exhaustive. |
| |
| ### Perfetto integration |
| |
| [Perfetto](https://perfetto.dev/docs/) is an open-source stack for performance instrumentation and |
| trace analysis widely used in Android. Perfetto supports capturing and visualizing hypervisor |
| traces. |
| |
| #### Capturing hypervisor traces on Android |
| |
| Consider first familiarizing yourself with Perfetto documentation for recording traces on Android: |
| https://perfetto.dev/docs/quickstart/android-tracing. |
| |
| The [record_android_trace]( |
| https://cs.android.com/android/platform/superproject/+/master:external/perfetto/tools/record_android_trace) |
| script supports a shortcut to capture all hypervisor events that are known to Perfetto: |
| |
| ```shell |
| external/perfetto/tools/record_android_trace hyp -t 15s -b 32mb -o /tmp/hyp.pftrace |
| ``` |
| |
| Alternatively you can use full trace config to capture hypervisor. Example usage: |
| |
| ```shell |
| cat<<EOF>config.pbtx |
| duration_ms: 10000 |
| |
| buffers: { |
| size_kb: 8960 |
| fill_policy: DISCARD |
| } |
| |
| data_sources: { |
| config { |
| name: "linux.ftrace" |
| ftrace_config { |
| instance_name: "hyp" |
| ftrace_events: "hyp/hyp_enter" |
| ftrace_events: "hyp/hyp_exit" |
| } |
| } |
| } |
| EOF |
| |
| ./record_android_trace -c config.pbtx -o trace_file.perfetto-trace |
| ``` |
| |
| If you have an Android tree checked out, then record_android_trace helper script can be located at |
| ${REPO_ROOT}/external/perfetto/tools/record_android_traces. Otherwise, you can download the script |
| by following steps outlined in the [Perfetto docs]( |
| https://perfetto.dev/docs/quickstart/android-tracing#recording-a-trace-through-the-cmdline) |
| |
| #### Capturing hypervisor traces on QEMU |
| |
| Perfetto supports capturing traces on Linux: https://perfetto.dev/docs/quickstart/linux-tracing. |
| However, since pKVM hypervisor is only supported on arm64, you will need to cross-compile Perfetto |
| binaries for linux-arm64 (unless you have an arm64 workstation). |
| |
| 1. Checkout Perfetto repository: https://perfetto.dev/docs/contributing/getting-started |
| 2. Follow https://perfetto.dev/docs/contributing/build-instructions#cross-compiling-for-linux-arm-64 |
| to compile Perfetto binaries for arm64 architecture. |
| 3. Copy the tracebox binary to QEMU |
| 4. Run `tracebox` binary on QEMU to capture traces, it's interface is very similar to the |
| `record_android_trace` binary. E.g. to capture all hypervisor events run: |
| ```shell |
| tracebox -t 15s -b 32mb hyp |
| ``` |
| |
| ### Analysing traces using SQL |
| |
| On top of visualisation, Perfetto also provides a SQL interface to analyse traces. More |
| documentation is available at https://perfetto.dev/docs/quickstart/trace-analysis and |
| https://perfetto.dev/docs/analysis/trace-processor. |
| |
| Hypervisor events can be queried via `pkvm_hypervisor_events` SQL view. You can load that view by |
| calling `SELECT IMPORT("pkvm.hypervisor");`, e.g.: |
| |
| ```sql |
| SELECT IMPORT("pkvm.hypervisor"); |
| SELECT * FROM pkvm_hypervisor_events limit 5; |
| ``` |
| |
| Below are some SQL queries that might be useful when analysing hypervisor traces. |
| |
| **What is the longest time CPU spent in hypervisor, grouped by the reason to enter hypervisor** |
| ```sql |
| SELECT IMPORT("pkvm.hypervisor"); |
| |
| SELECT |
| cpu, |
| reason, |
| ts, |
| dur |
| FROM pkvm_hypervisor_events |
| JOIN ( |
| SELECT |
| MAX(dur) as dur2, |
| cpu as cpu2, |
| reason as reason2 |
| FROM pkvm_hypervisor_events |
| GROUP BY 2, 3) AS sc |
| ON |
| cpu = sc.cpu2 |
| AND dur = sc.dur2 |
| AND (reason = sc.reason2 OR (reason IS NULL AND sc.reason2 IS NULL)) |
| ORDER BY dur desc; |
| ``` |
| |
| **What are the 10 longest times CPU spent in hypervisor because of host_mem_abort** |
| ```sql |
| SELECT |
| hyp.dur as dur, |
| hyp.ts as ts, |
| EXTRACT_ARG(slices.arg_set_id, 'esr') as esr, |
| EXTRACT_ARG(slices.arg_set_id, 'addr') as addr |
| FROM pkvm_hypervisor_events as hyp |
| JOIN slices |
| ON hyp.slice_id = slices.id |
| WHERE hyp.reason = 'host_mem_abort' |
| ORDER BY dur desc |
| LIMIT 10; |
| ``` |
| |
| ## Microdroid VM tracing |
| |
| IMPORTANT: Tracing is only supported for debuggable Microdroid VMs. |
| |
| ### Capturing trace in Microdroid |
| |
| Starting with Android U, Microdroid contains Perfetto tracing binaries, which makes it possible to |
| capture traces inside Microdroid VM using Perfetto stack. The commands used to capture traces on |
| Android should work for Microdroid VM as well, with a difference that Perfetto's tracing binaries |
| are not enabled in Microdroid by default, so you need to manually start them by setting |
| `persist.traced.enable` system property to `1`. |
| |
| Here is a quick example on how trace Microdroid VM: |
| |
| 1. First start your VM. For this example we are going to use |
| `adb shell /apex/com.android.virt/bin/vm run-microdroid`. |
| |
| 2. Set up an adb connection with the running VM: |
| ```shell |
| adb shell forward tcp:9876 vsock:${CID}:5555 |
| adb connect localhost:9876 |
| adb -s localhost:9876 root |
| ``` |
| Where `${CID}` corresponds to the running Microdroid VM that you want to establish adb connection |
| with. List of running VMs can be obtained by running `adb shell /apex/com.android.virt/bin/vm list`. |
| Alternatively you can use `vm_shell` utility to connect to a running VM, i.e.: `vm_shell connect`. |
| |
| 3. Start Perfetto daemons and capture trace |
| ```shell |
| adb -s localhost:9876 shell setprop persist.traced.enable 1 |
| ${ANDROID_BULD_TOP}/external/perfetto/tools/record_android_trace \ |
| -s localhost:9876 \ |
| -o /tmp/microdroid-trace-file.pftrace \ |
| -t 10s \ |
| -b 32mb \ |
| sched/sched_switch task/task_newtask sched/sched_process_exit |
| ``` |
| |
| If you don't have Android repo checked out, then you can download the record_android_trace script by |
| following the following [instructions]( |
| https://perfetto.dev/docs/quickstart/android-tracing#recording-a-trace-through-the-cmdline) |
| |
| More documentation on Perfetto's tracing on Android is available here: |
| https://perfetto.dev/docs/quickstart/android-tracing |
| |
| ### Capturing Microdroid boot trace |
| |
| TODO(b/271412868): Stay tuned, more docs are coming soon! |