vectorize - SIMD μ œμ–΄

κ°œμš”

이 νΌμ¦μ—μ„œλŠ” μˆ˜λ™ 벑터화와 vectorizeλ₯Ό μ‚¬μš©ν•˜μ—¬ GPU 컀널 λ‚΄μ—μ„œ SIMD 연산을 μ •λ°€ν•˜κ²Œ μ œμ–΄ν•˜λŠ” κ³ κΈ‰ 벑터화 기법을 νƒκ΅¬ν•©λ‹ˆλ‹€. λ²‘ν„°ν™”λœ 연산에 λŒ€ν•΄ 두 κ°€μ§€ λ‹€λ₯Έ 접근법을 κ΅¬ν˜„ν•©λ‹ˆλ‹€:

  1. μˆ˜λ™ 벑터화: λͺ…μ‹œμ  인덱슀 계산을 ν†΅ν•œ 직접적인 SIMD μ œμ–΄
  2. Mojo의 vectorize ν•¨μˆ˜: μžλ™ 경계 검사λ₯Ό ν¬ν•¨ν•œ κ³ μˆ˜μ€€ 벑터화

두 접근법 λͺ¨λ‘ 타일링 κ°œλ…μ„ 기반으둜 ν•˜μ§€λ§Œ, μ œμ–΄, μ•ˆμ „μ„±, μ„±λŠ₯ μ΅œμ ν™” κ°„μ˜ νŠΈλ ˆμ΄λ“œμ˜€ν”„κ°€ λ‹€λ¦…λ‹ˆλ‹€.

핡심 톡찰: 벑터화 μ „λž΅μ€ μ„±λŠ₯ μš”κ΅¬ 사항과 λ³΅μž‘λ„ μˆ˜μ€€μ— 따라 달리 선택해야 ν•©λ‹ˆλ‹€.

핡심 κ°œλ…

이 νΌμ¦μ—μ„œ 배울 λ‚΄μš©:

  • λͺ…μ‹œμ  인덱슀 관리λ₯Ό ν†΅ν•œ μˆ˜λ™ SIMD μ—°μ‚°
  • μ•ˆμ „ν•˜κ³  μžλ™μ μΈ 벑터화λ₯Ό μœ„ν•œ Mojo의 vectorize ν•¨μˆ˜
  • 졜적의 SIMD 정렬을 μœ„ν•œ 청크 기반 λ©”λͺ¨λ¦¬ ꡬ성
  • 경계 쑰건을 μœ„ν•œ 경계 검사 μ „λž΅
  • μˆ˜λ™ μ œμ–΄μ™€ μ•ˆμ „μ„± κ°„μ˜ μ„±λŠ₯ νŠΈλ ˆμ΄λ“œμ˜€ν”„

이전과 λ™μΌν•œ μˆ˜ν•™μ  μ—°μ‚°: \[\Large \text{output}[i] = a[i] + b[i]\]

ν•˜μ§€λ§Œ μ΅œλŒ€ μ„±λŠ₯을 μœ„ν•œ μ •κ΅ν•œ 벑터화 μ „λž΅μ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

μ„€μ •

  • 벑터 크기: SIZE = 1024
  • 타일 크기: TILE_SIZE = 32
  • 데이터 νƒ€μž…: DType.float32
  • SIMD 폭: GPU 의쑴적
  • λ ˆμ΄μ•„μ›ƒ: Layout.row_major(SIZE) (1D ν–‰ μš°μ„ )

1. μˆ˜λ™ 벑터화 방식

μ™„μ„±ν•  μ½”λ“œ

fn manual_vectorized_tiled_elementwise_add[
    layout: Layout,
    dtype: DType,
    simd_width: Int,
    num_threads_per_tile: Int,
    rank: Int,
    size: Int,
    tile_size: Int,
](
    output: LayoutTensor[mut=True, dtype, layout, MutAnyOrigin],
    a: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    b: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    ctx: DeviceContext,
) raises:
    # Each tile contains tile_size groups of simd_width elements
    comptime chunk_size = tile_size * simd_width

    @parameter
    @always_inline
    fn process_manual_vectorized_tiles[
        num_threads_per_tile: Int, rank: Int, alignment: Int = align_of[dtype]()
    ](indices: IndexList[rank]) capturing -> None:
        tile_id = indices[0]
        print("tile_id:", tile_id)
        output_tile = output.tile[chunk_size](tile_id)
        a_tile = a.tile[chunk_size](tile_id)
        b_tile = b.tile[chunk_size](tile_id)

        # FILL IN (7 lines at most)

    # Number of tiles needed: each tile processes chunk_size elements
    num_tiles = (size + chunk_size - 1) // chunk_size
    elementwise[
        process_manual_vectorized_tiles, num_threads_per_tile, target="gpu"
    ](num_tiles, ctx)


