Building AI infra · Since 2015 · Unum

The hardware moved on. Most software Didn’t.

Six assumptions worth revisiting, and what changes when you do.

And the open-source engines we built around each answer.

01 · Network latency

Latency doesn’t autoscale.

Capacity scales. Distance doesn’t.

Separating storage from compute is the most repeated lesson of the last decade of systems design, and it earned the repetition: storage scales on its own invoice, compute comes and goes, and durability becomes somebody else’s problem. For bulk scans it holds. A column store streaming a terabyte barely notices whether the bytes came from a bucket or a drive.

It stops holding where one read decides the next. A transaction commit, a graph walk and a nearest-neighbor search each issue hundreds of dependent reads, each waiting for the last, so a round trip of milliseconds becomes seconds per query. Those workloads belong beside the compute, with one copy of the data on local drives, in RAM or in VRAM, reached through direct I/O and not over a network. Once the bytes are local, the bottleneck moves into the core.

Fig. 1.1A server of local drives answers four orders of magnitude more random reads than one object-storage prefix

Random 4 KiB reads in one second on one linear axis · KIOXIA CM9 15.36 TB, PCIe 5.0, rated

more random reads a second: one server of drives against one S3 prefix
×14,800
lower latency per read: ≈ 80 µs on NVMe against ≈ 30 ms per S3 GET
×375
  1. One server 81,600,000 24× KIOXIA CM9
  2. One KIOXIA CM9 3,400,000
  3. S3 Express One Zone 200,000 one bucket
  4. S3 Standard 5,500 one prefix · Yes, the bar is here.
Drive figures are KIOXIA’s rating for the 15.36 TB CM9, a PCIe 5.0 drive, at queue depth 512. Object-storage figures are AWS’s documented request rates, which grow only as you add prefixes or buckets.

Sources KIOXIA CM9 · S3 performance guidelines · S3 Express One Zone

Fig. 1.2Scans tolerate a round trip; dependent reads multiply it

Scroll horizontally to explore →

WorkloadDependent reads per opLocal NVMeObject storageVerdict
Bulk scan of 1 TBstreamed≈ 5 s≈ 80 stolerable
Transaction commit≈ 2 + a write≈ 0.2 ms≈ 100 msprohibitive
Vector search, 1 B≈ 250 hops≈ 20 ms≈ 7.5 simpractical
Vector search, 100 B≈ 400 hops≈ 32 ms≈ 12 simpractical
A graph search walks ≈ 250 hops at a billion vectors, and the path grows with the dataset. Reading eight neighbors per hop shortens both columns about eightfold and leaves the 375× gap untouched. The times are estimates, not measurements, built from ≈ 80 µs per NVMe read and ≈ 30 ms per object-store GET.

Sources Durner, Leis & Neumann, VLDB 2023 · DiskANN, NeurIPS 2019

02 · Wider cores

Your compiler knows over 80,000 intrinsics. It just doesn’t know where they go.

Cores got wider. Compilers still use a fraction of what they know.

Trusting the compiler is the right default, and it won for good reasons: for scalar control flow, clang and GCC schedule better than any hand, and portable source outlives any one chip. Two decades of flat clocks were absorbed mostly by compilers and runtimes getting smarter.

Auto-vectorization stops at the loop it can prove. Mixed-precision dot products, masked substring search, AES-based hashing and predicated edit distances are different algorithms, not differently scheduled ones, and every extension spells them out as one intrinsic per type, width and mask. Those kernels are written by hand, one per ISA generation, and chosen at runtime. The same gap repeats across the PCIe bus, where most of the box’s compute now sits.

Fig. 2.1A course teaches 40 instructions, a compiler emits a few hundred, a vector ISA offers thousands

Taught in a course
40 instructions
Emitted at ‑O2
≈ 240 instructions
x86 AVX2, AVX-512 & AMX
5,335 intrinsics
Arm NEON, SVE & SME
13,383 intrinsics
RISC-V RVV 1.0
61,397 intrinsics
  • What compilers use
  • What the hardware added
