agentsclimarketplace

Rust perf

Skill dawidpereira/rust-skills/skills/rust-perf

Rust performance optimization — memory, compiler hints, and profiling. Use when optimizing allocations (SmallVec, with_capacity, arena), configuring release profiles (LTO, PGO, codegen-units), adding inline hints, benchmarking with criterion, or profiling with flamegraph. Also use when reviewing code for unnecessary allocations, premature optimization, or format! in hot paths.From its SKILL.md

Install
npx -y skills add dawidpereira/rust-skills --skill rust-perf

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.0 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

Performance Optimization

Core Question

Have you measured first, or are you guessing?

Intuition about performance is often wrong. The code you think is slow frequently isn't. Profile first, then optimize the actual bottleneck with data-driven decisions.


Quick Decisions

SituationReach ForWhy
Collection size known upfrontVec::with_capacity(n)Avoids ~10 reallocations for 1000 elements
Usually-small collection (2-8 items)SmallVec<[T; N]>Stack-allocated for common case, heap fallback
Hard upper bound, no heap allowedArrayVec<T, N>Guaranteed stack-only, panics on overflow
Fixed-size heap data, never growsBox<[T]> / Box<str>Saves 8 bytes per instance vs Vec/String
Often-empty vectors in many instancesThinVec<T>8 bytes empty vs 24 bytes for Vec
One enum variant much larger than othersBox the large variantClippy large_enum_variant catches this
Millions of short strings (< 24 chars)CompactStringInline storage, zero heap allocation
Repeatedly cloning into same variabletarget.clone_from(&source)Reuses existing allocation
Temporary collection in a loop.clear() + reuseKeeps capacity across iterations
format!() in a hot loopwrite!(&mut buf, ...)Zero allocation with reused buffer
Many small allocations (AST, parsing)bumpalo::Bump arenaBump-pointer allocation, bulk free
Parsing without ownership needs&str / &[u8] slicesZero-copy, no allocation
Map insert-or-update.entry().or_insert()Single lookup instead of two
Iterating with manual indexing.iter() / .zip()Eliminates bounds checks, enables SIMD
Intermediate .collect() callsChain iterators lazilyOne allocation, one pass
Release build performancelto = "fat", codegen-units = 110-20% improvement typical
Proven hot inner loop function#[inline] or #[inline(always)]Cross-crate inlining hint
Error construction path#[cold] + #[inline(never)]Keeps cold code out of hot path
Need to benchmark correctlyblack_box() inputs and outputsPrevents dead code elimination

Optimization Priority

Optimize in this order — each level has roughly 10x less impact than the one above:

  1. Algorithm & data structure — O(n) vs O(n^2) dwarfs everything else
  2. Data layout — SoA vs AoS, cache-friendly access, avoid pointer chasing
  3. Allocations — with_capacity, reuse buffers, arena allocators
  4. Compiler hints — LTO, PGO, codegen-units, inline hints
  5. SIMD & low-level — portable SIMD, bounds check elimination, target-cpu

Profile BEFORE Optimizing

Tools

ToolWhat It ShowsWhen to Use
cargo flamegraphCPU time by call stackFirst step — find where time goes
cargo instruments -t time (macOS)CPU time profilingmacOS alternative to perf
criterionMicro-benchmark with statisticsCompare before/after for specific functions
DHAT / heaptrackHeap allocation sites and countsWhen allocation pressure is suspected
perf stat -e cache-missesCache efficiencyWhen data layout matters
cargo bloatBinary size by function/crateWhen binary size is a concern

Workflow

1. Write correct code first
2. Write benchmarks for suspected hot paths
3. Profile under realistic load
4. Identify actual bottlenecks (top 10% of time)
5. Optimize ONE thing
6. Measure improvement with same benchmark
7. Repeat if needed

Criterion Quick Setup

