Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / codegen / runtime.py: 0%

512 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-25 05:45 +0800

1# Copyright 2026 Huawei Technologies Co., Ltd 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14# ============================================================================ 

15"""Codegen runtime: literal-plan execution helpers for generated modules. 

16 

17The generated modeling file must not re-derive the sharding plan — it only 

18executes the frozen literal plan (``_HYPER_PARAM_PLAN`` etc.) that generation 

19recorded in ``codegen_meta.json``. Execution is **convergent with the native 

20applier**: parameter sharding (Phase A ``_shard_planned_parameters``), special 

21handlers (Phase B) and tied weights (Phase D) run against a live 

22``ShardingPlan`` rebuilt from the meta (:func:`_rebuild_live_plan_from_meta`), 

23so codegen no longer keeps a second literal sharding implementation. Only the 

24forward assembly (the codegen Phase C helpers ``hp_install_boundaries`` / 

25``hp_bind_compute`` / ``hp_apply_inner_wrapper``) stays literal, because 

26the generated file pre-rewrites forward and the native Phase C would 

27double-wrap that redistribution. 

28 

29Helpers fail fast: any unknown placement form, missing entrypoint, or absent 

30meta errors instead of silently degrading to a ``Replicate()`` no-op. 

31""" 

32from __future__ import annotations 

33 

34import functools 

35import inspect 

36import logging 

37import os 

38from typing import Any, Optional 

39 

40from hyper_parallel.codegen.loader import import_generated_module 

41from hyper_parallel.codegen.meta import ( 

42 CodegenMeta, 

43 load_codegen_meta as _load_codegen_meta_from_path, 

44 meta_to_dict, 

45 validate_meta_schema, 

46) 

47# Shared boundary-form classifier (module-level imports are stdlib-only, so 

48# this stays importable without torch). The EP-dependence criterion must be 

49# the same one generation used to pick the boundary's forward form: an entry 

50# whose ``ep`` placement actually *changes* routes to the expert mesh; an 

51# identity ``R -> R`` key (the frozen plan's "not EP-dependent" marker) is not 

52# a dependency, so a degenerate topology (tp=cp=ep=1) prunes such boundaries 

53# to the identity form while the install path is skipped entirely. 

54from hyper_parallel.codegen.plan.boundary_forms import ( 

55 _entry_has_ep_placement, 

56 declared_out_names, 

57 is_boundary_entry, 

58) 

59# Pure placement parsing (freeze.py imports no torch), needed by both the 

60# meta->plan rebuild and its per-field deserializer below. 

61from hyper_parallel.codegen.plan.freeze import parse_named_placement 

62 

63# ``sharding/apply`` imports torch at module level, so it is deliberately not 

64# imported here: runtime.py must stay importable without torch (generation-time 

65# hosts and the local smoke tests import this module for its pure helpers). The 

66# apply helpers are imported lazily inside the one function that needs each. 

67 

68logger = logging.getLogger(__name__) 

69 

70 

71def load_codegen_meta(artifact_dir: str) -> Optional[CodegenMeta]: 

72 """Read ``codegen_meta.json`` from an artifact directory. 

73 

74 Thin wrapper over ``codegen/meta.load_codegen_meta``: the meta module 

75 takes a full path, the runtime contract is the artifact dir. ``None`` 

76 when absent or malformed. 

77 """ 

78 return _load_codegen_meta_from_path(os.path.join(artifact_dir, "codegen_meta.json")) 

79 

80 

81def verify_codegen_signature(meta: CodegenMeta, hf_config: Any = None) -> None: 

82 """Validate the generated bundle metadata before model construction. 

83 

84 The full recompute (canonical signature over YAML + env) is the trainer 

85 preflight's job — it runs before ``_build_model`` with the trainer config. 

86 The gate cannot see ``TrainerConfig`` (infrastructure only holds 

87 ``distributed_setup`` / ``hf_config``), so this check covers what it can 

88 and fails fast on anything inconsistent: 

89 

90 - meta passes the schema (``validate_meta_schema``); 

91 - ``covered`` / ``covered.sharding_plan`` / ``entrypoints["parallelize"]`` 

92 exist — the gate decision would be meaningless without them; 

93 - the meta's recorded architecture matches ``hf_config.architectures[0]``, 

94 when the hf_config is available (catches a bundle generated for a 

95 different model class). 

96 """ 

97 validate_meta_schema(meta_to_dict(meta)) 

98 covered = meta.covered or {} 

99 if not isinstance(covered.get("sharding_plan"), bool): 

100 raise TypeError( 

101 "codegen gate: meta.covered.sharding_plan must be a bool; " 

102 f"got {covered.get('sharding_plan')!r}" 

103 ) 

104 if not meta.entrypoints.get("parallelize"): 

105 raise KeyError( 

106 "codegen gate: meta.entrypoints['parallelize'] is missing — the " 

107 "generated module cannot be parallelized; regenerate the artifact" 

108 ) 

109 if hf_config is not None: 

110 architectures = getattr(hf_config, "architectures", None) or [] 

111 arch_name = architectures[0] if architectures else None 

112 source_arch = (meta.source or {}).get("architecture") 

113 if arch_name and source_arch and arch_name != source_arch: 

114 raise ValueError( 

115 f"codegen gate: meta records architecture {source_arch!r} but " 

116 f"hf_config resolves {arch_name!r}; the bundle does not match " 

117 "the requested model" 

118 ) 

119 

120 

121def publish_codegen_mesh_context(artifact_dir: str, mesh_context: Any) -> None: 

122 """Publish ``mesh_context`` into the generated module namespace. 

123 

124 Lowered boundary forwards reference ``mesh_context`` as a module global. 

125 A pure data-parallel/FSDP run does not need generated parameter sharding, 

126 but it still executes those lowered forwards; publishing the context keeps 

127 identity redistributions well-defined without calling ``hp_parallelize``. 

128 """ 

129 module = import_generated_module(artifact_dir) 

130 module.__dict__["mesh_context"] = mesh_context 

131 

132 

133# --------------------------------------------------------------------------- 

134# Mesh resolution (mirrors apply_sharding_plan's source-mesh selection) 

135# --------------------------------------------------------------------------- 

136 

137def _active_mesh(mesh: Any, mesh_dim_names): 

138 """Slice a full mesh down to the plan's active axes (``_get_active_mesh``). 

139 

140 Delegates to the native ``_get_active_mesh_with_names`` — the slicing and 

141 reordering contract lives in one place; this wrapper keeps no mirrored 

142 implementation to stay in sync. 

143 

144 ``apply_sharding_plan`` aligns its sharding mesh to ``plan.mesh_dim_names`` 

145 (the axes the placements were resolved against) by slicing the device 

146 mesh. The runtime receives the same 

147 full meshes (a raw ``DeviceMesh`` carries ``dp``/``cp`` axes the plan 

148 never shards on; the trainer's ``fsdp_non_moe_mesh`` carries 

149 ``fsdp_replicate``/``fsdp_shard``) — slicing by the same names keeps the 

150 dense mesh identical to the applier's active mesh, so a placement never 

151 lands on a wrong axis. 

152 

153 A mesh without the given axes (e.g. an ``OfflineMesh`` built without 

154 ``ep``) returns itself, matching ``_get_active_mesh``'s fallback. A mesh 

155 that HAS the axes but cannot be sliced raises — never silently returns the 

156 unsliced mesh (that would shard along a wrong axis). 

157 

158 The frozen plan records its active axes in *offline-mesh* order 

159 (``build_offline_mesh`` appends ``tp`` then ``cp``), which is NOT 

160 guaranteed to be the live ``DeviceMesh``'s declared order (a trainer mesh 

161 is ``("dp", "cp", "tp")``). ``DeviceMesh.__getitem__`` only accepts a 

162 slice whose axis indices are ascending (device_mesh.py), so the names are 

163 reordered into the mesh's own declared order before slicing. The reordered 

164 tuple is returned alongside the mesh 

165 (``(sub_mesh, active_dim_names)``): the caller must resolve placements 

166 against the *returned* names, because the sliced sub-mesh carries exactly 

167 that axis order and a placement tuple must line up with it. 

168 """ 

169 from hyper_parallel.distributed._builder.applier import ( # pylint: disable=C0415 

170 _get_active_mesh_with_names, 

171 ) 

172 return _get_active_mesh_with_names(mesh, mesh_dim_names) 

173 

174 

175def _resolve_runtime_meshes(mesh: Any, mesh_dim_names=None): 

176 """Resolve the active (dense) mesh and the FSDP source meshes. 

177 

178 Mirrors ``apply_sharding_plan`` / ``_resolve_parameter_source_meshes``. 

179 ``dense_mesh`` is the mesh parameters shard across and boundaries 

180 redistribute against: the **device** mesh sliced down to the caller's 

181 ``mesh_dim_names`` (the plan's active axes), exactly like 

182 ``_get_active_mesh(mesh_context.device_mesh, plan.mesh_dim_names)`` in the 

183 applier. ``dense_source_mesh`` is a different thing — the FSDP2 source 

184 metadata mesh: the non-MoE topology's ``tp`` child, with the device mesh 

185 ``tp`` child as the no-FSDP-context fallback. ``expert_source_mesh`` is 

186 the MoE topology's ``ep`` child. The source meshes stay un-sliced (they 

187 are the true ``tp`` / ``ep`` child meshes). 

188 

189 Returns ``(dense_mesh, dense_source_mesh, expert_source_mesh, 

190 active_dim_names)``. ``active_dim_names`` is the mesh-major reordering of 

191 the caller's ``mesh_dim_names`` (the order ``dense_mesh`` actually carries 

192 after slicing; ``_active_mesh`` reorders the frozen plan's offline-mesh 

193 order into the live mesh's declared order). Callers that resolve 

194 placements against ``dense_mesh`` must use this returned order, never the 

195 raw ``mesh_dim_names`` argument. 

196 """ 

197 device_mesh = getattr(mesh, "device_mesh", mesh) 

198 dense_mesh, active_dim_names = _active_mesh(device_mesh, mesh_dim_names) 

199 

200 fsdp_non_moe_mesh = getattr(mesh, "fsdp_non_moe_mesh", None) 

201 if fsdp_non_moe_mesh is not None: 

202 dense_source_mesh = ( 

203 fsdp_non_moe_mesh["tp"] 

204 if "tp" in tuple(getattr(fsdp_non_moe_mesh, "mesh_dim_names", ()) or ()) 

205 else None 

206 ) 

207 else: 

208 dense_source_mesh = ( 

209 device_mesh["tp"] 

210 if "tp" in tuple(getattr(device_mesh, "mesh_dim_names", ()) or ()) 

211 else None 

212 ) 

213 fsdp_moe_mesh = getattr(mesh, "fsdp_moe_mesh", None) 

214 expert_mesh = ( 

215 fsdp_moe_mesh["ep"] 

216 if fsdp_moe_mesh is not None 

217 and "ep" in tuple(getattr(fsdp_moe_mesh, "mesh_dim_names", ()) or ()) 

218 else None 

219 ) 

220 if expert_mesh is not None: 

221 # The expert mesh is also sliced to the plan's active axes, so it gets 

222 # the same mesh-major reordering (and must arrive with it). 

223 expert_mesh, _ = _active_mesh(expert_mesh, mesh_dim_names) 

224 return dense_mesh, dense_source_mesh, expert_mesh, active_dim_names 

225 

226 

227# --------------------------------------------------------------------------- 

228# TP gradient metadata (delegated to the native builder: 

229# parameter_sharding._build_runtime_source_shard_info -> 

230# source_shard.build_source_shard_info) 

231# --------------------------------------------------------------------------- 

232 

233def hp_build_tp_grad_info( 

234 model, 

235 plan, 

236 dense_source_mesh, 

237 expert_source_mesh, 

238) -> Optional[dict[str, tuple[Any, Any]]]: 

239 """Build FSDP2 source metadata through the native builder. 

240 

241 Delegates to the SAME entry the applier runs — 

242 ``parameter_sharding._build_runtime_source_shard_info``, which unwraps the 

243 production parameters once (``_local_params_context``) and calls 

244 ``source_shard.build_source_shard_info``. Codegen holds no second copy of 

245 that logic, so the two paths cannot drift: 

246 

247 - every planned parameter maps to its own declared placement, resolved over 

248 the source mesh's non-FSDP axes, recorded as a tuple (FSDP2 iterates the 

249 placements, so a bare ``Shard(0)`` would crash with "'Shard' object is 

250 not iterable"); 

251 - ``experts.*`` parameters of an EP spec (``spec._ep_size > 0``) map to the 

252 expert EP source mesh; 

253 - ``build_source_shard_info``'s FSDP-owned-axis rejection applies here too; 

254 - tied pairs normalize to one placement (``Shard`` takes precedence). 

255 

256 ``plan`` is the live ``ShardingPlan`` rebuilt from the frozen meta 

257 (:func:`_rebuild_live_plan_from_meta`); the two source meshes come from 

258 ``parameter_sharding._resolve_parameter_source_meshes``, exactly as 

259 ``apply_sharding_plan`` resolves them (``build_source_shard_info`` strips 

260 the FSDP-owned axes itself). 

261 

262 The one-shot ``_local_params_context`` unwrap happens inside the native 

263 builder — after this call the model's DTensor parameters are permanently 

264 plain locals, so ``hp_build_tp_grad_info`` must be the LAST sharding 

265 helper the generated ``hp_parallelize`` runs (the applier's own ordering 

266 invariant). 

267 """ 

268 from hyper_parallel.distributed._builder.parameter_sharding import ( 

269 _build_runtime_source_shard_info, 

270 ) 

271 

272 return _build_runtime_source_shard_info( 

273 [model], plan, dense_source_mesh, expert_source_mesh, False 

274 ) 

275 

276 

277# --------------------------------------------------------------------------- 

278# Boundary redistribution through PrecompiledBoundary 

279# --------------------------------------------------------------------------- 

280 

281def _load_target_path(path: str): 

282 """Import the callable at a dotted ``_target_`` path. 

283 

284 The frozen injection serializes a ``trainer.config.Target`` to 

285 ``{"_target_": <path>}``; the runtime re-imports the callable and rebuilds 

286 the ``Target`` so the applier's resolution helpers (``_is_delayed_target``, 

287 ``Target.build``) accept it unchanged. ``_target_`` paths may carry 

288 ``(obj, qualname)`` for classes, but injection targets are module-level 

289 functions, so the dotted path splits at the last dot into 

290 (module, attribute). 

291 """ 

292 from importlib import import_module 

293 

294 if not isinstance(path, str) or not path: 

295 raise ValueError(f"frozen injection target path must be a non-empty string, got {path!r}") 

296 module_name, _, attr = path.rpartition(".") 

297 if not module_name or not attr: 

298 raise ValueError(f"frozen injection target path {path!r} is not a dotted path") 

299 fn = getattr(import_module(module_name), attr, None) 

300 if fn is None: 

301 raise ValueError( 

302 f"frozen injection target path {path!r} does not name a callable " 

303 f"({module_name!r} has no attribute {attr!r})" 

304 ) 

305 if not callable(fn): 

306 raise TypeError(f"frozen injection target path {path!r} resolves to {type(fn).__name__}, not callable") 

307 return fn 

308 

309 

310def _injection_target(value: Any) -> Any: 

311 """Rebuild an injection factory/wrapper from its frozen form. 

312 

313 ``freeze_injections`` serializes a ``Target`` via ``to_dict()`` 

314 (``{"_target_": path, **kwargs}``) and a plain callable by ``__name__``. 

315 A dict is reconstructed into a real ``trainer.config.Target`` so the 

316 applier's ``_is_delayed_target`` / ``Target.build`` path applies; a string 

317 is left as the registry name the applier resolves the same way it would 

318 have at plan time. 

319 """ 

320 if isinstance(value, dict) and "_target_" in value: 

321 from hyper_parallel.trainer.config import Target 

322 

323 path = value["_target_"] 

324 return Target( 

325 _load_target_path(path), 

326 target_path=path, 

327 **{k: v for k, v in value.items() if k != "_target_"}, 

328 ) 

329 return value 

330 

331 

332class _FrozenBoundarySpec: 

333 """Minimal spec view over one frozen ``param_plan`` boundary entry. 

334 

335 ``PrecompiledBoundary`` reads ``in_src`` / ``in_dst`` / ``out_src`` / 

336 ``out_dst`` / ``out_names`` off the spec object; the frozen entry stores 

337 them as JSON strings, so the adapter re-parses them into real placements 

338 once, up front. 

339 

340 The injection helpers (``hp_bind_compute`` and 

341 ``hp_apply_inner_wrapper``) also hand this to the applier's resolution 

342 chain (``_resolve_local_compute_fn`` / ``_resolve_inner_wrapper``), so it 

343 additionally mirrors the injection fields those read. ``injection`` (a 

344 frozen ``freeze_injections`` entry) supplies ``inner_wrapper`` / 

345 ``inner_target`` / ``inner_out_src`` / ``local_compute_fn`` (each 

346 re-imported from the frozen form); ``entry`` (the frozen ``param_plan`` 

347 entry) supplies ``region_dispatch`` / ``out_src`` / ``out_names``. 

348 """ 

349 

350 def __init__(self, entry: dict[str, Any], injection: Optional[dict[str, Any]] = None): 

351 self.params = parse_named_placement(entry.get("params") or {}) or {} 

352 self.in_src = parse_named_placement(entry.get("in_src") or {}) or {} 

353 self.in_dst = parse_named_placement(entry.get("in_dst") or {}) or {} 

354 self.out_src = ( 

355 parse_named_placement(entry["out_src"]) if entry.get("out_src") else None 

356 ) 

357 self.out_dst = ( 

358 parse_named_placement(entry["out_dst"]) if entry.get("out_dst") else None 

359 ) 

360 self.out_names = list(entry["out_names"]) if entry.get("out_names") else None 

361 self.region_dispatch = entry.get("region_dispatch") 

362 # D-22: the native suppression/restore pair reads this off the spec 

363 # object it is handed, so the frozen view mirrors it. 

364 self._deferred_bias_params = tuple(entry.get("deferred_bias_params") or ()) 

365 for key in ("inner_wrapper", "inner_target", "inner_out_src", "local_compute_fn"): 

366 if injection is not None and key in injection: 

367 setattr(self, key, _injection_target(injection[key])) 

368 

369 

370def _build_rewrap_plan( 

371 plan_entry: dict[str, Any], 

372 dim_names: tuple[str, ...], 

373) -> list[tuple[int, str, tuple]]: 

374 """Pre-parse one frozen entry's ``out_src`` into executable rewrap ops. 

375 

376 Returns ``[(output_index, out_name, placements), ...]``. ``InstalledBoundary`` 

377 resolves once at install time so the per-forward path never re-parses. 

378 """ 

379 from hyper_parallel.distributed.recipe_spec import resolve_placements 

380 

381 declared = plan_entry.get("out_src") or {} 

382 out_names = declared_out_names(plan_entry) 

383 name_to_idx = {name: index for index, name in enumerate(out_names)} 

384 plan: list[tuple[int, str, tuple]] = [] 

385 for out_name, named_placement in declared.items(): 

386 index = name_to_idx.get(out_name) 

387 if index is None: 

388 raise ValueError( 

389 f"InstalledBoundary.rewrap_outputs: out_src declares output {out_name!r}, " 

390 f"but out_names={list(out_names)!r} does not contain it" 

391 ) 

392 # Out_src is a frozen JSON contract: its placement leaves are 

393 # canonical strings ("S(1)"/"R"/"P" ...). resolve_placements would 

394 # hand those strings straight to DTensor.from_local, and a string 

395 # sequence trips _build_layout's alias branch — which demands the 

396 # placement count equal the tensor rank. The extended MoE identity 

