5.4.7 · D4Memory Hierarchy & Caches

Exercises — Write-allocate vs no-allocate

2,434 words11 min readBack to topic

Before we start, let us fix the tiny vocabulary we will lean on the whole page. Every one of these was built in the parent note; here we just pin them down so no symbol arrives unannounced.

We measure everything in memory traffic: the number of read/write operations that actually cross from cache down to main memory. Fewer is better, because main memory is slow.


Level 1 — Recognition

L1.1 For each phrase, name the policy (write-allocate or no-allocate): (a) "fetch-on-write" (b) "write-around" (c) "the written data bypasses the cache" (d) "on a write miss we load the whole 8-byte block, then modify one byte".

Recall Solution L1.1
  • (a) Write-allocate — "fetch on write" is its literal other name.
  • (b) No-allocate — data goes around the cache.
  • (c) No-allocate — bypass = around.
  • (d) Write-allocate — loading the whole block before modifying is the defining move.

L1.2 True or false: "Write-back is almost always paired with write-allocate."

Recall Solution L1.2

True. Write-back keeps the only up-to-date copy inside the cache (marked dirty) and writes to memory later, at eviction. To hold a dirty copy you must first have a line — which is exactly what write-allocate provides. Pairing write-back with no-allocate leaves nowhere to store the deferred write, forcing an immediate memory write (i.e. write-through behaviour). See Write-back vs Write-through.


Level 2 — Application

