Repository navigation
[AffineIR] Analyze affine transfer batches before execution (Plan analysis & calibration Part-1) - #8967
[AffineIR] Analyze affine transfer batches before execution (Plan analysis & calibration Part-1)#8967jinyouzhi wants to merge 7 commits into
Conversation
Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
Address review on the affine transfer executor: - Decide stream-ordered completion with is_synchronized_device() instead of the device type, for both the per-round handle and the final stream synchronization. - Run the multi-rank executor tests on any accelerator. The disjoint-endpoint case now uses two or four ranks, so it fits the two-device PR runners and the four-rank CPU nightly. - Move the executor documentation from the AutoEP page to a new Checkpointing API page, and record that the staging arena and StagingBudget belong to the current torch point-to-point transport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
RL frameworks build their trainer <-> engine weight-update group
outside the default world: each process keeps its own default group
(world size 1 for a TP=1 trainer or engine) and joins a separate group
created with _new_process_group_helper on its own store, as slime,
SGLang and vLLM do. torch's rank bookkeeping for such a group maps
every member's default-world rank 0 to group rank 0, so
dist.get_rank(group) returned 0 on both ends and the preflight refused
the whole batch ("target location 0 is not owned by this process").
When a group is passed, read the rank and size from the group itself.
Every other path is unchanged.
Add a CPU reproduction: two processes, each with a world-size-1
default group, joined by an externally created gloo group. It fails
before this change and passes after it. The new test file builds that
group with torch.distributed directly, so it joins the existing
check-torchdist exclusion next to tests/unit/comm/test_dist.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
The test builds the trainer <-> engine weight-update group the way RL frameworks do, outside deepspeed.comm, so calling torch.distributed directly is intended. Say so next to the import, as requested in review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
Add calibrate_links/fit_links: raw local, pairwise, concurrent, 1-to-N and N-to-1 timings labelled by a path_of(from, to) hook, with a per-path alpha + bytes/bandwidth summary, as measured inputs for transfer cost models. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
Add analyze_transfers/expected_stats/report_to_dict: a dry-run report of an execute_transfers batch (volume, size distributions, rounds under a StagingBudget, per-process load and staging, per-pair and per-path bytes), labelled with the same path_of hook as calibrate_links. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
0z5a
left a comment
There was a problem hiding this comment.
Read the last commit (72081c1b). The report is what a policy or cost model needs: per-process sent and received bytes, rounds and messages give the bandwidth and per-message terms, and expected_stats matching the executor's TransferStats on 4 ranks is a good anchor. It passes on CPU (gloo, 4 ranks) here.
I checked the schedule reconstruction against the executor at e38477d7. The direct-send test (_is_packed versus region.is_contiguous()), the per-peer, per-direction arena sized by the largest staged round, and rounds as the maximum over a process's peer queues all match today. Two structural suggestions:
- Share the schedule instead of re-deriving it. The module imports the executor's private
_packed_rounds, andbuild_operationsisn't in its__all__either. It then re-implements the direct-versus-staged decision and the arena sizing. Those will drift when the executor's staging changes.staging_bytesin particular isn't covered by theexpected_statscomparison, sinceTransferStatshas no staging field. Would a public schedule helper in the executor work for you, returning each peer's rounds and whether each round is sent directly? Both sides could then call it. - Ordering. This stacks on #8966 only for
LOCALanddefault_path_of. Defining those here, or in a small shared module that calibration imports, would let this land first.
Minor: the report numbers processes by transport-group rank, while calibration uses default-group ranks, so the path labels join only when the two groups coincide. The docstring says so, but recording that assumption in the report itself would stop a consumer from mixing the two.
Analyze affine transfer batches before execution
Stacked on #8809 (executor) and #8966 (calibration path labels). Only the last commit is new.
Why
Plans that move the same bytes can differ a lot in time (up to 1.75× on 8× B70 between replica choices), and executor measurements show that the round count under a
StagingBudgetdominates sync time. A policy (#8935/#8936) or cost model (#8252) needs these facts before it runs a plan.What
deepspeed/checkpoint/affine_transfer_analysis.py:analyze_transfers(plans, endpoints, element_size, budget, path_of)is a pure function with no communication. It replays the executor'sbuild_operationsand round packing and reports:expected_stats(report, process)predicts that process'sTransferStats.report_to_dictreturns a JSON-ready summary.path_oflabels ascalibrate_links, so per-path totals can be priced withfit_links.It does not choose replicas, rank plans, or model time.
Note: it imports the executor's private
_packed_rounds/build_operations. @0z5a, would a public dry-run schedule API on the executor be preferable?Tests
expected_stats== the executor'sTransferStats, for a strided and a replicated parameter under budgets of 3 and 64 elements.Results: 6 passed on 4× L20 (nccl) and on 4× Intel Arc Pro B70 (xccl). Mutation checks (dropping the receiver's round count, or the local bytes in the path summary) are caught.