397 # contract declares 3 axes ({cp,ep,tp}) but the dense mesh carries only 

398 # 2, so resolving leaves 2 strings against a 3-D (B,S,H) output and 

399 # fails. Parse the leaves back into real Placement objects first (the 

400 # same step _FrozenBoundarySpec applies for the boundary compile / the 

401 # native _rewrap_local_outputs runs on already-object contracts); the 

402 # non-alias path then maps the 2-axis MeshPlacement onto the 3-D 

403 # tensor, padding the unpredicted dim with Replicate(). 

404 named_placement = parse_named_placement(named_placement) 

405 plan.append( 

406 (index, out_name, tuple(resolve_placements(named_placement, dim_names))) 

407 ) 

408 return plan 

409 

410 

411def hp_to_local_if_dtensor(output): 

412 """Convert a local-region boundary output back to a local tensor after exit. 

413 

414 Named by the emitted local-region forward template (``emit.parallel``), so 

415 it stays until that template goes away — see the boundary-ownership item in 

416 the restructuring plan. 

417 """ 

418 to_local = getattr(output, "to_local", None) 

419 if callable(to_local): 

420 return to_local() 

421 return output 

422 

423 

424# --------------------------------------------------------------------------- 

425# Install-time boundary compilation (one-shot; generated forwards bind these) 

426# --------------------------------------------------------------------------- 

427 

428def _compile_boundary(entry: dict[str, Any], mesh: Any, mesh_dim_names): 

429 """Compile one frozen entry into a ``PrecompiledBoundary`` (uncached). 

430 

431 The generated path compiles per module at install time: ``_bind_input_indices`` 

432 mutates ``op.arg_index`` against one module's forward signature, and two classes 

433 with identical contracts but different signatures must not share a plan. 

434 """ 

435 from hyper_parallel.distributed._builder.precompiled_boundary import ( 

436 PrecompiledBoundary, 

437 ) 

438 from hyper_parallel.distributed._builder.tp_collective_lowering import ( 

439 create_tp_collective_lowerer, 

440 ) 

441 

442 dim_names = ( 

443 mesh_dim_names 

444 or tuple(getattr(mesh, "mesh_dim_names", ()) or ()) 

445 ) 

446 return PrecompiledBoundary( 

447 _FrozenBoundarySpec(entry), 

448 mesh, 

449 dim_names, 

450 op_lowerer=create_tp_collective_lowerer(mesh, dim_names), 

451 ) 

452 

453 

454class InstalledBoundary: 

455 """One boundary's compiled redistribute plan, bound to a module instance. 

456 

457 ``hp_install_boundaries`` resolves everything once, at install time 

458 rather than on every forward call: the dense/expert mesh routing (the 

459 empty-active-axes no-op, the ep-entry expert-mesh compile, the ep-key drop 

460 when the dense mesh is active), the active-axis slicing, the 

461 rank-order/backend lowerer validation, and the input-index binding. 

462 Generated forwards then call 

463 ``self._hp_boundary.redistribute_inputs/outputs`` with zero per-call 

464 resolution; the execution semantics — identity passthrough, DTensor 

465 unwrap on identity ops, local collectives, ``DTensor.redistribute`` 

466 fallback — are the compiled ``PrecompiledBoundary``'s own. 

467 """ 

468 

469 def __init__( 

470 self, 

471 entry: dict[str, Any], 

472 mesh_context: Any, 

473 mesh_dim_names: Optional[tuple[str, ...]] = None, 

474 *, 

475 module: Any = None, 

476 ) -> None: 

477 dense_mesh, _, expert_mesh, active_dim_names = ( 

478 _resolve_runtime_meshes(mesh_context, mesh_dim_names) 

479 ) 

480 if dense_mesh is None: 

481 raise ValueError( 

482 "hp_install_boundaries requires a DeviceMesh / MeshContext " 

483 "to compile boundaries against" 

484 ) 

485 # Routing facts the tp_collective re-validation reads: the dense mesh 

486 # and the active axis names this boundary actually compiled against 

487 # (empty = the no-op / expert-mesh branches below). 

488 self.dense_mesh = dense_mesh 

489 self.active_dim_names = tuple(active_dim_names or ()) 

490 self.noop = False 

491 self._boundary = None 

492 if not active_dim_names: 

493 if expert_mesh is not None and _entry_has_ep_placement(entry): 

494 self._boundary = _compile_boundary(entry, expert_mesh, None) 

495 else: 

496 # Boundary-exit semantics for this branch: the payload is 

497 # returned untouched (no DTensor unwrap either). 

498 self.noop = True 

499 else: 

500 self._boundary = _compile_boundary(entry, dense_mesh, active_dim_names) 

501 if self._boundary is not None and module is not None: 

502 from hyper_parallel.distributed._builder.forward_rewriter import ( 

503 _bind_input_indices, 

504 ) 

505 

506 _bind_input_indices(self._boundary, module) 

507 

508 self._rewrap_plan: Optional[list[tuple[int, str, tuple]]] = None 

509 self._rewrap_mesh = None 

510 if entry.get("out_src"): 

511 rewrap_dims = ( 

512 tuple(active_dim_names) 

513 or tuple(getattr(dense_mesh, "mesh_dim_names", ()) or ()) 

514 ) 

515 self._rewrap_plan = _build_rewrap_plan(entry, rewrap_dims) 

516 self._rewrap_mesh = dense_mesh 

517 

518 def redistribute_inputs(self, payload): 

519 """Run the input plan on the ``(args, kwargs)`` pair. 

520 

521 Accepts the pair the generated forward builds and takes it as one 

522 positional argument, so the lowered call sites stay uniform across 

523 boundary forms. 

524 """ 

525 if self.noop: 

526 return payload 

527 args, kwargs = payload 

528 return self._boundary.redistribute_inputs(args, kwargs) 

529 

530 def redistribute_outputs(self, outputs): 

531 """Run the output plan on the forward's tensor output.""" 

532 if self.noop: 

533 return outputs 

534 return self._boundary.redistribute_outputs(outputs) 

535 

536 def rewrap_outputs(self, output): 

537 """Re-wrap local region outputs into DTensors per ``out_src``. 

538 

539 ``_build_rewrap_plan`` pre-resolves the placements at install time; the 

540 replay goes through the codegen-side counterpart of the native 

541 local-region re-wrap 

542 (:func:`~hyper_parallel.distributed._builder.forward_rewriter.rewrap_declared_outputs`). 

543 """ 

544 if self._rewrap_plan is None: 

545 return output 

546 from hyper_parallel.distributed._builder.forward_rewriter import ( # pylint: disable=import-outside-toplevel 

547 rewrap_declared_outputs, 

548 ) 

549 

550 return rewrap_declared_outputs( 

551 output, 

552 self._rewrap_plan, 

553 self._rewrap_mesh, 

554 label="InstalledBoundary.rewrap_outputs", 

555 ) 

556 

557 

558class TPOperators: 

559 """Bare-operator runtime bound to a statically lowered boundary forward. 

560 

561 A ``tp_collective`` template calls ``self._hp_tp.<kind>(...)`` directly 

562 (``emit/parallel``'s static form); ``hp_install_boundaries`` binds this 

563 object only after re-validating that form against the live mesh, so the 

564 baked calls never run unvalidated. Each method is instruction-equivalent 

565 to the compiled engine running the same transition (``RedistOp.execute`` 

566 with the TP lowerer attached): a DTensor input unwraps to its local shard 

567 first, ``None`` passes through untouched (the compiled plan's skip), and 

568 the collective dispatches through ``TPCollectiveLowerer.execution_op`` — 

569 so a gloo ``reduce_scatter`` remaps to all_reduce + local chunk exactly 

570 as the placement-driven path does. 

571 """ 

572 

573 def __init__(self, lowerer: Any) -> None: 

574 """Capture the install-time TP lowerer every operator dispatches through.""" 

575 self._lowerer = lowerer 

576 

577 def to_local(self, tensor: Any) -> Any: 

578 """Identity-transition semantics: a DTensor unwraps to its local shard.""" 

579 from hyper_parallel.core.dtensor.dtensor import DTensor # pylint: disable=C0415 

580 

581 if isinstance(tensor, DTensor): 

582 return tensor.to_local() 

583 return tensor 

584 

585 def all_gather(self, tensor: Any, dim: Optional[int] = None) -> Any: 

586 """Shard -> Replicate on the tp axis: concat-gather along ``dim``.""" 

587 return self._execute("all_gather", tensor, dim) 

588 

589 def all_reduce(self, tensor: Any) -> Any: 

590 """Partial -> Replicate on the tp axis: sum-reduce over the tp group.""" 

591 return self._execute("all_reduce", tensor) 

592 

593 def reduce_scatter(self, tensor: Any, dim: Optional[int] = None) -> Any: 

594 """Partial -> Shard on the tp axis: sum-reduce, then shard along ``dim``.""" 

595 return self._execute("reduce_scatter", tensor, dim) 

596 

597 def _execute(self, kind: str, tensor: Any, dim: Optional[int] = None) -> Any: 

598 """Unwrap, skip ``None``, and run one lowered collective op.""" 

599 from hyper_parallel.core.dtensor.dtensor import DTensor # pylint: disable=C0415 

600 

601 if tensor is None: 

602 return None 

603 if isinstance(tensor, DTensor): 

604 tensor = tensor.to_local() 

605 return self._lowerer.execution_op(kind, tensor_dim=dim).execute(tensor) 

606 

607 

608#: Generated class names whose ``forward`` an inline strategy body replaced 

609#: (the MoE EP shell): it orchestrates through parallel state bound on the 

610#: instance at install time rather than through a compiled boundary. Filled 

611#: per generated module from ``meta.external_state_classes`` — the injected 

612#: strategy's own resolved spec is the only declaration site. 

613_EXTERNAL_STATE_CLASSES_BY_MODULE: dict[str, frozenset[str]] = {} 

614 

615 

