Exercises — Bank conflicts in shared memory

Level 1 — Recognition
L1.1 — Read the bank off a word index
A thread reads shared[70] where shared is a float array. Which bank does it hit?
Recall Solution
WHAT: float = one 4-byte word, so word index directly (no extra division; we are already counting in words, not bytes).
WHY: bank .
Answer: bank 6.
L1.2 — Byte address to bank
A thread accesses byte address in shared memory (4-byte banks). Which bank?
Recall Solution
WHY divide by 4 first: the address is in bytes, so convert to a word index by . WHY mod 32: round-robin over 32 banks. Answer: bank 8.
Level 2 — Application
L2.1 — Conflict degree from stride
A warp runs float v = shared[tid * 8];. What is the conflict degree, and how many cycles does the access take?
Recall Solution
WHAT: stride in words is . WHY gcd: two threads collide when their word indices differ by a multiple of 32; the number colliding per bank is . Answer: 8-way conflict → the access is serialized into 8 cycles.
L2.2 — Odd stride surprise
float v = shared[tid * 7];. Conflict degree?
Recall Solution
Because 7 shares no factor with 32 (which is ), the map hits all 32 banks — a permutation. 1 cycle.
L2.3 — A double array
__shared__ double d[64]; double v = d[tid];. Reasoning in 4-byte banks, is this conflict-free?
Recall Solution
WHY not "divide by 8": banks are physically 4 bytes wide — there is no 8-byte bank. A double occupies two consecutive banks (low half + high half).
Thread 's two 4-byte halves sit at word indices and . Across the warp the low halves land in banks and high halves in ; hardware issues the two halves in two phases so that within a phase every bank serves exactly one thread.
Answer: conflict-free for straightforward d[tid].
Level 3 — Analysis
L3.1 — Array-of-structures, .x field
struct P { float x, y, z; }; // 12 bytes = 3 words
__shared__ P p[32];
float px = p[tid].x;Compute the stride and conflict degree for reading .x.
Recall Solution
Struct size words, so consecutive .x fields are 3 words apart ⇒ .
Thread hits bank , a permutation of all 32 banks (T0→0, T1→3, …, T11→33 mod 32 = 1, …). 1 cycle.
L3.2 — The AoS that does bite
struct Q { float a, b, c, d; }; // 16 bytes = 4 words
__shared__ Q q[32];
float qa = q[tid].a;Conflict degree on .a?
Recall Solution
Struct size words ⇒ . A "nice" power-of-two struct silently creates a 4-way conflict on every field. 4 cycles.
L3.3 — Column walk of a square tile
__shared__ float m[32][32]; // row-major, word(r,c)=32r+c
float v = m[tid][col]; // fixed col, tid = rowShow every thread hits the same bank.
Recall Solution
Thread reads word . Stride . Independent of ⇒ all 32 threads land in bank ⇒ 32-way conflict, 32 cycles. See figure.

Level 4 — Synthesis
L4.1 — Pad the tile to kill the conflict
Fix L3.3 by declaring __shared__ float m[32][33];. Show the column walk becomes conflict-free.
Recall Solution
WHAT changed: row stride is now 33 words (one padding column). Element sits at word . Thread reads word . WHY 33 works: , so As , sweeps all 32 distinct banks ⇒ conflict-free, 1 cycle. The padding cost is one wasted column per row (32 floats = 128 bytes).

L4.2 — Choose padding for a 16-wide tile
You have __shared__ float t[32][16]; and walk columns (t[tid][col], stride 16). What single padding value (making the row width ) is the smallest that makes the column walk conflict-free?
Recall Solution
Row width becomes words = the new stride . We need , i.e. must be odd. is even, so the smallest making it odd is (width 17). Check: ✓. Answer: , width 17.
Level 5 — Mastery
L5.1 — General stride cycle count
A warp uses stride words. Write the number of cycles as a function of , then evaluate for and .
Recall Solution
General: cycles (each colliding group serialized).
- : cycles.
- : cycles. Why: shares one factor of 2 with ; shares three.
L5.2 — Transpose kernel diagnosis
In 6.3.01-Matrix-transpose-optimization a kernel does tile[threadIdx.y][threadIdx.x] = in[...] (row write) and later out[...] = tile[threadIdx.x][threadIdx.y] (transposed read) with tile[32][32]. Which access conflicts, by how much, and what is the one-word fix?
Recall Solution
- Write
tile[ty][tx]: within a warptxvaries over the column → stride 1 → conflict-free. - Read
tile[tx][ty]: within a warptxvaries over the row index → stride 32 → → 32-way conflict, 32 cycles. - Fix: declare
tile[32][33]. Row stride 33 ≡ 1 (mod 32) ⇒ read becomes conflict-free (L4.1). Total wasted shared memory: bytes. This is why the transpose optimization exists — it links straight to 6.2.10-Occupancy-and-resource-limits because that extra column eats into your shared-memory budget.
L5.3 — Broadcast is NOT a conflict
float v = shared[0]; — every thread reads the same word 0. How many cycles?
Recall Solution
Same address ≠ conflict. A bank conflict needs threads at different addresses in the same bank. When all 32 threads request the identical word, the hardware broadcasts it in a single fetch.
Answer: 1 cycle. (Contrast with shared[tid*32], where the addresses differ but all map to bank 0 → 32-way conflict.)
Recall Two-line self test
Stride 8 conflict degree? ::: → 8-way
Padding that fixes a stride-32 column walk of float[32][N]? ::: any with odd; smallest is
Related: 6.2.08-Memory-coalescing · 6.2.07-Shared-memory-architecture · 6.2.11-Warp-divergence