1# Using `perf` on Linux 2 3One profiler supported by Wasmtime is the [`perf` 4profiler](https://perf.wiki.kernel.org/index.php/Main_Page) for Linux. This is 5an extremely powerful profiler with lots of documentation on the web, but for 6the rest of this section we'll assume you're running on Linux and already have 7`perf` installed. 8 9There are two profiling agents for `perf`: 10 11- a very simple one that will map code regions to symbol names: `perfmap`. 12- a more detailed one that can provide additional information and mappings between the source 13 language statements and generated JIT code: `jitdump`. 14 15## Profiling with `perfmap` 16 17Simple profiling support with `perf` generates a "perf map" file that the `perf` CLI will 18automatically look for, when running into unresolved symbols. This requires runtime support from 19Wasmtime itself, so you will need to manually change a few things to enable profiling support in 20your application. Enabling runtime support depends on how you're using Wasmtime: 21 22* **Rust API** - you'll want to call the [`Config::profiler`] method with 23 `ProfilingStrategy::PerfMap` to enable profiling of your wasm modules. 24 25* **C API** - you'll want to call the `wasmtime_config_profiler_set` API with a 26 `WASMTIME_PROFILING_STRATEGY_PERFMAP` value. 27 28* **Command Line** - you'll want to pass the `--profile=perfmap` flag on the command 29 line. 30 31Once perfmap support is enabled, you'll use `perf record` like usual to record 32your application's performance. 33 34For example if you're using the CLI, you'll execute: 35 36```console 37perf record -k mono wasmtime --profile=perfmap foo.wasm 38``` 39 40This will create a `perf.data` file as per usual, but it will *also* create a 41`/tmp/perf-XXXX.map` file. This extra `.map` file is the perf map file which is 42specified by `perf` and Wasmtime generates at runtime. 43 44After that you can explore the `perf.data` profile as you usually would, for example with: 45 46```console 47perf report --input perf.data 48``` 49 50You should be able to see time spent in wasm functions, generate flamegraphs based on that, etc.. 51You should also see entries for wasm functions show up as one function and the name of each 52function matches the debug name section in the wasm file. 53 54Note that support for perfmap is still relatively new in Wasmtime, so if you 55have any problems, please don't hesitate to [file an issue]! 56 57[file an issue]: https://github.com/bytecodealliance/wasmtime/issues/new 58 59 60## Profiling with `jitdump` 61 62Profiling support with `perf` uses the "jitdump" support in the `perf` CLI. This 63requires runtime support from Wasmtime itself, so you will need to manually 64change a few things to enable profiling support in your application. First 65you'll want to make sure that Wasmtime is compiled with the `jitdump` Cargo 66feature (which is enabled by default). Otherwise enabling runtime support 67depends on how you're using Wasmtime: 68 69* **Rust API** - you'll want to call the [`Config::profiler`] method with 70 `ProfilingStrategy::JitDump` to enable profiling of your wasm modules. 71 72* **C API** - you'll want to call the `wasmtime_config_profiler_set` API with a 73 `WASMTIME_PROFILING_STRATEGY_JITDUMP` value. 74 75* **Command Line** - you'll want to pass the `--profile=jitdump` flag on the command 76 line. 77 78Once jitdump support is enabled, you'll use `perf record` like usual to record 79your application's performance. You'll need to also be sure to pass the 80`--clockid mono` or `-k mono` flag to `perf record`. 81 82For example if you're using the CLI, you'll execute: 83 84```console 85perf record -k mono wasmtime --profile=jitdump foo.wasm 86``` 87 88This will create a `perf.data` file as per usual, but it will *also* create a 89`jit-XXXX.dump` file. This extra `*.dump` file is the jitdump file which is 90specified by `perf` and Wasmtime generates at runtime. 91 92The next thing you need to do is to merge the `*.dump` file into the 93`perf.data` file, which you can do with the `perf inject` command: 94 95```console 96perf inject --jit --input perf.data --output perf.jit.data 97``` 98 99This will read `perf.data`, automatically pick up the `*.dump` file that's 100correct, and then create `perf.jit.data` which merges all the JIT information 101together. This should also create a lot of `jitted-XXXX-N.so` files in the 102current directory which are ELF images for all the JIT functions that were 103created by Wasmtime. 104 105After that you can explore the `perf.jit.data` profile as you usually would, 106for example with: 107 108```console 109perf report --input perf.jit.data 110``` 111 112You should be able to annotate wasm functions and see their raw assembly. You 113should also see entries for wasm functions show up as one function and the 114name of each function matches the debug name section in the wasm file. 115 116Note that support for jitdump is still relatively new in Wasmtime, so if you 117have any problems, please don't hesitate to [file an issue]! 118 119[file an issue]: https://github.com/bytecodealliance/wasmtime/issues/new 120 121### `perf` and DWARF information 122 123If the jitdump profile doesn't give you enough information by default, you can 124also enable dwarf debug information to be generated for JIT code which should 125give the `perf` profiler more information about what's being profiled. This can 126include information like more descriptive function names, filenames, and line 127numbers. 128 129Enabling dwarf debug information for JIT code depends on how you're using 130Wasmtime: 131 132* **Rust API** - you'll want to call the [`Config::debug_info`] method. 133 134* **C API** - you'll want to call the `wasmtime_config_debug_info_set` API. 135 136* **Command Line** - you'll want to pass the `-g` flag on the command line. 137 138You shouldn't need to do anything else to get this information into `perf`. The 139perf collection data should automatically pick up all this dwarf debug 140information. 141 142### `perf` example 143 144Let's run through a quick example with `perf` to get the feel for things. First 145let's take a look at some wasm: 146 147```rust 148fn main() { 149 let n = 42; 150 println!("fib({}) = {}", n, fib(n)); 151} 152 153fn fib(n: u32) -> u32 { 154 if n <= 2 { 155 1 156 } else { 157 fib(n - 1) + fib(n - 2) 158 } 159} 160``` 161 162To collect perf information for this wasm module we'll execute: 163 164```console 165$ rustc --target wasm32-wasip1 fib.rs -O 166$ perf record -k mono wasmtime --profile=jitdump fib.wasm 167fib(42) = 267914296 168[ perf record: Woken up 1 times to write data ] 169[ perf record: Captured and wrote 0.147 MB perf.data (3435 samples) ] 170$ perf inject --jit --input perf.data --output perf.jit.data 171``` 172 173And we should have all our information now! We can execute `perf report` for 174example to see that 99% of our runtime (as expected) is spent in our `fib` 175function. Note that the symbol has been demangled to `fib::fib` which is what 176the Rust symbol is: 177 178```console 179perf report --input perf.jit.data 180``` 181 182 183 184Alternatively we could also use `perf annotate` to take a look at the 185disassembly of the `fib` function, seeing what the JIT generated: 186 187```console 188perf annotate --input perf.jit.data 189``` 190 191 192 193[`Config::debug_info`]: https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.debug_info 194