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

14 KiB
Raw Permalink Blame History

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:

_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를 계산할 때:

# 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)로 변경:

@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 전용 예약 기능 추가:

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 (IpcqDmaTokensrc_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 향상 가능:

# 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