Files
kernbench2/docs/adr-proposed/ADR-0030-mem-ipcq-physaddr.md
ywkang 687c98086d ADR housekeeping: category prefixes, lifecycle folders, retroactive 0034-0037
Filename + lifecycle:
- ADR rename to ADR-NNNN-<cat>-title.md with 8 3-letter category prefixes
  (dev / mem / lat / prog / algo / par / api / ver). Numbers stay immutable.
- ADR Lifecycle split into 3 folders, documented in CLAUDE.md Part 2:
  docs/adr/ (Accepted), docs/adr-proposed/ (Proposed/Stub/Draft),
  docs/adr-history/ (Superseded/Merged). Status field gains "Draft" for
  retroactive docs pending verification.

Merges (one ADR per topic, no change-history annotations):
- ADR-0017 absorbs ADR-0019 (Cube NOC + per-PE HBM connectivity, 10 D-items)
- ADR-0014 absorbs ADR-0021 (PE pipeline execution model, 8 D-items incl.
  TileToken self-routing and multi-op composite epilogue scope)
- ADR-0023 absorbs docs/ipcq-dma-codesign-hw.md as new "HW Realization
  Notes (Informative)" section (D16-D23 + Open HW Questions). codesign-hw.md
  deleted; ADR-0019/0021 moved to adr-history with one-line stub status

Retroactive documentation (G4 closures, code-verified):
- ADR-0037 forwarding component (TransitComponent: first-flit overhead,
  serial worker, path-based routing, single impl/multiple names)
- ADR-0036 IO_CPU component (target_start_ns global barrier stamping,
  per-cube fan-out, response aggregation)
- ADR-0035 M_CPU & M_CPU.DMA component (3 fan-out paths, DMA Resources,
  target_start_ns passthrough)
- ADR-0034 HBM controller internal design (per-PC state, address-based
  selection, flit-aware per-flit commit, async finalize, command-only
  fallback path)

Content updates:
- ADR-0010 expanded to full CLI surface (run/probe/web), retitled
  "Command Line Interface and Execution Semantics"
- ADR-0007 D2 rewritten to current state; ADR-0015 supersession notes pruned
- ADR-0005 wrapped in Decision header with D1-D5; ADR-0022 metadata
  block replaced with standard Status header
- ADR-0024 trimmed to rank=SIP launcher essentials (D1-D4);
  ADR-0027 cleaned of supersession history
- ADR-0033 D6 cleanup: address-based PC selection moved out of future-work
  (now documented in ADR-0034 D3); related D1/D3 wording realigned
- Cross-references back-filled in 5 ADRs (G3 gaps closed)

Onboarding docs split:
- docs/onboarding/ created
- moved: hw-architecture-overview.md, latency-model.md, di-presentation.md,
  ccl-author-guide{,.en}.md
- references updated in README, ADR-0023{,.en}, src/kernbench/ccl/__init__.py

Source / test / yaml: ADR-NNNN cross-references in docstrings and YAML
comments updated after the merges (ADR-0021->0014 D6, ADR-0019->0017 D8).
No behavior change.

Tooling:
- tools/verify_adr_lang_pairs.py + tests/test_verify_adr_lang_pairs.py
  (ADR EN/KO pair invariant checker)
