The memory wall and the illusion of a fast, big memory

After this lesson you will explain why a small SRAM cache makes a large, slow DRAM look fast, name the kind of locality behind every hit, derive AMAT = hit time + miss rate × miss penalty from scratch, and choose between a split and a unified first-level cache with numbers.

Main memory is far from the processor. The notes' Example 3 charges 100 clock cycles to bring a block from it, and a real DRAM access takes about 100 ns, which a 3 GHz core spends as 300 cycles. A loop that went to memory for every number it touches would wait a hundred cycles per number. Yet with a cache that holds a tiny slice of memory, the same example finds 6 cycles per access on average. Where did the other 94 go?

The second puzzle is the notes' Example 6 (p. 258). Two first-level caches of the same total size, 32 KB: one unified, one split into an instruction half and a data half. The unified one misses on 1.99% of the accesses, the split one on 2.10%. The unified one is the slower of the two.

Both puzzles have short answers, and by the end of the lesson you will give them with numbers.

The memory wall: fast or big, never both

Every programmer wants the same thing; the notes (p. 297) put it as "an unlimited amount of memory, as fast as the CPU". Physics and price say no: a memory can be fast or big, and the two qualities come from different technologies.

The fast one is SRAM, static RAM; the big one is DRAM, dynamic RAM. They differ already in how one bit is stored, and everything else follows from that:

The two technologies of the hierarchy: the cells as Hennessy & Patterson describe them, the roles as the notes give them (p. 301).
SRAM, static RAMDRAM, dynamic RAM
one bit issix transistors that hold the value while the power is onone transistor and a tiny capacitor whose charge leaks, so it must be refreshed
speedfast: 1–4 cycles in an L1slower: 60–100 ns per access
per bitlarge and expensivedense and cheap
used forthe caches, "small, fast, but expensive"main memory, SDRAM and DDR chips included, "larger, slower, but cheaper"

The notes pair them this way on p. 301, after a slip four pages earlier:

The way out is a stack of memories, the memory hierarchy: each level faster and smaller than the one below, slower and larger than the one above, each holding a subset of the data of the level below (p. 297). The notes' Example 1 (p. 299) is a student's books: the most-used ones on the desk (L1), others on the shelf in the room (L2), the rest in the university library (main memory), the rarest in the city archive (disk). "If we're smart about what to keep close (using locality), we'll avoid most slow trips."

Registers L1 · SRAM L2 · SRAM L3 · SRAM Main memory · DRAM SSD / disk latency ≈ 0.3 ns 1–4 cycles 10–20 cycles 30–60 cycles 60–100 ns 50 µs–10 ms managed by compiler hardware OS fast, small, costly slow, big, cheap
Fig. 1. The hierarchy, top to bottom: each level is faster, smaller and costlier per bit than the one below. The figures are typical values from Hennessy & Patterson (ch. 2), not from the notes: L1 16–64 KB per core, L2 256 KB–2 MB, L3 several to tens of MB shared, main memory gigabytes; cycle counts at a clock of a few GHz.

And the distance between the top and the bottom grew for decades. In Hennessy & Patterson's plot of the processor–memory gap, processor performance rises by about 50% a year from the mid-1980s to 2000, while DRAM latency improves by only about 7% a year.

William Wulf and Sally McKee named the gap in a five-page note, "Hitting the Memory Wall: Implications of the Obvious" (Computer Architecture News, March 1995). The obvious: two speeds that grow exponentially at different rates drift apart exponentially, so sooner or later waiting for memory dominates, whatever the hit rate of the caches.

The processor sees none of the pyramid. It has one address space and one LD instruction; whether the word comes from L1 in a cycle or from DRAM in a hundred is decided underneath it. That is the illusion of a large, fast memory (p. 297): almost as fast as the top, as large as the bottom.

Who keeps the illusion running? Not the programmer: "the hardware and compiler manage this automatically" (p. 298). Hennessy & Patterson split the work three ways. The compiler decides what lives in registers (register allocation); the hardware moves blocks between the caches and main memory, invisibly to the program; the operating system, with hardware help, moves pages between main memory and disk — virtual memory, lesson 27, the layer the notes' sentence leaves out.

Fast memory (SRAM) is small and expensive, big memory (DRAM) is slow and cheap; the hierarchy stacks them so that the processor sees one memory almost as fast as the top and as large as the bottom.

Why the illusion works: locality

The illusion is a bet on how programs behave. Take the loop the notes use on p. 298:

for (i = 0; i < 100; i++) sum += a[i];

Compile it with sum kept in memory, as the notes' comment assumes ("sum is read and written many times in a short span"), and one iteration is six instructions in the papers' mnemonics:

