22fd0d2b9d
- CLAUDE.md: add ADR Lifecycle subsection (superseded → docs/history/, immutable numbering, no renumber) - ADR-0011: merge ADR-0018 content as "Address Model: LA" section alongside PA / VA; status notes VA model is currently implemented - ADR-0018 / 0029 / 0031: moved to docs/history/ with status updates (0018 merged into 0011, 0029 superseded by 0032, 0031 absorbed into 0001 rev 2) - ADR-0019: rewrite Context as PE-HBM connectivity decision (self-contained, no LA model framing) - ADR-0019/0020/0021/0023/0025/0027: Status Proposed → Accepted (code verified) and prune Implementation Notes / Affected files / Test strategy / "현재 상태" sub-sections describing pre-impl state - ADR-0024/0026: same migration-flavor cleanup; 0026 also drops D6 Migration and D8 docs-update sub-decisions - ADR-0030: status simplified (blocker ADR-0031 now superseded) - SPEC.md: R10 + §0.2 reflect PA / VA / LA model names - ADR-0008/0012/0013: refresh ADR-0011 subtitle in Links 21 files changed, 553 insertions(+), 1290 deletions(-). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
306 lines
9.8 KiB
Markdown
306 lines
9.8 KiB
Markdown
# ADR-0019: CUBE NOC 내 Per-Channel 및 Aggregated HBM 연결 모델
|
||
|
||
## Status
|
||
|
||
Accepted
|
||
|
||
## Context
|
||
|
||
CUBE 내부 NOC은 각 PE를 HBM에 연결해야 한다. KernBench는 두 가지
|
||
connectivity 모델을 비교 평가할 수 있어야 한다.
|
||
|
||
- **1:1 mode** — PE_DMA가 N개 per-channel router 각각에 별도 link로
|
||
연결되고, 각 router는 hbm_ctrl에 자기 channel link를 가진다.
|
||
Per-channel BW contention을 정확히 모델링.
|
||
N = `hbm_pseudo_channels / pes_per_cube` (= `channels_per_pe`).
|
||
- **n:1 mode** — PE_DMA가 단일 aggregated router를 거쳐 하나의 link로
|
||
hbm_ctrl에 연결. Channel들이 interleaved 된 것으로 가정하고
|
||
aggregate BW만 모델링.
|
||
|
||
두 모드에서 PE당 effective BW는 동일 (= N × per-channel BW);
|
||
connectivity granularity만 다르다.
|
||
|
||
---
|
||
|
||
## Decision
|
||
|
||
### D1. HBM은 PE 라우터에 attach된다
|
||
|
||
현재의 `hbm_ctrl.slice{0-7}` (8개 노드)를 **`hbm_ctrl` 단일 노드**로 통합하고,
|
||
PE가 attach된 라우터에 HBM access point도 함께 attach한다.
|
||
|
||
- n:1 mode: PE의 local HBM 접근은 자기 라우터에서 바로 (switching overhead만, 0 hop)
|
||
- remote PE의 HBM 접근: mesh hop을 거쳐 대상 PE의 라우터에 도달
|
||
- HBM controller 내부의 read/write resource 모델은 유지
|
||
|
||
노드 네이밍 변경:
|
||
|
||
| 현재 | 변경 후 |
|
||
| ---- | ------- |
|
||
| `sip0.cube0.hbm_ctrl.slice0` ~ `slice7` | `sip0.cube0.hbm_ctrl` (단일) |
|
||
|
||
`mesh_gen.py`에서 PE attachment에 `pe{idx}.hbm`을 추가하여,
|
||
builder가 해당 라우터와 hbm_ctrl 간 edge를 생성한다.
|
||
|
||
---
|
||
|
||
### D2. xbar, bridge, 단일 NOC 노드 완전 제거
|
||
|
||
기존 다음 노드 및 관련 edge를 모두 제거한다:
|
||
|
||
- `{cube}.xbar_top`, `{cube}.xbar_bot`
|
||
- `{cube}.bridge.left`, `{cube}.bridge.right`
|
||
- `{cube}.noc` (단일 TwoDMeshNocComponent 노드)
|
||
- `noc_to_xbar`, `xbar_to_noc`, `xbar_to_hbm`, `hbm_to_xbar` 종류의 edge
|
||
- `xbar_to_bridge`, `bridge_to_xbar` 종류의 edge
|
||
- `pe_to_noc`, `noc_to_pe`, `noc_to_pe_cpu` 등 단일 noc 노드 참조 edge
|
||
|
||
이들의 역할은 **cube_mesh.yaml 기반의 명시적 라우터 mesh**가 대체한다.
|
||
기존 `mesh_gen.py`가 생성하는 6×6 라우터 grid의 각 라우터(r0c0, r0c1, ...)를
|
||
별도의 SimPy 노드로 topology graph에 생성하고,
|
||
인접 라우터 간 XY mesh edge로 연결한다.
|
||
|
||
---
|
||
|
||
### D3. 명시적 라우터 mesh (n:1 / 1:1 공통 기반)
|
||
|
||
#### cube_mesh.yaml 기반 라우터 노드
|
||
|
||
`mesh_gen.py`가 생성한 cube_mesh.yaml의 각 non-null 라우터를
|
||
topology graph의 **별도 SimPy 노드**로 생성한다.
|
||
|
||
- 노드 ID: `{cube}.r{row}c{col}` (e.g., `sip0.cube0.r0c0`)
|
||
- kind: `noc_router`, impl: `forwarding_v1`
|
||
- pos_mm: cube_mesh.yaml에서 가져옴
|
||
|
||
기존 cube_mesh.yaml의 attach 정보에 따라 각 라우터에 component를 연결:
|
||
- `pe{p}.dma` → PE_DMA ↔ 라우터 edge
|
||
- `pe{p}.cpu` → PE_CPU ↔ 라우터 edge
|
||
- `pe{p}.hbm` → HBM_CTRL ↔ 라우터 edge (n:1에서 추가)
|
||
- `m_cpu` → M_CPU ↔ 라우터 edge
|
||
- `sram` → SRAM ↔ 라우터 edge
|
||
- `ucie_{dir}.c{i}` → UCIe conn ↔ 라우터 edge
|
||
|
||
라우터 간 XY mesh edge: 인접 라우터 간 bidirectional edge.
|
||
null 라우터(HBM exclusion zone)는 skip.
|
||
|
||
#### 1:1 mode 확장 (나중에 구현)
|
||
|
||
1:1 mode에서는 각 라우터가 N개 channel mini-router로 분화된다.
|
||
per-channel routing과 ChannelSplitter (LA → per-channel PA) 도입이 필요.
|
||
PE당 N개 GEMM engine도 이 시점에 추가.
|
||
|
||
---
|
||
|
||
### D4. cross-PE HBM 접근 (n:1 mode)
|
||
|
||
n:1 mode에서 PE가 다른 PE의 local HBM에 접근하는 경우,
|
||
cube_mesh.yaml의 XY mesh를 통해 대상 PE의 라우터까지 hop한다.
|
||
|
||
예: PE0(r0c0)이 PE2(r1c4)의 HBM에 접근:
|
||
|
||
```text
|
||
PE0.pe_dma → r0c0 → r0c1 → r0c2 → r0c3 → r0c4 → r1c4 → hbm_ctrl
|
||
```
|
||
|
||
Dijkstra router가 mesh에서 최단 경로를 탐색한다.
|
||
|
||
1:1 mode에서의 cross-PE channel 접근은 D3의 1:1 확장 시 정의한다.
|
||
|
||
---
|
||
|
||
### D5. n:1 mode: cube_mesh.yaml 라우터 mesh 사용
|
||
|
||
n:1 mode에서는 별도의 "aggregated router"를 생성하지 않는다.
|
||
기존 cube_mesh.yaml의 라우터 grid가 그 역할을 한다.
|
||
|
||
#### 연결 구조
|
||
|
||
각 PE가 attach된 라우터에 PE_DMA, PE_CPU, HBM이 함께 연결된다:
|
||
|
||
```text
|
||
sip0.cube0.pe0.pe_dma ←→ sip0.cube0.r0c0 (bw: N × channel_bw_gbs)
|
||
sip0.cube0.hbm_ctrl ←→ sip0.cube0.r0c0 (bw: N × channel_bw_gbs)
|
||
```
|
||
|
||
라우터 간 XY mesh edge로 연결. PE의 local HBM 접근은
|
||
자기 라우터에서 바로 (switching overhead만).
|
||
|
||
#### n:1 mode 전체 데이터 경로
|
||
|
||
**local HBM (0 hop):**
|
||
```text
|
||
PE0.pe_dma → r0c0 → hbm_ctrl (switching overhead only)
|
||
```
|
||
|
||
**remote HBM (mesh hops):**
|
||
```text
|
||
PE0.pe_dma → r0c0 → r0c1 → ... → r1c4 → hbm_ctrl
|
||
```
|
||
|
||
**M_CPU DMA:**
|
||
```text
|
||
M_CPU → r2c0 → (mesh hops) → r{x}c{y} → hbm_ctrl
|
||
```
|
||
|
||
---
|
||
|
||
### D6. 모든 트래픽을 동일 router mesh로 통일한다
|
||
|
||
- 모든 memory access (DMA data)와 command (PE_CPU)가 동일 router mesh를 사용한다
|
||
- local access도 별도의 fast path(xbar)를 사용하지 않는다
|
||
- cross-cube (remote) access 경로:
|
||
|
||
```text
|
||
PE_DMA → r{x}c{y} → (mesh hops) → ucie_conn → ucie-{PORT}
|
||
→ [UCIe link] → remote ucie → remote conn → remote r{x}c{y} → hbm_ctrl
|
||
```
|
||
|
||
UCIe 연결은 기존 구조를 유지하되,
|
||
양쪽 endpoint가 xbar 대신 mesh 라우터가 된다.
|
||
|
||
UCIe line 수는 BW 비율로 결정: `ucie_lines_per_side = ceil(ucie_bw / noc_line_bw)`.
|
||
|
||
---
|
||
|
||
### D7. AddressResolver 변경
|
||
|
||
현재 `AddressResolver.resolve()`:
|
||
|
||
```python
|
||
# 현재: HBM offset → pe_slice → "sip{s}.cube{c}.hbm_ctrl.slice{pe_slice}"
|
||
pe_slice = PhysAddr.hbm_pe_id(addr.hbm_offset, self._slice_size_bytes)
|
||
return f"sip{s}.cube{c}.hbm_ctrl.slice{pe_slice}"
|
||
```
|
||
|
||
변경 후:
|
||
|
||
```python
|
||
# 변경: HBM → 단일 endpoint
|
||
return f"sip{s}.cube{c}.hbm_ctrl"
|
||
```
|
||
|
||
pe_slice 계산이 제거된다.
|
||
n:1 mode에서 PE_DMA는 자기 라우터에 attach된 hbm_ctrl에 직접 접근한다.
|
||
|
||
resolver.resolve()는 외부 접근(M_CPU DMA 등) 및 backward compatibility용으로 유지한다.
|
||
|
||
---
|
||
|
||
### D8. topology.yaml 설정 변경
|
||
|
||
#### 추가 설정
|
||
|
||
```yaml
|
||
cube:
|
||
memory_map:
|
||
hbm_mapping_mode: n_to_one # one_to_one | n_to_one
|
||
hbm_pseudo_channels: 64 # 전체 pseudo channel 수
|
||
hbm_channels_per_pe: 8 # PE당 local channel 수 (= pseudo_channels / pes_per_cube)
|
||
hbm_channel_bw_gbs: 32.0 # per-channel bandwidth (GB/s)
|
||
hbm_total_gb_per_cube: 48 # 유지
|
||
```
|
||
|
||
#### 제거 설정
|
||
|
||
```yaml
|
||
# 제거 대상
|
||
links:
|
||
xbar_to_hbm_bw_gbs: 256.0 # → channel_bw_gbs × channels_per_pe로 대체
|
||
xbar_to_hbm_mm: 2.5 # → ch_router_to_hbm_mm으로 대체
|
||
xbar_to_bridge_bw_gbs: 128.0 # → 제거 (bridge 없음)
|
||
xbar_to_bridge_mm: 3.0 # → 제거
|
||
noc_to_xbar_bw_gbs: ... # → 제거
|
||
noc_to_xbar_mm: ... # → 제거
|
||
```
|
||
|
||
#### 추가 link 설정
|
||
|
||
```yaml
|
||
links:
|
||
router_link_bw_gbs: 256.0 # 라우터 간 XY mesh link BW
|
||
router_overhead_ns: 2.0 # 라우터 switching overhead
|
||
pe_to_router_bw_gbs: 256.0 # PE_DMA ↔ 라우터
|
||
hbm_to_router_bw_gbs: 256.0 # HBM ↔ 라우터 (= N × channel_bw)
|
||
```
|
||
|
||
---
|
||
|
||
### D9. 대역폭 수치 정합
|
||
|
||
| 구성 | 값 |
|
||
| ---- | --- |
|
||
| pseudo channels per cube | 64 (파라미터) |
|
||
| PEs per cube | 8 (파라미터) |
|
||
| channels per PE (N) | `pseudo_channels / pes_per_cube` = 8 |
|
||
| per-channel BW | 32 GB/s (파라미터) |
|
||
| per-PE local BW | N × 32 = 256 GB/s |
|
||
| cube total HBM BW | 64 × 32 = 2048 GB/s |
|
||
|
||
두 모드에서 PE당 effective BW는 동일:
|
||
|
||
- 1:1 mode: N개 channel link × channel_bw_gbs = N × 32 = 256 GB/s
|
||
- n:1 mode: 1개 aggregated link = N × channel_bw_gbs = 256 GB/s
|
||
|
||
---
|
||
|
||
## Consequences
|
||
|
||
### Positive
|
||
|
||
- cube_mesh.yaml 기반 라우터 mesh로 물리적 배치를 정확히 반영한다
|
||
- n:1 mode에서 기존 VA 체계를 유지하여 전환 비용이 낮다
|
||
- local / remote / command 트래픽이 동일 mesh로 통일되어 단순하다
|
||
- graph compiler 기반 topology 생성과 잘 맞는다
|
||
- channel 수, PE 수가 모두 파라미터이므로 다양한 구성을 테스트할 수 있다
|
||
- 1:1 mode 확장이 라우터 분화로 자연스럽게 가능하다
|
||
|
||
### Negative
|
||
|
||
- 명시적 라우터 노드로 인해 SimPy 노드 수가 증가한다 (6×6 = 최대 32개 라우터/cube)
|
||
- TwoDMeshNocComponent의 내부 contention 모델을 라우터별 모델로 교체 필요
|
||
|
||
---
|
||
|
||
## Alternatives
|
||
|
||
### A1. 기존 xbar + HBM slice 유지
|
||
|
||
- local/remote 경로가 이원화됨
|
||
- pseudo-channel 단위 모델링 불가
|
||
- 1:1/n:1 mode 전환 불가
|
||
|
||
### A2. per-channel link를 항상 생성하고 n:1에서만 집계
|
||
|
||
- topology 구조가 항상 1:1 크기
|
||
- n:1 semantics를 link aggregation으로 표현하기 복잡
|
||
- router 노드 수 감소 효과 없음
|
||
|
||
### A3. 단계적 전환 (xbar 유지 + NOC 경로 추가)
|
||
|
||
- 호환성은 높으나 두 경로 공존으로 복잡도 증가
|
||
- 최종적으로 xbar 제거가 필요하므로 중간 단계의 가치가 낮음
|
||
|
||
---
|
||
|
||
## Test Requirements
|
||
|
||
- 1:1 mode에서 channel별 link로 request가 전달되는지 확인
|
||
- n:1 mode에서 aggregated link로 request가 전달되는지 확인
|
||
- 두 mode에서 topology가 올바르게 생성되는지 검증:
|
||
- 1:1: `total_ch`개 channel router + per-PE link + horizontal link
|
||
- n:1: `pes_per_cube`개 aggregated router + per-PE link
|
||
- 동일 workload에서 effective BW가 두 모드에서 일관적인지 확인
|
||
- cross-PE 접근 시 horizontal line routing이 동작하는지 확인
|
||
- cross-cube 접근 시 UCIe를 통한 routing이 동작하는지 확인
|
||
- 파라미터 변경 (channels_per_pe = 4, 8, 16 등)에서 topology 생성이 정상인지 확인
|
||
|
||
---
|
||
|
||
## Links
|
||
|
||
- ADR-0011 (LA model) → addressing 측 연동
|
||
- ADR-0017 (Cube NOC 2D Mesh) → 본 ADR이 xbar/bridge 부분을 대체
|
||
- ADR-0004 (Memory Semantics) → BW 모델 재정의
|
||
- ADR-0014 (PE Internal Execution Model) → PE_DMA 경로 변경 영향
|