7.2Baseline Snooping Protocol (MSI)

book pp. 111–122 · ~4 min read

  • MSI
  • Atomic Requests
  • Atomic Transactions
  • window of vulnerability
  • NoData

This section builds one straightforward MSI protocol twice: first on a simple system model whose atomicity properties keep the specification tiny, then on the baseline model, where relaxing just one property already multiplies the transient states. The inefficiencies you’ll notice are the motivation for everything in §7.3–7.6.

7.2.1 High-level specification

Three stable states — MSI — with a writeback cache; the block is owned by the LLC/memory unless some cache holds it in M. Loads hit in S and M; stores hit only in M. The FSMs below (the book’s Figures 7.1 and 7.2) show only stable states and the bus requests that move them; memory’s states use cache-centric names — the merged IorS says “no cache holds M.”

7.2.2 The simple model: Atomic Requests + Atomic Transactions

The system is chapter 2’s baseline with the network fixed as a bus (the book’s Figure 7.3 — essentially the SGI Challenge):

Multicore Processor ChipCoreCacheControllerPrivateData CacheCoreCacheControllerPrivateData CacheInterconnection NetworkLLC/MemoryControllerLast-levelCache(LLC)Main Memory

Two atomicity properties tame the protocol:

  • Atomic Requests : a request is ordered the cycle it is issued — a block’s state can’t change between issue and serialization.
  • Atomic Transactions : no subsequent request for the same block may appear until the current transaction’s response completes.

The result: only three cache transient states (IS^D, IM^D, SM^D — request already ordered, data pending) and one at memory. Explore both controllers — the shaded cells marked “(A)” are impossible because transactions are atomic:

Figures 7.1 + transients (recreated): simple MSI cache controller

Load → GetSDataStore → GetMDataStore → GetMDataOther-GetM · Repl (silent)Other-GetSOther-GetM · Repl (PutM)I — Invalid: No usable copy. Loads issue GetS, stores issue GetM — and with Atomic Requests, the request is ordered the same cycle, so the block jumps straight to a ^D transient.IIS^D — I → S, waiting for Data: GetS ordered; block logically S already (the transaction is serialized), but the load must wait for the Data message. Atomic Transactions guarantee no other request for this block intervenes.ISDIM^D — I → M, waiting for Data: GetM ordered; block logically M, data still in flight. No other request for this block can appear (Atomic Transactions).IMDS — Shared: Read-only copy; others may share. Loads hit. GetS requests are ignored (the LLC/memory responds); an Other-GetM invalidates. Eviction is silent.SSM^D — S → M, waiting for Data: GetM ordered from S; block logically M, awaiting data. Loads still hit (we had a valid copy all along).SMDM — Modified: Read-write; the only valid copy; this cache is the owner and must respond to both GetS (→S, send data to requestor and memory) and GetM (→I, send data to requestor).M

Solid = stable state · dashed = transient · click a state or an arrow.

Table 7.5 (recreated): simple snooping — cache controller

Core eventsBus: own transactionBus: other cores
StateLoadStoreReplacementOwn-GetSOwn-GetMOwn-PutMData (for own request)Other-GetSOther-GetMOther-PutM

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

Figure 7.2 (recreated): memory controller stable states

GetMGetS · PutMData from ownerIorS — No cache holds M (memory is owner): Cache-centric merged state: every cache is in I or S, so the LLC/memory owns the block and answers both GetS and GetM.IorSIorS^D — Waiting for the PutM's data: A PutM (or an M-cache's response to a GetS) is bringing the data home; memory waits for the Data message before resuming ownership.IorSDM — Some cache holds M (memory not owner): One cache owns the block in M; memory must not respond with its (potentially stale) copy.M

Solid = stable state · dashed = transient · click a state or an arrow.

Table 7.6 (recreated): simple snooping — memory controller

Bus events
StateGetSGetMPutMData from owner

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