전체 파일 보기: problems/p23/p23.mojo

팁

1. 청크 ꡬ성 μ΄ν•΄ν•˜κΈ°

comptime chunk_size = tile_size * simd_width  # 32 * 4 = 청크당 128개 μš”μ†Œ

각 타일은 이제 λ‹¨μˆœν•œ 순차 μš”μ†Œκ°€ μ•„λ‹Œ μ—¬λŸ¬ SIMD 그룹을 ν¬ν•¨ν•©λ‹ˆλ‹€.

2. μ „μ—­ 인덱슀 계산

global_start = tile_id * chunk_size + i * simd_width

청크 λ‚΄ 각 SIMD λ²‘ν„°μ˜ μ •ν™•ν•œ μ „μ—­ μœ„μΉ˜λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.

3. ν…μ„œ 직접 μ ‘κ·Ό

a_vec = a.load[simd_width](global_start, 0)     # μ „μ—­ ν…μ„œμ—μ„œ λ‘œλ“œ
output.store[simd_width](global_start, 0, ret)  # μ „μ—­ ν…μ„œμ— μ €μž₯

μ°Έκ³ : 타일 λ·°κ°€ μ•„λ‹Œ 원본 ν…μ„œμ— μ ‘κ·Όν•©λ‹ˆλ‹€.

4. μ£Όμš” νŠΉμ„±

  • 더 λ§Žμ€ μ œμ–΄, 더 λ§Žμ€ λ³΅μž‘μ„±, μ „μ—­ ν…μ„œ μ ‘κ·Ό
  • ν•˜λ“œμ›¨μ–΄μ— λŒ€ν•œ μ™„λ²½ν•œ SIMD μ •λ ¬
  • μˆ˜λ™ 경계 검사 ν•„μš”

μˆ˜λ™ 벑터화 μ‹€ν–‰

pixi run p23 --manual-vectorized
pixi run -e amd p23 --manual-vectorized
pixi run -e apple p23 --manual-vectorized
uv run poe p23 --manual-vectorized

퍼즐이 아직 풀리지 μ•Šμ€ 경우 λ‹€μŒκ³Ό 같이 좜λ ₯λ©λ‹ˆλ‹€:

SIZE: 1024
simd_width: 4
tile size: 32
tile_id: 0
tile_id: 1
tile_id: 2
tile_id: 3
tile_id: 4
tile_id: 5
tile_id: 6
tile_id: 7
out: HostBuffer([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])
expected: HostBuffer([1.0, 5.0, 9.0, ..., 4085.0, 4089.0, 4093.0])

μˆ˜λ™ 벑터화 풀이

fn manual_vectorized_tiled_elementwise_add[
    layout: Layout,
    dtype: DType,
    simd_width: Int,
    num_threads_per_tile: Int,
    rank: Int,
    size: Int,
    tile_size: Int,
](
    output: LayoutTensor[mut=True, dtype, layout, MutAnyOrigin],
    a: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    b: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    ctx: DeviceContext,
) raises:
    # Each tile contains tile_size groups of simd_width elements
    comptime chunk_size = tile_size * simd_width

    @parameter
    @always_inline
    fn process_manual_vectorized_tiles[
        num_threads_per_tile: Int, rank: Int, alignment: Int = align_of[dtype]()
    ](indices: IndexList[rank]) capturing -> None:
        tile_id = indices[0]

        output_tile = output.tile[chunk_size](tile_id)
        a_tile = a.tile[chunk_size](tile_id)
        b_tile = b.tile[chunk_size](tile_id)

        @parameter
        for i in range(tile_size):
            global_start = tile_id * chunk_size + i * simd_width

            a_vec = a.aligned_load[simd_width](Index(global_start))
            b_vec = b.aligned_load[simd_width](Index(global_start))
            ret = a_vec + b_vec
            # print("tile:", tile_id, "simd_group:", i, "global_start:", global_start, "a_vec:", a_vec, "b_vec:", b_vec, "result:", ret)

            output.store[simd_width](Index(global_start), ret)

    # Number of tiles needed: each tile processes chunk_size elements
    num_tiles = (size + chunk_size - 1) // chunk_size
    elementwise[
        process_manual_vectorized_tiles, num_threads_per_tile, target="gpu"
    ](num_tiles, ctx)