I0  LOOP: LD    F2, 0(R1)      ; F2 ← a[i]
I1        LD    F0, SUM(R0)    ; F0 ← sum
I2        FADD  F0, F0, F2     ; F0 ← sum + a[i]
I3        SD    F0, SUM(R0)    ; sum ← F0
I4        ADDUI R1, R1, 8      ; R1 → a[i+1], 8 bytes on
I5        BNE   R1, R2, LOOP   ; until R1 = R2

Write down the addresses the loop sends to memory. Data: a[0], SUM, SUM, a[1], SUM, SUM, a[2], … Instructions: I0, I1, …, I5, then I0 again. Two patterns jump out, and the notes name both (pp. 298 and 300):

Each kind is caught by its own mechanism (the table on p. 300). Temporal locality: keep what was used recently, and when something must leave, evict the block unused for the longest time — least recently used, LRU (lesson 23). Spatial locality: never move a single word; move a whole block, or line, "the smallest unit of data moved from main memory to cache", typically 32, 64 or 128 bytes. A 64-byte line holds eight of the loop's 8-byte elements: one trip to memory serves eight iterations.

a[0] … a[7], 8 bytes each memory cache loads 01234567 01234567 MMMMMMMM 8 trips to memory

Before: one-word blocks

a[0] … a[7], 8 bytes each memory cache loads 01234567 one 64-byte block 01234567 MHHHHHHH 1 trip, 7 hits

After: eight-word (64-byte) blocks

Fig. 2. The first eight loads of a[i]. With one-word blocks every load misses (M, orange) and makes its own trip to memory. With 64-byte blocks the first miss brings all eight elements, and the next seven loads hit (H, blue): spatial locality, caught by the block.

Hennessy & Patterson put a number on the effect: a program spends about 90% of its execution time in about 10% of its code, a hot loop fetched again and again from a handful of cache lines. In the probe below, the first program is this loop; the other two remove one kind of locality, then both.

Locality probe: which accesses hit, and why

Each row is one iteration, each column one memory instruction of the loop body, in the papers' mnemonics. A cell shows the word it touches and what happened: M a miss, T a hit on temporal locality (this very word was used before), S a hit on spatial locality (the word was never used, but a neighbour brought its block in). The cache is fully associative with LRU replacement; on the right, its blocks after the highlighted access, the one used last on top. A store that misses brings its block in too. Step through the 48 accesses or look at all of them at once.

  1. Program "sum += a[i]", block size 1 word. Before looking, predict which columns will be all misses and which will hit, and the hit rate over the 48 accesses.
    What you should see

    The LD a[i] column is all misses: every element is new, and a one-word block brings nothing else. Both sum columns hit from the second access on, all T: the cache keeps the block of sum. 17 misses, 31 hits: 64.6%. Temporal locality alone, caught by keeping blocks.

  2. Same program: raise the block size to 2, 4, then 8 words. Predict the new hit rate each time and which letter appears in the first column.
    What you should see

    81.3%, 89.6%, 93.8%. The first column now misses once per block and shows S for the other elements: one miss brings the neighbours. The two sum columns do not change. Each kind of locality has its own mechanism: retention for temporal, multi-word blocks for spatial.

  3. Block size 4, capacity 1 block. What happens to the LD sum column? Then try 2 blocks.
    What you should see

    With one block, a[i] and sum keep evicting each other: LD a[i] and LD sum miss in every iteration, only the store right after LD sum hits, and the hit rate falls to 33.3%. With two blocks LRU keeps both and you are back to 89.6%. Retention needs room, and LRU decides who stays.

  4. Set the capacity back to 4 blocks. Switch to "b[i] = a[i] + c[i]" and then to the random program, and try every block size. Predict each time before you look.
    What you should see

    Three arrays, each element used once: no T at all. With one-word blocks the hit rate is 0%; with 2, 4, 8 words it is 50%, 75%, 87.5%, all S. (With 1 or 2 blocks it stays at 0% at every block size: three streams need three blocks, and each evicts the block the next access needs.) The random program has neither kind of locality: 48 misses at every block size, an AMAT of 101 cycles — more than going to memory directly. Without locality a cache is useless, and each kind of locality is caught by a different mechanism.

The probe's third program is the notes' warning made concrete (p. 298): "Without locality, caches would be useless: every access would go to slow memory." Locality belongs to the program, not to the cache, which is why "compiler optimizations and programming style matter" (p. 300).

"The programmer has no say in what the cache does." The programmer cannot choose the level, but chooses the order of the accesses. A matrix stored row by row and walked column by column jumps a whole row between consecutive accesses, so each block brought in serves one word. The compiler's fixes, loop interchange and blocking, are in lesson 25.

Temporal locality is caught by keeping blocks and evicting the least recently used; spatial locality by moving whole blocks. Without locality, a cache only adds its hit time.

What a cache is: blocks, hits and misses

