Skip to content

feat: dynamic memory-aware GPU scheduling for model-free PTQ - #2976

Open
rohan9446 wants to merge 8 commits into
vllm-project:mainfrom
rohan9446:feat/dynamic-gpu-scheduler
Open

feat: dynamic memory-aware GPU scheduling for model-free PTQ#2976
rohan9446 wants to merge 8 commits into
vllm-project:mainfrom
rohan9446:feat/dynamic-gpu-scheduler

Conversation

@rohan9446

Copy link
Copy Markdown

SUMMARY:

Fixes #2975, replaces the static round-robin GPU assignment in model-free PTQ with a dynamic, memory-aware scheduler.

Problem

PR #2773 introduced multi-GPU support by statically assigning shards to GPUs via devices[i % len(devices)]. When shards differ in size or GPUs differ in speed, the slower GPU accumulates pending work and eventually OOMs. This was observed on 6-GPU setups.

Solution

New scheduler.py module with a capacity-first scheduling loop:

  • Dynamic device selection: before submitting each job, the main thread calls torch.get_device_module(dev).mem_get_info() and picks the GPU with the most free VRAM
  • Reservation tracking: submitted-but-not-yet-allocated memory is tracked per device, preventing multiple jobs from stacking on the same GPU in a single scheduling pass
  • Forced fallback: if no device can fit any pending job and nothing is in flight, the smallest job is forced onto the most-free device with a warning (instead of silently dropping work)
  • Caching allocator flush: empty_cache() is called after harvesting each completed future so mem_get_info reflects actually-free memory
  • concurrent.futures.wait(FIRST_COMPLETED) replaces a hand-rolled threading.Event callback, eliminating a lost-wakeup race

_build_jobs() no longer takes a devices parameter — device assignment is deferred entirely to the scheduler. Validation still uses upstream exec_jobs (it runs on meta device, so no scheduling needed).

Behavioral change

max_workers now sets an upper bound on concurrency rather than a fixed thread count. Effective concurrency may be lower when GPU memory is tight. This also prevents OOMs caused by users picking too many workers.

TEST PLAN:

Unit tests (test_scheduler.py, no GPU required — runs on all CI):

  • estimate_job_memory: verifies sum-of-file-sizes × multiplier
  • _pick_device: most-free selection, returns None when nothing fits, respects reservation accounting, CPU always eligible
  • exec_jobs_dynamic CPU path: all jobs complete, empty input, order preservation

Integration tests (test_multi_gpu.py, @requires_gpu(2)):

  • test_multi_gpu_matches_single_gpu: saves Qwen3-0.6B with max_shard_size="1MB" (~198 shards), quantizes with FP8_dynamic on 1 GPU vs N GPUs, asserts bitwise tensor equality
  • test_multi_gpu_more_workers_than_shards: verifies graceful handling when max_workers > len(jobs)

Validated on:

  • 2× NVIDIA RTX PRO 6000 Blackwell (homogeneous), Ubuntu 24.04, PyTorch 2.13.0+cu130
  • make quality passes (ruff check + ruff format + tools/lint_cuda.py)
  • All 11 tests pass

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8800efba-2d9f-46b4-a744-abcfa9d924b8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to llm-compressor. Please add the ready label when the PR is ready for review.

Note: This is required to complete the testing suite, please only add the label once the PR is code complete and local testing has been performed.

@mergify mergify Bot added the two-reviews When a PR requires two reviews label Jul 28, 2026
@mergify

mergify Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 1 of 2 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 Require two reviews 👀 reviews
🟢 Require one maintainer review

🔴 Require two reviews

Waiting for

  • #approved-reviews-by >= 2
This rule is failing.

PRs labelled "two-reviews" must have at least two approving reviews before merging.

  • #approved-reviews-by >= 2
  • #changes-requested-reviews-by = 0

Show 1 satisfied protection

🟢 Require one maintainer review

All PRs must have at least one approving review from a maintainer before merging.

  • #changes-requested-reviews-by = 0
  • any of:
    • approved-reviews-by=kylesayrs
    • approved-reviews-by=HDCharles
    • approved-reviews-by=brian-dellabetta
    • approved-reviews-by=dsikka
    • approved-reviews-by=yiliu30

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces a memory-aware dynamic job scheduler for multi-GPU model-free PTQ, replacing the previous static round-robin assignment with capacity-first scheduling based on real-time free VRAM. The reviewer provided valuable feedback to improve robustness and backward compatibility. Specifically, they recommended guarding device-module and cache-clearing operations against CPU devices and missing attributes to prevent runtime crashes, ensuring empty_cache() is called in the single-worker path to avoid false out-of-memory assumptions, and replacing torch.accelerator with torch.cuda in tests to maintain compatibility with PyTorch versions older than 2.4.

Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
@rohan9446
rohan9446 force-pushed the feat/dynamic-gpu-scheduler branch from 15e596d to fd12f99 Compare July 28, 2026 16:01
Replaces static round-robin device assignment with a capacity-first
scheduler that checks real-time GPU memory before each job submission.

Key changes:
- New scheduler module with reservation tracking, caching allocator
  flush, and forced-fallback when nothing fits
- model_free_ptq builds jobs without device assignment; scheduler
  picks GPUs dynamically at submit time

Closes vllm-project#2975

Signed-off-by: Rohan Bandaru <rohanbanadaru14838@gmail.com>
@rohan9446
rohan9446 force-pushed the feat/dynamic-gpu-scheduler branch from fd12f99 to d109158 Compare July 28, 2026 16:20
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py
Comment thread src/llmcompressor/entrypoints/model_free/__init__.py
Comment thread src/llmcompressor/entrypoints/model_free/__init__.py
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Rohan Bandaru added 2 commits July 28, 2026 20:19
Signed-off-by: Rohan Bandaru <rohanbanadaru14838@gmail.com>
Signed-off-by: Rohan Bandaru <rohanbanadaru14838@gmail.com>
@rohan9446
rohan9446 requested a review from kylesayrs July 29, 2026 03:56

@kylesayrs kylesayrs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice job! Pinging @brian-dellabetta for review

Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Rohan Bandaru and others added 2 commits July 30, 2026 12:52

@brian-dellabetta brian-dellabetta left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @rohan9446 , thanks for preparing this. i have a handful of comments/questions, particularly whether we want this just in the model-free-ptq pathway and not the convert_checkpoint pathway in compressed-tensors. We have some work underway to consolidate the 2 entirely:

Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/scheduler.py Outdated
Comment thread src/llmcompressor/entrypoints/model_free/__init__.py
…uling, rename test

Signed-off-by: Rohan Bandaru <rohanbanadaru14838@gmail.com>
@kylesayrs
kylesayrs enabled auto-merge (squash) August 14, 2026 23:06

@kylesayrs kylesayrs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

two-reviews When a PR requires two reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ModelFreePTQ] Memory issues with multi-gpu

3 participants