One square is 100 words. A course teaches RV32I’s 40 instructions, and a clang 20 ‑O2 build of SQLite emits about 240 distinct mnemonics. Vector extensions are spelled out as C intrinsics, one per type, width, mask and policy. Counting typed names without overloads, clang 23’s AVX2, AVX‑512, AMX, NEON, SVE and SME headers declare 18,718, and it accepts all 61,397 names in the RVV 1.0 specification’s base and policy lists, which leave out BF16, crypto and later extensions: over 80,000 in all.

Sources riscv-opcodes · instruction popularity in Ubuntu, SYSTOR 2019 · Intel Intrinsics Guide · Arm intrinsics · RVV intrinsics

Fig. 2.2Every layer below the engine has a hand-written replacement

  1. Byte & string primitives StringZilla

    Most softwarememmem · std::hash · std::sortGeneric string routines and hashing

    We builtsz_find · sz_hash · sz_levenshtein_*Vectorized search, hashes and edit distances

  2. Mixed-precision numerics NumKong

    Most softwarefor (…) · cblas_sgemmAuto-vectorized loops or vendor BLAS

    We builtnk_dot_* · nk_dots_* · nk_attention_*Typed products, attention and matrix tiles

  3. Parallelism & scheduling ForkUnion

    Most softwarestd::async · #pragma omp parallelGeneral-purpose tasks and thread pools

    We builtforkunion_t · extended_atomic_refNUMA-aware fork-join and extended atomics

  4. Atomics & collections SmashTable

    Most softwarestd::mutex · std::unordered_mapA lock around each shared container

    We builtatomic_hash_table · transaction_group::commitAtomic slots and commits across containers

  5. Search & storage engines USearchUStore

    Most softwareSELECT … · HTTP / JSONA separate server for each data model

    We builtusearch_* · ustore_*Embedded search and storage behind one ABI

03 · Accelerators

80% of the watts. Petabytes of capacity. Terabytes a second.

A GPU brings compute. An SSD brings capacity. Neither helps an application that can’t reach it.

Keeping the engine on the CPU and the dataset in RAM was right for a long time: GPUs were for training, VRAM was small, PCIe was slow, and a pointer-chasing index wanted a general-purpose core. Most storage engines and vector indexes still assume it.

In a current node most of the rated watts are in the accelerators and most of the capacity is in the drives, with the CPU and its RAM between them as the narrowest tier. A CPU-only engine idles the compute; a RAM-only engine caps the data at terabytes. So the graph walk belongs in VRAM, the merge of sorted runs on the GPU, and the kernels on NVIDIA, AMD and Apple devices beside six CPU families. The problem is no longer the number of devices but the copies between them.

Fig. 3.1The watts are in the GPUs, the capacity is in the drives, and the CPU sits between them

≈ 95% of the box
  • Rest of one DGX B300 ≈ 13.3 kW
  • 2× Xeon 6776P ≈ 0.7 kW
← Higher peak bandwidth Larger maximum capacity → Higher bandwidth first. Larger capacity below.

VRAM · GDDR & HBM

8 GB–2.3 TB

≈ 256 GB/s–64 TB/s

From 1x laptop GPU to 8x B300s with NVLink and HBM3e

Strength
Massive parallelism and aggregate HBM bandwidth
Tradeoff
Smaller capacity; irregular work needs new algorithms

RAM · DDR5

4 GiB–32 TB

≈ 40 GB/s–2.3 TB/s

From 32-bit WASM sandboxes to 8x-socket Xeon Platinum systems

Strength
Low-latency random access and flexible control flow
Tradeoff
Capacity costs more; remote NUMA access adds latency

NVMe · NAND

1.92 TB–2.46 PB

≈ 14–540 GB/s

From 1x to 40x PCIe 5.0 ×4 drives on dual-socket AMD Zen 5

Strength
Petabyte capacity close to the compute
Tradeoff
Higher read latency; batch requests and overlap I/O

Beyond one nodeNVLink, InfiniBand and Ethernet connect the next tier. Scale locally first; cross the network when the workload needs it.

