adr: add ADR-0050-0053 — close /report's second-pass G4 candidates
Documents four cross-cutting surfaces one layer deeper than the prior G4 batch: - 0050 par-ccl-algorithm-module-contract: how to author a new CCL algorithm in src/kernbench/ccl/algorithms/. Pairs with ADR-0045's bench-module contract. Pins the four required public symbols (kernel, kernel_args, TOPO_NAME_TO_KIND constants, kernel alias), the 9 + tl standardized kernel signature, the kernel_args tuple format, sip_topo_kind dispatch, and the ccl.yaml entry workflow. - 0051 lat-routing-helper-api: every public method of AddressResolver (resolve, find_m_cpu, find_pcie_ep, find_io_cpu, find_all_pcie_eps) and PathRouter (find_path, find_path_with_distance, find_mcpu_dma_path, find_memory_path, find_node_path + 2 shims). Pins the four adjacency graphs (_adj_all / _adj / _adj_mcpu_dma / _adj_local) and the edge-kind exclusion sets they use, plus the single-owner naming convention. - 0052 dev-oplog-memory-store-schemas: OpRecord's 7 fields, the per-op_name params matrix (dma_read, dma_write, gemm_*, math, math reduction, composite_gemm, ipcq_copy, unknown), snapshot timing rules (math = all inputs, dma_write = HBM-only — ADR-0027 race avoidance), TileToken stage_type capture, and MemoryStore's (space, addr) two-level dict with reference-store semantics. - 0053 dev-topology-builder-algorithms: the 6-stage compile pipeline, cube_mesh.yaml's source_hash cache and its 5 input fields, the cube NoC auto-layout algorithm (row/col placement, HBM exclusion zone, PE/M_CPU/SRAM attachment via nearest-router, UCIe N/S/E/W distribution), the node naming convention (single-owner with router.py), the edge-kind catalog, the 4 view projections, and a table of spec-field changes vs mesh regeneration. Bilingual pair verifier passes for all four EN/KO pairs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
# ADR-0053: Topology Builder + Visualizer Algorithms
|
||||
|
||||
## Status
|
||||
|
||||
Accepted (2026-05-22).
|
||||
|
||||
`topology/builder.py`, `topology/mesh_gen.py`, `topology/visualizer.py` 가
|
||||
함께 수행하는 토폴로지 컴파일·시각화 파이프라인의 핵심 알고리즘 선택
|
||||
(placement-driven router attachment, mesh auto-layout, source_hash 캐시,
|
||||
view projection, SVG rendering) 을 명시한다. ADR-0006 가 topology
|
||||
compilation 의 high-level intent (compiled topology, distance extraction,
|
||||
automatic diagram generation) 를 정의하나, **builder 가 실제로 어떤
|
||||
알고리즘을 사용하는지** 는 코드 grep 으로만 확인 가능했다.
|
||||
|
||||
## First action (제일 처음에 하는 일)
|
||||
|
||||
`resolve_topology(path_str)` 가 호출되면 다음 4 단계가 순서대로 일어난다:
|
||||
|
||||
1. **경로 검증** (`builder.py::resolve_topology`):
|
||||
`Path(path_str).expanduser().resolve()`, 존재 확인, file 여부 확인.
|
||||
실패 시 `FileNotFoundError` 또는 `ValueError`.
|
||||
2. **YAML 파싱** (`_read_spec`): `yaml.safe_load`. parse error 면 line/
|
||||
column 정보 포함한 `ValueError`. dict 가 아니면 reject.
|
||||
3. **mesh 자동 생성** (`mesh_gen.ensure_mesh_file`): topology yaml 과
|
||||
같은 디렉터리에 `cube_mesh.yaml` 을 만들거나 (캐시 invalid 시) 재사용
|
||||
(캐시 hit 시). 이 단계가 cube NoC 의 라우터 grid 와 부착 정보를 결정.
|
||||
4. **graph 컴파일** (`_compile_graph`): system → IO chiplets → cubes →
|
||||
inter-cube edges → IO↔cube edges → system↔IO edges 순으로 nodes/edges
|
||||
를 누적, 그 다음 4 개의 view projection (system, sip, cube, pe) 을
|
||||
생성하여 `TopologyGraph` 로 묶음.
|
||||
|
||||
즉, **topology compile 의 첫 일은 "topology.yaml 을 dict 로 읽고, 동일
|
||||
디렉터리에 cube_mesh.yaml 을 생성/검증한 뒤, system→sip→cube→pe 순으로
|
||||
flat graph + 4-view projection 을 만드는 것"** 이다.
|
||||
|
||||
## Context
|
||||
|
||||
`topology/` 패키지의 책임:
|
||||
|
||||
- **builder.py** (1207 줄): topology.yaml 을 받아 `TopologyGraph` (nodes
|
||||
+ edges + 4 view projections) 를 컴파일.
|
||||
- **mesh_gen.py** (305 줄): cube NoC 의 라우터 grid 와 PE/UCIe/M_CPU/SRAM
|
||||
부착 위치를 자동 결정하여 `cube_mesh.yaml` 로 캐시.
|
||||
- **visualizer.py** (887 줄): `TopologyGraph` 로부터 SVG 다이어그램 4종
|
||||
(system / sip / cube / pe) 을 생성.
|
||||
|
||||
ADR-0006 가 "topology compilation 의 결과는 distance metadata 와 diagram
|
||||
generation 의 single source" 라는 high-level 결정을 정의하나, 구체 알고리즘
|
||||
(예: placement-driven nearest-router attachment, HBM 제외 zone 산출,
|
||||
source_hash 의 어떤 필드가 invalidation 을 트리거하는가) 은 ADR 에 없다.
|
||||
|
||||
특히 다음 결정들이 ADR-level 에 부재:
|
||||
|
||||
- 왜 mesh_gen 이 별도 파일 (`cube_mesh.yaml`) 로 캐시되는가?
|
||||
- source_hash 가 어떤 필드를 포함하며, 어떤 변경이 재생성을 강제하는가?
|
||||
- placement coordinate 가 cube 좌표가 아닌 mm 단위인 이유?
|
||||
- HBM zone 제외와 UCIe N/S/E/W 분배가 mesh 안에서 어떻게 결정되는가?
|
||||
- view projection 4 개 (system/sip/cube/pe) 의 추상화 레벨 차이?
|
||||
|
||||
이 ADR 이 이 결정들을 한 곳에 정리한다.
|
||||
|
||||
## Decision
|
||||
|
||||
### D1. compile 파이프라인 — 6 단계
|
||||
|
||||
`_compile_graph(spec)`:
|
||||
|
||||
1. **시스템 노드 생성** (`_instantiate_system`): `fabric.switch0`, host CPU
|
||||
등 system-level 노드 추가.
|
||||
2. **per-SIP loop** (`for sip_id in range(system.sips.count)`):
|
||||
- **IO chiplets** (`_instantiate_io_chiplets`): pcie_ep / io_cpu /
|
||||
io_noc / io_ucie PHY / conn 노드 + 내부 양방향 edge 생성.
|
||||
- **cube instantiation** (`_instantiate_cube`): cube_mesh.yaml 의 router
|
||||
grid 를 토대로 cube-별 라우터, PE sub-components (pe_cpu, pe_dma,
|
||||
pe_fetch_store, pe_gemm, pe_math, pe_mmu, pe_tcm, pe_scheduler,
|
||||
pe_ipcq), m_cpu, sram, hbm_ctrl 인스턴스화 + 내부 edge 깔기.
|
||||
- **inter-cube edges** (`_add_inter_cube_edges`): UCIe N/S/E/W mesh
|
||||
edge.
|
||||
- **IO ↔ cube edges** (`_add_io_to_cube_edges`): io_noc 와 cube 의
|
||||
edge UCIe phy 사이 연결.
|
||||
3. **switch ↔ IO edges** (`_add_system_to_io_edges`): `fabric.switch0`
|
||||
와 각 SIP 의 `pcie_ep` 사이 양방향 edge (ADR-0038 D3 + ADR-0010 의
|
||||
cross-SIP IPCQ 경로).
|
||||
4. **view projections** 4 종 build:
|
||||
- `_build_system_view(spec)` — Tray 레벨, SIP 들과 system switch.
|
||||
- `_build_sip_view(spec)` — SIP 안의 cube mesh + IO chiplet.
|
||||
- `_build_cube_view(spec)` — 단일 cube 안의 router grid + PE/M_CPU/SRAM/
|
||||
HBM_CTRL 부착.
|
||||
- `_build_pe_view(spec)` — 단일 PE 안의 9 sub-components + 내부 edge.
|
||||
5. **TopologyGraph 리턴**: `TopologyGraph(spec, nodes, edges, system_view,
|
||||
sip_view, cube_view, pe_view)`.
|
||||
|
||||
이 6 단계는 **순서가 의미를 가진다**: cubes 가 만들어진 후에야 inter-cube
|
||||
edges 가 valid 한 src/dst 를 갖고, IO chiplet 이 먼저 만들어져야 IO ↔ cube
|
||||
edge 가 그를 참조할 수 있다. 새 노드 종류를 끼울 때는 의존 관계를 보고
|
||||
적절한 위치에 삽입해야 한다.
|
||||
|
||||
### D2. `cube_mesh.yaml` — 별도 파일 + source_hash 캐시
|
||||
|
||||
`mesh_gen.ensure_mesh_file(cube_spec, mesh_path)`:
|
||||
|
||||
1. `source_hash = _compute_source_hash(cube_spec)` 산출. 입력 필드:
|
||||
- `geometry` (cube_mm.w/h 등).
|
||||
- `pe_layout` (corners, pe_per_corner).
|
||||
- `ucie.n_connections`.
|
||||
- `memory_map.hbm_mapping_mode`.
|
||||
- `placement` (m_cpu/sram pos_mm).
|
||||
2. `mesh_path` (= `topology.yaml` 와 같은 디렉터리의 `cube_mesh.yaml`) 이
|
||||
존재하고 `existing.source_hash == source_hash` 면 재사용 (캐시 hit).
|
||||
3. 아니면 `_generate_mesh(cube_spec, source_hash)` 로 새 mesh 생성 후
|
||||
yaml 로 저장.
|
||||
|
||||
별도 파일로 캐시하는 이유:
|
||||
|
||||
- mesh 생성은 PE/UCIe/router 부착 계산이 들어가 매번 다시 하기 무거움.
|
||||
- 같은 cube spec 으로 여러 번 실행 시 동일 mesh 가 보장되어야 함.
|
||||
- 사람이 직접 mesh 를 inspect / debug 할 수 있는 artifact 가 됨.
|
||||
|
||||
`source_hash` 가 list 한 5 개 필드가 mesh 형상을 결정하는 핵심이며, 그
|
||||
외 (예: bandwidth, overhead_ns) 변경은 mesh 재생성을 트리거하지 않는다.
|
||||
|
||||
### D3. cube NoC mesh auto-layout 알고리즘
|
||||
|
||||
`_generate_mesh(cube_spec)`:
|
||||
|
||||
#### D3.1. 행/열 결정
|
||||
|
||||
- `pe_positions = _corner_pe_positions(cube_w, cube_h)`: 4 corner (NW/NE/
|
||||
SW/SE) 마다 PE center 좌표 (mm). hardcoded `(1.5, 1.5)` / `(cube_w-1.5,
|
||||
cube_h-1.5)` 패턴 + `pe_per_corner=2` 면 각 corner 에 2 PE 위치.
|
||||
- `col_xs = _compute_col_positions(...)`: PE 들의 x 좌표 union + `max_spacing
|
||||
= 3.0 mm` 보다 큰 gap 에 relay 컬럼 삽입.
|
||||
- `row_ys, rows_per_half = _compute_row_positions(cube_h, n_connections,
|
||||
pe_positions)`:
|
||||
- `n_conn = max(n_connections, 2)` (hot path minimum).
|
||||
- `rows_per_half = ceil(n_conn / 2)`.
|
||||
- top 절반 + HBM 두 row + bottom 절반. HBM 은 `(cube_h/2 - 1.5, cube_h/2
|
||||
+ 1.5)` 에 위치. PE rows 와 HBM rows 사이 `hbm_gap = 1.5 mm`.
|
||||
|
||||
#### D3.2. HBM 제외 zone
|
||||
|
||||
`hbm_row_start = rows_per_half`, `hbm_row_end = rows_per_half + 1`.
|
||||
`hbm_col_start = n_cols // 2 - 1`, `hbm_col_end = n_cols // 2`.
|
||||
|
||||
이 (row, col) 사각형 안의 router 슬롯은 `None` 으로 마킹 (라우터 없음).
|
||||
실제 HBM 컨트롤러는 별도 `hbm_ctrl.pe{X}` 노드로 ADR-0017 D9 의 per-PE
|
||||
파티션 패턴을 따라 부착.
|
||||
|
||||
#### D3.3. PE 부착
|
||||
|
||||
각 corner 의 PE 들은 다음 row 에 매핑:
|
||||
|
||||
- Top half: NW → row 0, NE → row 1 (top_corners 안의 index).
|
||||
- Bottom half: SW → row `hbm_row_end + 1`, SE → row `hbm_row_end + 2`.
|
||||
|
||||
각 PE 의 x 좌표가 가장 가까운 col 의 router 에 부착 (`min(range(n_cols),
|
||||
key=lambda c: abs(col_xs[c] - pe_x))`). 부착 항목은 `pe{pe_idx}.dma`,
|
||||
`pe{pe_idx}.cpu`, `pe{pe_idx}.hbm` 세 가지 (router 별 attach list 에 push).
|
||||
|
||||
#### D3.4. M_CPU / SRAM 부착 — nearest router by Euclidean distance
|
||||
|
||||
`placement.m_cpu.pos_mm` (default `[1.5, 5.5]`) 와 `placement.sram.pos_mm`
|
||||
(default `[1.5, 8.5]`) 의 좌표에서 가장 가까운 router 를 Euclidean
|
||||
distance 로 찾아 attach list 에 `"m_cpu"` / `"sram"` 추가.
|
||||
|
||||
#### D3.5. UCIe N/S/E/W 분배
|
||||
|
||||
`ucie_pe_rows = top_pe_rows + bot_pe_rows` (총 `2 * rows_per_half` 개).
|
||||
|
||||
- UCIe-E: 매 PE row 마다 rightmost col 의 router 에 `ucie_e.c{i}`.
|
||||
- UCIe-W: leftmost col 의 router 에 `ucie_w.c{i}` (E 의 mirror).
|
||||
- UCIe-N/S: PE column 들 중 절반을 좌측, 절반을 우측으로 나눠 top row /
|
||||
bottom row 의 해당 col 에 부착.
|
||||
|
||||
각 UCIe connection 은 `c{i}` index 가 붙어 ucie_n_connections 만큼의 PHY
|
||||
가 분산된다 (ADR-0017 D5+).
|
||||
|
||||
### D4. node 명명 규칙 — 단일 소유자
|
||||
|
||||
builder.py 는 다음 명명 규칙으로 노드를 만든다 (ADR-0051 D5 의 단일
|
||||
소유자 원칙):
|
||||
|
||||
- `fabric.switch0` — system-level switch.
|
||||
- `sip{S}.{io_id}.{pcie_ep|io_cpu|io_noc|io_ucie.{dir}|conn.{id}}` — IO
|
||||
chiplet.
|
||||
- `sip{S}.cube{C}.{m_cpu|sram|hbm_ctrl.pe{X}|noc.r{R}c{C}|...}` — cube 내부.
|
||||
- `sip{S}.cube{C}.pe{P}.{pe_cpu|pe_dma|pe_fetch_store|pe_gemm|pe_math|pe_mmu|pe_tcm|pe_scheduler|pe_ipcq}` — PE sub-components.
|
||||
|
||||
이 명명 규칙을 변경하려면 builder.py 와 router.py (ADR-0051) 의 helper
|
||||
양쪽이 함께 갱신되어야 한다. 컴포넌트는 명명 규칙을 직접 알지 못하고
|
||||
helper 만 호출한다.
|
||||
|
||||
### D5. edge `kind` 분류
|
||||
|
||||
각 edge 가 부여받는 `kind` 가 라우팅 정책 (ADR-0051 D2) 의 입력. 주요
|
||||
kind 값:
|
||||
|
||||
- `"pe_internal"` — PE 내부 sub-component 간.
|
||||
- `"pe_to_router"` — PE_DMA ↔ cube NoC router.
|
||||
- `"router_mesh"` — cube NoC router 간.
|
||||
- `"router_to_hbm"`, `"router_to_mcpu"`, `"router_to_sram"`,
|
||||
`"sram_to_router"` 등 — cube-attached component 간.
|
||||
- `"ucie_internal"`, `"ucie_conn_to_router"`, `"router_to_ucie_conn"`,
|
||||
`"ucie_conn_to_noc"`, `"noc_to_ucie_conn"`, `"ucie_mesh"` — UCIe 관련.
|
||||
- `"io_internal"` — IO chiplet 내부.
|
||||
- `"io_to_cube"`, `"cube_to_io"` — IO ↔ cube 경계.
|
||||
- `"pcie"` — switch ↔ pcie_ep.
|
||||
- `"command"` — control-plane only edges (M_CPU ↔ NOC 등; PE DMA path 에서
|
||||
제외).
|
||||
|
||||
새 edge kind 를 추가하면 router.py 의 4 adjacency graph (ADR-0051 D2) 의
|
||||
어느 카테고리에 속할지 결정해야 한다 — 그렇지 않으면 default 로 `_adj_all`
|
||||
에만 포함되어 의도와 다른 routing 발생 가능.
|
||||
|
||||
### D6. view projection — 4 추상화 레벨
|
||||
|
||||
`TopologyGraph` 는 flat (nodes + edges) 외에 4 개의 view projection 을
|
||||
보유:
|
||||
|
||||
- **system_view** (`_build_system_view`): Tray 레벨. SIP 박스들 + `fabric.
|
||||
switch0`. PCIE 링크 표시. 외부 발표용 high-level overview.
|
||||
- **sip_view** (`_build_sip_view`): 한 SIP 안. cube mesh + IO chiplet
|
||||
(pcie_ep + io_cpu + io_noc). UCIe N/S/E/W 가 cube 간 연결로 보임.
|
||||
- **cube_view** (`_build_cube_view`): 한 cube 안. router grid + PE/M_CPU/
|
||||
SRAM/HBM_CTRL 부착 + UCIe PHY edge 부분. cube 내부 라우팅 / placement
|
||||
진단용.
|
||||
- **pe_view** (`_build_pe_view`): 한 PE 안. 9 sub-components + 내부 edge
|
||||
(pe_internal kind). 자세한 PE 내부 dataflow 검토용.
|
||||
|
||||
view 는 spec 에서 `visualization.emit_views: [system, sip, cube]` 같이
|
||||
선택적으로 출력 (ADR-0006). pe view 는 기본 출력에서 빠져 있으나 코드는
|
||||
유지 (자세한 디버그용).
|
||||
|
||||
### D7. visualizer.py — SVG 다이어그램 출력
|
||||
|
||||
`emit_diagrams(graph, out_dir)` 가 모든 view 를 SVG 로 렌더. 핵심 함수:
|
||||
|
||||
- `_render_view_svg(view)` — 일반적인 view 렌더 (router grid 가 없는
|
||||
경우).
|
||||
- `_render_cube_view_svg(view, spec)` — cube view 전용 (HBM block 그리기,
|
||||
router grid layout, PE/M_CPU/SRAM/HBM positioning).
|
||||
- `_draw_node`, `_draw_edge` — 노드 / edge 의 시각적 표현.
|
||||
- `_pick_scale`, `_compute_node_sizes` — 자동 스케일링.
|
||||
|
||||
visualizer 는 **derived artifact** (ADR-0006) 로 분류되며, 코드 변경 시
|
||||
production check 대상이 아니다. CLAUDE.md 의 "Derived Artifacts" 항목과
|
||||
정합.
|
||||
|
||||
### D8. spec 변경의 영향 범위
|
||||
|
||||
| spec 필드 | 영향 | mesh 재생성 |
|
||||
|---------------------------------------|-------------------|-------------|
|
||||
| `system.sips.count` | SIP 갯수, node 수 | No |
|
||||
| `sip.cube_mesh.w/h` | cube mesh 형상 | No |
|
||||
| `cube.geometry.cube_mm.w/h` | cube 크기 (mm) | **Yes** |
|
||||
| `cube.pe_layout.corners/pe_per_corner`| PE 부착 위치 | **Yes** |
|
||||
| `cube.ucie.n_connections` | UCIe PHY 분배 | **Yes** |
|
||||
| `cube.memory_map.hbm_mapping_mode` | HBM 분배 모드 | **Yes** |
|
||||
| `cube.placement` | M_CPU/SRAM 위치 | **Yes** |
|
||||
| `cube.memory_map.*` (위 제외) | HBM 용량 / BW | No |
|
||||
| `*.links.*.bw_gbs` | edge bandwidth | No |
|
||||
| `*.attrs.overhead_ns` | 컴포넌트 latency | No |
|
||||
|
||||
위 표가 D2 의 `_compute_source_hash` 입력과 일치. mesh 재생성이 필요한
|
||||
변경은 `cube_mesh.yaml` 의 source_hash 가 자동 invalidate.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### A1. mesh 를 별도 캐시 파일 없이 매 compile 시 재생성
|
||||
|
||||
기각. 같은 spec 으로 여러 번 호출되는 케이스 (CLI run, probe, test) 마다
|
||||
mesh 생성 비용을 다시 지불. 또한 사람이 mesh 를 inspect 할 수 있는 artifact
|
||||
가 사라짐.
|
||||
|
||||
### A2. mesh 생성을 builder.py 에 합치기
|
||||
|
||||
기각 (현재). 305 줄 짜리 자체 알고리즘이며, mesh layout 의 결정 (placement-
|
||||
driven router attachment, HBM exclusion zone) 이 builder 의 일반적인
|
||||
node/edge 생성 책임과 다르다. 분리 유지가 단일 책임 원칙에 더 부합.
|
||||
|
||||
### A3. placement coordinate 를 cube 좌표 (col/row) 로 표현
|
||||
|
||||
기각. mm 단위 좌표가 시각화 측 (visualizer) 과 mesh layout 측 (nearest-
|
||||
router 산출) 양쪽에서 일관되게 쓰인다. cube 좌표는 router grid 가 결정
|
||||
되기 전까지는 정의되지 않으므로 placement 입력에 부적절.
|
||||
|
||||
### A4. view projection 을 lazy 하게 생성
|
||||
|
||||
기각 (현재). 4 개 view 의 생성 비용이 작고 (보통 < 100 ms), eager 생성이
|
||||
`TopologyGraph` 를 통한 single source of truth 를 보장.
|
||||
|
||||
### A5. visualizer 출력 형식을 SVG 외 (PNG/PDF) 도
|
||||
|
||||
기각. SVG 가 vector + 텍스트 검색 가능 + 브라우저 직접 렌더가 가능한 가장
|
||||
유연한 형식. PNG 변환이 필요하면 별도 도구 (rsvg-convert 등) 로 후처리.
|
||||
|
||||
## Consequences
|
||||
|
||||
- ADR-0006 의 high-level intent 가 D1–D7 로 구체화되어, topology 변경
|
||||
영향을 D8 표로 빠르게 가늠 가능.
|
||||
- D3 의 mesh auto-layout 알고리즘이 ADR-level 에서 굳어져, 추후 새 PE
|
||||
부착 패턴 (예: HBM 의 6-zone 분할) 도입 시 어느 단계가 영향받는지 명확.
|
||||
- D5 의 edge kind 목록과 D7 의 view 구조가 명시되어, 새 component 종류
|
||||
추가 시 (builder + router + visualizer) 어디까지 손대야 하는지 PR
|
||||
reviewer 가 한눈에 파악 가능.
|
||||
- D2 의 source_hash invalidation 규칙이 명시되어, cube_mesh.yaml 이 stale
|
||||
하게 남는 경우 (예: bw 값만 바꿨을 때) 가 정상 동작임이 분명.
|
||||
Reference in New Issue
Block a user