6.2.6 · D4 · HinglishGPU Architecture

ExercisesThread blocks and grids

3,854 words18 min read↑ Read in English

6.2.6 · D4 · Hardware › GPU Architecture › Thread blocks and grids

Ye page ek self-test ladder hai. Har solution ko cover karo, problem khud solve karo, phir reveal karo. Har level ek rung upar jaata hai: L1 Recognition → L2 Application → L3 Analysis → L4 Synthesis → L5 Mastery. Yahan sab kuch Thread blocks and grids pe build karta hai aur CUDA Programming Model, Streaming Multiprocessors, Warp Execution, GPU Occupancy, Shared Memory, Memory Coalescing, aur Parallel Algorithm Design ko touch karta hai.

Shuru karne se pehle, ek picture jo har problem mein use hone waali vocabulary ko fix karti hai.

Figure — Thread blocks and grids

Level 1 — Recognition

Exercise 1.1

Ek kernel blockDim.x = 128 ke saath launch hota hai. Ek thread report karta hai blockIdx.x = 3 aur threadIdx.x = 10. Uska globalID kya hai?

Recall Solution

WHAT: Ek formula mein plug in karo. WHY: block index hamare se pehle complete blocks count karta hai (har ek mein 128 seats hain), phir hum apna seat add karte hain. Answer: 394. Picture: hum blocks 0, 1, 2 ke upar se kood gaye (wo hai elements) aur block 3 mein 10 seats andar land kiye.

Exercise 1.2

Har built-in variable ko us cheez se match karo jo wo measure karta hai: threadIdx.x, blockDim.x, blockIdx.x, gridDim.x.

Recall Solution
  • threadIdx.x ::: thread ki apne block ke andar position (0 se blockDim.x - 1 tak).
  • blockDim.x ::: har block mein threads ki sankhya.
  • blockIdx.x ::: grid ke andar block ki position (0 se gridDim.x - 1 tak).
  • gridDim.x ::: grid mein blocks ki sankhya.

Memory hook: thread words "thread/block position" pe khatam hote hain; dim words sizes hain.

Exercise 1.3

Sach ya jhooth: alag-alag blocks ke do threads __syncthreads() call karke ek doosre ka intezaar kar sakte hain.

Recall Solution

Jhooth. __syncthreads() sirf ek block ke andar ek barrier hai — dekho Thread Synchronization. Blocks autonomous hain; ek single kernel launch ke andar koi cross-block barrier nahi hota. Alag blocks ke threads is tarah kabhi ek doosre ka intezaar nahi karte.


Level 2 — Application

Exercise 2.1

N = 1000 elements ka vector addition threadsPerBlock = 256 ke saath. Tum kitne blocks launch karte ho? Kitne total threads run hote hain, aur kitne idle hain?

Recall Solution

WHAT: ceiling division, kyunki hum har element ko cover karna chahte hain chahe aakhri block partly empty ho. WHY ceiling: , aur 3 blocks sirf threads dete hain — 232 elements abhi bhi uncovered. Toh upar 4 tak round karo.

  • Total threads launched: .
  • Idle (guarded-out) threads: .

Un 24 threads ka globalID mein hai aur if (i < N) guard unhe kuch nahi karne deta.

Exercise 2.2

Us launch mein, ek thread ka blockIdx.x = 2, threadIdx.x = 200 hai. Wo kaun sa element process karta hai, aur kya wo guarded out hai?

Recall Solution

Kyunki , guard if (i < N) pass ho jaata hai — ye zaroor element 712 process karta hai.

Exercise 2.3

Ek 2D image width = 512, height = 384 hai. Block 16 × 16 ka hai. Ek thread ka blockIdx.x = 5, threadIdx.x = 3 (columns) aur blockIdx.y = 7, threadIdx.y = 9 (rows) hai. col, row, aur flattened 1D memory index (row-major) do.

Recall Solution