Power: NVIDIA rates one DGX B300 at about 14 kW, and Intel rates each of its two Xeon 6776P at 350 W. Capacity spans separate configurations. Hardware bandwidth ceilings use one DDR5-4800 through 64 DDR5-4400 channels for RAM, one 8 GB laptop GPU through eight B300s for VRAM, and CM9 sequential reads for NVMe. Forty drives devote all 160 PCIe lanes to storage; application throughput depends on the workload.

Sources Xeon 8490H · DGX B300 · DGX B300 user guide · Xeon 6776P · CM9 SSDs

Fig. 3.2One runtime dispatch covers 40+ CPU and GPU generations

Scroll horizontally to explore →

Kernel familyx86ArmOthersNVIDIAAMDApple
HaswellSkylakeIce LakeSapphireGraniteSierraMilanGenoaTurinDiamondNEONSVESVE2SMERVVLoongArchPowerWASM SIMDWASM RelaxedAmpereAdaHopperBlackwellBlackwell RTXCDNA 4CDNA 5Metal 9Metal 10
NumKong
Vector Products dedicated dedicated dedicated compatible compatible dedicated compatible dedicated compatible dedicated dedicated dedicated compatible compatible dedicated dedicated dedicated dedicated dedicated compatible compatible compatible compatible compatible compatible compatible compatible compatible
Matrix Products dedicated dedicated dedicated dedicated dedicated dedicated compatible dedicated compatible dedicated dedicated compatible compatible dedicated dedicated dedicated dedicated dedicated dedicated dedicated compatible dedicated dedicated dedicated dedicated dedicated dedicated dedicated
Dense Attention dedicated dedicated dedicated dedicated compatible compatible compatible dedicated compatible dedicated dedicated compatible compatible dedicated dedicated fallback fallback fallback dedicated dedicated compatible dedicated dedicated dedicated dedicated dedicated dedicated dedicated
Late Interaction dedicated compatible dedicated dedicated compatible compatible compatible dedicated compatible compatible dedicated compatible compatible dedicated fallback fallback fallback fallback dedicated unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable
Geodesic Metrics dedicated dedicated compatible compatible compatible compatible compatible compatible compatible compatible dedicated compatible compatible compatible dedicated fallback fallback fallback dedicated dedicated compatible compatible compatible compatible unavailable unavailable unavailable unavailable
StringZilla
Hashes & Overlaps dedicated dedicated dedicated compatible compatible compatible compatible compatible compatible compatible dedicated dedicated dedicated compatible dedicated dedicated dedicated dedicated dedicated dedicated compatible compatible dedicated compatible dedicated compatible dedicated compatible
Unicode Matching dedicated compatible dedicated compatible compatible compatible compatible compatible compatible compatible dedicated compatible dedicated compatible dedicated dedicated dedicated dedicated compatible dedicated compatible compatible compatible compatible dedicated compatible dedicated compatible
Edit Distances dedicated dedicated dedicated compatible compatible compatible compatible compatible compatible compatible dedicated compatible compatible compatible fallback fallback fallback fallback fallback dedicated compatible compatible dedicated compatible dedicated compatible dedicated compatible
Regex & Lookarounds dedicated compatible dedicated compatible compatible compatible compatible compatible compatible compatible dedicated compatible compatible compatible fallback fallback fallback fallback fallback dedicated compatible compatible compatible compatible dedicated compatible dedicated compatible
JSONPath & XPath dedicated compatible dedicated compatible compatible compatible compatible compatible compatible compatible dedicated compatible dedicated compatible dedicated dedicated dedicated dedicated compatible dedicated compatible compatible compatible compatible dedicated compatible dedicated compatible
ForkUnion
Extended Atomics fallback fallback fallback fallback fallback dedicated fallback fallback fallback dedicated fallback dedicated dedicated dedicated dedicated fallback fallback dedicated compatible unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable
SmashTable
Collections dedicated dedicated dedicated compatible compatible compatible compatible compatible compatible compatible dedicated dedicated compatible compatible dedicated fallback fallback dedicated compatible unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable unavailable
  • Dedicated path for at least one operation or type
  • Reuses a compatible implementation
  • Portable fallback
  • Unavailable
A selection from NumKong v8, StringZilla v6, ForkUnion v4 and SmashTable v1. Columns group representative platform generations; optional extensions are checked at runtime.

