block.prefix_sum()๊ณผ ๋ณ๋ ฌ ํ์คํ ๊ทธ๋จ ๊ตฌ๊ฐ ๋ถ๋ฅ
์ด ํผ์ฆ์ ๋ธ๋ก ๋ ๋ฒจ block.prefix_sum ์ฐ์ฐ์ ์ฌ์ฉํ์ฌ ๊ณ ๊ธ ๋ณ๋ ฌ ํํฐ๋ง๊ณผ ์ถ์ถ์ ์ํ ๋ณ๋ ฌ ํ์คํ ๊ทธ๋จ ๊ตฌ๊ฐ ๋ถ๋ฅ๋ฅผ ๊ตฌํํฉ๋๋ค. ๊ฐ ์ค๋ ๋๊ฐ ์์ ์ ์์๊ฐ ์ํ ๋์ ๊ตฌ๊ฐ์ ๊ฒฐ์ ํ ๋ค์, block.prefix_sum()์ ์ ์ฉํ์ฌ ํน์ ๊ตฌ๊ฐ์ ์์๋ฅผ ์ถ์ถํ๊ธฐ ์ํ ์ฐ๊ธฐ ์์น๋ฅผ ๊ณ์ฐํฉ๋๋ค. ๋์ ํฉ์ด ๋จ์ํ ๋ฆฌ๋์
์ ๋์ด ๊ณ ๊ธ ๋ณ๋ ฌ ํํฐ์
๋์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
ํต์ฌ ํต์ฐฐ: block.prefix_sum() ์ฐ์ฐ์ ๋ธ๋ก ๋ด ๋ชจ๋ ์ค๋ ๋์ ๊ฑธ์ณ ์ผ์นํ๋ ์์์ ๋์ ์ฐ๊ธฐ ์์น๋ฅผ ๊ณ์ฐํ์ฌ ๋ณ๋ ฌ ํํฐ๋ง๊ณผ ์ถ์ถ์ ์ ๊ณตํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
์ด ํผ์ฆ์์ ๋ค๋ฃจ๋ ๋ด์ฉ:
block.prefix_sum()์ ํ์ฉํ ๋ธ๋ก ๋ ๋ฒจ ๋์ ํฉ- ๋์ ์ฐ์ฐ์ ์ฌ์ฉํ ๋ณ๋ ฌ ํํฐ๋ง๊ณผ ์ถ์ถ
- ๊ณ ๊ธ ๋ณ๋ ฌ ํํฐ์ ๋ ์๊ณ ๋ฆฌ์ฆ
- ๋ธ๋ก ์ ์ฒด ์กฐ์จ์ ํตํ ํ์คํ ๊ทธ๋จ ๊ตฌ๊ฐ ๋ถ๋ฅ
- ๋นํฌํจ(exclusive) vs ํฌํจ(inclusive) ๋์ ํฉ ํจํด
์ด ์๊ณ ๋ฆฌ์ฆ์ ํน์ ๊ฐ ๋ฒ์(๊ตฌ๊ฐ)์ ์ํ๋ ์์๋ฅผ ์ถ์ถํ์ฌ ํ์คํ ๊ทธ๋จ์ ๊ตฌ์ฑํฉ๋๋ค: \[\Large \text{Bin}_k = \{x_i : k/N \leq x_i < (k+1)/N\}\]
๊ฐ ์ค๋ ๋๊ฐ ์์ ์ ์์๊ฐ ์ํ๋ ๊ตฌ๊ฐ์ ๊ฒฐ์ ํ๊ณ , block.prefix_sum()์ด ๋ณ๋ ฌ ์ถ์ถ์ ์กฐ์จํฉ๋๋ค.
๊ตฌ์ฑ
- ๋ฒกํฐ ํฌ๊ธฐ:
SIZE = 128์์ - ๋ฐ์ดํฐ ํ์
:
DType.float32 - ๋ธ๋ก ๊ตฌ์ฑ:
(128, 1)๋ธ๋ก๋น ์ค๋ ๋ ์ (TPB = 128) - ๊ทธ๋ฆฌ๋ ๊ตฌ์ฑ:
(1, 1)๊ทธ๋ฆฌ๋๋น ๋ธ๋ก ์ - ๊ตฌ๊ฐ ์:
NUM_BINS = 8(๋ฒ์ [0.0, 0.125), [0.125, 0.25) ๋ฑ) - ๋ ์ด์์:
Layout.row_major(SIZE)(1D row-major) - ๋ธ๋ก๋น ์ํ ์:
128 / WARP_SIZE(GPU์ ๋ฐ๋ผ 2๊ฐ ๋๋ 4๊ฐ)
๋์ ๊ณผ์ : ๋ณ๋ ฌ ๊ตฌ๊ฐ ์ถ์ถ
๊ธฐ์กด์ ์์ฐจ์ ํ์คํ ๊ทธ๋จ ๊ตฌ์ฑ์ ์์๋ฅผ ํ๋์ฉ ์ฒ๋ฆฌํฉ๋๋ค:
# ์์ฐจ์ ๋ฐฉ์ - ๋ณ๋ ฌํ๊ฐ ์ด๋ ค์
histogram = [[] for _ in range(NUM_BINS)]
for element in data:
bin_id = int(element * NUM_BINS) # ๊ตฌ๊ฐ ๊ฒฐ์
histogram[bin_id].append(element) # ์์ฐจ์ ์ถ๊ฐ
๋จ์ํ GPU ๋ณ๋ ฌํ์ ๋ฌธ์ ์ :
- ๊ฒฝ์ ์ํ: ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๊ฐ์ ๊ตฌ๊ฐ์ ๋์์ ์ฐ๊ธฐ
- ๋น์ ๋ ฌ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ: ์ค๋ ๋๋ค์ด ์๋ก ๋ค๋ฅธ ๋ฉ๋ชจ๋ฆฌ ์์น์ ์ ๊ทผ
- ๋ถํ ๋ถ๊ท ํ: ์ผ๋ถ ๊ตฌ๊ฐ์ ํจ์ฌ ๋ง์ ์์๊ฐ ๋ชฐ๋ฆด ์ ์์
- ๋ณต์กํ ๋๊ธฐํ: ๋ฐฐ๋ฆฌ์ด์ ์์์ ์ฐ์ฐ์ด ํ์
๊ณ ๊ธ ๋ฐฉ์: block.prefix_sum() ์กฐ์จ
๋ณต์กํ ๋ณ๋ ฌ ํํฐ์ ๋์ ์กฐ์จ๋ ์ถ์ถ๋ก ๋ณํํฉ๋๋ค:
์์ฑํ ์ฝ๋
block.prefix_sum() ๋ฐฉ์
block.prefix_sum()์ ์ฌ์ฉํ์ฌ ๋ณ๋ ฌ ํ์คํ ๊ทธ๋จ ๊ตฌ๊ฐ ๋ถ๋ฅ๋ฅผ ๊ตฌํํฉ๋๋ค:
comptime bin_layout = Layout.row_major(SIZE) # Max SIZE elements per bin
fn block_histogram_bin_extract[
in_layout: Layout, bin_layout: Layout, out_layout: Layout, tpb: Int
](
input_data: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
bin_output: LayoutTensor[dtype, bin_layout, MutAnyOrigin],
count_output: LayoutTensor[DType.int32, out_layout, MutAnyOrigin],
size: Int,
target_bin: Int,
num_bins: Int,
):
"""Parallel histogram using block.prefix_sum() for bin extraction.
This demonstrates advanced parallel filtering and extraction:
1. Each thread determines which bin its element belongs to
2. Use block.prefix_sum() to compute write positions for target_bin elements
3. Extract and pack only elements belonging to target_bin
"""
global_i = Int(block_dim.x * block_idx.x + thread_idx.x)
local_i = Int(thread_idx.x)
# Step 1: Each thread determines its bin and element value
# FILL IN (roughly 9 lines)
# Step 2: Create predicate for target bin extraction
# FILL IN (roughly 3 line)
# Step 3: Use block.prefix_sum() for parallel bin extraction!
# This computes where each thread should write within the target bin
# FILL IN (1 line)
# Step 4: Extract and pack elements belonging to target_bin
# FILL IN (roughly 2 line)
# Step 5: Final thread computes total count for this bin
# FILL IN (roughly 3 line)
์ ์ฒด ํ์ผ ๋ณด๊ธฐ: problems/p27/p27.mojo
ํ
1. ํต์ฌ ์๊ณ ๋ฆฌ์ฆ ๊ตฌ์กฐ (์ด์ ํผ์ฆ์์ ์ ์ฉ)
block_sum_dot_product์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ค์ ํต์ฌ ๋ณ์๊ฐ ํ์ํฉ๋๋ค:
global_i = block_dim.x * block_idx.x + thread_idx.x
local_i = thread_idx.x
ํจ์๋ 5๊ฐ์ง ์ฃผ์ ๋จ๊ณ(์ด ์ฝ 15-20์ค)๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- ์์๋ฅผ ๋ก๋ํ๊ณ ๊ตฌ๊ฐ์ ๊ฒฐ์
- ๋์ ๊ตฌ๊ฐ์ ๋ํ ์ด์ง ํ๋ ๋์ผ์ดํธ ์์ฑ
- ํ๋ ๋์ผ์ดํธ์
block.prefix_sum()์คํ - ๊ณ์ฐ๋ ์คํ์ ์ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด๋ถ ์ฐ๊ธฐ
- ๋ง์ง๋ง ์ค๋ ๋๊ฐ ์ด ๊ฐ์๋ฅผ ๊ณ์ฐ
2. ๊ตฌ๊ฐ ๊ณ์ฐ (math.floor ์ฌ์ฉ)
Float32 ๊ฐ์ ๊ตฌ๊ฐ์ผ๋ก ๋ถ๋ฅํ๋ ค๋ฉด:
my_value = input_data[global_i][0] # ๋ด์ ์์์ฒ๋ผ SIMD ์ถ์ถ
bin_number = Int(floor(my_value * num_bins))
๊ฒฝ๊ณ ์ฌ๋ก ์ฒ๋ฆฌ: ์ ํํ 1.0์ธ ๊ฐ์ ๊ตฌ๊ฐ NUM_BINS์ ๋ค์ด๊ฐ์ง๋ง, ์ค์ ๊ตฌ๊ฐ์ 0๋ถํฐ NUM_BINS-1๊น์ง์
๋๋ค. if ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ต๋ ๊ตฌ๊ฐ์ ์ ํํ์ธ์.
3. ์ด์ง ํ๋ ๋์ผ์ดํธ ์์ฑ
์ด ์ค๋ ๋์ ์์๊ฐ target_bin์ ์ํ๋์ง๋ฅผ ๋ํ๋ด๋ ์ ์ ๋ณ์(0 ๋๋ 1)๋ฅผ ๋ง๋ญ๋๋ค:
var belongs_to_target: Int = 0
if (thread_has_valid_element) and (my_bin == target_bin):
belongs_to_target = 1
์ด๊ฒ์ด ํต์ฌ ํต์ฐฐ์ ๋๋ค: ๋์ ํฉ์ด ์ด ์ด์ง ํ๋๊ทธ์ ์์ฉํ์ฌ ์์น๋ฅผ ๊ณ์ฐํฉ๋๋ค!
4. block.prefix_sum() ํธ์ถ ํจํด
๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ํธ์ถ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
offset = block.prefix_sum[
dtype=DType.int32, # ์ ์ ํ๋ ๋์ผ์ดํธ๋ก ์์
block_size=tpb, # block.sum()๊ณผ ๋์ผ
exclusive=True # ํต์ฌ: ๊ฐ ์ค๋ ๋ ์ด์ ์ ์์น๋ฅผ ์ ๊ณต
](val=SIMD[DType.int32, 1](my_predicate_value))
์ ๋นํฌํจ(exclusive)์ธ๊ฐ? ์์น 5์์ ํ๋ ๋์ผ์ดํธ=1์ธ ์ค๋ ๋๋, ์์ ์์ 4๊ฐ์ ์์๊ฐ ์์๋ค๋ฉด output[4]์ ์จ์ผ ํฉ๋๋ค.
5. ์กฐ๊ฑด๋ถ ์ฐ๊ธฐ ํจํด
belongs_to_target == 1์ธ ์ค๋ ๋๋ง ๊ธฐ๋กํด์ผ ํฉ๋๋ค:
if belongs_to_target == 1:
bin_output[Int(offset[0])] = my_value # ์ธ๋ฑ์ฑ์ ์ํด SIMD๋ฅผ Int๋ก ๋ณํ
์ด๊ฒ์ Puzzle 12์ ๊ฒฝ๊ณ ๊ฒ์ฌ ํจํด๊ณผ ๋์ผํ์ง๋ง, ์กฐ๊ฑด์ด โ๋์ ๊ตฌ๊ฐ์ ์ํ๋์งโ๋ก ๋ฐ๋์์ต๋๋ค.
6. ์ต์ข ๊ฐ์ ๊ณ์ฐ
๋ง์ง๋ง ์ค๋ ๋(์ค๋ ๋ 0์ด ์๋!)๊ฐ ์ด ๊ฐ์๋ฅผ ๊ณ์ฐํฉ๋๋ค:
if local_i == tpb - 1: # ๋ธ๋ก์ ๋ง์ง๋ง ์ค๋ ๋
total_count = offset[0] + belongs_to_target # ํฌํจ = ๋นํฌํจ + ์์ ์ ๊ธฐ์ฌ๋ถ
count_output[0] = total_count
์ ๋ง์ง๋ง ์ค๋ ๋์ธ๊ฐ? ๊ฐ์ฅ ๋์ offset ๊ฐ์ ๊ฐ์ง๋ฏ๋ก, offset + ๊ธฐ์ฌ๋ถ์ด ์ด ๊ฐ์๊ฐ ๋ฉ๋๋ค.
7. ๋ฐ์ดํฐ ํ์ ๊ณผ ๋ณํ
์ด์ ํผ์ฆ์ ํจํด์ ๊ธฐ์ตํ์ธ์:
LayoutTensor์ธ๋ฑ์ฑ์ SIMD๋ฅผ ๋ฐํ:input_data[i][0]block.prefix_sum()์ SIMD๋ฅผ ๋ฐํ:offset[0]์ผ๋ก ์ถ์ถ- ๋ฐฐ์ด ์ธ๋ฑ์ฑ์
Int๊ฐ ํ์:bin_output[...]์Int(offset[0])
block.prefix_sum() ๋ฐฉ์ ํ ์คํธ:
pixi run p27 --histogram
pixi run -e amd p27 --histogram
pixi run -e apple p27 --histogram
uv run poe p27 --histogram
ํ์์ ๋์ ์์ ์ถ๋ ฅ:
SIZE: 128
TPB: 128
NUM_BINS: 8
Input sample: 0.0 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.11 0.12 0.13 0.14 0.15 ...
=== Processing Bin 0 (range [ 0.0 , 0.125 )) ===
Bin 0 count: 26
Bin 0 extracted elements: 0.0 0.01 0.02 0.03 0.04 0.05 0.06 0.07 ...
=== Processing Bin 1 (range [ 0.125 , 0.25 )) ===
Bin 1 count: 24
Bin 1 extracted elements: 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.2 ...
=== Processing Bin 2 (range [ 0.25 , 0.375 )) ===
Bin 2 count: 26
Bin 2 extracted elements: 0.25 0.26 0.27 0.28 0.29 0.3 0.31 0.32 ...
=== Processing Bin 3 (range [ 0.375 , 0.5 )) ===
Bin 3 count: 22
Bin 3 extracted elements: 0.38 0.39 0.4 0.41 0.42 0.43 0.44 0.45 ...
=== Processing Bin 4 (range [ 0.5 , 0.625 )) ===
Bin 4 count: 13
Bin 4 extracted elements: 0.5 0.51 0.52 0.53 0.54 0.55 0.56 0.57 ...
=== Processing Bin 5 (range [ 0.625 , 0.75 )) ===
Bin 5 count: 12
Bin 5 extracted elements: 0.63 0.64 0.65 0.66 0.67 0.68 0.69 0.7 ...
=== Processing Bin 6 (range [ 0.75 , 0.875 )) ===
Bin 6 count: 5
Bin 6 extracted elements: 0.75 0.76 0.77 0.78 0.79
=== Processing Bin 7 (range [ 0.875 , 1.0 )) ===
Bin 7 count: 0
Bin 7 extracted elements:
์๋ฃจ์
fn block_histogram_bin_extract[
in_layout: Layout, bin_layout: Layout, out_layout: Layout, tpb: Int
](
input_data: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
bin_output: LayoutTensor[dtype, bin_layout, MutAnyOrigin],
count_output: LayoutTensor[DType.int32, out_layout, MutAnyOrigin],
size: Int,
target_bin: Int,
num_bins: Int,
):
"""Parallel histogram using block.prefix_sum() for bin extraction.
This demonstrates advanced parallel filtering and extraction:
1. Each thread determines which bin its element belongs to
2. Use block.prefix_sum() to compute write positions for target_bin elements
3. Extract and pack only elements belonging to target_bin
"""
global_i = Int(block_dim.x * block_idx.x + thread_idx.x)
local_i = Int(thread_idx.x)
# Step 1: Each thread determines its bin and element value
var my_value: Scalar[dtype] = 0.0
var my_bin: Int = -1
if global_i < size:
# `[0]` returns the underlying SIMD value
my_value = input_data[global_i][0]
# Bin values [0.0, 1.0) into num_bins buckets
my_bin = Int(floor(my_value * num_bins))
# Clamp to valid range
if my_bin >= num_bins:
my_bin = num_bins - 1
if my_bin < 0:
my_bin = 0
# Step 2: Create predicate for target bin extraction
var belongs_to_target: Int = 0
if global_i < size and my_bin == target_bin:
belongs_to_target = 1
# Step 3: Use block.prefix_sum() for parallel bin extraction!
# This computes where each thread should write within the target bin
write_offset = block.prefix_sum[
dtype = DType.int32, block_size=tpb, exclusive=True
](val=SIMD[DType.int32, 1](belongs_to_target))
# Step 4: Extract and pack elements belonging to target_bin
if belongs_to_target == 1:
bin_output[Int(write_offset[0])] = my_value
# Step 5: Final thread computes total count for this bin
if local_i == tpb - 1:
# Inclusive sum = exclusive sum + my contribution
total_count = write_offset[0] + belongs_to_target
count_output[0] = total_count
block.prefix_sum() ์ปค๋์ ์ด์ ํผ์ฆ์ ๊ฐ๋
์ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ๊ธ ๋ณ๋ ฌ ์กฐ์จ ํจํด์ ๋ณด์ฌ์ค๋๋ค:
๋จ๊ณ๋ณ ์๊ณ ๋ฆฌ์ฆ ๋ถ์:
1๋จ๊ณ: ์์ ์ฒ๋ฆฌ (Puzzle 12 ๋ด์ ๊ณผ ์ ์ฌ)
์ค๋ ๋ ์ธ๋ฑ์ฑ (์ต์ํ ํจํด):
global_i = block_dim.x * block_idx.x + thread_idx.x // ์ ์ญ ์์ ์ธ๋ฑ์ค
local_i = thread_idx.x // ๋ก์ปฌ ์ค๋ ๋ ์ธ๋ฑ์ค
์์ ๋ก๋ฉ (LayoutTensor ํจํด๊ณผ ๋์ผ):
์ค๋ ๋ 0: my_value = input_data[0][0] = 0.00
์ค๋ ๋ 1: my_value = input_data[1][0] = 0.01
์ค๋ ๋ 13: my_value = input_data[13][0] = 0.13
์ค๋ ๋ 25: my_value = input_data[25][0] = 0.25
...
2๋จ๊ณ: ๊ตฌ๊ฐ ๋ถ๋ฅ (์๋ก์ด ๊ฐ๋ )
floor ์ฐ์ฐ์ ์ฌ์ฉํ ๊ตฌ๊ฐ ๊ณ์ฐ:
์ค๋ ๋ 0: my_bin = Int(floor(0.00 * 8)) = 0 // ๊ฐ [0.000, 0.125) โ ๊ตฌ๊ฐ 0
์ค๋ ๋ 1: my_bin = Int(floor(0.01 * 8)) = 0 // ๊ฐ [0.000, 0.125) โ ๊ตฌ๊ฐ 0
์ค๋ ๋ 13: my_bin = Int(floor(0.13 * 8)) = 1 // ๊ฐ [0.125, 0.250) โ ๊ตฌ๊ฐ 1
์ค๋ ๋ 25: my_bin = Int(floor(0.25 * 8)) = 2 // ๊ฐ [0.250, 0.375) โ ๊ตฌ๊ฐ 2
...
3๋จ๊ณ: ์ด์ง ํ๋ ๋์ผ์ดํธ ์์ฑ (ํํฐ๋ง ํจํด)
target_bin=0์ ๋ํด ์ถ์ถ ๋ง์คํฌ ์์ฑ:
์ค๋ ๋ 0: belongs_to_target = 1 (๊ตฌ๊ฐ 0 == ๋์ 0)
์ค๋ ๋ 1: belongs_to_target = 1 (๊ตฌ๊ฐ 0 == ๋์ 0)
์ค๋ ๋ 13: belongs_to_target = 0 (๊ตฌ๊ฐ 1 != ๋์ 0)
์ค๋ ๋ 25: belongs_to_target = 0 (๊ตฌ๊ฐ 2 != ๋์ 0)
...
์ด์ง ๋ฐฐ์ด ์์ฑ: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, ...]
4๋จ๊ณ: ๋ณ๋ ฌ ๋์ ํฉ (๋ง๋ฒ์ด ์ผ์ด๋๋ ๊ณณ!)
ํ๋ ๋์ผ์ดํธ์ block.prefix_sum[exclusive=True] ์ ์ฉ:
์
๋ ฅ: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, ...]
๋นํฌํจ: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, -, -, -, ...]
^
์ค์ํ์ง ์์
ํต์ฌ ํต์ฐฐ: ๊ฐ ์ค๋ ๋๊ฐ ์ถ๋ ฅ ๋ฐฐ์ด์์ ์์ ์ ์ฐ๊ธฐ ์์น๋ฅผ ๋ฐ์ต๋๋ค!
5๋จ๊ณ: ์กฐ์จ๋ ์ถ์ถ (์กฐ๊ฑด๋ถ ์ฐ๊ธฐ)
belongs_to_target=1์ธ ์ค๋ ๋๋ง ๊ธฐ๋ก:
์ค๋ ๋ 0: bin_output[0] = 0.00 // write_offset[0] = 0 ์ฌ์ฉ
์ค๋ ๋ 1: bin_output[1] = 0.01 // write_offset[1] = 1 ์ฌ์ฉ
์ค๋ ๋ 12: bin_output[12] = 0.12 // write_offset[12] = 12 ์ฌ์ฉ
์ค๋ ๋ 13: (๊ธฐ๋ก ์ ํจ) // belongs_to_target = 0
์ค๋ ๋ 25: (๊ธฐ๋ก ์ ํจ) // belongs_to_target = 0
...
๊ฒฐ๊ณผ: [0.00, 0.01, 0.02, ..., 0.12, ???, ???, ...] // ๋นํ์์ด ์ฑ์์ง!
6๋จ๊ณ: ๊ฐ์ ๊ณ์ฐ (block.sum() ํจํด๊ณผ ์ ์ฌ)
๋ง์ง๋ง ์ค๋ ๋๊ฐ ์ด ๊ฐ์๋ฅผ ๊ณ์ฐ (์ค๋ ๋ 0์ด ์๋!):
if local_i == tpb - 1: // ์ด ๊ฒฝ์ฐ ์ค๋ ๋ 127
total = write_offset[0] + belongs_to_target // ํฌํจ ํฉ ๊ณต์
count_output[0] = total
์ด ๊ณ ๊ธ ์๊ณ ๋ฆฌ์ฆ์ด ๋์ํ๋ ์ด์ :
Puzzle 12 (๊ธฐ์กด ๋ด์ )๊ณผ์ ์ฐ๊ฒฐ:
- ๋์ผํ ์ค๋ ๋ ์ธ๋ฑ์ฑ:
global_i์local_iํจํด - ๋์ผํ ๊ฒฝ๊ณ ๊ฒ์ฌ:
if global_i < size๊ฒ์ฆ - ๋์ผํ ๋ฐ์ดํฐ ๋ก๋ฉ:
[0]์ ์ฌ์ฉํ LayoutTensor SIMD ์ถ์ถ
block.sum() (์ด ํผ์ฆ์ ์๋ถ๋ถ)๊ณผ์ ์ฐ๊ฒฐ:
- ๋์ผํ ๋ธ๋ก ์ ์ฒด ์ฐ์ฐ: ๋ชจ๋ ์ค๋ ๋๊ฐ ๋ธ๋ก ๊ธฐ๋ณธ ์์์ ์ฐธ์ฌ
- ๋์ผํ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ: ํน์ ์ค๋ ๋(์ฒซ ๋ฒ์งธ ๋์ ๋ง์ง๋ง)๊ฐ ์ต์ข ๊ฒฐ๊ณผ ์ฒ๋ฆฌ
- ๋์ผํ SIMD ๋ณํ: ๋ฐฐ์ด ์ธ๋ฑ์ฑ์ ์ํ
Int(result[0])ํจํด
block.prefix_sum()๋ง์ ๊ณ ๊ธ ๊ฐ๋
:
- ๋ชจ๋ ์ค๋ ๋๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์: ์ค๋ ๋ 0๋ง ์ค์ํ
block.sum()๊ณผ ๋ฌ๋ฆฌ - ์กฐ์จ๋ ์ฐ๊ธฐ ์์น: ๋์ ํฉ์ด ๊ฒฝ์ ์ํ๋ฅผ ์๋์ผ๋ก ์ ๊ฑฐ
- ๋ณ๋ ฌ ํํฐ๋ง: ์ด์ง ํ๋ ๋์ผ์ดํธ๊ฐ ๊ณ ๊ธ ๋ฐ์ดํฐ ์ฌ๊ตฌ์ฑ์ ๊ฐ๋ฅํ๊ฒ ํจ
๋จ์ํ ๋ฐฉ์ ๋๋น ์ฑ๋ฅ ์ด์ :
vs. ์์์ ์ฐ์ฐ:
- ๊ฒฝ์ ์ํ ์์: ๋์ ํฉ์ด ๊ณ ์ ํ ์ฐ๊ธฐ ์์น๋ฅผ ์ ๊ณต
- ๋ณํฉ๋ ๋ฉ๋ชจ๋ฆฌ: ์์ฐจ์ ์ฐ๊ธฐ๊ฐ ์บ์ ์ฑ๋ฅ์ ํฅ์
- ์ง๋ ฌํ ์์: ๋ชจ๋ ์ฐ๊ธฐ๊ฐ ๋ณ๋ ฌ๋ก ์ํ
vs. ๋ค์ค ํจ์ค ์๊ณ ๋ฆฌ์ฆ:
- ๋จ์ผ ์ปค๋: ํ ๋ฒ์ GPU ์คํ์ผ๋ก ํ์คํ ๊ทธ๋จ ์ถ์ถ ์๋ฃ
- ์์ ํ์ฉ: ๋ฐ์ดํฐ ๋ถํฌ์ ๊ด๊ณ์์ด ๋ชจ๋ ์ค๋ ๋๊ฐ ์์
- ์ต์ ๋ฉ๋ชจ๋ฆฌ ๋์ญํญ: GPU ๋ฉ๋ชจ๋ฆฌ ๊ณ์ธต ๊ตฌ์กฐ์ ์ต์ ํ๋ ํจํด
์ด๊ฒ์ block.prefix_sum()์ด block.sum() ๊ฐ์ ๋จ์ํ ๊ธฐ๋ณธ ์์๋ก๋ ๋ณต์กํ๊ฑฐ๋ ๋ถ๊ฐ๋ฅํ ๊ณ ๊ธ ๋ณ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์ด๋ป๊ฒ ๊ฐ๋ฅํ๊ฒ ํ๋์ง ๋ณด์ฌ์ค๋๋ค.
์ฑ๋ฅ ์ธ์ฌ์ดํธ
block.prefix_sum() vs ๊ธฐ์กด ๋ฐฉ์:
- ์๊ณ ๋ฆฌ์ฆ ์ ๊ตํจ: ๊ณ ๊ธ ๋ณ๋ ฌ ํํฐ์ ๋ vs ์์ฐจ์ ์ฒ๋ฆฌ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ: ๋ณํฉ๋ ์ฐ๊ธฐ vs ๋ถ์ฐ๋ ๋ฌด์์ ์ ๊ทผ
- ๋๊ธฐํ: ๋ด์ฅ ์กฐ์จ vs ์๋ ๋ฐฐ๋ฆฌ์ด์ ์์์ ์ฐ์ฐ
- ํ์ฅ์ฑ: ๋ชจ๋ ๋ธ๋ก ํฌ๊ธฐ์ ๊ตฌ๊ฐ ์์ ๋์
block.prefix_sum() vs block.sum():
- ๋ฒ์: ๋ชจ๋ ์ค๋ ๋๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ vs ์ค๋ ๋ 0๋ง
- ์ฉ๋: ๋ณต์กํ ํํฐ์ ๋ vs ๋จ์ํ ์ง๊ณ
- ์๊ณ ๋ฆฌ์ฆ ์ ํ: ๋ณ๋ ฌ ์ค์บ ๊ธฐ๋ณธ ์์ vs ๋ฆฌ๋์ ๊ธฐ๋ณธ ์์
- ์ถ๋ ฅ ํจํด: ์ค๋ ๋๋ณ ์์น vs ๋จ์ผ ํฉ๊ณ
block.prefix_sum()์ ์ฌ์ฉํด์ผ ํ ๋:
- ๋ณ๋ ฌ ํํฐ๋ง: ์กฐ๊ฑด์ ๋ง๋ ์์ ์ถ์ถ
- ์คํธ๋ฆผ ์ปดํฉ์ : ๋ถํ์ํ ์์ ์ ๊ฑฐ
- ๋ณ๋ ฌ ํํฐ์ ๋: ๋ฐ์ดํฐ๋ฅผ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๋ถ๋ฆฌ
- ๊ณ ๊ธ ์๊ณ ๋ฆฌ์ฆ: ๋ถํ ๋ถ์ฐ, ์ ๋ ฌ, ๊ทธ๋ํ ์๊ณ ๋ฆฌ์ฆ
๋ค์ ๋จ๊ณ
block.prefix_sum() ์ฐ์ฐ์ ๋ฐฐ์ ์ผ๋, ๋ค์์ผ๋ก ์งํํ ์ ์์ต๋๋ค:
- block.broadcast()์ ๋ฒกํฐ ์ ๊ทํ: ๋ธ๋ก ๋ด ๋ชจ๋ ์ค๋ ๋์ ๊ฐ์ ๊ณต์
- ๋ฉํฐ ๋ธ๋ก ์๊ณ ๋ฆฌ์ฆ: ๋ ํฐ ๋ฌธ์ ๋ฅผ ์ํ ์ฌ๋ฌ ๋ธ๋ก ๊ฐ ์กฐ์จ
- ๊ณ ๊ธ ๋ณ๋ ฌ ์๊ณ ๋ฆฌ์ฆ: ์ ๋ ฌ, ๊ทธ๋ํ ํ์, ๋์ ๋ถํ ๋ถ์ฐ
- ๋ณต์กํ ๋ฉ๋ชจ๋ฆฌ ํจํด: ๋ธ๋ก ์ฐ์ฐ๊ณผ ๊ณ ๊ธ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ์ ๊ฒฐํฉ
๐ก ํต์ฌ ์์ : ๋ธ๋ก ๋์ ํฉ ์ฐ์ฐ์ GPU ํ๋ก๊ทธ๋๋ฐ์ ๋จ์ํ ๋ณ๋ ฌ ๊ณ์ฐ์์ ๊ณ ๊ธ ๋ณ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ณํํฉ๋๋ค. block.sum()์ด ๋ฆฌ๋์
์ ๋จ์ํํ๋ค๋ฉด, block.prefix_sum()์ ๊ณ ์ฑ๋ฅ ๋ณ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ํ์์ ์ธ ๊ณ ๊ธ ๋ฐ์ดํฐ ์ฌ๊ตฌ์ฑ ํจํด์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.