We use several buffer pools across `connlib` that are all backed by the same buffer-pool library. Within that library, we currently use another object-pool library to provide the actual pooling functionality. Benchmarking has shown that spend quite a bit of time (a few % of total CPU time), fighting for the lock to either add or remote a buffer from the pool. This is unnecessary. By using a queue, we can remove buffers from the front and add buffers at the back, both of which can be implemented in a lock-free way such that they don't contend. Using the well-known `crossbeam-queue` library, we have such a queue directly available. I wasn't able to directly measure a performance gain in terms of throughput. What we can measure though, is how much time we spend dealing with our buffer pool vs everything else. If we compare the `perf` outputs that were recorded during an `iperf` run each, we can see that we spend about 60% less time dealing with the buffer pool than we did before. |Before|After| |---|---| |<img width="1982" height="553" alt="Screenshot From 2025-07-24 20-27-50" src="https://github.com/user-attachments/assets/1698f28b-5821-456f-95fa-d6f85d901920" />|<img width="1982" height="553" alt="Screenshot From 2025-07-24 20-27-53" src="https://github.com/user-attachments/assets/4f26a2d1-03e3-4c0d-84da-82c53b9761dd" />| The number in the thousands on the left is how often the respective function was the currently executing function during the profiling run. Resolves: #9972
Rust development guide
Firezone uses Rust for all data plane components. This directory contains the Linux and Windows clients, and low-level networking implementations related to STUN/TURN.
We target the last stable release of Rust using rust-toolchain.toml.
If you are using rustup, that is automatically handled for you.
Otherwise, ensure you have the latest stable version of Rust installed.
Reading Client logs
The Client logs are written as JSONL for machine-readability.
To make them more human-friendly, pipe them through jq like this:
cd path/to/logs # e.g. `$HOME/.cache/dev.firezone.client/data/logs` on Linux
cat *.log | jq -r '"\(.time) \(.severity) \(.message)"'
Resulting in, e.g.
2024-04-01T18:25:47.237661392Z INFO started log
2024-04-01T18:25:47.238193266Z INFO GIT_VERSION = 1.0.0-pre.11-35-gcc0d43531
2024-04-01T18:25:48.295243016Z INFO No token / actor_name on disk, starting in signed-out state
2024-04-01T18:25:48.295360641Z INFO null
Benchmarking on Linux
The recommended way for benchmarking any of the Rust components is Linux' perf utility.
For example, to attach to a running application, do:
- Ensure the binary you are profiling is compiled with the
releaseprofile. sudo perf record -g --freq 10000 --pid $(pgrep <your-binary>).- Run the speed test or whatever load-inducing task you want to measure.
sudo perf script > profile.perf- Open profiler.firefox.com and load
profile.perf
Instead of attaching to a process with --pid, you can also specify the path to executable directly.
That is useful if you want to capture perf data for a test or a micro-benchmark.