Multithreading: fine-grained, coarse-grained, SMT, and the exam’s per-thread CPI

After this lesson you will draw the cycle × issue-slot grid of coarse-grained, fine-grained and simultaneous multithreading, say which stalls each one hides and what it costs, and get the ideal CPI and the ideal per-thread CPI of any SMT core in one line.

Hennessy and Patterson draw a quad-issue core for ten cycles: forty issue slots, Figure 29 of the notes (p. 382). One thread fills 16 of them, and in three of the ten cycles nothing issues at all. Lesson 28 ended on the one idea left when a miss cannot be avoided: let another thread run while it waits.

So give the same core four threads. Switch thread only when one stalls for long: 21 of 40. Switch thread every single cycle: still 21. Let the threads share each cycle: 32. Why does switching every cycle buy nothing over switching only on long stalls — and where do the eleven extra slots come from?

Keep your guess. Multithreading is in all three official papers (July 2024, June 2025, June 2026), as an open question and as a one-point quiz on the ideal CPI, and both are answered from this picture.

Forty slots, sixteen used: what one thread leaves empty

Lessons 8 to 21 asked one question: how many instructions of one thread can run at the same time? A superscalar answers it at run time, with Tomasulo, renaming and the reorder buffer; a VLIW at compile time, in bundles. Both meet the same wall (p. 371). A true RAW dependence makes an instruction wait for its producer; a branch wastes cycles when the guess is wrong; a load that misses waits for memory — "a cache miss that takes 200 cycles" (p. 372). So even a core able to issue eight instructions per cycle rarely finds eight ready ones in one thread; lesson 8 counted the walls.

Fig. 1 makes it concrete. It redraws the notes' Figure 29, a quad-issue core watched for ten cycles, C0 to C9. The left panel runs one thread. Count it: 16 of the 40 slots are filled. The 24 empty ones come in two shapes, and a good exam answer names both.

Issue slot — one of the w places per cycle where an instruction can start: a w-issue core has w slots per cycle. Vertical waste — a whole cycle in which nothing issues: the thread is stalled. Horizontal waste — the empty slots of a cycle in which something did issue: the thread had too few independent instructions. The notes call them "bubbles" and "empty slots" (p. 372); the two names are Tullsen, Eggers and Levy's (1995).

issue slot 1 2 3 4 C0 T1 T1 C1 T1 C2 T1 T1 T1 C3 T1 T1 C4 T1 T1 T1 T1 C5 C6 C7 C8 T1 C9 T1 T1 T1 horizontal vertical waste 16 of 40 slots filled CPI = 10 / 16 = 0.625

Before: one thread (superscalar)

issue slot 1 2 3 4 C0 T1 T1 T2 T2 C1 T2 T3 T3 T3 C2 T4 T1 C3 T2 T2 T3 T3 C4 T1 T1 T1 C5 T2 T3 T3 C6 T4 T4 T1 T1 C7 T2 T2 C8 T3 T3 T3 T4 C9 T4 T4 8 holes 32 of 40 slots filled CPI = 10 / 32 = 0.3125

After: four threads in the same cycles (SMT)

Fig. 1. The notes' Figure 29 (from Hennessy and Patterson) with the exam's labels: rows are the cycles C0–C9, columns the four issue slots, T1–T4 the threads (black and three greys in the notes). One thread wastes 24 slots in two shapes — whole empty cycles and holes inside busy cycles. Four threads sharing each cycle leave 8 holes.

In the left grid rows C5–C7 are empty: 3 × 4 = 12 slots of vertical waste, typically a miss. The other 12 empty slots are horizontal: the thread was running, but its ILP gave one, two or three ready instructions instead of four. A handful of numbers summarise any grid. The first is the formula sheet's code efficiency, counted on issue slots:

