Phase 2c-1: wire chunkifies into Flits + reassembly compat layer

Wire decomposes Transactions into Flits per `_flit_bytes` but emits all
flits atomically at the same env.now — preserves single-msg timing as
infrastructure for Phase 2c-2 (per-flit timing + flit-aware routers).

Non-flit-aware components reassemble Flits in `_fan_in`; `_update_step`
sets txn.step to current component's path position so legacy
step-based routing continues working when upstream is flit-aware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-14 22:03:59 -07:00
parent 5fdb6f8797
commit b31b3e8248
2 changed files with 67 additions and 11 deletions
+42 -2
View File
@@ -53,11 +53,51 @@ class ComponentBase(ABC):
env.process(self._fan_in(port))
env.process(self._worker(env))
# ADR-0033 Phase 2c: flit-aware components consume Flits directly;
# non-flit-aware components reassemble Flits into the parent
# Transaction before delivery to _inbox. Default False preserves
# legacy single-msg semantics during incremental rollout.
_FLIT_AWARE: bool = False
def _fan_in(self, port: simpy.Store) -> Generator:
"""Relay messages from one in_port into the shared inbox."""
"""Relay messages from in_port to _inbox. For non-flit-aware
components (default), Flits are accumulated by parent Transaction
and only the reassembled Transaction is placed on _inbox once
``is_last`` arrives. Step is updated to this component's path
position for legacy step-based routing."""
from kernbench.sim_engine.transaction import Flit
if self._FLIT_AWARE:
while True:
msg = yield port.get()
yield self._inbox.put(msg)
return
flit_buffers: dict[int, list[Any]] = {}
while True:
msg = yield port.get()
yield self._inbox.put(msg)
if isinstance(msg, Flit):
tid = id(msg.txn)
flit_buffers.setdefault(tid, []).append(msg)
if msg.is_last:
flit_buffers.pop(tid, None)
self._update_step(msg.txn)
yield self._inbox.put(msg.txn)
else:
yield self._inbox.put(msg)
def _update_step(self, txn: Any) -> None:
"""Set txn.step to this component's index in txn.path (if found).
Allows legacy step-based routing to work even when flit-aware
upstream components don't call txn.advance()."""
my_id = self.node.id
path = getattr(txn, "path", None)
if not path:
return
for i, n in enumerate(path):
if n == my_id:
txn.step = i
return
def _worker(self, env: simpy.Environment) -> Generator:
"""Generic forwarding worker: spawns _forward_txn per message (pipeline)."""