Skip to content

refactor: centralize speculative weight-update fan-out in the scheduler - #28548

Merged
yueming-yuan merged 2 commits into
sglang-milesfrom
refactor/spec-update-weights-fanout
Jun 17, 2026
Merged

refactor: centralize speculative weight-update fan-out in the scheduler#28548
yueming-yuan merged 2 commits into
sglang-milesfrom
refactor/spec-update-weights-fanout

Conversation

@guapisolo

@guapisolo guapisolo commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Centralize speculative weight-update fan-out in the scheduler via get_model_runners.

Motivation

update_weights_from_distributed / update_weights_from_tensor dispatched to self.draft_worker or self.tp_worker, and each of the 7 speculative workers re-implemented forwarding that hard-coded which runners to update — duplicating the runner-set knowledge iter_draft_runners() already encodes (introduced in #27749). The online weight-update behavior for the target and draft runners is unchanged; only where runner selection lives changes.

Before / After

  • Before: each speculative worker (eagle_worker, eagle_worker_v2, multi_layer_eagle_worker, multi_layer_eagle_worker_v2, frozen_kv_mtp_worker, ngram_worker, dflash_worker) built its own [draft..., target] runner list for update_weights_from_distributed_to_model_runners.
  • After: update_weights_from_distributed / _from_tensor in SchedulerUpdateWeightsMixin resolve the runner list once via get_model_runners(selector).
  • Distributed load: model_runner.update_weights_from_distributed_to_model_runners receives the broadcast once for all selected runners.
  • Tensor load: the mixin deserializes serialized_named_tensors[self.tp_rank] once for all selected runners.
  • What moved where: runner selection moved out of the 7 workers into the scheduler mixin.
  • Deleted: the per-worker update_weights_from_distributed / update_weights_from_tensor methods.
  • Worker surface: speculative workers now expose only iter_draft_runners().
  • API: disable_draft_model on the two UpdateWeights*ReqInput structs becomes the unified {target, draft} selector (default both).

Behavior Preservation

  • Scheduler fan-out: test_distributed_weight_update_spec_worker.py asserts one distributed receive loads into target plus draft.
  • Selector scope: the same test asserts a target-only selector skips the draft worker.
  • Checker unchanged: the weight-checker suites (test_check_weights_draft_fanout.py, test_weight_checker.py) still pass.
  • Behavior change: DFlash's draft runner is now refreshed on a distributed update.

Verification

  • Unit suite: 102 tests pass (fanout 31, _cuda 5, distributed-spec-worker 3, weight-checker 63).
  • Lint: ruff --select F401,F821, black --check, isort --check clean on the touched files.

Review Focus

  • Scrutinize update_weights_from_tensor in scheduler_update_weights_mixin.py for the once-only deserialize across selected runners.
  • Scrutinize the disable_draft_model to selector swap on the request structs.
  • Verify get_model_runners keeps the target first so the target owns the distributed update group.

CI States

Latest PR Test (Base): ❌ Missing run-ci label -- add it to run CI tests.
Latest PR Test (Extra): ❌ Blocked -- run-ci is required first.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@guapisolo
guapisolo force-pushed the refactor/spec-update-weights-fanout branch from fd31e41 to 7c1f636 Compare June 17, 2026 19:26
@github-actions github-actions Bot added the lora label Jun 17, 2026
@guapisolo
guapisolo changed the base branch from fix/mtp_weight_checker to sglang-miles June 17, 2026 19:44
…duler

Replace the per-worker update_weights_from_distributed / _from_tensor
forwarding added in #27749 with a single scheduler-side fan-out. The
scheduler resolves the runner list via get_model_runners(selector)
(target + drafts via each worker's iter_draft_runners); the target
runner owns the distributed update group, receives the broadcast once,
and loads the weights into every selected runner. The tensor path
deserializes once on the scheduler and loads into each selected runner.

Delete the per-worker forwarding methods in the 7 speculative workers;
they now only expose iter_draft_runners (TpModelWorker provides the base
implementation; draft-capable workers override it). Replace the ad-hoc
disable_draft_model field on the distributed/tensor request structs with
the unified {target,draft} selector (default both; "target" =
target-only); no caller sent disable_draft_model. This also closes the
DFlash stale-draft gap — its iter_draft_runners now fans the update out
to the draft runner.

Rewrite test_distributed_weight_update_spec_worker.py for the new
scheduler fan-out contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@guapisolo
guapisolo force-pushed the refactor/spec-update-weights-fanout branch from 7c1f636 to cc58960 Compare June 17, 2026 19:56
The fan-out commit routed update_weights_from_distributed through
ModelRunner.update_weights_from_distributed_to_model_runners(model_runners,
...), which made one ModelRunner iterate over sibling runners and load into
each — runner-set enumeration leaking into the runner layer (tech debt from
#27749).

Move the loop up to the scheduler so ModelRunner exposes only single-runner
ops, symmetric with the tensor path. The target (main) model owns this
process's update group, so the scheduler has it receive the broadcast once
(receive_weights_from_distributed) and then loads the received weights into
each selected runner (load_weights). Delete the multi-runner
update_weights_from_distributed_to_model_runners, the now-dead single
ModelRunner.update_weights_from_distributed, and the caller-less
BaseTpWorker.update_weights_from_{distributed,tensor} forwarders left by the
fan-out commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yueming-yuan
yueming-yuan merged commit 1dbbf3a into sglang-miles Jun 17, 2026
2 checks passed
@yueming-yuan
yueming-yuan deleted the refactor/spec-update-weights-fanout branch June 17, 2026 21:53
guapisolo added a commit to guapisolo/sglang that referenced this pull request Jun 18, 2026
Re-implement distributed weight-update for speculative draft worker(s) on the
v2 worker layout, on top of the preceding revert of sgl-project#27749's earlier design.

Centralize the weight-update fan-out in SchedulerWeightUpdaterManager: an
UpdateWeightsFrom{Distributed,Tensor}ReqInput `selector` ({target, draft,
both}) resolves to the (role, ModelRunner) pairs to update. For distributed
updates the target model receives the broadcast once and the weights are
loaded into every selected runner locally; tensor updates deserialize once and
fan out the same way. Draft workers expose their runner(s) via
iter_draft_runners(); the per-worker update_weights_from_{distributed,tensor}
methods and the `disable_draft_model` flag are gone.

Combines sglang-miles sgl-project#27749 and sgl-project#28548.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants