Benchmark Suite Results
MLPerf Storage
The MLPerf Storage benchmark suite measures how fast storage systems can supply training data when a model is being trained. Below is a short summary of the workloads and metrics from the latest round of benchmark results submissions.
Results
MLPerf Storage measures how well a storage system keeps AI accelerators fed — during training, checkpointing, vector search, and LLM inference caching. Every result below is a peer-reviewed submission run on the submitter’s own hardware under a common set of rules.
Choose a benchmark round, then a workload. Each workload stresses storage differently, so results are comparable within a workload but not across them. The notes under each selection explain what that workload does and which comparisons are meaningful.
Full submission details, including system configurations and any submitter notes, are in the supplemental information. The complete raw results are available as a Google Sheet.
v3.0 Results
Large-file sequential reads — the most bandwidth-hungry workload in the suite.
About this benchmark
What the Training benchmark measures
During model training, accelerators repeatedly read randomly ordered batches of samples from the training dataset. If storage cannot deliver samples as fast as the accelerators consume them, the accelerators sit idle — wasting the most expensive component in the system. The Training benchmark measures how many accelerators a storage system can keep busy.
The benchmark emulates the accelerators rather than requiring them: each simulated accelerator reads real data through a real ML framework (PyTorch) at the exact intensity of the real training job, then “computes” by sleeping for the measured per-batch computation time of the real accelerator (an NVIDIA B200 or an AMD MI355 in v3.0). The data path — storage through to client DRAM — is fully real; only the arithmetic is skipped. A result is valid only if the simulated accelerators stayed busy at least a threshold percentage of the time, called Accelerator Utilization (AU): 90% for Unet3D, 85% for RetinaNet. The reported figures are the average of five consecutive measured runs.
Two provisions prevent the benchmark from measuring the clients’ RAM instead of the storage: the dataset must be at least 5× the aggregate DRAM of all client nodes, and each run must process at least 500 batches per accelerator. For large accelerator counts, datasets reach many terabytes.
Column definitions
| Column | Units | Meaning |
|---|---|---|
| Accelerator Type | — | The accelerator emulated: b200 (NVIDIA B200) or mi355 (AMD MI355X). Each has its own measured batch size and computation time, so results with different accelerator types are different workloads. |
| # Client Nodes | count | How many client (load-generation) machines drove the storage. A harness property, not a storage property. |
| Code / Logs | — | Links to the exact benchmark code and the raw run logs for this result. |
| # Simulated Accelerators | count | The headline scale result: how many emulated accelerators the storage system kept at or above the AU threshold, summed across all client nodes. |
| Read B/W | GiB/s | The aggregate rate at which the storage delivered training data across all clients, averaged over the five runs. |
Read B/W and # Simulated Accelerators rise together: each simulated accelerator demands a roughly fixed bandwidth, so the bandwidth is approximately accelerators × per-accelerator demand × achieved AU.
Unet3D: large-file sequential reads
Unet3D is a 3D medical-image segmentation model, and its dataset (derived from the KiTS19 kidney-tumor CT scans) drives a distinctive I/O pattern:
A moderate number of very large files — averaging about 140 MiB each, with a wide spread (standard deviation ±65 MiB) — each holding exactly one training sample. Every file is read in full and sequentially; the next file to read is chosen effectively at random from the files not yet read this epoch. There are no writes.
Because the dataset must be 5× client DRAM, a submission at scale reads thousands to hundreds of thousands of these ~140 MiB files per epoch. Each simulated accelerator consumes samples in batches of 7 with 4 parallel reader threads, and the client software keeps a deep queue of file reads in flight, so the storage system sees many concurrent large sequential streams — a bandwidth-dominated workload. Keeping a single simulated B200 accelerator at 100% utilization requires about 5.9 GiB/s of read bandwidth, so the per-accelerator demand is severe: this is the most bandwidth-hungry workload in the suite.
What “good” looks like: high sustained aggregate read bandwidth under many concurrent sequential streams, without latency excursions long enough to stall any client’s pipeline below 90% utilization.
RetinaNet: small-file random reads at high rate
RetinaNet is an object-detection model trained on the OpenImages dataset, and it stresses the opposite end of the storage envelope:
A very large number of small files — about 315 KiB each (JPEG images), one sample per file — each read in full, in random order, with no writes. The 5×-DRAM sizing rule pushes the file count into the millions.
The per-accelerator bandwidth is modest — about 155 MiB/s for a simulated B200 — but each simulated accelerator opens and reads roughly 500 files per second (batches of 24, 8 reader threads). At hundreds of accelerators, the storage system must serve hundreds of thousands of small-file opens and reads per second from a namespace of millions of files. This makes RetinaNet a metadata- and IOPS-dominated workload: file-open latency, directory scalability, and small-request handling matter far more than streaming bandwidth.
What “good” looks like: sustained high file-operation rates with tightly bounded per-file latency, at 85%+ accelerator utilization.
Normalizing factors for training results
Meaningful
- Read B/W per TiB of usable capacity. Storage performance and capacity both scale with the hardware; their ratio describes the architecture’s performance density and lets a small test system be compared fairly against a large one.
- Read B/W (or accelerators supported) per rack unit, where reported. A direct measure of datacenter footprint efficiency.
- Read B/W per provisioned watt. Power provisioning scales with the system, making this a fair efficiency measure; the column is blank for cloud and client-local-storage rows.
Not meaningful
- Read B/W per client node, or the client-node count itself. Clients are load generators. A submitter with beefy clients uses few; a submitter with lean clients uses many, for the identical storage result.
- Read B/W per simulated accelerator. Approximately a constant fixed by the benchmark definition, so all valid rows show nearly the same value; differences are noise, not merit.
- Comparisons across models or accelerator types. A Unet3D-b200 simulated accelerator demands ~38× the bandwidth of a RetinaNet-b200 one.
What the Checkpointing benchmark measures
Training a large language model takes weeks to months across thousands of accelerators, and hardware faults are routine at that scale. The defense is checkpointing: periodically writing the entire training state — model weights plus optimizer state — to storage, and reading it back after a failure. While a checkpoint is being written synchronously, training is stalled; while one is being restored, the whole cluster waits. Checkpoint bandwidth therefore converts directly into recovered training time.
The benchmark emulates checkpointing for four sizes of Llama-3-family model. Each size fixes the model architecture, the parallelism layout, and therefore the exact number of writing processes and bytes written — a CLOSED submission cannot change any of it:
| Model | Processes | Parallelism (TP×PP×DP) | Data written per checkpoint | Files per checkpoint |
|---|---|---|---|---|
| 8B | 8 | 1×1×8 | ~105 GiB | 16 |
| 70B | 64 | 8×1×8 | ~911 GiB | 128 |
| 405B | 512 | 8×32×2 | ~5,290 GiB | 1,544 |
| 1250B | 1,024 | 8×64×2 | ~18,000 GiB | 2,072 |
The benchmark rules list these sizes nominally as 105 GB, 912 GB, 5.29 TB and 18 TB. A run performs 10 checkpoint writes, then 10 checkpoint reads of the same data. The read phase models recovery — including the case where a failed client’s checkpoint shard is read back by a different client, which is why the rules require the storage to be either simultaneously readable and writable across clients or rapidly remappable between them.
What the storage system experiences
Hundreds to a thousand processes, spread across the client nodes, simultaneously each stream one or two large files of their shard of the training state — roughly 9–20 GiB per process depending on the model — as fast as the storage will absorb them, with an fsync forcing every file to durable media before it counts as done. Five seconds later, they do it again; ten times in all. Then the same volume is read back in full, ten times.
It is a purely sequential, large-request workload — but a highly concurrent one, with hundreds of simultaneous streams, and it is one of only two workloads in the suite where write performance is measured. The fsync requirement means write-back caches cannot hide slow media: the clock stops only when data is durable. To keep client RAM from absorbing the working set, the rules require the data written per client node to exceed 3× that node’s memory (or caches to be explicitly dropped between the write and read phases).
For the two largest models the file structure changes slightly (model layers are written as many per-layer files by one data-parallel group while every process writes its optimizer shard), but from the storage system’s point of view the character is the same: massive parallel sequential writes, then massive parallel sequential reads.
Column definitions
| Column | Units | Meaning |
|---|---|---|
| Checkpoint Mode | — | Full = the complete process count and data volume for the model, per the table above. Subset = a reduced demonstration on 8 processes, permitted in CLOSED only for the 8B model (where 8 processes is the full configuration). Every v3.0 row is Full. |
| # Client Nodes | count | Client machines hosting the writer/reader processes. A harness property. |
| DP Instances | count | The number of data-parallel replicas in the emulated training job — a fixed property of each model configuration (8B: 1, 70B: 8, 405B: 2, 1250B: 2), shown for context. |
| Code / Logs | — | Links to the exact benchmark code and raw logs. |
| Write B/W | GiB/s | Aggregate write rate across all processes while writing one checkpoint, averaged over the 10 checkpoints. |
| Write Duration | seconds | Wall-clock time to write one checkpoint (first byte to last fsync completing), averaged over the 10. This is the time training would stall per checkpoint. |
| Read B/W | GiB/s | Aggregate read rate while restoring one checkpoint, averaged over the 10 reads. |
| Read Duration | seconds | Wall-clock time to read back one checkpoint, averaged over the 10. This is the storage component of recovery time after a failure. |
Bandwidth and duration are two views of the same event — duration ≈ checkpoint size ÷ bandwidth — but duration is the operationally meaningful number (how long is training stalled?), while bandwidth is the one that normalizes across systems.
Normalizing factors for checkpointing results
Meaningful
- Write (or Read) B/W per TiB of usable capacity, and per rack unit — the same performance-density logic as training. Here the write side is often the differentiator, since sustained fsync-bounded write bandwidth is harder to scale than read bandwidth.
- B/W per provisioned watt, where the column is populated.
- The write:read bandwidth ratio within a row, which is itself informative about the architecture’s balance (both phases move identical bytes).
Not meaningful
- B/W per client node. The process count is fixed per model, but submitters choose how many client machines to spread those processes across; the choice reflects client sizing, not storage capability.
- Comparisons across models. A 70B checkpoint (64 concurrent writers, ~911 GiB) and a 1250B checkpoint (1,024 writers, ~18 TiB) stress a system very differently. Compare 405B rows with 405B rows.
- Duration comparisons across models, for the same reason — the byte volumes differ by up to 170×.
What the Vector Database benchmark measures
Retrieval-augmented generation (RAG) and semantic search systems store documents as high-dimensional embedding vectors and answer queries by finding the stored vectors nearest to a query vector. At small scale the index fits in RAM; at production scale it does not, and the index moves to storage — making query performance a storage problem. This benchmark measures how well a storage system serves an on-disk approximate-nearest-neighbor (ANN) index under sustained query load.
The v3.0 CLOSED workload: a Milvus vector database holding 10 million vectors of 1,536 dimensions (float32 — about 6 KiB per vector, ~61 GB of raw vector data before index overhead), indexed with DiskANN, an index structure specifically designed to live on disk rather than in RAM. The measured phase issues top-10 similarity searches against that index across five consecutive timed runs. Search quality is not taken on faith: every reported result includes the recall of its answers, checked against an exact brute-force ground truth.
What the storage system experiences
After an initial bulk-load and index-build phase (not part of the measured result), the query phase is a stream of small random reads against a multi-hundred-gigabyte index structure. Each incoming query walks the DiskANN proximity graph: it hops node to node, and each hop that misses the client’s memory cache becomes a read of a small block of index data at an effectively random offset. Queries arrive continuously, so the storage sees a sustained, highly random, small-block, read-only pattern — latency-sensitive, since graph hops within one query are sequential in nature and storage latency accumulates per hop.
This is the suite’s purest random-read latency and IOPS workload, the opposite pole from checkpointing’s giant sequential streams.
Column definitions
| Column | Units | Meaning |
|---|---|---|
| # Client Nodes | count | Client machines issuing queries. A harness property. |
| Code / Logs | — | Links to the exact benchmark code and raw logs. |
| Vector Count | count | Vectors in the collection (10,000,000 in the v3.0 CLOSED configuration). |
| Vector Dimension | count | Elements per vector (1,536). |
| Index Type | — | The ANN index. CLOSED permits DISKANN, HNSW or AISAQ; all v3.0 submissions used DISKANN. |
| Queries per Sec | queries/s | The headline result: sustained rate of completed top-10 similarity searches, aggregated across all query processes. |
| Query Latency | ms | The 99th-percentile time to complete a single search — the tail experience, not the average. |
| Recall Percentage | % | Answer quality: the average fraction of each query’s true 10 nearest neighbors that the returned answer actually contained, ×100, verified against exact ground truth. |
| Storage IOPs | ops/s | Read+write operations per second observed at the block layer of the client’s local drives during the run. Only measurable when the storage under test is local block storage on the client, and only in the enhanced measurement mode; blank in all v3.0 rows. |
| Read B/W | GiB/s | Read bandwidth observed the same way (client-local block devices); like Storage IOPs, meaningful only for client-local storage. |
Reading and normalizing these results
Read QPS and recall together, always. ANN search trades accuracy for speed: an index searched lazily returns fast, low-quality answers; searched thoroughly, it returns slow, high-quality ones. A row with higher QPS at meaningfully lower recall has not demonstrated faster storage — it has answered an easier question. Only rows with comparable recall are performance-comparable. The P99 latency belongs in the same joint reading: it is the tail cost of delivering that QPS at that recall.
Meaningful
- Queries per second per rack unit and per TiB of usable capacity, carrying the same architecture-density signal as the other benchmarks — with the caveat that at only a few v3.0 submissions, cross-row comparison is thin.
- Per provisioned watt, where the Provisioned Power column is populated.
Not meaningful
- QPS per client node — a harness property.
- Any comparison against rows with substantially different recall, a different index type, or a different vector count or dimension (an OPEN submission may change these).
What the KV Cache benchmark measures
When an LLM serves a conversation, it builds an internal KV cache — the attention keys and values for every token of context it has read. That cache is large and expensive to recompute, and GPU memory is far too small to hold caches for the thousands of concurrent conversations an inference service juggles. The emerging architecture offloads inactive KV caches to storage and reloads them when a conversation continues — turning LLM inference serving into a storage workload. This benchmark measures how well a storage system plays that role: its performance directly bounds how many concurrent conversations an inference cluster can serve and how quickly it responds when a user sends their next message.
The benchmark simulates a population of users conversing with an LLM — a mix of chatbot sessions, coding-assistant sessions and document-analysis sessions with realistic context lengths, response lengths and think times — and issues the resulting KV-cache traffic to real storage. Every CLOSED submission runs the same three fixed configurations back to back (three trials each, 300 seconds per trial, results averaged); each configuration becomes one group of four metric columns:
| Column group | Emulated model | Memory tier | What it isolates |
|---|---|---|---|
| 8b Storage Only | Llama-3.1-8B | none — every cache access hits storage | Maximum storage stress at high request concurrency |
| 8b Storage + Mem | Llama-3.1-8B | 4 GiB DRAM cache tier in front of storage | The realistic tiered configuration: hot entries hit DRAM, the rest hit storage |
| 70b Storage Only | Llama-3.1-70B | none | The large-model case: 2.5× larger objects, fewer concurrent requests |
What the storage system experiences
Each simulated conversation’s KV cache is one file, written whole and re-read whole — never partially. The files are big: the KV state is 128 KiB per token of context for the 8B model and 320 KiB per token for the 70B model, so with contexts running from a few hundred tokens (chat) to 25,000 tokens (large coding sessions), individual objects range from tens of MiB to several GiB. A conversation turn writes its cache once — with an fsync before it counts — then reads it back repeatedly: once per batch of generated response tokens, and again in full each time the user returns for another turn. The byte mix is therefore strongly read-dominated, typically several times more bytes read than written, in whole-object sequential bursts arriving concurrently from every simulated user. The benchmark defeats the operating system’s page cache on reads, so a “Storage Only” read is a genuine storage read.
The workload thus combines checkpointing’s large sequential transfers with an inference service’s concurrency and latency sensitivity: many simultaneous multi-hundred-MiB reads whose completion time gates a simulated user’s response.
Each client node runs the full standard user population (200 users for the 8B Storage-Only test, 100 for Storage + Mem, 70 for the 70B test). Adding client nodes adds offered load — so the client-node count indicates how much aggregate demand the storage system absorbed while producing the numbers shown.
Column definitions
| Column | Units | Meaning |
|---|---|---|
| # Client Nodes | count | Client machines, each running the full per-client user population. More clients = more offered load. |
| Code / Logs | — | Links to the exact benchmark code and raw logs. |
| Throughput | tok/s | Per column group. The headline result: simulated LLM output tokens generated per second, summed across all clients, averaged over the three trials. Tokens can only be generated as fast as the storage delivers the KV caches they depend on, so this is an end-to-end measure of the storage keeping the simulated inference service fed. |
| Read B/W | GiB/s | Aggregate rate of KV-cache bytes read from storage, summed across clients, averaged over trials. |
| Write B/W | GiB/s | Aggregate rate of KV-cache bytes written (through fsync), likewise. |
| P95 Read Latency | ms | The 95th-percentile time for a single storage read of a KV-cache object — taken from the worst client node across all trials, a deliberately conservative worst-case bound rather than a population average. Since objects range from MiB to GiB, this reflects whole-object retrieval time, not per-4KiB-block device latency. |
When comparing the three groups within one row: “Storage + Mem” throughput is expected to exceed “Storage Only” (the DRAM tier absorbs the hottest re-reads, and its Read B/W column counts only the traffic that reached storage), and the 70B group’s token throughput is expected to be well below the 8B groups’ (each token drags 2.5× the bytes, with fewer concurrent requests). These are three different tests, reported side by side.
Normalizing factors for KV cache results
Meaningful
- Throughput or Read B/W per TiB of usable capacity, and per rack unit — the standard architecture-density measures.
- Per provisioned watt, where the column is populated.
- The latency column read jointly with the bandwidth columns. High aggregate read bandwidth at low worst-client P95 is the actual product requirement — a user is waiting on each read; either number alone is an incomplete picture.
Not meaningful
- Throughput per client node. Client count sets the offered load, and a submitter scales clients until the storage is saturated — the aggregate achieved is the result; dividing it back out by the load generators is circular. The client count is worth reading, but not dividing by.
- Comparisons across column groups presented as one ranking. Storage Only, Storage + Mem and 70B are different workloads by design.
- Comparing the P95 latency of a Storage-Only group against a Storage + Mem group. The DRAM tier changes which reads reach storage at all; the populations behind the two percentiles differ.
Workloads
Each workload supported by MLPerf Storage is defined by a corresponding MLPerf Training benchmark. The following table summarizes the workloads in this version of the benchmark (the rules remain the official source of truth):
| Area | Task | Model | Nominal Dataset | Latest Version Available |
|---|---|---|---|---|
| Vision | Medical image segmentation | 3D U-Net | KITS 2019 (602x512x512) | v2.0 |
| Vision | Image classification | ResNet50 | ImageNet | v2.0 |
| Scientific | Cosmology parameter prediction | CosmoFlow | CosmoFlow N-body simulation | v2.0 |
| Language | Language processing | BERT-large | Wikipedia (2.5KB/sample) | v0.5 |
| Checkpointing | Preserve forward progress in the face of infrastructure failures during Training | Llama-3 | From 105GB at an 8B scale to 18TB at a 1T scale. | v2.0 |
The dataset is referred to as a “nominal dataset” above because the MLPerf Storage benchmark simulates the above named real datasets using synthetically generated populations of files where the distribution of the size of the files matches the distribution in the real dataset. The size of the dataset used in each benchmark submission is automatically scaled to a size that prevents significant caching of the dataset in the systems actually running the benchmark code.
Divisions
MLPerf aims to encourage innovation in software as well as hardware by allowing submitters to reimplement the reference implementations. There are two Divisions that allow different levels of flexibility during reimplementation:
- The Closed division is intended to allow comparisons between storage systems in an “apples-to-apples” fashion and requires using a fixed set of benchmark tunables and options when running the benchmark.
- The Open division is intended to foster innovation, to show how performance could be increased if some changes were made. As a result, it allows using different data storage formats, access methods, tunables, and options.
- See the rules for specifics on what can be changed in each Division.
Availability
MLPerf divides benchmark results into categories based on the availability of the storage solution:
- Available systems contain only components that are available for purchase or for rent in the cloud.
- Preview systems must be submittable as Available in the next submission round. Ie: the code or h/w you used is on a path to being Available and will likely be Available within the next 6 to 9 months, it just hasn't quite gotten there yet.
- Research, Development, or Internal (RDI) contain experimental, in development, or internal-use hardware or software. These may never be Available, either because they're a proof-of-concept, or you believe you'll need to change them before being released because you learned things, etc.
Submission Information
Not all of the below columns are part of every submission round.
Each row in the results table is a set of results produced by a single submitter using the same software stack and hardware platform. Each Closed division row contains the following information:
Each row in the results table contains the following information for each workload submitted:
Throughput
This is the maximum performance the storage system was able to deliver while maintaining all the accelerator(s) at 90% utilization or above (ie: no more than 10% of the time were the accelerator(s) idle and waiting for the storage system to deliver data). It is reported as both “samples/second”, a metric that should be intuitively valuable to AI/ML practitioners, and as “MB/s”, a metric that should be intuitively valuable to storage practitioners.
Number of Simulated Accelerators
The number of simulated accelerators active during this test; ie: how many accelerators of the given type can this storage system keep busy.
Dataset Size
Since the dataset used in this test was synthesized and must be of a size to prevent significant caching of data in the compute node(s) running the benchmark, the size of the dataset used in this test is reported here.