WHAT: har axis pe wahi formula apply karo, phir flatten karo. WHY flatten: memory ek 1D line hai; row-major matlab "ek full row ke saath chalo, phir next pe drop karo" — dekho Memory Coalescing. Answer: col 83, row 121, memory index 62035.


Level 3 — Analysis

Exercise 3.1

Ek SM 2048 resident threads allow karta hai. Tum 256-thread blocks launch karte ho. Tumhare kernel ko 12 KB shared memory per block chahiye, aur SM ke paas 96 KB hai. Kitne blocks fit hote hain, aur tum kaun si occupancy achieve karte ho?

Recall Solution

WHY occupancy ek minimum hai: ek block tabhi resident ban sakta hai jab har resource jo use chahiye ek saath available ho — threads, registers, aur shared memory. Agar thread budget 8 blocks allow karta hai lekin memory budget sirf 5 allow karta hai, toh sirf 5 SM pe actually baith sakte hain: sabse tight resource real ceiling hai. Toh hum har limit alag se compute karte hain aur sabse chhota lete hain — dekho GPU Occupancy.

  • Thread limit: blocks.
  • Shared-memory limit: blocks.

WHY yahan floor: ek block jo apna poora memory footprint fit nahi kar sakta simply admit nahi hota — "0.7 of a block" resident jaisi koi cheez nahi hoti — toh koi bhi fractional part neeche discard ho jaata hai.

Dono limits 8 kehte hain, toh 8 blocks fit hote hain resident threads 100% occupancy.

Exercise 3.2

Wahi SM (2048 threads, 96 KB). Ab kernel 20 KB shared memory per 256-thread block use karta hai. Resident blocks? Occupancy?

Recall Solution

WHY phir min: occupancy us resource se cap hoti hai jo pehle khatam ho (dekho 3.1). Dono compute karo, chhota rakho.

  • Thread limit: blocks.
  • Shared-memory limit: blocks. WHY floor: , lekin 5th block ko KB KB chahiye — wo fit nahi hota, toh hum fractional 0.8 drop karte hain aur 4 rakhte hain.

Binding constraint chhota wala hai: blocks. Lesson: memory hunger — thread count nahi — ne occupancy aadhi kar di.

Exercise 3.3

Ek 256-thread block: kitne warps? Pehle, ek definition — ek warp ke 32 threads ke andar, har thread ek fixed lane occupy karta hai, 0 se 31 tak numbered (ek thread ki lane bas threadIdx.x % 32 hai, warp ke andar uski column). Ab maan lo lanes 0–15 har warp ka if branch lete hain aur lanes 16–31 else lete hain. Roughly divergent region ke andar kitne fraction execution slots divergence ke waste ho jaate hain?

Recall Solution

WHAT: ek warp 32 threads ka fixed bundle hai jo ek instruction saath run karta hai (SIMT) — dekho Warp Execution. Ek lane ek thread ki fixed slot hai us bundle ke andar, 0–31 numbered; jab warp ek instruction execute karta hai, saare 32 lanes ise saath fire karte hain (jab tak kuch mask off na hon).

  • Warps per block: warps.
  • Jab ek warp do paths mein split hota hai, hardware if path lanes 16–31 masked off ke saath run karta hai, phir else path lanes 0–15 masked off ke saath. Har pass masked half waste karta hai — wo lanes abhi bhi kuch na karte hue ek cycle consume karte hain.
  • Toh har divergent warp roughly 2× cycles spend karta hai; divergent region mein roughly 50% slots idle mask-outs hain.

Practice mein fix: branches is tarah arrange karo ki ek poora warp ek path le (branch on globalID / 32, lane number pe nahi), taki ek warp ke andar koi lane kabhi doosre ke against mask na ho.


Level 4 — Synthesis

Exercise 4.1

Tumhe N = 1 000 000 length ke do vectors add karne hain. Launch design karo: ek block size chunao jo recommended 128–512 range mein 32 ka multiple ho, block count compute karo, total threads, aur idle threads. Ek sentence mein block size justify karo.

