๊ฐ์
1D LayoutTensor a์ 1D LayoutTensor b์ ๋ด์ ์ ๊ณ์ฐํ์ฌ 1D LayoutTensor output(๋จ์ผ ๊ฐ)์ ์ ์ฅํ๋ ์ปค๋์ ๊ตฌํํ์ธ์.
์ฐธ๊ณ : ๊ฐ ์์น๋ง๋ค ์ค๋ ๋ 1๊ฐ๊ฐ ์์ต๋๋ค. ์ค๋ ๋๋น ์ ์ญ ์ฝ๊ธฐ 2ํ, ๋ธ๋ก๋น ์ ์ญ ์ฐ๊ธฐ 1ํ๋ง ํ์ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
์ด ํผ์ฆ์์ ๋ฐฐ์ธ ๋ด์ฉ:
- Puzzle 8, Puzzle 11์์ ์ด์ด์ง๋ LayoutTensor ๊ธฐ๋ฐ ๋ณ๋ ฌ ๋ฆฌ๋์
address_space๋ฅผ ํ์ฉํ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ- ์ฌ๋ฌ ์ค๋ ๋๊ฐ ํ๋ ฅํด ํ๋์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๊ฐ๋ ๊ณผ์
- ๋ ์ด์์์ ์ธ์ํ๋ ํ ์ ์ฐ์ฐ
ํต์ฌ์ LayoutTensor๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ๊ฐ์ํํ๋ฉด์๋, ๋ณ๋ ฌ ๋ฆฌ๋์ ์ ํจ์จ์ ๊ทธ๋๋ก ์ด๋ฆฌ๋ ๋ฐฉ์์ ์ดํดํ๋ ๊ฒ์ ๋๋ค.
๊ตฌ์ฑ
- ๋ฒกํฐ ํฌ๊ธฐ:
SIZE = 8 - ๋ธ๋ก๋น ์ค๋ ๋ ์:
TPB = 8 - ๋ธ๋ก ์: 1
- ์ถ๋ ฅ ํฌ๊ธฐ: 1
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ:
TPB๊ฐ
์ฐธ๊ณ :
- LayoutTensor ํ ๋น:
LayoutTensor[dtype, Layout.row_major(TPB), MutAnyOrigin, address_space = AddressSpace.SHARED].stack_allocation()์ฌ์ฉ - ์์ ์ ๊ทผ: ๊ฒฝ๊ณ ๊ฒ์ฌ๊ฐ ์๋์ผ๋ก ๋ฐ๋ผ์ค๋ ์์ฐ์ค๋ฌ์ด ์ธ๋ฑ์ฑ
- ๋ ์ด์์ ์ฒ๋ฆฌ: ์ ๋ ฅ์ฉ๊ณผ ์ถ๋ ฅ์ฉ ๋ ์ด์์์ ๋ฐ๋ก ๊ตฌ์ฑ
- ์ค๋ ๋ ์กฐ์จ: ๋์ผํ ๋๊ธฐํ ํจํด์ผ๋ก
barrier()์ฌ์ฉ
์์ฑํ ์ฝ๋
from gpu import thread_idx, block_idx, block_dim, barrier
from gpu.memory import AddressSpace
from layout import Layout, LayoutTensor
comptime TPB = 8
comptime SIZE = 8
comptime BLOCKS_PER_GRID = (1, 1)
comptime THREADS_PER_BLOCK = (TPB, 1)
comptime dtype = DType.float32
comptime layout = Layout.row_major(SIZE)
comptime out_layout = Layout.row_major(1)
fn dot_product[
in_layout: Layout, out_layout: Layout
](
output: LayoutTensor[dtype, out_layout, MutAnyOrigin],
a: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
b: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
size: UInt,
):
# FILL ME IN (roughly 13 lines)
...
์ ์ฒด ํ์ผ ๋ณด๊ธฐ: problems/p12/p12_layout_tensor.mojo
ํ
- LayoutTensor์
address_space๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ฑ shared[local_i]์a[global_i] * b[global_i]๋ฅผ ์ ์ฅbarrier()์ ํจ๊ป ๋ณ๋ ฌ ๋ฆฌ๋์ ํจํด ์ ์ฉ- ์ค๋ ๋ 0์ด ์ต์ข
๊ฒฐ๊ณผ๋ฅผ
output[0]์ ๊ธฐ๋ก
์ฝ๋ ์คํ
์๋ฃจ์ ์ ํ ์คํธํ๋ ค๋ฉด ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ธ์:
pixi run p12_layout_tensor
pixi run -e amd p12_layout_tensor
pixi run -e apple p12_layout_tensor
uv run poe p12_layout_tensor
ํผ์ฆ์ ์์ง ํ์ง ์์๋ค๋ฉด ์ถ๋ ฅ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
out: HostBuffer([0.0])
expected: HostBuffer([140.0])
์๋ฃจ์
fn dot_product[
in_layout: Layout, out_layout: Layout
](
output: LayoutTensor[dtype, out_layout, MutAnyOrigin],
a: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
b: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
size: UInt,
):
shared = LayoutTensor[
dtype,
Layout.row_major(TPB),
MutAnyOrigin,
address_space = AddressSpace.SHARED,
].stack_allocation()
global_i = block_dim.x * block_idx.x + thread_idx.x
local_i = thread_idx.x
# Compute element-wise multiplication into shared memory
if global_i < size:
shared[local_i] = a[global_i] * b[global_i]
# Synchronize threads within block
barrier()
# Parallel reduction in shared memory
stride = UInt(TPB // 2)
while stride > 0:
if local_i < stride:
shared[local_i] += shared[local_i + stride]
barrier()
stride //= 2
# Only thread 0 writes the final result
if local_i == 0:
output[0] = shared[0]
LayoutTensor๋ฅผ ํ์ฉํ ๋ณ๋ ฌ ๋ฆฌ๋์ ์ผ๋ก ๋ด์ ์ ๊ณ์ฐํ๋ ์๋ฃจ์ ์ ๋๋ค. ๋จ๊ณ๋ณ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1๋จ๊ณ: ์์๋ณ ๊ณฑ์
๊ฐ ์ค๋ ๋๊ฐ ์ง๊ด์ ์ธ ์ธ๋ฑ์ฑ์ผ๋ก ๊ณฑ์ ์ฐ์ฐ์ ํ๋์ฉ ์ฒ๋ฆฌํฉ๋๋ค:
shared[local_i] = a[global_i] * b[global_i]
2๋จ๊ณ: ๋ณ๋ ฌ ๋ฆฌ๋์
๋ ์ด์์์ ์ธ์ํ๋ ํธ๋ฆฌ ๊ธฐ๋ฐ ๋ฆฌ๋์ ์ ๋๋ค:
์ด๊ธฐ๊ฐ: [0*0 1*1 2*2 3*3 4*4 5*5 6*6 7*7]
= [0 1 4 9 16 25 36 49]
Step 1: [0+16 1+25 4+36 9+49 16 25 36 49]
= [16 26 40 58 16 25 36 49]
Step 2: [16+40 26+58 40 58 16 25 36 49]
= [56 84 40 58 16 25 36 49]
Step 3: [56+84 84 40 58 16 25 36 49]
= [140 84 40 58 16 25 36 49]
๊ตฌํ์ ํต์ฌ ํน์ง
-
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ:
address_spaceํ๋ผ๋ฏธํฐ ํ๋๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊น๋ํ๊ฒ ํ ๋น- ํ์ ์์ ํ ์ฐ์ฐ์ด ๋ณด์ฅ๋๊ณ
- ๊ฒฝ๊ณ ๊ฒ์ฌ๊ฐ ์๋์ผ๋ก ๋ฐ๋ผ์ค๋ฉฐ
- ์ธ๋ฑ์ฑ๋ ๋ ์ด์์์ ์ธ์
-
์ค๋ ๋ ๋๊ธฐํ:
- ์ด๊ธฐ ๊ณฑ์
์ด ๋๋๋ฉด
barrier() - ๋ฆฌ๋์
๋จ๊ณ ์ฌ์ด๋ง๋ค
barrier() - ์ค๋ ๋ ๊ฐ ์์ ํ ์กฐ์จ ๋ณด์ฅ
- ์ด๊ธฐ ๊ณฑ์
์ด ๋๋๋ฉด
-
๋ฆฌ๋์ ๋ก์ง:
stride = TPB // 2 while stride > 0: if local_i < stride: shared[local_i] += shared[local_i + stride] barrier() stride //= 2 -
์ฑ๋ฅ์ ์ด์ :
- \(O(\log n)\) ์๊ฐ ๋ณต์ก๋
- ๋ณํฉ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ
- ์ต์ํ์ ์ค๋ ๋ ๋ถ๊ธฐ
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ํจ์จ์ ํ์ฉ
LayoutTensor ๋ฒ์ ์ ๋ณ๋ ฌ ๋ฆฌ๋์ ์ ํจ์จ์ ๊ทธ๋๋ก ์ ์งํ๋ฉด์, ์ฌ๊ธฐ์ ๋ํด:
- ํ์ ์์ ์ฑ์ด ํ์ธต ๊ฐํ๋๊ณ
- ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ๋ ๊น๋ํด์ง๋ฉฐ
- ๋ ์ด์์์ ์๋์ผ๋ก ์ธ์ํ๊ณ
- ์ธ๋ฑ์ฑ ๋ฌธ๋ฒ๋ ์์ฐ์ค๋ฌ์์ง๋๋ค
๋ฐฐ๋ฆฌ์ด ๋๊ธฐํ์ ์ค์์ฑ
๋ฆฌ๋์
๋จ๊ณ ์ฌ์ด์ barrier()๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ํด ๋ฐ๋์ ํ์ํฉ๋๋ค. ๊ทธ ์ด์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
barrier()๊ฐ ์์ผ๋ฉด ๊ฒฝ์ ์ํ๊ฐ ๋ฐ์ํฉ๋๋ค:
์ด๊ธฐ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ: [0 1 4 9 16 25 36 49]
Step 1 (stride = 4):
Thread 0 ์ฝ๊ธฐ: shared[0] = 0, shared[4] = 16
Thread 1 ์ฝ๊ธฐ: shared[1] = 1, shared[5] = 25
Thread 2 ์ฝ๊ธฐ: shared[2] = 4, shared[6] = 36
Thread 3 ์ฝ๊ธฐ: shared[3] = 9, shared[7] = 49
barrier ์์ด:
- Thread 0 ์ฐ๊ธฐ: shared[0] = 0 + 16 = 16
- Thread 1์ด Thread 0๋ณด๋ค ๋จผ์ ๋ค์ ๋จ๊ณ(stride = 2)๋ก ๋์ด๊ฐ์
16์ด ์๋ ์ด์ ๊ฐ shared[0] = 0์ ์ฝ์ด๋ฒ๋ฆฝ๋๋ค!
barrier()๊ฐ ์์ผ๋ฉด:
Step 1 (stride = 4):
๋ชจ๋ ์ค๋ ๋๊ฐ ํฉ์ ๊ธฐ๋ก:
[16 26 40 58 16 25 36 49]
barrier()๊ฐ ๋ชจ๋ ์ค๋ ๋์๊ฒ ์ด ๊ฐ๋ค์ด ๋ณด์ด๋๋ก ๋ณด์ฅ
Step 2 (stride = 2):
์ด์ ์
๋ฐ์ดํธ๋ ๊ฐ์ ์์ ํ๊ฒ ์ฝ์ ์ ์์:
Thread 0: shared[0] = 16 + 40 = 56
Thread 1: shared[1] = 26 + 58 = 84
barrier()๋ ๋ค์์ ๋ณด์ฅํฉ๋๋ค:
- ํ์ฌ ๋จ๊ณ์ ๋ชจ๋ ์ฐ๊ธฐ๊ฐ ๋๋ ๋ค์์ผ ๋ค์์ผ๋ก ๋์ด๊ฐ
- ๋ชจ๋ ์ค๋ ๋๊ฐ ์ต์ ๊ฐ์ ๋ณผ ์ ์์
- ์ด๋ค ์ค๋ ๋๋ ์์ ๋๊ฐ์ง ์์
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํญ์ ์ผ๊ด๋ ์ํ๋ฅผ ์ ์ง
์ด๋ฐ ๋๊ธฐํ ์ง์ ์ด ์์ผ๋ฉด:
- ๊ฒฝ์ ์ํ๊ฐ ๋ฐ์ํ๊ณ
- ์ค๋ ๋๊ฐ ์ด๋ฏธ ์ง๋ ๊ฐ์ ์ฝ๊ฒ ๋๋ฉฐ
- ์คํํ ๋๋ง๋ค ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง๊ณ
- ์ต์ข ํฉ๊ณ๊ฐ ํ์ด์ง ์ ์์ต๋๋ค