Backoff & Memory Provisioning: Adaptive Spinning, Custom Allocators, NUMA & Huge Pages Part 6 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 1 decided where the shared cursors of a concurrent structure live in memory. Part 2 covered how two cores read…
Compile-Time Leverage: Specialization, Branch & Arithmetic Hygiene, and Inlining Part 5 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 1 decided where the shared cursors of a concurrent structure live in memory. Part 2 covered how two cores read and…
Zero-Copy on the Hot Path: Reserve/Commit and Fast-Path/Slow-Path Splitting Part 4 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 1 decided where the shared cursors of a concurrent structure live in memory. Part 2 covered how two cores read…
Amortizing Cross-Core Coordination: Cursor Caching and Batch Processing Part 3 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 1 decided where the shared cursors of a concurrent structure live in memory. Part 2 covered how two cores read and write them…
The Cross-Core Contract: Memory Ordering and Single-Writer State in Lock-Free Rust Part 2 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 1, Cache-Conscious Data Layout , decided where the shared fields of a concurrent structure live in memory. This…
Cache-Conscious Data Layout: Field Zoning, False Sharing, and the 128-Byte Rule Part 1 of Low-Level Systems Design in Rust - a series on writing high-throughput, low-latency systems code, using a single-producer / single-consumer (SPSC) ring buffer as the running example. Part 0 - Architectural Decomposition made the highest-leverage decision (remove contention structurally, so every writer…
Architectural Decomposition: Remove Contention by Design Across the Rust projects I've worked on, the ones that demanded high throughput and low latency were almost always built around a few architectural principles that remained invariant across all of them. Many of these principles are not limited to Rust, but apply equally, with implementation-specific variations, to lower-level languages…
Scalar Replacement of Aggregates: How "Copy to Locals" Unlocks the Compiler Some performance fixes look almost suspiciously small in the diff. You change a couple of lines, the code still says the same thing to a human reader, and a hot loop suddenly has far less memory traffic. TigerBeetle's PR #3201 is one of those fixes. It changed the AEGIS-128L state update in…
Why x86 Zeroes a Register With xor eax, eax If you have ever disassembled a program - even a trivial one - you have almost certainly seen this line: xor eax , eax It looks like a riddle. The instruction says "XOR the eax register with itself," but what it actually means is "set eax to zero." In optimized code, compilers and assembly programmers commonly reach for it instead of the more obvious:…
Set-Associative Caches: Trading Global Optimality for Predictable Speed Caches are everywhere in modern systems: CPU L1/L2 caches, database buffer caches, storage-engine object caches, and application-level LRU maps. They do not all make the same trade-offs. A set-associative cache sits at a particular point in the design space: it gives up global replacement freedom in exchange for bounded…
Building a custom Bitset - A study in access-pattern-driven data structure choice I was porting porcupine-rust to Zig - the core of the implementation is a Bitset data structure, which is used in the implementation of a cache (see below for the details of why we need the cache). porcupine-zig carries two bitset implementations and uses them in two different places: Site Type Mode Purpose…
Zig Allocation Patterns A reference for the allocation and ownership patterns used in porcupine-zig , plus the broader landscape of Zig allocator idioms. Examples cite types and functions in the codebase by name so the patterns can be grounded against real code. But the discussion in this post stands on its own and does not require reading those sources. 1. The two ownership models: aware vs.…
Why Zig’s Io Feels Like an Effect System (Without Being One) Context: What does "effect" even mean? The word is overloaded, and most arguments about whether something "is" an effect collapse the moment you fix a sense. At least four are in play: A semantic side effect - reading a file, mutating memory, throwing. A type-level effect annotation - Koka-style effect rows, where the function type…
Evaluating PBT Frameworks: How Proptest and Hegel Differ in Algebraic Expressivity Context I have recently been working on porcupine-rust is a Rust port of Porcupine , a linearizability checker for concurrent and distributed systems, with APIs over timestamped Operation histories and raw Event histories, optional timeout-bounded checking, P-compositional partitioning, and support for…
The RAII Drop-Guard Pattern in Rust Context In Rust, any value that owns a resource and frees it in its Drop implementation acts as a guard : the resource lives for exactly as long as the value is in scope. This is RAII - Resource Acquisition Is Initialization - and in Rust it is the primary, statically-enforced mechanism for resource management. A drop guard is the pattern of binding such a value…
Pin<Box<dyn Future + Send>> in Traits - Why the Manual Desugar? Context When a Rust trait needs async methods and must be usable as a trait object ( Box<dyn Trait> , &dyn Trait , Arc<dyn Trait> ), you cannot just write async fn and move on. async fn in traits returns an opaque impl Future whose concrete type differs per implementation - which breaks vtable dispatch. The compiler's own…