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