Skip to content

Revision · Part 6: Make It Fast

Part 6 is the discipline that separates “I use Rust” from “I made this fast.” Speed isn’t a property of the language; it’s a property of code you measured and fixed. The whole part runs one loop on the real quill under real load: profile, find the actual bottleneck, fix it, and prove the fix with numbers.

  • The one rule: measure first — establish a baseline, profile to find the hottest thing, change exactly one thing, re-measure, keep or revert. Never optimize what you haven’t measured; every instinct about “what’s slow” is wrong often enough that guessing is a bug.
  • A real load test and baselineoha/wrk giving requests/sec and p50/p99 latency for the list, read, and draft paths.
  • A profiling toolkitcriterion for microbenchmarks, cargo-flamegraph for CPU, and tokio-console to catch tasks that block the async runtime.
  • A sequence of real fixes, each with before/after — kill an accidental .clone() in a hot handler, move a blocking call off the runtime, right-size the connection pool, add the Part 4 cache to the hottest read, and serialize once instead of twice.
  • Where Rust’s speed comes from — and how to lose it — no GC pauses (lost by blocking the async runtime), zero-cost abstractions (lost by needless boxing/dyn on the hot path), stack and ownership (lost by cloning in a loop), and real parallelism (lost to one undersized pool serializing everything).
  • “Fast enough” is a real answer — the goal is a quill that meets a target you set (say p99 < 50 ms on the read path) and then stopping; optimization has diminishing returns and rising complexity.

Part 6’s answer to the thread is that performance is evidence, not vibes: you don’t get to say your Rust service is fast, you get to show a flamegraph, a before/after p99, and a load-test graph. That habit — measure, change one thing, measure again — is the most transferable skill in the entire book. Next, Part 7 automates the deploy and closes the loop.