Computer Organization and Design — Chapter 7
By the end of this lecture, you should be able to:
Parts 1–10 follow Sections 7.1–7.13 of the textbook.
Goal: do more work in less time, while using energy efficiently.
Consequence for you
Sequential programs no longer get faster “for free” on new chips. To go faster, programs must use the extra cores.
A multicore chip is one kind of multiprocessor. A cluster links whole computers together.
| Term | Meaning |
|---|---|
| Uniprocessor | A computer with one processor |
| Multiprocessor | A computer with two or more processors (the general term) |
| Multicore | Several processors (cores) on one chip. A quad-core chip has 4 cores. |
| Cluster | Separate computers, each with its own memory, connected by a network to work as one big system |
Note
Key takeaway: more processors can improve performance, but only if the software is designed to use them.
Steps follow one fixed order.
Example: a compiler: lexical analysis → parsing → code generation → optimization.
Example: compute the total price, add tax, then print the result.
Many activities make progress over overlapping periods.
Example: an operating system handling downloads, keyboard input and music playback, all at once.
Important
Running a sequential program on a multicore computer does not automatically make it faster. It still uses only one core at a time.
| Sequential software | Concurrent software | |
|---|---|---|
| Serial hardware (1 core) | Matrix multiply on a Pentium 4 | Operating system on a Pentium 4 |
| Parallel hardware (many cores) | Matrix multiply on an 8-core Xeon (may use only 1 core!) | Operating system on an 8-core Xeon |
The challenge: make both kinds of software run fast on parallel hardware.
Hardware gives us the opportunity for parallelism. Software must use it, and that is the hard part.
Eight reporters want to write one news story 8× faster.
What can go wrong?
Same problems in parallel programs
More reporters (processors) → these problems get worse. Parallel programs must be both correct and efficient.
The part of a program you cannot speed up limits the total speed-up.
\[ \text{Time after} = \frac{\text{Time affected}}{\text{Amount of improvement}} + \text{Time unaffected} \]
If the original time is 1 and a fraction \(F\) can run in parallel on \(P\) processors:
\[ \text{Speed-up} = \frac{1}{(1 - F) + \dfrac{F}{P}} \]
Even with only 1% sequential code, 128 processors give less than 60×.
Goal: a speed-up of 90× with 100 processors. How much of the program can be sequential?
Takeaway
To use many cores well, almost everything must be parallel.
Sum 10 scalar variables (sequential) + sum two matrices (parallel). One addition takes time \(t\).
| Problem | 1 processor | 10 processors | 100 processors |
|---|---|---|---|
| 10×10 (100 adds) | \(110t\) | \(\frac{100t}{10} + 10t = 20t\) → 5.5× | \(\frac{100t}{100} + 10t = 11t\) → 10× |
| 100×100 (10,000 adds) | \(10{,}010t\) | \(\frac{10{,}000t}{10} + 10t = 1010t\) → 9.9× | \(\frac{10{,}000t}{100} + 10t = 110t\) → 91× |
With 100 processors: small problem → only 10% of the ideal 100×; large problem → over 90%. Bigger problems are easier to speed up: the parallel part grows, the sequential part doesn’t.
Real-world example: a bank benchmark (TPC-C) must add more customer accounts to report more transactions per minute. Customers don’t use the ATM 100× more often just because the bank bought a faster computer.
Same 100×100 problem on 100 processors. Ideal: each processor does 1% of the work → 91×.
What if one processor gets more than its share?
| One processor’s share | Time | Speed-up |
|---|---|---|
| 1% (balanced) | \(100t + 10t = 110t\) | 91× |
| 2% (200 adds) | \(\max\!\left(\frac{9800t}{99}, 200t\right) + 10t = 210t\) | 48× |
| 5% (500 adds) | \(\max\!\left(\frac{9500t}{99}, 500t\right) + 10t = 510t\) | 20× |
Everyone must wait for the slowest processor. One processor with 2× the load cuts the speed-up almost in half.
True or false: Strong scaling is not bound by Amdahl’s law.
False. Strong scaling keeps the problem size fixed, so the sequential part limits the speed-up exactly as Amdahl’s law says. (Weak scaling can hide this by growing the parallel part.)
load or store any memory location.Important
Sharing memory makes communication easy, but cores must coordinate when they read and write the same data (next slides).
| UMA | NUMA | |
|---|---|---|
| Full name | Uniform Memory Access | Non-Uniform Memory Access |
| Memory access time | About the same for every processor and every address | Faster for nearby memory, slower for far memory |
| Programming | Easier | Harder (you should care where data lives) |
| Scale | Smaller systems | Scales to larger systems |
When processors share data, they must coordinate.
Note
Section 2.11 showed the MIPS instructions used to build locks (ll / sc).
100 processors, numbered Pn = 0 … 99. Each sums its own 1,000 numbers.
Step 1: each processor sums its own slice
A; each processor just starts at a different address.A reduction combines many values into one.
100 partial sums need only \(\lceil\log_2 100\rceil = 7\) rounds instead of 99 sequential additions.
half = 100; /* 100 processors */
repeat
synch(); /* wait for partial sums to finish */
if (half % 2 != 0 && Pn == 0)
sum[0] = sum[0] + sum[half-1]; /* odd case: P0 takes the extra one */
half = half / 2; /* dividing line on who sums */
if (Pn < half)
sum[Pn] = sum[Pn] + sum[Pn+half];
until (half == 1); /* final sum is in sum[0] */synch() is a barrier: no processor continues until all arrive.i and half must be private variables, one copy per processor.True or false: Shared memory multiprocessors cannot take advantage of job-level parallelism.
False. An SMP can run many independent jobs at once, each in its own virtual address space.
send a message, and another must receive it.send / receive also act as synchronization: the receiver waits until the message arrives.A cluster is a set of ordinary computers connected by standard network switches and cables.
| ✅ Strengths | ❌ Weaknesses |
|---|---|
| Cheap commodity parts | Managing n machines ≈ cost of n separate machines |
| High availability: replace a broken machine without stopping the system | Connected through I/O (slower) instead of the memory interconnect |
| Easy to expand gradually | Memory is divided: n memories and n copies of the OS |
How much more memory is available for user programs with shared memory?
\[ \frac{20 - 1}{5 \times (4 - 1)} = \frac{19}{15} \approx 1.27 \]
The shared-memory machine has about 27% more space for user programs, even though both systems have 20 GB in total.
Step 1: One processor sends 1,000 numbers to each of the 100 nodes.
Step 2: Every node sums its local array:
Now each of the 100 nodes holds one partial sum in its own memory.
Step 3: combine the partial sums by sending messages:
Upper half sends, lower half receives and adds: same divide-and-conquer idea, but with messages.
| Shared memory (SMP) | Message passing (cluster) | |
|---|---|---|
| Address space | One, shared | One per node, private |
| Communication | Implicit (load/store) |
Explicit (send/receive) |
| Synchronization | Locks, barriers | Built into send/receive |
| Hardware design | Harder (cache coherence) | Easier |
| Porting a sequential program | Easier | Harder (plan every message) |
| Performance surprises | More (hidden communication) | Fewer (visible communication) |
| Availability / expansion | Harder | Easier |
Idea: when one thread stalls (e.g., waiting on a cache miss), let another thread use the processor.
To make this possible, the hardware keeps a separate copy of each thread’s state:
Memory is shared through virtual memory.
Why hardware?
A thread switch in hardware can be almost instant. A process switch in the operating system takes hundreds to thousands of cycles.
| Style | When does it switch threads? | 👍 Good | 👎 Bad |
|---|---|---|---|
| Fine-grained | Every cycle (round-robin) | Hides short and long stalls | Each thread runs slower |
| Coarse-grained | Only on costly stalls (L2 miss) | One thread runs at full speed | Can’t hide short stalls; pipeline refill cost |
| Simultaneous (SMT) | Never: several threads issue in the same cycle | Fills idle issue slots | Needs a complex out-of-order, multiple-issue core |
Example: Intel’s Nehalem cores run 2 threads with SMT (Intel calls it Hyper-Threading).
A 4-wide superscalar processor running four threads (illustrative).
Note
Multicore and multithreading both use parallelism to get more work out of a chip. Multithreading shares one core’s units, while multicore duplicates the cores.
Classify hardware by the number of instruction streams and data streams:
| Single data stream | Multiple data streams | |
|---|---|---|
| Single instruction stream | SISD: a uniprocessor (Pentium 4) | SIMD: x86 SSE instructions |
| Multiple instruction streams | MISD: no real examples | MIMD: a multicore (8-core Xeon) |
if (Pn == …) so processors can do different parts.A single SIMD instruction can, for example, add 64 pairs of numbers at once using 64 ALUs.
for loops → data-level parallelism.switch / case statements: units with the “wrong” case sit idle, so you get about \(1/n\) performance for \(n\) cases.One wide ALU can be split into smaller ALUs:
| One 64-bit register can hold … |
|---|
| 1 × 64-bit value |
| 2 × 32-bit values |
| 4 × 16-bit values |
| 8 × 8-bit values |
An older, more elegant form of SIMD (Cray supercomputers).
Example: 32 vector registers, each holding 64 elements of 64 bits.
\(X\) and \(Y\) are vectors of 64 doubles; \(a\) is a scalar.
Ordinary MIPS (loop runs 64 times)
l.d $f0,a($sp) ;load scalar a
addiu r4,$s0,#512 ;upper bound
loop: l.d $f2,0($s0) ;load x(i)
mul.d $f2,$f2,$f0 ;a * x(i)
l.d $f4,0($s1) ;load y(i)
add.d $f4,$f4,$f2 ;a*x(i) + y(i)
s.d $f4,0($s1) ;store y(i)
addiu $s0,$s0,#8 ;next x
addiu $s1,$s1,#8 ;next y
subu $t0,r4,$s0 ;compute bound
bne $t0,$zero,loop ;done?
Vector MIPS
l.d $f0,a($sp) ;load scalar a
lv $v1,0($s0) ;load vector x
mulvs.d $v2,$v1,$f0 ;vector * scalar
lv $v3,0($s1) ;load vector y
addv.d $v4,$v2,$v3 ;add y to product
sv $v4,0($s1) ;store result
6 instructions instead of almost 600!
Note
Vector vs. SSE: in a vector machine the number of elements is in a register, not in the opcode, so new hardware with longer vectors can run old binaries. Vectors also support strided and indexed (non-contiguous) loads.
True or false: As exemplified in the x86, multimedia extensions can be thought of as a vector architecture with short vectors that supports only sequential (contiguous) vector data transfers.
True.
GPUs grew out of video games: drawing millions of independent pixels.
| CPU | GPU | |
|---|---|---|
| Role | General purpose | Accelerator for the CPU |
| Hiding memory latency | Big multilevel caches | Many threads: run others while one waits |
| Memory optimized for | Latency | Bandwidth |
| Cores | A few powerful cores | Many simple, multithreaded cores |
| Programming | C, Java, … | OpenGL, DirectX → now CUDA |
| GPU term | Meaning |
|---|---|
| Streaming processor (SP) | A simple core (8 per multiprocessor) |
| Multiprocessor (MP) | A group of SPs (the GeForce 8800 GTX has 16) |
| Warp | A group of 32 threads scheduled together |
| SIMT | Single Instruction, Multiple Thread: a warp runs one instruction together |
| Thread block | Up to 512 threads on one MP that can share local memory |
| CUDA | C-like language for programming GPUs |
Peak compute: 16 multiprocessors, 8 SPs each, 1 multiply-add (= 2 FLOPs) per SP per clock, 1.35 GHz
\[ 16 \times 8 \times 2 \times 1.35 \text{ GHz} = 345.6 \text{ GFLOP/s} \]
Peak memory bandwidth: 6 memory partitions, 8 bytes wide, 2 transfers per clock, 0.9 GHz
\[ 6 \times 8 \text{ B} \times 2 \times 0.9 \text{ GHz} = 86.4 \text{ GB/s} \]
Ratio: \(345.6 / 86.4 = 4\) FLOPs per byte. To use the full compute power, a GPU program must do about 4 operations for every byte it reads. (This idea returns in the roofline model.)
Threads in a warp share one instruction fetch unit.
switch statements.Note
Modern GPUs have thousands of cores, but the core ideas (warps of 32 threads, SIMT, hiding latency with many threads) are still the same.
True or false: GPUs rely on graphics DRAM chips to reduce memory latency and thereby increase performance on graphics applications.
False. Graphics DRAM provides high bandwidth. GPUs hide latency by switching among many threads, not by having low-latency memory.
Multicore chips need a network on chip. The design trade-off is cost vs. performance:
Total network bandwidth (best case) = bandwidth of one link × number of links
Bisection bandwidth (worst case)
We use the worst case because a parallel program is often limited by its weakest link.
\(P\) = number of processors; each link has bandwidth 1.
| Topology | Total bandwidth | Bisection bandwidth | \(P = 8\) (total / bisection) |
|---|---|---|---|
| Bus | 1 | 1 | 1 / 1 |
| Ring | \(P\) | 2 | 8 / 2 |
| Fully connected | \(\dfrac{P(P-1)}{2}\) | \(\left(\dfrac{P}{2}\right)^2\) | 28 / 16 |
Switches sit between processors instead of at each node.
| Crossbar | Omega network | |
|---|---|---|
| Switches for \(n\) processors | \(n^2\) | \(2n \log_2 n\) |
| For \(n = 8\) | 64 | 48 |
| Any pattern of messages at once? | ✅ Yes | ❌ No, messages can block each other |
In practice
Long wires are slow and costly, chips are 2-D, and power is limited. A topology that looks elegant on the whiteboard may be impractical in silicon, so many multicores use simple grids.
| Benchmark | What it measures | Scaling |
|---|---|---|
| Linpack | Dense linear algebra (ranks the Top500) | Weak |
| SPECrate | Many SPEC CPU copies (job-level) | Weak |
| SPLASH 2 | Shared-memory scientific kernels | Strong |
| NAS | Fluid dynamics kernels | Weak |
| PARSEC | Multithreaded apps (Pthreads, OpenMP) | Weak |
| Berkeley | 13 patterns (sparse matrix, MapReduce, …) | Either |
Fixed rules keep benchmarks fair but block innovation; the Berkeley patterns allow any implementation.
Arithmetic intensity (AI) = how much computation you do per byte you bring from memory:
\[ \text{AI} = \frac{\text{floating-point operations}}{\text{bytes transferred to/from main memory}} \]
\[ \text{Attainable GFLOP/s} = \min\left(\text{Peak memory BW} \times \text{AI},\;\; \text{Peak floating-point performance}\right) \]
Example machine: AMD Opteron X2 (peak 16 GFLOP/s, memory bandwidth 16 GB/s).
A machine has peak = 32 GFLOP/s and memory bandwidth = 8 GB/s.
If your program is far below the roof, the roofline tells you what to fix first.
Compute ceilings (for high-AI kernels)
Memory ceilings (for low-AI kernels)
You can also raise AI itself, for example with better cache use, so fewer bytes come from memory.
| System | Cores / threads | Peak GFLOP/s | SpMV* (GFLOP/s) | LBMHD* (GFLOP/s) |
|---|---|---|---|---|
| Xeon e5345 | 8 / 8 | 75 (highest) | 1.5 (lowest) | 5.6 (lowest) |
| Opteron X4 | 8 / 8 | 74 | 3.6 | 14.1 |
| UltraSPARC T2 | 16 / 128 | 22 | 4.1 | 10.5 |
| Cell QS20 | 16 / 16 | 29 | 6.4 | 16.7 |
*Fully optimized. SpMV = sparse matrix × vector; LBMHD = fluid dynamics on a grid.
Fallacy: “Amdahl’s law doesn’t apply to parallel computers.”
Fallacy: “Peak performance tracks observed performance.”
Pitfall: Not rewriting software for a multiprocessor.
Hardware provides the opportunity for parallelism. Software must be designed to take advantage of it.