Skip to content

Fix slow batch generation in server by setting wired_limit#652

Merged
angeloskath merged 2 commits into
ml-explore:mainfrom
otarkhan:fix-batch-generation-wired-limit
Dec 5, 2025
Merged

Fix slow batch generation in server by setting wired_limit#652
angeloskath merged 2 commits into
ml-explore:mainfrom
otarkhan:fix-batch-generation-wired-limit

Conversation

@otarkhan

@otarkhan otarkhan commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

Summary

  • The server's batch generation path was missing the wired_limit setting that stream_generate uses, causing ~10x slower performance and ~30% GPU utilization on large models.
  • When wired_limit is not set, model weights cannot stay pinned in GPU-accessible memory, causing frequent memory paging and GPU stalls.
  • This fix sets max_recommended_working_set_size when creating the BatchGenerator and restores the previous limit when done, matching the behavior of stream_generate.

Test plan

  • Tested with large model (MiniMax-M2-Q8) - GPU utilization went from ~30% to ~100%
  • Verified tokens/second improved ~10x to match sequential generation performance

Before

Before.mp4

After

After.mp4

The server's batch generation path was missing the wired_limit setting
that stream_generate uses, causing ~10x slower performance and ~30% GPU
utilization on large models.

When wired_limit is not set, model weights cannot stay pinned in
GPU-accessible memory, causing frequent memory paging and GPU stalls.

This fix sets max_recommended_working_set_size when creating the
BatchGenerator and restores the previous limit when done, matching
the behavior of stream_generate.
@otarkhan

otarkhan commented Dec 3, 2025

Copy link
Copy Markdown
Contributor Author

@awni
Would you please take a look? I think this is an important followup change for #626

@otarkhan otarkhan mentioned this pull request Dec 3, 2025
@otarkhan

otarkhan commented Dec 3, 2025

Copy link
Copy Markdown
Contributor Author

@angeloskath for visibility

@awni

awni commented Dec 4, 2025

Copy link
Copy Markdown
Member

We do need to set the wired limit but I don't want to do it this way in the server. It couples the generation and server in a way that would be good to avoid and adds complexity to the server logic which is already quite complex.

I wonder if it could make sense to set wired limit when you construct the batch generator object and unset it when it goes out of scope?

@angeloskath angeloskath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks great to me! Thanks for adding that :-)

@awni

awni commented Dec 4, 2025

Copy link
Copy Markdown
Member

Would you mind updating batch_generate to not set the wried limit since it's superfluous (e.g. here)?

- Set wired_limit in __init__() and restore in close()
- Add __del__() as fallback safety net
- Call close() explicitly in server and batch_generate
- Remove redundant wired_limit context manager from batch_generate
@otarkhan otarkhan force-pushed the fix-batch-generation-wired-limit branch from 9048adb to ec8ba23 Compare December 4, 2025 22:05
@otarkhan

otarkhan commented Dec 4, 2025

Copy link
Copy Markdown
Contributor Author

Would you mind updating batch_generate to not set the wried limit since it's superfluous (e.g. here)?

Good catch! Updated

@awni awni left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Very nice!

@angeloskath angeloskath merged commit 0fbff35 into ml-explore:main Dec 5, 2025
2 checks passed
otarkhan added a commit to otarkhan/vllm-metal that referenced this pull request Jan 8, 2026
Without wired_limit, model weights cannot stay pinned in GPU-accessible
memory, causing frequent memory paging and GPU stalls. This results in
~30% GPU utilization instead of ~100%.

The fix sets max_recommended_working_set_size as the wired limit before
model loading, matching the fix in ml-explore/mlx-lm#652.

Changes:
- Set wired_limit in MetalWorker.init_device() for v1 engine
- Set wired_limit in MetalModelRunner.load_model() for legacy path
- Use new mx.set_wired_limit() API with fallback to deprecated API
- Add error handling for graceful degradation
otarkhan added a commit to otarkhan/vllm-metal that referenced this pull request Jan 8, 2026
Without wired_limit, model weights cannot stay pinned in GPU-accessible
memory, causing frequent memory paging and GPU stalls. This results in
~30% GPU utilization instead of ~100%.

The fix sets max_recommended_working_set_size as the wired limit before
model loading, matching the fix in ml-explore/mlx-lm#652.

Changes:
- Set wired_limit in MetalWorker.init_device() for v1 engine
- Set wired_limit in MetalModelRunner.load_model() for legacy path
- Use new mx.set_wired_limit() API with fallback to deprecated API
- Add error handling for graceful degradation

Signed-off-by: otarkhan <osama.taha1994@gmail.com>
otarkhan added a commit to otarkhan/vllm-metal that referenced this pull request Jan 8, 2026
Without wired_limit, model weights cannot stay pinned in GPU-accessible
memory, causing frequent memory paging and GPU stalls. This results in
~30% GPU utilization instead of ~100%.

The fix sets max_recommended_working_set_size as the wired limit before
model loading, matching the fix in ml-explore/mlx-lm#652.

Changes:
- Set wired_limit in MetalWorker.init_device() for v1 engine
- Set wired_limit in MetalModelRunner.load_model() for legacy path
- Use new mx.set_wired_limit() API with fallback to deprecated API
- Add error handling for graceful degradation

Signed-off-by: otarkhan <osama.taha1994@gmail.com>
ericcurtin pushed a commit to vllm-project/vllm-metal that referenced this pull request Jan 8, 2026
## Summary

Without `wired_limit` set, model weights cannot stay pinned in
GPU-accessible memory, causing frequent memory paging and GPU stalls.
This results in ~30% GPU utilization instead of ~100%.

This fix sets `max_recommended_working_set_size` as the wired limit
before model loading, matching the fix in
ml-explore/mlx-lm#652.

## Changes

- Set `wired_limit` in `MetalWorker.init_device()` for v1 engine
- Set `wired_limit` in `MetalModelRunner.load_model()` for legacy path
- Use new `mx.set_wired_limit()` API with fallback to deprecated
`mx.metal.set_wired_limit()`
- Add error handling for graceful degradation

## Test plan

- [x] Verified GPU utilization increases from ~30% to ~100% on Mac
Studio with MiniMax-M2.1-Q8
- [x] Confirmed log message shows wired_limit being set on startup

Signed-off-by: otarkhan <osama.taha1994@gmail.com>
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