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-0037: Forwarding Component (forwarding_v1)
|
||||
# ADR-0037: Forwarding 컴포넌트 (forwarding_v1)
|
||||
|
||||
## Status
|
||||
|
||||
@@ -6,86 +6,78 @@ Accepted
|
||||
|
||||
## Context
|
||||
|
||||
The simulation graph has many node positions that exist purely to model
|
||||
fabric traversal — NOC mesh routers, switches, UCIe protocol endpoints,
|
||||
IO chiplet io_noc, transit cubes. These share a common pattern: receive
|
||||
a message, apply per-component overhead (modeling header decode +
|
||||
routing decision time), forward to the next hop along the pre-computed
|
||||
path.
|
||||
시뮬레이션 그래프에는 순전히 패브릭 통과를 모델링하기 위해 존재하는 노드
|
||||
위치들이 많다 — NOC 메시 라우터, 스위치, UCIe 프로토콜 엔드포인트, IO
|
||||
칩렛 io_noc, transit 큐브. 이들은 공통 패턴을 공유한다: 메시지를 수신하고,
|
||||
컴포넌트별 오버헤드(헤더 디코드 + 라우팅 결정 시간을 모델링)를 적용하며,
|
||||
사전 계산된 경로를 따라 다음 홉으로 전달한다.
|
||||
|
||||
This ADR defines the contract for these transit nodes: a single
|
||||
component type (`TransitComponent`) that handles flit-aware forwarding
|
||||
with wormhole cut-through semantics, used under multiple impl names
|
||||
according to the conceptual role each instance plays.
|
||||
본 ADR은 이러한 transit 노드에 대한 계약을 정의한다: 웜홀 cut-through
|
||||
의미로 flit 인지 포워딩을 처리하는 단일 컴포넌트 타입(`TransitComponent`)이며,
|
||||
각 인스턴스가 수행하는 개념적 역할에 따라 여러 impl 이름 아래에 사용된다.
|
||||
|
||||
## Decision
|
||||
|
||||
### D1. Role
|
||||
### D1. 역할
|
||||
|
||||
The Forwarding component (`TransitComponent` class) is a **stateless
|
||||
transit node** in the simulation graph. It models any fabric position
|
||||
where a message physically traverses but no semantic processing
|
||||
happens.
|
||||
Forwarding 컴포넌트(`TransitComponent` 클래스)는 시뮬레이션 그래프의
|
||||
**상태 없는 transit 노드**이다. 메시지가 물리적으로 통과하지만 의미론적
|
||||
처리는 일어나지 않는 모든 패브릭 위치를 모델링한다.
|
||||
|
||||
Per traversal, the component:
|
||||
통과당 컴포넌트는:
|
||||
|
||||
1. Reads an incoming Transaction or Flit from an `in_port`.
|
||||
2. Applies the configured per-component overhead (`overhead_ns`),
|
||||
applied **once per Transaction** even across multi-flit payloads
|
||||
(see D2).
|
||||
3. Looks up the next hop along the Transaction's pre-computed `path`.
|
||||
4. Forwards to the corresponding `out_port`; at the terminal node
|
||||
(no next hop), signals `txn.done` once the `is_last` flit arrives.
|
||||
1. `in_port`에서 들어오는 Transaction 또는 Flit을 읽는다.
|
||||
2. 설정된 컴포넌트별 오버헤드(`overhead_ns`)를 적용한다. 멀티 flit
|
||||
페이로드라도 **Transaction당 한 번** 적용된다(D2 참조).
|
||||
3. Transaction의 사전 계산된 `path`를 따라 다음 홉을 조회한다.
|
||||
4. 해당 `out_port`로 전달한다; 종단 노드(다음 홉 없음)에서는 `is_last`
|
||||
flit이 도착하면 `txn.done`을 시그널한다.
|
||||
|
||||
The component **does NOT**:
|
||||
본 컴포넌트는 다음을 하지 **않는다**:
|
||||
|
||||
- Decide routing — paths are pre-computed by the router (ADR-0002 /
|
||||
ADR-0017 D2). Forwarding only executes the per-hop step.
|
||||
- Model wire propagation or bandwidth occupancy — separate wire
|
||||
processes between components handle that (ADR-0015 D2).
|
||||
- Resolve addresses — the AddressResolver does that (ADR-0017 D9).
|
||||
- Aggregate completion — terminal endpoints (IO_CPU, M_CPU, HBM_CTRL)
|
||||
handle that.
|
||||
- 라우팅 결정 — 경로는 라우터에 의해 사전 계산된다(ADR-0002 /
|
||||
ADR-0017 D2). Forwarding은 홉별 단계만 실행한다.
|
||||
- 와이어 전파나 대역폭 점유 모델링 — 컴포넌트 사이의 별도 와이어
|
||||
프로세스가 처리한다(ADR-0015 D2).
|
||||
- 주소 해석 — AddressResolver가 담당한다(ADR-0017 D9).
|
||||
- 완료 집계 — 종단 엔드포인트(IO_CPU, M_CPU, HBM_CTRL)가 담당한다.
|
||||
|
||||
### D2. First-flit overhead model (header decode)
|
||||
### D2. First-flit 오버헤드 모델 (헤더 디코드)
|
||||
|
||||
Per-Transaction `overhead_ns` is applied **exactly once**, at first
|
||||
flit arrival:
|
||||
Transaction별 `overhead_ns`는 첫 flit 도착 시 **정확히 한 번** 적용된다:
|
||||
|
||||
- `_txn_decoded: set[int]` tracks which Transactions have already
|
||||
paid the overhead at this node.
|
||||
- On first-flit arrival for a Transaction: `yield self.run(env,
|
||||
msg.txn.nbytes)` — pays the overhead.
|
||||
- Subsequent flits of the same Transaction skip the overhead — they
|
||||
pipeline through with no extra delay.
|
||||
- On `is_last` flit: remove the Transaction from `_txn_decoded`.
|
||||
- `_txn_decoded: set[int]`이 본 노드에서 이미 오버헤드를 지불한
|
||||
Transaction들을 추적한다.
|
||||
- 어떤 Transaction의 첫 flit 도착 시: `yield self.run(env, msg.txn.nbytes)`
|
||||
— 오버헤드를 지불한다.
|
||||
- 동일 Transaction의 후속 flit들은 오버헤드를 건너뛰고 추가 지연 없이
|
||||
파이프라인 통과한다.
|
||||
- `is_last` flit 시: Transaction을 `_txn_decoded`에서 제거한다.
|
||||
|
||||
This models the real-HW behavior where header decode and routing
|
||||
decision happen once on first flit; payload flits then stream through
|
||||
the same path (wormhole cut-through). Multi-hop pipelining emerges
|
||||
naturally — each hop adds its own first-flit overhead, but flits
|
||||
after the first do not re-pay overhead at any hop they have already
|
||||
passed first.
|
||||
이는 실제 HW의 동작 — 헤더 디코드와 라우팅 결정이 첫 flit에서 한 번
|
||||
일어나고, 이후 페이로드 flit들은 같은 경로로 스트리밍되는(웜홀
|
||||
cut-through) — 을 모델링한다. 멀티 홉 파이프라이닝은 자연스럽게
|
||||
발현된다 — 각 홉이 자신의 first-flit 오버헤드를 추가하지만, 첫 flit
|
||||
이후의 flit들은 이미 첫 flit이 통과한 어떤 홉에서도 오버헤드를 다시
|
||||
지불하지 않는다.
|
||||
|
||||
### D3. Serial worker forwarding (preserves order)
|
||||
### D3. 직렬 워커 포워딩 (순서 보존)
|
||||
|
||||
The component's worker is a single SimPy process that consumes flits
|
||||
from `_inbox` and forwards them serially in arrival order. The
|
||||
component does NOT spawn `env.process(...)` per flit.
|
||||
본 컴포넌트의 워커는 `_inbox`에서 flit을 소비하여 도착 순서대로 직렬
|
||||
포워딩하는 단일 SimPy 프로세스이다. 컴포넌트는 flit마다
|
||||
`env.process(...)`를 spawn하지 **않는다**.
|
||||
|
||||
Rationale: if the first flit yields on `overhead_ns` while subsequent
|
||||
flits run in parallel processes, the later flits can overtake the
|
||||
first. This produces out-of-order delivery and lets the `is_last`
|
||||
flit arrive at the destination before the first flit — corrupting
|
||||
both the transaction's completion semantics and any flit-index-based
|
||||
processing downstream.
|
||||
근거: 첫 flit이 `overhead_ns`에서 yield하는 동안 후속 flit이 병렬
|
||||
프로세스에서 실행되면, 후속 flit이 첫 flit을 추월할 수 있다. 이는 순서가
|
||||
어긋난 전달을 낳고, `is_last` flit이 첫 flit보다 먼저 목적지에 도착하게
|
||||
하여 — 트랜잭션의 완료 의미와 다운스트림의 flit 인덱스 기반 처리 모두를
|
||||
손상시킨다.
|
||||
|
||||
### D4. Path-based next-hop routing
|
||||
### D4. 경로 기반 next-hop 라우팅
|
||||
|
||||
Routing is **not** a Forwarding-component concern. The Transaction
|
||||
arrives with a pre-computed `path` (built by the router; ADR-0002 /
|
||||
ADR-0017 D2). The component just looks up its own position in the
|
||||
path and forwards to `path[index + 1]`:
|
||||
라우팅은 Forwarding 컴포넌트의 관심사가 **아니다**. Transaction은 라우터에
|
||||
의해 사전 계산된 `path`(ADR-0002 / ADR-0017 D2)와 함께 도착한다.
|
||||
컴포넌트는 단지 자신의 경로상 위치를 찾아 `path[index + 1]`로 전달한다:
|
||||
|
||||
```python
|
||||
def _next_hop_in_path(self, txn):
|
||||
@@ -97,104 +89,97 @@ def _next_hop_in_path(self, txn):
|
||||
return None
|
||||
```
|
||||
|
||||
If `next_hop` is found and present in `out_ports`, the flit is
|
||||
forwarded. Otherwise (terminal node), `txn.done.succeed()` is
|
||||
invoked when the `is_last` flit arrives.
|
||||
`next_hop`이 발견되고 `out_ports`에 존재하면 flit이 전달된다. 그렇지
|
||||
않으면(종단 노드) `is_last` flit이 도착할 때 `txn.done.succeed()`가
|
||||
호출된다.
|
||||
|
||||
### D5. Flit-aware mode with Non-Flit fallback
|
||||
### D5. Flit 인지 모드와 Non-Flit 폴백
|
||||
|
||||
`_FLIT_AWARE = True` opts this component out of the base class's
|
||||
flit-reassembly logic in `_fan_in`. Flits are placed directly on
|
||||
`_inbox` (no reassembly), enabling per-flit handling in the worker
|
||||
loop (D2, D3).
|
||||
`_FLIT_AWARE = True`는 본 컴포넌트가 베이스 클래스의 `_fan_in` 내 flit
|
||||
재조립 로직에서 제외되도록 한다. Flit은 재조립 없이 `_inbox`에 직접
|
||||
놓이며, 이는 워커 루프(D2, D3)에서의 per-flit 처리를 가능케 한다.
|
||||
|
||||
Non-Flit messages — zero-byte control Transactions and other
|
||||
non-chunkified payloads — fall through to the base class's legacy
|
||||
`_forward_txn` path via `env.process`. This preserves backward
|
||||
compatibility for control-plane traffic that does not benefit from
|
||||
flit-level processing.
|
||||
Non-Flit 메시지 — 0바이트 제어 Transaction이나 그 외 청크화되지 않는
|
||||
페이로드 — 는 `env.process`를 통해 베이스 클래스의 레거시 `_forward_txn`
|
||||
경로로 빠진다. 이는 flit 수준 처리의 이득이 없는 제어 평면 트래픽에
|
||||
대한 하위 호환성을 보존한다.
|
||||
|
||||
### D6. Multi-stream merging at the base class
|
||||
### D6. 베이스 클래스에서의 멀티 스트림 병합
|
||||
|
||||
Multi-stream FIFO merging at routers is the base class's
|
||||
responsibility, not Forwarding's. The base class's `_fan_in` spawns
|
||||
one process per `in_port`; all push to a single shared `_inbox`.
|
||||
Flits from different upstream streams therefore interleave at
|
||||
flit granularity in `_inbox`'s FIFO order.
|
||||
라우터에서의 멀티 스트림 FIFO 병합은 Forwarding이 아닌 베이스 클래스의
|
||||
책임이다. 베이스 클래스의 `_fan_in`은 `in_port`마다 하나의 프로세스를
|
||||
spawn한다; 모두가 공유된 단일 `_inbox`에 push한다. 따라서 서로 다른
|
||||
업스트림 스트림의 flit들은 `_inbox`의 FIFO 순서로 flit 단위에서
|
||||
인터리브된다.
|
||||
|
||||
The Forwarding worker simply consumes `_inbox` in arrival order —
|
||||
correctly modeling per-router multi-flow arbitration as
|
||||
fair-FIFO over the shared inbox.
|
||||
Forwarding 워커는 단지 `_inbox`를 도착 순서대로 소비할 뿐이다 —
|
||||
공유 inbox 위의 공정 FIFO로 라우터별 멀티 플로우 중재를 올바르게
|
||||
모델링한다.
|
||||
|
||||
### D7. Single implementation under multiple impl names
|
||||
### D7. 여러 impl 이름 아래의 단일 구현
|
||||
|
||||
A single `TransitComponent` class is registered under four impl names
|
||||
in `components.yaml`:
|
||||
단일 `TransitComponent` 클래스가 `components.yaml`에서 네 가지 impl
|
||||
이름으로 등록된다:
|
||||
|
||||
- `builtin.forwarding` — generic forwarding (e.g., `io_noc`,
|
||||
`noc_router`, UCIe conn bridges)
|
||||
- `builtin.switch` — tray-level switch
|
||||
- `builtin.noc` — cube-level NOC fabric (legacy singleton; current
|
||||
NOC routers use `builtin.forwarding`)
|
||||
- `builtin.ucie` — UCIe protocol endpoint
|
||||
- `builtin.forwarding` — 범용 forwarding (예: `io_noc`, `noc_router`,
|
||||
UCIe conn 브리지)
|
||||
- `builtin.switch` — 트레이 수준 스위치
|
||||
- `builtin.noc` — 큐브 수준 NOC 패브릭(레거시 싱글톤; 현재 NOC
|
||||
라우터는 `builtin.forwarding`을 사용)
|
||||
- `builtin.ucie` — UCIe 프로토콜 엔드포인트
|
||||
|
||||
All four aliases instantiate the same class with the same behavior.
|
||||
Per-instance differentiation lives only in `attrs.overhead_ns`.
|
||||
Separate impl names exist as intent tags for readability and to
|
||||
allow future divergence without backward-incompatible config
|
||||
changes.
|
||||
네 별칭 모두 동일한 동작을 갖는 동일한 클래스를 인스턴스화한다.
|
||||
인스턴스별 차별화는 `attrs.overhead_ns`에만 존재한다. 별도 impl 이름이
|
||||
존재하는 것은 가독성을 위한 의도 태그이자, 하위 호환을 깨지 않고 향후
|
||||
분기를 허용하기 위함이다.
|
||||
|
||||
### D8. Configurable `overhead_ns`
|
||||
### D8. 설정 가능한 `overhead_ns`
|
||||
|
||||
A single attribute drives per-instance latency:
|
||||
단일 속성이 인스턴스별 레이턴시를 결정한다:
|
||||
|
||||
| Usage site | impl name | overhead_ns |
|
||||
| 사용 사이트 | impl 이름 | overhead_ns |
|
||||
| --- | --- | --- |
|
||||
| Tray-level switch | `builtin.switch` | 5.0 |
|
||||
| Cube NOC router | `builtin.forwarding` | 2.0 |
|
||||
| IO chiplet io_noc | `builtin.forwarding` | 0.0 |
|
||||
| UCIe protocol endpoint (`ucie-{N,S,E,W}`) | `builtin.ucie` | 8.0 |
|
||||
| UCIe conn bridge (`ucie-{PORT}.conn{N}`) | `builtin.forwarding` | 0.0 |
|
||||
| 트레이 수준 스위치 | `builtin.switch` | 5.0 |
|
||||
| 큐브 NOC 라우터 | `builtin.forwarding` | 2.0 |
|
||||
| IO 칩렛 io_noc | `builtin.forwarding` | 0.0 |
|
||||
| UCIe 프로토콜 엔드포인트(`ucie-{N,S,E,W}`) | `builtin.ucie` | 8.0 |
|
||||
| UCIe conn 브리지(`ucie-{PORT}.conn{N}`) | `builtin.forwarding` | 0.0 |
|
||||
|
||||
Default is 0.0. The attribute is read at each `run()` invocation, so
|
||||
dynamic reconfiguration is possible but not currently used.
|
||||
기본값은 0.0이다. 속성은 매 `run()` 호출에서 읽히므로 동적 재설정이
|
||||
가능하나 현재는 사용되지 않는다.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- A single class handles all transit-node roles in the simulation
|
||||
graph — minimal code surface for a high-population component type.
|
||||
- Flit-aware processing + serial worker preserves wormhole semantics
|
||||
across multi-hop paths without per-flit process overhead.
|
||||
- `overhead_ns` is the only per-instance tunable; routing, BW, and
|
||||
address resolution stay cleanly separated in their own components /
|
||||
modules.
|
||||
- Multi-stream merging emerges from the base-class structure; no
|
||||
router-specific logic duplicates fair-FIFO arbitration.
|
||||
- Non-Flit fallback path keeps control-plane traffic working without
|
||||
forcing every message into the flit framework.
|
||||
- 단일 클래스가 시뮬레이션 그래프의 모든 transit 노드 역할을 처리한다
|
||||
— 개체 수가 많은 컴포넌트 타입에 대한 최소 코드 표면.
|
||||
- Flit 인지 처리 + 직렬 워커는 per-flit 프로세스 오버헤드 없이 멀티 홉
|
||||
경로 전반에 걸쳐 웜홀 의미를 보존한다.
|
||||
- `overhead_ns`만이 유일한 인스턴스별 튜너블이다; 라우팅, 대역폭, 주소
|
||||
해석은 자체 컴포넌트/모듈에서 깨끗이 분리되어 있다.
|
||||
- 멀티 스트림 병합이 베이스 클래스 구조에서 자연스럽게 발현된다; 라우터
|
||||
전용 로직이 공정 FIFO 중재를 중복 구현하지 않는다.
|
||||
- Non-Flit 폴백 경로는 모든 메시지를 flit 프레임워크로 강제하지 않고도
|
||||
제어 평면 트래픽이 계속 동작하도록 한다.
|
||||
|
||||
### Negative
|
||||
|
||||
- The single class hides usage-site intent inside `attrs.overhead_ns`
|
||||
configuration; readers must consult `topology.yaml` +
|
||||
`components.yaml` to see which impl name maps to which behavior
|
||||
class.
|
||||
- Per-flit serial worker is a bottleneck if `overhead_ns` is large
|
||||
and many concurrent transactions arrive at the same router; current
|
||||
values (0–8 ns) make this negligible.
|
||||
- 단일 클래스가 사용 사이트의 의도를 `attrs.overhead_ns` 설정 안에
|
||||
숨긴다; 어떤 impl 이름이 어떤 동작 클래스로 매핑되는지 보려면 독자가
|
||||
`topology.yaml` + `components.yaml`을 참조해야 한다.
|
||||
- per-flit 직렬 워커는 `overhead_ns`가 크고 같은 라우터에 다수의 동시
|
||||
트랜잭션이 도착할 때 병목이 된다; 현재 값(0–8 ns)에서는 무시할 만한
|
||||
수준이다.
|
||||
|
||||
## Links
|
||||
|
||||
- ADR-0002 (Routing distance — path computation)
|
||||
- ADR-0015 D1 (Component port model)
|
||||
- ADR-0015 D2 (Wire process — BW + propagation, separate from this
|
||||
component)
|
||||
- ADR-0015 D6 (Transit cube forwarding pattern)
|
||||
- ADR-0016 D1 (IO chiplet io_noc — uses this component)
|
||||
- ADR-0017 D1 (Cube NOC routers — use this component)
|
||||
- ADR-0017 D6 (UCIe decomposition — `ucie-{PORT}` instances use this
|
||||
component)
|
||||
- ADR-0033 D1 (Flit-aware pass-through, first-flit overhead,
|
||||
multi-stream merge semantics)
|
||||
- ADR-0002 (라우팅 거리 — 경로 계산)
|
||||
- ADR-0015 D1 (컴포넌트 포트 모델)
|
||||
- ADR-0015 D2 (와이어 프로세스 — 본 컴포넌트와 별개의 BW + 전파)
|
||||
- ADR-0015 D6 (Transit 큐브 forwarding 패턴)
|
||||
- ADR-0016 D1 (IO 칩렛 io_noc — 본 컴포넌트 사용)
|
||||
- ADR-0017 D1 (큐브 NOC 라우터 — 본 컴포넌트 사용)
|
||||
- ADR-0017 D6 (UCIe 분해 — `ucie-{PORT}` 인스턴스가 본 컴포넌트 사용)
|
||||
- ADR-0033 D1 (Flit 인지 통과, first-flit 오버헤드, 멀티 스트림 병합
|
||||
의미)
|
||||
|
||||
Reference in New Issue
Block a user