10 lessons

Multicore & Coherence

What changes when there is more than one core: hardware threads versus OS threads, the coherence protocol keeping caches consistent, false sharing, NUMA and why moving a thread costs cache.

SourceCompilerInstructionsFront EndExecutionRegistersCachesMemoryI/OBehavior
What a Second Core Actually Adds

Eight cores is not one core that goes eight times faster. It is eight execution engines, each with private caches, sharing one last-level cache and one memory system through an interconnect — and that shared half is where multicore performance is usually won or lost.

Q · What is actually duplicated when a chip gains a second core, and what is still shared?
Core, Hardware Thread, Software Thread

Three things routinely called "a thread", stacked on top of each other. A core is silicon that executes. A hardware thread is an execution context inside it. A software thread is an OS bookkeeping structure that gets mapped onto one. Conflating them is how "we have 16 threads" becomes a wrong capacity estimate.

Q · When someone says "this machine has 16 threads", what exactly are they counting?
SMT: Two Contexts, One Core

Simultaneous multithreading gives one physical core a second register set so it can switch instruction streams instantly and fill cycles the first stream would waste. It does not add execution units, and it does not add a core. On the right workload it is a solid gain; on the wrong one it is negative.

Q · What does a second hardware thread on the same core actually give me, and when does it give me nothing?
Hardware Threads Are Not OS Threads

A §224 distinction the whole concurrency stack rests on. A hardware thread is a fixed execution context built into silicon. An OS thread is an allocated software object. The OS multiplexes many of the second onto few of the first, and every scheduling cost you can measure lives in that mapping.

Q · Where does a software thread stop being a data structure and start being something a core executes?
Cache Coherence: Why Shared Memory Works At All
▶ lab

Two cores cache the same variable. One writes. Nothing in your code tells the other core to look again — yet it must not read stale data. Coherence is the hardware protocol that guarantees it, running underneath every shared-memory program, and it is emphatically not free.

Q · When one core writes a variable that another core has cached, what makes the second core see the new value?
MESI and Its Relatives
▶ lab

Coherence needs each cached line tagged with what the core is allowed to do with it. MESI — Modified, Exclusive, Shared, Invalid — is the canonical four-state answer and the one worth learning. It is a family, not a standard: real chips extend it, and which variant yours uses is usually undocumented.

Q · What state does a core track per cache line, and what transitions does a read or a write trigger?
False Sharing: Independent Data, Shared Line
▶ lab

Two threads update two different variables. They never touch each other's data and the code is obviously correct. Throughput is worse than single-threaded, because the two variables happen to sit in one cache line and the hardware shares by line, not by variable.

Q · Why do two threads writing to genuinely separate variables slow each other down?
NUMA: Not All Memory Is Equally Far
▶ lab

On a multi-socket machine, memory is attached to sockets. A core reaching its own socket's memory is on a short path; reaching the other socket's memory crosses an inter-socket link. Same instruction, same address space, materially different cost — and the allocator decides which you get.

Q · Why does the same memory access cost more depending on which core is doing it?
Thread Affinity: Pinning and Its Price

Affinity constrains which cores a thread may run on. It buys cache locality, NUMA locality and predictable latency, and it costs the scheduler's ability to balance load. It is a genuine tool for latency-critical work and a genuine way to make a machine slower if applied by reflex.

Q · When does restricting a thread to specific cores make things faster, and when does it just tie the scheduler's hands?
Cache Warmth and the Real Cost of Migration

The expensive part of a context switch is not saving registers. It is that the thread resumes on a core whose caches and TLB hold someone else's data, so it must take a burst of cold misses to rebuild a working set that existed perfectly well a moment ago somewhere else.

Q · Why does a context switch cost far more than saving and restoring registers?