Puzzle 24: μν κΈ°μ΄
κ°μ
Part VII: μν λ 벨 νλ‘κ·Έλλ°μμλ GPUμ μν λ 벨 κΈ°λ³Έ μμ - μν λ΄ λκΈ°νλ μ€λ λ μ€νμ νμ©νλ νλμ¨μ΄ κ°μ μ°μ°μ μκ°ν©λλ€. 볡μ‘ν 곡μ λ©λͺ¨λ¦¬ ν¨ν΄μ κ°λ¨νκ³ ν¨μ¨μ μΈ ν¨μ νΈμΆλ‘ λ체νλ λ΄μ₯ μν μ°μ°μ λ°°μλλ€.
λͺ©ν: 볡μ‘ν 곡μ λ©λͺ¨λ¦¬ + λ°°λ¦¬μ΄ + νΈλ¦¬ 리λμ ν¨ν΄μ νλμ¨μ΄ λκΈ°νλ₯Ό νμ©νλ ν¨μ¨μ μΈ μν κΈ°λ³Έ μμ νΈμΆλ‘ λ체ν©λλ€.
ν΅μ¬ ν΅μ°°: GPU μνλ λ‘μ€ν (lockstep)μΌλ‘ μ€νλ©λλ€ - Mojoμ μν μ°μ°μ μ΄ λκΈ°νλ₯Ό νμ©νμ¬ λͺ μμ λκΈ°ν μμ΄ κ°λ ₯ν λ³λ ¬ κΈ°λ³Έ μμλ₯Ό μ 곡ν©λλ€.
λ°°μΈ λ΄μ©
GPU μν μ€ν λͺ¨λΈ
GPU λ³λ ¬μ±μ κΈ°λ³Έ νλμ¨μ΄ λ¨μλ₯Ό μ΄ν΄ν©λλ€:
GPU λΈλ‘ (μ: 256 μ€λ λ)
βββ μν 0 (32 μ€λ λ, SIMT λ‘μ€ν
μ€ν)
β βββ λ μΈ 0 ββ
β βββ λ μΈ 1 β λͺ¨λ μ€λ λκ° κ°μ λͺ
λ Ήμ
β βββ λ μΈ 2 β λμμ μ€ν (SIMT)
β β ... β
β βββ λ μΈ 31 ββ
βββ μν 1 (32 μ€λ λ, λ
립μ )
βββ μν 2 (32 μ€λ λ, λ
립μ )
βββ ...
νλμ¨μ΄ νμ€:
- NVIDIA GPUμμ μνλΉ 32 μ€λ λ (
WARP_SIZE=32) - AMD GPUμμ μνλΉ 32 λλ 64 μ€λ λ (
WARP_SIZE=32 or 64) - λ‘μ€ν μ€ν: μν λ΄ λͺ¨λ μ€λ λκ° λμΌν λͺ λ Ήμ λμμ μ€νν©λλ€
- λκΈ°ν λΉμ© μ λ‘: μν μ°μ°μ κ° μν λ΄μμ μ¦μ μνλ©λλ€
Mojoμμ μ¬μ© κ°λ₯ν μν μ°μ°
gpu.primitives.warpμ ν΅μ¬ μν κΈ°λ³Έ μμλ₯Ό λ°°μλλ€:
sum(value): μνμ λͺ¨λ λ μΈμμ κ°μ ν©μ°shuffle_idx(value, lane): νΉμ λ μΈμμ κ°μ κ°μ Έμ€κΈ°shuffle_down(value, delta): lane+delta μμΉμ κ°μ κ°μ Έμ€κΈ°prefix_sum(value): λ μΈ μ 체μ κ±Έμ³ λμ ν© κ³μ°lane_id(): νμ¬ μ€λ λμ λ μΈ λ²νΈ λ°ν (0-31 λλ 0-63)
μ±λ₯ λ³ν μμ
# 1. 곡μ λ©λͺ¨λ¦¬λ₯Ό ν΅ν 리λμ
# μμ μ΄ν΄λ³Έ 볡μ‘ν ν¨ν΄ (p12.mojo):
shared = LayoutTensor[
dtype,
Layout.row_major(WARP_SIZE),
MutAnyOrigin,
address_space = AddressSpace.SHARED,
].stack_allocation()
shared[local_i] = partial_product
barrier()
# 곡μ λ©λͺ¨λ¦¬λ₯Ό ν΅ν μμ ν νΈλ¦¬ 리λμ
μ κ° λ¨κ³λ§λ€ 배리μ΄κ° νμν©λλ€:
stride = WARP_SIZE // 2
while stride > 0:
if local_i < stride:
shared[local_i] += shared[local_i + stride]
barrier()
stride //= 2
# 2. μν κΈ°λ³Έ μμλ₯Ό νμ©ν 리λμ
# μν κΈ°λ³Έ μμλ₯Ό μ¬μ©ν μμ ν νΈλ¦¬ 리λμ
μ 곡μ λ©λͺ¨λ¦¬λ κ° λ¨κ³μ 배리μ΄κ°
# νμνμ§ μμ΅λλ€.
# Mojoμ μν λ 벨 sum μ°μ°μ λ΄λΆμ μΌλ‘ μν κΈ°λ³Έ μμλ₯Ό μ¬μ©νμ¬ μ΄ λͺ¨λ 볡μ‘μ±μ
# μ¨κΉλλ€:
total = sum(partial_product) # λ΄λΆμ μΌλ‘ 배리μ΄λ, κ²½μ μνλ μμ΅λλ€!
μν μ°μ°μ΄ λΉλλ μκ°
μ±λ₯ νΉμ±μ μ΄ν΄ν©λλ€:
λ¬Έμ κ·λͺ¨ κΈ°μ‘΄ λ°©μ μν μ°μ°
λ¨μΌ μν (32) λΉ λ¦ κ°μ₯ λΉ λ¦ (λ°°λ¦¬μ΄ μμ)
μμ μν (128) μ’μ μ°μ (μ€λ²ν€λ μ΅μ)
λ€μ μν (1024+) μ’μ λ°μ΄λ¨ (μ ν νμ₯)
λκ·λͺ¨ (16K+) λ³λͺ© λ°μ λ©λͺ¨λ¦¬ λμν μ ν
μ μ μ§μ
μν νλ‘κ·Έλλ°μ λ€μ΄κ°κΈ° μ μ λ€μ λ΄μ©μ μ΅μν΄μΌ ν©λλ€:
- Part VI ν¨μν ν¨ν΄: elementwise, tiled, vectorize μ κ·Ό λ°©μ
- GPU μ€λ λ κ³μΈ΅ ꡬ쑰: λΈλ‘, μν, μ€λ λμ λν μ΄ν΄
- LayoutTensor μ°μ°: λ‘λ, μ μ₯, ν μ μ‘°μ
- 곡μ λ©λͺ¨λ¦¬ κ°λ : 배리μ΄μ νΈλ¦¬ 리λμ μ΄ μ 볡μ‘νμ§
νμ΅ κ²½λ‘
1. SIMT μ€ν λͺ¨λΈ
β μν λ μΈκ³Ό SIMT μ€ν
μν μ°μ°μ κ°λ₯νκ² νλ νλμ¨μ΄ κΈ°λ°μ μ΄ν΄ν©λλ€.
λ°°μΈ λ΄μ©:
- SIMT(Single Instruction, Multiple Thread) μ€ν λͺ¨λΈ
- μν λΆκΈ°μ μλ ΄ ν¨ν΄
- μν λ΄ λ μΈ λκΈ°ν
- νλμ¨μ΄ vs μννΈμ¨μ΄ μ€λ λ κ΄λ¦¬
ν΅μ¬ ν΅μ°°: μνλ GPU μ€νμ κΈ°λ³Έ λ¨μμ λλ€ - SIMTλ₯Ό μ΄ν΄νλ©΄ μν νλ‘κ·Έλλ°μ λ¬Έμ΄ μ΄λ¦½λλ€.
2. μν sum κΈ°μ΄
λ΄μ ꡬνμ ν΅ν΄ κ°μ₯ μ€μν μν μ°μ°μ λ°°μλλ€.
λ°°μΈ λ΄μ©:
- 곡μ λ©λͺ¨λ¦¬ + 배리μ΄λ₯Ό
sum()μΌλ‘ λ체 - GPU μν€ν
μ² κ° νΈνμ± (
WARP_SIZE) - μνλ₯Ό νμ©ν 컀λ vs ν¨μν νλ‘κ·Έλλ° ν¨ν΄
- κΈ°μ‘΄ λ°©μκ³Όμ μ±λ₯ λΉκ΅
ν΅μ¬ ν¨ν΄:
partial_result = compute_per_lane_value()
total = sum(partial_result) # λ§λ²μ΄ μΌμ΄λλ κ³³!
if lane_id() == 0:
output[0] = total
3. μΈμ μν νλ‘κ·Έλλ°μ μ¬μ©ν κΉ
β μΈμ μν νλ‘κ·Έλλ°μ μ¬μ©ν κΉ
λμ λλΉ μν μ°μ°μ μ ννκΈ° μν μμ¬κ²°μ νλ μμν¬λ₯Ό λ°°μλλ€.
λ°°μΈ λ΄μ©:
- μν μ°μ°μ μ 리ν λ¬Έμ νΉμ±
- μν μμ λ°λ₯Έ μ±λ₯ νμ₯ ν¨ν΄
- λ©λͺ¨λ¦¬ λμν vs μ°μ°λ νΈλ μ΄λμ€ν
- μν μ°μ° μ ν κ°μ΄λλΌμΈ
μμ¬κ²°μ νλ μμν¬: 리λμ μ°μ°μ΄ λ³λͺ©μ΄ λ λ, μν κΈ°λ³Έ μμκ° λνꡬλ₯Ό μ 곡νλ κ²½μ°κ° λ§μ΅λλ€.
ν΅μ¬ κ°λ
νλμ¨μ΄-μννΈμ¨μ΄ μ λ ¬
Mojo μν μ°μ°μ΄ GPU νλμ¨μ΄μ λ§€νλλ λ°©μμ μ΄ν΄ν©λλ€:
- SIMT μ€ν: λͺ¨λ λ μΈμ΄ λμΌν λͺ λ Ήμ λμμ μ€νν©λλ€
- λ΄μ₯ λκΈ°ν: μν λ΄μμ λͺ μμ 배리μ΄κ° νμνμ§ μμ΅λλ€
- ν¬λ‘μ€ μν€ν
μ² μ§μ:
WARP_SIZEκ° NVIDIAμ AMDμ μ°¨μ΄λ₯Ό μ²λ¦¬ν©λλ€
ν¨ν΄ λ³ν
볡μ‘ν λ³λ ¬ ν¨ν΄μ μν κΈ°λ³Έ μμλ‘ λ³νν©λλ€:
- νΈλ¦¬ 리λμ
β
sum() - λμ ν© μ°μ° β
prefix_sum() - λ°μ΄ν° μ
ν β
shuffle_idx(),shuffle_down()
μ±λ₯ νΉμ±
μν μ°μ°μ΄ μ΄μ μ μ 곡νλ κ²½μ°λ₯Ό νμ ν©λλ€:
- μ~μ€κ·λͺ¨ λ¬Έμ : λ°°λ¦¬μ΄ μ€λ²ν€λλ₯Ό μ κ±°ν©λλ€
- λκ·λͺ¨ λ¬Έμ : λ©λͺ¨λ¦¬ νΈλν½μ μ€μ΄κ³ μΊμ νμ©μ κ°μ ν©λλ€
- κ·μΉμ μΈ ν¨ν΄: μμΈ‘ κ°λ₯ν μ κ·Ό ν¨ν΄μμ μν μ°μ°μ΄ νμν©λλ€
μμνκΈ°
SIMT μ€ν λͺ¨λΈμ μ΄ν΄νλ κ²μΌλ‘ μμνμ¬, μ€μ©μ μΈ warp.sum ꡬνμ λ€λ£¨κ³ , μ λ΅μ μμ¬κ²°μ νλ μμν¬λ‘ λ§λ¬΄λ¦¬ν©λλ€.
π‘ μ±κ³΅ ν: μνλ₯Ό λ 립μ μΈ μ€λ λκ° μλ λκΈ°νλ λ²‘ν° μ λμΌλ‘ μκ°νμΈμ. μ΄ λ©ν λͺ¨λΈμ΄ ν¨κ³Όμ μΈ μν νλ‘κ·Έλλ° ν¨ν΄μΌλ‘ μλ΄ν κ²μ λλ€.
νμ΅ λͺ©ν: Part VIIμ λ§μΉλ©΄, μν μ°μ°μ΄ 볡μ‘ν λκΈ°ν ν¨ν΄μ λ체ν μ μλ μν©μ μΈμνμ¬ λ κ°λ¨νκ³ λΉ λ₯Έ GPU μ½λλ₯Ό μμ±ν μ μκ² λ©λλ€.
μμνκΈ°: μν λ μΈκ³Ό SIMT μ€ν μμ μν λ 벨 νλ‘κ·Έλλ°μ νμ λ§λ보μΈμ!