<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nvme on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/nvme/</link><description>Recent content in Nvme on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 22 Jun 2026 12:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/nvme/index.xml" rel="self" type="application/rss+xml"/><item><title>Storage in the AI era (1/4): the state of the art</title><link>https://blog.lo0.es/en/posts/ai-era-storage-state-of-the-art/</link><pubDate>Mon, 22 Jun 2026 12:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/ai-era-storage-state-of-the-art/</guid><description>&lt;p>Public conversation about AI infrastructure almost always revolves around the GPU: how many FLOPs, how much HBM, how many watts. But anyone who designs or runs an &lt;em>AI factory&lt;/em> knows the bottleneck has moved. A Blackwell GPU sitting idle waiting for data costs exactly the same as a Blackwell GPU doing work; what makes the difference is the subsystem feeding it. This first article in the series maps the state of the art in AI storage as of mid-2026: the memory and storage hierarchy, the media technologies (NAND, NVMe, CXL), the parallel file systems that dominate GPU clusters and the new inference stack that has turned the SSD into a component of the memory hierarchy.&lt;/p>
&lt;p>The three articles that follow go deeper into the three properties that matter to an architect once that storage reaches production: &lt;a href="https://blog.lo0.es/en/posts/ai-era-storage-performance/">performance&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/storage-ai-era-security/">security&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/storage-ai-era-availability/">availability&lt;/a>.&lt;/p>
&lt;h2 id="the-underlying-problem-the-memory-wall">The underlying problem: the memory wall&lt;/h2>
&lt;p>A modern GPU is, above all, a machine for moving data. Compute itself is almost never the limit; the limit is the bandwidth feeding the functional units. The hierarchy that runs from GPU registers down to NVMe spans six orders of magnitude in latency and several in bandwidth. Registers are on the order of a million times faster than an NVMe access, and in between sit on-chip SRAM, HBM, host DRAM and, finally, persistent storage.&lt;/p>
&lt;p>The practical consequence is well known: in many training workloads GPUs run at 30-50 % of their theoretical FLOPs utilisation because they spend a significant fraction of their time waiting for data. This is the &lt;em>memory wall&lt;/em>. Its most useful quantitative formulation is arithmetic intensity, the ratio of operations to bytes moved:&lt;/p>
$$I = \frac{\text{FLOPs}}{\text{bytes}}$$
&lt;p>When a workload&amp;rsquo;s intensity falls below the hardware&amp;rsquo;s break-even point (the &lt;em>ridge point&lt;/em> of the &lt;em>roofline&lt;/em> model), performance is limited by bandwidth rather than compute. The industry&amp;rsquo;s race towards HBM, towards NVLink and, at the layer that concerns us, towards 28 GB/s NVMe and 800 Gb/s networks, is at bottom a war against that wall.&lt;/p>
&lt;p>The problem gets worse because compute has grown much faster than memory bandwidth. Each GPU generation multiplies FLOPs more generously than the TB/s of memory that feed them, so the &lt;em>ridge point&lt;/em> shifts towards ever higher arithmetic intensities: more workloads fall on the bandwidth-limited side. This is the structural reason storage and memory have moved to the foreground. It is not that storage has improved less (it has improved enormously), but that the GPU demands more of it every year. An architect who designs with FLOPs alone in mind will build systems that spend half their time waiting.&lt;/p>
&lt;p>It pays to keep the whole pyramid in view when we talk about &amp;ldquo;storage&amp;rdquo; in AI, because design decisions at one level constrain the others:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Level&lt;/th>
&lt;th>Technology&lt;/th>
&lt;th>Typical bandwidth&lt;/th>
&lt;th>Latency&lt;/th>
&lt;th>Capacity per device&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>On-package&lt;/td>
&lt;td>HBM3e / HBM4&lt;/td>
&lt;td>1.2-3.3 TB/s per stack&lt;/td>
&lt;td>ns&lt;/td>
&lt;td>36-64 GB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Host memory&lt;/td>
&lt;td>DDR5 / CXL&lt;/td>
&lt;td>0.3-0.5 TB/s&lt;/td>
&lt;td>~100 ns&lt;/td>
&lt;td>TB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hot flash&lt;/td>
&lt;td>NVMe Gen5/Gen6&lt;/td>
&lt;td>14-28 GB/s&lt;/td>
&lt;td>10-100 µs&lt;/td>
&lt;td>4-256 TB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Capacity&lt;/td>
&lt;td>Nearline QLC / HDD&lt;/td>
&lt;td>1-7 GB/s&lt;/td>
&lt;td>ms&lt;/td>
&lt;td>30-245 TB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Archive&lt;/td>
&lt;td>Object / tape&lt;/td>
&lt;td>variable&lt;/td>
&lt;td>s&lt;/td>
&lt;td>EB (aggregate)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The state of the art in 2026 consists, to a large extent, in how the boundaries between these levels blur: HBM spills over into DRAM, DRAM into CXL, and the inference KV-cache into NVMe. Storage has stopped being the basement of the hierarchy and has become part of it.&lt;/p>
&lt;h2 id="hbm4-the-ceiling-rises-but-it-stays-expensive">HBM4: the ceiling rises, but it stays expensive&lt;/h2>
&lt;p>At the top sits high-bandwidth memory stacked next to the GPU. In April 2025 JEDEC published the HBM4 standard (JESD270-4), which doubles the interface to 2048 bits per &lt;em>stack&lt;/em> against HBM3e&amp;rsquo;s 1024 bits, reaches up to 8 Gb/s per pin and lands around 2 TB/s typical with peaks up to 3.3 TB/s per &lt;em>stack&lt;/em>. It supports configurations of 4 to 16 layers with 24 or 32 Gb dies, up to 64 GB per cube. HBM3e, the generation that dominates accelerators in production in mid-2026, sits near 1.2 TB/s and a 36 GB maximum.&lt;/p>
&lt;p>The figure that matters to an architect is not peak bandwidth but scarcity. Micron has essentially sold out its entire HBM production through 2026, and capacity expansion is not expected before late 2027-2028. That constraint is what pushes the load downwards through the hierarchy: if you cannot add HBM, you have to learn to spill gracefully into DRAM, CXL and flash. Much of the recent innovation comes from there.&lt;/p>
&lt;h2 id="nand-and-ssd-capacity-explodes-the-interface-widens">NAND and SSD: capacity explodes, the interface widens&lt;/h2>
&lt;p>The flash layer is where AI&amp;rsquo;s pressure on the market shows most. Two vectors at once: capacity and interface.&lt;/p>
&lt;p>On &lt;strong>capacity&lt;/strong>, 2025-2026 has been the year of the race to 245 TB. The Solidigm D5-P5336 reached 122 TB (PCIe 4.0) and became the highest-capacity SSD available, on sale for around 12,400 USD; Solidigm has confirmed models of 245 TB or more for late 2026. Micron introduced the 6600 ION with 245 TB in E3.L form factor. By mid-2026 there are at least eight 245 TB SSDs announced by SanDisk, Samsung, Kioxia, Micron, SK hynix and others, all built on high-density QLC NAND (SK hynix is already producing 321-layer QLC) to satisfy hyperscaler demand. Enterprise QLC is consolidating as a replacement for nearline HDD, whose supply lags well behind demand and whose &lt;em>lead times&lt;/em> have stretched.&lt;/p>
&lt;p>QLC deserves a qualification that sometimes gets lost in the excitement over capacity: write endurance. QLC NAND stores four bits per cell, which multiplies density but reduces the number of erase cycles it tolerates compared with TLC. For AI datasets written once and read many times, the typical case of a &lt;em>training set&lt;/em>, this is irrelevant and QLC is the right choice. For workloads with intensive, constant writes, certain &lt;em>checkpoints&lt;/em> or a fast-rotating KV-cache, wear has to be watched and TLC often reserved. Knowing the write pattern of each workload is what allows the right medium to be assigned without overpaying or under-wearing.&lt;/p>
&lt;p>On &lt;strong>interface&lt;/strong>, PCIe Gen6 has entered datacenter production. The Micron 9650 was the first mass-produced PCIe Gen6 datacenter SSD (February 2026), with 28 GB/s of &lt;em>throughput&lt;/em>, roughly double Gen5. Controllers are keeping pace: the Silicon Motion SM8466 advertises 28 GB/s sequential and 7 million random IOPS; FADU&amp;rsquo;s Gen6 part (&amp;ldquo;Lhotse&amp;rdquo;) targets 28.5 GB/s read, 6.9 million IOPS, NVMe 2.2 and native SR-IOV with 128 virtual functions. The adoption path is clear: Gen6 arrives first in AI, HPC and the datacenter, and only afterwards, if at all, in the consumer PC.&lt;/p>
&lt;p>Over the network, &lt;strong>NVMe-oF&lt;/strong> splits into two worlds. NVMe/TCP leads &lt;em>greenfield&lt;/em> array-to-host deployments for its operational simplicity, with latencies of 100-200 µs. NVMe over RDMA (RoCEv2, iWARP) remains the gold standard for low latency (10-20 µs) where a lossless &lt;em>fabric&lt;/em> already exists, such as the ones AI clusters deploy. Ethernet at 25-100 Gb/s is steadily eroding Fibre Channel&amp;rsquo;s share of storage traffic.&lt;/p>
&lt;p>The choice between TCP and RDMA is not an aesthetic preference. NVMe/TCP runs over any existing Ethernet network and greatly simplifies operations, at the cost of higher latency and of host CPU consumption that, under heavy load, competes with compute. NVMe/RoCE demands a lossless &lt;em>fabric&lt;/em>, with priority flow control and &lt;em>congestion control&lt;/em> properly tuned, plus capable NICs, but it delivers the latency that latency-sensitive AI workloads need and offloads processing to the NIC. In an AI cluster that already deploys InfiniBand or RoCE for GPU-to-GPU traffic, reusing that &lt;em>fabric&lt;/em> for storage is the natural decision; in a mixed enterprise infrastructure, NVMe/TCP usually wins on operability.&lt;/p>
&lt;h2 id="cxl-from-powerpoint-to-production">CXL: from PowerPoint to production&lt;/h2>
&lt;p>Compute Express Link spent years as the eternal promise. By early 2026 it has finally reached &lt;em>mainstream&lt;/em> adoption in production platforms with CXL 3.0/3.1, aligned with PCIe 6.1. The hardware support is there: Intel Xeon 6 (Granite Rapids and later) includes native CXL 3.0 in the CPU, and AMD EPYC Turin is a target platform. CXL 3.0 multi-host pooling &lt;em>switches&lt;/em> are already running at some colocation providers.&lt;/p>
&lt;p>The use case that has moved from theory to numbers is memory &lt;em>tiering&lt;/em>: keeping hot data in GPU HBM and pushing cold data to a shared CXL DRAM &lt;em>pool&lt;/em>. Supply chain vendors (Astera Labs, MemVerge, XConn) report notable gains from offloading the inference KV-cache to CXL memory compared with SSD or RDMA-based solutions. The specific figures deserve caution, since they come largely from the manufacturers themselves, but the direction is real: CXL has become a usable disaggregated memory layer, not a laboratory experiment. &lt;em>Tiering&lt;/em> support in the Linux kernel (6.1 onwards) is maturing, although getting value from it still requires NUMA-aware applications.&lt;/p>
&lt;h2 id="parallel-file-systems-the-gpu-battlefield">Parallel file systems: the GPU battlefield&lt;/h2>
&lt;p>If the media layer is where silicon vendors compete, the parallel file system layer is where platform vendors compete, and it is the one an AI architect touches daily. The market has reshuffled in a few years.&lt;/p>
&lt;p>&lt;strong>WEKA&lt;/strong> has probably been the most talked-about case. Its system (WekaFS, now repackaged as NeuralMesh) bypasses the Linux kernel by running as an RTOS in user space, uses RDMA instead of TCP/IP and distributes metadata through consistent &lt;em>hashing&lt;/em>. Published figures cite latencies of 100-200 µs against more than 1000 µs for traditional stacks, and metadata performance that doubles Lustre&amp;rsquo;s. In 2026 it launched its NeuralMesh AI Data Platform on the NVIDIA reference design, with an &amp;ldquo;Augmented Memory Grid&amp;rdquo; aimed at context memory for agentic AI.&lt;/p>
&lt;p>&lt;strong>VAST Data&lt;/strong> has bet on a different architecture, DASE (&lt;em>Disaggregated Shared-Everything&lt;/em>), a single all-flash &lt;em>tier&lt;/em> on which it has built what it calls an &amp;ldquo;AI OS&amp;rdquo;: a stack with a database, a data engine, &lt;em>InsightEngine&lt;/em> for real-time AI &lt;em>pipelines&lt;/em>, vector search and RAG, and integrated governance. Azure has adopted its system, a sign of the traction it has gained.&lt;/p>
&lt;p>&lt;strong>Lustre&lt;/strong> (DDN) remains the most widespread file system in classic supercomputing, but it is being eroded in the GPU arena by VAST and WEKA. &lt;strong>DAOS&lt;/strong> shines at the &lt;em>top end&lt;/em> of traditional HPC but barely appears in commercial AI clusters. &lt;strong>IBM Storage Scale&lt;/strong> (the former Spectrum Scale/GPFS) has repositioned itself with &lt;em>Content Awareness&lt;/em> for RAG and support for NVIDIA&amp;rsquo;s data platform, alongside a refresh of the FlashSystem range.&lt;/p>
&lt;p>The common denominator of this whole generation is alignment with NVIDIA. Platforms are certified against DGX SuperPOD and integrate with &lt;strong>GPUDirect Storage&lt;/strong>, which allows direct DMA between storage and GPU memory, skipping the CPU and the &lt;em>bounce buffer&lt;/em>. In GB200 NVL72 architectures, a liquid-cooled rack that presents 72 GPUs as a single giant GPU through NVLink, with 13.4 TB of unified GPU memory, GPUDirect Storage certification stops being an ornament and becomes a requirement.&lt;/p>
&lt;p>To place the main players side by side, it helps to summarise their architectural bets, which are genuinely different and not mere variations on a single design:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Platform&lt;/th>
&lt;th>Architecture&lt;/th>
&lt;th>Differentiator&lt;/th>
&lt;th>Fit in AI&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>WEKA NeuralMesh&lt;/td>
&lt;td>User-space RTOS, RDMA&lt;/td>
&lt;td>Very low latency, metadata distributed by hashing&lt;/td>
&lt;td>Training and agentic inference, context memory&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>VAST DataStore&lt;/td>
&lt;td>Disaggregated all-flash DASE&lt;/td>
&lt;td>Single exabyte-scale multiprotocol namespace, AI OS&lt;/td>
&lt;td>Lakehouse + RAG + inference&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>IBM Storage Scale&lt;/td>
&lt;td>Parallel (ex-GPFS)&lt;/td>
&lt;td>Content Awareness for RAG, HPC maturity&lt;/td>
&lt;td>Enterprise and HPC with unstructured data&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>DDN EXAScaler/Lustre&lt;/td>
&lt;td>Hardened Lustre&lt;/td>
&lt;td>Raw throughput per rack, massive deployments&lt;/td>
&lt;td>Supercomputing and &lt;em>AI factories&lt;/em>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Pure Storage&lt;/td>
&lt;td>All-flash with Purity&lt;/td>
&lt;td>&lt;em>Evergreen&lt;/em> operations, simplicity&lt;/td>
&lt;td>Enterprises that value operations over peak&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The choice between them is rarely decided by peak GB/s, but by workload pattern (sequential training against random inference), by the operating model and by the degree of integration required with the NVIDIA stack. A sensible architect first assesses their workload mix and only then compares numbers.&lt;/p>
&lt;h2 id="the-rack-as-the-unit-of-compute-gb200-rubin-and-bluefield-4">The rack as the unit of compute: GB200, Rubin and BlueField-4&lt;/h2>
&lt;p>The change in granularity is worth pausing on. For decades the design unit was the server; today, in AI, it is the rack. The GB200 NVL72 integrates 72 Blackwell GPUs and 36 Grace CPUs into a single 130 TB/s NVLink domain, presented to software as one logical GPU with 13.4 TB of unified memory and capable of up to 30 times the real-time inference of a trillion-parameter LLM against the previous generation. At that scale storage does not compete with internal bandwidth (it could not), but it must feed model loading and the inference KV-cache (and, where applicable, training &lt;em>checkpointing&lt;/em>) without strangling the 72 GPUs that behave as one.&lt;/p>
&lt;p>The roadmap sharpens the trend. The Rubin generation and, in particular, the Rubin CPX, a GPU specialised in long-context inference with more than a million tokens, push still more data towards the memory and storage layers. And the piece that stitches it all together is the DPU: NVIDIA&amp;rsquo;s BlueField-4 enables an &amp;ldquo;Inference Context Memory Storage&amp;rdquo; platform that turns the KV-cache into a &lt;em>pod&lt;/em>-level shared flash resource, connected over Spectrum-X Ethernet. The DPU offloads storage and security data movement from the CPU, and is becoming the true storage controller of the AI node. For the architect, this means storage design no longer ends at the array: it includes the NIC, the DPU and the &lt;em>fabric&lt;/em>.&lt;/p>
&lt;h2 id="the-inference-stack-when-the-ssd-joins-the-memory-hierarchy">The inference stack: when the SSD joins the memory hierarchy&lt;/h2>
&lt;p>The most important conceptual change of the past two years, and the one that best summarises the state of the art, is this: &lt;strong>flash storage has become part of the inference memory hierarchy&lt;/strong>. The cause is context windows. As models handle hundreds of thousands, or millions, of tokens, the KV-cache generated by the &lt;em>prefill&lt;/em> phase overflows HBM. That overflowing KV-cache drops first into host DRAM and then to the NVMe SSD.&lt;/p>
&lt;p>NVIDIA has standardised this pattern. Its Dynamo orchestration layer operates across the whole hierarchy, HBM → CPU DRAM → NVMe → network storage, with a KV-cache &lt;em>offload&lt;/em> engine and a transfer library (NIXL) for sharing cache between nodes. In January 2026 it standardised KV-cache &lt;em>offload&lt;/em> to NVMe SSD, and it has introduced an &amp;ldquo;Inference Context Memory Storage&amp;rdquo; platform based on BlueField-4 DPUs that turns the KV-cache into a high-bandwidth shared resource at &lt;em>pod&lt;/em> level. Solidigm and other SSD makers have aligned their message around the same idea: long-context inference is, in part, a flash storage problem.&lt;/p>
&lt;p>The design consequences are concrete. A 2026 inference server carries between 8 and 32 SSDs, with the figure expected to reach 32 within a couple of years, and a random access pattern, against the sequential pattern and the dozen or so drives of a training server. The ratio of inference to training servers can reach 50 to 1. The centre of gravity of storage investment is shifting towards inference.&lt;/p>
&lt;h2 id="anatomy-of-storage-in-an-inference-factory">Anatomy of storage in an inference factory&lt;/h2>
&lt;p>It is worth pausing here, because an &lt;em>inference AI factory&lt;/em>, a system designed to serve models in production rather than train them, has a storage profile of its own, different from the training cluster that dominates the literature. While training is a batch job that tolerates stoppages and is measured in weeks, inference is a continuous service, latency-sensitive and bound by an SLA: every millisecond and every failure shows up at the client. Its storage is organised into four planes that are best designed separately.&lt;/p>
&lt;p>The first plane is the &lt;strong>model registry&lt;/strong>. The weights of the models being served, which may number in the dozens, with versions, quantised variants and LoRA &lt;em>adapters&lt;/em>, live in object storage or a shared file system, and are loaded into GPU HBM when a model is activated. The critical requirement here is not sustained &lt;em>throughput&lt;/em> but &lt;strong>load time&lt;/strong>: when a new replica has to start or a GPU has to switch models, reading tens or hundreds of GB of weights determines the &lt;em>cold start&lt;/em>. A slow registry translates into sluggish autoscaling and GPUs that take their time entering service, exactly when demand rises.&lt;/p>
&lt;p>The second plane is the &lt;strong>KV-cache hierarchy&lt;/strong>, the heart of modern inference performance. As we saw, the KV-cache overflows HBM and drops to DRAM, CXL and NVMe. In an inference factory this is not a marginal detail: it is a first-class storage layer, with its own sizing, its random access pattern and critical latency, and a lifetime measured in seconds. NVIDIA&amp;rsquo;s standardisation of KV-cache &lt;em>offload&lt;/em> to NVMe SSD and the ICMS platform on BlueField-4 exist precisely for this: to allow long contexts and cache reuse across requests (and across nodes) without paying the price of recomputation or of adding HBM, which is scarce and expensive.&lt;/p>
&lt;p>The third plane is the &lt;strong>knowledge store for RAG&lt;/strong>: the vector databases (Milvus, Weaviate, Pinecone, or S3 Vectors) and the source documents the system retrieves to enrich its answers. The pattern here is read-intensive, with similarity searches over indexes that can run to TB and are best kept on low-latency flash. The availability and freshness of this store determine answer quality as much as the model itself, and updating it, reindexing and taking in new documents, is a constant write flow the design has to account for.&lt;/p>
&lt;p>The fourth plane is &lt;strong>observability and logging&lt;/strong>: traces, request and response &lt;em>logs&lt;/em>, metrics and, where regulation demands it, the auditable archive of interactions. It is a high-volume append-only write flow that usually ends up in object storage, and one that a GPU-centric design tends to forget about until it saturates something.&lt;/p>
&lt;p>The conclusion for anyone building an inference factory is that its storage looks nothing like a rescaled training cluster. It is sized by model load time, by KV-cache capacity and latency, by vector search performance and by telemetry volume, with a cross-cutting imperative of continuous service under SLA. Training, where it exists, is the occasional guest; inference is the permanent resident.&lt;/p>
&lt;h2 id="the-other-end-object-lakehouse-and-vectors">The other end: object, lakehouse and vectors&lt;/h2>
&lt;p>Not everything is hot flash. The training database and the system of record live in object storage. The novelty of 2025-2026 is convergence with open table formats: Apache Iceberg, Delta Lake and Hudi bring ACID transactions, &lt;em>time travel&lt;/em> and schema evolution on top of cheap object storage. AWS has launched S3 Tables (managed Iceberg, with faster queries) and S3 Vectors (native vector storage with savings of up to 90 % for AI workloads). Vector databases, Pinecone, Milvus, Weaviate, integrate with data lakes to feed RAG, and columnar formats such as Parquet, together with Lance for multimodal data, are consolidating as the substrate of the &lt;em>lakehouse&lt;/em>.&lt;/p>
&lt;p>&lt;strong>Computation near the data&lt;/strong> (&lt;em>computational storage&lt;/em>) remains active R&amp;amp;D rather than mass deployment. The corresponding NVMe specifications have been published since late 2023, with eBPF as the execution environment for downloadable functions, but real adoption is still marginal. The idea, running filtering, decompression or search directly on the device so the data never travels to the CPU, is seductive for AI workloads that read enormous datasets at low arithmetic intensity, but the programming model and the lack of tooling standardisation hold deployment back. It is a technology to watch, not yet one to put into production.&lt;/p>
&lt;h2 id="the-data-lifecycle-tiering-as-an-architectural-decision">The data lifecycle: tiering as an architectural decision&lt;/h2>
&lt;p>Taking in the whole picture, it is clear that no data lives in a single place for its entire lifecycle. A dataset arrives raw in the object &lt;em>data lake&lt;/em>, is transformed and catalogued in an open table format (Iceberg, Delta), is promoted to the hot flash layer of the parallel file system to feed training, generates &lt;em>checkpoints&lt;/em> that live for days on NVMe, and finally, together with the resulting models, is archived to cold object storage or tape. Automatic &lt;em>tiering&lt;/em> between these layers has gone from a cost optimisation to a first-order architectural decision, especially amid NAND and HBM scarcity.&lt;/p>
&lt;p>The practical rule that emerges is to place every byte in the cheapest &lt;em>tier&lt;/em> that satisfies its latency and bandwidth requirement at that moment, and to automate the transitions. Hot flash (NVMe Gen5/Gen6) absorbs the training &lt;em>working set&lt;/em> and the inference KV-cache; capacity QLC replaces nearline HDD for datasets that are read sequentially; object storage is the durable, versioned system of record; and tape is resurging as an active archive at exabyte scale to fight the cost of flash. Designing those boundaries, and measuring how much data crosses each one, is now part of the AI storage architect&amp;rsquo;s job, not the administrator&amp;rsquo;s.&lt;/p>
&lt;h2 id="the-market-context-a-supply-supercrisis">The market context: a supply supercrisis&lt;/h2>
&lt;p>None of this happens in an economic vacuum. Storage demand from AI servers is 8 to 10 times that of a traditional server, and it is growing above 20 % a year, while global NAND supply grows only 15-17 %. The result, in the words of several analysts, is a memory &amp;ldquo;supercrisis&amp;rdquo;: high double-digit contract price rises for DRAM and NAND in 2026, stretched &lt;em>lead times&lt;/em> and collateral effects on smartphones and PCs. For an architect, this turns capacity efficiency (QLC, compression, &lt;em>erasure coding&lt;/em>, &lt;em>tiering&lt;/em>) into a first-order cost lever rather than an implementation detail.&lt;/p>
&lt;h2 id="what-this-changes-for-the-architect">What this changes for the architect&lt;/h2>
&lt;p>If the state of the art had to be distilled into a handful of practical implications, these would be them. First, storage is designed by workload pattern, not by capacity: a training server and an inference server have opposite requirements, sequential against random, few drives against many, and mixing them in a single template is a common mistake. Second, the limit almost never sits in the medium any more but in the full chain of medium, NVMe, DPU, NIC, fabric and file system; optimising one link while leaving the rest untouched does not move the needle. Third, supply scarcity turns capacity efficiency (QLC, compression, &lt;em>erasure coding&lt;/em>, &lt;em>tiering&lt;/em>) into a cost lever comparable to buying the drives themselves. And fourth, the boundary between memory and storage has dissolved: thinking in terms of &amp;ldquo;RAM on one side, disk on the other&amp;rdquo; no longer describes a modern AI system, where HBM, DRAM, CXL and NVMe form a software-managed continuum.&lt;/p>
&lt;h2 id="takeaways">Takeaways&lt;/h2>
&lt;p>The state of the art in AI storage in 2026 comes down to one idea: the hierarchy has become continuous. HBM spills into DRAM, DRAM is disaggregated over CXL, the inference KV-cache drops all the way to NVMe, and the parallel file system orchestrates the whole so the GPU never waits. Media technologies (HBM4, 245 TB QLC, NVMe Gen6) raise the ceilings, but supply scarcity turns efficiency into a design constraint. And the software battlefield, WEKA, VAST, IBM, DDN, is fought over a single metric: keeping the GPUs fed.&lt;/p>
&lt;p>With this map on the table, the three articles that follow go into the detail of the properties that decide whether a storage architecture works in production.&lt;/p>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/ai-era-storage-performance/">Storage in the AI era (2/4): performance&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/storage-ai-era-security/">Storage in the AI era (3/4): security&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/storage-ai-era-availability/">Storage in the AI era (4/4): availability&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>FADU, &lt;em>From Training to Inference: FADU at CFMS 2026&lt;/em> — &lt;a href="https://blogs.fadu.io/ai-inference-ssd-data-centers/">https://blogs.fadu.io/ai-inference-ssd-data-centers/&lt;/a>&lt;/li>
&lt;li>Avnet, &lt;em>Riding the AI Supercycle: 2026 Memory &amp;amp; Storage Market&lt;/em> — &lt;a href="https://www.avnet.com/integrated/resources/article/2026-memory-shortage-ai-supercycle/">https://www.avnet.com/integrated/resources/article/2026-memory-shortage-ai-supercycle/&lt;/a>&lt;/li>
&lt;li>JEDEC, &lt;em>JESD270-4 HBM4 Standard&lt;/em> — &lt;a href="https://www.jedec.org/news/pressreleases/jedec%C2%AE-and-industry-leaders-collaborate-release-jesd270-4-hbm4-standard-advancing">https://www.jedec.org/news/pressreleases/jedec%C2%AE-and-industry-leaders-collaborate-release-jesd270-4-hbm4-standard-advancing&lt;/a>&lt;/li>
&lt;li>Tom&amp;rsquo;s Hardware, &lt;em>JEDEC finalizes HBM4 memory standard&lt;/em> — &lt;a href="https://www.tomshardware.com/pc-components/ram/jedec-finalizes-hbm4-memory-standard-with-major-bandwidth-and-efficiency-upgrades">https://www.tomshardware.com/pc-components/ram/jedec-finalizes-hbm4-memory-standard-with-major-bandwidth-and-efficiency-upgrades&lt;/a>&lt;/li>
&lt;li>StorageNewsletter, &lt;em>Micron 9650 PCIe Gen6 data center SSDs in mass production&lt;/em> — &lt;a href="https://www.storagenewsletter.com/2026/02/19/micron-9650-pcie-gen6-data-center-ssds-in-mass-production/">https://www.storagenewsletter.com/2026/02/19/micron-9650-pcie-gen6-data-center-ssds-in-mass-production/&lt;/a>&lt;/li>
&lt;li>Tom&amp;rsquo;s Hardware, &lt;em>Solidigm reveals 122TB SSD&lt;/em> — &lt;a href="https://www.tomshardware.com/pc-components/ssds/solidigm-reveals-122tb-ssd-the-worlds-highest-capacity-drive-for-ai-workloads-d5-p5336-offers-unlimited-write-durability">https://www.tomshardware.com/pc-components/ssds/solidigm-reveals-122tb-ssd-the-worlds-highest-capacity-drive-for-ai-workloads-d5-p5336-offers-unlimited-write-durability&lt;/a>&lt;/li>
&lt;li>TechRadar, &lt;em>Solidigm confirms 245TB SSDs before end of 2026&lt;/em> — &lt;a href="https://www.techradar.com/pro/solidigm-confirms-245-tb-ssds-set-to-launch-before-end-of-2026">https://www.techradar.com/pro/solidigm-confirms-245-tb-ssds-set-to-launch-before-end-of-2026&lt;/a>&lt;/li>
&lt;li>KAD, &lt;em>CXL in 2026: How Memory Pooling is Reshaping Data Centers&lt;/em> — &lt;a href="https://www.kad8.com/hardware/cxl-in-2026-how-memory-pooling-is-reshaping-data-centers/">https://www.kad8.com/hardware/cxl-in-2026-how-memory-pooling-is-reshaping-data-centers/&lt;/a>&lt;/li>
&lt;li>Blocks &amp;amp; Files, &lt;em>Parallel filesystem definitions&lt;/em> — &lt;a href="https://blocksandfiles.com/2025/11/26/parallel-filesystem-definitions-and-powerscale/">https://blocksandfiles.com/2025/11/26/parallel-filesystem-definitions-and-powerscale/&lt;/a>&lt;/li>
&lt;li>NAND Research, &lt;em>WEKA NeuralMesh AIDP &amp;amp; STX integration&lt;/em> — &lt;a href="https://nand-research.com/weka-neuralmesh-aidp-stx-integration-gtc-2026/">https://nand-research.com/weka-neuralmesh-aidp-stx-integration-gtc-2026/&lt;/a>&lt;/li>
&lt;li>VAST Data, &lt;em>InsightEngine&lt;/em> — &lt;a href="https://www.vastdata.com/platform/insightengine">https://www.vastdata.com/platform/insightengine&lt;/a>&lt;/li>
&lt;li>NVIDIA, &lt;em>GB200 NVL72&lt;/em> — &lt;a href="https://www.nvidia.com/en-us/data-center/gb200-nvl72/">https://www.nvidia.com/en-us/data-center/gb200-nvl72/&lt;/a>&lt;/li>
&lt;li>Blocks &amp;amp; Files, &lt;em>Nvidia standardizes GPU cluster KV cache offload to NVMe SSDs&lt;/em> — &lt;a href="https://blocksandfiles.com/2026/01/06/nvidia-standardizes-gpu-cluster-kv-cache-offload-to-nvme-ssds/">https://blocksandfiles.com/2026/01/06/nvidia-standardizes-gpu-cluster-kv-cache-offload-to-nvme-ssds/&lt;/a>&lt;/li>
&lt;li>AWS, &lt;em>Building AI-Ready Data Lakes: S3 Tables, Iceberg, S3 Vectors&lt;/em> — &lt;a href="https://builder.aws.com/content/34vssNUviyG5WPv3IRiGZFKZYkn/building-ai-ready-data-lakes-amazon-s3-tables-apache-iceberg-and-s3-vectors">https://builder.aws.com/content/34vssNUviyG5WPv3IRiGZFKZYkn/building-ai-ready-data-lakes-amazon-s3-tables-apache-iceberg-and-s3-vectors&lt;/a>&lt;/li>
&lt;li>TrendForce, &lt;em>AI Server Demand to Drive Memory Contract Price Increases 2Q26&lt;/em> — &lt;a href="https://www.trendforce.com/presscenter/news/20260331-12995.html">https://www.trendforce.com/presscenter/news/20260331-12995.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>The pantry lift: from disk to HBM, or why the kitchen opens late</title><link>https://blog.lo0.es/en/posts/pantry-lift-from-disk-to-hbm-why-the-kitchen-opens-late/</link><pubDate>Sun, 07 Jun 2026 08:30:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/pantry-lift-from-disk-to-hbm-why-the-kitchen-opens-late/</guid><description>&lt;blockquote>
&lt;p>This is a trip down to the basement. The &lt;a href="https://blog.lo0.es/en/posts/nvlink-nvswitch-nccl-cable-every-token-crosses/">under the engine&lt;/a> series optimised the &lt;strong>hot path&lt;/strong>, what happens with every token once you are already serving. This post looks at the journey that comes &lt;strong>before&lt;/strong> serving: how the weights climb from disk to HBM. It is the first of a pair on the two things that happen outside the API and that almost nobody times: &lt;strong>model loading&lt;/strong> (this one) and &lt;a href="https://blog.lo0.es/en/posts/sms-cuda-streams-cuda-graphs-inference/">execution on the silicon&lt;/a> (the next one).&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Before an inference pod generates its first token, it has to &lt;strong>push the whole model into HBM&lt;/strong>. A Llama-70B in FP16 is &lt;strong>140 GB&lt;/strong> travelling along a path nobody draws: &lt;strong>disk → page cache → host buffer → PCIe → HBM&lt;/strong>. Intuition fails here: HBM is not the bottleneck, it moves 3.35 TB/s and swallows 140 GB in &lt;strong>42 ms&lt;/strong>; the bottleneck is the &lt;strong>supply chain&lt;/strong>. The Gen5 NVMe disk reads at ~14 GB/s (10 s for 140 GB); PCIe Gen5 copies host→GPU at ~50 GB/s (2.8 s); and the &lt;strong>default safetensors loader&lt;/strong>, which deserialises tensor by tensor and bounces every byte through a CPU buffer, inflates all of that up to &lt;strong>30-60 s&lt;/strong>. That time is the &lt;strong>cold start&lt;/strong>, and it is the hidden tax paid by &lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">autoscaling&lt;/a> (scale-from-zero), by &lt;a href="https://blog.lo0.es/en/posts/canary-blue-green-shadow-llm-models/">canary/blue-green&lt;/a> and by &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">disaggregated serving&lt;/a> every time a pod is born. There are three families of solution, &lt;strong>GPUDirect Storage&lt;/strong> (direct DMA disk→HBM, no bounce through the CPU), &lt;strong>fastsafetensors&lt;/strong> (4.8-7.5× over the default loader) and the &lt;strong>Run:ai Model Streamer&lt;/strong> (concurrent reads that saturate the disk), plus the simplest lever of all: &lt;strong>move fewer bytes&lt;/strong> (FP8 is half of FP16). This post explains the path, the maths, the 10 knobs, and the cruellest trap: &lt;em>&amp;ldquo;the second time it loaded fast&amp;rdquo;&lt;/em> is not your loader being good, it is the &lt;strong>page cache&lt;/strong> lying to you. On the generic 4×H100 SXM cluster.&lt;/p>
&lt;h2 id="where-you-are-the-basement-before-opening">Where you are: the basement, before opening&lt;/h2>
&lt;div class="diagram" style="max-width:560px;margin:1.2rem auto;">
&lt;svg viewBox="0 0 560 340" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The loading path: from disk to HBM, before the hot path of the token">
&lt;text x="280" y="24" text-anchor="middle" font-family="sans-serif" font-size="13" font-weight="700" fill="currentColor">The loading path · before the first token&lt;/text>
&lt;rect x="120" y="40" width="320" height="40" rx="6" fill="currentColor" fill-opacity="0.05" stroke="#888" stroke-width="1.3"/>
&lt;text x="280" y="65" text-anchor="middle" font-family="sans-serif" font-size="12" fill="currentColor">HBM · 80 GB, 3.35 TB/s — the destination, never the bottleneck&lt;/text>
&lt;rect x="120" y="86" width="320" height="40" rx="6" fill="currentColor" fill-opacity="0.05" stroke="#888" stroke-width="1.3"/>
&lt;text x="280" y="111" text-anchor="middle" font-family="sans-serif" font-size="12" fill="currentColor">PCIe Gen5 x16 · ~50 GB/s host→GPU (H2D)&lt;/text>
&lt;rect x="120" y="132" width="320" height="58" rx="6" fill="#dceede" stroke="#3c8c54" stroke-width="3"/>
&lt;text x="280" y="156" text-anchor="middle" font-family="sans-serif" font-size="12.5" font-weight="700" fill="#1f5c34">YOU ARE HERE · loader + page cache + host buffer&lt;/text>
&lt;text x="280" y="174" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="#2c6b42">deserialise, bounce through CPU or direct DMA (GDS)&lt;/text>
&lt;rect x="120" y="196" width="320" height="40" rx="6" fill="#eef3fb" stroke="#4a6fa5" stroke-width="1.4"/>
&lt;text x="280" y="221" text-anchor="middle" font-family="sans-serif" font-size="12" fill="currentColor">NVMe Gen5 · ~14 GB/s per disk — the origin&lt;/text>
&lt;rect x="120" y="248" width="320" height="40" rx="6" fill="currentColor" fill-opacity="0.05" stroke="#888" stroke-width="1.3"/>
&lt;text x="280" y="273" text-anchor="middle" font-family="sans-serif" font-size="12" fill="currentColor">Network / Ceph RGW · shared weights (slower still)&lt;/text>
&lt;text x="280" y="312" text-anchor="middle" font-family="sans-serif" font-size="11" fill="currentColor" opacity="0.75">The hot path of the token lives above; this post opens up what is below&lt;/text>
&lt;text x="280" y="330" text-anchor="middle" font-family="sans-serif" font-size="11" fill="currentColor" opacity="0.75">the journey that decides whether the kitchen opens in 10 s or in 60 s&lt;/text>
&lt;/svg>
&lt;/div>
&lt;h2 id="the-analogy-the-pantry-lift">The analogy: the pantry lift&lt;/h2>
&lt;p>Let us stay in the restaurant of the series. The &lt;a href="https://blog.lo0.es/en/posts/nvlink-nvswitch-nccl-cable-every-token-crosses/">shared table&lt;/a> was the NVSwitch, the &lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">floor next door&lt;/a> was NUMA, the &lt;a href="https://blog.lo0.es/en/posts/cpu-memory-topology-manager-rke2/">maître&lt;/a> was the kubelet. All of that describes the restaurant &lt;strong>running&lt;/strong>, with diners seated. But there is a moment no post looked at: &lt;strong>before opening&lt;/strong>, somebody has to bring the entire pantry up from the basement store to the kitchen.&lt;/p>
&lt;p>The model weights are the ingredients. They live in the &lt;strong>basement store&lt;/strong> (the disk). The kitchen, the &lt;strong>hot line&lt;/strong> where tokens are plated, is the GPU&amp;rsquo;s HBM. And between one and the other there is a &lt;strong>service lift&lt;/strong>: the path disk → host → PCIe → HBM. The kitchen cannot serve the first dish until the pantry is upstairs and in place. That restocking time is the &lt;strong>cold start&lt;/strong>.&lt;/p>
&lt;p>The intuition trap: the kitchen (HBM) is enormous and blazingly fast, it places ingredients at 3.35 TB/s. So we blame the kitchen when the restaurant opens late. But the kitchen is standing idle &lt;strong>waiting for the lift&lt;/strong>. The bottleneck is never the hot line: it is the &lt;strong>lift and the store&lt;/strong>. And worse still, there is a porter (the default loader) who, instead of carrying whole crates, &lt;strong>takes the ingredients out one by one, writes each one down in a notebook and packs them again&lt;/strong> before sending them up. That porter, not the lift, is half the problem.&lt;/p>
&lt;h2 id="the-mechanism-what-really-happens-when-a-model-loads">The mechanism: what really happens when a model loads&lt;/h2>
&lt;p>When vLLM starts up with a model in &lt;code>safetensors&lt;/code>, the 140 GB of the Llama-70B FP16 make this journey:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Disk → page cache.&lt;/strong> The kernel reads the &lt;code>.safetensors&lt;/code> files from NVMe into the &lt;strong>page cache&lt;/strong> (host RAM). If this is the first time after a reboot, it is a physical read from disk (~14 GB/s on Gen5). If the files are already in page cache from an earlier start-up, this is almost free, and here is where the trap we will see is born.&lt;/li>
&lt;li>&lt;strong>Deserialise.&lt;/strong> The default Hugging Face loader &lt;code>mmap&lt;/code>s the file and builds the tensors &lt;strong>one by one&lt;/strong>, copying them into a CPU tensor before moving them. This is single-threaded CPU work that saturates neither the disk nor PCIe: most of the &amp;ldquo;slow&amp;rdquo; loading time goes here, not on moving bytes.&lt;/li>
&lt;li>&lt;strong>Host → HBM (H2D).&lt;/strong> Each tensor is copied from the host buffer into HBM over &lt;strong>PCIe Gen5 x16&lt;/strong> (~50 GB/s in practice). For the DMA to be efficient, the host buffer should be &lt;strong>pinned&lt;/strong>, which connects directly with the &lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">hugepages and pinned memory&lt;/a> of the NUMA post.&lt;/li>
&lt;li>&lt;strong>Place in HBM.&lt;/strong> HBM receives the 140 GB. At 3.35 TB/s, &lt;strong>this takes 42 ms&lt;/strong>. It is never the bottleneck.&lt;/li>
&lt;/ol>
&lt;p>The path has a &lt;strong>shortcut&lt;/strong>: &lt;strong>GPUDirect Storage (GDS)&lt;/strong>. Instead of bouncing through the CPU buffer (steps 2-3), a DMA engine close to the NVMe controller writes &lt;strong>straight from disk to HBM&lt;/strong>, without involving the CPU. It is the same principle as the &lt;a href="https://blog.lo0.es/en/posts/network-numa-cilium-ebpf-dranet-fourth-leg-pinning/">GPUDirect RDMA of the network&lt;/a>: get the CPU out of the way. &lt;code>fastsafetensors&lt;/code> uses GDS and reaches &lt;strong>26.4 GB/s&lt;/strong> reading a Llama-70B from NVMe across 4 GPUs.&lt;/p>
&lt;div class="diagram" style="max-width:680px;margin:1.4rem auto;">
&lt;svg viewBox="0 0 680 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Two paths: default loader bouncing through the CPU vs direct GPUDirect Storage">
&lt;text x="340" y="22" text-anchor="middle" font-family="sans-serif" font-size="13" font-weight="700" fill="currentColor">Two paths from disk to HBM&lt;/text>
&lt;text x="170" y="48" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="600" fill="#c1121f">Default: bounce through the CPU&lt;/text>
&lt;rect x="60" y="60" width="90" height="40" rx="5" fill="#eef3fb" stroke="#4a6fa5" stroke-width="1.3"/>
&lt;text x="105" y="84" text-anchor="middle" font-family="sans-serif" font-size="11" fill="currentColor">NVMe&lt;/text>
&lt;rect x="190" y="60" width="90" height="40" rx="5" fill="currentColor" fill-opacity="0.06" stroke="#888" stroke-width="1.3"/>
&lt;text x="235" y="78" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">CPU buffer&lt;/text>
&lt;text x="235" y="92" text-anchor="middle" font-family="sans-serif" font-size="9" fill="currentColor" opacity="0.7">+ deserialise&lt;/text>
&lt;line x1="150" y1="80" x2="188" y2="80" stroke="#c1121f" stroke-width="2" marker-end="url(#dha)"/>
&lt;defs>&lt;marker id="dha" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#c1121f"/>&lt;/marker>&lt;/defs>
&lt;rect x="320" y="60" width="90" height="40" rx="5" fill="#dceede" stroke="#3c8c54" stroke-width="1.5"/>
&lt;text x="365" y="84" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#1f5c34">HBM&lt;/text>
&lt;line x1="280" y1="80" x2="318" y2="80" stroke="#c1121f" stroke-width="2" marker-end="url(#dha)"/>
&lt;text x="235" y="120" text-anchor="middle" font-family="sans-serif" font-size="9.5" fill="currentColor" opacity="0.7">the CPU touches every byte · single-threaded · slow&lt;/text>
&lt;text x="170" y="168" text-anchor="middle" font-family="sans-serif" font-size="11.5" font-weight="600" fill="#2a9d8f">GPUDirect Storage: direct DMA&lt;/text>
&lt;rect x="60" y="180" width="90" height="40" rx="5" fill="#eef3fb" stroke="#4a6fa5" stroke-width="1.3"/>
&lt;text x="105" y="204" text-anchor="middle" font-family="sans-serif" font-size="11" fill="currentColor">NVMe&lt;/text>
&lt;rect x="320" y="180" width="90" height="40" rx="5" fill="#dceede" stroke="#3c8c54" stroke-width="1.5"/>
&lt;text x="365" y="204" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#1f5c34">HBM&lt;/text>
&lt;path d="M150,200 C230,200 240,200 318,200" stroke="#2a9d8f" stroke-width="2.4" fill="none" marker-end="url(#dhb)"/>
&lt;defs>&lt;marker id="dhb" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#2a9d8f"/>&lt;/marker>&lt;/defs>
&lt;text x="235" y="240" text-anchor="middle" font-family="sans-serif" font-size="9.5" fill="currentColor" opacity="0.7">the CPU never touches the data · ~26 GB/s NVMe→HBM&lt;/text>
&lt;line x1="470" y1="55" x2="470" y2="240" stroke="currentColor" stroke-width="1" opacity="0.25"/>
&lt;text x="575" y="90" text-anchor="middle" font-family="sans-serif" font-size="10.5" font-weight="600" fill="currentColor">140 GB FP16&lt;/text>
&lt;text x="575" y="112" text-anchor="middle" font-family="sans-serif" font-size="10" fill="currentColor" opacity="0.8">HBM: 42 ms&lt;/text>
&lt;text x="575" y="130" text-anchor="middle" font-family="sans-serif" font-size="10" fill="currentColor" opacity="0.8">PCIe: 2.8 s&lt;/text>
&lt;text x="575" y="148" text-anchor="middle" font-family="sans-serif" font-size="10" fill="currentColor" opacity="0.8">NVMe: 10 s&lt;/text>
&lt;text x="575" y="170" text-anchor="middle" font-family="sans-serif" font-size="10" fill="#c1121f" opacity="0.9">default: 30-60 s&lt;/text>
&lt;/svg>
&lt;/div>
&lt;h2 id="why-the-problem-exists-the-economics-of-bytes">Why the problem exists: the economics of bytes&lt;/h2>
&lt;p>The size of the model in bytes is decided by quantisation, and that sets the floor of the cold start, because &lt;strong>all&lt;/strong> those bytes have to move before the first token. For a 70B parameter model:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Format&lt;/th>
&lt;th>Bytes/param&lt;/th>
&lt;th>Size 70B&lt;/th>
&lt;th>Read 1 NVMe @14 GB/s&lt;/th>
&lt;th>H2D PCIe @50 GB/s&lt;/th>
&lt;th>HBM @3.35 TB/s&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>FP16 / BF16&lt;/td>
&lt;td>2&lt;/td>
&lt;td>140 GB&lt;/td>
&lt;td>10.0 s&lt;/td>
&lt;td>2.8 s&lt;/td>
&lt;td>42 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>FP8&lt;/td>
&lt;td>1&lt;/td>
&lt;td>70 GB&lt;/td>
&lt;td>5.0 s&lt;/td>
&lt;td>1.4 s&lt;/td>
&lt;td>21 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>INT4 (GPTQ/AWQ)&lt;/td>
&lt;td>0.5&lt;/td>
&lt;td>~35 GB&lt;/td>
&lt;td>2.5 s&lt;/td>
&lt;td>0.7 s&lt;/td>
&lt;td>10 ms&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Three readings of this table:&lt;/p>
&lt;p>&lt;strong>HBM never shows up as a problem.&lt;/strong> The last column is always milliseconds. Anyone saying &amp;ldquo;the GPU is slow to load&amp;rdquo; is blaming the wrong place.&lt;/p>
&lt;p>&lt;strong>Quantising is the most underrated cold start lever.&lt;/strong> Going from FP16 to FP8 does not only double inference throughput (less HBM bandwidth per token, as we saw in &lt;a href="https://blog.lo0.es/en/posts/quantization-llm-inference-fp8-int4-gguf/">quantization&lt;/a>): &lt;strong>it also halves the cold start&lt;/strong>, because there are half as many bytes to push up. It is a two-for-one that sizing usually ignores.&lt;/p>
&lt;p>&lt;strong>The disk is the bottleneck on bytes; the loader is the bottleneck on time.&lt;/strong> The figures in the table are the &lt;strong>theoretical floor&lt;/strong>, just moving bytes. The default loader adds single-threaded deserialisation on top, which is the difference between the theoretical 10 s and the real 30-60 s. That is why the solutions attack on two fronts: &lt;strong>fewer bytes&lt;/strong> (quantisation) and &lt;strong>a better porter&lt;/strong> (concurrent loaders / GDS).&lt;/p>
&lt;h2 id="the-maths-that-matter-cold-start-as-a-tax-on-autoscaling">The maths that matter: cold start as a tax on autoscaling&lt;/h2>
&lt;p>Cold start is not paid once. It is paid &lt;strong>every time a pod is born&lt;/strong>. And on an elastic platform, pods are born continuously.&lt;/p>
&lt;p>Take an &lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">autoscaling setup with KEDA&lt;/a> that scales from 2 to 6 replicas when the queue grows. The 4 new replicas take this long to be ready:&lt;/p>
$$ T_{\text{ready}} = T_{\text{schedule}} + T_{\text{pull-image}} + T_{\text{load-weights}} + T_{\text{cuda-graphs}} $$
&lt;p>With a Llama-70B FP16 and the default loader, $T_{\text{load-weights}}$ dominates: it can be &lt;strong>40 s&lt;/strong> of the ~60 s total. During those 40 s, the queue that triggered the autoscaling &lt;strong>keeps growing&lt;/strong>, since the new replicas absorb no traffic until they have loaded. The real number in the formula is not &amp;ldquo;how many replicas&amp;rdquo;, it is &lt;strong>how long each one takes to start serving&lt;/strong>, and that number is written by the loading path.&lt;/p>
&lt;p>This has a harsh operational consequence: &lt;strong>scale-to-zero is unworkable for workloads with a latency SLO if the cold start is 40 s.&lt;/strong> Nobody waits 40 s for the first token. The real elasticity of an inference platform is not limited by GPU availability, it is limited by &lt;strong>how long that GPU takes to have the model inside it&lt;/strong>. Bringing the cold start down from 40 s to 8 s (with streamer + FP8) is what turns &amp;ldquo;theoretical scale-to-zero&amp;rdquo; into &amp;ldquo;usable scale-to-zero&amp;rdquo;.&lt;/p>
&lt;p>The published numbers give the order of magnitude of the improvement: &lt;code>fastsafetensors&lt;/code> cuts start-up from &lt;strong>12.39 s to 4.74 s&lt;/strong> on a Llama-2-13B over 4×L40S, and from &lt;strong>16.04 s to 6.88 s&lt;/strong> on 1×A100, &lt;strong>4.8-7.5×&lt;/strong> over the default deserialiser. The &lt;strong>Run:ai Model Streamer&lt;/strong> loads in &lt;strong>4.88 s from S3 at concurrency 32&lt;/strong> and &lt;strong>7.53 s from SSD IO2 at concurrency 8&lt;/strong>; integrated into vLLM, total time to &lt;em>ready&lt;/em> drops to ~23 s from S3. There is no magic here: it is &lt;strong>getting the CPU out of the loop&lt;/strong> (GDS) and &lt;strong>reading in parallel&lt;/strong> (concurrency) to saturate the disk instead of leaving it half idle while one thread deserialises.&lt;/p>
&lt;h2 id="the-10-knobs-worth-touching">The 10 knobs worth touching&lt;/h2>
&lt;h3 id="knob-1--measure-where-the-time-goes-read-vs-deserialise-vs-h2d">Knob 1 — Measure where the time goes (read vs deserialise vs H2D)&lt;/h3>
&lt;p>Before touching anything: time it. Is the time going on reading from disk, on deserialising, or on the H2D? &lt;code>iostat -x 1&lt;/code> during the load tells you whether the NVMe is saturated (disk bottleneck) or nearly idle (loader/CPU bottleneck). If the disk is at 20%, the problem is &lt;strong>not&lt;/strong> the disk: it is the porter. Changing disk would fix nothing; changing loader would.&lt;/p>
&lt;h3 id="knob-2----load-format-choosing-the-porter">Knob 2 — &lt;code>--load-format&lt;/code>: choosing the porter&lt;/h3>
&lt;p>vLLM exposes several loaders via &lt;code>--load-format&lt;/code>: &lt;code>safetensors&lt;/code> (default), &lt;code>runai_streamer&lt;/code>, &lt;code>fastsafetensors&lt;/code>, &lt;code>tensorizer&lt;/code>. The default is the slowest. Changing one flag can be the cheapest 4-7× there is.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Run:ai Model Streamer (concurrent reads, saturates the disk)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vllm serve meta-llama/Llama-3.1-70B --load-format runai_streamer
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># fastsafetensors (GPUDirect Storage, direct DMA disk→HBM)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">vllm serve meta-llama/Llama-3.1-70B --load-format fastsafetensors
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="knob-3--streamer-concurrency">Knob 3 — Streamer concurrency&lt;/h3>
&lt;p>The Run:ai Model Streamer splits the read across N threads according to the size of each tensor in order to saturate the storage bandwidth. Concurrency is the key parameter: &lt;strong>16 is usually enough for local NVMe; 32 (sometimes 64)&lt;/strong> for high-throughput network storage. One thread does not saturate a Gen5 NVMe; 32 do.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">vllm serve &amp;lt;model&amp;gt; --load-format runai_streamer &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model-loader-extra-config &lt;span class="s1">&amp;#39;{&amp;#34;concurrency&amp;#34;: 32}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="knob-4--gpudirect-storage-gds--fastsafetensors">Knob 4 — GPUDirect Storage (GDS) + fastsafetensors&lt;/h3>
&lt;p>If there is an &lt;code>nvidia-fs&lt;/code> driver, a supported filesystem and local NVMe, GDS writes straight disk→HBM with no bounce through the CPU. It is the difference between the two paths in the diagram. &lt;strong>But&lt;/strong>: it requires the stack to be in place, and it only wins if the bottleneck is the CPU bounce, not the disk itself. Check with &lt;code>gdscheck&lt;/code>.&lt;/p>
&lt;h3 id="knob-5--local-nvme-for-the-weights-not-network">Knob 5 — Local NVMe for the weights, not network&lt;/h3>
&lt;p>Serving the weights from Ceph RGW / NFS is convenient (one shared place) but it puts the &lt;strong>network&lt;/strong> into the loading path. For cold start, &lt;strong>weights on the node&amp;rsquo;s local NVMe&lt;/strong> (or a local cache). Network storage is for the model repository; the inference node should have a hot local copy.&lt;/p>
&lt;h3 id="knob-6--pre-pull--local-model-cache">Knob 6 — Pre-pull / local model cache&lt;/h3>
&lt;p>An &lt;code>initContainer&lt;/code> that downloads the model onto a &lt;code>local&lt;/code> or &lt;code>hostPath&lt;/code> NVMe volume before starting vLLM turns a cold start &amp;ldquo;from the network&amp;rdquo; into one &amp;ldquo;from local NVMe&amp;rdquo;. Combined with a per-node cache DaemonSet, new pods on an already warm node read from local disk, not from the network.&lt;/p>
&lt;h3 id="knob-7--quantisation-move-fewer-bytes">Knob 7 — Quantisation: move fewer bytes&lt;/h3>
&lt;p>Weights already in FP8 or INT4 on disk = half or a quarter of the cold start. It is the knob from the table above. And it composes with all the others: FP8 + streamer + GDS is multiplicative.&lt;/p>
&lt;h3 id="knob-8--parallel-loading-across-gpus-vllm-v1">Knob 8 — Parallel loading across GPUs (vLLM V1)&lt;/h3>
&lt;p>vLLM&amp;rsquo;s V1 engine (the default since 0.19) loads the weight shards &lt;strong>in parallel&lt;/strong> across the GPUs of a TP group, instead of sequentially. At TP=4, each GPU loads its quarter at the same time. Check it is active; in old versions loading was serial and the cold start of TP=4 was almost 4× that of TP=1.&lt;/p>
&lt;h3 id="knob-9--numa-locality-of-the-nvme">Knob 9 — NUMA locality of the NVMe&lt;/h3>
&lt;p>The NVMe hangs off a &lt;strong>PCIe root under a specific socket&lt;/strong>, exactly the same NUMA map as the &lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">host post&lt;/a>. If the load&amp;rsquo;s host buffer lands on the wrong socket, the H2D crosses the UPI. The fifth list to align, alongside &lt;code>isolcpus&lt;/code>, &lt;code>reserved-cpus&lt;/code> and the NIC IRQs: &lt;strong>which socket is local to the NVMe and to the destination GPU&lt;/strong>. &lt;code>nvidia-smi topo -m&lt;/code> shows it.&lt;/p>
&lt;h3 id="knob-10--do-not-pay-the-cold-start-keep-pods-warm">Knob 10 — Do not pay the cold start: keep pods warm&lt;/h3>
&lt;p>Sometimes the answer is not to load faster, but &lt;strong>not to unload&lt;/strong>. A floor of always-live replicas (no scale-to-zero), or a pool of preloaded warm standbys, swaps &amp;ldquo;wait 40 s&amp;rdquo; for &amp;ldquo;0 s&amp;rdquo;. It is the cost of idle GPU in exchange for start-up latency: a &lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">capacity planning&lt;/a> decision, not a technical one.&lt;/p>
&lt;h3 id="summary-table">Summary table&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>#&lt;/th>
&lt;th>Knob&lt;/th>
&lt;th>What it attacks&lt;/th>
&lt;th>Risk / cost&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>&lt;code>iostat&lt;/code> while loading&lt;/td>
&lt;td>knowing whether the bottleneck is disk or loader&lt;/td>
&lt;td>none; always do it first&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>&lt;code>--load-format&lt;/code>&lt;/td>
&lt;td>single-threaded deserialisation&lt;/td>
&lt;td>format compatibility&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>streamer concurrency&lt;/td>
&lt;td>underused disk&lt;/td>
&lt;td>host RAM for buffers&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>GPUDirect Storage&lt;/td>
&lt;td>bounce through the CPU&lt;/td>
&lt;td>requires nvidia-fs + supported FS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>local NVMe vs network&lt;/td>
&lt;td>the network in the path&lt;/td>
&lt;td>duplicating weights per node&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>pre-pull / node cache&lt;/td>
&lt;td>network on every start-up&lt;/td>
&lt;td>local disk space&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7&lt;/td>
&lt;td>FP8/INT4 quantisation&lt;/td>
&lt;td>bytes to move&lt;/td>
&lt;td>quality (measure, do not assume)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8&lt;/td>
&lt;td>V1 parallel loading&lt;/td>
&lt;td>serial loading across GPUs&lt;/td>
&lt;td>none if V1 is active&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>9&lt;/td>
&lt;td>NUMA of the NVMe&lt;/td>
&lt;td>H2D crossing the UPI&lt;/td>
&lt;td>align with the rest of the NUMA lists&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>10&lt;/td>
&lt;td>warm pods / no zero&lt;/td>
&lt;td>the whole cold start&lt;/td>
&lt;td>idle GPU paid for&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="how-it-connects-with-the-rest-of-the-stack">How it connects with the rest of the stack&lt;/h2>
&lt;p>&lt;strong>With autoscaling.&lt;/strong> The whole of &lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">scale-from-zero with KEDA&lt;/a> rests on this: real elasticity is limited by the cold start, not by GPU availability. An autoscaler with 40 s of loading reacts late to every peak.&lt;/p>
&lt;p>&lt;strong>With disaggregated serving.&lt;/strong> In &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">disaggregated prefill/decode&lt;/a>, bringing up a decode pool on demand pays the cold start of loading the model into each new pod. The elasticity of the pattern depends on how fast those pods start.&lt;/p>
&lt;p>&lt;strong>With canary/blue-green.&lt;/strong> Every &lt;a href="https://blog.lo0.es/en/posts/canary-blue-green-shadow-llm-models/">canary deployment&lt;/a> loads a new version of the model alongside the old one. The validation time of a canary includes its cold start; large models make deployments slower and more expensive.&lt;/p>
&lt;p>&lt;strong>With NUMA and hugepages.&lt;/strong> The load&amp;rsquo;s host buffer wants to be &lt;strong>pinned&lt;/strong> and &lt;strong>NUMA-local&lt;/strong>, the same thing the &lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">host post&lt;/a> asked for on the hot path. The loading path is another client of the same NUMA map.&lt;/p>
&lt;p>&lt;strong>With quantisation.&lt;/strong> &lt;a href="https://blog.lo0.es/en/posts/quantization-llm-inference-fp8-int4-gguf/">FP8/INT4&lt;/a> is not only inference throughput: it is the direct lever on the bytes of the cold start.&lt;/p>
&lt;p>&lt;strong>With capacity planning.&lt;/strong> &lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">Sizing&lt;/a> that ignores cold start underestimates how many replicas are needed to absorb a peak: if they take 40 s to start, you need a bigger permanent cushion.&lt;/p>
&lt;h2 id="traps-and-things-that-are-not-what-they-seem">Traps and things that are not what they seem&lt;/h2>
&lt;p>&lt;strong>&amp;ldquo;The second time it loaded really fast.&amp;rdquo;&lt;/strong> This is the star trap. The first load filled the &lt;strong>page cache&lt;/strong> (host RAM); the second reads from RAM, not from disk, and flies. But in production pods are ephemeral and are born on different nodes: the start-up that counts is the &lt;strong>cold&lt;/strong> one, on a node where those files are not in page cache. Benchmarking the second load is measuring a situation that almost never happens at the moment that matters (the peak that triggers the autoscaler).&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;GDS always speeds things up.&amp;rdquo;&lt;/strong> No. GDS removes the bounce through the CPU; if your bottleneck is the disk itself (saturated NVMe) or the deserialisation, GDS does not touch that part. Measure first (knob 1). It also demands &lt;code>nvidia-fs&lt;/code>, a supported filesystem, and sometimes it does not work over whatever network storage you have.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;mmap makes loading instant.&amp;rdquo;&lt;/strong> &lt;code>mmap&lt;/code> maps the file but &lt;strong>reads nothing yet&lt;/strong>: the cost is deferred to the first access to each page. The time does not disappear, it moves, and the &lt;strong>first token&lt;/strong> pays the page faults that start-up did not. You have moved the cold start into the latency of the first request, which is probably a worse place to have it.&lt;/p>
&lt;p>&lt;strong>Weights on network storage &amp;ldquo;because it is cleaner&amp;rdquo;.&lt;/strong> Sharing a model repository on Ceph RGW is fine for storing them; serving the cold start from there puts the network (and its latency and its contention) into the critical path. Local NVMe cache on the inference node.&lt;/p>
&lt;p>&lt;strong>Loading FP16 and quantising at start-up.&lt;/strong> Quantising on the fly during loading (for example FP16→FP8 on the GPU) can be &lt;strong>slower&lt;/strong> than having the weights already quantised on disk: you move twice the bytes and on top of that you do conversion work. If you are going to serve in FP8, store the weights in FP8.&lt;/p>
&lt;p>&lt;strong>Optimising the load and ignoring &lt;code>T_cuda-graphs&lt;/code>.&lt;/strong> Bringing weight loading down to 8 s and forgetting that CUDA graph capture adds several more seconds leaves the cold start half done. That second half of start-up is the subject of the &lt;a href="https://blog.lo0.es/en/posts/sms-cuda-streams-cuda-graphs-inference/">next post&lt;/a>.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>The whole series optimised what happens &lt;strong>with every token&lt;/strong>: the cable, the host, the network, the silicon. But before the first token there is a journey almost nobody times and that decides whether an inference pod opens in 10 s or in 60 s: pushing the model from disk to HBM. Intuition blames the GPU, and the GPU is innocent: HBM swallows 140 GB in 42 ms. The bottleneck is the &lt;strong>supply chain&lt;/strong>: a disk reading at 14 GB/s, a PCIe copying at 50, and above all a default loader that deserialises tensor by tensor with a single thread and turns 10 s of bytes into 60 s of waiting. The solutions attack the two right fronts, &lt;strong>fewer bytes&lt;/strong> (quantisation) and &lt;strong>better transport&lt;/strong> (GDS, concurrent streamers, local NVMe), and give 4-7× almost for free. And above the technique, an idea that reorders the priorities: on an elastic platform, cold start &lt;strong>is not a start-up detail, it is the ceiling on elasticity&lt;/strong>. The fastest GPU in the world does not scale if it takes 40 s to have the model inside. The pantry lift, the one nobody timed, is what decides what time the kitchen really opens.&lt;/p>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/speeding-up-model-cold-start-minutes-to-seconds/">Speeding up model cold start: from minutes to seconds&lt;/a> — the runbook that attacks each of the five line items of start-up.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/serving-several-models-single-gpu-co-residency-swapping-sleep-mode/">Serving several models on a single GPU: co-residency, model-swapping and sleep mode&lt;/a> — sleep mode dodges this cold start by parking the weights in RAM instead of on disk.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/pcie-topology-gpudirect-p2p-acs-security-guard/">The corridors and the guard: PCIe, GPUDirect P2P and ACS&lt;/a> — the bus GDS uses to push the weights up from NVMe; ACS enabled throttles that direct path just as it throttles P2P between GPUs.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/vllm-scheduler-step-maitre-d-each-round/">The pass: vLLM&amp;rsquo;s scheduler step&lt;/a> — cold start is the ceiling on the elasticity the scheduler exercises: preemption and scale-from-zero pay this load in every new pod.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/nvlink-nvswitch-nccl-cable-every-token-crosses/">The shared table: NVLink, NVSwitch and NCCL&lt;/a> — the first of &amp;ldquo;under the engine&amp;rdquo;; this post goes down to the basement that series took for granted as full.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/numa-hugepages-cpu-isolation-gpu-waits-kernel/">The floor next door: NUMA, hugepages and CPU isolation&lt;/a> — the pinned, NUMA-local memory the loading path needs for an efficient H2D.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/network-numa-cilium-ebpf-dranet-fourth-leg-pinning/">The kitchen door: network NUMA, Cilium eBPF and DRANET&lt;/a> — the same &amp;ldquo;get the CPU out of the way&amp;rdquo; principle (GPUDirect) that GDS applies here to the disk.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/sms-cuda-streams-cuda-graphs-inference/">SM, CUDA streams and CUDA graphs&lt;/a> — the second half of the cold start (graph capture) and what happens on the silicon once the weights are inside.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/quantization-llm-inference-fp8-int4-gguf/">Quantization for inference&lt;/a> — the lever that halves the bytes of the cold start, not just HBM bandwidth per token.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/llm-inference-autoscaling-kubernetes-hpa-keda/">LLM autoscaling on Kubernetes with KEDA&lt;/a> — why cold start is the real ceiling on elasticity and kills scale-to-zero.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">Disaggregated serving: prefill and decode separated&lt;/a> — bringing up pools on demand pays the cold start in every new pod.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/canary-blue-green-shadow-llm-models/">Canary, blue-green and shadow for models&lt;/a> — the validation time of a canary includes its model loading.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/capacity-planning-on-premise-llm-inference/">Capacity planning for on-premise inference&lt;/a> — cold start as a parameter of the replica cushion and of the warm-vs-zero decision.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>NVIDIA, &lt;em>Reducing Cold Start Latency for LLM Inference with NVIDIA Run:ai Model Streamer&lt;/em>: &lt;a href="https://developer.nvidia.com/blog/reducing-cold-start-latency-for-llm-inference-with-nvidia-runai-model-streamer/">https://developer.nvidia.com/blog/reducing-cold-start-latency-for-llm-inference-with-nvidia-runai-model-streamer/&lt;/a>.&lt;/li>
&lt;li>vLLM, &lt;em>Loading models with Run:ai Model Streamer&lt;/em>: &lt;a href="https://docs.vllm.ai/en/stable/models/extensions/runai_model_streamer/">https://docs.vllm.ai/en/stable/models/extensions/runai_model_streamer/&lt;/a>.&lt;/li>
&lt;li>vLLM, &lt;em>Loading model weights with fastsafetensors&lt;/em>: &lt;a href="https://docs.vllm.ai/en/stable/models/extensions/fastsafetensor/">https://docs.vllm.ai/en/stable/models/extensions/fastsafetensor/&lt;/a>.&lt;/li>
&lt;li>foundation-model-stack, &lt;em>fastsafetensors&lt;/em> (high-performance loader, GDS): &lt;a href="https://github.com/foundation-model-stack/fastsafetensors">https://github.com/foundation-model-stack/fastsafetensors&lt;/a>.&lt;/li>
&lt;li>&lt;em>Speeding up Model Loading with fastsafetensors&lt;/em> (arXiv 2505.23072): &lt;a href="https://arxiv.org/html/2505.23072v1">https://arxiv.org/html/2505.23072v1&lt;/a>.&lt;/li>
&lt;li>NVIDIA, &lt;em>GPUDirect Storage: A Direct Path Between Storage and GPU Memory&lt;/em>: &lt;a href="https://developer.nvidia.com/blog/gpudirect-storage/">https://developer.nvidia.com/blog/gpudirect-storage/&lt;/a>.&lt;/li>
&lt;li>NVIDIA, &lt;em>Magnum IO GPUDirect Storage&lt;/em> (benchmarking and configuration): &lt;a href="https://developer.nvidia.com/gpudirect-storage">https://developer.nvidia.com/gpudirect-storage&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>