6.1.2 · D4Parallelism & Multicore

Exercises — Instruction-level vs thread-level parallelism

2,332 words11 min readBack to topic

These exercises climb a ladder. L1 Recognition (can you name it?) → L2 Application (can you plug into the formula?) → L3 Analysis (can you explain why a number comes out?) → L4 Synthesis (can you combine ideas?) → L5 Mastery (can you design and defend a choice?).

Every problem has a full worked solution hidden inside a collapsible callout — cover it, try yourself, then reveal. This page is your self-test for the parent topic.

Before we start, one shared toolbox. We will lean on Amdahl's Law repeatedly, so let us make sure every symbol is earned.

A picture of why the serial part is the villain:


Level 1 — Recognition

Recall Solution 1.1

(a) ILP — many independent instructions, one stream. This is the superscalar idea. (b) TLP — many independent streams (tabs), different cores. (c) DLPone instruction, many data. See SIMD-Vector-Processing. It is NOT ILP (only one instruction!) and NOT TLP (only one thread!). (d) TLP — two threads share one core. Sharing execution units within a core is still thread-level, because the streams are independent programs.

Recall Solution 1.2

False. Issue width is an ILP knob — it lets one thread finish faster by executing more of its own independent instructions per cycle. The number of threads is a TLP knob (cores / hardware contexts). They are orthogonal dials: you can raise one while the other stays fixed.


Level 2 — Application

Recall Solution 2.1

Plug in: serial fraction , parallel part . Notice the serial 0.2 already equals the whole parallel part — that is why we do not get anywhere near .

Recall Solution 2.2

(a) . (b) . Eight-fold more cores (8 → 64) gave only ~2.6× more speedup. The serial 0.05 is choking us.

Recall Solution 2.3

ILP and TLP are independent multiplicative factors here (each thread individually enjoys the ILP win): (matches the parent's ).


Level 3 — Analysis

Recall Solution 3.1

(a) . ✓ (b) The serial dependency chain (pointer chasing — you cannot load next until the current load returns) pins ; that 0.9 term dominates the denominator no matter how wide the machine is. : . Going 4→16 wide bought us from 1.081 to 1.103 — a rounding error. This is why Memory-Level-Parallelism and pointer-chasing latency dominate such code.

Recall Solution 3.2

Design A (pure ILP): .

Design B (TLP × per-thread ILP): Per-thread ILP: . TLP across 4 cores: . Combined: .

Design B wins ( vs ) because deep ILP hits diminishing returns (that ceiling), whereas spreading work across cores exploits the abundant algorithmic parallelism . This is the industry's swing toward multicore — see Power-Performance-Tradeoffs.


Level 4 — Synthesis

Recall Solution 4.1

For each: , , total .

Total

Best: . Because (more parallel fraction lives in threads than in instructions), the optimum leans toward more cores — but not all the way to , since a little ILP width still pays. The sweet spot is interior.

Recall Solution 4.2

Ceiling first: as , , so . Good — is below the ceiling, so it is reachable.

Solve . So cores (must round up to an integer). Check: ✓; (short).


Level 5 — Mastery

Recall Solution 5.1

, .

Total

(a) wins (). ILP is nearly useless here ( ceiling ), so wide cores are wasted silicon. Thread count is the only lever with headroom.

(b) Yes, SMT plausibly beats all three. The bottleneck is latency, not throughput: each thread stalls waiting for a memory load to return (pointer chasing). SMT lets a core, while thread T1 is stalled on a load miss, execute thread T2's ready instructions — filling otherwise-dead cycles. This converts memory latency into useful work without needing the algorithm to be more parallel. It directly attacks the exact weakness (load-to-use stalls) that both ILP and naive multicore fail to hide. This is Memory-Level-Parallelism harvested through threading.

Recall Solution 5.2

Set , : . .

So 99.78% of the work must be parallel; only 0.22% may be serial. In plain words: the code must be almost perfectly dividable with essentially no setup, synchronization, or final-merge step. Real reason it fails: synchronization and shared-data overhead (locks, cache-coherence traffic between 128 cores, thread spawn/join) easily eat more than 0.22%, pushing the effective serial fraction up and the speedup far below the claim.