5.4.7 · D5Memory Hierarchy & Caches

Question bank — Write-allocate vs no-allocate

1,431 words7 min readBack to topic

Quick vocabulary refresh so every line below is readable from zero:


True or false — justify

Write-back caches are almost always paired with write-allocate.
True. Write-back defers writes and tracks them with a Dirty Bit inside the cache line; if a write miss did not allocate a line, there would be nowhere to hold the dirty data, forcing an immediate memory write — which is just write-through in disguise.
No-allocate can only be paired with write-through.
True in practice. Without a line to mark dirty, the write has nowhere to "wait," so it must be pushed to memory now — that is exactly write-through behaviour. See Write-back vs Write-through.
Write-allocate always lowers total memory traffic.
False. It lowers traffic only when the fetched block is reused (read or written again). For a one-shot streaming write, the fetch is pure wasted bandwidth — you read a block just to overwrite it and never touch it again.
No-allocate never brings any data into the cache on a write.
True by definition — that is the whole point. The written bytes travel "around" the cache to the lower level, so a later read of that same block will still miss.
A single write-allocate on a 64-byte line still fetches all 64 bytes even for a 1-byte store.
True. Caches manage data at Cache Line Size granularity, so the whole block is fetched to keep the line coherent and to serve future reads of neighbouring bytes.
Write-allocate benefits come from temporal locality only.
False. It exploits both: temporal locality (you write/read the same byte again) and spatial locality (later accesses land on neighbouring bytes already in the fetched block).
Non-temporal / streaming store instructions implement write-allocate.
False. They implement no-allocate precisely to bypass the cache and avoid Cache Pollution — see Streaming Stores.
Choosing no-allocate can never hurt performance.
False. If the write is actually followed by a nearby read soon after, no-allocate turns what would have been a hit into a miss, costing a full memory read latency.

Spot the error

"With write-back + no-allocate, we just hold the write in the cache line and flush it later."
Error: no-allocate means no line is allocated, so there is no line to hold or flush. The write must go to memory immediately, which contradicts the "flush later" premise.
"Write-allocate is faster on the missing write itself because the data ends up in cache."
Error: on the miss itself write-allocate is slower — it must fetch the block first (read latency) before writing. The payoff comes only on subsequent accesses.
"No-allocate saves bandwidth because it never touches memory."
Error: no-allocate still writes the data to the lower level, so it does touch memory. What it saves is the extra read (block fetch) that write-allocate would perform.
"Since the frame-buffer loop writes every byte, write-allocate is fine — we overwrite the fetched block anyway."
Error: you overwrite it, yes, but you still paid to fetch it first, and you evicted useful data to make room — double waste with zero reuse. No-allocate is correct here.
"Write-through + write-allocate is pointless because you write to memory anyway."
Error: it is not pointless — allocating the block means future reads of that block hit in cache. The write cost is unchanged, but read locality is captured.
"A write miss under write-allocate sets the dirty bit under any write policy."
Error: the Dirty Bit is only meaningful under write-back. Under write-through the data is already in memory, so nothing is "dirty."

Why questions

Why does write-back need the block in cache?
Because write-back's whole savings come from marking a line dirty and deferring the memory write; a dirty flag has meaning only on a resident line, so the line must exist — hence write-allocate.
Why does no-allocate reduce cache pollution?
One-time writes never get a cache line, so they cannot evict data that will actually be reused — the cache's precious lines stay dedicated to hot data. See Cache Pollution.
Why does write-allocate turn a run of writes to one block into a single memory read?
The first write misses and fetches the block; every following write to that same block now hits, and under write-back nothing is flushed until eviction — so the entire run costs just that one read.
Why do streaming writes prefer no-allocate even though later reads will miss?
Because streaming data is written once and (essentially) never read again, so there is no "later read" to protect — the fetch and eviction costs of allocating would buy nothing. Write Combining Buffers can further batch these writes.
Why does the decision hinge on P(reuse | write)?
Because write-allocate's fetch cost is only recouped if the block is used again; the higher the probability of reuse, the more likely the saved future misses outweigh the up-front fetch.
Why can no-allocate have lower latency on the missing write?
It writes straight to memory without waiting for a block fetch, so the store is not blocked behind a read — whereas write-allocate must read-then-write.

Edge cases

You write to a block that is already in cache (a write hit). Does allocate/no-allocate matter?
No — both policies only differ on a write miss. On a hit the line already exists, so the write simply updates it regardless of allocation policy.
You write every byte of a full line with no-allocate + Write Combining Buffers. Any fetch needed?
No fetch is needed even conceptually, since the whole line is being overwritten — combining buffers gather the partial writes and push a full line to memory, avoiding a read-for-ownership.
Under write-allocate, you write 1 byte of a 64-byte line. What is the cache state right after?
The full 64-byte block is fetched, that 1 byte is updated, and (under write-back) the line is marked valid and dirty; the other 63 bytes hold their memory values.
A workload writes a huge array once, then reads it back much later after it has been evicted. Allocate or not?
No-allocate is fine — by the time the reads happen the block would have been evicted anyway, so allocating on the write bought nothing but pollution during the write phase.
memset(buf, 0, HUGE) followed immediately by heavy reads of buf. Allocate or not?
Write-allocate here — the immediate reuse means the initialized blocks stay hot and the reads hit, so paying the allocate cost is worth it (this is the opposite of the streaming case).
Degenerate case: a cache with only write-through and no-allocate. Can a line ever become dirty?
No — every write goes straight to memory and misses never allocate, so no resident line is ever "ahead" of memory; the dirty concept simply does not arise.
Recall One-line summary to lock in

Reuse soon ::: prefer write-allocate (fetch pays off). Write once, never reuse ::: prefer no-allocate (avoid fetch + pollution). Write-back ::: forces write-allocate. No-allocate ::: forces write-through-style immediate writes.