Use this fixed setup for L2 (same as the parent's examples):

  • Cache: 4 lines, 8 bytes/line, direct-mapped, initially empty.
  • Line index rule: (drop the low 3 bits to get the block number, then take it mod 4).

L2.1 Under write-allocate + write-back, you do WRITE 0x28. List the memory traffic and the final state of line 1 (valid? dirty?).

Recall Solution L2.1
  1. Which line? . . . → line 1.
  2. Line 1 is invalid → write miss.
  3. Write-allocate: fetch the 8-byte block 0x280x2F from memory. → 1 read.
  4. Write the byte at 0x28 into the cached line.
  5. Write-back: don't touch memory now; set dirty = 1. Memory traffic: 1 read. Final line 1: valid = yes, dirty = yes.

L2.2 Same write 0x28 but under no-allocate + write-through. Traffic and final state of line 1?

Recall Solution L2.2
  1. Line 1, invalid → write miss.
  2. No-allocate: do not fetch, do not allocate.
  3. Write-through: send the write straight to memory. → 1 write. Memory traffic: 1 write. Final line 1: still invalid (valid = no).

L2.3 For each policy above, a READ 0x29 immediately follows the write. Hit or miss, and why?

Recall Solution L2.3
  • 0x29 is in the same block as 0x28 (both in 0x280x2F).
  • Write-allocate case: the block is already in line 1 → hit, 0 memory traffic. This is spatial locality paying off (see Temporal vs Spatial Locality).
  • No-allocate case: the block was never brought in → miss, must fetch the block now (1 read).

Level 3 — Analysis

L3.1 Same setup. Consider the sequence WRITE 0x100, WRITE 0x104, WRITE 0x108, WRITE 0x10C, READ 0x100 (all four addresses are in one 8-byte block? Check this!). Count total memory traffic under write-allocate + write-back vs no-allocate + write-through.

Recall Solution L3.1

First, block check. Block number = address .

  • 0x100 = 256, .
  • 0x104 = 260, .
  • 0x108 = 264, . Different block!
  • 0x10C = 268, .

So 0x100,0x104 are in block 32; 0x108,0x10C are in block 33. The parent note's Example 3 casually said "all in same block" — with an 8-byte line that is false. We correct it below. (See the figure.)

Figure — Write-allocate vs no-allocate

Write-allocate + write-back:

  • WRITE 0x100: miss → fetch block 32 (1 read), write, dirty.
  • WRITE 0x104: hit (block 32 present) → 0.
  • WRITE 0x108: miss → fetch block 33 (1 read), write, dirty.
  • WRITE 0x10C: hit → 0.
  • READ 0x100: hit → 0. Blocks 32 and 33 map to lines and — different lines, no eviction, no write-back yet. Total: 2 reads, 0 writes = 2 operations.

No-allocate + write-through:

  • Every write is a miss and goes straight to memory: 4 writes.
  • READ 0x100: never cached → miss, 1 read. Total: 1 read + 4 writes = 5 operations.

Write-allocate wins 2 vs 5, because it amortised each fetched block over the two writes that hit it and the final read.

L3.2 Now suppose the cache line were 16 bytes instead of 8. Redo the write-allocate + write-back count for the same four writes + read.

Recall Solution L3.2

With a 16-byte line, block number = address .

  • 0x100: .
  • 0x104,0x108,0x10C: . All in block 16! So:
  • WRITE 0x100: miss → 1 read, dirty.
  • next three writes: all hits → 0.
  • READ 0x100: hit → 0. Total: 1 read. Bigger lines captured more spatial locality here — one fetch covered all four. This is the direct link to Cache Line Size.

Level 4 — Synthesis

L4.1 A frame-buffer loop writes 1920×1080 pixels once each, never reads them, then the program moves on. Which allocation + write policy, and estimate the cache-pollution damage of the wrong choice.

Recall Solution L4.1

Choose no-allocate + write-through (equivalently, use non-temporal / Streaming Stores). Why: each pixel is written once and never re-read → zero temporal locality, so caching buys nothing. Pollution damage of write-allocate here: the buffer is pixels. Say 4 bytes/pixel = bytes. With 64-byte lines that is distinct blocks streamed through the cache. A typical L1 holds only a few hundred lines — so the entire cache is flushed and refilled with garbage the program will never touch again, evicting genuinely useful data. That is Cache Pollution. No-allocate sends the pixels around the cache untouched, and Write Combining Buffers coalesce them into full-line bursts. See Streaming Stores.

L4.2 Explain, from first principles, why "write-back + no-allocate" is a self-contradiction. Do it as a 3-step deduction.

Recall Solution L4.2
  1. Write miss to A. We must eventually get the new value of A into memory.
  2. No-allocate says: don't create a cache line for A. So the modified value has no home inside the cache.
  3. Write-back says: defer the memory write until the (dirty) line is evicted. But step 2 gave us no line to hold and no dirty bit to set — there is nothing to defer from. With no place to store and no way to defer, the write must go to memory immediately. But "write to memory immediately on a hit-or-miss write" is the definition of write-through. So "write-back + no-allocate" silently becomes write-through — it cannot exist as its own policy. Hence write-back requires write-allocate.

Level 5 — Mastery

L5.1 Design decision with numbers. You are choosing between write-allocate and no-allocate for a write-heavy region. Costs (in cycles): fetch a block , write into cache , write straight through to memory . Let be the probability that, after a write miss, the block is reused (read or written again) at least once before eviction — and assume one reuse saves you exactly one that no-allocate would have paid.

Derive the threshold probability above which write-allocate is the cheaper policy, and evaluate it.

Recall Solution L5.1

Set up per-write-miss expected cost.

  • No-allocate: every access to the (uncached) region costs a through-write. The initial miss costs , and if reuse happens it costs another . Expected cost .
  • Write-allocate: pay the fetch once () plus a cheap cache write () on the miss; if reuse happens it is a cheap cache access instead of . Expected cost .

Write-allocate cheaper when Group the terms: So Plug in : Interpretation: because a through-write is as expensive as a fetch here, write-allocate only needs about a 1% reuse chance to win. High-fetch / low-reuse is the only regime where no-allocate dominates. This matches the parent's decision-framework inequality up to the small correction in the denominator.

L5.2 Sanity-check the framework: if fetching were free () with the same , what is , and what does its sign tell you?

Recall Solution L5.2

A negative threshold means "write-allocate wins even for " — since probabilities can't be negative, the condition is always true. Reading: if fetching costs nothing, always allocate, because you gain a possibly-cheaper future access at no downside. The sign of is a quick "is one policy unconditionally better?" test.

Recall Quick self-test clozes

Write-allocate on a miss first fetches the whole block, then writes. No-allocate sends the write around the cache to memory. Write-back must pair with write-allocate because it needs a line to hold the dirty copy. The right policy for a write-once frame buffer is no-allocate to avoid cache pollution.

Related: Write-back vs Write-through · Cache Line Size · Temporal vs Spatial Locality · Streaming Stores · Cache Pollution · Write Combining Buffers · Dirty Bit