616def _mesh_group(mesh: Any, name: str) -> Any: 

617 """Return a named mesh group, tolerating one-dimensional mesh APIs.""" 

618 if mesh is None: 

619 return None 

620 try: 

621 return mesh.get_group(name) 

622 except TypeError: 

623 return mesh.get_group() 

624 

625 

626def _install_inline_state_bindings(module: Any, expert_mesh: Any) -> None: 

627 """Bind the instance-attribute parallel channel an inlined forward reads. 

628 

629 The inlined EP MoE shell orchestrates through the same instance attributes 

630 the boundary templates read: ``self._hp_ep_group`` plus the 

631 ``self.ep_enable`` guard. The value comes from the live mesh (expert mesh 

632 -> EP group) and reproduces the removed module-level state object's verdict 

633 exactly: ``ep_enable`` iff the resolved group spans more than one rank. 

634 

635 No other axis is bound here. A class whose forward is *not* replaced by an 

636 inline body keeps the emitted boundary form, and its channel comes from the 

637 shared install paths: the compiled plan plus the TP operators 

638 (``hp_install_boundaries``) and the declared inner wrapper 

639 (``hp_apply_inner_wrapper``). 

640 """ 

641 ep_group = _mesh_group(expert_mesh, "ep") if expert_mesh is not None else None 

642 module._hp_ep_group = ep_group 

643 module.ep_enable = ep_group is not None and ep_group.size() > 1 

644 

645 

646def hp_bind_inline_state( 

647 model: Any, 

648 mesh_context: Any, 

649 mesh_dim_names: Optional[tuple[str, ...]] = None, 

650 *, 

651 generated_module: Any = None, 

652) -> None: 

653 """Bind the parallel channel on every inlined component module instance. 

654 

655 A class declared in ``meta.external_state_classes`` has its ``forward`` 

656 replaced by an inline strategy body, so the boundary / compute / 

657 inner-wrapper installers all skip it: its orchestration reads instance 

658 attributes instead. This walks the live model once and binds them on every 

659 instance of a declared class — the same classes the installers skip, so an 

660 inlined forward can never run with a partially bound channel. 

661 

662 The mesh facts are resolved lazily and only when a declared class is 

663 actually present, so an artifact without inlined components never touches 

664 the mesh. 

665 """ 

666 if model is None or generated_module is None: 

667 return 

668 targets = [ 

669 module 

670 for _, module in model.named_modules() 

671 if _is_external_state_inline_module(module, generated_module) 

672 ] 

673 if not targets: 

674 return 

675 _, _, expert_mesh, _ = _resolve_runtime_meshes(mesh_context, mesh_dim_names) 

676 for module in targets: 

677 _install_inline_state_bindings(module, expert_mesh) 

678 

679 

680def register_external_state_classes(generated_module: Any, class_names: Any) -> None: 

681 """Record which generated classes take their parallel state externally.""" 

682 if generated_module is None: 

683 return 

684 _EXTERNAL_STATE_CLASSES_BY_MODULE[generated_module.__name__] = frozenset( 

685 class_names or () 

686 ) 

687 

688 

689def _is_external_state_inline_module(module: Any, generated_module: Any = None) -> bool: 

690 """Whether this generated class gets its state from instance attributes. 

691 

692 True for an instance of a class the artifact declared in 

693 ``meta.external_state_classes``: codegen replaced that class's forward with 

694 an inline strategy body and it reads the attributes 

695 ``hp_bind_inline_state`` binds, so the boundary installers must leave it 

696 alone. 

697 """ 

698 if generated_module is None: 

699 return False 

700 module_name = getattr(generated_module, "__name__", None) 

701 class_names = _EXTERNAL_STATE_CLASSES_BY_MODULE.get(module_name) 

702 if not class_names: 

703 return False 

704 cls = type(module) 

705 return cls.__module__ == module_name and cls.__name__ in class_names 

706 

707 

708def _install_deferred_bias_pair(module: Any, spec: Any, *, lowered: bool) -> None: 

709 """Install the D-22 bias-suppression / deferred-re-add pair on one boundary. 

710 

711 Reuses the native Phase C primitives (``_make_bias_free_forward`` / 

712 ``_maybe_add_deferred_biases`` from ``forward_rewriter``) so the hiding 

713 semantics cannot drift from the trainer's path; the exit hook is bound as 

714 ``module._hp_deferred_bias``, which the emitted forward templates call 

715 after the output redistribution. 

716 

717 The one codegen-specific adjustment vs the native 

718 ``_install_bias_suppression`` loop: on a source-lowered boundary 

719 (``lowered=True``) a deferred param path with no dot — the boundary's OWN 

720 bias — wraps the extracted ``_forward_impl`` (the compute forward the 

721 rewritten ``forward`` calls), not ``forward`` itself: wrapping 

722 ``forward`` would keep the bias hidden while the emitted 

723 ``self._hp_deferred_bias(outputs)`` reads it at the exit. Child-owned 

724 paths and imported-class boundaries keep the native placement exactly. 

725 """ 

726 from hyper_parallel.distributed._builder.forward_rewriter import ( # pylint: disable=C0415 

727 _make_bias_free_forward, 

728 _maybe_add_deferred_biases, 

729 ) 

730 

731 for param_path in spec._deferred_bias_params: # pylint: disable=protected-access 

732 owner_path = param_path.rpartition(".")[0] 

733 if owner_path: 

734 owner = module.get_submodule(owner_path) 

735 owner.forward = _make_bias_free_forward(owner, owner.forward) 

736 elif lowered: 

737 module._forward_impl = _make_bias_free_forward( 

738 module, module._forward_impl 

739 ) 

740 else: 

741 module.forward = _make_bias_free_forward(module, module.forward) 

742 module._hp_deferred_bias = functools.partial( 

743 _maybe_add_deferred_biases, module, spec 

744 ) 

745 

746 

747def _wrap_installed_boundary_forward( 

748 module: Any, installed: InstalledBoundary, spec: Any = None 

749) -> None: 

750 """Install native-style boundary entry/exit redistribution on one module. 

751 

752 The compiled plan is captured once at install time instead of being 

753 re-derived on every call. When ``spec`` carries D-22 deferred bias 

754 params, the wrapper also re-adds them after the exit redistribution — 

755 the native Phase C exit order (suppress inside, reduce, add once). 

756 """ 

757 if getattr(module, "_codegen_boundary_wrapped", False): 

758 return 

759 original_forward = module.forward 

760 deferred_bias = spec is not None and bool(spec._deferred_bias_params) 

761 

762 @functools.wraps(original_forward) 

763 def codegen_boundary_forward(*args: Any, **kwargs: Any) -> Any: 

764 redist_args, redist_kwargs = installed.redistribute_inputs((args, kwargs)) 

765 outputs = original_forward(*redist_args, **redist_kwargs) 

766 outputs = installed.redistribute_outputs(outputs) 

767 if deferred_bias: 

768 outputs = module._hp_deferred_bias(outputs) 

769 return outputs 

770 

771 module.forward = codegen_boundary_forward 

772 module._codegen_boundary_wrapped = True 

773 module._codegen_original_forward = original_forward 

774 

775 

776def _wrap_static_fallback_forward(module: Any, installed: InstalledBoundary) -> None: 

777 """Replace a rejected static ``tp_collective`` forward with the generic engine. 

778 

779 The static template's body references ``self._hp_tp``, which this 

780 install path refused to bind; replacing ``module.forward`` wholesale 

781 keeps the class runnable — the compiled plan carries the same 

782 transitions through the generic redistribute engine. A D-22 exit hook 

783 already bound on the module (``_hp_deferred_bias``, installed before 

784 this fallback wraps) is re-applied after the exit redistribution, so the 

785 fallback preserves the deferred-bias semantics the emitted template had. 

786 """ 

787 impl = module._forward_impl 

788 deferred_bias = getattr(module, "_hp_deferred_bias", None) 

789 

790 def generic_boundary_forward(*args: Any, **kwargs: Any) -> Any: 

791 redist_args, redist_kwargs = installed.redistribute_inputs((args, kwargs)) 

792 outputs = impl(*redist_args, **redist_kwargs) 

793 outputs = installed.redistribute_outputs(outputs) 

794 if deferred_bias is not None: 

795 outputs = deferred_bias(outputs) 

796 return outputs 

797 

798 module.forward = generic_boundary_forward 

799 

800 

801def _install_static_tp_operators( 

802 module: Any, 

803 entry: dict[str, Any], 

804 installed: InstalledBoundary, 

805 mesh_dim_names: Optional[tuple[str, ...]], 

806 injection: Optional[dict[str, Any]], 

807) -> None: 

808 """Validate a statically lowered ``tp_collective`` forward against the live mesh. 

809 

810 The emitter baked bare-operator calls under an optimistic verdict — the 

811 frozen entry classified as ``tp_collective`` under the plan's own axes 

812 and the source passed the structural gates (the class marker records 

813 that). The live mesh may disagree: active axes the plan did not freeze, 

814 a tp rank order the lowerer rejects, a backend without the needed 

815 collective. Re-derive the form from the install-time routing facts 

816 (``installed.active_dim_names``, the live mesh's mesh-major order) and 

817 bind ``module._hp_tp`` only when the live verdict reproduces the 

818 emitted ops; on any mismatch replace the forward with the generic 

819 engine, so the baked calls never run unvalidated. 

820 """ 

821 from hyper_parallel.codegen.emit.parallel import ( # pylint: disable=C0415 

822 TP_FORM_ATTRIBUTE, 

823 TP_FORM_MARKER, 

824 ) 

825 from hyper_parallel.codegen.plan.boundary_forms import ( # pylint: disable=C0415 

826 FORM_TP_COLLECTIVE, 

827 classify_boundary_form, 

828 ) 

829 from hyper_parallel.distributed._builder.tp_collective_lowering import ( # pylint: disable=C0415 

830 create_tp_collective_lowerer, 

831 ) 

832 

833 if getattr(module, TP_FORM_ATTRIBUTE, None) != TP_FORM_MARKER: 