μˆ˜λ™ 벑터화 심측 뢄석

μˆ˜λ™ λ²‘ν„°ν™”λŠ” λͺ…μ‹œμ  인덱슀 계산을 톡해 SIMD 연산에 λŒ€ν•œ 직접적인 μ œμ–΄λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€:

  • 청크 기반 ꡬ성: chunk_size = tile_size * simd_width
  • μ „μ—­ 인덱싱: λ©”λͺ¨λ¦¬ μœ„μΉ˜μ˜ 직접 계산
  • μˆ˜λ™ 경계 관리: 경계 쑰건을 직접 처리

μ•„ν‚€ν…μ²˜μ™€ λ©”λͺ¨λ¦¬ λ ˆμ΄μ•„μ›ƒ:

comptime chunk_size = tile_size * simd_width  # 32 * 4 = 128

청크 ꡬ성 μ‹œκ°ν™” (TILE_SIZE=32, SIMD_WIDTH=4):

원본 λ°°μ—΄: [0, 1, 2, 3, ..., 1023]

청크 0 (thread 0): [0:128]    ← 128개 μš”μ†Œ = 4κ°œμ”© 32개 SIMD κ·Έλ£Ή
청크 1 (thread 1): [128:256]  ← λ‹€μŒ 128개 μš”μ†Œ
청크 2 (thread 2): [256:384]  ← λ‹€μŒ 128개 μš”μ†Œ
...
청크 7 (thread 7): [896:1024] ← λ§ˆμ§€λ§‰ 128개 μš”μ†Œ

ν•˜λ‚˜μ˜ 청크 λ‚΄ 처리:

@parameter
for i in range(tile_size):  # i = 0, 1, 2, ..., 31
    global_start = tile_id * chunk_size + i * simd_width
    # tile_id=0일 λ•Œ: global_start = 0, 4, 8, 12, ..., 124
    # tile_id=1일 λ•Œ: global_start = 128, 132, 136, 140, ..., 252

μ„±λŠ₯ νŠΉμ„±:

  • μŠ€λ ˆλ“œ 수: 8개 μŠ€λ ˆλ“œ (1024 Γ· 128 = 8)
  • μŠ€λ ˆλ“œλ‹Ή μž‘μ—…λŸ‰: 128개 μš”μ†Œ (각 4개 μš”μ†Œμ˜ SIMD μ—°μ‚° 32회)
  • λ©”λͺ¨λ¦¬ νŒ¨ν„΄: μ™„λ²½ν•œ SIMD 정렬을 κ°–μΆ˜ λŒ€ν˜• 청크
  • μ˜€λ²„ν—€λ“œ: μ΅œμ†Œ - ν•˜λ“œμ›¨μ–΄μ— 직접 λ§€ν•‘
  • μ•ˆμ „μ„±: μˆ˜λ™ 경계 검사 ν•„μš”

μ£Όμš” μž₯점:

  • 예츑 κ°€λŠ₯ν•œ 인덱싱: λ©”λͺ¨λ¦¬ μ ‘κ·Ό νŒ¨ν„΄μ— λŒ€ν•œ μ •ν™•ν•œ μ œμ–΄
  • 졜적의 μ •λ ¬: SIMD 연산이 ν•˜λ“œμ›¨μ–΄μ— μ™„λ²½νžˆ μ •λ ¬
  • μ΅œλŒ€ μ²˜λ¦¬λŸ‰: μ•ˆμ „μ„± κ²€μ‚¬λ‘œ μΈν•œ μ˜€λ²„ν—€λ“œ μ—†μŒ
  • ν•˜λ“œμ›¨μ–΄ μ΅œμ ν™”: GPU SIMD μœ λ‹›μ— 직접 λ§€ν•‘

