Sayak's blog

Building an Inference Engine for the Non-GPU Era

Why I built it

I wanted to actually understand how a modern LLM inference server works — not just use vLLM, but reimplement the hard parts myself: continuous batching (packing requests into a GPU step efficiently instead of waiting for a whole batch to finish) and paged KV cache memory (block-based memory management so sequences can share a common prompt prefix instead of duplicating it). I called it iron-batch. Rust, built from scratch, scheduler and memory allocator with no assumptions baked in about what hardware sits underneath.

Why Rust

The scheduler manages a lot happening at once — sequences being admitted, evicted, and preempted while memory blocks get allocated and freed underneath them. That's exactly the kind of code where a small mistake in shared state turns into a bug that doesn't show up in testing and only appears under real, concurrent load. Rust's ownership rules catch a meaningful category of these mistakes at compile time instead of in production. It doesn't catch logic bugs — I found plenty of those the hard way — but for infrastructure code, removing that category of risk upfront felt worth the tradeoff.

Doubts along the way

For a while, my scheduler was only ever tested against a fake backend that simulated token generation without running any real model. It passed every test. It also proved nothing about whether the design actually worked with a real model attached, and I had to sit with that gap before I trusted anything I'd built. Wiring in a real model surfaced two bugs immediately that the fake backend had never once caught — one where a tensor had the wrong data type, one where an empty default value broke the model's attention computation. Both were invisible until a real model was involved. That was a useful, uncomfortable reminder that a clean design and a correct implementation aren't the same thing.

Things I did differently from vLLM

Not better — different, on purpose, for a different goal. A few concrete choices:

None of this makes iron-batch faster — measured throughput is in BENCHMARKS.md, and at single-request speed the two are close, with vLLM's advantage showing up properly under real concurrent load, which I haven't tested yet. These differences are about what iron-batch is for: a hardware-agnostic scheduling core, not a faster vLLM.

What I ditched from the legacy approach

The biggest thing I deliberately left out: any hardcoded assumption about the underlying compute layer. No CUDA calls, no PyTorch dependency, nothing GPU-specific anywhere in the scheduler or the memory allocator. Everything hardware-specific lives entirely behind the one interface mentioned above.

If you want to look at any of this more technically, here's the code: github.com/Dev-X25874/iron-batch


Real numbers, and what they show

I benchmarked iron-batch against vLLM (running Model Runner V2, its current execution engine — vLLM removed PagedAttention as a named path and replaced it with MRv2, which pipelines CPU scheduling and GPU execution instead of running them sequentially) on the same model, Qwen2.5-3B, on the same GPU.

Engine GPU Throughput
vLLM A10 22.08 tok/s
iron-batch A10 21.5 tok/s

Within about 3% of each other at single-request speed. Getting here took two real fixes: batching multiple tokens per network call instead of making one HTTP round-trip per token, and matching precision and GPU tier between the two engines for a fair comparison (an earlier, unfair version of this test had iron-batch running 4-bit quantized against vLLM's float16 — that gap disappears once precision is matched).

What this result doesn't show: neither engine's actual specialty gets exercised at concurrency 1. vLLM's pipelined scheduling and iron-batch's own continuous batching both exist to serve many concurrent requests efficiently — a single-request test measures raw decode speed with KV cache reuse, nothing more. That's the next test to run, not something this result already answers.

Every command and raw output behind these numbers is in BENCHMARKS.md, including how to reproduce it yourself against your own Modal deployment.