834 return 

835 lowerer = create_tp_collective_lowerer( 

836 installed.dense_mesh, installed.active_dim_names 

837 ) 

838 emitted = classify_boundary_form(entry, mesh_dim_names, injection) 

839 live = classify_boundary_form(entry, installed.active_dim_names, injection) 

840 if ( 

841 lowerer is not None 

842 and emitted.form == FORM_TP_COLLECTIVE 

843 and live.form == FORM_TP_COLLECTIVE 

844 and live.in_ops == emitted.in_ops 

845 and live.out_ops == emitted.out_ops 

846 ): 

847 module._hp_tp = TPOperators(lowerer) 

848 return 

849 logger.warning( 

850 "hp_install_boundaries: static tp_collective forward on %s does not " 

851 "match the live mesh (emitted=%s live=%s lowerer=%s); falling back to " 

852 "the generic redistribute engine", 

853 type(module).__name__, emitted.form, live.form, lowerer is not None, 

854 ) 

855 _wrap_static_fallback_forward(module, installed) 

856 

857 

858def _install_toggle_bindings( 

859 module: Any, 

860 installed: InstalledBoundary, 

861) -> None: 

862 """Install the switch/toggle enabler booleans and operators onto one module. 

863 

864 A ``toggle``-marked forward (see ``emit.parallel.lower_forward_boundaries_toggle``) 

865 calls ``self._hp_tp.<kind>(...)`` inside ``if self.{axis}_enable:`` 

866 segments. This binds that runtime surface from the live mesh facts the 

867 compiled ``InstalledBoundary`` already carries — one codegen path, no second 

868 execution engine: 

869 

870 - ``module.tp_enable`` / ``module.cp_enable`` / ``module.ep_enable`` are 

871 set from ``installed.active_dim_names`` (the boundary's actual parallel 

872 dimensions on the live mesh), so a segment only runs when its axis is 

873 genuinely active. 

874 - ``module._hp_tp`` reuses the SAME ``TPOperators`` + native lowerer that 

875 the ``tp_collective`` static form binds, so the toggle body dispatches 

876 through the production collectives rather than a duplicated path within 

877 the raw operator. 

878 """ 

879 from hyper_parallel.codegen.emit.parallel import ( # pylint: disable=C0415 

880 TOGGLE_FORM_MARKER, 

881 TP_FORM_ATTRIBUTE, 

882 ) 

883 from hyper_parallel.distributed._builder.tp_collective_lowering import ( # pylint: disable=C0415 

884 create_tp_collective_lowerer, 

885 ) 

886 

887 if getattr(module, TP_FORM_ATTRIBUTE, None) != TOGGLE_FORM_MARKER: 

888 return 

889 active = tuple(installed.active_dim_names or ()) 

890 module.tp_enable = bool(active and "tp" in active) 

891 module.cp_enable = bool(active and "cp" in active) 

892 module.ep_enable = bool(active and "ep" in active) 

893 if ( 

894 (module.tp_enable or module.cp_enable) 

895 and getattr(installed, "dense_mesh", None) is not None 

896 ): 

897 lowerer = create_tp_collective_lowerer(installed.dense_mesh, active) 

898 if lowerer is not None: 

899 module._hp_tp = TPOperators(lowerer) 

900 

901 

902def hp_install_boundaries( 

903 model: Any, 

904 param_plan: dict[str, Any], 

905 mesh_context: Any, 

906 mesh_dim_names: Optional[tuple[str, ...]] = None, 

907 *, 

908 injections: Optional[list[dict[str, Any]]] = None, 

909 generated_module: Any = None, 

910) -> None: 

911 """Compile every frozen boundary once and bind it to its module instance. 

912 

913 Owns the per-boundary install the removed per-forward wrappers used to do: 

914 each boundary's mesh selection (dense vs 

915 expert, the empty-active-axes no-op), rank-order/backend lowering checks, 

916 and input-index binding run once here, and the compiled 

917 ``InstalledBoundary`` is stored as ``module._hp_boundary`` — the 

918 generated forwards reference that attribute instead of module globals. 

919 

920 Source-lowered boundaries (classes rewritten in the generated file) only 

921 get the attribute binding; imported-class boundaries (``nn.Embedding``, 

922 ``nn.Linear``) additionally get the entry/exit forward wrapper installed, 

923 after the vocab-parallel-embedding wrap, mirroring the previous runtime 

924 behavior. An imported-class boundary whose frozen injection declares a 

925 ``local_compute_fn`` gets no plain wrapper here: ``hp_bind_compute`` 

926 installs the native local-region skeleton against the compiled boundary, 

927 so the injected compute — not the original forward — runs inside the 

928 region. A statically lowered ``tp_collective`` forward additionally gets 

929 its bare operators bound (``module._hp_tp``) only after the live-mesh 

930 re-validation in :func:`_install_static_tp_operators`; a mismatch replaces 

931 the forward with the generic engine. 

932 

933 A boundary whose frozen entry carries ``deferred_bias_params`` (D-22) 

934 additionally gets the native suppression/restore pair installed 

935 (:func:`_install_deferred_bias_pair`): child ``Linear`` forwards run 

936 bias-free inside the region and the exit hook 

937 ``module._hp_deferred_bias`` re-adds each bias exactly once after the 

938 output redistribution — the same order the emitted templates encode. An 

939 external-state inline boundary cannot run that exit hook and fails fast 

940 instead of silently dropping the bias. 

941 

942 Boundaries are installed in post-order (deepest FQN first) via the native 

943 ``_boundary_post_order_key`` — the same D-14 invariant 2 ordering as the 

944 applier's Phase C driving loop, so inner wrappers exist before an outer 

945 boundary's local_compute_fn can cache them. 

946 """ 

947 if not param_plan: 

948 return 

949 from hyper_parallel.distributed._builder.applier import ( 

950 _boundary_post_order_key, 

951 _get_tp_submesh, 

952 ) 

953 from hyper_parallel.distributed._builder.forward_rewriter import ( 

954 _is_vocab_parallel_embed, 

955 ) 

956 from hyper_parallel.distributed._builder.parameter_sharding import ( 

957 _resolve_module, 

958 ) 

959 

960 meshes_resolved = False 

961 tp_mesh = None 

962 

963 for fqn, entry in sorted(param_plan.items(), key=_boundary_post_order_key): 

964 if _is_tp_sequence_parallel_embed_entry(entry): 

965 parent_fqn = fqn.rpartition(".")[0] 

966 _wrap_default_position_ids(_resolve_module(model, parent_fqn)) 

967 if not is_boundary_entry(entry): 

968 continue 

969 module = _resolve_module(model, fqn) 

970 if _has_lowered_forward(module, generated_module): 

971 injection = _injection_spec(injections or [], fqn) 

972 installed = InstalledBoundary( 

973 entry, mesh_context, mesh_dim_names, module=module 

974 ) 

975 if _is_external_state_inline_module(module, generated_module): 

976 # D-22: an inline-strategy class body never passes through 

977 # this boundary exit, so a deferred bias would be suppressed 

978 # but never re-added — fail fast instead of silently 

979 # dropping the bias from every forward. 

980 if entry.get("deferred_bias_params"): 

981 raise NotImplementedError( 

982 f"hp_install_boundaries: boundary {fqn!r} defers bias " 

983 f"params {entry['deferred_bias_params']}, but its class is " 

984 "an external-state inline strategy the D-22 exit hook " 

985 "cannot run in" 

986 ) 

987 continue 

988 module._hp_boundary = installed 

989 if entry.get("deferred_bias_params"): 

990 # Before _install_static_tp_operators: the static-fallback 

991 # wrap captures module._forward_impl at wrap time, so the 

992 # suppression must already be in place there. 

993 _install_deferred_bias_pair( 

994 module, _FrozenBoundarySpec(entry, injection), lowered=True 

995 ) 

996 _install_static_tp_operators( 

997 module, 

998 entry, 

999 installed, 

1000 mesh_dim_names, 

1001 injection, 

1002 ) 

1003 _install_toggle_bindings(module, installed) 

1004 continue 

1005 spec = _FrozenBoundarySpec(entry) 

1006 if spec.params: 

1007 if not meshes_resolved: 

1008 dense_mesh, _, _, active_dim_names = _resolve_runtime_meshes( 

1009 mesh_context, mesh_dim_names 

1010 ) 

1011 tp_mesh = _get_tp_submesh(dense_mesh, tuple(active_dim_names)) 

1012 meshes_resolved = True 

1013 if _is_vocab_parallel_embed(module, spec, tp_mesh): 

1014 _install_vocab_parallel_embedding(module, tp_mesh) 

1015 installed = InstalledBoundary( 

1016 entry, mesh_context, mesh_dim_names, module=module 

1017 ) 

1018 # Every boundary module carries its compiled plan — the imported-class 

1019 # wrapper below closes over it, so introspection and debugging see the 

1020 # same object the generated source-lowered forwards would. 

1021 module._hp_boundary = installed 

1022 if spec._deferred_bias_params: 

1023 # Native order: suppression first, so the wrapper below captures 

1024 # the suppressed forward as its original (D-22, Phase C identity). 

1025 _install_deferred_bias_pair(module, spec, lowered=False) 

1026 injection = _injection_spec(injections or [], fqn) 

1027 if injection is not None and injection.get("local_compute_fn") is not None: 

1028 # A local-region boundary on an imported class: hp_bind_compute 

1029 # installs the native local-region skeleton (boundary entry -> 

1030 # injected compute -> boundary exit) against this compiled 

1031 # boundary. The plain entry/exit wrapper here would run the 

1032 # original forward instead of the injected compute and double 

1033 # the redistribution. 

1034 continue 

1035 _wrap_installed_boundary_forward(module, installed, spec=spec) 

1036 

1037 

1038# --------------------------------------------------------------------------- 

1039# Compute binding and inner-wrapper installation 

1040# --------------------------------------------------------------------------- 

1041 