Key behaviors worth reading off the tables: a Data response comes from the memory controller or from a cache in M; an S cache ignores GetS (memory answers) but invalidates on GetM; an M cache answers both — sending data to requestor + memory on GetS (ownership returns to memory), to the requestor alone on GetM. Evictions: S→I is silent; M→I issues a PutM with the data (the only valid copy can’t be dropped).

Try it: the running example

Table 7.7’s scenario — C1 loads, C2 stores, C1 loads again — as a live system. Step through the preset, then experiment freely (watch the data values expose stale memory):

Simple snooping MSI — one block, atomic bus

Core C1

I

Core C2

I

LLC / Memory

IorS

data: v0

Bus timeline (one block; atomic requests + atomic transactions)

  1. ·Reset: all caches I, LLC/memory IorS holding v0.

At the end of the preset: C1 and C2 both hold S, and the LLC/memory — refreshed by C2’s response to the final GetS — owns the block in IorS.

7.2.3 The baseline model: non-atomic requests

Real implementations put message queues between cache controllers and the bus — so a request is issued now but ordered later, opening the window of vulnerability . (Atomic Transactions still hold; §7.5 drops those too.) The protocol grows new ^AD states — issued, waiting to observe own request, then data — during which the block is effectively still in its old state:

Table 7.8 (recreated): baseline MSI — cache controller (click the SM^AD × Other-GetM cell!)

Core eventsBus: own transactionBus: other coresBus: own transaction
StateLoadStoreReplacementOwn-GetSOwn-GetMOwn-PutMOther-GetSOther-GetMOther-PutMOwn Data Response

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

Three stories to find in that table:

  • I→S: Issue GetS (IS^AD, effectively I — other requests ignored) → observe Own-GetS (IS^D, logically S: the transaction is ordered) → Data → S, load performs.
  • S→M hijacked: in SM^AD, loads still hit — but if an Other-GetM is serialized first, our copy dies: → IM^AD, no more hits. This window is also why an Upgrade transaction is easy with Atomic Requests and painful without: an Upgrade that lost its S copy suddenly needs data, and the LLC/memory in IorS can’t tell (the book’s sidebar traces a three-core interleaving where this bites).
  • M→I complicated: PutM issued → MI^A, where the block is effectively still M — so the cache keeps answering others’ requests. If a GetS/GetM intervenes, it responds and slides to II^A, and when its stale PutM finally appears it must send NoData — its data would overwrite newer values, but silence would strand the memory controller in a transient state:

Table 7.9 (recreated): baseline MSI — memory controller (X^D reverts to X on NoData)

Bus events
StateGetSGetMPutMDataNoData

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

Note the naming exception: memory’s M^D means “revert to M if NoData arrives, go to IorS if Data arrives” — the controller must remember which stable state to fall back to.

7.2.4–7.2.5 The running example, and what simplicity cost

The baseline running example (the book’s Table 7.10) ends exactly like the simple one — both cores in S, memory in IorS — with one visible difference: both cores issue their requests concurrently and change state immediately (IS^AD, IM^AD), with the bus later deciding that C1’s GetS wins serialization.

The simplicity scorecard: Atomic Transactions erased every “(A)” cell — §7.5 shows the redesign when they’re gone — and the missing Upgrade transaction means every S→M store pays for a full data transfer it doesn’t need.

Check yourself

1.Flashback (pop quiz Q6): 'In an MSI snooping protocol, a cache block may only be in one of three coherence states.' True or false?

2.What do the simple model's two atomicity properties say, and what does each buy?

3.In the baseline protocol, a cache in SM^AD (upgrading S→M) observes an Other-GetM before its own GetM. What happens, and why?

4.Why does a cache in II^A send a NoData message (rather than its data, or nothing) when it finally observes its own PutM?

5.A cache holds a block in M and observes an Other-GetS. Why must it send data to the requestor AND to memory?

6.Why can an S block be evicted SILENTLY, while an M block cannot?

6 questions