@@ -86,6 +86,21 @@ def _path_c_default_target() -> str:
8686
8787
8888FUSION_MODE_ENV = "CPPMEGA_PATH_C_FUSION"
89+ # Opt-in lever (target-agnostic, identical on Metal and CUDA): when enabled,
90+ # the auto-discovery region splitter does NOT close the current fused segment
91+ # at a route brick that lacks a surface lowerer (e.g. ``E``/moe). Instead, when
92+ # such a brick is *bracketed* by surface-eligible bricks (an eligible run has
93+ # already started and at least one more eligible brick follows), the brick is
94+ # absorbed into the region as an in-chain EAGER EDGE: it is recorded in the
95+ # region span / metadata but emits NO fused kernel surface. The fused chain
96+ # therefore still contains only M/R/A surfaces (so backward math is unchanged),
97+ # while the region span grows across the eager-edge brick. Growing the span
98+ # moves the region's first brick earlier, which is what shrinks the eager
99+ # prefix that the direct-chain training runtime runs before the fused region.
100+ # Off by default so the fused-chain ABI, paths B/D/E, and every existing
101+ # acceptance/region test stay byte-identical until an eager-edge-capable
102+ # runtime opts in.
103+ SPAN_EAGER_EDGE_ENV = "CPPMEGA_PATH_C_SPAN_EAGER_EDGE"
89104DEFAULT_MAX_PATH_B_CACHE_GIB = 55.0
90105DEFAULT_MAX_PATH_B_MEDIAN_STEP_S = 10.0
91106DEFAULT_MIN_C_OVER_B = 1.0
@@ -190,6 +205,13 @@ class _ResolvedPathCModelBrick:
190205 route_symbol : str
191206 attention_qkv_has_bias : bool = True
192207 attention_out_proj_has_bias : bool = True
208+ # When True this brick is carried as an in-chain EAGER EDGE: it counts
209+ # toward the region span (so the region's first brick / start layer can
210+ # move earlier) but it emits NO fused kernel surface and its delta is
211+ # produced eagerly by the runtime. Only set for bricks whose route symbol
212+ # has no surface lowerer (e.g. ``E``/moe) and only when the span-eager-edge
213+ # lever is enabled.
214+ is_eager_edge : bool = False
193215
194216
195217@dataclass (frozen = True )
@@ -237,6 +259,23 @@ def selected_path_c_fusion_mode(
237259 return _FUSION_MODE_ALIASES .get (raw .strip ().lower (), PathCFusionMode .OFF )
238260
239261
262+ _TRUTHY_FLAG_VALUES = frozenset ({"1" , "true" , "yes" , "on" , "force" })
263+
264+
265+ def path_c_span_eager_edges_enabled (
266+ env : Mapping [str , str ] | None = None ,
267+ ) -> bool :
268+ """Return whether the region splitter may span non-fusible eager edges.
269+
270+ Controlled by ``CPPMEGA_PATH_C_SPAN_EAGER_EDGE`` (see ``SPAN_EAGER_EDGE_ENV``).
271+ Target-agnostic: there is no Metal/CUDA branch; the same flag governs both.
272+ Off by default.
273+ """
274+
275+ raw = (env or os .environ ).get (SPAN_EAGER_EDGE_ENV , "" )
276+ return raw .strip ().lower () in _TRUTHY_FLAG_VALUES
277+
278+
240279@dataclass (frozen = True )
241280class Z3SyncSpec :
242281 """Z3-backed sync/async scheduling attachment for a fusion plan."""
@@ -953,6 +992,31 @@ def build_path_c_model_regions_from_route_symbols(
953992 return tuple (regions )
954993
955994
995+ def _can_absorb_eager_edge (
996+ resolved_bricks : Sequence [_ResolvedPathCModelBrick ],
997+ * ,
998+ index : int ,
999+ segment : Sequence [_ResolvedPathCModelBrick ],
1000+ ) -> bool :
1001+ """Return whether a non-fusible brick may be carried as an eager edge.
1002+
1003+ An eager edge is only valid when it is *bracketed* by surface-eligible
1004+ bricks: the current fused segment must already contain at least one
1005+ surface-eligible brick (so there is a producer hidden state to carry the
1006+ residual forward), and at least one later brick must also be
1007+ surface-eligible (so the segment does not terminate on a non-fused edge).
1008+ This keeps every fused chain bounded by real kernel surfaces while letting
1009+ the region span grow across the eager edge.
1010+ """
1011+
1012+ if not any (not b .is_eager_edge for b in segment ):
1013+ return False
1014+ for later in resolved_bricks [index + 1 :]:
1015+ if _path_c_model_brick_surface_lowerer_for (later .route_symbol ) is not None :
1016+ return True
1017+ return False
1018+
1019+
9561020def build_path_c_model_regions_from_bricks (
9571021 bricks : Sequence [Any ],
9581022 * ,
@@ -973,6 +1037,7 @@ def build_path_c_model_regions_from_bricks(
9731037 _resolved_path_c_model_brick (brick , index = index )
9741038 for index , brick in enumerate (bricks )
9751039 )
1040+ span_eager_edges = path_c_span_eager_edges_enabled ()
9761041 regions : list [PathCFusionRegion ] = []
9771042 segment : list [_ResolvedPathCModelBrick ] = []
9781043 segment_start = 0
@@ -982,6 +1047,15 @@ def build_path_c_model_regions_from_bricks(
9821047 segment_start = index
9831048 segment .append (brick )
9841049 continue
1050+ if span_eager_edges and _can_absorb_eager_edge (
1051+ resolved_bricks , index = index , segment = segment
1052+ ):
1053+ # Carry the non-fusible brick (e.g. moe) as an in-chain eager edge:
1054+ # it extends the region span but emits no fused surface, so the
1055+ # fused chain stays surface-eligible-only and gradients are
1056+ # unchanged. The runtime computes its delta eagerly.
1057+ segment .append (replace (brick , is_eager_edge = True ))
1058+ continue
9851059 _append_path_c_model_brick_segment (
9861060 regions ,
9871061 segment ,
@@ -1027,11 +1101,15 @@ def build_path_c_model_region_from_bricks(
10271101 if not resolved_bricks :
10281102 raise ValueError ("bricks must contain at least one model brick" )
10291103 supported_symbols = _path_c_supported_route_symbols ()
1104+ # Eager-edge bricks intentionally carry an unsupported route symbol (no
1105+ # surface lowerer); they extend the region span but are never lowered to a
1106+ # fused surface, so they are exempt from the supported-symbol check.
10301107 unsupported = sorted (
10311108 {
10321109 brick .route_symbol
10331110 for brick in resolved_bricks
10341111 if brick .route_symbol not in supported_symbols
1112+ and not brick .is_eager_edge
10351113 }
10361114 )
10371115 if unsupported :
@@ -1041,9 +1119,13 @@ def build_path_c_model_region_from_bricks(
10411119 f"{ unsupported !r} "
10421120 )
10431121 resolved_shape_env = shape_env or _path_c_model_shape_env_from_config (model_config )
1122+ eager_edge_names = tuple (
1123+ brick .name for brick in resolved_bricks if brick .is_eager_edge
1124+ )
10441125 metadata : dict [str , Any ] = {
10451126 "path_c_route_symbols" : tuple (brick .route_symbol for brick in resolved_bricks ),
10461127 "path_c_bricks" : tuple (_path_c_brick_metadata (brick ) for brick in resolved_bricks ),
1128+ "path_c_eager_edge_bricks" : eager_edge_names ,
10471129 "path_c_acceptance_tags" : tuple (str (tag ) for tag in acceptance_tags ),
10481130 "path_c_acceptance_fixture_abi" : False ,
10491131 }
@@ -1134,6 +1216,10 @@ def _resolved_path_c_model_brick(
11341216 * ,
11351217 index : int ,
11361218) -> _ResolvedPathCModelBrick :
1219+ # An already-resolved brick is returned unchanged so the eager-edge flag
1220+ # (and any other resolved attributes) survive a re-resolution pass.
1221+ if isinstance (brick , _ResolvedPathCModelBrick ):
1222+ return brick
11371223 kind = _brick_attr (brick , "kind" )
11381224 route_symbol = _path_c_route_symbol_from_brick (brick )
11391225 raw_name = _brick_attr (brick , "name" )
@@ -1169,6 +1255,8 @@ def _path_c_brick_metadata(
11691255 "kind" : brick .kind ,
11701256 "route_symbol" : brick .route_symbol ,
11711257 }
1258+ if brick .is_eager_edge :
1259+ metadata ["eager_edge" ] = "true"
11721260 if brick .route_symbol == "A" and not brick .attention_qkv_has_bias :
11731261 metadata ["attention_qkv_has_bias" ] = "false"
11741262 if brick .route_symbol == "A" and not brick .attention_out_proj_has_bias :
@@ -1392,7 +1480,16 @@ def _append_path_c_model_brick_segment(
13921480 shape_env : PathCModelShapeEnv | None ,
13931481 acceptance_tags : Sequence [str ],
13941482) -> None :
1395- if len (segment ) < min_route_bricks :
1483+ # A fused chain must be bounded by real kernel surfaces, so drop any
1484+ # trailing eager-edge bricks (no surface) before emitting the region.
1485+ trimmed = list (segment )
1486+ while trimmed and trimmed [- 1 ].is_eager_edge :
1487+ trimmed .pop ()
1488+ segment = trimmed
1489+ # ``min_route_bricks`` counts surface-eligible (fused) bricks only; eager
1490+ # edges extend the span but do not themselves form a fusible region.
1491+ fused_count = sum (1 for brick in segment if not brick .is_eager_edge )
1492+ if fused_count < min_route_bricks :
13961493 return
13971494 end = segment_start + len (segment ) - 1
13981495 regions .append (
@@ -1676,6 +1773,31 @@ def _path_c_model_surfaces_from_bricks(
16761773 if not bricks :
16771774 raise ValueError ("bricks must contain at least one route" )
16781775
1776+ # Eager-edge bricks (e.g. moe) extend the region span but are NOT lowered
1777+ # to fused surfaces -- the direct-chain runtime computes their delta
1778+ # eagerly and stitches the hidden state across the gap. Each fused
1779+ # sub-segment between two eager edges keeps a byte-identical M/R/A ABI; at
1780+ # an eager-edge boundary the surface chain DOES NOT connect the previous
1781+ # fused brick's output directly to the next fused brick (that would silently
1782+ # drop the eager delta). Instead the next fused sub-segment re-seeds its
1783+ # residual/route hidden from a runtime-provided eager-edge output buffer,
1784+ # so the ABI explicitly records the dependency and a compile-and-run cannot
1785+ # bypass the eager moe.
1786+ #
1787+ # ``eager_edge_before[i]`` is True when an eager-edge brick sits in the
1788+ # original span immediately before the i-th *fused* brick.
1789+ eager_edge_before : list [bool ] = []
1790+ pending_eager_edge = False
1791+ for brick in bricks :
1792+ if brick .is_eager_edge :
1793+ pending_eager_edge = True
1794+ continue
1795+ eager_edge_before .append (pending_eager_edge )
1796+ pending_eager_edge = False
1797+ bricks = tuple (brick for brick in bricks if not brick .is_eager_edge )
1798+ if not bricks :
1799+ raise ValueError ("region must contain at least one fusible route brick" )
1800+
16791801 context = _PathCBrickSurfaceLoweringContext (
16801802 residual_hidden = initial_hidden ,
16811803 route_hidden = initial_hidden ,
@@ -1711,12 +1833,27 @@ def _path_c_model_surfaces_from_bricks(
17111833 )
17121834 result = lowerer .emit (brick , context )
17131835 if index + 1 < len (bricks ):
1714- _append_path_c_inter_brick_residual_norm (
1715- context ,
1716- producer_brick = brick ,
1717- norm_brick = bricks [index + 1 ],
1718- delta = result .delta_output ,
1719- )
1836+ if eager_edge_before [index + 1 ]:
1837+ # An eager edge sits between this fused brick and the next one.
1838+ # Finalize this brick's residual (producer side) into a
1839+ # caller-visible ``hidden_after`` buffer, then start a fresh
1840+ # fused sub-segment whose residual/route hidden is the
1841+ # runtime-provided eager-edge output. The runtime is contracted
1842+ # to write the eager moe delta into this buffer; the surface
1843+ # chain never connects the two sub-segments directly.
1844+ _append_path_c_eager_edge_boundary (
1845+ context ,
1846+ producer_brick = brick ,
1847+ norm_brick = bricks [index + 1 ],
1848+ delta = result .delta_output ,
1849+ )
1850+ else :
1851+ _append_path_c_inter_brick_residual_norm (
1852+ context ,
1853+ producer_brick = brick ,
1854+ norm_brick = bricks [index + 1 ],
1855+ delta = result .delta_output ,
1856+ )
17201857 return tuple (context .surfaces )
17211858
17221859
@@ -1901,6 +2038,57 @@ def _append_path_c_inter_brick_residual_norm(
19012038 context .route_hidden = next_hidden
19022039
19032040
2041+ def _append_path_c_eager_edge_boundary (
2042+ context : _PathCBrickSurfaceLoweringContext ,
2043+ * ,
2044+ producer_brick : _ResolvedPathCModelBrick ,
2045+ norm_brick : _ResolvedPathCModelBrick ,
2046+ delta : str ,
2047+ ) -> None :
2048+ """Close a fused sub-segment at an eager-edge (e.g. moe) boundary.
2049+
2050+ Emits the producer's residual fold into ``{producer}_hidden_after`` -- the
2051+ hidden state the runtime feeds into the eager moe brick(s) -- then re-seeds
2052+ the surface walk so the next fused sub-segment reads its residual/route
2053+ hidden from a runtime-provided ``{norm_brick}_eager_edge_in`` buffer. The
2054+ surface chain therefore never connects the two sub-segments directly; the
2055+ eager-edge output buffer is an explicit ABI dependency the runtime must
2056+ populate (with the eager moe delta already folded in) before the next
2057+ sub-segment runs. This keeps each fused sub-segment's M/R/A math identical
2058+ while making the dropped-delta failure mode impossible to reach silently.
2059+ """
2060+
2061+ norm_name = f"{ producer_brick .name } _residual_norm"
2062+ hidden_after = f"{ producer_brick .name } _hidden_after"
2063+ eager_normed = f"{ norm_name } _hidden"
2064+ context .surfaces .append (
2065+ _residual_norm_surface (
2066+ name = norm_name ,
2067+ hidden = context .residual_hidden ,
2068+ delta = delta ,
2069+ norm_weight = f"{ norm_name } _weight" ,
2070+ hidden_after = hidden_after ,
2071+ next_hidden = eager_normed ,
2072+ )
2073+ )
2074+ # Runtime-provided seed for the next fused sub-segment: the residual
2075+ # baseline carrying the eager moe delta, plus the entry RMSNorm the next
2076+ # fused brick consumes.
2077+ eager_edge_in = f"{ norm_brick .name } _eager_edge_in"
2078+ entry_norm_name = f"{ norm_brick .name } _entry_rmsnorm"
2079+ entry_normed_hidden = f"{ entry_norm_name } _hidden"
2080+ context .surfaces .append (
2081+ _entry_rmsnorm_surface (
2082+ name = entry_norm_name ,
2083+ hidden = eager_edge_in ,
2084+ norm_weight = f"{ entry_norm_name } _weight" ,
2085+ normed_hidden = entry_normed_hidden ,
2086+ )
2087+ )
2088+ context .residual_hidden = eager_edge_in
2089+ context .route_hidden = entry_normed_hidden
2090+
2091+
19042092def _residual_norm_surface (
19052093 * ,
19062094 name : str ,
0 commit comments