Skip to content

Latest commit

 

History

History
130 lines (97 loc) · 4.99 KB

File metadata and controls

130 lines (97 loc) · 4.99 KB

Contributor's guide

Prerequisites

Using Nix (Recommended)

The easiest way to set up the development environment is using Nix:

nix develop

This automatically provides all required dependencies (Rust toolchain, Protobuf, oas3-gen, cargo-deny) and configures git hooks.

Manual Setup

If you prefer not to use Nix, install the following manually:

Then install the pre-push git hook:

git config core.hooksPath .githooks

Building

To build the project with all its crates, run:

cargo build --workspace --all-features

Run Unit and Integration Tests

To run all tests - unit and integration - run:

cargo test --workspace --all-features

Running the Rust Documentation Locally

To build the documentation locally:

cargo doc --workspace --all-features --no-deps

Performance

When contributing, besides correctness, it is also important to ensure good performance and reproducibility of the results. We recommend using Criterion for general benchmarking, as it provides a well-structured framework that allows reproducible benchmarks by just running a few commands. We want to highlight 2 very useful commands in Criterion:

  • cargo bench -- --save-baseline <name> allows you to save a benchmark under a given name to serve as baseline.
  • cargo bench -- --baseline <name> compares the current benchmark against a previously saved baseline.

As an alternative to Criterion, we also recommend Divan, which provides a simpler API and a more intuitive benchmark organization. Criterion is still recommended for more rigorous statistical analysis, but Divan is great for most applications.

For performance, the profiling cycle is a 3-step process in which you need to first measure the resources consumed by your application, then isolate the most consuming ones, and finally optimize them. This cycle repeats until the performance goals are met. To carry out this optimization cycle, we recommend the following profiling tools, as they are powerful, general-purpose, and are either written or well integrated with Rust:

  • Hyperfine: Provides a simple CLI interface that allows us to benchmark compiled binaries.
  • Samply: Generates a detailed graphic of the different operations and their time in the application. We recommend it over FlameGraph as it allows for filtering, and the webserver viewer provides a better experience than the .svg your get from Flamegraph.
  • Dhat: Measures memory allocations within the application.

Hyperfine

Once installed, we can simply run:

hyperfine <binary>

Samply

Samply creates flame graphs and detailed call stacks with a browser-based Firefox Profiler.

Run

cargo install --locked samply

You may need to grant some system access to samply.

Into your Cargo.toml to add debug symbols in profiling mode:

[profile.profiling]
inherits = "release"
debug = true

Otherwise, reading the output will be impossible.

Then, we can run:

samply record <binary>

This command will open a browser page that contains a graphic representation of where the time is being spent in our application.

Dhat

We can add Dhat as a dependency:

[dependencies]
dhat = "latest"

[features]
dhat-heap = []

Then we need to replace the default allocator with the dhat allocator. And set the profiler when the dhat-heap feature is enabled:

#[cfg(feature = "dhat-heap")]
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;

fn main() {
    #[cfg(feature = "dhat-heap")]
    let _profiler = dhat::Profiler::new_heap();
}

If we run the binary again with the dhat-heap feature enabled, we will get a JSON file with the memory allocations done during the execution.

Many other profiling libraries exist, please check the Rust Performance Book for a more detailed list. But these 3 should be enough for the average application to identify bottlenecks and optimize them.

For async-rust we also recommend: Tracing, Tokio-Console, and Oha. For Rayon-based parallel Rust code, we recommend Samply. It provides good profiling despite missing some multithreading details.