Repository navigation
fix(metrics): fan the structured token drain out across tokenizer shards - #561
Closed
karverma-amd wants to merge 1 commit into
Closed
karverma-amd wants to merge 1 commit into
karverma-amd wants to merge 1 commit into
Conversation
|
MLCommons CLA bot All contributors have signed the MLCommons CLA ✍️ ✅ |
At end of run the aggregator drains every pending tokenization. Plain-text inputs already fan out across the ProcessPoolExecutor shards, but structured inputs (MessageInput / PromptInput) were counted one at a time on the in-process thread. apply_chat_template is Jinja and Python and holds the GIL, so that lane runs on a single core. On a large agentic run the drain can take hours, and result_summary.json is not written until it finishes. Move the counting into module-level count_message_tokens / count_prompt_tokens so the in-process lane and the shards share one implementation. During the drain, deal structured items to the shards in chunks of 64, round-robin, so long prompts spread across shards. A failed chunk marks only its own items as errors, and progress is logged every 30 s. The live (mid-run) lane is unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
karverma-amd
force-pushed
the
fix/parallel-structured-token-drain
branch
from
November 4, 2026 22:34
a529530 to
4b00266
Compare
karverma-amd
marked this pull request as ready for review
November 4, 2026 22:36
4 of 10 tasks
Collaborator
Collaborator
|
Hi Karan, thanks for noticing, we also did realize the potential OOM issue. #556 aims to addressing 3 level of drain slowness. Will compare the solution between this and 556 |
Collaborator
|
Hi, could you try the updated 556 which incorporate 561 with some syntax refactoring to merge with more related changes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Makes the metrics aggregator's end-of-run drain count structured inputs
(
MessageInput/PromptInput) on the tokenizer shard processes instead ofone at a time on the in-process thread.
The problem
When a run ends, the aggregator drains every pending tokenization before it
writes the final snapshot and
result_summary.json. Plain-text inputs alreadyfan out across the
ProcessPoolExecutorshards, but structured inputs wentthrough
_token_count_message/_token_count_promptone at a time on thein-process thread. Those call
apply_chat_template, which is Jinja and Pythonand holds the GIL, so the whole structured drain ran on a single core.
Agentic runs are almost entirely structured inputs, with long multi-turn
prompts. On a large agentic replay the drain ran for hours with one core
pegged and the rest idle. Meanwhile the session showed every sample complete,
the endpoint was idle, and no summary had been written, so the run looked hung
at the tail.
The fix
count_message_tokens/count_prompt_tokens(pluschat_template_baseline). The in-process laneand the shards share one implementation, so both produce the same counts.
baseline alongside the fast text backend. It falls back to
(0, 0)the sameway the parent does.
live=False),BatchTokenizer._fan_out_structureddealsstructured items to the shards in chunks of 64, round-robin, so the long
prompts spread across shards instead of landing on one.
The worker also returns per-item exceptions instead of raising, so one bad
input does not fail its chunk.
no output.
With this change the same drain finished in minutes and the run wrote its
summary normally.
Comparison with #556
We also tried #556 on the same workload in place of this change. #556 speeds
up the encode step: it renders every pending item to text on one thread and
then encodes the batch in parallel. On our workload the time goes into
rendering the chat template, which stays serial in #556, and holding all of
the rendered prompts at once made the aggregator's memory grow without bound.
The aggregator was killed by the OOM killer partway through the drain, so the
run never finished.
This PR keeps memory flat because each shard renders and counts one small
chunk at a time and returns only integers. It does not touch the
full_run_osl.pyorscoring.pychanges in #556, which are independent ofthis one.
Type of change
Related issues
Related: #556
Testing
New tests in
test_token_metrics.py(TestStructuredDrainFanOut):chunks, with chunks dealt round-robin;
pytest -m unit: 2724 passed, 6 skipped. Manually verified on a large agenticrun: the drain completed and
result_summary.jsonwas written.Checklist
Pre-commit: ruff, ruff-format, mypy, license-header and the file hygiene hooks
pass. The
prettierhook could not install its Node environment locally, andthis PR changes no files that hook formats.