Cache — "a small, fast memory located close to the processor that temporarily stores copies of data from the main memory, aiming to reduce the average time needed to access data and instructions" (notes, p. 301, Definition 1).

In a two-level picture the cache is the upper level, holding a subset of memory, and main memory the lower level, accessed only when the data is not in the cache: "a buffer between fast CPU and slow main memory". Everything moves in blocks, so the first thing to know is how many blocks a cache holds:

\[ \#\text{blocks} = \frac{\text{Cache size}}{\text{Block size}} \]
sizes
in the same unit, bytes or words; 1 KB = 1024 bytes
Example 2
a 64 KB cache with 16-byte blocks: 64 × 1024 / 16 = 65 536 / 16 = 4096 blocks

An access is a hit when the requested address is already in the cache, a miss when its block must be fetched from the level below. What does a miss cost? Follow the first load of the loop when the block holding a[4] is not in the cache; the notes (p. 301) list four consequences, numbered in Fig. 3:

CPU LD F2, 0(R1) a[4–7] cache memory a[4]? 2 fetch block 3 write block 4 retry: hit 1 stall hit time 1–3 cycles miss penalty 10s–100s of cycles
Fig. 3. One miss, the four steps of the notes (p. 301). The load asks for a[4]; its block, a[4] to a[7] with 32-byte blocks, is not in the cache. (1) The CPU stalls, (2) the cache fetches the whole block from memory, (3) writes it into one of its lines, (4) the load is retried and now hits. The hit time is paid by every access; the miss penalty only by misses.
  1. Stall the CPU. The load cannot complete, so the pipeline freezes: the same stall as for a hazard (lesson 2), only tens to hundreds of cycles long.
  2. Fetch the block that holds a[4] from memory, or from the next-level cache.
  3. Write the block into the cache.
  4. Retry the access, which now becomes a hit.

Two times describe the two outcomes (p. 302). The hit time is the time to access the cache, determine whether it is a hit and return the data. The miss penalty is the time to fetch the block from main memory or the next-level cache, update the cache and resume the CPU. A miss pays both, because the cache is looked up before it knows it missed:

What each outcome of an access costs (notes, pp. 301–302).
OutcomeWhat happensTime it costs
hitaccess the cache, determine that it is a hit, return the datahit time: typically 1–3 CPU cycles
missthe same lookup, then: stall the CPU, fetch the block, write it into the cache, retry the accesshit time + miss penalty; the penalty is often tens to hundreds of cycles

The notes call the cost of a miss the miss time (eq. 49):

\[ \text{Miss time} = HT + MP \]
\(HT\), \(MP\)
the notes' Hit Time and Miss Penalty; with HT = 1 and MP = 100, one miss costs 101 cycles

Counted over a run, hits and misses give two rates that add up to one (p. 257); HR and MR stand for the notes' Hit Rate and Miss Rate:

\[ HR = \frac{\#\text{hits}}{\#\text{accesses}} \] \[ MR = \frac{\#\text{misses}}{\#\text{accesses}} = 1 - HR \]
Why retry the access, instead of handing the word straight to the CPU?

Because it is the simplest controller: fill the line, then let the stalled load run again as an ordinary hit. Real caches are less patient: they pass the requested word to the processor as soon as it arrives (early restart, critical word first), and a non-blocking cache keeps serving other accesses during the miss. Both shorten the effective miss penalty; both are in lesson 26.

Maurice Wilkes described the idea in a two-page paper in 1965, as a "slave memory". The first commercially available computer with one was IBM's System/360 Model 85, announced in January 1968. Its engineers said "high-speed buffer", until the editor of the IBM Systems Journal found the name "too shopworn to do justice to innovation" and suggested "cache".

A hit costs the hit time; a miss costs the hit time plus the miss penalty, because the lookup is paid before the cache knows it missed.

AMAT: what one access costs on average

Count before you average. Take the notes' Example 3 (p. 302): hit time 1 cycle, miss rate 5%, miss penalty 100 cycles, and run 100 accesses. 95 hit and cost 1 cycle each: 95 cycles. 5 miss and cost 1 + 100 cycles each: 505 cycles. Together 600 cycles, 6 per access. That average is the average memory access time, AMAT, "the expected cost of accessing memory, accounting for both hits and misses". The derivation is the same count with letters (p. 303).

  1. Every access is either a hit or a miss. Weight the time of each case by its probability; the notes call this "the most general formula" (eq. 70), with MT the miss time:

    \[ \text{AMAT} = HR \cdot HT + MR \cdot MT \]
  2. A miss first checks the cache, exactly like a hit, then fetches the block (eq. 71):

    \[ MT = HT + MP \]
  3. Substitute and multiply out:

    \[ \begin{aligned} \text{AMAT} = {} & HR \cdot HT + MR \cdot HT \\ + {} & MR \cdot MP \end{aligned} \]
  4. The first two terms share the hit time. Factor it out:

    \[ \begin{aligned} \text{AMAT} = {} & HT\,(HR + MR) \\ + {} & MR \cdot MP \end{aligned} \]
  5. Hit or miss, nothing else: \(HR + MR = 1\). The bracket disappears, and the formula of the notes (eq. 69, 72) and of the formula sheet is left:

    \[ \text{AMAT} = HT + MR \times MP \]
\[ \text{AMAT} = HT + MR \times MP \]
\(HT\)
Hit Time: paid by every access, hit or miss
\(MR\)
Miss Rate: misses / accesses, a pure fraction; 5% enters as 0.05
\(MP\)
Miss Penalty: the extra time a miss adds, to fetch the block and update the cache
AMAT
in the unit of HT and MP, cycles or ns

AMAT mixer: every access pays the hit time

The strip shows 100 accesses, the misses marked with a cross. The bar below is the cost of the average access on a fixed scale: the blue part, HT, is paid by every access; the orange part, MR × MP, is what the misses add on average. The readouts assemble the formula with the numbers you set; it starts at the notes' Example 3.

  1. At Example 3 (HT 1, MR 5%, MP 100), predict how much one more percent of miss rate costs. Check with MR = 6%. Then predict the same step at MP = 200 and check.
    What you should see

    6 → 7 cycles at MP = 100, and 11 → 13 at MP = 200: each percent of miss rate costs MP / 100 cycles on every access. With a slow memory the orange part dominates the bar.

  2. Set MR = 1% and MP = 100. Which part of the bar is larger? Now predict AMAT at HT = 3, then move the slider.
    What you should see

    At HT 1 the two parts are equal, 1 + 1 = 2 cycles. At HT 3 the blue part triples and AMAT is 4: when misses are rare, the hit time is the bigger lever, because every access pays it.

  3. The last readout is a classic slip, HR × HT + MR × MP (the pitfall below the widget). At Example 3 it is short by 0.05 cycles. Predict how far off it is at HT 4, MR 20%, MP 100, then check.
    What you should see

    AMAT is 4 + 0.2 × 100 = 24 cycles; the slip gives 0.8 × 4 + 20 = 23.2, short by 0.8 = MR × HT: exactly the hit time the misses paid and the slip forgot. A miss pays the hit time too, and the error grows with both.

Read the formula the way the count went: every access pays the hit time, and the misses add MR × MP on average. At a 100-cycle penalty each percent of miss rate costs a whole cycle on every access — why the miss rate gets so much attention, and why it is not the whole story.

"AMAT = HR × HT + MR × MP." A classic slip: 0.95 × 1 + 0.05 × 100 = 5.95 cycles. It forgets that the 5 misses paid the 1-cycle lookup too, 5 cycles over 100 accesses, the missing 0.05. Use either HR × HT + MR × (HT + MP) or HT + MR × MP, never a mix of the two.

On the exam sheet, turn every percentage into a fraction as you copy it: 5% → 0.05, 0.64% → 0.0064. Then check that AMAT lies between the hit time and the hit time + miss penalty.

Three levers, and the map of the next lessons

The formula has three terms, so there are exactly three ways to make the average access faster. The notes list them twice (p. 258 and pp. 321–322), and they organise the rest of the memory part of this course:

The three strategies of the notes and where each is taught. The techniques are the notes' own lists (pp. 321–322), shortened.
StrategyTerm of AMATTechniques in the notesLesson
Reduce the miss rateMRlarger caches, larger blocks, higher associativity, prefetching, compiler optimizations25
Reduce the miss penaltyMPsecond-level caches, early restart and critical word first, priority to read misses, non-blocking caches24, 26
Reduce the hit timeHTsmall and simple L1, avoiding address-translation delays, virtually indexed caches, pipelined writes27, 28

The notes call the three strategies "orthogonal", one per term. In practice most techniques move two terms at once: a bigger cache misses less but answers more slowly, a bigger block catches more spatial locality but makes every miss longer. Weighing one term against another is the design space of lesson 24, and AMAT is the scale.

AMAT = HT + MR × MP: every access pays the hit time, and on average the misses add MR × MP.

Split or unified L1: the paradox of Example 6

The first-level cache can be built in two ways (p. 258). A unified cache holds instructions and data together. A split cache, separate instruction and data caches (the notes write I$ and D$), is also called the Harvard architecture.

The 5-stage pipeline of lesson 1 makes the choice concrete. In every cycle IF fetches an instruction while a load or store in MEM accesses data. A split L1 serves both at once; a unified cache with a single port serves one, and the other waits — a structural hazard of exactly the kind lesson 2 describes. Below, the load I0 reads memory in cycle 4, the cycle in which I3 should be fetched:

Four independent instructions on the 5-stage pipeline. With a split L1 the fetch of I3 and the data access of I0 share cycle 4; with a one-port unified cache the fetch waits a cycle.
123456789
I0 LD F2, 0(R1)IFIDEXMEMWB
I1 ADDUI R1, R1, 8IFIDEXMEMWB
I2 SUBI R3, R3, 1IFIDEXMEMWB
I3 ADDUI R4, R4, 8, splitIFIDEXMEMWB
I3, unified, one portstallIFIDEXMEMWB

One data access, one lost cycle: 4 + 4 = 8 cycles with the split L1, 4 + 4 + 1 = 9 with the one-port unified cache (cycles = IC + 4 + stalls, lesson 3). Example 6 charges the cycle to the data access: "Data hit has 1 more stall for Unified cache (only one port)".

To average over all accesses, count how many are instruction fetches. Every instruction is fetched once, and a fraction d of the instructions are loads or stores with one data access each: 1 + d accesses per instruction, so

\[ \%\text{Instr} = \frac{1}{1 + d} \] \[ \%\text{Data} = \frac{d}{1 + d} \]
\(d\)
loads and stores per instruction: the fraction of the instructions that access data
%Instr, %Data
the shares of all memory accesses that are instruction fetches and data accesses

With d = 0.33, as in Example 6: 1 / 1.33 ≈ 0.75 and 0.33 / 1.33 ≈ 0.25. The notes print these two shares correctly, but their premise skips this very step:

Each stream then gets its own AMAT, and the two are weighted by their shares. This is the Harvard formula of the notes (eq. 51), also on the example formula sheet that the course page shows:

\[ \text{AMAT}_{I} = HT + MR_{I\$} \times MP \] \[ \text{AMAT}_{D} = HT + MR_{D\$} \times MP \] \[ \begin{aligned} \text{AMAT}_{\text{Harvard}} = {} & \%\text{Instr} \times \text{AMAT}_{I} \\ + {} & \%\text{Data} \times \text{AMAT}_{D} \end{aligned} \]
\(MR_{I\$}\), \(MR_{D\$}\)
the miss rates of the instruction cache and of the data cache
unified, one port
the same weights, one miss rate \(MR_U\) for both streams, and 1 more cycle on every data access

Now Example 6 (pp. 258–259): 16 KB instruction and data caches missing 0.64% and 6.47% of their accesses, against a 32 KB unified cache missing 1.99%; hit time 1 cycle, miss penalty 50 cycles.

Example 6, recomputed. Each AMAT is the weighted sum of the per-stream costs; the last column is the miss rate over all accesses.
L1 organisationinstruction access (75%)data access (25%)AMAT (cycles)miss rate
split, 16 KB + 16 KB1 + 0.0064 × 50 = 1.321 + 0.0647 × 50 = 4.2350.75 × 1.32 + 0.25 × 4.235 = 2.0490.75 × 0.64% + 0.25 × 6.47% = 2.10%
unified, 32 KB, one port1 + 0.0199 × 50 = 1.9951 + 1 + 0.0199 × 50 = 2.9950.75 × 1.995 + 0.25 × 2.995 = 2.2451.99%

Read the last two columns together. The unified cache misses less, because 32 KB shared between code and data adapt to whichever needs more room: on misses alone it would gain (2.10% − 1.99%) × 50 ≈ 0.05 cycles per access. But one access in four is a data access that waits a cycle for the port: 0.25 cycles per access. A quarter of a cycle lost against a twentieth gained: the unified cache ends up 0.2 cycles slower, 2.245 against 2.05 (the notes round 2.245 to 2.24).

Split or unified: the miss rate is not the verdict

Two bars, one per organisation, each split into the hit time (blue), the miss part, miss rate × MP (orange), and for the unified cache the port stall, %Data × 1 cycle (dashed). The miss rates stay at the notes' values (0.64%, 6.47%, 1.99%) and the hit time at 1 cycle; you set the loads and stores per instruction, the miss penalty and the port. It starts at Example 6.

  1. At the start values (d = 0.33, MP 50, one port), predict which cache has the lower miss rate and which the lower AMAT. Then read the bars and the readouts.
    What you should see

    Unified: miss rate 1.99% against 2.10%. Split: AMAT 2.049 against 2.245 cycles. The orange part of the unified bar is indeed shorter; the dashed port stall, 0.25 cycles, more than makes up for it.

  2. Switch off the one-port stall: a unified cache with two ports. Predict its AMAT before looking.
    What you should see

    1 + 0.0199 × 50 = 1.995 cycles: now the unified cache wins, 1.995 against 2.049. In Example 6 the split organisation wins only because of the structural hazard; by miss rate alone the unified cache is better.

  3. Put the stall back and raise the miss penalty. Predict whether the split cache keeps winning forever, then find where the order flips.
    What you should see

    Between 230 and 240 cycles: at MP = 230 split 5.824 against unified 5.827, at 240 unified 6.026 against split 6.034. The port costs a fixed 0.25 cycles, the 0.1075-point gap in miss rate costs 0.001075 × MP, and the two are equal at MP ≈ 233. The metric is AMAT, not the miss rate, and which design wins depends on every term.

"A split L1 is always faster than a unified one." The notes close Example 6 with "So Harvard (separate I$ and D$) gives better performance than Unified Cache, because AMAT (Average Memory Access Time) is less" (p. 259): right for these numbers, but silent on why. The split cache wins only because the single-ported unified cache adds a stall cycle to every data access; by miss rate the unified cache is the better one. Drop the "+1" from its data term and it wins, 0.75 × 1.995 + 0.25 × 1.995 = 1.995 cycles against 2.049; keep it and it still wins once the miss penalty passes about 233 cycles (the widget's third task). Miss rate is not performance; AMAT is.

Back to the two puzzles

The 94 cycles of the first puzzle were never spent: 95 accesses in 100 find their block in the cache, because the program reuses data and walks through neighbours, and pay one cycle; only 5 pay the trip. The illusion is an average that only locality keeps alive — the probe's random program pays 101 cycles per access. In the second puzzle the unified cache wins on miss rate and loses on AMAT, because its single port charges a cycle to every data access: the miss rate is one ingredient, the average access time is the measure.

Miss rate is not performance: compare AMATs. A split L1 misses a little more; a single-ported unified L1 pays a cycle on every data access.

Exam-style questions

The questions follow the paper's forms: an open question with eight sub-points, an exercise answered with every intermediate number, and single-answer, multiple-answer and true/false quizzes. The model answers are recomputed here, not official solutions. AMAT and its Harvard form are on the example formula sheet that the course page shows.

Explain the main concepts and benefits of each one of the following concepts of the memory hierarchy: 1. Memory hierarchy; 2. Temporal locality; 3. Spatial locality; 4. Cache block (cache line); 5. Hit time and miss penalty; 6. Average Memory Access Time (AMAT); 7. Separate instruction and data caches (Harvard architecture) versus a unified cache; 8. SRAM and DRAM technologies.

Show model answer

1. A layered memory system: small, fast, expensive levels close to the processor (registers; L1, L2, L3 caches in SRAM) and large, slow, cheap levels further away (main memory in DRAM, disk). Each upper level holds a subset of the level below. Benefit: the processor sees one large memory with an average access time close to that of the fastest level, at a cost per bit close to that of the cheapest (the illusion of a large, fast memory). It works only because programs have locality. Registers are managed by the compiler, caches by hardware, main memory and disk by the operating system.

2. A location accessed now is likely to be accessed again soon (an accumulator in a loop, the instructions of a loop body). Exploited by keeping recently used blocks in the cache and, when space is needed, replacing the least recently used one (LRU), so that the repeated accesses hit. Benefit: after the first access the reused word costs only the hit time; the cache needs enough capacity to keep the block until the reuse comes.

3. After a location, nearby locations are likely to be accessed soon (array elements a[i], a[i+1]; sequential instructions). Exploited by transferring whole multi-word blocks: one miss brings the neighbours, whose accesses then hit (8 doubles in a 64-byte block: 1 miss, 7 hits). Benefit: one miss penalty is shared by several accesses; if the neighbours are never used, a larger block only makes each miss longer.

4. The smallest unit transferred between memory and cache, typically 32 to 128 bytes; number of blocks = cache size / block size (64 KB / 16 B = 4096). Benefit: one transfer serves several accesses (spatial locality). Cost: a larger block makes each miss longer.

5. Hit time: time to access the cache, determine whether it is a hit and return the data (1 to 3 cycles for L1). Miss penalty: extra time to fetch the block from the lower level, write it into the cache and resume the CPU (tens to hundreds of cycles). On a miss the CPU stalls, the block is fetched and written, and the access is retried; miss time = hit time + miss penalty.

6. AMAT = Hit Rate × Hit Time + Miss Rate × (Hit Time + Miss Penalty) = Hit Time + Miss Rate × Miss Penalty, because Hit Rate + Miss Rate = 1: every access pays the hit time, the misses add the penalty. The miss rate is a fraction (5% = 0.05): 1 + 0.05 × 100 = 6 cycles. Benefit: one number that combines the three parameters and shows the three ways to improve a cache: reduce the hit time, the miss rate or the miss penalty.

7. Split L1: separate I-cache and D-cache, so the pipeline can fetch an instruction and access data in the same cycle (no structural hazard). AMAT = %Instr × (HT + MRI × MP) + %Data × (HT + MRD × MP), with %Instr = 1/(1 + d) and %Data = d/(1 + d), d = loads/stores per instruction. Unified: one cache shared flexibly between code and data, usually a lower miss rate for the same total size, but with one port every data access stalls one cycle. Example: unified 1.99% against split 2.10% miss rate, yet AMAT 2.245 against 2.05 cycles: the split cache is better there because of the port, and the comparison must be made on AMAT.

8. SRAM: six transistors per bit, fast but large and expensive per bit, used for the caches. DRAM: one transistor and a capacitor per bit, dense and cheap but slower, and it must be refreshed; used for main memory (SDRAM and DDR are DRAM). No single technology is both fast and big, which is why the hierarchy combines them.

The 2026 paper leaves five lines per sub-point: room for a definition, the mechanism, the benefit, the cost and a number. In sub-point 6 write the derivation, not only the final formula; in sub-point 7 give the reason the unified cache loses, the structural hazard on its single port. Writing SDRAM for the caches in sub-point 8 repeats the notes' slip of p. 297.

MEMORY HIERARCHY. Let's consider a processor where 25% of the instructions are loads/stores, with two alternative L1 organisations of the same total size: (a) separate instruction and data caches (Harvard architecture) with Miss RateI$ = 1% and Miss RateD$ = 6%; (b) a unified cache with Aggregate Miss Rate = 1.8% and only one port, so a data access has 1 more stall cycle. Hit Time = 1 clock cycle and Miss Penalty = 50 clock cycles in both cases.

1. How much are the percentages of instruction accesses and of data accesses? 2. How much is the miss rate of the Harvard organisation over all accesses? 3. How much is the AMAT of each organisation? 4. Which organisation is better, and why?

Show model answer

1. Per instruction: 1 fetch + 0.25 data accesses = 1.25 accesses. %Instr = 1 / 1.25 = 0.80 (80%); %Data = 0.25 / 1.25 = 0.20 (20%).

2. MRHarvard = 0.8 × 0.01 + 0.2 × 0.06 = 0.008 + 0.012 = 0.020 (2.0%), higher than the unified 1.8%.

3. AMATHarvard = 0.8 × (1 + 0.01 × 50) + 0.2 × (1 + 0.06 × 50) = 0.8 × 1.5 + 0.2 × 4 = 1.2 + 0.8 = 2.0 cycles. AMATunified = 0.8 × (1 + 0.018 × 50) + 0.2 × (1 + 1 + 0.018 × 50) = 0.8 × 1.9 + 0.2 × 2.9 = 1.52 + 0.58 = 2.1 cycles.

4. The Harvard organisation is better, 2.0 against 2.1 cycles, although its miss rate is higher (2.0% against 1.8%). The unified cache saves (0.020 − 0.018) × 50 = 0.1 cycles per access on misses but loses 0.2 × 1 = 0.2 cycles per access in structural-hazard stalls on its single port. The comparison is decided by AMAT, not by the miss rate.

The same structure as the notes' Example 6 with rounder numbers. The steps to get right: the shares derived per instruction (80% and 20%, not 75% and 25%), every percentage converted to a fraction, and the "why" of point 4: the structural hazard and its cost per access.

A cache has a Hit Time of 1 clock cycle and a Miss Penalty of 100 clock cycles. Which Miss Rate gives an AMAT of 3 clock cycles? Write it as a decimal fraction, not as a percentage.

Show model answer

AMAT = Hit Time + Miss Rate × Miss Penalty ⇒ 3 = 1 + Miss Rate × 100 ⇒ Miss Rate = 2 / 100 = 0.02 (2%).

The answer "2" is the percentage written as a bare number: the "unit is %" trap of p. 321 in reverse. Check it: 1 + 0.02 × 100 = 3.

(Single answer.) Let's consider a cache with Hit Time = 1 clock cycle, Miss Rate = 5% and Miss Penalty = 100 clock cycles. How much is the AMAT?

  • Answer 1: 5.95 clock cycles 0.95 × 1 + 0.05 × 100 forgets the hit time that the misses pay too.
  • Answer 2: 6 clock cycles 1 + 0.05 × 100: every access pays the hit time, the misses add the penalty on average.
  • Answer 3: 101 clock cycles That is the cost of one miss, hit time plus miss penalty, not the average.
  • Answer 4: 501 clock cycles The miss rate was entered as 5 instead of 0.05.
Show model answer

Answer 2: AMAT = 1 + 0.05 × 100 = 6 clock cycles.

The notes' Example 3. Each distractor is one classic slip: the dropped hit time, the cost of one miss, the percentage used as a number.

(Multiple answers.) Which of the following statements about locality and caches are correct?

  • Answer 1: Temporal locality is exploited by keeping recently accessed blocks in the cache and replacing the least recently used one The reused word is still there when it is needed again; LRU protects the blocks in use.
  • Answer 2: Spatial locality is exploited by transferring multi-word blocks between memory and cache One miss brings the neighbours, whose accesses then hit.
  • Answer 3: A larger block size helps a program that reads each element of a large array once, in random order The neighbours are read only much later, long after their block has been evicted: each block serves one useful word, and a larger block only makes each miss longer.
  • Answer 4: The instructions of a loop body show both temporal and spatial locality They are fetched again in every iteration (temporal) and lie at consecutive addresses (spatial).
  • Answer 5: Without any locality, a cache still reduces the average memory access time Every access misses: AMAT = hit time + miss penalty, more than accessing memory directly.
Show model answer

Answers 1, 2 and 4.

The locality probe shows four of the five: answers 1 and 2 are its first program (capacity, then block size), answers 3 and 5 its third. Answer 4 is the instruction stream of the six-instruction loop in section 2: fetched again in every iteration, from consecutive addresses.

(True/False.) For the same total size, a unified L1 cache always has a higher AMAT than separate instruction and data caches.

  • True In the notes' Example 6 the split cache wins only because the unified one has a single port; without that stall the unified cache, with its lower miss rate, has AMAT 1.995 against 2.049.
  • False The result depends on the miss rates, the share of data accesses, the miss penalty and the number of ports: compute both AMATs.
Show model answer

False. A unified cache usually has the lower miss rate for the same size; it loses only when the structural-hazard stalls on its single port cost more than its miss-rate advantage saves (Example 6: 0.25 cycles against about 0.05 per access). With two ports, or a large enough miss penalty (above about 233 cycles with the numbers of Example 6), it wins.

An "always" in a true/false question is a hint to look for the counterexample. Here it is one line of arithmetic.

Check yourself

A program reads every element of a 2 MB array exactly once, from the first to the last. What locality do its data accesses have?

  • Temporal only No element is read twice, so nothing is reused.
  • Spatial only Each block brought in for one element also serves the next ones; no word is used twice.
  • Both Temporal locality would need the same address again.
  • None: the cache cannot help A sequential walk is the best case for multi-word blocks.

Hit time 1 cycle, miss penalty 100 cycles. How many cycles does a single miss cost?

  • 100 That is the penalty alone; the lookup that discovered the miss came first.
  • 101 Miss time = hit time + miss penalty.
  • 6 6 is the average over hits and misses at a 5% miss rate, not the cost of one miss.
  • 99 The hit time is added to the penalty, not subtracted from it.

Hit time 1 cycle, miss rate 2%. The miss penalty doubles from 100 to 200 cycles. AMAT goes from 3 cycles to

  • 6 Only the miss term doubles; the hit time stays as it was.
  • 5 1 + 0.02 × 200 = 5: the miss term grows from 2 to 4.
  • 3 The miss rate did not change, but the penalty multiplies it.
  • 201 That is the cost of one miss, not the average access.

In the miss model of the notes, what happens on a cache miss? Select all that apply.

  • The CPU stalls The load cannot complete; the pipeline freezes as for a hazard.
  • The whole block that holds the address is fetched from the lower level The block is the unit of transfer.
  • The block is written into the cache, and the access is retried and hits Steps 3 and 4 of p. 301.
  • Only the requested word is fetched, to save time Blocks move, not words: that is how spatial locality is caught.
  • The hit time is not paid, since the data was not found The lookup came first: miss time = hit time + miss penalty.

In the memory hierarchy of the notes, which technology are the L1, L2 and L3 caches made of?

  • SDRAM Synchronous DRAM, a main-memory technology: the slip of the notes on p. 297.
  • SRAM Static RAM: six transistors per bit, fast and expensive.
  • DRAM Dense and cheap but slow: main memory.
  • Flash Non-volatile storage, at the bottom of the hierarchy with the disks.

In Example 6 the unified 32 KB cache misses less than the split one (1.99% against 2.10%) and is still slower. Why?

  • Its hit time is longer on every access Both have a 1-cycle hit time; only the data accesses pay an extra cycle.
  • Its single port makes every data access wait one cycle, a structural hazard 25% of the accesses × 1 cycle = 0.25 cycles per access, against about 0.05 saved on misses.
  • Its miss penalty is larger Both have 50 cycles.
  • Its instruction accesses miss more often The example gives one miss rate, 1.99%, for all its accesses; the loss comes from the port, not from misses.

How many blocks does a 32 KB cache with 64-byte blocks hold?

  • 512 32 × 1024 / 64 = 32 768 / 64 = 512.
  • 500 1 KB is 1024 bytes, not 1000.
  • 2048 That would be 32 KB with 16-byte blocks.
  • 0.5 32 / 64 mixes kilobytes and bytes: put both sizes in the same unit first.

Key take-aways

What to watch and read