\[ U = \frac{\text{filled slots}}{C \times w} \] \[ \mathrm{IPC} = \frac{\text{filled}}{C} \qquad \mathrm{CPI} = \frac{C}{\text{filled}} \] \[ W_v = w \times (\text{empty cycles}) \] \[ W_h = C\,w - \text{filled} - W_v \]
\(C\)
cycles observed (10 in the exam's grids)
\(w\)
issue width: slots per cycle (the formula sheet's #issues)
filled
instructions issued in those cycles
\(W_v\), \(W_h\)
vertical and horizontal waste, in slots

For the left grid: \(U = 16/40 = 0.40\), IPC = 1.6, CPI = 10/16 = 0.625 — two and a half times the ideal \(1/w = 0.25\) of lesson 8. Sixty per cent of a core that was paid for in area and power does nothing.

The way out is the notes' next question: "If one thread alone cannot keep the machine busy, why not let another thread provide instructions in the meantime?" (p. 372). Instruction-level parallelism (ILP) is parallelism inside one instruction stream; thread-level parallelism (TLP) is parallelism across streams, and multithreading "does not replace ILP, it complements it". The threads must already exist — written by the programmer, or separate programs run by the operating system. The hardware interleaves them; it does not create them.

The right panel shows the gain and the price. Four threads fill 32 slots: the core's CPI halves to 10/32 = 0.3125. But T1, the same thread as on the left, now issues 8 instructions in the ten cycles instead of 16: its own CPI doubles from 0.625 to 1.25. Multithreading is throughput-oriented (p. 377): the core completes more instructions per cycle, and each thread may finish later. A web server with hundreds of independent requests gains; a single-threaded program gains nothing.

Multithreading fills the slots one thread leaves empty with other threads' instructions: the core's throughput rises, while a single thread's latency does not fall and may rise.

A thread lives in a context: what is copied, what is shared, why the OS is too slow

A program in execution is a process: its own address space (code, heap, stack, data) and operating-system resources such as open files. Inside a process run one or more threads (p. 373).

Thread — "the smallest unit of execution that can be scheduled by the operating system" (p. 373). It has its own program counter and its own register state; the threads of a process share its address space, so they see the same code and global data and communicate through memory — cheaply, and with data races if they synchronise badly. The process is the container, the thread the flow of execution inside it.

Take one loop and run it in two threads, T1 over an array A and T2 over an array B:

LOOP: LD    F2, 0(R1)
      FADD  F4, F2, F2
      SD    F4, 0(R1)
      ADDUI R1, R1, 8
      BNE   R1, R2, LOOP

Both threads write R1 and F2. If they shared one R1, each ADDUI would move the other thread's pointer too. So each thread needs its own program counter, its own registers and its own status bits: its hardware context. "If one core supports 4 hardware threads, it will contain 4 PCs and 4 register files" (p. 378). Everything expensive stays shared — the functional units, the caches, the TLB and the memory system — because duplicating them "would make multithreading as expensive as adding more cores" (p. 378). A context costs registers and a little control logic; a core costs a datapath and its caches.

The operating system can already run T1 and T2 one after the other. A context switch saves the old thread's registers, program counter and status to memory, restores the new thread's and, between two processes, changes the memory mappings: "thousands of CPU cycles" (p. 375). That is fine for multitasking at the OS level, and useless against a 200-cycle miss. Hardware multithreading keeps all the contexts inside the core at once: changing thread means selecting another program counter and another set of registers, "a few cycles or even just one cycle", with no OS call and nothing copied (p. 375). The widget weighs the two.

Stall or switch?

A thread meets a stall of L cycles. Either the core waits, or it switches to another ready thread, paying S cycles to drain and refill. Top bar: waiting. Bottom bar: switching. Both sliders move in big steps; the stall goes from 1 cycle to a million. The buttons set typical values: a 200-cycle miss (p. 372), an OS switch of "thousands" of cycles (p. 375) and a coarse-grained switch of "a few" (p. 380), shown as 2000 and 5; the other stalls are orders of magnitude.

  1. Press "DRAM miss · 200" and "coarse-grained · 5". Before you look: what share of the stall does the switch hide?
    What you should see

    195 of 200 cycles, 97.5 %: another thread works through almost the whole miss. A long miss is what coarse-grained multithreading was built for.

  2. Keep the 200-cycle miss and press "OS context switch · 2000". Then press "page fault · 10⁶".
    What you should see

    Against the miss nothing is hidden: the switch lasts ten times the stall. Against the page fault the OS switch hides 998 000 of 1 000 000 cycles. That is the division of labour: the OS switches threads around page faults and time slices, and only contexts kept in hardware can switch around a cache miss.

  3. Press "RAW stall · 3" with the coarse-grained switch, then with "fine-grained or SMT · 0".
    What you should see

    Coarse-grained: max(0, 3 − 5) = 0 — the switch would cost more than the stall, so the core waits and loses the 3 cycles. With S = 0 all 3 cycles go to another thread. This is the one insight of the widget: a switch pays only when it is cheaper than the stall.

The rule the widget draws fits in one line: a switch hides a stall of L cycles only if it costs less than the stall.

\[ \text{cycles hidden} = \max(0,\; L - S) \]
\(L\)
length of the stall, in cycles
\(S\)
cost of the switch: thousands for the OS, a few for a pipeline drain, 0 when the thread changes every cycle

With S in the thousands, the OS cannot hide any cache miss. With a drain of a few cycles, a 200-cycle DRAM miss is worth a switch and a 3-cycle RAW stall is not. With S = 0 every stall is worth hiding. The three hardware schemes of the next section are three answers to one question: when, and how cheaply, to change thread.

Three ways to share one pipeline: coarse, fine, simultaneous

The notes define three schemes (pp. 380–381). They differ in two rules: when the core changes thread, and how many threads may issue in the same cycle. Look at the textbook's four grids before reading the rules: each tab writes one of them in the form the papers ask for, one row per cycle and one column per issue slot.

CycleIssue 1Issue 2Issue 3Issue 4
C0T1T1––
C1T1–––
C2T1T1T1–
C3T1T1––
C4T1T1T1T1
C5––––
C6––––
C7––––
C8T1–––
C9T1T1T1–
CycleIssue 1Issue 2Issue 3Issue 4
C0T1T1––
C1T1–––
C2T1T1T1–
C3T1T1––
C4T1T1T1T1
C5T2T2T2–
C6T2T2T2–
C7T2T2––
C8T2–––
C9––––
CycleIssue 1Issue 2Issue 3Issue 4
C0T1T1––
C1T2T2T2–
C2T3T3T3–
C3T4–––
C4T1–––
C5T2T2––
C6T3T3––
C7T4T4T4–
C8T1T1T1–
C9T2–––
CycleIssue 1Issue 2Issue 3Issue 4
C0T1T1T2T2
C1T2T3T3T3
C2T4T1––
C3T2T2T3T3
C4T1T1T1–
C5T2T3T3–
C6T4T4T1T1
C7T2T2––
C8T3T3T3T4
C9T4T4––

Coarse-grained multithreading runs one thread until it hits a long-latency stall, typically a miss to DRAM, then switches to another thread. The switch drains and refills the pipeline — a few cycles, "negligible compared to hundreds of cycles of stall" (p. 380). In the coarse-grained tab T1 runs from C0 to C4; when it stalls, T2 takes over at C5, and in C9 nobody issues: a switch is not free. It is the simplest scheme — duplicate the PC and the registers and leave the per-cycle logic alone, "run until we hit a brick wall, then switch" (p. 374) — and it is useless against short stalls such as data hazards and mispredictions, where the switch costs as much as the stall. It pays where the notes place it (p. 374): stalls of hundreds of cycles, a drain that is short beside them, and a core narrow enough that one thread per cycle keeps it fed. The machines usually cited are IBM's RS64-II "Northstar" (1998) and Intel's Itanium 2 "Montecito" (2006). The notes' "some GPUs in specific modes" (p. 374) points the wrong way: a GPU's warp scheduler changes thread every cycle (lesson 32).

Fine-grained multithreading switches thread every cycle, usually round robin: "If one thread is stalled, it's skipped" (p. 380). In the fine-grained tab the threads rotate T1, T2, T3, T4, T1 …, one per row: no row is empty, and no row is full. While any thread is ready the pipeline never idles, so short stalls are hidden as well as long ones, at no switch cost. Each thread now issues only every few cycles, and the core needs selection logic fast enough to decide every cycle. Sun's Niagara (2005) is the commercial case: eight single-issue pipelines with four threads each, whose second stage is literally called "thread select", "with a zero cycle switch penalty" (Kongetira and others, 2005).

Simultaneous multithreading (SMT) runs on a superscalar whose issue slots one thread rarely fills — 4 to 8 of them in the notes, 2 or 4 in the papers' questions — and issues "instructions from different threads in the same cycle" (p. 381). The notes' smallest example has two cycles (p. 383): in the first T1 issues three instructions and T2 one; in the second T1 is stalled and T2 fills all four slots. In the SMT tab C0 already holds T1 and T2, and C1 holds T2 and T3. It combines ILP, several instructions per thread, with TLP, several threads. The price: the threads compete for caches, functional units and branch predictors, the speed of one thread depends on what its siblings do, and the issue logic must decide every cycle "which thread's instructions win each slot" (p. 381).

The three schemes side by side (pp. 379–381). The machine names are background beyond the notes.
Coarse-grainedFine-grainedSMT
Changes threadon a long-latency stallevery cycle, round robin, skipping stalled threadsnever: all threads active at once
Threads issuing in one cycleoneoneseveral
Cost of a switcha few cycles: drain and refillnonenone
Hideslong stalls onlyall stalls, short ones tooall stalls, and the holes inside a cycle
Costsshort stalls still waste whole cycleseach thread runs slower; a thread choice every cyclecontention for caches, units, predictors; unpredictable per-thread speed; complex issue logic
MachinesIBM RS64-II, Itanium 2 MontecitoSun Niagara; GPU warp schedulersIntel Hyper-Threading, IBM POWER5 and later, AMD Zen

"Our program feels slower if it's the only one running" — the notes' parenthesis on fine-grained multithreading (p. 380). Not because of the mechanism: a core that skips stalled threads gives a lone thread every cycle. The slowdown comes from sharing the cycles with other ready threads. Only strict barrel designs, with a fixed turn for every context, slow a lone thread down too.

Figure 29 in numbers: ten cycles of a quad-issue core, 40 slots; waste counted in slots; per-thread CPI = 10 / (slots of that thread), T1 to T4 in order.
SchemeFilled\(U\)CPIVerticalHorizontalPer-thread CPI
One thread160.400.62512120.625
Coarse, 2 threads210.5250.4764150.83 · 1.11
Fine, 4 threads210.5250.4760191.67 · 1.67 · 2 · 2.5
SMT, 4 threads320.800.3125081.25 · 1.25 · 1 · 1.67

Back to the opening puzzle. Coarse-grained gives the three empty cycles of T1's long stall to T2, but leaves an empty cycle at C9 and does nothing about the holes inside T1's cycles: vertical waste falls from 12 to 4, horizontal waste grows from 12 to 15. Fine-grained removes every empty cycle, but each cycle still belongs to one thread and is only as full as that thread's ILP: horizontal waste grows to 19. The same 21 slots, reached in two different ways. Only SMT puts several threads in one cycle, and the 11 extra slots are horizontal waste turned into work: 19 becomes 8. Tullsen, Eggers and Levy put it in one sentence: traditional multithreading "converts much of the vertical waste to horizontal waste, rather than eliminating it."

Coarse- and fine-grained multithreading reassign whole cycles and attack only vertical waste; SMT fills the empty slots inside a cycle and attacks both.

Tullsen, Eggers and Levy simulated an 8-issue superscalar running the SPEC92 benchmarks. One thread "fails to sustain 1.5 instructions per cycle" — 19 % of the slots — and 61 % of the waste was vertical. A fine-grained machine switching every cycle at no cost still "utilizes only about 40% of a wide superscalar, regardless of the number of threads". Letting threads share a cycle, they wrote, "has the potential to achieve 4 times the throughput of a superscalar, and double that of fine-grain multithreading." Seven years later Intel shipped the idea as Hyper-Threading.

The issue-slot grid

Rows are the cycles C0–C9, columns the issue slots; a coloured cell is an instruction of T1–T4, a grey cell an empty slot, and the bars compare the four schemes on the same threads. "Figure 29" is the notes' fixed drawing. "Exam example" simulates four threads with their own ILP and stalls: T1 stalls after its fourth group (the slider sets how long), T2 and T4 have misses of 5 and 4 cycles, T3 a 2-cycle stall. Coarse-grained switches only on stalls of 3 cycles or more, paying one empty cycle; SMT hands the free slots to the ready threads one at a time, starting from a different thread every cycle.

  1. "Figure 29", fine-grained: no cycle is empty, yet 19 slots are wasted. Predict how many of them SMT fills, then switch the scheme.
    What you should see

    SMT fills 32 slots instead of 21: horizontal waste drops from 19 to 8. The 11 new instructions sit inside cycles that fine-grained gave to one thread. This is the insight the widget is for: only SMT fills slots inside a cycle; coarse- and fine-grained reassign whole cycles.

  2. "Exam example", coarse-grained, 4 threads. Move T1's stall from 3 cycles to 2. Predict the filled slots before you look.
    What you should see

    21 becomes 19, exactly the single thread's count with that stall: a 2-cycle stall is below the switch threshold, so coarse-grained just waits, and its bar equals the "one thread" bar. From 3 cycles on it switches twice, paying one empty cycle each time (C4 and C8), and stays at 21 however long the stall grows.

  3. "Exam example", quad-issue, fine-grained: set the threads to 1, 2, 3 and 4 and watch both kinds of waste.
    What you should see

    Vertical waste 12, 12, 0, 0 slots: with two threads T1 and T2 are stalled at the same time, from three on there is always a ready thread. Horizontal waste goes 12, 10, 16, 14 — up, not down. Fine-grained converts vertical waste into horizontal waste, as Tullsen wrote.

  4. "Exam example", dual-issue, SMT, 4 threads: compare the per-thread CPI readout with the ideal n/w.
    What you should see

    The grid is full, 20 of 20 slots, and the core's CPI is 0.5 = 1/w. The ideal per-thread CPI is 4/2 = 2; the threads get 5, 7, 5 and 3 instructions, CPI 2, 1.43, 2 and 3.33. The ideal is a fair share: T2 beats it while T4 waits for its miss and leaves its slots to the others. This is the kind of grid the June 2026 paper asks you to draw.

Which stalls does each scheme hide? It follows from the switch rule of section 2 and from who may use a cycle.

Which stall each scheme hides. Lengths are orders of magnitude: the DRAM miss from the notes (p. 372), the others typical of a modern out-of-order core.
StallLengthCoarse-grainedFine-grainedSMT
RAW dependence2–3 cyclesno: the switch costs moreyes, if another thread is readyyes
Branch misprediction10–20 cyclesno: about the cost of a drainyesyes: only that thread is squashed
Cache miss to DRAMhundreds of cyclesyesyesyes
Too little ILP in a cycleevery cyclenonoyes

SMT on an out-of-order core, and the exam’s ideal CPIs

Why does SMT live on a dynamically scheduled superscalar (lessons 11–18)? Because that core already has the two mechanisms SMT needs. Register renaming gives every instruction in flight a destination nobody else names — the ROB number of lesson 17, or a physical register — so T1's F2 and T2's F2 cannot be confused. And the scheduler already issues whatever is ready, whichever thread it comes from. "The SMT logic is added to the existing wide superscalar design" (p. 383). A VLIW's bundles, by contrast, are fixed by the compiler for one thread.

What SMT adds is short. Hennessy and Patterson list it in one line — a renaming table per thread, separate PCs, and the ability to commit instructions of several threads — and the notes' answer to the February 2025 paper expands it (pp. 576–577):

per thread shared T1 PC · registers T2 PC · registers T3 PC · registers T4 PC · registers select one pipeline 1 thread per cycle FUs · caches TLB · memory just a select

Before: four register files and a thread select

per thread shared T1 PC · map F2 → P12 T2 PC · map F2 → P37 T3 PC · map F2 → P5 T4 PC · map F2 → P50 physical register file one shared pool ROB · RS entries T1 T3 T2 FUs · caches

After: SMT, four rename maps and one register pool

Fig. 2. Where the state of a thread lives. An in-order fine- or coarse-grained core keeps one register file per thread, and a multiplexer picks the thread of the cycle (the notes' p. 378; Niagara works this way). An SMT core keeps per thread only a PC and a rename map: T1's F2 and T2's F2 name different physical registers of one shared pool, and a thread tag on every ROB and reservation-station entry routes results and commits (the notes' p. 576).

The first commercial SMT, Intel's Hyper-Threading in the Xeon of 2002, sorted the core's resources into three groups (Marr and others, 2002): duplicated, partitioned while two threads run, and shared. Partitioning a buffer guarantees that a stalled thread cannot fill it all, and the halves are "recombined when only one software thread is active". The price was "less than 5% to the relative chip size and maximum power requirements", the gain "up to 30% on common server application benchmarks". The notes give the same order of magnitude: a 2-way SMT core "often achieves 20-30% more throughput", not 2× (p. 383), and a single thread may run slightly slower because it now shares caches and predictors. The gain is largest when one thread stalls on memory while the other computes, or when the two use different units, one integer-heavy and one floating-point-heavy (p. 378); and since the same datapath does more work, the energy per instruction improves (p. 384).

How the first Hyper-Threading core split its resources between two threads (Marr and others, 2002, in the resources).
ClassResources
Duplicatedthe architecture state: general-purpose, control and machine-state registers; the interrupt controller; the instruction pointers and the register alias table (the rename map) of each thread
Partitioned while two threads runqueues and buffers: the re-order buffer (half each), the load and store buffers — recombined when one thread runs alone
Sharedcaches, execution units, branch predictors, control logic, buses

The arithmetic of the three papers

Each of the three official papers asks two numbers for a w-issue SMT core with n threads. Start from a concrete case, a dual-issue core with 4 threads, and draw the ideal: no grey cell anywhere, the slots handed out in turn. In 8 cycles there are 2 × 8 = 16 slots for 4 threads, 4 each, so T1 issues every second cycle. The general rule takes four steps, and a fifth checks it on the papers.

  1. Ideal means every one of the w slots is filled in every cycle: the core completes w instructions per cycle.

    \[ \mathrm{IPC}_{ideal} = w \;\Rightarrow\; \mathrm{CPI}_{ideal} = \frac{1}{w} \]

    It depends on the width only. Threads are how the core gets close to it, not a way to lower it.

  2. The n threads share the w slots evenly, so each completes w/n instructions per cycle.

    \[ \mathrm{IPC}_{thread} = \frac{w}{n} \]
  3. Invert to get the cycles per instruction of one thread.

    \[ \mathrm{CPI}_{thread} = \frac{n}{w} = n \cdot \mathrm{CPI}_{ideal} \]

    Sharing stretches a thread's cycles per instruction: its CPI is a multiple of the core's, never a fraction.

  4. A chip of c such cores completes c·w instructions per cycle, while a thread still shares only its own core's slots.

    \[ \mathrm{CPI}_{chip} = \frac{1}{c \cdot w} \] \[ \mathrm{CPI}_{thread} = \frac{n}{w} \ \text{(unchanged)} \]
  5. Check on the papers. Dual-issue, 4 threads: 1/2 = 0.5 and 4/2 = 2 (July 2024 quiz, June 2026). Quad-issue, 4 threads: 1/4 = 0.25 and 4/4 = 1 (July 2024, Question 2). Quad-issue, 8 threads: 1/4 = 0.25 and 8/4 = 2 (June 2025). Dual-core, dual-issue, 2 threads per core: 0.5 per core, 1/(2·2) = 0.25 for the chip, 2/2 = 1 per thread (June 2025).

Ideal CPI and ideal per-thread CPI

The picture is the ideal schedule: every slot filled in every cycle, the slots of each core handed in turn to its threads. Follow T1, the blue cells. Choose a paper's question to get its five options in a shuffled order and pick one; or set w, n and c yourself. Real grids stay above these numbers: Figure 29's SMT grid, a good case drawn by hand, has core CPI 0.3125 against the ideal 0.25.

  1. Dual-issue, 4 threads (July 2024, June 2026). Before you look: how many times does T1 issue in the 8 cycles drawn?
    What you should see

    4 times: 2 × 8 = 16 slots shared by 4 threads. 8 cycles / 4 instructions = 2 = n/w, while the core's ideal CPI is 1/2 = 0.5 — the option "0.5 & 2", Answer 3 in both papers.

  2. Pick "quad-issue, 4 threads (2024 Q2)", then set the threads to 8. Which readout moves, which stays?
    What you should see

    The ideal CPI stays 0.25 — only the width sets it. The ideal per-thread CPI doubles from 1 to 2: T1's blue cells thin out to one every second cycle. That is the June 2025 quiz, "0.25 & 2", and the insight of this widget: the width fixes the core's ideal, the threads only divide it.

  3. Dual-core, dual-issue, 2 threads per core (June 2025, Question 2). Predict the three numbers, then pick the option.
    What you should see

    Per core 1/2 = 0.5; chip 1/(2 × 2) = 0.25, four instructions per cycle on the chip; per thread 2/2 = 1. T1 shares only core 1's two slots with T2, so the second core does not change its CPI.

"More threads, lower CPI." The ideal CPI 1/w depends on the width alone: threads are a way to get near it, not to go below it. The ideal per-thread CPI n/w gets worse with every thread added.

Cores times threads: what lscpu counts, who shares which cache, and the dual-core question

Real chips combine both ideas: several cores, each running several hardware threads. The count is the notes' formula (81), p. 385:

\[ N_{hw} = N_{cores} \times N_{smt} \]
\(N_{hw}\)
total hardware threads: what the OS lists as logical CPUs
\(N_{cores}\)
physical cores (with several sockets: sockets × cores per socket)
\(N_{smt}\)
SMT threads per core

An Intel Core i7 with 8 cores and 2-way SMT has 16 hardware threads; an IBM POWER9 with 24 cores and 4-way SMT has 96 (p. 385). The operating system sees each hardware thread as a logical CPU. The notes' own laptop, a ThinkPad T430, reports it through lscpu; these are the lines that matter:

CPU(s):              8
Model name:          Intel(R) Core(TM) i7-3632QM CPU @ 2.20GHz
Thread(s) per core:  2
Core(s) per socket:  4
Socket(s):           1
Socket(s): 1 Core(s) per socket: 4 core ctx ctx L1 L2 core ctx ctx L1 L2 core ctx ctx L1 L2 core ctx ctx L1 L2 L3: shared by all four cores siblings share L1 Thread(s) per core: 2 1 socket × 4 cores × 2 threads = 8 logical CPUs
Fig. 3. The notes' lscpu example (p. 385) as boxes: one socket, four cores, two hardware contexts (ctx) per core — eight logical CPUs. The two contexts of a core share its L1, and on this chip its L2; the L3 is shared by all cores (p. 386).

A socket is the connector that holds one processor package. One socket × 4 cores × 2 threads gives 8 logical CPUs, so Linux can schedule eight software threads at once. The second thread of each core, however, "doesn't double performance. It just helps keep the core busy when one thread is stalled" (p. 385). The two ways of adding hardware threads are not equivalent (p. 386): more cores add execution resources and help threads that are truly independent and each need compute; more SMT threads per core help when a core has idle slots that one thread's ILP cannot fill.

Threads that share a core also share its caches (p. 386). The L1 is "almost always shared between SMT threads of the same core": simple, nothing duplicated, but the siblings can evict each other's lines — cache thrashing. The L2 is private to each core in most Intel and AMD designs and shared by a cluster of cores in others; the L3 is usually shared by all cores. Two active threads double the working set competing for the L1 and L2, so designers add partitioning of the cache space, quality-of-service mechanisms that keep one thread from starving the other, and replacement policies aware of the thread ID.

The June 2025 paper strings all of this into one question: a single-chip dual-core shared-memory processor, each core a dual-issue superscalar with up to 2 threads. Each core runs SMT. The chip completes 2 × 2 = 4 instructions per cycle, while T1 shares only its own core's two slots with T2:

The June 2025 chip in numbers: c = 2 cores, w = 2 slots per core, n = 2 threads per core.
QuantityFormulaValue
ideal per-core CPI\(1/w\)1/2 = 0.5
ideal dual-core CPI\(1/(c \cdot w)\)1/4 = 0.25
ideal per-thread CPI\(n/w\)2/2 = 1
hardware threads\(c \times n\)4

Inside each thread the instructions are scheduled dynamically — Tomasulo with renaming and a reorder buffer, lessons 11–18 — and the two cores' private caches are kept coherent by a snooping protocol such as MESI, lessons 35–36. The full answer, schedule included, is the second exam question below.

Multithreading is the smallest scale of thread-level parallelism. The same parallelism also runs on many cores sharing one memory, the multiprocessors of lessons 33–36, and on clusters of computers that share no memory at all.

Exam-style questions

The questions follow the forms of the papers: open questions with a table to fill, the five-line sub-point of the June 2026 paper, single-answer and true/false quizzes, and the schedules the papers ask you to draw. The model answers are computed here; there are no official solutions.

QUESTION 2: MULTITHREADING (5 points). Let's consider the fine-grained and simultaneous multithreading techniques used to manage thread-level parallelism by hardware processors. Answer to the following questions:

  • Explain the main concepts for each technique.
  • For each technique, make an example with up to 4 threads (T1, T2, T3, T4) on a quad-issue processor.
  • Let's consider a quad-issue SMT processor that can manage up to 4 threads: How much is the ideal CPI? How much is the ideal per-thread CPI?
  • What are the main benefits for each technique?
  • What are the main drawbacks for each technique?
Show model answer

Concepts. Fine-grained MT: the core holds the context (PC, registers) of several threads and switches thread every clock cycle, round robin, skipping a thread that is stalled; in each cycle all the issue slots belong to one thread. SMT: on a dynamically scheduled (out-of-order, renamed) superscalar, the issue slots of one cycle are filled with ready instructions of several threads; each thread has its own PC and renaming table, instructions carry a thread tag in the reservation stations and the ROB, and functional units and caches are shared.

Example, fine-grained (one thread per cycle; T4 is stalled at C7 and skipped):

CycleIssue 1Issue 2Issue 3Issue 4
C0T1T1T1–
C1T2T2T2–
C2T3T3T3–
C3T4T4T4–
C4T1T1––
C5T2T2––
C6T3–––
C7T1T1T1T1
C8T2T2T2–
C9T3T3––

Example, SMT (several threads per cycle; T4 is stalled from C3 to C6 and the others take its slots):

CycleIssue 1Issue 2Issue 3Issue 4
C0T1T2T3T4
C1T2T3T4T1
C2T3T4T1T2
C3T1T1T2T3
C4T1T1T1T2
C5T2T2T2T1
C6T3T3T1–
C7T4T4T3T3
C8T3T4T4T4
C9T3T3T3T4

Ideal CPI = 1 / issue width = 1/4 = 0.25. Ideal per-thread CPI = threads / issue width = 4/4 = 1: the four slots are shared by four threads, one instruction per cycle each.

Benefits. Fine-grained: hides short and long stalls (RAW, mispredictions, misses), because a stalled thread just loses its turn; no switch cost; simple fair rotation. SMT: the highest throughput, because it fills both the empty cycles (vertical waste) and the empty slots inside a cycle (horizontal waste); it combines ILP and TLP at a small hardware cost on an out-of-order core.

Drawbacks. Fine-grained: each thread runs slower when the others are ready (one cycle in N); the slots a thread cannot fill in its cycle stay empty; a thread selection every cycle. SMT: the threads compete for caches, functional units and branch predictors, so per-thread performance is lower and unpredictable; complex fetch, issue and commit logic; a larger register file.

This is the July 2024 question, a two-column table with five rows; the CPI row is asked for SMT only. What it checks: the rule "one thread per cycle" against "several threads per cycle", said in the concepts and visible in the drawings; the two numbers with their reason; benefits and drawbacks named in terms of waste. The two grids are the widget's exam example, quad-issue with four threads: fine-grained fills 26 of 40 slots, SMT 39. Any grid that respects the two rules is a valid example.

QUESTION 2: MULTICORE PROCESSORS (5 points). High-performance multicore processors today use a combination of several computer architecture techniques. Let's consider a single-chip dual-core shared-memory architecture where each core is a dual-issue superscalar processor with multi-threading up to 2 threads per core.

  • Explain the preferred technique used to manage the multiple threads for each core.
  • Make an example of scheduling up to 4 threads per chip where T1 and T2 are executed on Core1 and T3 and T4 on Core2 (table: Cycle C0–C9 × Core 1: Issue 1, Issue 2 × Core 2: Issue 1, Issue 2).
  • Let's consider our dual-issue SMT processor that can manage up to 4 concurrent threads (2-thread per core): How much is the ideal per core CPI? How much is the ideal dual-core CPI? How much is the ideal per-thread CPI?
  • Explain the preferred technique used in each superscalar processor to manage the instruction scheduling in each thread.
  • Explain the preferred technique used to manage the cache coherency problem in the dual core chip.
Show model answer

Threads in each core: simultaneous multithreading (Intel Hyper-Threading style). Both hardware threads of a core are active at once and, in the same cycle, their ready instructions fill the two issue slots of the shared out-of-order engine; per thread a PC and a renaming table, thread tags in the reservation stations and the ROB; caches and functional units shared.

CycleCore 1Core 2
Issue 1Issue 2Issue 1Issue 2
C0T1T2T3T4
C1T2T1T4T3
C2T1T2T3T4
C3T2T1T3–
C4T1T2––
C5T2T1––
C6T1T2T3T3
C7T2T1T4T3
C8T1–T3T4
C9T1–T4T3

Ideal CPIs: per core = 1/2 = 0.5; dual-core = 1/(2 × 2) = 0.25, since the chip completes four instructions per cycle; per thread = 2/2 = 1, since each thread shares its core's two slots with one other thread.

Scheduling inside each thread: dynamic scheduling — Tomasulo's algorithm with reservation stations and register renaming, out-of-order execution, and a reorder buffer for speculation with in-order commit, together with dynamic branch prediction.

Coherence: each core has private caches holding copies of shared blocks; a snooping write-invalidate, write-back protocol (MESI) on the shared bus keeps them coherent: a write to a shared block first invalidates the other copies.

The June 2025 question. The schedule is the widget's exam example split over two cores. At C4 and C5 both threads of core 2 are stalled: its slots stay empty, because core 1's threads cannot issue on core 2 — the thread-to-core assignment is part of the question. Any schedule in which each thread stays on its core and either thread of a core may take both of its slots is a valid example. For the last row snooping is the natural choice: two cores on one chip share a bus, while directories serve machines with many nodes (lessons 37–38).

Question 1: Instruction-Level and Thread-Level Parallelism. Modern processors exploit Instruction Level Parallelism and Thread Level Parallelism. Answer to the following questions:

  • Explain the main concepts for each approach (Instruction Level Parallelism ILP, Thread Level Parallelism TLP).
  • Which type of technique can be applied in superscalar processors to combine both ILP and TLP?
  • Explain what type of instruction scheduling is used in superscalar processors to combine both ILP and TLP?
  • What are the main hardware modifications required for a generic superscalar processor to support both ILP and TLP?
Show model answer

ILP executes independent instructions of one instruction stream in parallel: pipelining, multiple issue (superscalar or VLIW), dynamic scheduling with out-of-order execution, register renaming against WAR and WAW hazards, branch prediction and speculation. It is limited by true dependences, control dependences and memory latency, is extracted mostly by the hardware (by the compiler in a VLIW) and speeds up one thread. TLP executes independent instruction streams — threads or processes provided by the programmer or the OS — in parallel: multithreading in one core (coarse-grained, fine-grained, SMT), multicores and shared-memory multiprocessors (coherent caches, synchronisation with locks and barriers), and clusters with private memories and message passing. It raises the throughput of a multithreaded workload.

Combining both: simultaneous multithreading, which fills the issue slots of a superscalar in the same cycle with instructions of several threads.

Scheduling: dynamic scheduling — the hardware reorders the instructions at run time (Tomasulo with renaming and a reorder buffer), instead of static scheduling by the compiler as in simple in-order superscalars and VLIWs. One instruction window holds the instructions of all active threads; every cycle the ready instructions, from whichever thread, are issued to the free functional units. Renaming gives each in-flight instruction a unique physical destination, so threads cannot collide on register names.

Hardware: a PC per thread; a renaming table per thread over a larger shared physical register file that holds every thread's architectural registers; a thread tag on every instruction in the reservation stations, the ROB and the load/store queues; per-thread commit and exception squash; a fetch policy that selects the thread each cycle (round robin, ICOUNT); issue logic that picks ready instructions across threads; buffers shared or partitioned between threads; caches, functional units and predictors shared.

The question of the 11 February 2025 paper as the notes transcribe it (p. 574). Their worked answer (pp. 574–577) is long and has three slips, corrected in the red pens of sections 4 and 5: clusters do not share memory, SMT threads raise no coherence problem, and the buffers need not all grow. The compact hardware list of Hennessy and Patterson — a renaming table per thread, separate PCs, commit from several threads — is a good first line, then expand.

QUESTION 1: SUPERSCALAR PROCESSORS (8 points). Explain the main concepts and benefits of each one of the following techniques used by modern superscalar processors (Tomasulo-style): 1. Dynamic Instruction Scheduling; 2. Dynamic branch prediction and speculative execution; 3. Multiple-issue pipeline; 4. Reservation stations; 5. Dynamic Register Renaming; 6. Out-of-Order Execution; 7. Reorder Buffer; 8. Simultaneous multi-threading.

Here: sub-point 8 only, in five lines.

Show model answer

8. Simultaneous multi-threading. Several hardware threads are active at once in one out-of-order superscalar core: each keeps its own PC and renaming table over the shared physical registers, and a thread tag in the reservation stations and the ROB keeps results and commits apart. Every cycle the issue logic sends the ready instructions of any thread to the free functional units, so one cycle mixes threads. Benefit: the other threads fill the slots that one thread's ILP leaves empty (vertical and horizontal waste) — higher throughput and unit utilisation for little hardware (Hyper-Threading: under 5 % of the die, up to 30 % more throughput). Cost: shared caches and units, so single threads run slower and less predictably.

The June 2026 paper asks eight techniques in five lines each, one point apiece; SMT is sub-point 8. A good answer names four things: several threads issue in the same cycle (the line that separates SMT from fine-grained multithreading), on an out-of-order core with per-thread renaming and thread tags, filling the slots ILP leaves empty, at the price of contention. The other seven sub-points belong to lessons 5 to 18.

(SINGLE ANSWER) Let's consider a quad-issue SMT processor that can manage up to 8 simultaneous threads. What are the values of the ideal CPI and the ideal per-thread CPI?

  • Answer 1: Ideal CPI = 1 & Ideal per-thread CPI = 0.125 1 is the ideal of a single-issue pipeline, and 0.125 = 1/8 divides by the threads, as if sharing made a thread faster than the core.
  • Answer 2: Ideal CPI = 0.5 & Ideal per-thread CPI = 2 The per-thread value is right, but 0.5 is the ideal of a dual-issue core; four slots give 1/4.
  • Answer 3: Ideal CPI = 0.25 & Ideal per-thread CPI = 2 1/w = 1/4 = 0.25; eight threads share four slots, half an instruction per cycle each: 8/4 = 2.
  • Answer 4: Ideal CPI = 0.5 & Ideal per-thread CPI = 4 Both values belong to a dual-issue core with 8 threads: 1/2 and 8/2.
  • Answer 5: Ideal CPI = 0.25 & Ideal per-thread CPI = 4 The core value is right; 4 would need sixteen threads on four slots.
Show model answer

Answer 3. Ideal CPI = 1 / issue width = 1/4 = 0.25; ideal per-thread CPI = threads / issue width = 8/4 = 2.

The June 2025 quiz, with its options verbatim. All three papers build the five options from the same few numbers permuted, so the only defence is the two formulas: 1/w for the core, n/w per thread. The CPI widget of section 4 drills the other two papers' versions.

(SINGLE ANSWER, 1 point) Let's consider a dual-issue SMT processor that can manage up to 4 hardware threads. What are the values of the ideal CPI and the ideal per-thread CPI? Answer 1: Ideal CPI = 1 & Ideal per-thread CPI = 0.25. Answer 2: Ideal CPI = 0.25 & Ideal per-thread CPI = 0.25. Answer 3: Ideal CPI = 0.5 & Ideal per-thread CPI = 2. Answer 4: Ideal CPI = 0.5 & Ideal per-thread CPI = 1. Answer 5: Ideal CPI = 0.25 & Ideal per-thread CPI = 4.

Make a practical example of SMT scheduling with up to 4 threads (T1, T2, T3, T4) on the dual-issue processor (1 point), in the table C0–C9.

Show model answer

Answer 3: ideal CPI = 1/2 = 0.5; ideal per-thread CPI = 4/2 = 2.

CycleIssue 1Issue 2
C0T1T2
C1T2T3
C2T3T4
C3T4T1
C4T1T2
C5T2T3
C6T3T4
C7T1T2
C8T1T2
C9T2T3

In every cycle the two slots hold instructions of two threads issued together. From C7 on T4 waits for a miss and the other threads take its slots.

The June 2026 Question 5: 1 point for the option and 1 for the example. The example must show what makes SMT simultaneous — different threads in the same row; a row with the same thread twice is allowed too (that thread had two ready instructions). This grid is the widget's exam example on the dual-issue core; it fills all 20 slots.

(True/False) In fine-grained multithreading, instructions from different threads can be issued in the same clock cycle.

  • True That is the definition of simultaneous multithreading. Fine-grained MT changes thread between cycles; inside a cycle all the issued instructions belong to one thread.
  • False Right: one thread per cycle, a different one every cycle. That is exactly why fine-grained MT leaves horizontal waste.
Show model answer

False. Fine-grained multithreading switches thread every clock cycle, so consecutive cycles may belong to different threads, but within one cycle only one thread issues; issuing from several threads in the same cycle is simultaneous multithreading.

The classic confusion in the July 2024 two-column answer. If the drawing of the fine-grained column shows two threads in one row, the example contradicts the concept.

Check yourself

A quad-issue core runs fine-grained multithreading with four ready threads. In one cycle, thread T3 issues one instruction and three slots stay empty. What is this waste, and which scheme could have used the three slots?

  • Vertical waste; coarse-grained could fill it Vertical waste is a cycle with no issue at all; here T3 issued one. And coarse-grained also gives the whole cycle to one thread.
  • Horizontal waste; only SMT could fill it Empty slots in a busy cycle are horizontal waste. Coarse- and fine-grained give each cycle to one thread, so only issuing from several threads in the same cycle fills them.
  • Horizontal waste; fine-grained with eight threads would fill it More threads make an empty cycle rarer, but the rule is still one thread per cycle: T3's single instruction still leaves three slots.
  • No waste: T3 had nothing more to issue From T3's point of view, yes; but the slots were paid for and stayed idle, and that is exactly what the word waste counts.

A coarse-grained core needs 4 cycles to drain and refill its pipeline on a thread switch. The running thread meets a 3-cycle RAW stall. What should the core do?

  • Switch, so that another thread hides the 3 cycles The switch alone costs 4 cycles: max(0, 3 − 4) = 0 hidden, and one cycle more lost than by waiting.
  • Stay, and wait 3 cycles Waiting costs 3 cycles, switching 4. Coarse-grained switches only on stalls much longer than its switch cost, such as a miss to DRAM.
  • Ask the operating system for a context switch Thousands of cycles to hide three.

Which of these are shared by the hardware threads of one SMT core? Select all that apply.

  • The integer and floating-point functional units Shared: keeping them busy with several threads is the point of SMT.
  • The L1 data cache Shared by the siblings (p. 386), which is why they can evict each other's lines.
  • The branch predictor Shared: the notes list branch predictors among the resources the threads compete for (p. 381).
  • The program counter Each thread has its own: it records where that thread is in its code.
  • The rename map One per thread: T1's F2 and T2's F2 must point to different physical registers.

The rule of thumb: whatever describes where a thread is and what its registers hold is per thread; whatever does the work or stores data is shared.

A quad-issue SMT core is redesigned to hold 8 hardware threads instead of 4. What happens to the ideal CPI and to the ideal per-thread CPI?

  • The ideal CPI halves to 0.125; the per-thread CPI stays 1 The slots per cycle are still four: 1/w = 0.25 does not move.
  • The ideal CPI stays 0.25; the per-thread CPI doubles from 1 to 2 The width alone sets 1/w; eight threads share the four slots: 8/4 = 2.
  • Both stay the same Each thread's share of the slots halves, so its CPI doubles.
  • The ideal CPI stays 0.25; the per-thread CPI halves to 0.5 Inverted: more threads on the same slots means fewer slots per thread, so a larger CPI.

lscpu prints Socket(s): 2, Core(s) per socket: 12, Thread(s) per core: 2. How many logical CPUs does the operating system see?

  • 24 That counts the cores; each core holds two hardware threads.
  • 48 2 sockets × 12 cores × 2 threads = 48 hardware threads, each a logical CPU.
  • 16 The three numbers multiply, they do not add.
  • 96 Each factor counts once: 2 × 12 × 2 = 48.

On which workload does turning SMT on pay best?

  • A web server handling hundreds of independent requests, often waiting on memory Many ready threads with low ILP and many misses: their empty slots are what SMT fills. Throughput is what a server is judged on.
  • A single-threaded program whose own completion time matters With one thread the extra contexts sit idle, and the thread's latency does not improve.
  • One numerical kernel that already sustains nearly 4 instructions per cycle on a quad-issue core Its slots are already full: a second thread can only compete for them and for the cache.

Key take-aways

What to watch and read