1042def _injection_spec(injections: list[dict[str, Any]], fqn: str) -> Optional[dict[str, Any]]: 

1043 """Find one frozen boundary's injection declaration by its FQN.""" 

1044 for rule in injections: 

1045 if rule.get("match") == fqn: 

1046 return rule 

1047 return None 

1048 

1049 

1050def hp_expand_injections( 

1051 rules: Optional[list[dict[str, Any]]], 

1052) -> list[dict[str, Any]]: 

1053 """Expand grouped injection rules into the per-FQN form helpers consume. 

1054 

1055 The generated ``_HYPER_INJECTIONS`` literal groups rules that differ only 

1056 in their ``match`` under one record with a ``match`` **list** (one rule 

1057 for every layer's CP wrapper instead of one per layer). This expansion — 

1058 called once at the top of the generated ``hp_parallelize`` — restores 

1059 the per-FQN shape, so ``hp_install_boundaries`` / 

1060 ``hp_bind_compute`` / ``hp_apply_inner_wrapper`` keep their frozen 

1061 single-FQN ``match`` contract unchanged. 

1062 

1063 A scalar ``match`` (the frozen ``meta.injections`` shape and every 

1064 pre-grouping artifact) passes through untouched; ``None`` / empty becomes 

1065 ``[]``. 

1066 """ 

1067 if not rules: 

1068 return [] 

1069 expanded: list[dict[str, Any]] = [] 

1070 for rule in rules: 

1071 match = rule.get("match") if isinstance(rule, dict) else None 

1072 if isinstance(match, (list, tuple)): 

1073 for fqn in match: 

1074 one = dict(rule) 

1075 one["match"] = fqn 

1076 expanded.append(one) 

1077 else: 

1078 expanded.append(rule) 

1079 return expanded 

1080 

1081 

1082def _install_runtime_region_forward( 

1083 module: Any, 

1084 spec: Any, 

1085 compute_fn: Any, 

1086 mesh: Any, 

1087 mesh_dim_names: Any, 

1088) -> None: 

1089 """Install the native local-region skeleton on an imported-class boundary. 

1090 

1091 The compiled plan ``hp_install_boundaries`` left on the module 

1092 (``module._hp_boundary``) carries the native ``PrecompiledBoundary``, so 

1093 the region executes the exact native Phase C path: boundary entry -> 

1094 injected compute -> boundary exit. A boundary compiled as a no-op (no 

1095 active axes) degenerates to the compute swap plus the D-22 exit hook -- 

1096 its entry/exit are identity, the only remaining skeleton effects. 

1097 """ 

1098 from hyper_parallel.distributed._builder.forward_rewriter import ( # pylint: disable=C0415 

1099 _maybe_add_deferred_biases, 

1100 _wrap_local_region_forward, 

1101 ) 

1102 

1103 installed = getattr(module, "_hp_boundary", None) 

1104 if installed is None: 

1105 raise RuntimeError( 

1106 "codegen: local-region injection on " 

1107 f"{type(module).__name__} has no compiled boundary; " 

1108 "hp_install_boundaries must run before hp_bind_compute" 

1109 ) 

1110 if installed.noop: 

1111 

1112 @functools.wraps(module.forward) 

1113 def runtime_region_forward(*args: Any, **kwargs: Any) -> Any: 

1114 output = compute_fn(*args, **kwargs) 

1115 return _maybe_add_deferred_biases(module, spec, output) 

1116 

1117 module.forward = runtime_region_forward 

1118 return 

1119 _wrap_local_region_forward( 

1120 module, 

1121 installed._boundary, # pylint: disable=protected-access 

1122 spec, 

1123 mesh, 

1124 tuple(mesh_dim_names or ()), 

1125 validate_mode=False, 

1126 compute_fn=compute_fn, 

1127 ) 

1128 

1129 

1130def hp_bind_compute( 

1131 model, 

1132 injections: list[dict[str, Any]], 

1133 mesh_context, 

1134 mesh_dim_names: Optional[tuple[str, ...]] = None, 

1135 *, 

1136 param_plan: Optional[dict[str, Any]] = None, 

1137 generated_module: Any = None, 

1138) -> None: 

1139 """Bind ``module.__hp_compute__`` for every local-region boundary. 

1140 

1141 A generated local-compute forward calls 

1142 ``self.__hp_compute__(*args, **kwargs)`` on the redistributed inputs. 

1143 The bound callable is the applier's local-compute resolution 

1144 (``_resolve_local_compute_fn`` → ``functools.partial(compute_fn, module)``), 

1145 so the compute function's first argument is the boundary module and the 

1146 remaining arguments are the redistributed forward inputs. 

1147 

1148 ``injections`` is the frozen ``meta.injections`` list (``freeze_injections`` 

1149 shape); only entries with an explicit ``local_compute_fn`` are bound (the 

1150 ``region_dispatch=False`` gate that would otherwise fall back to 

1151 ``module.forward`` is deliberately NOT bound — the applier runs that path 

1152 by re-entering ``forward``, which the generated file already does as 

1153 ``_forward_impl``). ``param_plan`` (``meta.param_plan``) supplies 

1154 ``region_dispatch`` / ``ep_size`` for the factory's mesh context, exactly 

1155 as the applier reads them off a live spec. 

1156 

1157 An imported-class boundary (the class is not defined in the generated 

1158 file) has no emitted forward that could call ``__hp_compute__``; for 

1159 those the native local-region skeleton is installed instead 

1160 (:func:`_install_runtime_region_forward`). 

1161 """ 

1162 from hyper_parallel.distributed._builder.rule_resolver import ( 

1163 _resolve_local_compute_fn, 

1164 ) 

1165 from hyper_parallel.distributed._builder.parameter_sharding import _resolve_module 

1166 

1167 dense_mesh, _, expert_mesh, active_dim_names = ( 

1168 _resolve_runtime_meshes(mesh_context, mesh_dim_names) 

1169 ) 

1170 if dense_mesh is None: 

1171 raise ValueError( 

1172 "hp_bind_compute requires a DeviceMesh / MeshContext to bind compute against" 

1173 ) 

1174 if not injections: 

1175 return 

1176 for rule in injections: 

1177 if rule.get("local_compute_fn") is None: 

1178 continue 

1179 fqn = rule.get("match") 

1180 if not fqn: 

1181 raise ValueError( 

1182 f"hp_bind_compute: injection rule {rule!r} has no 'match' FQN" 

1183 ) 

1184 entry = (param_plan or {}).get(fqn, {}) 

1185 spec = _FrozenBoundarySpec(entry, rule) 

1186 module = _resolve_module(model, fqn) 

1187 compute_fn = _resolve_local_compute_fn( 

1188 module, spec, dense_mesh, active_dim_names, expert_mesh) 

1189 # External-state inline modules (e.g. Qwen3MoeSparseMoeBlock) carry an 

1190 # inlined forward and must not receive __hp_compute__, but the local 

1191 # compute factory above still has to run: it installs companion state 

1192 # such as ``experts.local_expert_count`` and the bound experts.forward 

1193 # that the inlined forward relies on. 

1194 if _is_external_state_inline_module(module, generated_module): 

1195 continue 

1196 # _resolve_local_compute_fn returns module.forward for the 

1197 # region_dispatch=False gate; that path is not a bound compute (the 

1198 # generated forward already calls _forward_impl), so it must not be 

1199 # bound as __hp_compute__. 

1200 if compute_fn is None or compute_fn is module.forward: 

1201 continue 

1202 if _has_lowered_forward(module, generated_module): 

1203 module.__hp_compute__ = compute_fn 

1204 continue 

1205 # An imported-class boundary has no emitted forward that could call 

1206 # ``__hp_compute__``: install the native local-region skeleton 

1207 # instead (boundary entry -> injected compute -> boundary exit), the 

1208 # same code path the native applier runs for this boundary. 

1209 _install_runtime_region_forward( 

1210 module, spec, compute_fn, dense_mesh, active_dim_names 

1211 ) 

1212 

1213 

1214def hp_apply_inner_wrapper( 

1215 model, 

1216 injections: list[dict[str, Any]], 

1217 mesh_context, 

1218 mesh_dim_names: Optional[tuple[str, ...]] = None, 

1219 *, 

1220 param_plan: Optional[dict[str, Any]] = None, 

1221 generated_module: Any = None, 

1222) -> None: 

1223 """Install the declared inner CP wrapper on its target module. 

1224 

1225 A generated redistribution forward delegates computation to 

1226 ``_forward_impl``. The 

1227 CP K/V all-gather wrapper is applied to ``target.forward`` IN PLACE by the 

1228 applier (``_wrap_inner_attention``), which is not bindable as a method 

1229 without changing its invocation contract. This helper repeats that 

1230 one-shot installation from the frozen ``meta.injections``, so the 

1231 wrapper's ``compute`` runs inside the ``_forward_impl`` call at train time. 

1232 

1233 Uses the applier's own resolution chain — ``_wrap_inner_attention`` 

1234 resolves the registry name / Target / callable, resolves the target, and 

1235 installs the dual-mode adapter (production pass-through / validate local 

1236 re-wrap) via ``_install_inner_adapter``. This is the one CP path for a 

1237 generated artifact: the wrapper is applied on the module whose forward is 

1238 the emitted boundary form (the rendered fused attention), so the companion 

1239 ``attention_interface`` swap and the boundary redistribution compose 

1240 instead of being re-implemented per component. 

1241 """ 

1242 from hyper_parallel.distributed._builder.applier import ( 

1243 _get_cp_submesh, 

1244 _get_ep_submesh, 

1245 _get_tp_submesh, 

1246 ) 

1247 from hyper_parallel.distributed._builder.forward_rewriter import ( 

1248 _wrap_inner_attention, 

1249 ) 

1250 from hyper_parallel.distributed._builder.parameter_sharding import _resolve_module 

1251 

1252 dense_mesh, _, expert_mesh, active_dim_names = ( 

1253 _resolve_runtime_meshes(mesh_context, mesh_dim_names) 

1254 ) 

