Files
kernbench2/docs/adr-ko/ADR-0049-ver-probe-subcommand.md
T
ywkang 9a02955770 adr: add ADR-0046-0049 — close G4 coverage gaps from /report
Documents four cross-cutting surfaces that previously had no ADR backing,
each surfaced as a G4 candidate by /report:

- 0046 prog-tl-context-contract: the kernel-side tl.* API. Enumerates
  all primitives (ref/load/store/dot/composite/math/reduction/IPCQ/...),
  the two execution modes (command-list vs greenlet runner), scratch
  allocator semantics, dispatch-overhead model, and the kernel registry.

- 0047 par-ahbm-ccl-backend: torch.distributed.init_process_group
  (backend="ahbm") install path. world_size priority (algorithm >
  defaults > topology), the 4-step init sequence (load ccl.yaml, import
  algorithm module, derive world_size, install SFR + IPCQ), greenlet-
  local rank registry, all_reduce dispatch via _defer_wait, barrier
  no-op rationale, and the explicit list of unsupported dist.* APIs.

- 0048 mem-allocator-algorithms: VirtualAllocator + PEMemAllocator
  free-list semantics. Offset-keyed first-fit with coalescing, the
  no-validation trust model for free(), HBM/TCM channel separation,
  page-aligned VA allocation, the page_size dual-default
  (VirtualAllocator 2 MiB / _ensure_allocators 4 KiB fallback), and
  one-allocator-per-sub-unit rule.

- 0049 ver-probe-subcommand: kernbench probe traffic-pattern catalog.
  H2D / D2H / PE DMA categories with their exact cube-index choices,
  the 32 KiB reference size, the 5-point utilization sweep, the
  formula vs actual column meanings, automatic invariant checks
  (monotonicity, D2H >= H2D, best < worst), per-case GraphEngine
  isolation, and the human-readable (not machine-parsable) output
  contract.

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:25:04 -07:00

11 KiB
Raw Blame History

ADR-0049: kernbench probe Subcommand — Traffic-Pattern Verification Harness

Status

Accepted (2026-05-22).

probes/probe.pyrun_probe(...) 가 노출하는 traffic-pattern catalog, formula vs actual 비교, 그리고 monotonicity / D2H≥H2D 같은 invariant 체크의 의미를 명시한다. ADR-0010 (CLI surface) 가 kernbench probe subcommand 를 enumerate 하나, probe 가 실제로 측정하는 것어떤 invariant 를 PASS/FAIL 로 판정하는가는 ADR-level 에 없었다.

First action (제일 처음에 하는 일)

run_probe(topology_path, case_filter=None) 의 첫 4가지 작업:

  1. Path(topology_path).expanduser().resolve() 로 절대 경로 산출.
  2. load_topology(path)TopologyGraph 인스턴스 (그래프 + spec).
  3. _build_edge_map(graph){(src, dst): Edge} 빠른 lookup 테이블.
  4. AddressResolver(graph) + PathRouter(graph) 인스턴스화.

그 다음 nbytes = 32768 (= 32 KiB, summary table 의 기준 데이터 크기) 와 show_all = (case_filter is None or case_filter == "all") 를 설정.

즉, probe 의 첫 일은 "토폴로지를 한 번 로드하여 edge map / resolver / router 를 준비하고, 32 KiB 라는 표준 측정 크기를 픽스하는 것". 그 이후 H2D → D2H → PE DMA 세 카테고리의 case 들이 각각 별도의 GraphEngine 인스턴스에서 실행된다 (case 간 cross-talk 차단).

Context

kernbench probe 는 다음 의도로 도입된 verification 도구다:

  • 수동 분석 ground truth: 실 시뮬레이션 (kernbench run --bench ...) 결과의 latency 가 비정상으로 보일 때, 단순 traffic pattern 의 정답을 별도 로 얻어 비교.
  • formula vs actual 비교: 분석 모델 (wire latency + overhead + drain) 과 시뮬레이션 결과 (total_ns) 가 일치하는지 확인. 일치하지 않으면 모델 단순화 가정 (ADR-0033) 어디가 빠진 것인지 단서.
  • monotonicity check: hop 수가 늘면 latency 가 단조 증가해야 한다는 invariant 의 자동 확인.
  • utilization sweep: 데이터 크기 (4 KiB ~ 1 MiB) 별 BW 활용률 표.

이 도구의 동작 사양이 ADR-level 에 없으면:

  • 다른 형식의 traffic pattern (예: MCpuDma, IPCQ) 을 추가하려는 사람이 기존 카테고리의 표 포맷 / 측정 단위를 일관되게 따르기 어렵다.
  • monotonicity 가 무엇을 기준으로 검사되는지 (hop 수? cube 거리? wire 길이?) 모호.
  • 32 KiB 라는 기준 크기와 [4 KiB, 16 KiB, 64 KiB, 256 KiB, 1 MiB] sweep 의 의미가 코드 grep 으로만 확인 가능.

Decision

D1. 세 가지 case category — H2D / D2H / PE DMA

