Split data-loader wait from preprocessing in schedule metrics#567
Merged
Conversation
#564 timed `next(context.data_iterator)` in `_get_forward_input`, but that iterator is the `_preprocess_data` generator, so the metric conflated the real data-loader block with CPU preprocessing (share_batch_data / preprocess_batch). In the RL path this reads near zero because the loader is drained into a buffer before the schedule runs. Move the timing into `_preprocess_data`: time only the raw `next(data_iterator)` pulls as `data_wait_time_ms` (input starvation), and the generator's own active runtime -- paused across each yield to exclude schedule compute between micro-batches -- as a new `data_preprocessing_time_ms`. Both are logged to the terminal. Drop the now-redundant `data_batch_warn_time_ms` warning and its config field, since the wait is logged explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Removing the slow-load warning left the module `logger` (and `import logging`) with no consumer -- drop both. Guard `wait_start` with `if measure_time:` to match its sibling `preprocess_start` instead of a ternary fallback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jlamypoirier
added a commit
that referenced
this pull request
Jul 16, 2026
Brings main (#562/#564/#567) into the branch. The one semantic conflict was policy-gradient metrics: main #562 added reward/staleness data metrics (`_register_data_metrics`) to the standalone GRPO/GSPO `_forward_backward`, while this branch reworked registration to compute policy metrics in the fused kernel and register them through `register_combinable_extras`. Kept the fused-metrics design and grafted the data metrics onto every registration path: - `register_combinable_extras` gains `split_index` (base + GRPO/GSPO overrides + 3 call sites) so the compiled and monolithic paths can register data metrics. - GRPO triton-standalone and both `register_combinable_extras` overrides now call `_register_data_metrics`; GSPO standalone already did (auto-merged). - `_policy_metric_definitions` folds in `_data_metric_definitions()`. `test_lm_head` now supplies reward/model_version/documents_seen and asserts the data-metric family via a `reference_data_metrics` helper. CPU validation: test_lm_head + test_lm_losses = 722 passed, 75 skipped (triton/GPU-only skipped locally). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Claude Opus 4.8 authored this PR.
Problem
training.data_wait_time_ms(added in #564) reads near-zero (~19 ms) in the RL/streaming trainer while the DeepSpeed reference reports the true stream-block time (~4.2 s) — off by ~200×.#564 timed
next(context.data_iterator)inside_get_forward_input, butcontext.data_iteratoris the_preprocess_datagenerator. So the metric clocked the raw loader block plus CPU preprocessing (share_batch_data/preprocess_batch, i.e. GPU transfer and batch prep). And in the RL path the loader is drained into a buffer before the schedule runs, so the generator's rawnext()returns instantly and only preprocessing (~19 ms) is left to measure.Fix
Move all timing into
_preprocess_data, splitting it into two metrics:data_wait_time_ms— times only the rawnext(data_iterator)pulls (time blocked on the data loader = input starvation).data_preprocessing_time_ms(new) — the generator's own active runtime (share_batch_data+preprocess_batch), with the clock paused across eachyieldso schedule compute between micro-batches is excluded.Both are logged to the terminal (
| data wait: … | data preprocessing: …). All timing is gated oncontext.metrics is not None, so there is no overhead off logging steps._get_forward_inputno longer times anything. Thedata_batch_warn_time_mswarning and its config field are removed — the wait is now logged explicitly every step, so a threshold warning is redundant.Notes
ScheduleConfigvalidates without the field, and the training log format's keys are all declared (no format-timeKeyError).