Sources NumKong dispatch lists · StringZilla dispatch lists · ForkUnion atomics · SmashTable row kits

04 · Data movement

Linking jemalloc is not enough.

The fastest byte is the one that never moves.

When a profile shows malloc, swapping in jemalloc or mimalloc is the right first move, and for allocation-heavy services it pays. Rewriting the hot loop is the right second. Both act on the compute third of the profile.

The other two thirds are memcpy, page faults, cross-socket stalls and waiting, and a faster allocator only makes the next copy cheaper to start. We design the path so the bytes stop moving: io_uring and SPDK read into registered buffers, threads and memory stay on one NUMA node, and pinned buffers or GPUDirect Storage land drive reads in VRAM without a staging copy. A path this direct also removes the safety nets that catch mistakes, which is where testing has to change.

Fig. 4.1Two thirds of a typical first profile is moving and waiting for bytes

31%
11%
9%
8%
9%
32%
  • memcpy 31%
  • malloc / free 11%
  • page faults 9%
  • cross-socket stalls 8%
  • sync 9%
  • compute 32%
Illustrative shares, the pattern we meet most often: two thirds of the time is spent moving, allocating and waiting for bytes.

Fig. 4.2Each path to the drive skips one more stop

Scroll horizontally to explore →

Every layer between the application and the drive is another copy, lock or context switch. io_uring with O_DIRECT stops at the block layer. GPUDirect Storage skips host memory, not the kernel: the drive DMAs reads into VRAM. SPDK skips the kernel, not host memory.

Fig. 4.3Four of six stages between NVMe and a GPU need not exist

The same work twice. On top, the defaults: buffered reads, heap copies, threads on the wrong socket and a staging copy per transfer. Below, the path we build, with GPUDirect Storage landing reads in VRAM and three shards in flight at once. Without it, one pinned copy from host to VRAM stays.
05 · Deep testing

Rewriting in Rust is not enough.

We test at nanosecond resolution and petabyte scale.

Memory safety is worth the rewrite: a borrow checker retires a whole class of crashes and exploits, and for most services that is the class that pages someone at night. It is the right floor.

It says nothing about the bugs that survive it. A safe program can still leave a graph region no search reaches, accumulate numerical error, publish half a commit, or wrap an address past 2⁶⁴ and keep running. Each needs its own proof: audit reachability from landmarks, check every kernel against extended-precision references, model-check rings and commits in Spin, and schedule with miniature index types to hit every boundary. Those races are decided in nanoseconds, six orders below where a cluster test suite looks.

Fig. 5.1Four failure modes a borrow checker cannot see

Connected nodes, unreachable results

Deleting a bridge can leave valid nodes unreachable. Average recall can hide the lost neighborhood.

Audit connectivityAudit reachability after every graph refinement, including deletions and merges.

Small errors, long-term drift

Small rounding errors accumulate over long sequences. Wider sums keep that drift within bounds.

Bound numerical errorCompare every numeric type with extended-precision references and enforce ULP bounds.

Safe threads, unsafe schedules

Memory-safe threads can still publish the wrong result. The order of operations decides correctness.

Explore every interleavingModel-check protocol interleavings in Spin and GenMC, beyond the schedules ordinary tests encounter.

2⁶⁴ is smaller than you think

Valid operands can overflow an address. A petabyte offset times a wide stride reaches beyond 64 bits.

Check arithmetic boundariesCheck arithmetic at the boundary and return an explicit error, without allocating a petabyte.

Fig. 5.2Six orders of magnitude between two definitions of “correct”

06 · One framework

Speed, scale, portability: pick three.

The world is increasingly multimodal… one tastefully crafted framework is much more pleasant than buying from 10 different vendors.

Fig. 6.1Where four engines stop

Building this far down is rare, and the next section says why we do it anyway.

Engine Speed Parallel algorithms One writer < Many readers < GPU writersScale External-memory algorithms RAM < One drive < Many drivesPortability Bindings and packaging Few languages < Many < Preinstalled
Faiss

Writers and GPU indexes need a lock

On-disk IVF, apart from GPU indexes

C++ and Python bindings, plus a thin C API

