Skip to content

Latest commit

 

History

History
88 lines (68 loc) · 3.79 KB

File metadata and controls

88 lines (68 loc) · 3.79 KB

Contributor's guide

Commit signing

Enable commit signing

git config commit.gpgsign true

Prerequisites

Code quality assurance

Install a pre-push git hook:

git config core.hooksPath .githooks

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.

Samply

Run

cargo install --locked samply

Please remember to add:

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

Into your Cargo.toml to add debug symbols in profiling mode. Otherwise, reading the output will be impossible.

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.