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