Architecture & Measurement-Design Analysis

GPU-Initiated On-Demand High-Throughput Storage Access in the BaM System Architecture

Source: Qureshi, Z.; Mailthody, V. S.; Gelado, I.; Min, S.; Masood, A.; Park, J.; Xiong, J.; Newburn, C. J.; Vainbrand, D.; Chung, I.-H.; Garland, M.; Dally, W.; Hwu, W. Proceedings of the 28th ACM International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '23), Vol. 2, March 25-29, 2023, Vancouver, BC, Canada, pp. 325-339. DOI: 10.1145/3575693.3575748 Code: Open-source hardware + software (publicly accessible per §1; IMPACT/UIUC + NVIDIA). Affiliations: NVIDIA, UIUC, AMD, University at Buffalo, IBM Research, Stanford. Reader: Direct PDF read via Claude Read tool with pages parameter (gemini-reader quota exhausted; codex-reader not attempted — full 12-page PDF fit in one read window). Analyst: Vishwakarma Date: 2026-06-15


Table of Contents

  1. System Architecture (the "specimen": GPU-initiated storage stack)
  2. System-Under-Test Architecture (BaM prototype testbed)
  3. Design-Space Diagram (axes swept, axes held fixed)
  4. Algorithm / Control Flow Diagrams (queue insertion, cache probe, warp coalescing)
  5. Quantitative Results — Empirical Findings by Regime
  6. Configuration-Regime Trade-off Tables
  7. Bottlenecks & Insights Surfaced by the Measurements
  8. Limitations of the Methodology
  9. Analogy

1. System Architecture (the "specimen": GPU-initiated storage stack)

BaM ("Big accelerator Memory") is an accelerator-centric system architecture. Its thesis is a single inversion of control: instead of the CPU initiating and orchestrating every storage access (the "CPU-centric" baseline), the GPU thread itself initiates on-demand, fine-grained access to data wherever it lives — host memory or NVMe storage — without any CPU involvement on the critical path. The authors name this new family GPU Kernel Initiated (KI) storage access: GPUDirect Async KI Storage.

The architecture has three load-bearing components, all resident in GPU memory: (1) a scalable, highly concurrent software cache that coalesces redundant on-demand accesses and exposes locality; (2) a set of high-throughput I/O submission/completion (SQ/CQ) queues mapped into GPU memory, with the NVMe doorbell registers mapped into the GPU address space so GPU threads can ring them directly; and (3) the bam::array<T> abstraction — an array-like, mmap-style API that hides all of the above behind an overloaded subscript operator.