use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn bench_hot_function(c: &mut Criterion) {
    let data = generate_test_data(1000);
    c.bench_function("hot_function", |b| {
        b.iter(|| hot_function(black_box(&data)))
    });
}

criterion_group!(benches, bench_hot_function);
criterion_main!(benches);

Anti-Patterns to Watch For

Anti-PatternFix
format!() in hot loopwrite!(&mut buffer, ...) with reused buffer
Intermediate .collect() between iterator stepsChain lazily, collect once at end
Optimizing without profiling dataRun cargo flamegraph first
#[inline(always)] everywhereLet compiler decide; use #[inline] for cross-crate
unsafe to skip bounds checksUse iterators — they eliminate bounds checks safely
contains_key() then insert()Use .entry() API for single lookup

Usage Scenarios

Scenario 1: "My web handler is slow and I'm not sure why" -> Run cargo flamegraph on a representative workload. Look for wide bars (time hogs), malloc/free (allocation heavy), memcpy (unnecessary copies). Optimize only what the flamegraph shows as hot.

Scenario 2: "I have a Vec that I fill in a loop and it's showing up in profiling" -> Check if size is known: use with_capacity(). If the Vec is reused across iterations: .clear() instead of creating new. If always small (< 8 items): consider SmallVec. If fixed after creation: convert to Box<[T]>.

Scenario 3: "I need maximum throughput for a release binary" -> Set release profile: lto = "fat", codegen-units = 1, panic = "abort", strip = true. For deployment on known hardware: RUSTFLAGS="-C target-cpu=native". For maximum gains: use PGO with representative workloads.


Release Profile

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

[profile.bench]
inherits = "release"
debug = true
strip = false

[profile.dev.package."*"]
opt-level = 3

Reference Files

FileRead When
references/memory.mdAllocation strategies: with_capacity, SmallVec, arena, zero-copy, compact strings, type size assertions
references/compiler.mdCompiler hints: inline, #[cold], LTO, PGO, codegen-units, target-cpu, SIMD, cache layout
references/runtime.mdRuntime patterns: iterators vs indexing, lazy chains, entry API, drain/extend, collect patterns, benchmarking

Cross-References

WhenCheck
Clone vs borrow decision for performancerust-ownership -> Quick Decisions
Error construction on cold pathsrust-errors -> Quick Decisions
Async runtime and spawn_blocking for CPU workrust-async -> Quick Decisions
API design that avoids unnecessary allocationsrust-api -> Quick Decisions
Clippy perf lints and lint configurationrust-quality -> Quick Decisions

What ships with it: 3 files

24.5 KB alongside SKILL.md

references/

Gives 0 of the 12 instructions most performance cost skills give in ~1.7k tokens

Counted across 803 of the 1,058 authors here whose files we hold, read 2026-08-07

  • Keep skill files under 500 lines or tokensin 82 of 803, across 16 files
  • Use imperative form in instructionsin 80 of 803, across 9 files
  • Draft assertions while test runs are in progressin 75 of 803, across 9 files
  • Create two to three realistic test promptsin 74 of 803, across 9 files
  • Write skill descriptions to be pushyin 72 of 803, across 7 files
  • Save test cases to evals JSONin 72 of 803, across 6 files
  • Ask questions about edge cases and input formatsin 72 of 803, across 7 files
  • Save timing data immediately when runs completein 70 of 803, across 5 files
  • Include all trigger conditions in the skill descriptionin 69 of 803, across 3 files
  • Launch all test runs in a single turn or simultaneouslyin 69 of 803, across 3 files
  • Capture intent before writing a skillin 67 of 803, across 1 file
  • Import directly instead of barrel filesin 52 of 803, across 15 files

Said here and by no other author read

  • Write benchmarks for hot paths
  • Measure improvements with the same benchmark
  • Preallocate collections if size is known
  • Chain iterators lazily to avoid intermediate collections
  • Set LTO and single codegen unit for release builds
  • Use black box for benchmark inputs and outputs

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,861. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.