각 category 는 토폴로지 상 별개의 데이터 경로를 가지며, 별도의 summary table + sweep table + route detail block 으로 출력된다.

  • H2D (Host→Device Write): MemoryWriteMsg(dst_sip=0, dst_cube, dst_pe=0, pattern="zero")pcie_ep → io_cpu → m_cpu → hbm_ctrl 경로 를 흐른다. cube 인덱스로 hop 수가 증가:
    • h2d-1hop: cube=0, hops=1
    • h2d-2hop: cube=4, hops=2
    • h2d-3hop: cube=8, hops=3
    • h2d-4hop: cube=12, hops=4
  • D2H (Device→Host Read): MemoryReadMsg(src_sip=0, src_cube, src_pe=0). forward command path + reverse data path 의 합 latency. 같은 4 hops 카테고리.
  • PE DMA (PE-initiated): PeDmaMsg(src_sip, src_cube, src_pe, dst_pa). 5 가지 케이스로 cube/PE 위치 변화:
    • pe-local-hbm: same cube, same PE
    • pe-same-half-hbm: same cube, different PE (PE 1)
    • pe-cross-half-hbm: same cube, far PE (PE 4)
    • pe-cross-cube-hbm-best: adjacent cube (cube 1)
    • pe-cross-cube-hbm-worst: diagonal far cube (cube 15)

cube 인덱스가 4/8/12 (H2D), 1/4/15 (PE DMA) 같이 의미 있는 이유는 4x4 cube mesh (sip.cube_mesh.w=4, h=4) 에서의 거리 정의 — 추후 cube_mesh 크기 변경 시 이 값들이 같이 갱신되어야 한다.

D2. 표준 측정 크기 — nbytes = 32768 (32 KiB)

모든 case 의 summary table 은 nbytes=32768 로 한 번 실행한 결과를 보여준다. 32 KiB 가 선택된 이유:

  • DMA overhead 와 BW drain 이 한쪽으로 치우치지 않는 적당한 크기.
  • 다수 sub-unit (TCM, register file) 의 1회 transfer 단위와 비교 가능.

크기별 utilization 변화는 별도 sweep table 이 보여준다 (D3).

D3. Utilization sweep — [4 KiB, 16 KiB, 64 KiB, 256 KiB, 1 MiB]

SWEEP_SIZES = [4096, 16384, 65536, 262144, 1048576], SWEEP_LABELS = ["4KB", "16KB", "64KB", "256KB", "1MB"]. 매 size 마다 다음 공식:

drain   = nbytes / bottleneck_bw
total   = overhead + wire + drain
eff_bw  = nbytes / total
util%   = eff_bw / bottleneck_bw × 100

bn_bw is None or <= 0 이면 그 컬럼은 0.0 % 로 출력. 의미: hop 수가 늘 수록 작은 transfer 는 overhead-bound, 큰 transfer 는 drain-bound 가 되는 패턴을 한 표에서 확인.

D4. 측정 항목 — actual / formula / breakdown

각 case 행에 표시되는 컬럼:

  • Actual (total_ns): SimPy 실행 결과의 trace["total_ns"].
  • Ovhd: 경로상 모든 node 의 node.attrs["overhead_ns"] 합 (formula breakdown).
  • Drain: nbytes / min(edge.bw_gbs over path) (formula).
  • Wire: Σ edge.distance_mm * (ns_per_mm from spec).
  • Ovhd% / Drain%: Ovhd/Drain 이 Actual 에서 차지하는 비율 (formula 의 Wire 는 통상 매우 작아 표시하지 않음).
  • Eff.BW: nbytes / total_ns (실 측정 BW).
  • BN.BW: bottleneck bandwidth (formula). path 상 모든 edge 의 BW 중 최소. edge BW 가 없으면 "-".
  • Util%: Eff.BW / BN.BW × 100. 100% 면 single-stream BW upper bound 에 도달.

formula 의 합 (wire + ovhd + drain) 과 actual 의 차이가 크면 모델 단순화가 잡지 못하는 요소가 있다는 신호 (ADR-0033 의 가정 점검).

D5. Invariant 자동 체크 — PASS/FAIL

다음 invariant 들이 자동으로 확인되어 [v] PASS / [x] FAIL 로 출력:

  • H2D / D2H monotonic increase: hop 수가 늘면 actual latency 가 단조 증가해야 함. all(lats[i] < lats[i+1] for ...).
  • D2H ≥ H2D: 같은 hop 인덱스에서 D2H ≥ H2D (D2H 는 forward command
    • reverse data 두 leg 이므로). all(d2h[i].total >= h2d[i].total).
  • PE DMA best < worst: cross-cube best (adjacent) latency < cross-cube worst (diagonal) latency.
  • PE DMA local vs remote: local BN BW vs remote BN BW 의 비교 출력 (PASS/FAIL 이 아닌 정보성).

체크가 FAIL 이면 사람이 즉시 모델/토폴로지 회귀를 인지할 수 있도록 한 줄로 분명하게 출력.

D6. Route detail — per-hop timestamp trace