+-------------------------------------------------------------------+
|                    BaM Logical Architecture                       |
|                   (everything below lives in GPU memory)          |
|                                                                   |
|  +-----------------------+        +---------------------------+   |
|  | bam::array<T>         |  --->  | Software Cache            |   |
|  | (user-facing API,     |        | - Cache Metadata          |   |
|  |  overloaded [] op)    |        | - Cache-line data buffers |   |
|  | (role: mmap'd handle) |        | - clock replacement       |   |
|  +-----------+-----------+        | - ref-count + lock per CL |   |
|              |                    +-------------+-------------+   |
|         offset calc                              | MISS           |
|         + coalesce                               v                |
|              |                    +---------------------------+   |
|              |                    | High-Throughput I/O Queues|   |
|              +------------------> | - Submission Queues (SQ)  |   |
|                                   | - Completion Queues (CQ)  |   |
|                                   | - ticket counter          |   |
|                                   | - turn_counter[] array    |   |
|                                   | - mark bit-vector + lock  |   |
|                                   +-------------+-------------+   |
|                                                 | ring doorbell   |
+-------------------------------------------------|-----------------+
                                                  v
              ============= PCIe Gen4 x16 Interconnect =============
                                                  |
+-------------------------------------------------|-----------------+
|                       Storage (NVMe SSDs)        v                |
|  +-------------+   +-------------+   ...   +-------------+         |
|  | DB Reg #N   |   | DB Reg #N   |         | DB Reg #N   |         |
|  | + DMA engine|   | + DMA engine|         | + DMA engine|         |
|  | + CTRL      |   | + CTRL      |         | + CTRL      |         |
|  | + Media     |   | + Media     |         | + Media     |         |
|  +-------------+   +-------------+         +-------------+         |
|   (role: storage controller per SSD, posts CQ entries)           |
+-------------------------------------------------------------------+
^ Fig 1: Logical view of BaM (paper Figure 1). The control path
  (doorbell ring) and the data path (DMA over PCIe) are decoupled:
  GPU threads ring SSD doorbells directly; SSD DMA engines move
  bytes peer-to-peer into GPU memory. No CPU on either path.

The architecturally decisive choice is that the doorbell registers of the SSD controllers are memory-mapped into the GPU's address space (via GPUDirect Async, with the SSD BAR space mapped through the cudaHostRegister API). This is what lets a GPU thread initiate an I/O without a host round trip. Everything else in BaM — the cache, the queue protocol, the coalescing — exists to make this raw capability survive the GPU's thousand-fold-higher thread-level parallelism, which would otherwise serialize catastrophically on the shared doorbell and queue state.

The contrast with the CPU-centric baseline is the entire point. In the CPU-centric model, the CPU page-fault handler (or an explicit io_uring/read call) transfers data to GPU memory before a compute kernel can run, then launches the kernel, then synchronizes, repeatedly. This incurs CPU-GPU synchronization overhead, I/O traffic amplification (the CPU cannot know which bytes the data-dependent kernel will actually touch, so it over-fetches), and long CPU software latencies. BaM removes the CPU from the storage control path entirely.


2. System-Under-Test Architecture (BaM prototype testbed)

The prototype is built from off-the-shelf hardware: a single NVIDIA A100-80GB PCIe GPU, a Supermicro AS-4124GS-TNR server with 2x AMD EPYC 7702 64-core CPUs and 1 TB DDR4-3200, and — critically — a PCIe expansion chassis (H3 Platform Falcon-4016) that supplies the extra PCIe Gen4 x16 slots needed to attach many NVMe SSDs at full bandwidth. Software is Ubuntu 20.04 LTS, NVIDIA driver 470.82, CUDA 11.4, plus a custom Linux character-device driver that creates one device node per NVMe SSD and uses GPUDirect RDMA to pin and map the NVMe queues and I/O buffers into GPU memory.

+--------------- BaM Prototype Testbed (paper Table 1) -------------+
|                                                                   |
|   Supermicro AS-4124GS-TNR (4U)                                   |
|   +-----------------------------------------------------------+   |
|   |  2x AMD EPYC 7702 (64-core)   |   1 TB Micron DDR4-3200   |   |
|   +--------------------------+--------------------------------+   |
|                              |                                    |
|                       PCIe Gen4 x16                               |
|                              |                                    |
|   +--------------------------+--------------------------------+   |
|   |        NVIDIA A100-80GB PCIe GPU (the initiator)          |   |
|   +--------------------------+--------------------------------+   |
|                              |                                    |
|              =====  PCIe expansion fabric  =====                  |
|              H3 Platform Falcon-4016 chassis                      |
|              (two independent drawers, x16 each,                  |
|               PCIe bifurcation -> >16 M.2 SSDs/drawer)            |
|                              |                                    |
|   +--------------------------+--------------------------------+   |
|   |  Up to 10 Intel Optane P5800X (DC SSDs) OR                |   |
|   |  Samsung 980pro (consumer) OR Samsung Z-NAND PM1735       |   |
|   |  (P2P DMA target; doorbells mapped into GPU addr space)   |   |
|   +-----------------------------------------------------------+   |
+-------------------------------------------------------------------+

  SSD technology trade-off (paper Table 2):
  +------------+------------------+-----------+------+--------+-------+
  | Technology | RD IOPs(512B,4KB)| Latency us| DWPD | $/GB   | Gain  |
  +------------+------------------+-----------+------+--------+-------+
  | DRAM DDR4  | >10M             | O(0.1)    |>1000 | 11.13  | 1.0x  |
  | Optane     | 5.1M / 1.5M      | O(10)     | 100  | 2.54   | 4.4x  |
  | Z-NAND     | 1.1M / 1.6M      | O(25)     | 3    | 2.64   | 4.3x  |
  | NAND Flash | 700-800K         | O(100)    | 0.3  | 0.51   | 21.8x |
  +------------+------------------+-----------+------+--------+-------+
^ Fig 2: System-under-test. The expansion chassis is not incidental —
  no single NVMe SSD can match a PCIe x16 Gen4 link, so BaM must
  *scale out* SSDs to saturate the GPU's PCIe bandwidth. The $/GB
  "Gain" column is the cost argument: 4.3x-21.8x cheaper per GB than
  a DRAM-only solution, even after paying for chassis + risers.

The testbed embodies the paper's economic thesis. The GPU's PCIe Gen4 x16 link delivers ~26 GB/s; the authors quote 26 GB/s / 512 B = 51 M accesses/sec and 26 GB/s / 4 KB = 6.35 M accesses/sec as the access- rate ceilings the storage tier must feed. A single Optane SSD tops out near 5.1 M read IOPs, so reaching the PCIe ceiling requires striping across ~10 SSDs — which is exactly why the expansion chassis is a first-class component, not an accessory.

Little's Law is the sizing tool the authors apply explicitly: T x L = Q_d, where T is target throughput, L is device latency, and Q_d is the minimal queue depth to sustain T. For Optane (L = 11 us), sustaining 51 M accesses of 512 B needs Q_d = 51M x 11us = 561 in-flight requests; for Samsung 980pro (L = 324 us), the same target needs Q_d = 16,524. That second number — tens of thousands of concurrent in-flight requests — is the structural justification for the entire high-throughput-queue design: only the GPU's massive thread-level parallelism can keep that many requests in flight.

  Software / hardware stack of the SUT:
  +------------------------------------------------+
  | Application GPU kernel (bam::array<T> access)  |  user code
  +------------------------------------------------+
  | bam::array<T>  high-level abstraction          |  API layer
  +------------------------------------------------+
  | BaM Software Cache (coalesce + locality)       |  caching layer
  +------------------------------------------------+
  | BaM I/O Stack (SQ/CQ queue protocol)           |  protocol layer
  +------------------------------------------------+
  | Custom Linux char driver (1 node / SSD)        |  setup-time only
  | + GPUDirect RDMA / GPUDirect Async             |  (not on hot path)
  +------------------------------------------------+
  | NVMe over PCIe Gen4 x16 (P2P DMA)              |  transport
  +------------------------------------------------+
  | Intel Optane / Samsung Z-NAND / NAND SSDs      |  media
  +------------------------------------------------+
^ Fig 3: SUT layered stack. The custom driver participates only at
  initialization (pin + map queues/doorbells); once mapped, the GPU
  bypasses it entirely. This is the "setup in kernel space, steady
  state in user space" split that gives BaM its throughput.

3. Design-Space Diagram (axes swept, axes held fixed)

BaM's evaluation is a multi-axis sweep over storage configuration, workload class, cache geometry, and baseline. Unlike a survey paper, the swept axes here are properties of one system (BaM) measured against fixed external baselines (GDS, ActivePointers, RAPIDS, host-memory Target).

                  DESIGN SPACE (swept + held-fixed)
  +---------------------------------------------------------------+
  |                                                               |
  |  Axis 1: NUMBER OF SSDs (raw-throughput + app scaling)         |
  |    [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]                    |
  |    (round-robin striping; replication for app workloads)      |
  |                                                               |
  |  Axis 2: I/O ACCESS GRANULARITY / cache-line size             |
  |    [512 B] [4 KB] [8 KB]  (raw); also vs GDS 4KB..1MB          |
  |                                                               |
  |  Axis 3: WORKLOAD CLASS                                        |
  |    [Raw IOPs microbench] (512B/4KB random read+write)         |
  |    [Graph analytics: BFS, CC]  (5 graphs, Table 3)            |
  |    [Data analytics: 6 NYC-Taxi queries Q0..Q5 vs RAPIDS]      |
  |    [vectorAdd: write-intensive, 4B-element x 4 billion]       |
  |                                                               |
  |  Axis 4: CACHE GEOMETRY                                        |
  |    cache size [1,2,4,8,16,32,64 GB]                           |
  |    cache mode [No cache | Naive cache | Optimized (coalesce + |
  |                reference reuse)]                              |
  |                                                               |
  |  Axis 5: NVMe QUEUE-PAIR COUNT (SQ/CQ depth = 1024)           |
  |    [128] [96] [80] [64] [48] [40] [32]  queue pairs           |
  |                                                               |
  |  Axis 6: BASELINE / COMPARATOR                                |
  |    [NVIDIA GDS] [ActivePointers+GPUfs] [host-memory Target T] |
  |    [RAPIDS (CPU-mem preloaded)] [DRAM-only solution]          |
  |                                                               |
  |  Held FIXED (no sweep, unless noted):                         |
  |    - GPU: single NVIDIA A100-80GB PCIe                        |
  |    - Interconnect: PCIe Gen4 x16 (~26 GB/s ceiling)          |
  |    - Default SSD: Intel Optane P5800X, 128 QP @ 1024 depth   |
  |    - Default graph cache: 8 GB, 4 KB cache-line              |
  |    - Bare-metal, direct NVMe access (no virtualization)      |
  |    - bam::array default template params (no specialization)  |
  +---------------------------------------------------------------+
^ Fig 4: 6-axis design space. The most important "held fixed" lines
  are the single A100 + single PCIe x16 link: BaM's whole story is
  saturating ONE PCIe link from MANY SSDs. The cache-mode axis
  (No / Naive / Optimized) is where BaM's software contribution is
  isolated from the raw hardware capability.

Two scoping choices define the measurement. First, the cache-mode axis (No cache / Naive cache / Optimized) isolates the software contribution from the raw hardware: "No cache" measures the bare GPUDirect-Async capability, "Naive cache" adds the coalescing cache, and "Optimized" adds warp coalescing + cache-line reference reuse. The gap between these three columns is BaM's software value, separated from the SSD's raw IOPs. Second, almost everything runs against a single A100 over a single PCIe x16 link — the SSDs scale out, but the GPU does not — so the experiment is deliberately bottlenecked at the PCIe ceiling, which makes "did we saturate PCIe?" the central success criterion.


4. Algorithm / Control Flow Diagrams

4.1 Life of a GPU thread accessing data (the master control flow)

This is the end-to-end path from data[tid] to bytes-in-GPU-memory, spanning the BaM lookup, the I/O stack, and the storage controller (paper Figure 2).

  START: GPU thread executes  val = data[tid]   (bam::array)
       |
       v
  (1) Offset calc: compute cache-line for this element
       |
       v
  (2) Coalescer: threads in a warp accessing the SAME cache line
       elect ONE leader to probe metadata (warp coalescing)
       |
       v
  (3) Cache lookup ----> read(off, tid)
       |
       +-- HIT  --> atomically inc cache-line ref-count -->
       |            directly read data in GPU memory --> [done]
       |
       +-- MISS --> lock cache line, find victim (clock replace),
                    enter the BaM I/O stack:
            |
            v
  (4) Prepare CMD            (build NVMe read command)
       |
       v
  (5) Submit CMD to SQ       (ticket counter -> entry; turn ordering;
       |                      copy command into physical SQ slot)
       v
  (6) Ring doorbell (sq_db)  (coalesced: move_tail does ONE doorbell
       |                      write for many threads' commands)
       v
  ===== Storage Controller side =====
  (a) Wait for doorbell
  (b) Read SQ entry from GPU
  (c) Process CMD
  (d) DMA write to GPU I/O buffer   (P2P, bypasses CPU)
  (e) Write CQ entry in GPU mem
  ===================================
       |
       v
  (7) Poll for completion    (no lock; scan CQ for this request)
       |
       v
  (8) Update cache state     (mark line valid, store data)
       |
       v
  (9) Update SQ/CQ head      (winner thread rings CQ head doorbell,
       |                      advances heads on behalf of coalesced peers)
       v
  Access fetched data in GPU memory --> [done]
^ Fig 5: Life of a GPU thread in BaM (paper Figure 2). Steps (4)-(9)
  only execute on a MISS. The whole design effort is to make steps
  (5), (6), and (9) survive thousands of concurrent threads with
  minimal critical sections.

The design intent is visible in which steps hold locks. The cache probe (3) and completion poll (7) are lock-free — only a miss that must insert/evict (4) or a doorbell ring (6) and head advance (9) touch the small critical sections. This is the same "minimize the critical section, maximize lock-free fast paths" discipline that lets the GPU's thread-level parallelism actually translate into IOPs rather than collapsing onto a serialized doorbell.

4.2 Lock-free queue insertion (the ticket / turn protocol)

The SQ insertion protocol is the cleverest piece of the I/O stack. It turns a naive "lock-enqueue-ring-doorbell" critical section (which would serialize thousands of threads) into a mostly-lock-free ticketed protocol with a single coalesced doorbell write.

  Per-SQ metadata in GPU memory:
    head, tail   |  ticket counter  |  turn_counter[]  |  mark[]  |  lock

  Thread wants to enqueue a command:
       |
       v
  (1) atomically  ticket += 2     -> returns a global index into a
       |                              VIRTUAL queue of 2^32 entries
       v
  (2) entry = ticket % phys_size  (which physical slot)
      turn  = ticket / phys_size  (which "pass" over that slot)
       |
       v
  (3) spin until turn_counter[entry] == my turn
       |   (turn_counter creates per-slot SUB-QUEUES ordered by turn;
       |    waiting threads on the same slot are FIFO-ordered)
       v
  (4) slot is now mine: copy I/O command into SQ[entry]
       set mark[entry] = 1
       |
       v
  (5) call move_tail:
        - ONE thread wins the lock
        - advances tail past consecutive marked entries
        - reset_marks for those entries
        - rings the SQ doorbell ONCE (coalesces many writes)
        - releases lock
      (losing threads return immediately if their mark was cleared;
       else they retry to take the lock and push the tail further)
^ Fig 6: Lock-free-ish SQ insertion. The doorbell — the expensive PCIe
  write — is amortized across all threads whose commands the winner's
  move_tail covered. CQ dequeue is symmetric (winner advances CQ head
  and signals forward progress via new-head in the CQ entry).

The turn_counter[] array is the subtle invention: it maps a 2^32-entry virtual queue onto a finite physical queue, with each physical slot owning a FIFO of waiting threads ordered by turn. This gives correctness (no two threads write the same slot concurrently) without a global lock on the common path — the lock is only taken in move_tail, and only by one winning thread per batch.

4.3 Cache probe + clock eviction (concurrency-safe)

  Thread probes cache line for an offset:
       |
       v
  state == VALID? --yes--> atomically inc ref_count --> use data
       |                   (when done: dec ref_count)
       no
       v
  lock cache line --> find victim via CLOCK replacement:
       |
       v
  global counter++ -> assigns a candidate cache SLOT
       |
       +-- slot maps to line with ref_count != 0 (pinned)?
       |      yes --> counter++ again, try next slot (skip pinned)
       |       no  --> mark old line INVALID, remap slot to new line
       v
  request new line from backing memory (SSD or host)
       |
       v
  on completion: unlock, set VALID, inc ref_count
^ Fig 7: Concurrency-safe clock replacement. The global atomic counter
  lets many concurrent evictions pick DIFFERENT slots in parallel;
  pinned (non-zero ref-count) lines are skipped, never evicted
  mid-use. This is what lets the cache "support many more concurrent
  accesses" than an OS-kernel allocator's coarse critical sections.

4.4 Warp coalescing (__match_any_sync)

The final mechanism collapses redundant cache probes within a warp. Prior work (GPUfs/ActivePointers) serialized unique probes per warp, costing many instructions; BaM uses the __match_any_sync warp primitive to partition the warp's 32 threads into groups by cache line, elects a leader per group via __shfl_sync, and lets each group's leader probe in parallel with no inter-group dependency.

  32 threads in a warp, each with a target offset:
       |
       v
  __match_any_sync(mask, cache_line_id)
       -> partitions warp into GROUPS sharing a cache line
       |
       v
  per group: elect leader (lowest lane)         [parallel across groups]
       |
       v
  leader probes cache for the group's line       [no inter-group dep]
       |
       v
  __shfl_sync broadcasts the GPU-memory address to group members
       |
       v
  all members read their element from the shared cache line
^ Fig 8: Warp coalescing. vs prior serialized-probe designs, BaM's
  groups probe concurrently. This is the micro-architectural reason
  the "Optimized" cache mode beats the "Naive" cache mode in Fig 8
  of the paper (6.07x BFS / 11.24x CC additional speedup).

5. Quantitative Results — Empirical Findings by Regime

5.1 Headline end-to-end results (abstract)

Comparison BaM result
BFS / CC vs host-memory DRAM-only T 1.0x and 1.49x end-to-end speedup, while DRAM-only is up to 21.7x more expensive
Data analytics vs CPU-centric (RAPIDS) up to 5.3x faster on same hardware
Prior GPU-initiated attempts ~823K IOPs (A100) baseline BaM shatters

The framing is two-pronged: BaM is on-par-or-better in performance and dramatically cheaper, because it replaces expensive DRAM with cheap SSDs while matching throughput.

5.2 Raw I/O throughput (microbenchmark, §4.3, Figure 4)

Config Random Read Random Write
Single Optane SSD (512 B) 16K-64K GPU threads to reach peak
10 Optane SSDs (512 B) 45.8 M IOPs 10.6 M IOPs
10 Optane SSDs (effective BW) 22.9 GBps (90% of measured Gen4 x16 peak) 5.3 GBps

BaM's I/O stack reaches 45.8 M read IOPs for 512 B accesses across 10 SSDs and scales linearly with additional SSDs. 22.9 GBps is 90% of the measured Gen4 x16 peak — i.e., BaM's software is not the bottleneck; PCIe is. Write bandwidth has further headroom (5.3 GBps is not yet PCIe-limited; more SSDs would help).

5.3 vs NVIDIA GDS — the small-granularity cliff (§5.1, Figure 5)

I/O granularity GDS (% of PCIe x16 peak BW) BaM (% of peak BW)
4 KB ~24% (limited by Linux SW) ~100% (~25 GBps)
32 KB crosses ~100% ~100%
< 32 KB cannot saturate PCIe saturates at 4 KB

GDS cannot saturate PCIe below 32 KB because of the traditional CPU software stack overhead; GDS only reaches 23.6% of bandwidth at 4 KB. BaM saturates the interface at even 4 KB (~25 GBps). This is the cleanest demonstration that the CPU software path — not the hardware — is what kills fine-grained access.

5.4 vs ActivePointers (§5.1, Figure 6)

Metric ActivePointers BaM
Miss-handling throughput (512 B) 823 KIOPs 17 MIOPs (20.7x)
Cold-cache effective BW (8 KB) 4.4 GBps (BaM far higher)
Hot-cache peak BW ~38 GBps 430 GBps (11.2x)

BaM beats ActivePointers by >1 order of magnitude in both cache-miss handling and hit-data delivery. ActivePointers is hindered by the GPUfs mechanism (GPU threads must request transfers from the CPU); BaM's GPU-initiated path removes that handshake.

5.5 Graph analytics (§5.2, Figures 7-9)

Workload BaM 1-SSD vs Target T BaM 4-SSD vs Target T
BFS 1.43x slower 1.00x (on par)
CC 1.27x slower 1.49x faster

Scaling 1 -> 4 SSDs improves BaM's aggregate bandwidth and pushes it to PCIe-level bandwidth (3.48x for BFS, 4x for CC). With 4 SSDs, BaM matches or beats a host-memory DRAM-only solution that costs up to 21.7x more. The Uk graph is the hard case for BFS (deep traversal, small frontiers -> insufficient concurrent I/O to hide latency).

Cache-mode decomposition (Figure 8):

Cache mode BFS speedup CC speedup
Naive cache vs No cache 11.9x 12.65x
Optimized vs Naive +6.07x +11.24x

The naive cache alone gives ~12x (it minimizes I/O amplification); warp coalescing + reference reuse adds another 6-11x on top.

SSD-type sensitivity (Figure 9): with consumer Samsung 980pro SSDs, BaM is on average 3.21x (BFS) / 2.68x (CC) slower than with Optane — yet 980pro is "by far the lowest cost," so the trade is explicit. Datacenter Samsung DC PM1735 (S1735) performs similarly to Optane (both hit similar 4 KB read IOPs).

5.6 Data analytics vs RAPIDS (§5.3, Figure 12)

Query / config BaM result
Q0 (single SSD) 1.22x over RAPIDS (even with dataset preloaded in CPU mem)
Q1-Q5 (more data-dependent) advantage grows with data-dependence
4-SSD BaM, peak up to 5.3x faster than RAPIDS
End-to-end scaling 1.46x (2 SSDs) / 1.62x (4 SSDs)

The gain source is reduced I/O amplification (on-demand fetch of only the touched columns) plus reduced GPU-memory-management overhead (RAPIDS pays CPU software overhead even with data preloaded). The advantage grows as queries become more data-dependent, because RAPIDS must move whole columns while BaM fetches on demand.

5.7 Cache-size and queue-pair sensitivity (§5.3, Figures 10-11)

Sweep Finding
Cache 1 GB vs 8 GB (K) No degradation at 1 GB — locality captured
Cache 32-64 GB (K) Holds entire working set -> only cold misses
Queue pairs 128 -> 48 No degradation
Queue pairs 40 -> 32 Starts degrading (queue contention + NVMe serialization)

The 1 GB cache matching 8 GB performance is the locality argument: the working set fits, so a tiny cache suffices. The 40-queue-pair knee is the structural floor — below it, NVMe protocol serialization per queue starts to bite.

5.8 Cache-overhead and floor analysis (§5.2)

Config BaM cache overhead (vs ideal)
Single SSD 2-15%
Four SSDs 4-45%

With more SSDs the cache overhead share grows (metadata contention, long-latency atomics, warp scheduling under polling) — but BaM still beats the most-optimistic baseline. The floor is the storage I/O throughput (5-6.2 M IOPs, >80% of peak storage throughput); past this, more SSDs do not help and only application modification can.

5.9 vectorAdd (write-intensive, §5.4)

BaM is 1.51x slower than the proactive-tiling baseline on this write-intensive workload, because BaM does not yet overlap read-miss handling with write-back — it exposes the full write latency. This is an honest negative result with a named fix (asynchronous write-back, left as future work).

5.10 Register / SM utilization (§5.5, Figure 13)

App Regs w/o BaM Regs w/ BaM
BFS 28 68
CC 36 66
RAPIDS Q0 12 90
RAPIDS Q5 21 255
vectorAdd 32 112

BaM raises per-thread register usage substantially (up to 255 for RAPIDS Q5), causing register spilling in RAPIDS — but because all workloads are storage-I/O-bound, the reduced occupancy does not bottleneck performance. The hardware resource that matters is I/O, not registers.


6. Configuration-Regime Trade-off Tables

6.1 GPU-initiated (BaM) vs CPU-centric baseline

Dimension CPU-centric (GDS / page-fault) BaM (GPU-initiated) Winner
Who initiates I/O CPU (host round trip) GPU thread directly BaM
Fine-grained (<32 KB) PCIe sat. No (24% at 4 KB) Yes (~100% at 4 KB) BaM
I/O amplification High (over-fetch, can't predict) Low (on-demand) BaM
CPU-GPU sync overhead Per-transfer None on hot path BaM
Write-back overlap (tiling overlaps) Not yet (1.51x slower) CPU-centric (writes)
Compute/I/O overlap Coarse (tile granularity) Fine (per-thread) BaM

For an accelerator-centric stack, prefer GPU-initiated access for any data-dependent, fine-grained, read-dominated workload; the only regime where the CPU-centric tiling baseline still wins is pure write-intensive workloads, until asynchronous write-back lands.

6.2 Storage media regime (Table 2 + Figure 9)

Dimension Optane P5800X Z-NAND PM1735 NAND (980pro) Winner
512 B/4 KB IOPs 5.1M / 1.5M 1.1M / 1.6M 700-800K Optane
Latency O(10) us O(25) us O(100) us Optane
$/GB 2.54 2.64 0.51 NAND
Cost gain vs DRAM 4.4x 4.3x 21.8x NAND
BFS/CC perf baseline ~similar (S1735) 3.21x/2.68x slower Optane (perf)

For performance, prefer Optane (lowest latency -> smallest queue depth via Little's Law). For cost, prefer NAND — BaM still functions, just slower, and the 21.8x cost advantage may dominate the decision for capacity-bound deployments.

6.3 Cache-mode regime (Figure 8)

Dimension No cache Naive cache Optimized (coalesce+reuse) Winner
I/O amplification Highest Low Lowest Optimized
BFS speedup 1x 11.9x ~72x (11.9 x 6.07) Optimized
CC speedup 1x 12.65x ~142x (12.65 x 11.24) Optimized
Warp probe cost per-thread per-line parallel groups Optimized
App code effort None None Some (must exploit locality) Naive (if effortless)

Prefer the Optimized cache mode whenever the application has warp- level locality to exploit — the bulk of BaM's software value lives in the gap between Naive and Optimized, and it requires the application to expose coalescable access patterns.

6.4 Scale-out regime (number of SSDs)

Dimension 1 SSD 4 SSDs 10 SSDs Winner
BFS vs Target T 1.43x slower 1.00x (on par) (PCIe-bound) 4+ SSDs
CC vs Target T 1.27x slower 1.49x faster (PCIe-bound) 4+ SSDs
Raw read IOPs (512B) ~5M ~18M 45.8M (90% PCIe) 10 SSDs
Cache overhead share 2-15% 4-45% grows 1 SSD (overhead)
Cost lowest medium highest 1 SSD

Prefer enough SSDs to saturate PCIe (≈4 for graph analytics, ≈10 for raw 512 B IOPs). Beyond the PCIe ceiling, additional SSDs are wasted; below it, BaM is bandwidth-starved and loses to host memory.


7. Bottlenecks & Insights Surfaced by the Measurements

7.1 The bottleneck is PCIe, not BaM's software

22.9 GBps at 45.8 M IOPs is 90% of measured Gen4 x16 peak — BaM's queue protocol and cache are not the limiter once enough SSDs are attached. This is the single most important measurement: it certifies that the software stack scales to the hardware ceiling, which is the whole claim of the paper. The corollary is that BaM's value will grow on PCIe Gen5 / NVLink-attached storage, where the ceiling is higher.

7.2 The CPU software stack is the real enemy of fine-grained I/O

GDS at 4 KB reaches only 23.6% of PCIe bandwidth; BaM reaches ~100%. The delta is entirely CPU software overhead (OS page-fault handler, kernel crossing, driver). The insight generalizes: as device latency drops (Optane, Z-NAND), software overhead becomes a larger fraction of total I/O time — the authors cite up to 36.4% for an optimized io_uring CPU stack. Removing the CPU from the path is therefore the right lever precisely because storage got fast.

7.3 Little's Law sets the queue-depth requirement, and only the GPU

can meet it

Sustaining peak throughput on high-latency consumer SSDs needs ~16,524 concurrent in-flight requests. No CPU can keep that many requests in flight; the GPU's thousand-fold thread-level parallelism is the only hardware that can. The GPU is not just a faster initiator — it is the only initiator that can hide modern SSD latency at peak throughput. This reframes BaM from "convenience" to "necessity."

7.4 Critical-section minimization is what unlocks the parallelism

The naive design (lock + enqueue + doorbell ring) would serialize thousands of threads on the doorbell write. BaM's ticket/turn protocol

7.5 I/O amplification is the data-analytics win, not raw bandwidth

Against RAPIDS, the 1.22x-to-5.3x advantage comes from fetching only the touched columns on demand rather than moving whole columns. The advantage grows with data-dependence (Q0 -> Q5) because that is exactly when over-fetching hurts most. The lesson: for irregular, data-dependent workloads, the right metric is bytes-actually-needed / bytes-moved, and on-demand fine-grained access optimizes it directly.

7.6 The honest negative: write-back latency is unhidden

vectorAdd's 1.51x slowdown is the one place BaM loses, and the authors name the cause precisely: no overlap between read-miss handling and write-back, so the full write latency is exposed. This is a clean, falsifiable bottleneck with a named remedy (async write-back), and its inclusion strengthens the paper's credibility.

7.7 Locality means a tiny cache suffices

A 1 GB cache matches an 8 GB cache on the K dataset. The working set's spatial/temporal locality is captured at 1 GB; the rest is cold misses that no cache size fixes. This argues against over-provisioning scarce GPU HBM for caching — small caches plus on-demand fetch beat large caches plus preloading.


8. Limitations of the Methodology

Limitation Consequence / scope note
Single A100-80GB GPU, single PCIe x16 link Multi-GPU / NVLink-attached storage untested; PCIe ceiling is the only ceiling measured
Bare-metal, direct NVMe (no virtualization) Security/isolation of user-level queues acknowledged but deferred to "trusted services" model
No asynchronous write-back Write-intensive workloads (vectorAdd) regress 1.51x; full write latency exposed
GPUDirect RDMA write-ordering caveat P2P writes not ordered without a following PCIe read; BaM pays 100% overhead on the I/O-consistency dual-submit path, mitigated to <8% via shared global virtual queue
Read-miss / write-back not overlapped Named as future work; current numbers are a lower bound for writes
Custom PCIe expansion chassis required Result depends on H3 Platform Falcon-4016 + PCIe bifurcation; not a stock-server result
Workloads: graph + data analytics + vecAdd No GNN, no recommender, no full RAPIDS pipeline timed end-to-end despite motivation citing them
RAPIDS preloaded into CPU page cache Favorable to RAPIDS (no storage I/O for baseline), so BaM's win is conservative
Register pressure up to 255 (RAPIDS Q5) Occupancy drop tolerated only because workloads are I/O-bound; compute-bound kernels untested
Cache-line size fixed per workload (4 KB) Limited granularity sweep for the application workloads (raw sweep is broader)
Floor at storage throughput (5-6.2 M IOPs) Past this, BaM cannot improve without application changes — an inherent ceiling, not a tuning knob

The most consequential scoping limit is the single-GPU, single-PCIe- link setup: every result is a story about saturating one link from many SSDs. The multi-GPU regime — where storage bandwidth must be shared or partitioned across GPUs, and where NVLink could change the ceiling entirely — is entirely future work. The second is the write-back gap, which is the one regime BaM loses and which the authors correctly flag rather than hide.


9. Analogy

BaM is a just-in-time warehouse-to-workshop delivery system that lets each individual worker order parts directly, instead of routing every order through a single dispatch manager.

In the CPU-centric world (GDS, page-fault tiling), there is one dispatch manager (the CPU). Every time a worker (GPU thread) needs a part (data), the worker stops, raises a hand, and waits for the manager to walk to the warehouse, guess which crate of parts might be needed, haul the whole crate back (I/O amplification — over-fetching), and hand it over. With thousands of workers, the manager is mobbed; the factory floor idles waiting on one overworked dispatcher. Worse, the manager cannot read the workers' minds, so the crates are full of parts nobody asked for.

BaM rips out the dispatcher. Now each worker holds a direct order terminal wired straight to the warehouse loading dock (the SSD doorbell mapped into GPU address space). A worker who needs a single bolt orders exactly that bolt (fine-grained, on-demand), and a fleet of forklifts (SSD DMA engines) deliver it straight to that worker's bench (P2P DMA into GPU memory) — never passing through the manager's office.

But a thousand workers all slamming order buttons at the same dock would jam the loading-dock paperwork (the doorbell write). So BaM adds a deli-counter ticket machine (the ticket/turn protocol): you grab a numbered ticket, and when your number is called you drop your order in the bin — and one runner (the move_tail winner) carries a whole batch of orders to the dock in a single trip, so the dock is rung once, not a thousand times. Next to the dock sits a shared parts shelf (the software cache): if the bolt you need is already on the shelf because a neighbor just ordered it, you take it off the shelf instantly (cache hit, lock-free) instead of bothering the warehouse at all — and workers reaching for the same shelf box elect one person to fetch for the group (warp coalescing).

The economics close the analogy: the warehouse (cheap NVMe SSDs) is far cheaper per part than keeping every part on the expensive workbench itself (DRAM) — 4x-22x cheaper per part. As long as enough forklifts (SSDs) feed the single delivery corridor (PCIe x16) fast enough to keep it full, the workshop runs as fast as if every part were already on the bench, at a fraction of the cost. The one thing the new system has not yet solved is shipping finished parts back out (write-back) while still receiving new ones — for now, outbound and inbound share the corridor serially, which is the single case where the old crate-hauling manager was actually faster.