ADR: translate adr-ko/ to Korean, fix ADR-0013 slug, refine Status check

Follow-up to the bilingual-structure commit: docs/adr-ko/ now holds
only Korean versions (24 files translated from English placeholders),
ADR-0013 slug uses kebab-case in both folders, and the verify tool
allows translated parenthetical commentary in the Status block.

- Translate 24 English files in docs/adr-ko/ to Korean. The previous
  bilingual-structure commit had left these as English copies because
  their source content was already English; this commit fulfills the
  policy that docs/adr-ko/ contains only Korean.
- Rename ADR-0013 in both adr/ and adr-ko/ from
  ver-verification_strategy.md to ver-verification-strategy.md
  (kebab-case consistency with other ADRs).
- CLAUDE.md (ADR Translation Discipline): clarify that only the
  Status lifecycle keyword (Accepted / Proposed / Stub / Draft /
  Superseded by ADR-NNNN / Merged into ADR-NNNN) must match across
  EN and KO; parenthetical commentary and trailing list items may be
  translated.
- tools/verify_adr_lang_pairs.py: replace byte-equal Status check
  with normalize_status_keyword() which strips parenthetical
  commentary and takes only the first non-empty line.
- tests/test_verify_adr_lang_pairs.py: update existing test names,
  add coverage for translated parenthetical, translated trailing
  list, and Superseded-by-NNNN keyword equality.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 08:17:56 -07:00
