Performance of Rust Language [pdf]

Rust’s claim to offer C-like performance with stronger memory safety is examined through real-world experiences and benchmarks, with many noting that bounds checks usually cost only a few percent but can hurt in tight loops or where vectorization is blocked. Commenters contrast Rust with C and modern C++, arguing that C++’s powerful templates and compile-time metaprogramming often make it easier to write highly optimized code in practice, even though equivalent performance is theoretically possible in Rust or C with more effort. A recurring concern is Rust’s slow compile times and heavy use of procedural macros, which can make the edit–compile–run loop painful on larger projects despite various suggested workarounds.

Rust performance and safety overhead

  • Bounds checks usually cost a few percent, but can reach ~20% in some hot paths or block autovectorization.
  • Techniques to reduce bounds checks include range-based iterators, slicing, explicit assert!s, and carefully placed unsafe.
  • When C++ is compiled with strong hardening (_FORTIFY_SOURCE, sanitizers, hardened STL), it often becomes slower than Rust for equivalent safety.
  • Integer overflow checks are expensive but are disabled in Rust release builds by default; they can be enabled if desired.

Bounds checking, optimization, and proofs

  • Rust currently lacks a stable, explicit contract for carrying high-level invariants from HIR to MIR, making sophisticated proof-based elimination of checks difficult.
  • LLVM’s scalar evolution (SCEV) is language-neutral and can’t exploit Rust-specific invariants well.
  • Bounds-check hoisting in MIR is possible but thorny: the compiler must preserve exact panic behavior and messages, and must reconstruct information lost during iterator lowering.
  • Some bounds-check patterns can already be removed via explicit asserts that LLVM can prove.

Comparisons with C and C++

  • One position: Rust is roughly as fast as C; modern C++ can be faster in practice due to powerful metaprogramming enabling zero-cost abstractions.
  • Counter-position: raw compiler optimizations on LLVM IR are shared, so C, C++, Rust, and Zig should be comparable; differences come from ergonomics, LTO, and how code is written.
  • C++ templates and constexpr are praised for enabling high-performance generic algorithms; others argue they increase complexity and can bloat code.
  • Rust’s strict aliasing rules can theoretically outperform C/C++, but current backends underutilize this potential.

Other languages and metaprogramming

  • Zig and Nim are cited as having strong compile-time metaprogramming; Nim’s crypto library is claimed to outperform C via generated assembly.
  • Julia and Fortran are mentioned as highly performant in numeric domains, but Julia is not considered a systems language.
  • Refinement-type approaches (e.g., Flux for Rust) aim to statically eliminate bounds checks.

Panics, exceptions, and semantics

  • Rust panics are catchable (like C++ exceptions), so the compiler cannot freely “time-travel” panics (e.g., hoisting a bounds failure to loop entry) without changing observable behavior.
  • Different rewrites of an out-of-bounds loop change when and where the panic occurs, which matters if panics are caught.

Compile times and tooling

  • Multiple comments criticize Rust’s slow compilation for large projects, harming the edit–compile–run loop.
  • Mitigations discussed: splitting code into multiple crates for parallelism and caching, reducing heavy proc macros (notably serde), using faster linkers (lld, mold), and caches like sccache/kache.
  • Rust’s single-crate “translation unit” model limits parallelism within a crate; LTO trades compile speed for runtime speed.
  • Some expect compiler parallelism and infrastructure work to improve this over time.

Ergonomics and real-world experience

  • Several practitioners report that writing truly high-performance code is:
    • Easiest in C++ (templates, allocators, compile-time tricks),
    • Much harder in C (no integrated generics),
    • Rust encourages safer, cache-friendly patterns and avoids some C++ pitfalls (e.g., overuse of inheritance and vtables).
  • A recurring theme: there is “no performance of a language” in the abstract; real performance depends on compilers, tooling, and what programmers are willing and able to express ergonomically.