Data parallelism: user guide
dataparallel.html shows the same data-parallel work on different hardware, one cycle per step. It follows slides 46 to 50 of The Processor (Advanced): SIMD/vector versus SIMT, warp divergence and latency hiding, plus memory coalescing as the next question on GPUs.
Open the file in a browser. It needs no server, but dataparallel_engine.js must sit in the same folder.
Controls
| Control | Action |
|---|---|
| ▶ / Space | Play or pause |
| ▶| / → | One cycle forward |
| ◀ / ← | One cycle back |
| ⏮ / Home | Start |
| 1 to 4 | Switch demo |
| Slider | Scrub to any cycle |
Each demo keeps its own position and settings. Changing a setting rewinds that demo. On a phone, Setup shows the settings.
1. SIMD · SIMT
y[i] = a*x[i] + y[i] on a scalar core, a vector core and a SIMT core. Each issues one instruction per cycle.
- Elements and Lanes set n and the vector or warp width. Pick an n that is not a multiple of the width to see the tail: the last strip or warp leaves lanes idle, and "lanes busy" drops below 100%.
- The vector core runs
vsetvliplus four vector instructions per strip. The SIMT core runs four per warp and masks the threads past n. - Set lanes to 1: the vector core is slower than scalar, because it still pays for
vsetvli.
2. Divergence
One or more warps run if (x[i] > 0) A else B. Every lane evaluates the condition, then each path runs with the other lanes masked off. A path no lane takes is skipped.
- Data order sets the signs of x. With 50% taken, sorted by sign keeps whole warps on one side and nothing diverges, while random splits almost every warp.
- Click a data cell to flip that lane.
- Path A and Path B set the instruction counts. "Independent lanes would need" is the cost if each lane followed its own path.
3. Latency
Warps share one core. Each issues a burst of instructions ending in a load, then waits. The core keeps issuing from a warp while it can, otherwise switches to the next ready warp.
- With the defaults (4 warps, bursts of 2, latency 6) the core never idles, which is slide 50.
- Reduce Resident warps until idle cycles appear. Warps needed is ⌈(burst + latency) / burst⌉.
- Warp 0 finishes no earlier than it would alone. Only the total time improves.
4. Coalescing
One warp loads a word per lane. Memory is served in aligned segments, one transaction per cycle, so the cost is the number of segments touched.
- Compare
a[i],a[i+1](misaligned),a[s*i]anda[idx[i]]. - Segment sets the transaction size. A stride of at least the segment size costs one transaction per lane.
- The readout names the vector load that does the same job:
vle32.v(unit stride),vlse32.v(strided),vluxei32.v(gather).
Simplifications
- One instruction issues per cycle and every instruction takes one cycle, except the loads in demo 3 and the transactions in demo 4.
- Loop control, address arithmetic and the bounds check are not counted.
- Demo 3 has one scheduler and no limit on registers. On a real core, the register file bounds the resident warps.
- A transaction in demo 4 is one segment per cycle with no caches.