summary 와 sweep 표 이후 각 case 의 path 와 per-hop 누적 시간 ( _hop_timestamps) 가 별도 섹션에서 출력된다:

  • H2D: leg1 (pcie_ep → io_cpu) + leg2 (io_cpu → m_cpu) + leg3 (m_cpu → hbm_ctrl) + per-hop trace.
  • D2H: forward (cmd, no data) + reverse (data) trace 분리 표시.
  • PE DMA: pe_dma → router → hbm_ctrl path + per-hop trace.

각 hop 의 timestamp 는 cumulative wire_ns + overhead_ns 누적. terminal hop 의 annotation 에 drain:Xns 가 붙는다. bottleneck edge 는 <BN:XXGB/s> 로 표시되어 시각적으로 식별 가능.

D7. case_filter 인자의 의미

  • None 또는 "all": 모든 case 실행 (default).
  • 다른 문자열: 그 이름과 정확히 일치하는 case 만 실행. 예: kernbench probe --case h2d-2hop.

각 카테고리 안에서 name != case_filter 면 skip 되며, 그 카테고리의 monotonicity / D2H≥H2D 비교는 데이터가 1개일 때 자연히 skip 된다.

CLI parser 의 --case 기본값은 "all"이라 인자 생략 시 전체 실행.

D8. 매 case 별 fresh GraphEngine

H2D 4개, D2H 4개, PE DMA 5개의 case 가 각각 새로운 GraphEngine 인스턴스에서 실행된다 (engine = GraphEngine(graph)). 이유:

  • case 간 누적 상태 (op_log, completion 추적, allocator 등) 가 cross-talk 하지 않도록 격리.
  • 한 case 의 traffic 이 다른 case 의 BW 측정에 영향을 주지 않도록 보장.

이 격리는 probe 의 측정 결과를 각 case 단독 single-flow 의 latency 로 해석할 수 있게 한다. multi-flow contention 측정은 별도 도구 (예: pe2pe_overview 플롯, ADR-0033 의 multi-flow merging 모델) 책임.

D9. 출력 포맷의 안정성

probe 의 stdout 출력은 사람이 읽기 위함이며, 정확한 컬럼 폭/구분자/공백 은 machine-readable contract 가 아니다. 자동화된 도구가 probe 결과를 파싱 하려면 별도 JSON 출력 모드를 추가해야 한다 (현재 미구현).

PASS/FAIL 줄의 [v] / [x] 접두사는 CI grep 용 anchor 로 안정 보장.

Alternatives Considered

A1. Probe 를 별도 bench 로 등록 (@bench(name="probe"))

기각. probe 는 bench 가 아니라 verification 도구로 의도된다 — sweep / 분석 용 multi-engine 실행과 invariant PASS/FAIL 출력이 본질이며, ADR-0045 의 "단일 디바이스 + 단일 RuntimeContext" bench 모델과 맞지 않는다.

A2. monotonicity 위반 시 exit code 1

기각 (현재). 인간 검사 도구 위주로 의도되어 있어 PASS/FAIL 줄을 출력하고 exit 0 로 종료. CI 가 violation 으로 fail 하길 원하면 별도 wrapper 가 grep "\[x\]" 결과로 판단하면 됨. 후속으로 strict-mode flag (--strict) 도입 가능.

A3. probe 의 case 정의를 외부 YAML 로

기각 (현재). 8개 case (4 H2D + 4 D2H + 5 PE DMA — 합 13개) 는 코드에 하드코딩되어 있고 의미가 토폴로지 mesh 구조에 단단히 묶여 있다. 외부 YAML 로 옮기면 cube 인덱스의 의미 (4, 8, 12 / 1, 4, 15) 를 별도로 문서화 해야 하므로 응집도 손실. 케이스 추가가 잦아지면 그때 별도 ADR 로 도입.

A4. multi-flow contention 측정 추가

기각 (probe 범위 밖). D8 에서 명시한 single-flow 격리 모델이 probe 의 핵심 의도. multi-flow contention 은 ADR-0033 latency model 의 다른 영역으로, 별도 도구 또는 별도 case category 로 처리.

Consequences

  • probe 의 case catalog (D1) 와 측정 단위 (D2/D3) 가 ADR-level 에서 명시 되어, 새 traffic 카테고리 추가 시 어떤 표 포맷을 따라야 하는지 분명.
  • formula vs actual 의 컬럼 의미 (D4) 가 굳어져, probe 결과를 보고 "왜 Drain% 가 5% 인가 / 70% 인가" 같은 질문을 빠르게 ADR-0033 가정 점검으로 연결 가능.
  • invariant 자동 체크 (D5) 가 ADR 에 굳어져, 향후 latency 모델 변경 시 monotonicity / D2H≥H2D 회귀를 probe 가 즉시 잡아낸다는 안전망 정착.
  • D8 의 case 간 격리가 명시되어, probe 결과를 single-flow 측정으로 안전 하게 해석 가능. multi-flow 측정이 필요해지면 별도 도구 트랙이 필요함이 분명.
  • A2 의 strict-mode flag 가 후속 작업 후보로 기록되어, CI 통합 요구 시 최소 추가 작업으로 도입 가능.