안녕하세요. GEMM 커널을 구현하다 보니 추가적인 궁금증이 생겨서 질문드립니다.
RNGD에서 일반 row-major GEMM 입력을 여러 slice로 배치하는 과정에서 TDMA 비용이 크게 늘어나는 현상을 확인했습니다. 단순한 연속 HBM→DM 복사는 문서에 설명된 startup latency 범위로 보이지만, compact source를 여러 slice로 broadcast하는 mapping에서는 source가 작아질수록 cycle이 오히려 증가하거나 결과가 틀리는 경우가 있었습니다.
- DMA Engine: DMA Engine - Programming Tensor Contraction Processors
- Memory Performance: Memory Performance - Programming Tensor Contraction Processors
## 환경
```text
Host: Ubuntu, Linux 6.8.0-124-generic, x86_64
Device: RNGD npu5
Device firmware reported by furiosa-smi: 2026.2.0 (a5db283)
Installed furiosa-driver-rngd: 2026.3.0
Installed furiosa-firmware-image-rngd: 2026.3.0
rustc: 1.97.0-nightly (2026-04-30), selected by nightly-2026-05-01
furiosa-opt-std: 0.4.0
```
## 최소 재현
모든 kernel은 HBM 입력을 같은 32 KiB DM tensor로 옮긴 뒤, correctness 확인을 위해 같은 packed HBM layout으로 다시 저장합니다.
```rust
axes![ProbePe = 8, ProbeLocalSlice = 64, ProbeValue = 32];
type ProbeCluster = m![ProbePe / 4];
type ProbeSlice = m![ProbePe % 4, ProbeLocalSlice];
type ProbeElement = m![ProbeValue];
type FullLayout = m![ProbePe, ProbeLocalSlice, ProbeValue];
type CompactF2Layout = m![ProbePe, ProbeLocalSlice / 2, ProbeValue];
type CompactF8Layout = m![ProbePe, ProbeLocalSlice / 8, ProbeValue];
type CompactF64Layout = m![ProbePe, ProbeLocalSlice / 64, ProbeValue];
let loaded: DmTensor<bf16, m![1], ProbeCluster, ProbeSlice, ProbeElement> =
input.to_dm_at(&mut ctx.tdma, 0);
loaded.to_hbm(&mut ctx.tdma)
```
`CompactF2`, `CompactF8`, `CompactF64`의 기대 결과는 각 source group을 각각 2개, 8개, 64개 local slice에 반복한 값입니다.
컴파일 명령:
```bash
FURIOSA_OPT_OUT_DIR=/tmp/tdma-f64 \
RUSTFLAGS=‘–cfg=feature=“tdma-read-probes”’ \
cargo furiosa-opt compile rngd_tdma_compact_f64 \
–exact -p rngd-bf16-matmul \
–dump-visa /tmp/tdma-f64.visa \
–dump-schedule /tmp/tdma-f64.schedule.json \
–dump-summary /tmp/tdma-f64-summary
```
다른 variant도 kernel 이름만 바꿔 같은 방식으로 컴파일했습니다.
## 결과
| HBM→DM mapping | HBM source | DM destination | DmaLoad | DmaStore | 결과 |
|—|—:|—:|—:|—:|—|
| contiguous | 32 KiB | 32 KiB | 707 cycles | 8,457 cycles | 정확 |
| compact ×2 | 16 KiB | 32 KiB | 702 cycles | 8,457 cycles | 8,191개 불일치 |
| compact ×8 | 4 KiB | 32 KiB | 733 cycles | 8,457 cycles | 14,329개 불일치 |
| compact ×64 | 512 B | 32 KiB | 5,020 cycles | 8,457 cycles | 정확 |
| prepacked | 32 KiB | 32 KiB | 707 cycles | 8,457 cycles | 정확 |
Compiler cycle은 현재 0.4 toolchain에서 다시 생성했습니다. Correctness와 host wall은 같은 환경의 물리 `npu5`에서 측정했습니다. Host wall median은 129.002–152.733 µs였지만, 이 값에는 kernel launch와 runtime synchronization이 포함되어 있으므로 TDMA engine 시간으로 해석하지 않았습니다.
32 KiB contiguous load가 707 cycles인 것은 Book에 설명된 command당 약 500-cycle startup latency를 고려하면 특별히 이상하지 않아 보입니다. 확인이 필요한 부분은 세 가지입니다.
1. 512 B source를 32 KiB DM으로 배치하는 compact ×64 load가 contiguous보다 7.10배 긴 5,020 cycles입니다.
2. compact ×2와 ×8은 compiler가 오류 없이 EDF/vISA를 생성하지만 물리 NPU 결과가 틀립니다. 반면 같은 방식의 compact ×64는 정확합니다.
3. 모든 variant에서 32 KiB DM→HBM store가 8,457 cycles로 동일하며, contiguous HBM→DM load보다 약 12배 깁니다.
compact ×64의 LIR에는 `DmaLoad` 한 개가 생성됩니다. Source 쪽 반복 축의 stride는 0이고 destination은 64개 slice로 전개됩니다. Schedule만으로는 5,020 cycles가 하나의 command 내부 직렬화 때문인지, 내부 command 분할이나 HBM/DMN interleaving 문제 때문인지 확인하기 어렵습니다.
실제 4K GEMM에서도 비슷한 결과가 나왔습니다. Compact 입력 variant의 compiler estimated I/O는 203,085 cycles, prepacked variant는 58,262 cycles였습니다. Prepacked variant가 compiler 보고 기준 DRAM data를 16.25배 더 사용했는데도 I/O estimate는 compact의 28.7%였습니다. 출력도 일반 row-major store는 145,022 cycles였지만 tiled packed store는 2,167 cycles, reducer packed store는 1,304 cycles였습니다.
## 확인 부탁드리는 내용
1. `ProbeLocalSlice / N` 형태의 HBM mapping을 전체 `ProbeLocalSlice` DM mapping으로 옮기는 것이 지원되는 broadcast 표현인지 확인 부탁드립니다.
2. 지원되는 표현이라면 compact ×2와 ×8이 compile-time 진단 없이 잘못된 값을 만드는 이유를 확인해 주실 수 있을까요?
3. compact ×64의 5,020-cycle DmaLoad는 기대되는 비용인가요? 한 개의 LIR `DmaCommand`가 내부적으로 어떻게 분할되고 직렬화되는지 확인하는 방법도 알려주시면 감사하겠습니다.
4. 32 KiB DmaStore의 8,457 cycles는 64-byte packet에 대한 HBM partial-write/RMW 비용 때문인가요? Compiler가 연속 packet을 256-byte 단위로 합치도록 mapping이나 stream을 지정하는 권장 방법이 있다면 안내 부탁드립니다.
5. Compiler artifact에서 실제 packet size, DMA command 수, homogeneous/heterogeneous aggregate 여부, HBM channel 및 stack 사용, row conflict, RMW 횟수를 확인하는 방법이 있을까요?
6. 일반 row-major GEMM 입력과 출력을 별도 prepacking 없이 효율적으로 HBM↔DM에 배치하는 권장 mapping 예제가 있다면 공유 부탁드립니다.
필요하시면 최소 재현 프로젝트를 비롯해 EDF, vISA, LIR, schedule JSON, 물리 NPU 측정 결과 JSON을 제공하겠습니다.