# Rust Performance

> When to activate: Rust performance, profiling, zero-cost abstractions, iterators, SIMD, memory layout, flamegraph, allocation optimization

- Skill: `mattakushi432/rust-performance` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/rust-performance`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/rust-performance/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/rust-performance

---


# Rust Performance Patterns

## Profiling Tools

```bash
# Flamegraph (CPU profiling)
cargo install flamegraph
cargo flamegraph --bin my-server

# Benchmarks
cargo install cargo-criterion
cargo criterion

# Inspect generated assembly
cargo install cargo-asm
cargo asm my_crate::hot_function

# Memory profiling with dhat
# Add dhat feature to Cargo.toml and instrument main
```

## Iterator Performance

Iterators compile to the same machine code as hand-written loops — zero overhead.

```rust
// Single-pass chain — no intermediate allocations
let result: Vec<_> = data.iter()
    .filter(|&&x| x > 0)
    .map(|&x| x * 2)
    .collect();

// Avoid collect() in the middle of a chain
// BAD: two allocations
let filtered: Vec<_> = data.iter().filter(|&&x| x > 0).collect();
let mapped: Vec<_> = filtered.iter().map(|&&x| x * 2).collect();
```

## Avoiding Allocations

```rust
// &str instead of String when ownership isn't needed
fn process(input: &str) -> usize { input.len() }

// Stack allocation for small collections
use smallvec::SmallVec;
let mut v: SmallVec<[u8; 16]> = SmallVec::new(); // on stack until > 16 bytes

// Cow for conditionally owned data
use std::borrow::Cow;
fn normalize(s: &str) -> Cow<str> {
    if s.chars().all(|c| c.is_lowercase()) {
        Cow::Borrowed(s)
    } else {
        Cow::Owned(s.to_lowercase())
    }
}

// Pre-allocate known sizes
let mut result = Vec::with_capacity(items.len());
for item in &items { result.push(transform(item)); }
```

## Memory Layout Optimization

```rust
// Largest fields first to minimize padding
#[derive(Debug)]
struct Optimized {
    b: u64,  // 8 bytes
    d: u32,  // 4 bytes
    a: u8,   // 1 byte
    c: u8,   // 1 byte
    // 2 bytes padding
}  // 16 bytes total

// Compare to field-order that wastes space
#[derive(Debug)]
struct Wasteful {
    a: u8,   // 1 byte + 7 padding
    b: u64,  // 8 bytes
    c: u8,   // 1 byte + 3 padding
    d: u32,  // 4 bytes
}  // 24 bytes total

// Explicit layout control
#[repr(C)]          // C-compatible layout
#[repr(align(64))]  // cache-line aligned
struct CacheAligned { data: [u8; 64] }
```

## Cache-Friendly Data Structures

```rust
// Structure of Arrays (SoA) — better for bulk operations than Array of Structs
struct Particles {
    x: Vec<f32>,
    y: Vec<f32>,
    z: Vec<f32>,
    mass: Vec<f32>,
}

fn update_x(p: &mut Particles, velocities: &[f32], dt: f32) {
    // Sequential memory access = cache-friendly
    for (x, &vx) in p.x.iter_mut().zip(velocities.iter()) {
        *x += vx * dt;
    }
}
```

## Parallelism with rayon

```rust
use rayon::prelude::*;

let sum: i64 = data.par_iter().map(|&x| expensive(x)).sum();

let mut v: Vec<i32> = (0..1_000_000).collect();
v.par_sort();
```

## String Performance

```rust
// write! to a pre-allocated String instead of format! in hot paths
use std::fmt::Write;
let mut s = String::with_capacity(64);
write!(s, "user_{}_event_{}", user_id, event_id).unwrap();

// smol_str: stack-allocated for short strings
use smol_str::SmolStr;
let s: SmolStr = "short string".into(); // no heap for ≤23 bytes
```

## Release Profile Tuning

```toml
[profile.release]
opt-level = 3
lto = "thin"       # link-time optimization
codegen-units = 1  # cross-function optimization
strip = true
panic = "abort"    # no unwinding overhead

[profile.bench]
inherits = "release"
debug = true       # keep symbols for profiling
```

## Common Anti-Patterns

- **`clone()` in hot loops** — profile first; often avoidable with references or restructuring
- **`String` where `&str` suffices** — unnecessary heap allocation
- **`dyn Trait` in hot paths** — use generics (monomorphization) for zero-cost dispatch
- **Blocking I/O on async runtimes** — use `tokio::task::spawn_blocking`
- **Profiling debug builds** — always profile `--release` builds; debug is 10x slower