- .claude/commands/report.md tracked (/report slash command)
- .gitignore: allow .claude/commands/*.md while keeping settings files ignored

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 01:15:55 -07:00

348 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0030: IPCQ Physical Addressing — PhysAddr integration
## Status
Proposed
## Context
### 목표
IPCQ ring buffer의 주소 체계를 ADR-0023의 **synthetic parallel namespace**
(`_IPCQ_BASE = 1<<60`)에서 **ADR-0001의 PhysAddr**로 이관한다. Routing /
allocator / MemoryStore의 정합성을 회복하고, buffer_kind (tcm/hbm/sram)별
physical backing을 구조적 좌표로 표현한다.
### 현재 상태 (ADR-0023 D2.5)
`src/kernbench/ccl/install.py:52-56`:
```python
_IPCQ_BASE = 1 << 60
def _ipcq_base_for_pe(sip, cube, pe):
return _IPCQ_BASE | (sip << 40) | (cube << 32) | (pe << 24)
def rx_base(s, c, p, d):
return _ipcq_base_for_pe(s, c, p) + direction_idx[d] * bytes_per_direction
```
- **bit 60** 사용 → ADR-0001의 51-bit PhysAddr 공간 밖 (`MAX_51 = (1 << 51) - 1`)
- `PhysAddr.decode(addr)``PhysAddrError("addr must be a 51-bit value")`
- `IpcqEndpoint.rx_base_pa: int` — 타입이 raw int, 구조 없음
- `buffer_kind` (tcm/hbm/sram)와 synthetic 주소의 관계가 coupling 없음
- Allocator (`PEMemAllocator`) 우회 — synthetic unique id per (sip, cube, pe,
direction). 진짜 physical allocation이 아님
ADR-0023 D2.5 원문:
> This bypasses the topology's address resolver / PhysAddr encoding and
> treats IPCQ buffers as a separate, parallel address namespace. Real PA
> encoding can be plugged in later without changing the rest of the design.
"later"가 이 ADR.
### 왜 지금 다루는가
- ADR-0025 (direction addressing)은 주소-기반 매칭으로 전환. 주소가 correctness에
직접 기여 → 주소 체계가 설계 관점에서 더 중요해짐
- ADR-0001의 "Routing consumes decoded domains, not raw bit-fields" 계약 위반
지속 → 기술 부채
- Routing fabric (cube_noc / UCIe)은 PhysAddr.decode()로 destination을 정함.
IPCQ의 synthetic 주소가 fabric routing에서 실제로 어떻게 처리되는지 **검증되지
않음** (별도 경로로 배달되는 것으로 추정)
- TCM / HBM / SRAM의 실제 memory layout과 IPCQ ring buffer 위치가 **disjoint**
→ allocator가 IPCQ 영역을 모르므로 실수로 겹칠 가능성 (현재는 bit 60로 완전
분리되어 문제 없지만 설계 원칙상 건강하지 않음)
### 풀어야 할 문제
1. **IPCQ ring buffer의 PhysAddr 표현**: buffer_kind별로 어떤 PhysAddr factory를
쓸지.
2. **PhysAddr 공간 부족 가능성**: 51-bit 공간에 IPCQ 버퍼를 담을 여유가 있는지.
3. **Allocator 통합**: `PEMemAllocator`에 IPCQ buffer 영역 예약 기능 추가, 또는
기존 pool에서 정상 allocation.
4. **MemoryStore space naming 정리**: 현재는 `{"tcm", "hbm", "sram"}` 문자열로
space 구분. IPCQ buffer도 이 space에 속하면 일반 data와 주소 겹침 방지 필요.
5. **Routing fabric 통합**: PhysAddr 기반 routing이 IPCQ 토큰을 올바른 SIP의
올바른 메모리로 배달.
6. **ADR-0025와의 정합**: 주소-기반 매칭이 PhysAddr에서도 동일하게 작동.
---
## Decision
### D1. IPCQ ring buffer = PhysAddr factory 사용
`buffer_kind`가 해당하는 PhysAddr factory를 호출:
| buffer_kind | PhysAddr factory | 필요한 인자 |
|---|---|---|
| `tcm` | `PhysAddr.pe_tcm_addr(rack_id, sip_id, cube_id, pe_id, tcm_offset)` | PE-local TCM |
| `hbm` | `PhysAddr.pe_hbm_addr(rack_id, sip_id, cube_id, pe_id, pe_local_hbm_offset, slice_size_bytes)` | PE-local HBM slice |
| `sram` | `PhysAddr.cube_sram_addr(rack_id, sip_id, cube_id, sram_offset)` | Cube-shared SRAM |
Install plan builder (`build_install_plans` in ADR-0024)가 각 PE의 rx_base를
계산할 때:
```python
# ADR-0030 후 install_plan.py (pseudocode)
def _compute_rx_base(sip, cube, pe, direction_idx, buffer_kind, n_slots, slot_size,
allocator_pool, rack_id=0) -> PhysAddr:
bytes_per_direction = n_slots * slot_size
offset = direction_idx * bytes_per_direction
if buffer_kind == "tcm":
# TCM base (per-PE) + direction offset
tcm_base = allocator_pool.reserve_pe_tcm_for_ipcq(sip, cube, pe,
total_bytes=N_DIR * bytes_per_direction)
return PhysAddr.pe_tcm_addr(rack_id=rack_id, sip_id=sip, cube_id=cube,
pe_id=pe, tcm_offset=tcm_base + offset)
elif buffer_kind == "hbm":
hbm_base = allocator_pool.reserve_pe_hbm_for_ipcq(sip, cube, pe,
total_bytes=...)
return PhysAddr.pe_hbm_addr(rack_id=rack_id, sip_id=sip, cube_id=cube,
pe_id=pe, pe_local_hbm_offset=hbm_base + offset,
slice_size_bytes=slice_size)
elif buffer_kind == "sram":
sram_base = allocator_pool.reserve_cube_sram_for_ipcq(sip, cube,
total_bytes=...)
return PhysAddr.cube_sram_addr(rack_id=rack_id, sip_id=sip, cube_id=cube,
sram_offset=sram_base + offset)
```
`IpcqEndpoint.rx_base_pa`의 타입을 `PhysAddr` (또는 encoded `int`)로 변경:
```python
@dataclass(frozen=True)
class IpcqEndpoint:
sip: int
cube: int
pe: int
buffer_kind: str
rx_base_pa: int # PhysAddr.encode() 결과 (51-bit)
rx_base_va: int
n_slots: int
slot_size: int
```
타입은 int 유지 (encoded form), 단 **반드시 PhysAddr.decode()로 복원 가능**한
값임을 invariant으로 둔다. 디코더 호출자는 `PhysAddr.decode(rx_base_pa)`
구조적 좌표 획득.
### D2. Allocator 확장 — IPCQ 예약 API
`PEMemAllocator`에 IPCQ 전용 예약 기능 추가:
```python
class PEMemAllocator:
def reserve_ipcq_tcm(self, total_bytes: int) -> int:
"""Reserve TCM region for IPCQ ring buffers at this PE.
Returns tcm_offset (to be used in PhysAddr.pe_tcm_addr)."""
# TCM에서 `total_bytes` 연속 영역 예약.
# Tensor allocation과 겹치지 않도록.
def reserve_ipcq_hbm(self, total_bytes: int) -> int: ...
# cube-level allocator도 유사
```
Install plan 빌더가 각 PE allocator에서 예약. 예약 결과(offset)를 PhysAddr
factory에 전달.
**기존 `_ipcq_base_for_pe` / `_IPCQ_BASE` 제거**.
### D3. MemoryStore space 통합
현재 `MemoryStore``{space_name: {addr: ndarray}}` 구조. IPCQ buffer는 일반
tensor 데이터와 같은 space (tcm/hbm/sram)를 공유하게 됨. 주소 유일성은 ADR-0001의
PhysAddr 계층 보장.
Backward compatibility: 기존 IPCQ address (synthetic)을 쓰는 code path는
**제거**하고, 모두 PhysAddr.encode() 결과만 사용. 이 자체는 API 변경이 아니라
값 변경.
### D4. Routing fabric 통합
IPCQ DMA write (`IpcqDmaToken``src_addr → dst_addr`)이 PhysAddr encoding을
사용하므로 **routing fabric이 `PhysAddr.decode(dst_addr)`로 destination
SIP/cube/PE를 정확히 찾을 수 있음**. Fabric routing 로직 변경 없음 (기존에도
PhysAddr.decode를 쓰는 것으로 추정).
**검증 필요**: 현재 fabric이 bit 60 synthetic 주소를 어떻게 라우팅하는지 확인.
별도 경로가 있다면 제거, PhysAddr 경로로 통합.
### D5. ADR-0025와의 정합
ADR-0025의 주소-기반 매칭 (dst_addr로 direction 식별)은 PhysAddr.encode()
결과를 비교하는 것으로 자연스럽게 호환. 변경 없음.
다만 debug / diagnostic 향상 가능:
```python
# pointer_dump 등에서
print(f"E: rx_base_pa={PhysAddr.decode(qp.peer.rx_base_pa)}")
# 출력 예: PhysAddr(sip=1, cube=0, pe=0, kind="pe_resource", unit_type=PE, ...)
```
이전 synthetic 주소는 decode 불가 → diagnostic 질 저하. PhysAddr 전환으로 개선.
### D6. ADR-0023 D2.5 amendment
ADR-0023의 "bypasses PhysAddr encoding" 문구를 **Accepted fallback → now
replaced by ADR-0030**으로 수정. 본 ADR이 적용되면 ADR-0023 D2.5의 "Real PA
encoding can be plugged in later" 약속이 이행된 것.
---
## Migration strategy
단계적 전환 (한 PR로 하지 않는다):
### Phase 1: PhysAddr 공간 재검토
- 51-bit PhysAddr 공간에 IPCQ ring buffer가 실제로 들어갈 수 있는지 확인.
- 각 buffer_kind (tcm/hbm/sram)별 factory가 제공하는 `local_offset` 범위가
IPCQ 요구 (4 direction × n_slots × slot_size)를 수용 가능한지.
- 부족하면 PhysAddr layout 자체 확장 (ADR-0001 amendment 별도 필요).
### Phase 2: Allocator API 확장
- `PEMemAllocator.reserve_ipcq_*` 메소드 추가.
- 기존 tensor allocation과 영역 충돌 방지.
### Phase 3: Install plan builder 전환
- `_ipcq_base_for_pe` 제거, PhysAddr factory 호출로 대체.
- `IpcqEndpoint.rx_base_pa`가 PhysAddr.encode() 결과 (51-bit).
### Phase 4: Routing fabric 검증
- IPCQ DMA token이 fabric 정상 경로로 배달되는지 확인.
- 별도 fast-path가 있다면 제거, 통합.
### Phase 5: MemoryStore space 검증
- IPCQ buffer 주소가 기존 tensor 주소와 겹치지 않는지.
- Allocator 레벨에서 이미 예약했으므로 정상적으로 분리되어야 함.
### Phase 6: ADR-0023 D2.5 업데이트 + 기존 sideband path 제거 (완료)
---
## Dependencies
- **ADR-0031** (PhysAddr PE-resource extension) — **Blocker**: PhysAddr가 PE
resource (특히 IPCQ ring buffer)를 충분히 표현할 수 있도록 schema 확장이
선행되어야 함. 본 ADR은 ADR-0031 완료 후에만 실행 가능.
- **ADR-0001** (PhysAddr layout): 본 ADR의 기반. 51-bit 공간 / factory API의
ADR-0031 확장본을 사용.
- **ADR-0023** (IPCQ protocol): 본 ADR은 ADR-0023 D2.5의 "later" 약속 이행.
D9 piggyback / credit return 프로토콜 자체는 불변.
- **ADR-0024** (launcher + install_plan.py): `build_install_plans`가 PhysAddr
factory를 호출하게 됨.
- **ADR-0025** (direction addressing): 주소-기반 매칭이 PhysAddr에서도 동일하게
작동. 변경 없음.
---
## Non-goals
- **ADR-0001 PhysAddr layout 자체 변경**: 51-bit 공간과 segment 구조는 유지.
부족 시 별도 ADR.
- **IPCQ protocol semantic 변경**: ADR-0023 D9 piggyback 등 프로토콜 로직 유지.
- **Allocator 전반 재설계**: IPCQ 예약 API 추가만.
---
## Open questions
### 🔴 Critical — Migration 전 반드시 검증
- **PhysAddr 51-bit 공간에 IPCQ 버퍼가 실제로 들어가는가**: 각 PE의 TCM
영역에서 `4 direction × n_slots (default 4) × slot_size (default 4KB)` =
64KB가 PE TCM 공간에 수용 가능. TCM size (e.g., 16MB) 대비 충분. HBM도 여유
많음. SRAM은 cube 공유라 direction × PE 곱이 있음 — 별도 검증 필요.
- **Routing fabric의 현재 IPCQ 주소 처리**: 현재 synthetic 주소가 fabric에서
어떻게 routing되는지 trace 필요. `PhysAddr.decode()`로 판독 불가한 값이
fabric에서 정상 배달된다면 어떤 경로를 쓰는지 조사.
### 🟡 Nice-to-have
- **IPCQ 전용 kind / sub_offset 인코딩**: `UnitType.PE`의 sub_offset 공간을
IPCQ와 공유. 충돌 방지를 위해 IPCQ 전용 sub-space 정의할지 여부.
- **Debug tool**: `pointer_dump`를 PhysAddr 포매팅으로 개선.
---
## Test strategy
### T1. PhysAddr round-trip
`tests/test_ipcq_physaddr.py` (new):
- `PhysAddr.pe_tcm_addr(...)` → encode → decode → 동일 필드 복원
- TCM / HBM / SRAM 각 factory에 대해
### T2. Allocator 예약
`tests/test_ipcq_alloc.py` (new):
- `PEMemAllocator.reserve_ipcq_tcm` → 반환된 offset이 valid TCM 영역
- 중복 예약 → 에러 또는 non-overlapping offset
- Tensor allocation과 충돌 없음
### T3. Install plan PhysAddr integration
`tests/test_ccl_install_plan.py` (확장):
- `build_install_plans` 결과의 `rx_base_pa`가 PhysAddr.decode() 가능
- Decoded 좌표가 plan의 (sip, cube, pe)와 일치
- I3.1 invariant (ADR-0025 D6) — rx_base range disjointness가 PhysAddr에서도 성립
### T4. Routing — IPCQ DMA fabric traversal
`tests/test_ipcq_routing.py` (new):
- Cross-SIP IPCQ send → fabric이 `PhysAddr.decode(dst_addr)`로 destination SIP
정확히 판단 → 올바른 MemoryStore에 write
- UCIe 경로 / cube_noc 경로 모두 검증
### T5. 회귀
- 기존 IPCQ E2E 테스트 (ring, mesh, tree) 모두 통과
- ADR-0024, ADR-0025 통합 테스트 통과
---
## Consequences
### Positive
- **ADR-0001 정합성 회복**: routing과 addressing이 단일 체계.
- **buffer_kind 명확**: TCM/HBM/SRAM이 구조적 좌표로 구분.
- **Debug 향상**: PhysAddr.decode()로 사람이 읽을 수 있는 좌표.
- **Allocator 통합**: IPCQ 영역이 정상 예약 → tensor와의 충돌 리스크 사전 차단.
- **Fabric routing 일원화**: 별도 경로 없이 기존 PhysAddr-based routing 재활용.
### Negative
- **Migration 복잡도**: 6 Phase 단계적 전환 필요. 각 Phase마다 regression 리스크.
- **PhysAddr 공간 검증 부담**: Phase 1에서 TCM/HBM/SRAM 공간이 IPCQ 요구를
수용하는지 실측 필요.
- **Routing fabric 검증**: 현재 fabric이 synthetic 주소를 어떻게 처리하는지
조사 필요.
### Neutral
- IPCQ protocol semantic (ADR-0023 D9 등) 불변.
- ADR-0025의 direction addressing 로직 불변.
---
## Affected files
| File | Change |
|------|--------|
| `src/kernbench/ccl/install.py` | `_IPCQ_BASE`, `_ipcq_base_for_pe` 제거 |
| `src/kernbench/ccl/install_plan.py` (ADR-0024) | D1: PhysAddr factory 호출로 rx_base 계산 |
| `src/kernbench/policy/address/allocator.py` (or similar) | D2: IPCQ 예약 API (`reserve_ipcq_tcm` 등) |
| `src/kernbench/common/ipcq_types.py` | D1: `IpcqEndpoint.rx_base_pa` 문서화 — PhysAddr.encode 결과 |
| `src/kernbench/sim_engine/memory_store.py` | D3: IPCQ buffer가 기존 space와 공유되는지 검증 |
| `src/kernbench/sim_engine/engine.py` | D4: IPCQ token routing이 PhysAddr-based fabric 경로 사용 |
| `src/kernbench/ccl/diagnostics.py` | D5: pointer_dump를 PhysAddr 포매팅으로 개선 |
| `docs/adr/ADR-0023-dev-ipcq-pe-collective.md` | D6: D2.5 amendment note |
| `tests/test_ipcq_physaddr.py` (new) | T1 |
| `tests/test_ipcq_alloc.py` (new) | T2 |
| `tests/test_ccl_install_plan.py` | T3 확장 |
| `tests/test_ipcq_routing.py` (new) | T4 |