### Install canbench Source: https://github.com/dfinity/canbench/blob/main/README.md Install the canbench CLI tool using cargo. ```bash cargo install canbench ``` -------------------------------- ### Complete Canister Example with Benchmarks Source: https://context7.com/dfinity/canbench/llms.txt Demonstrates state management benchmarking in a Rust canister, comparing BTreeMap with HashMap. Includes pre-upgrade logic and various benchmark functions for insertion, removal, and serialization. ```rust use candid::{CandidType, Encode}; use ic_cdk::pre_upgrade; use std::cell::RefCell; #[derive(CandidType)] struct User { name: String, } #[derive(Default, CandidType)] struct State { // Try replacing BTreeMap with HashMap and run canbench to compare users: std::collections::BTreeMap, } thread_local! { static STATE: RefCell = RefCell::new(State::default()); } #[pre_upgrade] fn pre_upgrade() { let bytes = { #[cfg(feature = "canbench-rs")] let _p = canbench_rs::bench_scope("serialize_state"); STATE.with(|s| Encode!(s).unwrap()) }; #[cfg(feature = "canbench-rs")] let _p = canbench_rs::bench_scope("writing_to_stable_memory"); ic_cdk::stable::StableWriter::default() .write(&bytes) .unwrap(); } #[cfg(feature = "canbench-rs")] mod benches { use super::*; use canbench_rs::bench; #[bench] fn insert_users() { STATE.with(|s| { let mut s = s.borrow_mut(); for i in 0..1_000_000 { s.users.insert(i, User { name: "foo".to_string() }); } }); } #[bench(raw)] fn remove_users() -> canbench_rs::BenchResult { insert_users(); canbench_rs::bench_fn(|| { STATE.with(|s| { let mut s = s.borrow_mut(); for i in 0..1_000_000 { s.users.remove(&i); } }) }) } #[bench(raw)] fn pre_upgrade_bench() -> canbench_rs::BenchResult { insert_users(); canbench_rs::bench_fn(pre_upgrade) } } fn main() {} ``` -------------------------------- ### Cargo.toml Setup for Canbench Source: https://context7.com/dfinity/canbench/llms.txt Add canbench-rs as an optional dependency in your Cargo.toml file. This prevents benchmarks from being included in production builds. ```toml [dependencies] canbench-rs = { version = "0.4.1", optional = true } [features] canbench-rs = ["dep:canbench-rs"] ``` -------------------------------- ### #[bench(raw)] Macro for Excluding Setup Code Source: https://context7.com/dfinity/canbench/llms.txt Use `#[bench(raw)]` when setup code needs to be excluded from measurements. The function must return `canbench_rs::BenchResult`. This allows for precise benchmarking of specific operations. ```rust #[cfg(feature = "canbench-rs")] mod benches { use super::*; use canbench_rs::bench; // Setup function to populate state (not measured) fn initialize_state() { STATE.with(|s| { let mut s = s.borrow_mut(); for i in 0..1_000_000 { s.users.insert(i, User { name: "foo".to_string() }); } }); } #[bench(raw)] fn pre_upgrade_bench() -> canbench_rs::BenchResult { // Setup: populate state with 1 million users initialize_state(); // Only benchmark the pre_upgrade function canbench_rs::bench_fn(pre_upgrade) } #[bench(raw)] fn remove_users() -> canbench_rs::BenchResult { // Setup: insert users first initialize_state(); // Only benchmark the removal operation canbench_rs::bench_fn(|| { STATE.with(|s| { let mut s = s.borrow_mut(); for i in 0..1_000_000 { s.users.remove(&i); } }) }) } } // Output: // --------------------------------------------------- // Benchmark: pre_upgrade_bench (new) // total: // instructions: 717.10 M (new) // heap_increase: 519 pages (new) // stable_memory_increase: 184 pages (new) // --------------------------------------------------- ``` -------------------------------- ### Inefficient Recursive Fibonacci Implementation Source: https://context7.com/dfinity/canbench/llms.txt An example of an inefficient recursive implementation of the Fibonacci function, which will likely show regressions when benchmarked against a baseline. ```rust // After persisting baseline with `canbench --persist` // Subsequent runs compare against the baseline // If implementation becomes inefficient: #[ic_cdk::query] fn fibonacci(n: u32) -> u32 { match n { 0 => 1, 1 => 1, _ => fibonacci(n - 1) + fibonacci(n - 2), // Inefficient recursive } } ``` -------------------------------- ### Benchmark a Specific Function with bench_fn() Source: https://context7.com/dfinity/canbench/llms.txt Use `bench_fn` to benchmark a specific closure. Setup code outside the closure is not included in the measurement. Returns a `BenchResult`. ```rust use canbench_rs::{bench_fn, BenchResult}; #[bench(raw)] fn benchmark_serialization() -> BenchResult { // Setup: create data (not benchmarked) let data = create_large_dataset(); // Only benchmark the serialization bench_fn(|| { let bytes = candid::Encode!(&data).unwrap(); std::hint::black_box(bytes); }) } ``` -------------------------------- ### Run All Benchmarks Source: https://context7.com/dfinity/canbench/llms.txt Execute all benchmarks defined in the project. ```bash canbench ``` -------------------------------- ### Show Summary of All Benchmark Results Source: https://context7.com/dfinity/canbench/llms.txt Display a summary of all benchmark results, useful for a quick overview. ```bash canbench --show-summary ``` -------------------------------- ### Use Custom Runtime Path Source: https://context7.com/dfinity/canbench/llms.txt Specify a custom path to the Pocket IC runtime environment. ```bash canbench --runtime-path /path/to/pocket-ic ``` -------------------------------- ### Enable Instruction Tracing Source: https://context7.com/dfinity/canbench/llms.txt Activate instruction tracing for benchmarks. This feature is experimental. ```bash canbench --instruction-tracing ``` -------------------------------- ### CLI Commands - Running Benchmarks Source: https://context7.com/dfinity/canbench/llms.txt The canbench CLI allows for running, persisting, and reporting on benchmark results. ```APIDOC ## CLI Commands ### Description Run benchmarks and manage results using the canbench command line interface. ### Usage - `canbench`: Run all benchmarks - `canbench [pattern]`: Run specific benchmark by name pattern - `canbench --persist`: Persist results to canbench_results.yml - `canbench --csv`: Generate CSV report - `canbench --show-summary`: Show summary of all benchmark results - `canbench --show-canister-output`: Show canister debug output (ic_cdk::eprintln!) ``` -------------------------------- ### Basic canbench.yml Configuration Source: https://context7.com/dfinity/canbench/llms.txt A basic configuration file for canbench, specifying build commands and WASM paths. Optional fields for results paths, init arguments, and stable memory are also shown. ```yaml # Basic configuration build_cmd: cargo build --release --target wasm32-unknown-unknown --locked --features canbench-rs wasm_path: ./target/wasm32-unknown-unknown/release/my_canister.wasm # Optional: custom results file path results_path: custom_results.yml # Optional: custom CSV results file path csv_results_path: custom_results.csv # Optional: init arguments (hex-encoded Candid) init_args: hex: 4449444c0001710568656c6c6f # Optional: load stable memory from file after init stable_memory: file: stable_memory.bin ``` -------------------------------- ### Run Specific Benchmark by Name Pattern Source: https://context7.com/dfinity/canbench/llms.txt Execute benchmarks that match a given name pattern. ```bash canbench fibonacci_20 ``` -------------------------------- ### Set Custom Config File via Environment Variable Source: https://context7.com/dfinity/canbench/llms.txt Specify a custom configuration file for Canbench using the `CANBENCH_CFG_FILE` environment variable. ```bash CANBENCH_CFG_FILE=custom_config.yml canbench ``` -------------------------------- ### Persist Benchmark Results Source: https://context7.com/dfinity/canbench/llms.txt Save benchmark results to a `canbench_results.yml` file for future comparisons. ```bash canbench --persist ``` -------------------------------- ### Basic #[bench] Macro Usage Source: https://context7.com/dfinity/canbench/llms.txt Marks a function as a benchmark using the `#[bench]` macro. The function must take no arguments and return nothing. Use `std::hint::black_box` to prevent compiler optimizations. ```rust #[cfg(feature = "canbench-rs")] mod benches { use super::*; use canbench_rs::bench; #[bench] fn fibonacci_20() { // Use black_box to prevent compiler optimizations std::hint::black_box(fibonacci(std::hint::black_box(20))); } #[bench] fn fibonacci_45() { std::hint::black_box(fibonacci(std::hint::black_box(45))); } } // Output when running `canbench`: // --------------------------------------------------- // Benchmark: fibonacci_20 (new) // total: // instructions: 2301 (new) // heap_increase: 0 pages (new) // stable_memory_increase: 0 pages (new) // --------------------------------------------------- // Benchmark: fibonacci_45 (new) // total: // instructions: 3088 (new) // heap_increase: 0 pages (new) // stable_memory_increase: 0 pages (new) // --------------------------------------------------- // Executed 2 of 2 benchmarks. ``` -------------------------------- ### Set Custom Noise Threshold Source: https://context7.com/dfinity/canbench/llms.txt Configure a custom noise threshold for benchmark comparisons. The default is 2.0%. ```bash canbench --noise-threshold 5.0 ``` -------------------------------- ### Benchmark with Debug Print Source: https://context7.com/dfinity/canbench/llms.txt Demonstrates how to use `ic_cdk::eprintln!` within a benchmark to output debug information. Use the `--show-canister-output` flag when running Canbench to see this output. ```rust #[cfg(feature = "canbench-rs")] mod benches { use canbench_rs::bench; #[bench] fn bench_with_debug_print() { ic_cdk::eprintln!("Starting benchmark for {}!", env!("CARGO_PKG_NAME")); let result = expensive_computation(); ic_cdk::eprintln!("Computation result: {:?}", result); std::hint::black_box(result); } } ``` -------------------------------- ### Show Less Verbose Output Source: https://context7.com/dfinity/canbench/llms.txt Display only benchmark results, reducing the verbosity of the output. ```bash canbench --less-verbose ``` -------------------------------- ### Show Canister Debug Output Source: https://context7.com/dfinity/canbench/llms.txt Enable the display of debug output (e.g., from `ic_cdk::eprintln!`) generated during canister execution. ```bash canbench --show-canister-output ``` -------------------------------- ### bench_fn() - Benchmark a Specific Function Source: https://context7.com/dfinity/canbench/llms.txt The bench_fn() function wraps and benchmarks only the code passed to it, returning a BenchResult containing instruction counts and memory measurements. ```APIDOC ## bench_fn() ### Description Wraps and benchmarks a specific block of code, returning a `BenchResult` object. ### Request Example ```rust use canbench_rs::{bench_fn, BenchResult}; #[bench(raw)] fn benchmark_serialization() -> BenchResult { let data = create_large_dataset(); bench_fn(|| { let bytes = candid::Encode!(&data).unwrap(); std::hint::black_box(bytes); }) } ``` ``` -------------------------------- ### Generate CSV Report Source: https://context7.com/dfinity/canbench/llms.txt Persist results to YAML and generate a CSV report alongside it. ```bash canbench --persist --csv ``` -------------------------------- ### Hide Individual Benchmark Outputs Source: https://context7.com/dfinity/canbench/llms.txt Suppress the detailed output for each individual benchmark, showing only the summary. ```bash canbench --hide-results ``` -------------------------------- ### BenchResult and Measurement Types in Rust Source: https://context7.com/dfinity/canbench/llms.txt Defines the structures for benchmark results, including overall and per-scope measurements of calls, instructions, and memory increases. Used to access and assert benchmark outcomes programmatically. ```rust use canbench_rs::{BenchResult, Measurement}; // BenchResult structure pub struct BenchResult { pub total: Measurement, // Overall benchmark measurement pub scopes: BTreeMap, // Per-scope measurements } // Measurement structure pub struct Measurement { pub calls: u64, // Number of calls made during measurement pub instructions: u64, // Total instruction count pub heap_increase: u64, // Heap memory increase in pages pub stable_memory_increase: u64, // Stable memory increase in pages } // Access results programmatically #[bench(raw)] fn custom_benchmark() -> BenchResult { let result = bench_fn(|| { // benchmarked code }); // You can inspect or modify the result assert!(result.total.instructions < 1_000_000); result } ``` -------------------------------- ### bench_scope() - Granular Scope Measurement Source: https://context7.com/dfinity/canbench/llms.txt The bench_scope() function measures specific code sections within a benchmark, allowing for detailed profiling of individual operations. ```APIDOC ## bench_scope() ### Description Measures specific code sections within a benchmark. It must be assigned to a variable to maintain the scope duration. ### Request Example ```rust #[pre_upgrade] fn pre_upgrade() { let bytes = { #[cfg(feature = "canbench-rs")] let _p = bench_scope("serialize_state"); STATE.with(|s| candid::Encode!(s).unwrap()) }; #[cfg(feature = "canbench-rs")] let _p = bench_scope("writing_to_stable_memory"); ic_cdk::stable::StableWriter::default().write(&bytes).unwrap(); } ``` ``` -------------------------------- ### Skip Runtime Integrity Check Source: https://context7.com/dfinity/canbench/llms.txt Disable the integrity check for the runtime environment. ```bash canbench --no-runtime-integrity-check ``` -------------------------------- ### Measure Specific Code Sections with bench_scope() Source: https://context7.com/dfinity/canbench/llms.txt Use `bench_scope` to measure granular code sections within a benchmark. The result must be assigned to a variable. Useful for identifying performance bottlenecks in different parts of a function. ```rust use canbench_rs::bench_scope; use ic_cdk::pre_upgrade; #[pre_upgrade] fn pre_upgrade() { // Measure serialization separately let bytes = { #[cfg(feature = "canbench-rs")] let _p = bench_scope("serialize_state"); STATE.with(|s| candid::Encode!(s).unwrap()) }; // Measure stable memory writes separately #[cfg(feature = "canbench-rs")] let _p = bench_scope("writing_to_stable_memory"); ic_cdk::stable::StableWriter::default() .write(&bytes) .unwrap(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.