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의 핡심 μ›Œν”„ κΈ°λ³Έ μš”μ†Œλ₯Ό λ°°μ›λ‹ˆλ‹€:

  1. sum(value): μ›Œν”„μ˜ λͺ¨λ“  λ ˆμΈμ—μ„œ 값을 ν•©μ‚°
  2. shuffle_idx(value, lane): νŠΉμ • λ ˆμΈμ—μ„œ 값을 κ°€μ Έμ˜€κΈ°
  3. shuffle_down(value, delta): lane+delta μœ„μΉ˜μ˜ 값을 κ°€μ Έμ˜€κΈ°
  4. prefix_sum(value): 레인 전체에 걸쳐 λˆ„μ  ν•© 계산
  5. 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 기초

β†’ warp.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 μ‹€ν–‰ μ—μ„œ μ›Œν”„ 레벨 ν”„λ‘œκ·Έλž˜λ°μ˜ νž˜μ„ λ§Œλ‚˜λ³΄μ„Έμš”!