6.5.5 · D2Advanced & Emerging Architectures

Visual walkthrough — Processing-in-memory (PIM)

2,192 words10 min readBack to topic

Everything below is built from zero. If a symbol appears, it was drawn first.


Step 1 — What actually happens when a program touches data

WHY split them? Because if we lump "running a program" into one blob of time, we can't see which part is slowing us down. The whole PIM argument rests on the fact that movement and compute are different, and that one of them dominates. So the first move is to name them apart.

Let me define the two quantities we will track for the rest of the page:

  • = the number of bytes the workload must move (a byte = 8 bits, the unit memory is measured in).
  • = the number of compute operations (an "op" = one arithmetic action, like one add).

PICTURE. The chef-and-warehouse cartoon, made literal. The number lives far away in memory; a long wire carries it to the processor; only there does the "+" happen.

Look at the two arrows: the long red one is movement, the short green one is compute. Step 2 asks which one costs more.


Step 2 — Movement is the expensive part (the energy picture)

WHY does this decide everything? If the expensive part is compute, you speed things up by building a faster arithmetic unit. If the expensive part is movement, a faster arithmetic unit changes nothing — you'd just wait at a faster ALU. So we must find out which term dominates before we design anything.

To compare fairly, both energies must be measured per operand of the same size — say one 4-byte (32-bit) word, the natural unit an "add" consumes. That way and refer to the exact same chunk of data, and their ratio is meaningful.

PICTURE. Two bars on the same axis: a tiny green bar (compute energy) beside a towering red bar (move energy), both for one word. The height gap is the memory wall in energy form.


Step 3 — Writing down the total time on a classic machine

WHY this shape? Time = work / rate is the most basic timing law there is: if you move bytes at bytes per second, it takes seconds. Same logic for compute. We use it because it isolates the bottleneck cleanly — each fraction is one independent stage.

Two new rates enter, each defined before use:

  • = bandwidth: how many bytes per second the external bus (the long wire) can carry.
  • = compute rate: how many operations per second the processor can execute.

PICTURE. A horizontal timeline split into two colored segments: a long red segment () followed by a short green one (). The length of each segment is literally its formula.


Step 4 — Arithmetic intensity: which segment wins?

WHY invent this ratio? Because has two terms and we want to know which one is bigger without plugging in machine speeds. Dividing compute-work by move-work strips the timeline down to one comparable number. This is exactly the axis of the Roofline Model.

For a data-hungry job (streaming, low reuse), is tiny, so is negligible next to :

PICTURE. Two timelines stacked: top one has small (mostly red), bottom has large (mostly green). The dividing question — "which color fills the bar?" — is the PIM go/no-go test.


Step 5 — Where PIM attacks: the hidden internal bandwidth

WHY does this matter? The bottleneck was the external straw. If we compute inside memory, we never squeeze through that straw — we use the wide internal read instead. So we must name the internal bandwidth.

  • = number of banks that can work in parallel.
  • = bandwidth of one bank's internal read.
  • = the combined internal bandwidth.

PICTURE. A wide reservoir (many parallel bank-pipes, each ) all feeding one narrow external straw . PIM lets you drink from the reservoir directly.


Step 6 — The PIM timeline and the speedup formula

WHY simply swap ? Because the only thing PIM changes is the rate at which operands reach the arithmetic unit. Compute work and compute rate are unchanged. Movement work is unchanged. Only the road got wider.

PICTURE. Two timelines drawn to scale, one on top of the other: the von Neumann bar (long red) above the PIM bar (short red). The ratio of the red lengths is the speedup.


Step 7 — The edge cases (where the formula lies)

WHY do these failure modes even exist? Look back at the two things the derivation assumed. Step 6's cancellation of only worked because we dropped the compute term (assumption 1: bandwidth-bound). And the speedup counts a whole program as if it were one bandwidth-bound kernel (assumption 2: everything benefits). Each case below is exactly what happens when one of those hidden assumptions breaks — so each one modifies a specific line of the derivation, not the picture in general.

Case A — Compute-bound ( large). Which assumption breaks: assumption 1. If is not negligible, the terms no longer dominate, so the cancellation in Step 6 never happens. Then , the same as von Neumann, and speedup . Widening the road doesn't help if you were never stuck on the road. This is the roofline ceiling.

Case B — Amdahl's ceiling. Which assumption breaks: assumption 2. Only the movement-bound fraction of the program is sped up; the rest runs at its old speed. If a fraction of the work is bandwidth-bound and gets sped up by , then Amdahl's Law replaces the raw speedup with which even at cannot beat . The un-accelerated portion sets the ceiling.

Case C — Degenerate / analog input. Which assumption breaks: the "op is exact" premise hidden inside . For crossbar-style compute using the memory's own physics, the "op" is not digital — it is an analog current summed on a wire. Define fresh symbols (they are electrical, not the intensity from Step 4):

  • = conductance of a memory cell (how easily current flows, in siemens).
  • = input voltage applied to a column (in volts).
  • = current through that cell (Ohm's law); currents on a shared row wire add (Kirchhoff), giving the dot product.

Zero input voltage () → zero current (a harmless degenerate case), but conductance drift and analog-to-digital noise make the summed result approximate. The speedup is real; the exactness is not. Use it for error-tolerant neural nets, never for exact finance.

PICTURE. Three mini-panels: (A) a timeline still green-dominated after PIM (no win); (B) an Amdahl curve flattening to ; (C) an ideal straight line with a fuzzy noisy band around it.


The one-picture summary

Everything in one frame: the long von Neumann timeline shrinks because the fat external-bus segment is replaced by a thin internal-bandwidth segment, while the compute segment (unchanged) is what eventually limits you.

Recall Feynman retelling — the whole walkthrough in plain words

A program does two jobs: fetching numbers and doing math on them. Fetching them across the long wire is slow and burns 100–1000× the energy of the math (Steps 1–2, both measured per 32-bit word). So we wrote total time as "move time + compute time" = (Step 3). To know which part hurts, we divide ops by bytes to get arithmetic intensity ; if it's small, we're stuck waiting on the wire (Step 4). PIM's trick: memory is already wide inside — many banks, each reading thousands of bits at once — so its internal bandwidth dwarfs the skinny external bus (Step 5). Compute there and the move segment shrinks by exactly ; that ratio is the speedup (Step 6). But it only helps if you were bandwidth-bound, it's capped by how much of your program is bandwidth-bound (Amdahl), and analog versions trade exactness for speed (Step 7). One sentence: don't move the data — move the math.