Files
kernbench2/docs/adr-ko/ADR-0053-dev-topology-builder-algorithms.md
ywkang bd49c93703 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>
2026-05-22 10:52:42 -07:00

15 KiB
Raw Permalink Blame History

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 가 D1D7 로 구체화되어, 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 값만 바꿨을 때) 가 정상 동작임이 분명.