Recall Solution

Choice: B = 256 — 32 ka multiple (whole warps, no wasted lanes), aur 128–512 sweet spot mein jo enough blocks per SM rakhta hai memory latency hide karne ke liye occupancy starve kiye bina. Check: , toh 3906 kam hai; 3907 sahi hai.

  • Total threads: .
  • Idle (guarded) threads: .

Launch: vecAdd<<<3907, 256>>>(...) with if (i < N) guard.

Exercise 4.2

Matrices multiply karo jahan C M × N hai with M = 1000, N = 500, 16 × 16 blocks use karke. gridDim.x (columns) aur gridDim.y (rows) compute karo, total thread count, aur fraction of threads jo guarded out hain.

Recall Solution

WHAT: x ke along columns cover karo, y ke along rows (convention: x = horizontal = columns) — dekho Parallel Algorithm Design.

  • Threads launched: .
  • Useful outputs: .
  • Guarded-out threads: .
  • Fraction wasted: .

Thodi waste normal hai — ye non-multiple grid ko tile karne ki keemat hai.

Neeche wali figure exactly yahi draw karti hai: mint region useful 500 × 1000 output hai, dashed coral rectangle launched 512 × 1008 region hai, aur right aur bottom edges pe do lavender strips extra columns aur rows hain jinke threads guarded out ho jaate hain. Notice karo ki waste sirf last (partial) blocks mein hai har edge ke along — interior 100% useful hai.

Figure — Thread blocks and grids

Exercise 4.3

Ek 3D volume size X = 64, Y = 64, Z = 64 ko 8 × 8 × 8 blocks ke saath process kiya jaata hai. gridDim.x, gridDim.y, gridDim.z compute karo, aur us thread ke global (x, y, z) coordinates do jiska blockIdx = (2, 3, 4) aur threadIdx = (1, 5, 7) hai.

Recall Solution

WHAT: index rule teen axes mein se har ek pe independently apply hota hai — kuch naya nahi, bas x, y, z side by side. Answer: grid blocks hai; thread voxel pe map karta hai.

1D memory index mein flatten karo — aur WHY exactly yeh nesting: memory ek lambi line hai, toh hum decide karna chahte hain kaun sa coordinate sabse tez chalta hai. Convention x ko fastest-changing banati hai (neighbouring x memory mein adjacent hain, jo Memory Coalescing help karta hai), phir y, phir z slowest. Toh hum address layers mein banate hain: z-slice chuno (har slice voxels hold karta hai), phir us mein y-row (har row voxels hold karta hai), phir us row ke along x step karo: WHY kaam karta hai: row number hai volume ke bilkul shuru se count kiya hua, aur se multiply karna hamare se pehle ke saare full rows skip karta hai — phir current row mein humari seat pe land karta hai. Ye wahi "apne se pehle ke complete groups skip karo, phir apna offset add karo" logic hai jaise 1D global-index formula, teen deep nested.


Level 5 — Mastery

Exercise 5.1

Tumhare paas ek kernel ke liye teen candidate block sizes hain jo register + shared-memory budgets use karta hai, "blocks-that-fit-per-SM" ke roop mein summarize kiye gaye hain. SM 2048 threads hold karta hai. Har block size ke liye resources pe blocks ka ceiling diya gaya hai. Resident threads aur occupancy compute karo, aur winner chuno.

Block size Blocks allowed by resources
128 12
256 8
1024 2
Recall Solution

WHAT: resident threads , jahan thread-limit blocks .

128: thread limit ; resources 12 allow karte hain; .

256: thread limit ; resources 8 allow karte hain; .

1024: thread limit ; resources 2 allow karte hain; .

Winner: 256-thread block. Dono 256 aur 1024 100% occupancy reach karte hain, lekin 256 safer choice hai — 8 blocks resident hone ke saath, ek stalled block abhi bhi 7 aur scheduler ke liye rehne deta hai latency run aur hide karne ke liye; 1024 ke saath tumhare paas sirf 2 blocks hain, toh ek stall tumhari latency-hiding capacity half kar deta hai. 128-thread block eliminate ho jaata hai kyunki resources (threads nahi) ise 12 blocks pe cap karte hain sirf 75% occupancy. 256 chuno.

