4.1–4.1.1Scratchpad Memory & the L1 Data Cache

Book pp. 67–72 · ~4 min read

  • local memory
  • memory coalescing
  • shared-memory bank conflict
  • pending request table (PRT)
  • virtually-tagged L1

Chapter 3 built the cores; this chapter feeds them. Kernels touch memory through loads and stores against a subdivided address space: local memorylocal memoryPer-thread private memory space, used mostly for register spills and stack data; cached write-back in L1.Glossary → (per-thread — mostly register spills), global memoryglobal memoryThe address space accessible to all threads; slower and more energy-costly than shared memory; the only way threads in different CTAs communicate.Glossary → (shared data structures), and the programmer-managed shared memoryshared memoryNVIDIA's name for the per-SM scratchpad (16–64 KB), declared with __shared__; a software-controlled cache.Glossary → scratchpad. The motivation is brutal economics: DRAM bandwidth is tiny next to instruction throughput, and off-chip transfers cost orders of magnitude more energy than on-chip accesses (remember Table 1.1) — so the programmer who stages data on-chip wins twice.

The two programmer-visible hazards

Two access patterns dominate GPU memory performance, and both come down to how a warp’s 32 addresses relate to each other. For global memory, the question is whether they fall in the same cache block — coalescingmemory coalescingMerging a warp's per-thread global accesses that fall in one cache block into a single memory request; uncoalesced access = multiple requests.Glossary →:

Global access: coalesced vs. scatteredcycle 0 / 6

warp lanes → addresses

t00
t14
t28
t312
t416
t520
t624
t728
t8256
t9260
t10512
t11516
t12768
t131024
t141280
t15

memory transactions issued

block @0(8 lanes)
block @256(2 lanes)
block @512(2 lanes)
block @768(1 lane)
block @1024(1 lane)
block @1280(1 lane)

Step to issue the first transaction/round.

One tick = one 128-byte memory transaction issued for this 16-lane toy warp. Lanes 0–7 coalesce into one block; the scattered tail lanes each drag in their own.

For shared memory (one 32-bit bank per lane, one read + one write port each), the question is whether two threads hit different rows of the same bank — a bank conflictshared-memory bank conflictTwo threads targeting different locations in the same shared-memory bank in one cycle; the arbiter splits the access and replays the conflicting part.Glossary →:

Shared access: bank conflicts → replay roundscycle 0 / 2

warp lanes → addresses (bank = word mod 8)

t00
t14
t28
t312
t432
t536
t640
t744

access rounds (conflicts → replay)

accepted(4 lanes)
replay 1(4 lanes)

Step to issue the first transaction/round.

One tick = one access round on an 8-bank toy scratchpad. Lanes 0–3 and 4–7 collide pairwise (addr mod 32 equal), so the arbiter serves half and REPLAYS the rest.

Programmers avoid both; the hardware tolerates both — that tolerance is the story of Fig 4.1.

4.1.1 One SRAM, two personalities

Fermi and Kepler implement shared memory and the L1 data cache as one configurable SRAM array: partly direct-mapped (shared), partly set-associative (cache) — early NVIDIA patents even call shared memory a “Global Register File,” and its latency is register-file-like. The surrounding machinery gives the instruction pipeline a non-stalling interface: hazards become replays, never stalls. Walk all four operation types through the numbered datapath:

The unified L1 (Fig 4.1), four operationscycle 0 / 12
Load/Store Unit ①Arbiter ②Tag Unit ③Pending Request Table ⑦Address Crossbar ④Data Array ⑤ (32 banks)MMU ⑧Fill Unit ⑨Write Buffer ⑩Data Crossbar ⑥Register Fileshared ld

step 0SHARED-MEMORY LOAD: the LSU sends one address per thread plus the operation type to the L1 block.

One tick = one step through the unified L1's datapath (Fig 4.1's numbered blocks). Four operations play in sequence: shared-memory access, coalesced hit, miss, and a write.

Details worth pinning down:

  • Shared accesses bypass the tag unit (direct-mapped, constant latency), which is what lets the arbiter schedule the register-file writeback at accept time. The banks’ independent decoders are why arbitrary per-lane rows work at all.
  • Global accesses are one cache block per cycle — 128-byte blocks (Fermi/Kepler), split into four 32-byte sectorssector32-byte quarter of a 128-byte cache line, matching the GDDR5 access atom; Maxwell/Pascal L1s and L2 slices are sectored.Glossary → from Maxwell/Pascal on, matching the GDDR5 access atom. Less tag overhead, DRAM-shaped requests.
  • The pending request tablepending request table (PRT)The GPU L1's MSHR-like structure: merges misses to the same block and remembers which deferred access to replay when the fill returns.Glossary → is the GPU’s take on the classic MSHRMSHRMiss-status holding register: tracks an outstanding cache miss so further misses to the same line merge instead of replaying to memory.Glossary →: merge same-block misses, remember which deferred access to replay, find it again via the request’s subid when the fill returns — and the fill unit locks the line so the replayed load cannot miss twice.
  • The L1 is virtually indexed and virtually taggedvirtually-tagged L1GPU L1s are virtually indexed AND tagged (unlike CPU VIPT): no per-cycle translation needed, acceptable because all warps share one address space.Glossary →. CPUs avoid VIVT because context switches force flushes — but every warp on a GPU belongs to the same application, so the GPU takes the faster, simpler option (keeping page-based virtual memory for allocation simplicity and fragmentation control).
  • Writes match their space’s locality: global stores → write-through, no-allocate (kernels stream results out and exit); local-memory spills → write-back, write-allocate (they’ll be re-read). Store data stages in the write data buffer; fully-covering coalesced writes may bypass the cache entirely (invalidating stale tags on the way).
  • There is no L1 coherence. SM 1 can happily read a stale copy of a location SM 2 just wrote. NVIDIA’s Kepler-era answer: only spills, stack data, and read-only global data may live in L1. (Research on coherent GPU L1s and properly defined GPU memory consistency models is ongoing — the book cites Singh et al., Ren & Lis, Alglave et al.)

Check yourself

  1. 1. Predict the transactions (use the coalescing widget): 8 threads access addresses 0,4,8,…,28 (consecutive words). With 128-byte blocks, how many memory requests leave the core?

  2. 2. How does the unified L1 handle a shared-memory bank conflict WITHOUT stalling the pipeline?

  3. 3. Why can a GPU L1 be virtually indexed AND virtually tagged when CPU L1s usually aren't?

  4. 4. A load misses, and moments later a second load wants the SAME block. What does the PRT do?

  5. 5. Why write-through with NO write-allocate for global-memory stores?

0 / 5 correct · 5 unanswered