μ£Όμš” 과제:

  • 인덱슀 λ³΅μž‘μ„±: μ „μ—­ μœ„μΉ˜μ˜ μˆ˜λ™ 계산
  • 경계 처리 μ±…μž„: 경계 쑰건을 직접 μ²˜λ¦¬ν•΄μ•Ό 함
  • 디버깅 λ‚œμ΄λ„: μ •ν™•μ„± 검증이 더 볡작

2. Mojo vectorize 방식

μ™„μ„±ν•  μ½”λ“œ

fn vectorize_within_tiles_elementwise_add[
    layout: Layout,
    dtype: DType,
    simd_width: Int,
    num_threads_per_tile: Int,
    rank: Int,
    size: Int,
    tile_size: Int,
](
    output: LayoutTensor[mut=True, dtype, layout, MutAnyOrigin],
    a: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    b: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    ctx: DeviceContext,
) raises:
    # Each tile contains tile_size elements (not SIMD groups)
    @parameter
    @always_inline
    fn process_tile_with_vectorize[
        num_threads_per_tile: Int, rank: Int, alignment: Int = align_of[dtype]()
    ](indices: IndexList[rank]) capturing -> None:
        tile_id = indices[0]
        tile_start = tile_id * tile_size
        tile_end = min(tile_start + tile_size, size)
        actual_tile_size = tile_end - tile_start
        print(
            "tile_id:",
            tile_id,
            "tile_start:",
            tile_start,
            "tile_end:",
            tile_end,
            "actual_tile_size:",
            actual_tile_size,
        )

        # FILL IN (9 lines at most)

    num_tiles = (size + tile_size - 1) // tile_size
    elementwise[
        process_tile_with_vectorize, num_threads_per_tile, target="gpu"
    ](num_tiles, ctx)


전체 파일 보기: problems/p23/p23.mojo

팁

1. 타일 경계 계산

tile_start = tile_id * tile_size
tile_end = min(tile_start + tile_size, size)
actual_tile_size = tile_end - tile_start

λ§ˆμ§€λ§‰ 타일이 tile_size보닀 μž‘μ„ 수 μžˆλŠ” 경우λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

2. 벑터화 ν•¨μˆ˜ νŒ¨ν„΄

fn vectorized_add[
  width: Int
](i: Int) unified {read tile_start, read a, read b, mut output}:
    global_idx = tile_start + i
    if global_idx + width <= size:  # 경계 검사
        # SIMD μ—°μ‚° μ½”λ“œ

width λ§€κ°œλ³€μˆ˜λŠ” vectorize ν•¨μˆ˜μ— μ˜ν•΄ μžλ™μœΌλ‘œ κ²°μ •λ©λ‹ˆλ‹€.

3. vectorize 호좜

vectorize[simd_width](actual_tile_size, vectorized_add)

제곡된 SIMD 폭으둜 벑터화 루프λ₯Ό μžλ™ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

4. μ£Όμš” νŠΉμ„±

  • μžλ™ λ‚˜λ¨Έμ§€ 처리, λ‚΄μž₯ μ•ˆμ „μ„±, 타일 기반 μ ‘κ·Ό
  • λͺ…μ‹œμ  SIMD 폭 λ§€κ°œλ³€μˆ˜ μ‚¬μš©
  • λ‚΄μž₯ 경계 검사와 μžλ™ λ‚˜λ¨Έμ§€ μš”μ†Œ 처리

Mojo vectorize μ‹€ν–‰

uv run poe p23 --vectorized
pixi run p23 --vectorized

퍼즐이 아직 풀리지 μ•Šμ€ 경우 λ‹€μŒκ³Ό 같이 좜λ ₯λ©λ‹ˆλ‹€:

SIZE: 1024
simd_width: 4
tile size: 32
tile_id: 0 tile_start: 0 tile_end: 32 actual_tile_size: 32
tile_id: 1 tile_start: 32 tile_end: 64 actual_tile_size: 32
tile_id: 2 tile_start: 64 tile_end: 96 actual_tile_size: 32
tile_id: 3 tile_start: 96 tile_end: 128 actual_tile_size: 32
...
tile_id: 29 tile_start: 928 tile_end: 960 actual_tile_size: 32
tile_id: 30 tile_start: 960 tile_end: 992 actual_tile_size: 32
tile_id: 31 tile_start: 992 tile_end: 1024 actual_tile_size: 32
out: HostBuffer([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])
expected: HostBuffer([1.0, 5.0, 9.0, ..., 4085.0, 4089.0, 4093.0])

Mojo vectorize 풀이

fn vectorize_within_tiles_elementwise_add[
    layout: Layout,
    dtype: DType,
    simd_width: Int,
    num_threads_per_tile: Int,
    rank: Int,
    size: Int,
    tile_size: Int,
](
    output: LayoutTensor[mut=True, dtype, layout, MutAnyOrigin],
    a: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    b: LayoutTensor[mut=False, dtype, layout, MutAnyOrigin],
    ctx: DeviceContext,
) raises:
    # Each tile contains tile_size elements (not SIMD groups)
    @parameter
    @always_inline
    fn process_tile_with_vectorize[
        num_threads_per_tile: Int, rank: Int, alignment: Int = align_of[dtype]()
    ](indices: IndexList[rank]) capturing -> None:
        tile_id = indices[0]
        tile_start = tile_id * tile_size
        tile_end = min(tile_start + tile_size, size)
        actual_tile_size = tile_end - tile_start

        fn vectorized_add[
            width: Int
        ](i: Int) unified {read tile_start, read a, read b, mut output}:
            global_idx = tile_start + i
            if global_idx + width <= size:
                a_vec = a.aligned_load[width](Index(global_idx))
                b_vec = b.aligned_load[width](Index(global_idx))
                result = a_vec + b_vec
                output.store[width](Index(global_idx), result)

        # Use vectorize within each tile
        vectorize[simd_width](actual_tile_size, vectorized_add)

    num_tiles = (size + tile_size - 1) // tile_size
    elementwise[
        process_tile_with_vectorize, num_threads_per_tile, target="gpu"
    ](num_tiles, ctx)


Mojo vectorize 심측 뢄석

Mojo의 vectorize ν•¨μˆ˜λŠ” λ‚΄μž₯ μ•ˆμ „μ„±κ³Ό ν•¨κ»˜ μžλ™ 벑터화λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€:

  • λͺ…μ‹œμ  SIMD 폭 λ§€κ°œλ³€μˆ˜: μ‚¬μš©ν•  simd_widthλ₯Ό 직접 μ§€μ •
  • λ‚΄μž₯ 경계 검사: 버퍼 μ˜€λ²„ν”Œλ‘œμš°λ₯Ό μžλ™μœΌλ‘œ λ°©μ§€
  • μžλ™ λ‚˜λ¨Έμ§€ 처리: 남은 μš”μ†Œλ₯Ό μžλ™μœΌλ‘œ 처리
  • 쀑첩 ν•¨μˆ˜ νŒ¨ν„΄: 벑터화 둜직의 κΉ”λ”ν•œ 뢄리

타일 기반 ꡬ성:

tile_start = tile_id * tile_size    # 0, 32, 64, 96, ...
tile_end = min(tile_start + tile_size, size)
actual_tile_size = tile_end - tile_start

μžλ™ 벑터화 λ©”μ»€λ‹ˆμ¦˜:

fn vectorized_add[
  width: Int
](i: Int) unified {read tile_start, read a, read b, mut output}:
    global_idx = tile_start + i
    if global_idx + width <= size:
        # μžλ™ SIMD μ΅œμ ν™”

vectorize의 λ™μž‘ 방식:

  • μžλ™ 청크 λΆ„ν• : actual_tile_sizeλ₯Ό μ§€μ •ν•œ simd_width의 청크둜 λΆ„ν• 
  • λ‚˜λ¨Έμ§€ 처리: 남은 μš”μ†Œλ₯Ό 더 μž‘μ€ 폭으둜 μžλ™ 처리
  • 경계 μ•ˆμ „μ„±: 버퍼 μ˜€λ²„ν”Œλ‘œμš°λ₯Ό μžλ™μœΌλ‘œ λ°©μ§€
  • 루프 관리: 벑터화 루프λ₯Ό μžλ™μœΌλ‘œ 처리

