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.
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).
Before: one thread (superscalar)
After: four threads in the same cycles (SMT)
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:
- \(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.
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.
- \(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.
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 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 | – |
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 4 |
|---|---|---|---|---|
| C0 | T1 | T1 | – | – |
| C1 | T1 | – | – | – |
| C2 | T1 | T1 | T1 | – |
| C3 | T1 | T1 | – | – |
| C4 | T1 | T1 | T1 | T1 |
| C5 | T2 | T2 | T2 | – |
| C6 | T2 | T2 | T2 | – |
| C7 | T2 | T2 | – | – |
| C8 | T2 | – | – | – |
| C9 | – | – | – | – |
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 4 |
|---|---|---|---|---|
| C0 | T1 | T1 | – | – |
| C1 | T2 | T2 | T2 | – |
| C2 | T3 | T3 | T3 | – |
| C3 | T4 | – | – | – |
| C4 | T1 | – | – | – |
| C5 | T2 | T2 | – | – |
| C6 | T3 | T3 | – | – |
| C7 | T4 | T4 | T4 | – |
| C8 | T1 | T1 | T1 | – |
| C9 | T2 | – | – | – |
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 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 | – | – |
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).
| Coarse-grained | Fine-grained | SMT | |
|---|---|---|---|
| Changes thread | on a long-latency stall | every cycle, round robin, skipping stalled threads | never: all threads active at once |
| Threads issuing in one cycle | one | one | several |
| Cost of a switch | a few cycles: drain and refill | none | none |
| Hides | long stalls only | all stalls, short ones too | all stalls, and the holes inside a cycle |
| Costs | short stalls still waste whole cycles | each thread runs slower; a thread choice every cycle | contention for caches, units, predictors; unpredictable per-thread speed; complex issue logic |
| Machines | IBM RS64-II, Itanium 2 Montecito | Sun Niagara; GPU warp schedulers | Intel 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.
| Scheme | Filled | \(U\) | CPI | Vertical | Horizontal | Per-thread CPI |
|---|---|---|---|---|---|---|
| One thread | 16 | 0.40 | 0.625 | 12 | 12 | 0.625 |
| Coarse, 2 threads | 21 | 0.525 | 0.476 | 4 | 15 | 0.83 · 1.11 |
| Fine, 4 threads | 21 | 0.525 | 0.476 | 0 | 19 | 1.67 · 1.67 · 2 · 2.5 |
| SMT, 4 threads | 32 | 0.80 | 0.3125 | 0 | 8 | 1.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.
Which stalls does each scheme hide? It follows from the switch rule of section 2 and from who may use a cycle.
| Stall | Length | Coarse-grained | Fine-grained | SMT |
|---|---|---|---|---|
| RAW dependence | 2–3 cycles | no: the switch costs more | yes, if another thread is ready | yes |
| Branch misprediction | 10–20 cycles | no: about the cost of a drain | yes | yes: only that thread is squashed |
| Cache miss to DRAM | hundreds of cycles | yes | yes | yes |
| Too little ILP in a cycle | every cycle | no | no | yes |
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):
- One rename map per thread over one shared, larger physical register file, which holds the architectural registers of every thread.
- A thread-ID tag on every instruction in the reservation stations, the ROB and the load/store queues, so that results, commits and exception squashes reach the right thread.
- Thread-aware fetch and issue: several PCs, and a policy that picks the thread to fetch each cycle — round robin, or ICOUNT, which favours the thread with the fewest instructions in the front end (Tullsen's group, 1996) — so that a stalled thread cannot clog the shared queues.
- Per-thread commit and exceptions: a fault squashes only the faulting thread's instructions.
Before: four register files and a thread select
After: SMT, four rename maps and one register pool
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).
| Class | Resources |
|---|---|
| Duplicated | the 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 run | queues and buffers: the re-order buffer (half each), the load and store buffers — recombined when one thread runs alone |
| Shared | caches, 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.
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.
The n threads share the w slots evenly, so each completes w/n instructions per cycle.
\[ \mathrm{IPC}_{thread} = \frac{w}{n} \]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.
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)} \]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).
"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}\)
- 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
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:
| Quantity | Formula | Value |
|---|---|---|
| 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):
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 4 |
|---|---|---|---|---|
| C0 | T1 | T1 | T1 | – |
| C1 | T2 | T2 | T2 | – |
| C2 | T3 | T3 | T3 | – |
| C3 | T4 | T4 | T4 | – |
| C4 | T1 | T1 | – | – |
| C5 | T2 | T2 | – | – |
| C6 | T3 | – | – | – |
| C7 | T1 | T1 | T1 | T1 |
| C8 | T2 | T2 | T2 | – |
| C9 | T3 | T3 | – | – |
Example, SMT (several threads per cycle; T4 is stalled from C3 to C6 and the others take its slots):
| Cycle | Issue 1 | Issue 2 | Issue 3 | Issue 4 |
|---|---|---|---|---|
| C0 | T1 | T2 | T3 | T4 |
| C1 | T2 | T3 | T4 | T1 |
| C2 | T3 | T4 | T1 | T2 |
| C3 | T1 | T1 | T2 | T3 |
| C4 | T1 | T1 | T1 | T2 |
| C5 | T2 | T2 | T2 | T1 |
| C6 | T3 | T3 | T1 | – |
| C7 | T4 | T4 | T3 | T3 |
| C8 | T3 | T4 | T4 | T4 |
| C9 | T3 | T3 | T3 | T4 |
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.
| Cycle | Core 1 | Core 2 | ||
|---|---|---|---|---|
| Issue 1 | Issue 2 | Issue 1 | Issue 2 | |
| C0 | T1 | T2 | T3 | T4 |
| C1 | T2 | T1 | T4 | T3 |
| C2 | T1 | T2 | T3 | T4 |
| C3 | T2 | T1 | T3 | – |
| C4 | T1 | T2 | – | – |
| C5 | T2 | T1 | – | – |
| C6 | T1 | T2 | T3 | T3 |
| C7 | T2 | T1 | T4 | T3 |
| C8 | T1 | – | T3 | T4 |
| C9 | T1 | – | T4 | T3 |
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?
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.
| Cycle | Issue 1 | Issue 2 |
|---|---|---|
| C0 | T1 | T2 |
| C1 | T2 | T3 |
| C2 | T3 | T4 |
| C3 | T4 | T1 |
| C4 | T1 | T2 |
| C5 | T2 | T3 |
| C6 | T3 | T4 |
| C7 | T1 | T2 |
| C8 | T1 | T2 |
| C9 | T2 | T3 |
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.
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?
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?
Which of these are shared by the hardware threads of one SMT core? Select all that apply.
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?
lscpu prints Socket(s): 2, Core(s) per socket: 12, Thread(s) per core: 2. How many logical CPUs does the operating system see?
On which workload does turning SMT on pay best?
Key take-aways
- One thread leaves two kinds of holes in a wide core: whole empty cycles while it stalls (vertical waste) and empty slots in busy cycles because its ILP is low (horizontal waste); Figure 29's quad-issue core fills 16 of 40 slots.
- A hardware thread is a context kept in the core — PC, registers or a rename map, status bits — while units and caches are shared; changing thread is a select, not an OS copy of thousands of cycles, and a switch hides \(\max(0, L - S)\) cycles.
- Coarse-grained multithreading switches only on long stalls and pays a drain; fine-grained switches every cycle, skipping stalled threads, with one thread per cycle; SMT issues several threads in the same cycle. That answers the opening puzzle: coarse and fine reach the same 21 slots by reassigning whole cycles, and SMT's eleven extra slots are horizontal waste that only it can fill.
- SMT is added to an out-of-order core: per-thread PCs and rename maps over one physical register file, thread tags in the RS and the ROB, per-thread commit; Hyper-Threading cost under 5 % of the chip for up to 30 % more throughput, not 2×.
- Ideal CPI = 1/w, ideal per-thread CPI = n/w, ideal chip CPI = 1/(c·w); more threads never lower the first and always raise the second, and real grids stay above the ideal.
- Hardware threads = cores × threads per core = the logical CPUs of
lscpu; SMT siblings share the L1 and fight over it (contention, not coherence); coherence is between the private caches of different cores.
What to watch and read
-
Computer Architecture, Lecture 28: Fine-Grained Multithreading (ETH Zürich, Fall 2020)
Onur Mutlu
The animated pipeline in which every cycle belongs to a different thread — the CDC 6600, HEP and Tera machines — and why that removes dependence checking and the need for branch prediction at the cost of single-thread latency, before the contrast with SMT.
-
Simultaneous Multithreading: Maximizing On-Chip Parallelism (ISCA 1995)
D. Tullsen, S. Eggers, H. Levy
Figure 1 is the original picture of horizontal and vertical waste, and section 3 has the 19 % utilisation of the 8-issue superscalar quoted in this lesson; read it with the exam question "main concepts and benefits of SMT" in mind.
-
Hyper-Threading Technology Architecture and Microarchitecture (Intel Technology Journal, 2002)
D. Marr and others, Intel
The article starts on page 4 of the issue: the duplicated, partitioned and shared resources of the first commercial SMT core, its "less than 5%" cost and its "up to 30%" gain.
-
Niagara: A 32-Way Multithreaded Sparc Processor (IEEE Micro, 2005)
P. Kongetira, K. Aingaran, K. Olukotun
Fine-grained multithreading as a product: eight single-issue pipelines with four threads each, a "thread select" pipeline stage, and the case for throughput over single-thread speed in servers.