diff --git a/docs/cli-options.md b/docs/cli-options.md index 9fe1ea36f..d606e1bb4 100644 --- a/docs/cli-options.md +++ b/docs/cli-options.md @@ -874,8 +874,9 @@ AGENTIC_REPLAY only: upper bound (inclusive) on the random start position within #### `--burst-phase-starts` -AGENTIC_REPLAY only: collapse the WARMUP-start and PROFILING-start dispatches into synchronized bursts instead of spreading them by each request's recorded offset from t*. By default (False) the phase starts are SPREAD: WARMUP requests are aligned globally so every trajectory reaches its t* at the same instant (the warmup end), and each lane's first PROFILING request waits out its recorded gap after t* -- reproducing the recorded arrival pattern at both phase boundaries. The rest of the replay (inter-turn delays) is timing-faithful regardless of this flag; it governs ONLY the burst-vs-spread of the two phase starts. Pass --burst-phase-starts to fire each phase's first requests together (faster concurrency ramp, synchronized start), e.g. for a throughput-oriented run rather than a faithful arrival replay. +AGENTIC_REPLAY only: collapse the WARMUP-start and PROFILING-start dispatches into synchronized bursts instead of spreading them by each request's recorded offset from t*. By default (True) the phase starts are BURST so configured concurrency becomes active inside the benchmark window. When False, WARMUP requests are aligned globally so every trajectory reaches its t* at the same instant (the warmup end), and each lane's first PROFILING request waits out its recorded gap after t*. The rest of the replay (inter-turn delays) is timing-faithful regardless of this setting; it governs ONLY the burst-vs-spread behavior at the two phase starts.
_Flag (no value required)_ +
_Default: `True`_ #### `--concurrency` `` diff --git a/src/aiperf/common/config/loadgen_config.py b/src/aiperf/common/config/loadgen_config.py index b8c7a7b96..7784c4701 100644 --- a/src/aiperf/common/config/loadgen_config.py +++ b/src/aiperf/common/config/loadgen_config.py @@ -262,22 +262,20 @@ def parse_concurrency_list( description="AGENTIC_REPLAY only: collapse the WARMUP-start and " "PROFILING-start dispatches into synchronized bursts instead of " "spreading them by each request's recorded offset from t*. By " - "default (False) the phase starts are SPREAD: WARMUP requests are " - "aligned globally so every trajectory reaches its t* at the same " - "instant (the warmup end), and each lane's first PROFILING request " - "waits out its recorded gap after t* -- reproducing the recorded " - "arrival pattern at both phase boundaries. The rest of the replay " - "(inter-turn delays) is timing-faithful regardless of this flag; " - "it governs ONLY the burst-vs-spread of the two phase starts. Pass " - "--burst-phase-starts to fire each phase's first requests together " - "(faster concurrency ramp, synchronized start), e.g. for a " - "throughput-oriented run rather than a faithful arrival replay.", + "default (True) the phase starts are BURST so configured concurrency " + "becomes active inside the benchmark window. When False, WARMUP " + "requests are aligned globally so every trajectory reaches its t* " + "at the same instant (the warmup end), and each lane's first " + "PROFILING request waits out its recorded gap after t*. The rest " + "of the replay (inter-turn delays) is timing-faithful regardless " + "of this setting; it governs ONLY the burst-vs-spread behavior at " + "the two phase starts.", ), CLIParameter( name=("--burst-phase-starts",), group=Groups.LOAD_GENERATOR, ), - ] = False + ] = True concurrency: Annotated[ Any, # CLI accepts string, validator converts to Union[int, list[int], None] diff --git a/src/aiperf/timing/strategies/agentic_replay.py b/src/aiperf/timing/strategies/agentic_replay.py index e786b9fcc..782b63600 100644 --- a/src/aiperf/timing/strategies/agentic_replay.py +++ b/src/aiperf/timing/strategies/agentic_replay.py @@ -20,10 +20,11 @@ not reproduced. This includes parents gated on a child join (they sent turn n-1 before t* and resume at the join turn during PROFILING, so n-1 warms that turn). Streams whose first request is at/after t* (``next_turn_index == 0``) -have nothing to warm. By default the priming -requests are SPREAD -- aligned globally on t* so every trajectory's t* lands -at the warmup end (see ``_execute_warmup``); ``--burst-phase-starts`` fires -them all at once instead. The phase exits via the standard +have nothing to warm. By default the priming requests BURST together so the +configured lanes become active inside the benchmark window. When +``burst_phase_starts`` is false, requests are spread and aligned globally on +t* so every trajectory's t* lands at the warmup end (see ``_execute_warmup``). +The phase exits via the standard ``SendingCompleteStopCondition`` plus ``grace_period_sec=inf`` semantics already in CreditPhaseConfig (count-driven: every turn-n-1 must return). @@ -36,9 +37,10 @@ degraded trajectory pool. PROFILING: each stream resumes at its first turn at/after t* -(``next_turn_index``). Default dispatch preserves the stream's recorded offset -from the replay boundary; ``--burst-phase-starts`` collapses each lane's first -eligible request to profiling-time 0. Accelerated cache warmup synthesizes a +(``next_turn_index``). Default dispatch collapses each lane's first eligible +request to profiling-time 0. When ``burst_phase_starts`` is false, dispatch +preserves the stream's recorded offset from the replay boundary. Accelerated +cache warmup synthesizes a new replay boundary at the warmup handoff and carries each live stream's residual next-turn delay into profiling, so the handoff ramps instead of firing every live stream at once. Subsequent turns honor trace inter-turn @@ -210,13 +212,8 @@ def __init__( self._benchmark_id: str = ( user_config.benchmark_id if user_config is not None else "unknown" ) - # ``--burst-phase-starts`` (loadgen.burst_phase_starts). Default False: - # the WARMUP and PROFILING phase starts are SPREAD by each request's - # recorded offset from t* (warmup globally t*-aligned, profiling - # preserving each lane's leading gap). When True, both phase starts - # collapse into synchronized bursts. Governs ONLY the two phase-start - # dispatch patterns; the rest of replay timing is faithful regardless. - # ``is True`` guards MagicMock/None test configs -> default (spread). + # Real loadgen configs default to burst. Missing/mocked configs retain + # the spread fallback used by isolated strategy callers. loadgen = getattr(user_config, "loadgen", None) self._burst_phase_starts: bool = ( getattr(loadgen, "burst_phase_starts", False) is True @@ -1429,14 +1426,12 @@ async def _dispatch_snapshot_for_profiling( Each stream profiles from turn ``next_turn_index`` (the first turn at or after t*; its predecessor, if any, was primed during WARMUP). - Dispatch anchoring depends on ``--burst-phase-starts``: by default - (spread) ``t0_offset = 0`` so each stream waits out its recorded offset - from t* -- the leading t*->first-request gap is preserved and lanes - ramp in. With ``--burst-phase-starts`` the trajectory's earliest - post-t* request is anchored at profiling-time 0 (subtracting T0, the - min offset) so the lane bursts at once. Relative timing among the - trajectory's streams and turns is identical either way -- only the - per-lane start offset differs. + By default, the trajectory's earliest post-t* request is anchored at + profiling-time 0 so every lane starts together. When + ``burst_phase_starts`` is false, ``t0_offset = 0`` and each stream waits + out its recorded offset from t*. Relative timing among the trajectory's + streams and turns is identical either way -- only the per-lane start + offset differs. Gated parents (``waiting_on_children``) are not dispatched here; their join is seeded with the orchestrator and their gated turn fires when