RocksDB

Parallel writes, compaction on the CPU

Built for flash, db_paths spans drives

C++, C and Java in tree, others third-party

SQLite

Only one writer at any instant, and no GPUs

One file per database, up to 281 TB in size

Self-contained C, in every phone and Mac

Unum

CPUs and GPUs from NVIDIA, AMD and Apple

RAM, VRAM and NVMe, two-phase commits

14 languages over one C ABI, not preinstalled

Bars count rungs reached, not benchmark scores. Only SQLite is preinstalled. Only Unum stays off the bottom rung on all three.

Sources Faiss on the GPU · Faiss threads · Faiss beyond RAM · Faiss README · RocksDB README · RocksDB compaction · RocksDB thread pool · RocksDB options.h · RocksDB bindings · SQLite self-contained · SQLite most deployed · SQLite limits · When to use SQLite

Talk is cheap.
Show me the code.

Linus Torvalds

Fig. 6.2Same calls in every language, wherever the data lives

Python

from usearch import Arena, DenseIndex

index = DenseIndex.init_ram(768)
index.insert(keys, vectors)
arena = Arena()
matches = index.search(queries, 10, arena)

Rust

use usearch::*;

let index = DenseIndex::init_ram(&DenseOptions { dimensions: 768, ..Default::default() }, &[])?;
index.insert(&keys, &rows(&vectors, 768)?)?;
let mut arena = Arena::new()?;
let matches = index.search(&rows(&queries, 768)?, 10, &mut arena)?;

JavaScript

const usearch = require('usearch');

const index = usearch.DenseIndex.initRam({ dimensions: 768 });
index.insert(keys, vectors);
const arena = new usearch.Arena();
const matches = index.search(queries, 10, arena);

Swift

import USearch

let index = try DenseIndex.initRam(DenseOptions(dimensions: 768))
try index.insert(keys: keys, vectors: vectors)
let arena = try Arena()
let matches = try index.search(queries, wanted: 10, arena: arena)
Four bindings, the same native library. Follow the C link to explore the interface underneath.

A very small company
with a Big Tech habit.

Google and Meta build their own engines because they have to. We build ours because we can’t stop.

The symptoms so far: four engines and four libraries.
We’ve stopped pretending we can quit.

Problem GoogleMetaUnum
Networking gRPCThriftUCall
See all layers

That’s why you may already be running Unum without knowing it, through the databases that embed it. Some government agencies, frontier AI labs and search companies use it directly. Every engine above is one shared library away.

  • Government agencies

    Petabyte-scale search on hardware they own

  • Frontier AI labs

    Retrieval and data pipelines at GPU speed

  • Search companies

    Billions of vectors, one box before a cluster

Built with Unum building blocks

Open source

Best of all — it’s all under Apache 2.0. Free for commercial use, built with love, so the world can build its AI infrastructure on Unum.

GitHub Documentation Talk to us

From our blog

Long reads, measured on real hardware

Benchmarks, kernels and the reasoning behind them.

Shell attractor with a wide aperture

Apr 20, 2026IO · AI

FP8 Search & KV-Caching in USearch

GPUs moved to FP8. CPUs didn't. 200'000 lines of SIMD kernels later, USearch bridges both worlds — native Float8 Vector Search and KV Caching for the upcoming Arm-based NVIDIA Vera racks, Intel Xeons, open-source RISC-V chips, IBM Mainframes, Chinese LoongArch, and even WebAssembly in the browser — for higher throughput at 99% recall and half the memory cost

Chaotic attractor: an open vortex of filaments

Nov 7, 2023IO · AI

USearch: 10x - 100x Faster than Meta's FAISS

Scaling Retrieval Augmented Generation with the USearch vector search engine on Intel Sapphire Rapids CPUs on Gcore, outperforming Meta's FAISS library by 10x - 100x on a scale of 100M to 1B vectors.

Carved interlace: a vaulted knot

Jun 8, 2023IO · News

Making the Edge Efficient with Gcore and Intel

Partnering with Gcore and Intel to deploy the world most efficient data-processing infrastructure at the edge, powered by Unum assembly-optimized engines.