performance.md

  1---
  2title: Rough quick CPU profiling (Flamechart)
  3description: "Performance profiling and optimization for Zed development."
  4---
  5
  6How to use our internal tools to profile and keep Zed fast.
  7
  8# Rough quick CPU profiling (Flamechart)
  9
 10See what the CPU spends the most time on. Strongly recommend you use
 11[samply](https://github.com/mstange/samply). It opens an interactive profile in
 12the browser (specifically a local instance of [firefox_profiler](https://profiler.firefox.com/)).
 13
 14See [samply](https://github.com/mstange/samply)'s README on how to install and run.
 15
 16The profile.json does not contain any symbols. Firefox profiler can add the local symbols to the profile for for. To do that hit the upload local profile button in the top right corner.
 17
 18<img width="851" height="auto" alt="image" src="https://github.com/user-attachments/assets/cbef2b51-0442-4ee9-bc5c-95f6ccf9be2c" style="display: block; margin: 0 auto;" />
 19
 20# In depth CPU profiling (Tracing)
 21
 22See how long each annotated function call took and its arguments (if
 23configured).
 24
 25Annotate any function you need appear in the profile with instrument. For more
 26details see
 27[tracing-instrument](https://docs.rs/tracing/latest/tracing/attr.instrument.html):
 28
 29```rust
 30#[instrument(skip_all)]
 31fn should_appear_in_profile(kitty: Cat) {
 32    sleep(QUITE_LONG)
 33}
 34```
 35
 36Then either compile Zed with `ZTRACING=1 cargo r --features tracy --release`. The release build is optional but highly recommended as like every program Zeds performance characteristics change dramatically with optimizations. You do not want to chase slowdowns that do not exist in release.
 37
 38## One time Setup/Building the profiler:
 39
 40Download the profiler:
 41[linux x86_64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-profiler-linux-x86_64)
 42[macos aarch64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-profiler-0.13.0-macos-aarch64)
 43
 44### Alternative: Building it yourself
 45
 46- Clone the repo at git@github.com:wolfpld/tracy.git
 47- `cd profiler && mkdir build && cd build`
 48- Run cmake to generate build files: `cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..`
 49- Build the profiler: `ninja`
 50- [Optional] move the profiler somewhere nice like ~/.local/bin on linux
 51
 52## Usage
 53
 54Open the profiler (tracy-profiler), you should see zed in the list of `Discovered clients` click it.
 55
 56<img width="392" height="auto" alt="image" src="https://github.com/user-attachments/assets/b6f06fc3-6b25-41c7-ade9-558cc93d6033" style="display: block; margin: 0 auto;"/>
 57
 58Tracy is an incredibly powerful profiler which can do a lot however it's UI is not that friendly. This is not the place for an in depth guide to Tracy, I do however want to highlight one particular workflow that is helpful when figuring out why a piece of code is _sometimes_ slow.
 59
 60Here are the steps:
 61
 621. Click the flamechart button at the top.
 63
 64<img width="1815" height="auto" alt="Click flamechart" src="https://github.com/user-attachments/assets/9b488c60-90fa-4013-a663-f4e35ea753d2" />
 65
 662. Click on a function that takes a lot of time.
 67
 68<img width="2001" height="auto" alt="Click snapshot" src="https://github.com/user-attachments/assets/ddb838ed-2c83-4dba-a750-b8a2d4ac6202" />
 69
 703. Expand the list of function calls by clicking on main thread.
 71
 72<img width="2313" height="auto" alt="Click main thread" src="https://github.com/user-attachments/assets/465dd883-9d3c-4384-a396-fce68b872d1a" />
 73
 744. Filter that list to the slower calls then click on one of the slow calls in the list
 75
 76<img width="2264" height="auto" alt="Select the tail calls in the histogram to filter down the list of calls then click on one call" src="https://github.com/user-attachments/assets/a8fddc7c-f40a-4f11-a648-ca7cc193ff6f" />
 77
 785. Click zoom to zone to go to that specific function call in the timeline
 79
 80<img width="1822" height="auto" alt="Click zoom to zone" src="https://github.com/user-attachments/assets/3391664d-7297-41d4-be17-ac9b2e2c85d1" />
 81
 826. Scroll to zoom in and see more detail about the callers
 83
 84<img width="1964" height="auto" alt="Scroll to zoom in" src="https://github.com/user-attachments/assets/625c2bf4-a68d-40c4-becb-ade16bc9a8bc" />
 85
 867. Click on a caller to to get statistics on _it_.
 87
 88<img width="1888" height="auto" alt="Click on any of the zones to get statistics" src="https://github.com/user-attachments/assets/7e578825-2b63-4b7f-88f7-0cb16b8a3387" />
 89
 90While normally the blue bars in the Tracy timeline correspond to function calls they can time any part of a codebase. In the example below we have added an extra span "for block in edits" and added metadata to it: the block_height. You can do that like this:
 91
 92```rust
 93let span = ztracing::debug_span!("for block in edits", block_height = block.height());
 94let _enter = span.enter(); // span guard, when this is dropped the span ends (and its duration is recorded)
 95```
 96
 97# Task/Async profiling
 98
 99Get a profile of the zed foreground executor and background executors. Check if
100anything is blocking the foreground too long or taking too much (clock) time in
101the background.
102
103The profiler always runs in the background. You can save a trace from its UI or
104look at the results live.
105
106## Setup/Building the importer:
107
108Download the importer
109[linux x86_64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-import-miniprofiler-linux-x86_64)
110[mac aarch64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-import-miniprofiler-macos-aarch64)
111
112### Alternative: Building it yourself
113
114- Clone the repo at git@github.com:zed-industries/tracy.git on v0.12.2 branch
115- `cd import && mkdir build && cd build`
116- Run cmake to generate build files: `cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..`
117- Build the importer: `ninja`
118- Run the importer on the trace file: `./tracy-import-miniprofiler /path/to/trace.miniprof.json /path/to/output.tracy`
119- Open the trace in tracy:
120  - If you're on windows download the v0.12.2 version from the releases on the upstream repo
121  - If you're on other platforms open it on the website: https://tracy.nereid.pl/ (the version might mismatch so your luck might vary, we need to host our own ideally..)
122
123## To Save a Trace:
124
125- Run the action: `zed open performance profiler`
126- Hit the save button. This opens a save dialog or if that fails to open the trace gets saved in your working directory.
127- Convert the profile so it can be imported in tracy using the importer: `./tracy-import-miniprofiler <path to performance_profile.miniprof.json> output.tracy`
128- Go to <https://tracy.nereid.pl/> hit the 'power button' in the top left and then open saved trace.
129- Now zoom in to see the tasks and how long they took
130
131# Warn if function is slow
132
133```rust
134let _timer = zlog::time!("my_function_name").warn_if_gt(std::time::Duration::from_millis(100));
135```