Exercise 5.2

Tumhare paas ek GPU hai jinke SMs mein se har ek at most 8 resident blocks allow karta hai (ek real hardware limit). Ek student likhta hai: block 0 global memory mein flag = 1 set karta hai, aur baaki saare blocks ek kernel launch ke andar while (flag == 0); spin karte hain wait karte hue. 4 SMs aur 40 blocks ke grid wale GPU pe, precisely explain karo ye kyun deadlock ho sakta hai, aur do sahi alternatives do.

Recall Solution

Residency limit jo ise fail karti hai: har SM at most 8 blocks at a time hold kar sakta hai, aur sirf 4 SMs hain, toh at most of the 40 blocks simultaneously resident ho sakte hain. Baaki 8 blocks ko ek resident block ke finish hone aur apna slot free karne ka intezaar karna padega pehle shuru hone se.

Kyun deadlock hota hai: blocks SMs pe arbitrary order mein schedule hote hain. Maan lo 32 resident slots saare blocks 1–32 se bhar gaye hain, har ek flag pe spin kar raha hai. Spinning blocks kabhi finish nahi hote, toh unke slots kabhi free nahi hote, toh not-yet-resident blocks — jinme block 0 bhi ho sakta hai — kabhi schedule nahi hote. Agar block 0 waiting 8 mein se ek hai, flag kabhi set nahi hota, toh resident blocks forever spin karte hain: ek circular wait. Koi guarantee nahi ki block 0 pehle run kare; block indices koi execution order imply nahi karte.

Sahi alternatives (Thread Synchronization se):

  1. Do kernel launches mein split karo. Kernel boundary ek implicit global barrier hai — launch 1 ki sab cheez launch 2 shuru hone se pehle complete ho jaati hai.
  2. Cooperative groups (CUDA 9+) grid-level sync, cudaLaunchCooperativeKernel ke saath launch kiya, jo guarantee karta hai ki saare blocks co-resident hain toh grid barrier legal hai.
  3. (Last resort) coordination ke liye global memory pe atomic operations — sahi lekin slow, aur phir bhi yeh assume karne se bachna hoga ki koi block pehle run kare.

Exercise 5.3

N = 4096 elements ki fixed problem ke saath, tum chahte ho ki har resident thread useful ho (koi guarded-out waste nahi) aur block size ek warp multiple ho. {64, 128, 256, 512} mein se wo block sizes list karo jo N ko evenly divide karte hain, aur har ke liye exact block count do.

Recall Solution

"No waste" matlab N block size ka exact multiple ho (remainder 0). Har ek check karo:

  • exactly → 64 blocks, no waste. ✅
  • exactly → 32 blocks, no waste. ✅
  • exactly → 16 blocks, no waste. ✅
  • exactly → 8 blocks, no waste. ✅

Charon ko evenly divide karte hain (ye saare powers of two hain jo ise divide karte hain), aur saare warp multiples hain (har ek 32 ka multiple hai). Toh har listed size zero guarded-out threads deti hai. Unme se, 256 Exercise 5.1 mein argue kiye gaye occupancy/latency-hiding balance ke liye usual pick hai.


Recall Quick self-check ladder
  • Universal 1D index formula :::
  • Teen axes mein se har ek pe wahi rule ::: x, y, aur z pe independently apply karo (jaise )
  • N elements cover karne ke liye block count (round up) :::
  • Fixed resource budget fit karne wale blocks (round down) :::
  • Occupancy ::: resident threads ÷ SM max threads, saare resource limits ke minimum se capped
  • Kyun blocks ek kernel mein ek doosre ko message nahi kar sakte ::: arbitrary scheduling order + limited residency → deadlock risk