Skip to content

Cap pending idle-persistence bytes - #536

Open
vahako wants to merge 1 commit into
youssofal:mainfrom
vahako:persistence-pending-byte-budget
Open

vahako wants to merge 1 commit into
youssofal:mainfrom
vahako:persistence-pending-byte-budget

Conversation

@vahako

@vahako vahako commented Sep 26, 2026

Copy link
Copy Markdown

Summary

Each session-bank commit queues a snapshot settle and an SSD cold encode on the idle-persistence lane, and every pending job pins its entry's snapshot until the engine is idle. Coalescing is per session, so an agent fan-out with many one-off sessions grows the queue without bound under continuous load. Active memory climbs until requests fail with 507 "sustained critical memory pressure during prefill", including small prompts.

This PR adds a total byte budget for pending persistence work:

  • The settle and cold-encode jobs carry pinned_bytes, which is the entry's nbytes.
  • When the pending total exceeds MTPLX_PERSISTENCE_MAX_PENDING_BYTES (default 4G; off disables the budget), the oldest pinned jobs are cancelled. The newest job and unpinned jobs are never dropped.
  • New stats: persistence_pending_bytes, persistence_max_pending_bytes and persistence_budget_dropped.

Verification

  • New tests in tests/test_model_scheduler_persistence.py cover drop order, the newest and unpinned exemptions, the disabled budget, coalescing accounting and the env parsing.
  • All scheduler, session-bank and cold-tier tests pass (264).
  • test_no_mlx_imports, test_public_cli and test_runtime_kpis: 9 test_public_cli failures are identical on main without this change.
  • The same test run found no new ruff findings.

Note: I made this fix recently and have only run the short load test below so far. I am continuing to test it on longer runs and will update this PR with the results.

Benchmark Evidence

Setup: Apple M5 Max, 128 GB, macOS 26.4, mlx 0.32.2, mtplx 2.12.0 with this change on commit 33a554b. Model Youssofal/Qwen3.8-Flash-Next-MTPLX-Optimized-Speed, profile turbo, MTP depth 3, fan mode default, 2026-09-26.

Load: 4 concurrent clients. Each request is a new session with a ~1.4k-token shared system prompt, max_tokens 120 and thinking off. SSD session cache on.

4 min load pending jobs pending bytes active memory requests
2.12.0 0 → 103 not capped 83.4 → 104.1 GB, still rising 104
this PR ≤ 10 ≤ 4.2 GB flat 86.5 GB 98

Without the budget, an overnight agent run hit the 507 wall roughly every 20 minutes (79 refusals). With the budget, the queue still drains to SSD once the engine is idle.

Each session-bank commit queues a snapshot settle and an SSD cold encode
that pin the entry's snapshot until the engine is idle. Coalescing is per
session, so many one-off sessions under continuous load grow the queue
without bound and end in 507 memory refusals.

Jobs now carry pinned_bytes; when the pending total exceeds
MTPLX_PERSISTENCE_MAX_PENDING_BYTES (default 4G, "off" disables), the
oldest pinned jobs are dropped. The newest job is always kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vahako
vahako requested a review from youssofal as a code owner September 26, 2026 00:26

This branch has not been deployed

No deployments
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.

1 participant