# Measure performance and resource use

Measure speed and memory use before changing how the program works.

Canonical: https://rust.robertdevore.com/course/24-performance/
Author: Robert DeVore
Technical baseline: Rust 1.98.1, edition 2024; verified 2026-09-06.

## A measurement starts with a question

Does parsing allocate? Does input reading dominate runtime? Does parallelism help on representative files? Each question needs its own test. “Rust is fast” does not answer any of them.


### Run the example

```sh
cargo run --locked --example 23_performance
```

```rust
use std::{hint::black_box, time::Instant};
fn main() {
    let input = "INFO small message";
    let start = Instant::now();
    for _ in 0..10_000 {
        black_box(audit_core::parse(black_box(input)).unwrap());
    }
    println!(
        "10,000 parses: {:?}; one sample, not a benchmark conclusion",
        start.elapsed()
    );
}
```

[View the tested source](https://github.com/robertdevore/rust.robertdevore.com/blob/main/examples/23_performance.rs)


The example shows how to time code and use `black_box`. One timing result is not enough to draw a conclusion. Startup, optimization, CPU frequency, background work, and tiny sample size can dominate. `black_box` is a best-effort optimization barrier useful in experiments, not a mathematical guarantee about generated code.

## Design the experiment

Run optimized builds when evaluating optimized production behavior. Record compiler version, target, profile, input distribution, hardware, and sample count. Make sure both versions produce the same output and handle errors the same way. Include empty input, typical records, long records near the limit, and malformed data if those occur in the workload.

Separate warm-up from samples where appropriate. Report a distribution rather than one favorable run. Change one significant variable at a time. If you claim lower memory use, measure it or prove a specific bound and state precisely which allocations the bound covers.

Our parser borrows message text rather than allocating a new string. That is visible in its interface and implementation. The reader keeps one bounded record vector, while the caller's buffering layer can have its own allocation. A borrowed design still pays for reading, validation, and counting; avoiding one allocation does not mean the whole program is zero-cost.

## Optimize the bottleneck

A profile may show that filesystem I/O dominates, in which case replacing an iterator with a loop is unlikely to matter. It may show formatting costs, in which case current standard-library APIs deserve review before adding a crate. Rust 1.98 introduced integer buffer formatting APIs, but our three-line-sized summary does not justify optimizing that path without evidence.

Monomorphization can improve inlining and also increase compile time or code size. Dynamic dispatch has indirection costs and can reduce duplication. `Arc::clone` updates an atomic count; `String::clone` copies text. Treat these as different operations. Check whether unnecessary copies or allocations cause the slowdown before reaching for unsafe code.

## Exercise

Compare parsing borrowed records with a version that creates a new owned message for each record. Preserve outputs and error handling. Record at least several repeated optimized runs and explain which part of the measurement is noisy. Do not commit a machine-specific speed claim as a universal fact.

<details><summary>Solution and acceptance check</summary>

Keep input bytes and loop counts identical, consume results so they cannot trivially disappear, and record toolchain/profile. The owned version allocates new message strings, but the timing difference may vary. A useful conclusion states the tested workload and uncertainty. If the difference is below noise, report that rather than selecting the fastest run.

</details>

Sources: [`black_box`](https://doc.rust-lang.org/std/hint/fn.black_box.html), [Cargo profiles](https://doc.rust-lang.org/cargo/reference/profiles.html), and [Rust 1.98 release notes](https://blog.rust-lang.org/2026/08/20/Rust-1.98.0/).

