Skip to content

Stabilize DeepCompile ZeRO-3 memory scheduling - #8169

Closed
tohtana wants to merge 11 commits into
deepspeedai:masterfrom
tohtana:tohtana/deepcompile-zero3-memory-stability-scheduler-standalone
Closed

Stabilize DeepCompile ZeRO-3 memory scheduling#8169
tohtana wants to merge 11 commits into
deepspeedai:masterfrom
tohtana:tohtana/deepcompile-zero3-memory-stability-scheduler-standalone

Conversation

@tohtana

@tohtana tohtana commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Depends on #8159.

Overview

DeepCompile's ZeRO-3 scheduler does not consistently account for memory pressure across gather/release ordering, prefetch, selective gathering, and native gather-buffer reuse. This can retain excess gathered storage or trigger a full-parameter gather while Dynamo evaluates guards.

This PR adds rank-consistent scheduler budgeting and diagnostics, coordinates prefetch and selective gathering with graph profiling, reuses native gather storage within a bounded pressure-aware lifecycle, and avoids guard-time full-parameter gathers while the DeepCompile eager fallback is active.

Results

The end-to-end measurements were collected.

  • Model: Qwen3-14B
  • Hardware: one node with 8 H100 GPUs
  • Activation checkpointing: enabled
  • Micro-batch size: 4
  • Sequence length: 4096
  • Measurement: 10 warmup iterations followed by 20 measured iterations
Mode Allocator retries per rank Average step time Throughput
ZeRO-3-only pass 18–19 → 0 8.4% faster 9.2% higher
Full DeepCompile pass 20 → 2–4 9.2% faster 10.1% higher

In a longer observation window covering steps 31–300, no allocator retries occurred.

tohtana added 2 commits July 22, 2026 17:50
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana tohtana changed the title Tohtana/deepcompile zero3 memory stability scheduler standalone Stabilize DeepCompile ZeRO-3 memory scheduling Jul 23, 2026
tohtana added 4 commits August 2, 2026 10:51
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana
tohtana marked this pull request as ready for review August 3, 2026 17:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55779855e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread deepspeed/utils/allocator_telemetry.py Outdated
Comment thread deepspeed/utils/allocator_telemetry.py Outdated
tohtana added 3 commits August 3, 2026 11:23
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Comment thread csrc/compile/init.cpp
m.def("register_graph_z3",
&dc::register_graph_z3,
"Register graph with a list of ds parameter ids");
m.def("set_z3_gather_buffer_pool_budget_for_test",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if these new items are just test purpose only?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these three new APIs are for testing purpose only. We need them to set or inspect the internal state of the memory pool. It doesn't look great to have these as public APIs, but I didn't have an idea about other approaches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious if it is possible to do integration test rather than unit test on this level? For example, instead of writing the scaffold to test GatherBufferPool, can do a test of functions that call the natural creation of this class, e.g. calling from Z3CustomOpExecutor?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is actually how the current tests are structured. They do not construct or call GatherBufferPool directly. register_graph_z3() creates Z3CustomOpExecutor with the shared pool, and the CUDA test runs the real allgather_param, wait_allgather, and release_param ops.
The _for_test APIs are limited to making the budget and allocator-pressure inputs deterministic and exposing accounting of internal values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, your last sentence explains my confusion. OK, maybe we can call it deterministic or pre determined size etc?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I think “fixed budget” is more precise because the test fixes the pool’s byte budget rather than individual buffer sizes. If we keep for_test, how about these

  • set_z3_gather_buffer_pool_budget_for_test -> set_z3_gather_buffer_pool_fixed_budget_for_test
  • setBudgetForTest -> setFixedBudgetForTest
  • update_z3_gather_buffer_pool_allocator_pressure_for_test -> update_z3_gather_buffer_pool_allocator_pressure_for_test

Comment thread deepspeed/compile/inductor.py
Comment thread deepspeed/compile/util.py Outdated
Comment thread csrc/compile/z3.cpp
if (!enabled_ || pressure_recovery_in_progress_) { return at::Tensor(); }

Entry* best = nullptr;
for (auto& entry : entries_) {

@pengdurice pengdurice Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is entries_ ordered? if not, is the full loop expensive vs an max heap like solution?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entries_ is currently an unsorted std::vector as we don't simply choose the maximum one (best fit to capacity, LRU for eviction, search by storage identity, etc.)
However, I don't think the scan is significant overhead. I expect the pool to contain tens of entries rather than thousands because it is byte-bounded and the dominant gather buffers are relatively large. Given an 80GB GPU, the hard cap is 80 GiB / 32 = 2.5 GiB. If we the average buffer size is 64MB, we will have 80 entries. This should be negligible in the C++ code.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small correction to my previous example: a 2.5 GiB cap with an average 64 MiB buffer gives about 40 entries, not 80.

@pengdurice

Copy link
Copy Markdown
Contributor

general question, do we have experiments results showcasing the changes' benefits?

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Comment thread csrc/compile/z3.cpp
pool = std::make_shared<GatherBufferPool>();
weak_gather_buffer_pool = pool;
if (gather_buffer_pool_test_budget) {
pool->setBudgetForTest(gather_buffer_pool_test_budget.value());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setBudgetForTest is only called when it is test purpose?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. gather_buffer_pool_test_budget is unset by default and is populated only by set_z3_gather_buffer_pool_budget_for_test().

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
@tohtana

tohtana commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

general question, do we have experiments results showcasing the changes' benefits?

Yes. We have some measurements although I have not rerun the exact current head yet.

The experiment used

  • Qwen3-14B
  • One node with 8 H100s
  • Activation checkpointing enabled
  • Micro-batch 4
  • Sequence length 4096
  • 10 warmup and 20 measured iterations

The results are:

  • With the ZeRO-3-only pass, the measured PyTorch caching-allocator retry count fell from 18–19 retries per rank to zero on every rank. Average step time improved by 8.4%, and throughput improved by 9.2%.
  • With the full DeepCompile pass, the retry count fell from 20 per rank to 2–4 per rank. Average step time improved by 9.2%, and throughput improved by 10.1%.
    For a longer run, from 31-300 steps, no allocator retry happened.

@pengdurice

Copy link
Copy Markdown
Contributor

general question, do we have experiments results showcasing the changes' benefits?

Yes. We have some measurements although I have not rerun the exact current head yet.

The experiment used

  • Qwen3-14B
  • One node with 8 H100s
  • Activation checkpointing enabled
  • Micro-batch 4
  • Sequence length 4096
  • 10 warmup and 20 measured iterations

The results are:

  • With the ZeRO-3-only pass, the measured PyTorch caching-allocator retry count fell from 18–19 retries per rank to zero on every rank. Average step time improved by 8.4%, and throughput improved by 9.2%.
  • With the full DeepCompile pass, the retry count fell from 20 per rank to 2–4 per rank. Average step time improved by 9.2%, and throughput improved by 10.1%.
    For a longer run, from 31-300 steps, no allocator retry happened.

That's great, maybe add that to the PR's description?

@pengdurice

Copy link
Copy Markdown
Contributor

the gather buffer pool and the memory budget seem to be two separate optimization, worth considering splitting to to PRs?

@tohtana

tohtana commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

the gather buffer pool and the memory budget seem to be two separate optimization, worth considering splitting to to PRs?

I split this PR and opened #8233 and #8234. Can you review these? @pengdurice
I'm closing this now.

@tohtana tohtana closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants