[furiosa-opt v0.9.0]# VE sweep cost: two-input sweeps are ~10× a constant-operand sweep, and the compiler schedule models them 2~3× too short

Furiosa Opt 0.9.0, RNGD 1 chip. 재현 크레이트를 첨부합니다(`rngd-ve-sweep-repro.tar.gz`).

지난번 알려 주신 `FURIOSA_OPT_PROFILE=trace`로 커스텀 커널을 명령 단위로 보니, VE sweep 하나의 시간이 operand 형태에 따라 크게 달랐습니다. 특히 두 텐서를 번갈아 읽는 sweep과 plane 크기 VRF operand sweep이 예상보다 훨씬 비쌌고, compiler schedule은 이 둘을 실제의 1/2~1/3로 잡아서 schedule만 보고 최적화 방향을 정하면 반대로 가는 경우가 있었습니다.

## 측정

같은 sweep을 1번 하는 커널과 33번 이어 하는 커널을 각각 이어 launch하고, host launch wall 중앙값의 차이 / 32를 sweep 하나의 시간으로 썼습니다(warmup 3, 50회). 원소는 i32, 원소 수는 slice당 값이고 연산은 모두 덧셈 하나입니다.

| sweep | N = 1K | N = 8K |

| — | — | — |

| 한 텐서, 상수 operand(8-lane packet) | 0.26 µs | 0.78 µs |

| 두 텐서 번갈아 읽기(`begin_interleaved`) | 1.10 µs | 7.39 µs |

| 한 텐서, 데이터와 같은 크기의 VRF operand(4 KiB, 한 번 올려 재사용) | 0.66 µs | — |

trace의 명령 span으로 봐도 같은 값이 나옵니다(이어 도는 명령에서 1~3% 안).

- 두 텐서 sweep은 읽는 데이터가 2배인데 시간은 8K에서 9.5배입니다.

- VRF operand sweep은 상수 operand sweep의 2.5배입니다. 그런데 같은 VRF operand 덧셈을 contraction 출력의 VE 단계에 붙이면(출력 2,048개) contraction 명령이 1.59 → 1.62 µs로 거의 늘지 않습니다.

- 4 KiB를 VRF에 올리는 StoVrf 하나가 trace에서 0.68~0.73 µs입니다. 바로 앞 sweep 결과를 올려 다음 sweep의 operand로 쓰면 Main이 이만큼 기다립니다.

- compiler schedule(1 cycle = 1 ns)에서는 두 텐서 sweep 8K가 2.33 µs, VRF operand sweep 1K가 0.29 µs로, 실측의 1/3, 1/2 정도입니다.

## 질문

1. 두 텐서 sweep이 한 텐서 sweep의 약 10배(8K)인 것이 정상인지 궁금합니다. 원인이 DM 읽기 방식(두 텐서를 번갈아 읽을 때의 bank 충돌 등)인지, 두 입력의 배치(layout, packet, DM 위치)를 바꿔 줄일 수 있는지 알고 싶습니다.

2. 데이터 크기 VRF operand sweep이 따로 내면 상수 operand의 2.5배인데 contraction 출력 단계에 붙이면 거의 공짜인 이유가 무엇인지, 따로 낼 때도 빠르게 하는 방법이 있는지 궁금합니다.

3. StoVrf로 4 KiB를 올리는 데 0.7 µs(약 6 GB/s/slice)가 드는 것이 VRF 쓰기 대역폭의 한계인지, 더 빠르게 올리는 방법(크기, layout, 나눠 올리기)이 있는지 궁금합니다.

4. compiler schedule이 두 텐서 sweep과 VRF operand sweep을 짧게 잡는 것이 알려진 차이인지, 앞으로 cost model이 보정될 예정인지 궁금합니다.