1255 if dense_mesh is None: 

1256 raise ValueError( 

1257 "hp_apply_inner_wrapper requires a DeviceMesh / MeshContext to install against" 

1258 ) 

1259 if not injections: 

1260 return 

1261 dim_names = tuple(active_dim_names) if active_dim_names else () 

1262 cp_mesh = _get_cp_submesh(dense_mesh, dim_names) 

1263 tp_mesh = _get_tp_submesh(dense_mesh, dim_names) 

1264 ep_mesh = _get_ep_submesh(dense_mesh, dim_names) or expert_mesh 

1265 for rule in injections: 

1266 if rule.get("inner_wrapper") is None: 

1267 continue 

1268 fqn = rule.get("match") 

1269 if not fqn: 

1270 raise ValueError( 

1271 f"hp_apply_inner_wrapper: injection rule {rule!r} has no " 

1272 "'match' FQN" 

1273 ) 

1274 entry = (param_plan or {}).get(fqn, {}) 

1275 spec = _FrozenBoundarySpec(entry, rule) 

1276 module = _resolve_module(model, fqn) 

1277 if _is_external_state_inline_module(module, generated_module): 

1278 continue 

1279 # The applier's boundary loop runs _resolve_local_compute_fn even for 

1280 # inner-wrap boundaries, and the preflight fails fast on a missing 

1281 # region_dispatch. Reuse the exact applier entry here for parity. 

1282 _wrap_inner_attention( 

1283 module, 

1284 cp_mesh, 

1285 spec=spec, 

1286 mesh=dense_mesh, 

1287 mesh_dim_names=dim_names, 

1288 tp_mesh=tp_mesh, 

1289 ep_mesh=ep_mesh, 

1290 ) 

1291 

1292 

1293def _has_lowered_forward(module: Any, generated_module: Any = None) -> bool: 

1294 """Return whether the generated source already owns this boundary wrapper.""" 

1295 if _is_external_state_inline_module(module, generated_module): 

1296 return True 

1297 return hasattr(module, "_forward_impl") 

1298 

1299 

1300def _is_tp_sequence_parallel_embed_entry(entry: dict[str, Any]) -> bool: 

1301 """Return whether an embedding output is reduce-scattered over sequence.""" 

1302 out_src = (entry.get("out_src") or {}).get("output") or {} 

1303 out_dst = (entry.get("out_dst") or {}).get("output") or {} 

1304 return ( 

1305 str(out_src.get("tp", "")).startswith("P(") 

1306 and out_dst.get("tp") == "S(1)" 

1307 ) 

1308 

1309 

1310def _wrap_default_position_ids(module: Any) -> None: 

1311 """Build default position ids before an embedding sequence reduce-scatter. 

1312 

1313 Transformers commonly derives missing position ids from ``inputs_embeds``. 

1314 A generated model's vocab-parallel embedding may already have changed that 

1315 tensor from TP-replicated sequence length to a TP sequence shard. Supplying 

1316 the default from the still-replicated ``input_ids`` keeps rotary embeddings 

1317 in the attention boundary's declared TP-replicated layout. 

1318 """ 

1319 if getattr(module, "_codegen_position_ids_wrapped", False): 

1320 return 

1321 original_forward = module.forward 

1322 signature = inspect.signature(original_forward) 

1323 if ( 

1324 "input_ids" not in signature.parameters 

1325 or "position_ids" not in signature.parameters 

1326 ): 

1327 return 

1328 positional_names = [ 

1329 name 

1330 for name, parameter in signature.parameters.items() 

1331 if parameter.kind in ( 

1332 inspect.Parameter.POSITIONAL_ONLY, 

1333 inspect.Parameter.POSITIONAL_OR_KEYWORD, 

1334 ) 

1335 ] 

1336 position_index = ( 

1337 positional_names.index("position_ids") 

1338 if "position_ids" in positional_names 

1339 else None 

1340 ) 

1341 

1342 @functools.wraps(original_forward) 

1343 def codegen_position_ids_forward(*args: Any, **kwargs: Any) -> Any: 

1344 """Supply replicated default position ids to the original model forward.""" 

1345 bound = signature.bind_partial(*args, **kwargs) 

1346 if bound.arguments.get("position_ids") is not None: 

1347 return original_forward(*args, **kwargs) 

1348 input_ids = bound.arguments.get("input_ids") 

1349 if input_ids is None: 

1350 return original_forward(*args, **kwargs) 

1351 

1352 past_key_values = bound.arguments.get("past_key_values") 

1353 past_seen_tokens = ( 

1354 past_key_values.get_seq_length() if past_key_values is not None else 0 

1355 ) 

1356 import torch # pylint: disable=C0415 

1357 

1358 position_ids = torch.arange( 

1359 int(input_ids.shape[-1]), 

1360 dtype=input_ids.dtype, 

1361 device="cpu", 

1362 ) 

1363 position_ids = (position_ids + past_seen_tokens).unsqueeze(0).to(input_ids.device) 

1364 if position_index is not None and position_index < len(args): 

1365 call_args = list(args) 

1366 call_args[position_index] = position_ids 

1367 return original_forward(*call_args, **kwargs) 

1368 call_kwargs = kwargs.copy() 

1369 call_kwargs["position_ids"] = position_ids 

1370 return original_forward(*args, **call_kwargs) 

1371 

1372 module.forward = codegen_position_ids_forward 

1373 module._codegen_position_ids_wrapped = True 

1374 module._codegen_original_position_ids_forward = original_forward 

1375 

1376 

1377def _install_vocab_parallel_embedding(module: Any, tp_mesh: Any) -> None: 

1378 """Install native's D-02 masked-embedding wrapper, once per module. 

1379 

1380 The wrapper itself is native 

1381 (``forward_rewriter._wrap_vocab_parallel_embedding``): codegen installs the 

1382 boundary before its one-shot parameter unwrap, and native derives the 

1383 vocab interval from the local shard, so both paths share one 

1384 implementation. Only the re-install guard is codegen-local — 

1385 ``hp_install_boundaries`` is documented idempotent, while native Phase C 

1386 runs exactly once. 

1387 """ 

1388 if getattr(module, "_codegen_vocab_parallel_wrapped", False): 

1389 return 

1390 from hyper_parallel.distributed._builder.forward_rewriter import ( # pylint: disable=C0415 

1391 _wrap_vocab_parallel_embedding, 

1392 ) 

1393 

1394 _wrap_vocab_parallel_embedding(module, tp_mesh) 

1395 module._codegen_vocab_parallel_wrapped = True 

1396 

1397 

1398# --------------------------------------------------------------------------- 

1399# Generated entry-point dispatch 

1400# --------------------------------------------------------------------------- 

1401 

1402def parallelize_from_generated( 

1403 model, 

1404 mesh_context, 

1405 artifact_dir: str, 

1406 *, 

1407 hf_config: Any = None, 

1408) -> dict[str, tuple[Any, Any]]: 

1409 """Run the generated module's ``hp_parallelize`` entry point. 

1410 

1411 The entry point is taken from ``meta.entrypoints["parallelize"]`` and must 

1412 return ``tp_grad_info`` with the same semantics as 

1413 ``apply_sharding_plan()``. Infrastructure validates the metadata before 

1414 dispatch, so this function repeats the check only when called directly 

1415 with ``hf_config``. 

1416 """ 

1417 meta = load_codegen_meta(artifact_dir) 

1418 if meta is None: 

1419 raise FileNotFoundError( 

1420 f"codegen: no meta at {os.path.join(artifact_dir, 'codegen_meta.json')}; " 

1421 "cannot parallelize from the generated module" 

1422 ) 

1423 if hf_config is not None: 

1424 verify_codegen_signature(meta, hf_config) 

1425 module = import_generated_module(artifact_dir) 

1426 # The artifact's own record of which generated classes take their parallel 

1427 # state externally — declared once by the adapter render spec and carried 

1428 # here in ``meta``. 

1429 register_external_state_classes(module, meta.external_state_classes) 

1430 entry_name = meta.entrypoints.get("parallelize") 

1431 entry = getattr(module, entry_name, None) if entry_name else None 

1432 if entry is not None: 

1433 return entry(model, mesh_context) 

1434 return _parallelize_inline_from_meta(model, mesh_context, meta, module) 

1435 

1436 

1437def _parallelize_inline_from_meta(model: Any, mesh_context: Any, meta: CodegenMeta, generated_module: Any) -> dict: 

1438 """Parallelize a clean inline artifact whose model file carries no plan globals. 

1439 

1440 Execution is convergent with the native applier (see 

1441 :func:`_parallelize_via_native_apply`): Phase A parameter sharding / 

1442 B special handlers / D tied weights run against a live ``ShardingPlan`` 

1443 rebuilt from the frozen meta; Phase C forward assembly stays codegen-owned 

1444 because the generated file pre-rewrites forward. 

1445 """ 

1446 return _parallelize_via_native_apply(model, mesh_context, meta, generated_module) 

1447 

1448 

1449def _rebuild_live_plan_from_meta(meta: CodegenMeta): 

1450 """Rebuild a live ``ShardingPlan`` from the frozen meta (meta -> plan). 

1451 

1452 Proof-of-concept reconstruction: re-parses the frozen literal forms back 

1453 into real ``Placement``/``Target`` objects so native builder helpers 

1454 (``_shard_planned_parameters`` / ``_apply_plan_special_handlers`` / 

1455 ``_replicate_tied_weights``) can consume this plan exactly as they consume 

1456 a planner-produced one. 

1457 

1458 Which fields cross the meta boundary is declared in 

1459 :mod:`hyper_parallel.codegen.plan.spec_fields` — freeze and this rebuild 

1460 walk the same table, so the two sides cannot drift apart. ``init=False`` 

1461 fields (``_deferred_bias_params``, D-22) are rebuilt via ``setattr`` 

1462 after construction (``POST_INIT_SPEC_FIELDS``). Exempt fields (never 

1463 frozen): 

1464 - ``_is_terminal`` — validate-mode only, not used in production; 

1465 - ``_tp_local_attr_plan`` — planner-derived; the rebuilt spec leaves it 

1466 None and ``maybe_update_head_counts`` takes its backward-compatible 

1467 path (auto attrs via the head-sharded heuristic, user attrs via the 

1468 rebuilt ``tp_divide_attrs``); 

1469 - ``_needs_cp_attn`` / ``_resolved_inner_*`` — apply-time preflight and 

1470 introspection state, not consumed on the rebuild path. 

1471 

1472 Injection-side fields (``local_compute_fn`` / ``inner_wrapper`` / 

1473 ``inner_out_src``) are reconstructed with the same :func:`_injection_target` 

1474 the existing ``_FrozenBoundarySpec`` uses, so injection fidelity matches 

1475 the status-quo codegen path. 

1476 """ 

