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) ILP — many independent instructions, one stream. This is the superscalar idea.
(b) TLP — many independent streams (tabs), different cores.
(c) DLP — one 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 n 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.
Plug in: serial fraction 1−f=0.2, parallel part f/n=0.8/4=0.2.
SILP=0.2+0.21=0.41=2.50×
Notice the serial 0.2 already equals the whole parallel part — that is why we do not get anywhere near 4×.
Recall Solution 2.2
(a) S=0.05+0.95/81=0.05+0.118751=0.168751=5.93×.
(b) S=0.05+0.95/641=0.05+0.01484381=0.06484381=15.42×.
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):
Scombined=SILP×STLP=2.11×7.46=15.74×
(matches the parent's 15.7×).
(a) S=0.9+0.1/41=0.9251=1.081×. ✓
(b) The serial dependency chain (pointer chasing — you cannot load next until the current load returns) pins 1−f=0.9; that 0.9 term dominates the denominator no matter how wide the machine is.
n=16: S=0.9+0.1/161=0.906251=1.103×. 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):SA=0.4+0.6/61=0.4+0.11=0.51=2.00×.
Design B (TLP × per-thread ILP):
Per-thread ILP: SILP=0.4+0.6/21=0.71=1.4286×.
TLP across 4 cores: STLP=0.1+0.9/41=0.3251=3.0769×.
Combined: 1.4286×3.0769=4.396×.
Design B wins (4.40× vs 2.00×) because deep ILP hits diminishing returns (that f=0.6 ceiling), whereas spreading work across cores exploits the abundant algorithmic parallelism p=0.9. This is the industry's swing toward multicore — see Power-Performance-Tradeoffs.
For each: SILP(n)=0.3+0.7/n1, STLP(N)=0.1+0.9/N1, total =SILP⋅STLP.
(N,n)
SILP
STLP
Total
(1,8)
0.38751=2.581
1.01=1.000
2.581
(2,4)
0.4751=2.105
0.551=1.818
3.827
(4,2)
0.651=1.538
0.3251=3.077
4.734
(8,1)
1.01=1.000
0.21251=4.706
4.706
Best: (4,2) → 4.73×. Because p>f (more parallel fraction lives in threads than in instructions), the optimum leans toward more cores — but not all the way to (8,1), since a little ILP width still pays. The sweet spot is interior.
Recall Solution 4.2
Ceiling first: as N→∞, Np→0, so Smax=1−p1=0.11=10×. Good — 6× is below the ceiling, so it is reachable.
Solve 0.1+0.9/N1≥6⇒0.1+N0.9≤61=0.166⇒N0.9≤0.066⇒N≥0.06660.9=13.5.
So N=14 cores (must round up to an integer). Check: S(14)=0.1+0.9/141=0.1642861=6.087× ✓; S(13)=0.1692311=5.909× (short).
(a) (8,1) wins (2.58×). ILP is nearly useless here (f=0.15 ceiling ≈1.18×), 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 S=100, N=128: (1−p)+p/1281=100⇒(1−p)+128p=0.01.
1−p+0.0078125p=0.01⇒1−0.9921875p=0.01⇒p=0.99218750.99=0.997797.
So p≈0.9978 — 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.