μ‹€ν–‰ μ‹œκ°ν™” (TILE_SIZE=32, SIMD_WIDTH=4):

Tile 0 처리:
  vectorize 호좜 0: μš”μ†Œ [0:4]λ₯Ό SIMD_WIDTH=4둜 처리
  vectorize 호좜 1: μš”μ†Œ [4:8]λ₯Ό SIMD_WIDTH=4둜 처리
  ...
  vectorize 호좜 7: μš”μ†Œ [28:32]λ₯Ό SIMD_WIDTH=4둜 처리
  합계: 8회 μžλ™ SIMD μ—°μ‚°

μ„±λŠ₯ νŠΉμ„±:

  • μŠ€λ ˆλ“œ 수: 32개 μŠ€λ ˆλ“œ (1024 Γ· 32 = 32)
  • μŠ€λ ˆλ“œλ‹Ή μž‘μ—…λŸ‰: 32개 μš”μ†Œ (μžλ™ SIMD 청크 λΆ„ν• )
  • λ©”λͺ¨λ¦¬ νŒ¨ν„΄: μžλ™ 벑터화λ₯Ό κ°–μΆ˜ μž‘μ€ 타일
  • μ˜€λ²„ν—€λ“œ: μ•½κ°„ - μžλ™ μ΅œμ ν™” 및 경계 검사
  • μ•ˆμ „μ„±: λ‚΄μž₯ 경계 검사와 경계 쑰건 처리

μ„±λŠ₯ 비ꡐ와 λͺ¨λ²” 사둀

각 μ ‘κ·Όλ²•μ˜ 선택 κΈ°μ€€

μˆ˜λ™ 벑터화λ₯Ό 선택할 λ•Œ:

  • μ΅œλŒ€ μ„±λŠ₯이 μ€‘μš”ν•œ 경우
  • 예츑 κ°€λŠ₯ν•˜κ³  μ •λ ¬λœ 데이터 νŒ¨ν„΄μ΄ μžˆλŠ” 경우
  • λ©”λͺ¨λ¦¬ 접근에 λŒ€ν•œ μ „λ¬Έκ°€ μˆ˜μ€€μ˜ μ œμ–΄κ°€ ν•„μš”ν•œ 경우
  • μˆ˜λ™μœΌλ‘œ 경계 μ•ˆμ „μ„±μ„ 보μž₯ν•  수 μžˆλŠ” 경우
  • ν•˜λ“œμ›¨μ–΄λ³„ μ΅œμ ν™”κ°€ ν•„μš”ν•œ 경우

Mojo vectorizeλ₯Ό 선택할 λ•Œ:

  • 개발 속도와 μ•ˆμ „μ„±μ΄ μš°μ„ μΈ 경우
  • λΆˆκ·œμΉ™ν•˜κ±°λ‚˜ 동적인 데이터 크기λ₯Ό λ‹€λ£¨λŠ” 경우
  • μˆ˜λ™ 경계 쑰건 관리 λŒ€μ‹  μžλ™ λ‚˜λ¨Έμ§€ 처리λ₯Ό μ›ν•˜λŠ” 경우
  • 경계 검사 λ³΅μž‘λ„κ°€ 였λ₯˜λ₯Ό μœ λ°œν•  수 μžˆλŠ” 경우
  • μˆ˜λ™ 루프 관리보닀 κΉ”λ”ν•œ 벑터화 νŒ¨ν„΄μ„ μ„ ν˜Έν•˜λŠ” 경우

κ³ κΈ‰ μ΅œμ ν™” μΈμ‚¬μ΄νŠΈ

λ©”λͺ¨λ¦¬ λŒ€μ—­ν­ ν™œμš©:

μˆ˜λ™:      8 μŠ€λ ˆλ“œ Γ— 32 SIMD μ—°μ‚° = 총 256회 SIMD μ—°μ‚°
vectorize: 32 μŠ€λ ˆλ“œ Γ— 8 SIMD μ—°μ‚° = 총 256회 SIMD μ—°μ‚°

λ‘˜ λ‹€ λΉ„μŠ·ν•œ 총 μ²˜λ¦¬λŸ‰μ„ λ‹¬μ„±ν•˜μ§€λ§Œ, 병렬성 μ „λž΅μ΄ λ‹€λ¦…λ‹ˆλ‹€.