1477 from hyper_parallel.distributed.plan import ShardingPlan 

1478 from hyper_parallel.distributed.recipe_spec import ModuleShardingSpec 

1479 from hyper_parallel.codegen.plan.spec_fields import ( 

1480 INJECTION_SPEC_FIELDS, 

1481 PARAM_PLAN_SPEC_FIELDS, 

1482 POST_INIT_SPEC_FIELDS, 

1483 ) 

1484 

1485 by_fqn: dict[str, Any] = {} 

1486 for rule in meta.injections or []: 

1487 if isinstance(rule, dict) and rule.get("match"): 

1488 by_fqn[rule["match"]] = rule 

1489 

1490 modules: dict[str, Any] = {} 

1491 for fqn, entry in (meta.param_plan or {}).items(): 

1492 inj = by_fqn.get(fqn, {}) 

1493 kwargs: dict[str, Any] = { 

1494 field.name: _rebuild_spec_field(field, entry) 

1495 for field in PARAM_PLAN_SPEC_FIELDS 

1496 if not field.post_init 

1497 } 

1498 for field in INJECTION_SPEC_FIELDS: 

1499 kwargs[field.name] = _rebuild_spec_field(field, inj) 

1500 spec = ModuleShardingSpec(**kwargs) 

1501 for field in POST_INIT_SPEC_FIELDS: 

1502 value = _rebuild_spec_field(field, entry) 

1503 if value is not None: 

1504 setattr(spec, field.name, value) 

1505 modules[fqn] = spec 

1506 

1507 return ShardingPlan( 

1508 modules=modules, 

1509 special_handlers=dict(meta.special_handlers or {}), 

1510 mesh_dim_names=tuple(meta.mesh_dim_names or ()), 

1511 tied_pairs=[tuple(pair) for pair in (meta.tied_pairs or [])], 

1512 ) 

1513 

1514 

1515def _rebuild_spec_field(field: Any, source: dict[str, Any]) -> Any: 

1516 """Deserialize one spec field per its :class:`SpecField` kind contract. 

1517 

1518 The inverse of freeze's ``_freeze_spec_field``: reads the field's meta 

1519 key from the frozen entry (param-plan fields) or injection rule 

1520 (injection fields) and restores the live value. Absent keys restore the 

1521 dataclass defaults — ``None`` for optional declarations, ``True`` for 

1522 ``is_boundary`` (pre-flag metas), ``{}``/``0`` for the EP internals — 

1523 matching what ``_rebuild_live_plan_from_meta`` passed positionally 

1524 before the table drove both sides. 

1525 """ 

1526 kind, key = field.rebuild, field.key 

1527 if kind == "placement_map": 

1528 # Key absent/None -> None (not declared); an explicit {} ("shards 

1529 # nothing") must round-trip as {} — Phase A iterates params.items() 

1530 # and a None there is the crash this rebuild must not reintroduce. 

1531 if source.get(key) is None: 

1532 return None 

1533 return parse_named_placement(source[key]) 

1534 if kind == "named_placements": 

1535 return parse_named_placement(source[key]) if source.get(key) else None 

1536 if kind in ("name_list", "attr_list"): 

1537 return list(source[key]) if source.get(key) is not None else None 

1538 if kind == "bool_default_true": 

1539 return bool(source[key]) if source.get(key) is not None else True 

1540 if kind == "injection_target": 

1541 return _injection_target(source[key]) if source.get(key) is not None else None 

1542 if kind == "dict_copy": 

1543 return dict(source[key]) if source.get(key) else {} 

1544 if kind == "int_truthy": 

1545 return source.get(key) or 0 

1546 if kind == "tuple_empty": 

1547 # D-22 param paths: absent/empty restores the dataclass default () 

1548 # — consumers iterate the tuple, so None would crash. 

1549 return tuple(source[key]) if source.get(key) else () 

1550 # opt_scalar 

1551 return source.get(key) 

1552 

1553 

1554def _parallelize_via_native_apply( 

1555 model: Any, 

1556 mesh_context: Any, 

1557 meta: CodegenMeta, 

1558 generated_module: Any, 

1559) -> dict: 

1560 """Reuse the native execution body for a codegen artifact. 

1561 

1562 Rebuilds a live ``ShardingPlan`` from the frozen meta 

1563 (:func:`_rebuild_live_plan_from_meta`) and runs native Phase A 

1564 (``_shard_planned_parameters``) / B (``_apply_plan_special_handlers``) / 

1565 D (``_replicate_tied_weights``) against it. This is the converging 

1566 execution path: codegen no longer maintains a second literal 

1567 parameter-sharding replay. 

1568 

1569 Phase C forward assembly is deliberately NOT reused: the generated file 

1570 has already rewritten every boundary's ``forward`` into the 

1571 redistribute-in / ``_forward_impl`` / redistribute-out form (resolved at 

1572 runtime against the ``_hp_boundary`` / ``__hp_compute__`` bound 

1573 here). Native ``_apply_phase_c`` captures the *current* forward as its 

1574 ``original_forward`` and wraps it in ANOTHER 

1575 ``redistribute_inputs -> original -> redistribute_outputs`` — running it 

1576 on a codegen artifact double-wraps the redistribution (double TP/EP 

1577 communication) because no native branch skips the wrap. So full 

1578 ``apply_sharding_plan`` reuse is not viable; A/B/D reuse with codegen-owned 

1579 Phase C is the minimum viable convergence. 

1580 

1581 MoE/EP artifacts are supported: native Phase A applies the same 

1582 ``_stack_moe_experts`` step here as it does for a planner-produced plan, so 

1583 dense and MoE topologies share this one reuse path. 

1584 """ 

1585 from hyper_parallel.distributed.mesh import MeshContext # pylint: disable=C0415 

1586 from hyper_parallel.distributed._builder.applier import ( # pylint: disable=C0415 

1587 _apply_plan_special_handlers, 

1588 _get_active_mesh, 

1589 _get_tp_submesh, 

1590 ) 

1591 from hyper_parallel.distributed._builder.parameter_sharding import ( # pylint: disable=C0415 

1592 _replicate_tied_weights, 

1593 _resolve_parameter_source_meshes, 

1594 _shard_planned_parameters, 

1595 detect_tied_weights, 

1596 ) 

1597 

1598 plan = _rebuild_live_plan_from_meta(meta) 

1599 mesh_dim_names = plan.mesh_dim_names 

1600 param_plan = meta.param_plan or {} 

1601 injections = hp_expand_injections(meta.injections or []) 

1602 

1603 mc = mesh_context if isinstance(mesh_context, MeshContext) else None 

1604 device_mesh = mc.device_mesh if mc is not None else mesh_context 

1605 if device_mesh is None: 

1606 raise ValueError( 

1607 "native A/B/D reuse requires a DeviceMesh / MeshContext" 

1608 ) 

1609 mesh = _get_active_mesh(device_mesh, mesh_dim_names) 

1610 tp_mesh = _get_tp_submesh(mesh, mesh_dim_names) 

1611 expert_mesh, dense_source_mesh, expert_source_mesh = ( 

1612 _resolve_parameter_source_meshes(plan, mesh_context, device_mesh, tp_mesh) 

1613 ) 

1614 

1615 # Native A / B / D are executed against the reconstructed live plan. 

1616 _shard_planned_parameters([model], plan, mesh, expert_mesh, validate_mode=False) 

1617 _apply_plan_special_handlers([model], plan, mesh) 

1618 _replicate_tied_weights(model, list(plan.tied_pairs) or detect_tied_weights(model)) 

1619 

1620 # Native C is not reusable (see docstring) — keep the codegen forward 

1621 # assembly that matches the pre-rewritten generated file. 

1622 hp_install_boundaries( 

1623 model, 

1624 param_plan, 

1625 mesh_context, 

1626 mesh_dim_names, 

1627 injections=injections, 

1628 generated_module=generated_module, 

1629 ) 

1630 hp_bind_inline_state( 

1631 model, 

1632 mesh_context, 

1633 mesh_dim_names, 

1634 generated_module=generated_module, 

1635 ) 

1636 hp_bind_compute( 

1637 model, 

1638 injections, 

1639 mesh_context, 

1640 mesh_dim_names, 

1641 param_plan=param_plan, 

1642 generated_module=generated_module, 

1643 ) 

1644 hp_apply_inner_wrapper( 

1645 model, 

1646 injections, 

1647 mesh_context, 

1648 mesh_dim_names, 

1649 param_plan=param_plan, 

1650 generated_module=generated_module, 

1651 ) 

1652 return hp_build_tp_grad_info( 

1653 model, plan, dense_source_mesh, expert_source_mesh 

1654 ) 

1655 

1656 

1657__all__ = [ 

1658 "hp_apply_inner_wrapper", 

1659 "hp_bind_compute", 

1660 "hp_bind_inline_state", 

1661 "hp_build_tp_grad_info", 

1662 "hp_install_boundaries", 

1663 "hp_to_local_if_dtensor", 

1664 "import_generated_module", 

1665 "load_codegen_meta", 

1666 "parallelize_from_generated", 

1667 "verify_codegen_signature", 

1668]