parent a796c1d2f7
commit 168b0c89f0
29 changed files with 2631 additions and 2651 deletions
+127 -138
View File
@@ -1,4 +1,4 @@
# ADR-0036: IO_CPU Component Model
# ADR-0036: IO_CPU 컴포넌트 모델
## Status
@@ -6,72 +6,70 @@ Accepted
## Context
IO_CPU is the IO chiplet's host-facing endpoint inside the simulation
graph. PCIE_EP receives host messages from the runtime API and routes
them via the io_noc; for command-bearing requests (KernelLaunch,
MmuMap/Unmap) the io_noc forwards to IO_CPU, which:
IO_CPU는 시뮬레이션 그래프 내부의 IO 칩렛 호스트 대향 엔드포인트이다.
PCIE_EP는 런타임 API로부터 호스트 메시지를 수신하여 io_noc를 통해
라우팅한다; 명령을 동반하는 요청(KernelLaunch, MmuMap/Unmap)의 경우
io_noc는 IO_CPU로 전달하며, IO_CPU는 다음을 수행한다:
- Fans out the request to per-cube M_CPUs.
- Aggregates per-cube responses into a single host-visible completion.
- For kernel launches, stamps a global `target_start_ns` barrier so
every PE across every targeted cube begins kernel body execution at
the same simulated time (ADR-0009 D5).
- 요청을 큐브별 M_CPU로 팬아웃.
- 큐브별 응답을 단일 호스트 가시 완료로 집계.
- 커널 런치의 경우, 타깃이 된 모든 큐브의 모든 PE가 동일한 시뮬레이션
시각에 커널 본체 실행을 시작하도록 전역 `target_start_ns` 배리어를
스탬프함(ADR-0009 D5).
Memory R/W traffic bypasses IO_CPU per ADR-0015 D4 / ADR-0016 D3;
this component therefore handles only command-plane traffic in normal
operation.
Memory R/W 트래픽은 ADR-0015 D4 / ADR-0016 D3에 따라 IO_CPU를 우회한다;
따라서 본 컴포넌트는 정상 동작에서 명령 평면 트래픽만을 처리한다.
This ADR documents the IO_CPU component implementation that realizes
those responsibilities.
본 ADR은 위의 책임을 실현하는 IO_CPU 컴포넌트 구현을 문서화한다.
## Decision
### D1. Role
### D1. 역할
IO_CPU is the host-facing endpoint of the IO chiplet. It has two
primary responsibilities:
IO_CPU는 IO 칩렛의 호스트 대향 엔드포인트이다. 두 가지 주요 책임을
갖는다:
1. **Multi-cube fan-out** — distribute KernelLaunchMsg / MmuMapMsg /
MmuUnmapMsg to per-cube M_CPUs.
2. **Response aggregation** — collect per-cube ResponseMsg, signal
parent `txn.done` when all targeted cubes have responded.
1. **멀티 큐브 팬아웃** KernelLaunchMsg / MmuMapMsg / MmuUnmapMsg를
큐브별 M_CPU로 분배.
2. **응답 집계** — 큐브별 ResponseMsg를 수집하고, 타깃이 된 모든 큐브가
응답한 후 부모 `txn.done`을 시그널.
A third, narrower responsibility applies only to KernelLaunchMsg:
**`target_start_ns` global barrier stamping** (D3).
세 번째이자 더 좁은 책임은 KernelLaunchMsg에만 적용된다:
**`target_start_ns` 전역 배리어 스탬핑**(D3).
The component does **not**:
본 컴포넌트는 다음을 하지 **않는다**:
- Decide routing — paths are pre-computed by the router (ADR-0002).
- Decode tensor or kernel internals — those concerns belong to
M_CPU / PE_CPU / engines.
- Handle PE-level fan-out — M_CPU fans out within a cube (ADR-0009 D3).
- Handle Memory R/W data path — those bypass IO_CPU per ADR-0015 D4
and ADR-0016 D3 (Memory R/W resolution code in
`_resolve_cube_targets` exists as a defensive fallback only).
- 라우팅 결정 — 경로는 라우터에 의해 사전 계산된다(ADR-0002).
- 텐서 또는 커널 내부 디코드 — 그러한 관심사는 M_CPU / PE_CPU / 엔진에
속한다.
- PE 수준 팬아웃 처리 — M_CPU가 큐브 내에서 팬아웃한다(ADR-0009 D3).
- Memory R/W 데이터 경로 처리 — ADR-0015 D4와 ADR-0016 D3에 따라
IO_CPU를 우회한다(`_resolve_cube_targets` 내의 Memory R/W 해석 코드는
방어적 폴백으로만 존재).
Per invocation (`run()`): applies the configured `overhead_ns` once
per incoming Transaction (D8).
호출당(`run()`): 들어오는 Transaction마다 설정된 `overhead_ns`를 한 번
적용한다(D8).
### D2. Forward path — multi-cube fan-out
### D2. 정방향 경로 — 멀티 큐브 팬아웃
When a non-response Transaction arrives, the worker:
응답이 아닌 Transaction이 도착하면, 워커는:
1. Pays `overhead_ns` via `run()`.
2. Calls `_resolve_cube_targets` to derive the list of `(sip, cube)`
targets from the request (D5).
3. For each target:
- Resolves M_CPU node id via `ctx.resolver.find_m_cpu(sip, cube)`.
- Resolves the path via `ctx.router.find_node_path(io_cpu, m_cpu)`.
- Creates a per-cube sub-Transaction with `path` populated and
forwards it to `path[1]` (the first hop on the io_noc).
4. Registers aggregation state: `_pending[request_id] = (expected,
received=0, parent_done)`.
1. `run()`을 통해 `overhead_ns`를 지불.
2. `_resolve_cube_targets`를 호출하여 요청으로부터 `(sip, cube)` 타깃
리스트를 도출(D5).
3. 각 타깃에 대해:
- `ctx.resolver.find_m_cpu(sip, cube)`를 통해 M_CPU 노드 id를 해석.
- `ctx.router.find_node_path(io_cpu, m_cpu)`를 통해 경로를 해석.
- `path`가 채워진 큐브별 서브 Transaction을 생성하여 `path[1]`
(io_noc의 첫 홉)으로 전달.
4. 집계 상태 등록: `_pending[request_id] = (expected, received=0,
parent_done)`.
### D3. KernelLaunch `target_start_ns` global barrier (ADR-0009 D5)
### D3. KernelLaunch `target_start_ns` 전역 배리어 (ADR-0009 D5)
IO_CPU is the canonical stamper for `target_start_ns`. When the
request is a `KernelLaunchMsg`, IO_CPU computes a single global
barrier covering every targeted PE across every targeted cube:
IO_CPU `target_start_ns`의 정규 스탬퍼이다. 요청이
`KernelLaunchMsg`일 때, IO_CPU는 타깃이 된 모든 큐브의 모든 PE를 포괄하는
단일 전역 배리어를 계산한다:
```text
for (sip, cube) in cube_targets:
@@ -85,132 +83,123 @@ for (sip, cube) in cube_targets:
target_start_ns = env.now + global_max
```
The request is then replaced (via `dataclasses.replace`) so the
stamped value propagates through the fan-out.
이후 요청은 (`dataclasses.replace`를 통해) 교체되어 스탬프된 값이 팬아웃
전반에 전파된다.
Two overhead corrections:
두 가지 오버헤드 보정:
- `io_overhead_ns` is subtracted because IO_CPU has already paid it
in `run()` before this method runs.
- `m_overhead_ns` is subtracted once because it appears as the
endpoint of leg1 *and* the start of leg2 in path latency, but
M_CPU pays it only once at run time.
- `io_overhead_ns`는 차감되는데, IO_CPU가 본 메서드 실행 전에 `run()`에서
이미 지불했기 때문이다.
- `m_overhead_ns`는 한 번 차감되는데, 경로 레이턴시에서 leg1의 종단점인
동시에 leg2의 시작점으로 두 번 등장하지만 M_CPU는 런타임에 단 한 번만
지불하기 때문이다.
Every downstream PE_CPU yields until `target_start_ns` before
beginning kernel body execution; all PEs therefore start at the same
simulated time regardless of how long their individual dispatch path
took.
모든 다운스트림 PE_CPU는 커널 본체 실행을 시작하기 전 `target_start_ns`
까지 yield한다; 이를 통해 개별 디스패치 경로가 얼마나 오래 걸렸는지와
무관하게 모든 PE가 동일한 시뮬레이션 시각에 시작한다.
### D4. KernelLaunch sub-Transactions carry `nbytes=0`
### D4. KernelLaunch 서브 Transaction `nbytes=0`을 운반
Per-cube sub-Transactions for KernelLaunchMsg force `nbytes=0`,
overriding the parent `txn.nbytes`:
KernelLaunchMsg의 큐브별 서브 Transaction은 부모 `txn.nbytes`를 무시하고
`nbytes=0`을 강제한다:
- Kernel launch is a control message; payload size is irrelevant at
the data-fabric level.
- If `nbytes > 0`, every per-cube sub-txn occupies fabric BW on the
io_noc's shared first hop. With 16 cubes this serializes fan-out,
pushing far M_CPUs past `target_start_ns` and breaking the D3
invariant.
- 커널 런치는 제어 메시지이다; 데이터 패브릭 수준에서 페이로드 크기는
무관하다.
- `nbytes > 0`이면 모든 큐브별 서브 트랜잭션이 io_noc의 공유 first-hop
패브릭 BW를 점유한다. 16개 큐브에서는 이로 인해 팬아웃이 직렬화되어
먼 M_CPU들이 `target_start_ns`를 지나치게 되고 D3 불변식이 깨진다.
Non-KernelLaunch sub-Transactions preserve `txn.nbytes` (only relevant
for the defensive Memory R/W fallback path, which carries actual
payload sizes).
KernelLaunch가 아닌 서브 Transaction `txn.nbytes`를 보존한다(실제
페이로드 크기를 운반하는 방어적 Memory R/W 폴백 경로에만 관련됨).
### D5. Per-request-type cube target resolution
### D5. 요청 타입별 큐브 타깃 해석
`_resolve_cube_targets` dispatches by request type:
`_resolve_cube_targets`는 요청 타입에 따라 디스패치한다:
| Request type | Source of `(sip, cube)` | `target_cubes="all"` semantics |
| 요청 타입 | `(sip, cube)`의 출처 | `target_cubes="all"` 의미 |
| --- | --- | --- |
| `MemoryWriteMsg` | `dst_sip`, `dst_cube` (or `PhysAddr.decode(dst_pa).die_id` fallback) | single cube derived from PA decode |
| `MemoryReadMsg` | `src_sip`, `src_cube` (or `PhysAddr.decode(src_pa).die_id` fallback) | single cube derived from PA decode |
| `KernelLaunchMsg` | tensor shards filtered by `shard.sip == my_sip` | every cube that owns a shard on this SIP |
| `MmuMapMsg` / `MmuUnmapMsg` | `target_cubes` list, filtered to this SIP | `range(cubes_per_sip)` from spec |
| `MemoryWriteMsg` | `dst_sip`, `dst_cube` (또는 `PhysAddr.decode(dst_pa).die_id` 폴백) | PA 디코드로 도출되는 단일 큐브 |
| `MemoryReadMsg` | `src_sip`, `src_cube` (또는 `PhysAddr.decode(src_pa).die_id` 폴백) | PA 디코드로 도출되는 단일 큐브 |
| `KernelLaunchMsg` | `shard.sip == my_sip`으로 필터링된 텐서 샤드 | 이 SIP 위에서 샤드를 소유하는 모든 큐브 |
| `MmuMapMsg` / `MmuUnmapMsg` | 본 SIP로 필터링된 `target_cubes` 리스트 | 스펙으로부터 `range(cubes_per_sip)` |
Each IO_CPU instance fans out only within its own SIP — `_my_sip()`
parses the SIP id from the node id (e.g., `sip0.io0.io_cpu` → 0).
IO_CPU 인스턴스는 자기 SIP 내에서만 팬아웃한다 — `_my_sip()`
노드 id에서 SIP id를 파싱한다(예: `sip0.io0.io_cpu` → 0).
The Memory R/W rows exist for defensive completeness; the engine's
normal path routes Memory R/W via `_process_memory_direct()` /
`find_memory_path()`, bypassing IO_CPU entirely (ADR-0015 D4 /
ADR-0016 D3).
Memory R/W 행은 방어적 완전성을 위해 존재한다; 엔진의 정상 경로는
Memory R/W `_process_memory_direct()` / `find_memory_path()`로
라우팅하여 IO_CPU를 완전히 우회한다(ADR-0015 D4 / ADR-0016 D3).
### D6. Response aggregation
### D6. 응답 집계
`_pending: dict[request_id → (expected, received, parent_done)]`:
- On dispatch: register `(len(cube_targets), 0, txn.done)`.
- `_worker` recognises responses by `is_response=True` and routes
them to `_collect_response`.
- `_collect_response` increments `received`; when `received >=
expected`, `parent_done.succeed()` is invoked and the entry is
removed from `_pending`.
- 디스패치 시: `(len(cube_targets), 0, txn.done)`을 등록.
- `_worker`는 `is_response=True`로 응답을 인식하여 `_collect_response`로
라우팅한다.
- `_collect_response` `received`를 증가시키며, `received >= expected`가
되면 `parent_done.succeed()`를 호출하고 엔트리를 `_pending`에서
제거한다.
This is a simple per-request counter. There is no per-cube identity
tracking and no partial-failure handling — a missing response
indefinitely stalls the parent done. Production-style failure paths
are out of scope for the current simulator model.
이는 단순한 요청별 카운터이다. 큐브별 정체성 추적이나 부분 실패 처리는
없다 — 누락된 응답은 부모 done을 무기한 스톨시킨다. 프로덕션 스타일의
실패 경로는 현재 시뮬레이터 모델의 범위 밖이다.
### D7. `target_pe` resolution helper
### D7. `target_pe` 해석 헬퍼
`_resolve_pe_ids(target_pe)`:
- `int` → `[target_pe]`.
- `tuple[int, ...]` → `list(target_pe)`.
- `"all"` → `range(n_slices)`, where `n_slices` comes from cube
`memory_map.hbm_slices_per_cube` (default 8).
- `"all"` → `range(n_slices)`, 여기서 `n_slices`는 큐브
`memory_map.hbm_slices_per_cube`(기본 8)에서 가져온다.
Used in D3's barrier computation to enumerate every PE target per
cube.
D3의 배리어 계산에서 큐브별로 모든 PE 타깃을 열거하는 데 사용된다.
### D8. Configurable `overhead_ns`
### D8. 설정 가능한 `overhead_ns`
A single attribute drives per-instance latency:
단일 속성이 인스턴스별 레이턴시를 결정한다:
| Site | impl name | overhead_ns |
| 사이트 | impl 이름 | overhead_ns |
| --- | --- | --- |
| IO chiplet `io_cpu` | `builtin.io_cpu` | 10.0 |
| IO 칩렛 `io_cpu` | `builtin.io_cpu` | 10.0 |
Applied once in `run()` per Transaction. Models command
interpretation + dispatch-decision time at IO_CPU.
Transaction마다 `run()`에서 한 번 적용된다. IO_CPU에서의 명령 해석 및
디스패치 결정 시간을 모델링한다.
## Consequences
### Positive
- Cross-cube and cross-SIP kernel launches share a single global
barrier (D3 + D4) — no per-cube divergence in start time.
- nbytes=0 invariant keeps fan-out off the shared first-hop fabric
BW, preserving the barrier's accuracy at scale (16 cubes).
- Response aggregation via a single counter → minimal state,
deterministic ordering of completion.
- Per-SIP scoping (`_my_sip()`) keeps IO_CPUs in different SIPs
cleanly independent.
- 크로스 큐브 및 크로스 SIP 커널 런치가 단일 전역 배리어를 공유한다
(D3 + D4) — 시작 시각의 큐브별 분기가 없다.
- nbytes=0 불변식이 팬아웃을 공유 first-hop 패브릭 BW로부터 떼어내,
대규모(16 큐브)에서도 배리어의 정확도를 보존한다.
- 단일 카운터를 통한 응답 집계 → 최소 상태, 결정론적 완료 순서.
- SIP별 스코핑(`_my_sip()`)이 서로 다른 SIP의 IO_CPU들을 깨끗이
독립시킨다.
### Negative
- No partial-failure semantics — a missing per-cube response
indefinitely stalls the parent. Adequate for simulation but not
suitable as a production-style endpoint.
- `_pending` is a regular dict; in-flight requests accumulate state.
Acceptable for current benchmark workloads (few concurrent
outstanding launches); unbounded in principle.
- The Memory R/W resolution branches in `_resolve_cube_targets` are
dead code in the normal engine path. Kept defensively but invite
drift if the bypass path ever changes.
- 부분 실패 의미가 없음 — 누락된 큐브별 응답은 부모를 무기한
스톨시킨다. 시뮬레이션 용도로는 충분하나 프로덕션 스타일의
엔드포인트로는 적합하지 않다.
- `_pending`은 일반 dict이다; in-flight 요청이 상태로 누적된다. 현재
벤치마크 워크로드(미해결 런치가 적음)에는 허용 가능하나, 원리적으로는
무한하다.
- `_resolve_cube_targets`의 Memory R/W 해석 분기는 정상 엔진 경로에서
데드 코드이다. 방어적으로 남겨두었으나 우회 경로가 변경되면 드리프트
위험을 초래한다.
## Links
- ADR-0002 (Routing distance — path computation)
- ADR-0009 D1 (Kernel launch is an endpoint request to IO_CPU)
- ADR-0009 D3 (M_CPU fans out within a cube; IO_CPU fans out across
cubes)
- ADR-0009 D5 (target_start_ns canonical stamping at IO_CPU)
- ADR-0011 D-VA3 (MmuMapMsg routes through IO_CPU for cube fan-out)
- ADR-0012 (Host ↔ IO_CPU message schema)
- ADR-0015 D4 (Memory R/W bypasses IO_CPU; Kernel Launch via IO_CPU)
- ADR-0016 D1 (IO chiplet io_noc — IO_CPU attaches here)
- ADR-0016 D3 (Memory R/W path bypasses IO_CPU)
- ADR-0016 D4 (Kernel Launch path through IO_CPU for command
interpretation)
- ADR-0002 (라우팅 거리 — 경로 계산)
- ADR-0009 D1 (커널 런치는 IO_CPU에 대한 엔드포인트 요청)
- ADR-0009 D3 (M_CPU는 큐브 내에서 팬아웃; IO_CPU는 큐브 사이에서 팬아웃)
- ADR-0009 D5 (IO_CPU에서의 target_start_ns 정규 스탬핑)
- ADR-0011 D-VA3 (MmuMapMsg가 큐브 팬아웃을 위해 IO_CPU를 경유)
- ADR-0012 (호스트 ↔ IO_CPU 메시지 스키마)
- ADR-0015 D4 (Memory R/W는 IO_CPU 우회; 커널 런치는 IO_CPU 경유)
- ADR-0016 D1 (IO 칩렛 io_noc — IO_CPU가 여기 부착됨)
- ADR-0016 D3 (Memory R/W 경로가 IO_CPU 우회)
- ADR-0016 D4 (명령 해석을 위한 IO_CPU 경유 커널 런치 경로)