μΊμ‹œ λ™μž‘:

  • μˆ˜λ™: λŒ€ν˜• 청크가 L1 μΊμ‹œλ₯Ό μ΄ˆκ³Όν•  수 μžˆμ§€λ§Œ, μ™„λ²½ν•œ 순차 μ ‘κ·Ό
  • vectorize: μž‘μ€ 타일이 μΊμ‹œμ— 더 잘 맞고, μžλ™ λ‚˜λ¨Έμ§€ 처리

ν•˜λ“œμ›¨μ–΄ λ§€ν•‘:

  • μˆ˜λ™: μ›Œν”„ ν™œμš©κ³Ό SIMD μœ λ‹› 맀핑에 λŒ€ν•œ 직접 μ œμ–΄
  • vectorize: μžλ™ 루프 및 λ‚˜λ¨Έμ§€ 관리λ₯Ό ν†΅ν•œ κ°„μ†Œν™”λœ 벑터화

λͺ¨λ²” 사둀 μš”μ•½

μˆ˜λ™ 벑터화 λͺ¨λ²” 사둀:

  • 인덱슀 계산을 항상 μ‹ μ€‘ν•˜κ²Œ 검증
  • κ°€λŠ₯ν•˜λ©΄ chunk_size에 컴파일 νƒ€μž„ μƒμˆ˜ μ‚¬μš©
  • μΊμ‹œ μ΅œμ ν™”λ₯Ό μœ„ν•΄ λ©”λͺ¨λ¦¬ μ ‘κ·Ό νŒ¨ν„΄ ν”„λ‘œνŒŒμΌλ§
  • 졜적의 SIMD μ„±λŠ₯을 μœ„ν•œ μ •λ ¬ μš”κ΅¬ 사항 κ³ λ €

Mojo vectorize λͺ¨λ²” 사둀:

  • 데이터와 ν•˜λ“œμ›¨μ–΄μ— μ ν•©ν•œ SIMD 폭 선택
  • λ―Έμ„Έ μ΅œμ ν™”λ³΄λ‹€ μ•Œκ³ λ¦¬μ¦˜μ˜ λͺ…확성에 집쀑
  • κΉ”λ”ν•œ 벑터화 λ‘œμ§μ„ μœ„ν•΄ 쀑첩 νŒŒλΌλ―Έν„° ν•¨μˆ˜ μ‚¬μš©
  • 경계 μ‘°κ±΄μ—λŠ” μžλ™ 경계 검사와 λ‚˜λ¨Έμ§€ 처리 μ‹ λ’°

두 접근법 λͺ¨λ‘ GPU μ„±λŠ₯ μ΅œμ ν™” 도ꡬ λͺ¨μŒμ—μ„œ μœ νš¨ν•œ μ „λž΅μž…λ‹ˆλ‹€. μˆ˜λ™ λ²‘ν„°ν™”λŠ” μ΅œλŒ€ν•œμ˜ μ œμ–΄λ₯Ό, Mojo의 vectorizeλŠ” μ•ˆμ „μ„±κ³Ό μžλ™ λ‚˜λ¨Έμ§€ 처리λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

λ‹€μŒ 단계

μ„Έ κ°€μ§€ κΈ°λ³Έ νŒ¨ν„΄μ„ λͺ¨λ‘ μ΄ν•΄ν–ˆλ‹€λ©΄:

πŸ’‘ 핡심 μš”μ•½: 벑터화 μ „λž΅μ€ μ„±λŠ₯ μš”κ΅¬ 사항에 따라 달리 선택해야 ν•©λ‹ˆλ‹€. μˆ˜λ™ λ²‘ν„°ν™”λŠ” μ΅œλŒ€ν•œμ˜ μ œμ–΄λ₯Ό, Mojo의 vectorize ν•¨μˆ˜λŠ” μ•ˆμ „μ„±κ³Ό μžλ™ λ‚˜λ¨Έμ§€ 처리λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. ꡬ체적인 μ„±λŠ₯ μš”κ΅¬ 사항과 개발 μ œμ•½ 쑰건에 따라 μ„ νƒν•˜μ„Έμš”.