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![perf report output](assets/perf-report-fib.png)
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![perf annotate output](assets/perf-annotate-fib.png)
151
152[`Config::debug_info`]: https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.debug_info
153