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:
@@ -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 경유 커널 런치 경로)
|
||||
|
||||
Reference in New Issue
Block a user