168b0c89f0
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>
186 lines
8.9 KiB
Markdown
186 lines
8.9 KiB
Markdown
# ADR-0037: Forwarding 컴포넌트 (forwarding_v1)
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
시뮬레이션 그래프에는 순전히 패브릭 통과를 모델링하기 위해 존재하는 노드
|
|
위치들이 많다 — NOC 메시 라우터, 스위치, UCIe 프로토콜 엔드포인트, IO
|
|
칩렛 io_noc, transit 큐브. 이들은 공통 패턴을 공유한다: 메시지를 수신하고,
|
|
컴포넌트별 오버헤드(헤더 디코드 + 라우팅 결정 시간을 모델링)를 적용하며,
|
|
사전 계산된 경로를 따라 다음 홉으로 전달한다.
|
|
|
|
본 ADR은 이러한 transit 노드에 대한 계약을 정의한다: 웜홀 cut-through
|
|
의미로 flit 인지 포워딩을 처리하는 단일 컴포넌트 타입(`TransitComponent`)이며,
|
|
각 인스턴스가 수행하는 개념적 역할에 따라 여러 impl 이름 아래에 사용된다.
|
|
|
|
## Decision
|
|
|
|
### D1. 역할
|
|
|
|
Forwarding 컴포넌트(`TransitComponent` 클래스)는 시뮬레이션 그래프의
|
|
**상태 없는 transit 노드**이다. 메시지가 물리적으로 통과하지만 의미론적
|
|
처리는 일어나지 않는 모든 패브릭 위치를 모델링한다.
|
|
|
|
통과당 컴포넌트는:
|
|
|
|
1. `in_port`에서 들어오는 Transaction 또는 Flit을 읽는다.
|
|
2. 설정된 컴포넌트별 오버헤드(`overhead_ns`)를 적용한다. 멀티 flit
|
|
페이로드라도 **Transaction당 한 번** 적용된다(D2 참조).
|
|
3. Transaction의 사전 계산된 `path`를 따라 다음 홉을 조회한다.
|
|
4. 해당 `out_port`로 전달한다; 종단 노드(다음 홉 없음)에서는 `is_last`
|
|
flit이 도착하면 `txn.done`을 시그널한다.
|
|
|
|
본 컴포넌트는 다음을 하지 **않는다**:
|
|
|
|
- 라우팅 결정 — 경로는 라우터에 의해 사전 계산된다(ADR-0002 /
|
|
ADR-0017 D2). Forwarding은 홉별 단계만 실행한다.
|
|
- 와이어 전파나 대역폭 점유 모델링 — 컴포넌트 사이의 별도 와이어
|
|
프로세스가 처리한다(ADR-0015 D2).
|
|
- 주소 해석 — AddressResolver가 담당한다(ADR-0017 D9).
|
|
- 완료 집계 — 종단 엔드포인트(IO_CPU, M_CPU, HBM_CTRL)가 담당한다.
|
|
|
|
### D2. First-flit 오버헤드 모델 (헤더 디코드)
|
|
|
|
Transaction별 `overhead_ns`는 첫 flit 도착 시 **정확히 한 번** 적용된다:
|
|
|
|
- `_txn_decoded: set[int]`이 본 노드에서 이미 오버헤드를 지불한
|
|
Transaction들을 추적한다.
|
|
- 어떤 Transaction의 첫 flit 도착 시: `yield self.run(env, msg.txn.nbytes)`
|
|
— 오버헤드를 지불한다.
|
|
- 동일 Transaction의 후속 flit들은 오버헤드를 건너뛰고 추가 지연 없이
|
|
파이프라인 통과한다.
|
|
- `is_last` flit 시: Transaction을 `_txn_decoded`에서 제거한다.
|
|
|
|
이는 실제 HW의 동작 — 헤더 디코드와 라우팅 결정이 첫 flit에서 한 번
|
|
일어나고, 이후 페이로드 flit들은 같은 경로로 스트리밍되는(웜홀
|
|
cut-through) — 을 모델링한다. 멀티 홉 파이프라이닝은 자연스럽게
|
|
발현된다 — 각 홉이 자신의 first-flit 오버헤드를 추가하지만, 첫 flit
|
|
이후의 flit들은 이미 첫 flit이 통과한 어떤 홉에서도 오버헤드를 다시
|
|
지불하지 않는다.
|
|
|
|
### D3. 직렬 워커 포워딩 (순서 보존)
|
|
|
|
본 컴포넌트의 워커는 `_inbox`에서 flit을 소비하여 도착 순서대로 직렬
|
|
포워딩하는 단일 SimPy 프로세스이다. 컴포넌트는 flit마다
|
|
`env.process(...)`를 spawn하지 **않는다**.
|
|
|
|
근거: 첫 flit이 `overhead_ns`에서 yield하는 동안 후속 flit이 병렬
|
|
프로세스에서 실행되면, 후속 flit이 첫 flit을 추월할 수 있다. 이는 순서가
|
|
어긋난 전달을 낳고, `is_last` flit이 첫 flit보다 먼저 목적지에 도착하게
|
|
하여 — 트랜잭션의 완료 의미와 다운스트림의 flit 인덱스 기반 처리 모두를
|
|
손상시킨다.
|
|
|
|
### D4. 경로 기반 next-hop 라우팅
|
|
|
|
라우팅은 Forwarding 컴포넌트의 관심사가 **아니다**. Transaction은 라우터에
|
|
의해 사전 계산된 `path`(ADR-0002 / ADR-0017 D2)와 함께 도착한다.
|
|
컴포넌트는 단지 자신의 경로상 위치를 찾아 `path[index + 1]`로 전달한다:
|
|
|
|
```python
|
|
def _next_hop_in_path(self, txn):
|
|
my_id = self.node.id
|
|
path = txn.path
|
|
for i, n in enumerate(path):
|
|
if n == my_id and i + 1 < len(path):
|
|
return path[i + 1]
|
|
return None
|
|
```
|
|
|
|
`next_hop`이 발견되고 `out_ports`에 존재하면 flit이 전달된다. 그렇지
|
|
않으면(종단 노드) `is_last` flit이 도착할 때 `txn.done.succeed()`가
|
|
호출된다.
|
|
|
|
### D5. Flit 인지 모드와 Non-Flit 폴백
|
|
|
|
`_FLIT_AWARE = True`는 본 컴포넌트가 베이스 클래스의 `_fan_in` 내 flit
|
|
재조립 로직에서 제외되도록 한다. Flit은 재조립 없이 `_inbox`에 직접
|
|
놓이며, 이는 워커 루프(D2, D3)에서의 per-flit 처리를 가능케 한다.
|
|
|
|
Non-Flit 메시지 — 0바이트 제어 Transaction이나 그 외 청크화되지 않는
|
|
페이로드 — 는 `env.process`를 통해 베이스 클래스의 레거시 `_forward_txn`
|
|
경로로 빠진다. 이는 flit 수준 처리의 이득이 없는 제어 평면 트래픽에
|
|
대한 하위 호환성을 보존한다.
|
|
|
|
### D6. 베이스 클래스에서의 멀티 스트림 병합
|
|
|
|
라우터에서의 멀티 스트림 FIFO 병합은 Forwarding이 아닌 베이스 클래스의
|
|
책임이다. 베이스 클래스의 `_fan_in`은 `in_port`마다 하나의 프로세스를
|
|
spawn한다; 모두가 공유된 단일 `_inbox`에 push한다. 따라서 서로 다른
|
|
업스트림 스트림의 flit들은 `_inbox`의 FIFO 순서로 flit 단위에서
|
|
인터리브된다.
|
|
|
|
Forwarding 워커는 단지 `_inbox`를 도착 순서대로 소비할 뿐이다 —
|
|
공유 inbox 위의 공정 FIFO로 라우터별 멀티 플로우 중재를 올바르게
|
|
모델링한다.
|
|
|
|
### D7. 여러 impl 이름 아래의 단일 구현
|
|
|
|
단일 `TransitComponent` 클래스가 `components.yaml`에서 네 가지 impl
|
|
이름으로 등록된다:
|
|
|
|
- `builtin.forwarding` — 범용 forwarding (예: `io_noc`, `noc_router`,
|
|
UCIe conn 브리지)
|
|
- `builtin.switch` — 트레이 수준 스위치
|
|
- `builtin.noc` — 큐브 수준 NOC 패브릭(레거시 싱글톤; 현재 NOC
|
|
라우터는 `builtin.forwarding`을 사용)
|
|
- `builtin.ucie` — UCIe 프로토콜 엔드포인트
|
|
|
|
네 별칭 모두 동일한 동작을 갖는 동일한 클래스를 인스턴스화한다.
|
|
인스턴스별 차별화는 `attrs.overhead_ns`에만 존재한다. 별도 impl 이름이
|
|
존재하는 것은 가독성을 위한 의도 태그이자, 하위 호환을 깨지 않고 향후
|
|
분기를 허용하기 위함이다.
|
|
|
|
### D8. 설정 가능한 `overhead_ns`
|
|
|
|
단일 속성이 인스턴스별 레이턴시를 결정한다:
|
|
|
|
| 사용 사이트 | impl 이름 | overhead_ns |
|
|
| --- | --- | --- |
|
|
| 트레이 수준 스위치 | `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 |
|
|
|
|
기본값은 0.0이다. 속성은 매 `run()` 호출에서 읽히므로 동적 재설정이
|
|
가능하나 현재는 사용되지 않는다.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
- 단일 클래스가 시뮬레이션 그래프의 모든 transit 노드 역할을 처리한다
|
|
— 개체 수가 많은 컴포넌트 타입에 대한 최소 코드 표면.
|
|
- Flit 인지 처리 + 직렬 워커는 per-flit 프로세스 오버헤드 없이 멀티 홉
|
|
경로 전반에 걸쳐 웜홀 의미를 보존한다.
|
|
- `overhead_ns`만이 유일한 인스턴스별 튜너블이다; 라우팅, 대역폭, 주소
|
|
해석은 자체 컴포넌트/모듈에서 깨끗이 분리되어 있다.
|
|
- 멀티 스트림 병합이 베이스 클래스 구조에서 자연스럽게 발현된다; 라우터
|
|
전용 로직이 공정 FIFO 중재를 중복 구현하지 않는다.
|
|
- Non-Flit 폴백 경로는 모든 메시지를 flit 프레임워크로 강제하지 않고도
|
|
제어 평면 트래픽이 계속 동작하도록 한다.
|
|
|
|
### Negative
|
|
|
|
- 단일 클래스가 사용 사이트의 의도를 `attrs.overhead_ns` 설정 안에
|
|
숨긴다; 어떤 impl 이름이 어떤 동작 클래스로 매핑되는지 보려면 독자가
|
|
`topology.yaml` + `components.yaml`을 참조해야 한다.
|
|
- per-flit 직렬 워커는 `overhead_ns`가 크고 같은 라우터에 다수의 동시
|
|
트랜잭션이 도착할 때 병목이 된다; 현재 값(0–8 ns)에서는 무시할 만한
|
|
수준이다.
|
|
|
|
## Links
|
|
|
|
- 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 오버헤드, 멀티 스트림 병합
|
|
의미)
|