Exercises — Processing-in-memory (PIM)
Before we start, here is the tiny toolbox every problem draws from. Keep it in view.

The figure above is our map: the roofline. The flat part on the left is bandwidth-bound territory (PIM's home turf); the slanted part on the right is compute-bound (caches and fast ALUs win). Arithmetic intensity places every workload left-to-right.
L1 — Recognition
Exercise 1.1
A job has operations and moves bytes. Compute its arithmetic intensity and state, in one word, whether it is bandwidth-bound or compute-bound.
Recall Solution 1.1
WHAT we do: apply the definition . WHY it answers the question: is "how much math per byte fetched." A quarter-op per byte means we fetch four bytes for every single operation — the wire does almost all the work. Verdict: very low ⇒ bandwidth-bound ⇒ a good PIM candidate.
Exercise 1.2
Two flavors of PIM were defined. Which flavor uses the analog physics of the array itself (e.g., a memristor crossbar), and which one puts ordinary digital logic physically near the memory?
Recall Solution 1.2
- Processing-using-memory (PUM): computes using the memory's own physics — the crossbar where Ohm's + Kirchhoff's laws do a matrix–vector multiply. See Memristor / ReRAM Crossbars.
- Processing-near-memory (PNM): ordinary ALUs/cores placed next to memory, e.g. on the logic die of a 3D-stacked HBM stack. Mnemonic from the parent: Near = Next to; Using = the memory's own physics.
Exercise 1.3
True or false: "PIM's main win is a faster ALU." Justify in one sentence.
Recall Solution 1.3
False. PIM's win is reduced data movement, not faster arithmetic — it attacks the Memory Wall, the cost of dragging bytes across the bus. (This is the trap steel-manned just below.)
L2 — Application
Exercise 2.1
A vector operation a[i] = 2*b[i] + c[i] runs over elements of 4-byte floats. Each element needs a multiply and an add. Compute , , and .
Recall Solution 2.1
WHAT — count the ops : one multiply + one add per element ⇒ ops each.
WHY: the operation 2*b[i] + c[i] literally spells out one multiplication and one addition, and we perform it once for each of the elements — so the op count is simply per element times elements.
WHAT — count the bytes : read b, read c, write a ⇒ 3 accesses × 4 bytes each.
WHY: every memory touch crosses the bus and must be counted — two reads (b, c) plus one write (a) per element, each a 4-byte float. Forgetting the write-back is the classic slip (see the trap below).
WHAT — intensity:
WHY it matters: is tiny — we move six bytes for every op. On the roofline (figure s01) this lands far left in the flat, bandwidth-bound zone ⇒ good PIM candidate.
Exercise 2.2
An HBM stack has banks, each with internal bandwidth GB/s. The external bus is GB/s. Estimate the near-memory speedup.
Recall Solution 2.2
WHAT — internal bandwidth: WHY: each of the banks reads and computes on its own data simultaneously; because they run in parallel, their bandwidths add. This internal parallelism is exactly the resource the external bus could never expose. WHAT — speedup (bandwidth-bound approximation): WHY this ratio: for a bandwidth-bound job the runtime is set by how fast bytes flow. PIM replaces the GB/s wire with GB/s of internal flow, so time shrinks by the bandwidth ratio — here . (When compute time is not negligible this over-estimates; the full timing that exposes the gap is Exercise 5.2.)
Exercise 2.3
Rough energy fact: moving operands costs , where is the energy of one op. For a job with ops/byte, roughly what fraction of energy is spent moving data vs. computing? (Assume one "move event" per byte, one per op.)
Recall Solution 2.3
WHAT we build: per byte we do ops, so per byte:
- compute energy
- move energy
WHY split per byte: normalizing "per byte moved" lets us compare the two energies on the same footing — one move event (cost ) against the fraction of an op that byte earns (). Fraction moving: Interpretation: essentially all energy is spent moving data. This is why PIM exists — cut the movement and you cut almost the whole energy bill.
L3 — Analysis
Exercise 3.1
A dense matrix multiply of size has ops and moves bytes. Compute and decide: is PIM a strong win here? Contrast with the vector add from Exercise 2.1.
Recall Solution 3.1
Ops: . Bytes: . Intensity: Analysis: is huge compared to the vector add's . Matrix multiply reuses each loaded value times, so it is compute-bound — caches and fast ALUs already keep it fed. PIM's bandwidth win barely applies. See Roofline Model.
Exercise 3.2
A workload is 70% bandwidth-bound (call this fraction ) and PIM makes that part faster. The remaining 30% is untouched. Use Amdahl's Law to compute the overall speedup.
Recall Solution 3.2
Amdahl's Law: if a fraction of the runtime is sped up by , and the rest () is unchanged, overall speedup is WHY this tool: PIM only accelerates the movement part of the job; the rest is a serial anchor. Amdahl is exactly "what happens when you speed up only a slice." Plug in : Even a 4× local win yields only ~2.1× overall — the untouched 30% caps you.
Exercise 3.3
You measure that PIM gives near the maximum possible speedup even as for the job in 3.2. What is that ceiling, and what does it prove?
Recall Solution 3.3
Let in Amdahl: the term , leaving Proof it delivers: no matter how good PIM gets, the serial 30% caps you at 3.33×. This is why measuring the bandwidth-bound fraction matters more than tuning — the ceiling lives in .
L4 — Synthesis
Exercise 4.1
A memristor crossbar has a matrix of size with . Input voltages are volts. Row produces current (Ohm's law per cell, Kirchhoff's sum per row). Given compute the output current vector . Then state how many analog steps this took vs. a sequential CPU.
Recall Solution 4.1
Symbol note: here (boldface, components ) is an electric current vector — not the arithmetic intensity of the earlier problems. Same letter, different world; the boldface and the "amps" units keep them apart. WHY the crossbar does this in one shot: each crosspoint obeys Ohm's law ; currents on a shared row wire add (Kirchhoff), giving — a dot product per row, all rows in parallel. Trace this on figure s02 below: the input voltages (lavender arrows) enter down the columns, each crosspoint conductance (coral dots) scales its column's voltage into a current, and the currents merge rightward along each mint row wire into the output (coral arrows). Row by row ():
Step count: the crossbar does this in one analog step (). A CPU needs multiply-accumulates (). That collapse is why PIM loves Neural Network Accelerators.

Read this figure alongside Solution 4.1: it is the physical picture behind the numbers . The conductance printed inside each coral dot is the corresponding from the matrix; multiply it by its column's voltage and sum along the row to reproduce each by hand.
Exercise 4.2
Combine two levels. A neural-net layer is 90% matrix–vector multiply by runtime (). A crossbar does that part effectively faster. (a) Overall speedup by Amdahl? (b) But crossbar output is approximate (device drift, ADC noise). What class of workload makes this acceptable, and what would make it unacceptable?
Recall Solution 4.2
(a) Amdahl with : (b) Acceptable for error-tolerant workloads — neural network inference tolerates small numeric noise (training already added robustness). Unacceptable for exact workloads like IEEE-precise finance or cryptography, where a drifted conductance corrupts the result. PUM trades exactness for speed.
L5 — Mastery
Exercise 5.1 (Design & defend)
You are handed three workloads. For each, decide PUM crossbar, PNM (near-memory ALUs), or plain CPU/GPU, and justify with the numbers.
- W1: streaming vector add, ops/byte, must be bit-exact.
- W2: neural-net inference, dominated by matrix–vector multiplies, tolerates ~1% error.
- W3: dense scientific matrix multiply, ops/byte, must be IEEE-exact.
Recall Solution 5.1
W1 → PNM. Very low ⇒ bandwidth-bound ⇒ PIM helps. But it must be exact, so we cannot use analog PUM (approximate). Digital near-memory ALUs give the bandwidth win and exactness. W2 → PUM crossbar. Matrix–vector multiply is the crossbar's native operation; 1% error tolerance suits the analog imprecision. Ideal PUM case. W3 → plain CPU/GPU. ⇒ compute-bound, so the bytes are already reused heavily inside the caches and PIM's bandwidth win barely helps. On top of that the job must be IEEE-exact, which rules out analog PUM entirely. Keep it on the GPU, where fast ALUs fed by cache are exactly the right tool. See Roofline Model.
Exercise 5.2 (Full pipeline estimate)
A job moves bytes and does ops. External bus GB/s B/s. Compute rate ops/s. A PNM design has banks, GB/s, and executes compute at the same rate . (a) Baseline time . (b) PIM time . (c) Actual speedup . Compare it to the naive and explain the gap.
Recall Solution 5.2
Internal bandwidth: GB/s B/s. (a) Baseline: (b) PIM: (c) Actual speedup: Naive estimate . Gap explained: the naive ratio assumes the job is pure movement. Here the compute term s is large and unchanged by PIM — it becomes the new bottleneck. This is exactly Amdahl's ceiling: PIM only shrank the s movement part, not the s compute part. Always compute the full , never trust alone.
Wrap-up
Return to the parent PIM note · related: DRAM Organization (banks, rows), Roofline Model, Amdahl's Law.