Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,7 @@ The grace period in seconds to wait for responses after warmup phase ends. Only

#### `--warmup-concurrency-ramp-duration` `<float>`

Duration in seconds to ramp warmup session concurrency from 1 to target. If not set, uses `--concurrency-ramp-duration` value.
Duration in seconds to ramp warmup session concurrency from 1 to target. If not set, uses `--concurrency-ramp-duration` value. Under an agentic scenario, this paces the auto-synthesized trajectory warmup without changing profiling concurrency.
<br/>_Constraints: > 0_

#### `--warmup-prefill-concurrency-ramp-duration` `<float>`
Expand Down Expand Up @@ -2704,7 +2704,7 @@ The grace period in seconds to wait for responses after warmup phase ends. Only

#### `--warmup-concurrency-ramp-duration` `<float>`

Duration in seconds to ramp warmup session concurrency from 1 to target. If not set, uses `--concurrency-ramp-duration` value.
Duration in seconds to ramp warmup session concurrency from 1 to target. If not set, uses `--concurrency-ramp-duration` value. Under an agentic scenario, this paces the auto-synthesized trajectory warmup without changing profiling concurrency.
<br/>_Constraints: > 0_

#### `--warmup-prefill-concurrency-ramp-duration` `<float>`
Expand Down
6 changes: 6 additions & 0 deletions docs/tutorials/agentx-mvp.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ multi-turn coding contexts before any measurement starts. When the profiling
phase begins, every trajectory resumes from `k_i + 1` — and the server's cache
already holds the prefix.

For a high-concurrency deployment with a narrow request ingress, pass
`--warmup-concurrency-ramp-duration SECONDS` to open the synthesized warmup's
session-tree limit gradually from 1 to `--concurrency`. The ramp paces the
mandatory snapshot primers and any cache-pressure warmup requests; profiling
still starts directly at the configured concurrency after warmup drains.

The `k_i` values are deterministic given the random seed: same dataset + same
seed = same trajectories + same start points + same recycle order, on any
machine. That's why the scenario insists on a seed.
Expand Down
8 changes: 8 additions & 0 deletions src/aiperf/config/flags/_converter_profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ def _apply_agentic_replay_fields(phase: dict[str, Any], cli: CLIConfig) -> None:
for attr in _AGENTIC_REPLAY_ROUTES:
if attr in fields_set:
phase[attr] = getattr(cli, attr)
# AGENTIC_REPLAY replaces user-declared warmup phases with a phase
# synthesized from this profiling config. Preserve the existing warmup
# ramp flag on that source config so the synthesized phase can consume it
# without applying the ramp to profiling itself.
if cli.scenario is not None and "warmup_concurrency_ramp_duration" in fields_set:
phase["agentic_warmup_concurrency_ramp_duration"] = (
cli.warmup_concurrency_ramp_duration
)
# v1 parity: under a --scenario, --warmup-grace-period fed the agentic
# warmup barrier grace (there was no dedicated flag). Route it onto
# agentic_warmup_grace_period when the dedicated flag is unset; an
Expand Down
4 changes: 3 additions & 1 deletion src/aiperf/config/flags/cli_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2403,7 +2403,9 @@ def url(self) -> str:
Field(
gt=0,
description="Duration in seconds to ramp warmup session concurrency from 1 to target. "
"If not set, uses `--concurrency-ramp-duration` value.",
"If not set, uses `--concurrency-ramp-duration` value. Under an "
"agentic scenario, this paces the auto-synthesized trajectory "
"warmup without changing profiling concurrency.",
),
CLIParameter(
name=("--warmup-concurrency-ramp-duration",),
Expand Down
14 changes: 14 additions & 0 deletions src/aiperf/config/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,20 @@ class ConcurrencyPhase(BasePhaseConfig):
),
]

agentic_warmup_concurrency_ramp_duration: Annotated[
float | None,
Field(
default=None,
gt=0,
description="AGENTIC_REPLAY only: duration in seconds to ramp the "
"auto-synthesized warmup's session concurrency from 1 to the "
"profiling target. Populated by "
"--warmup-concurrency-ramp-duration under an agentic scenario and "
"read by timing.config._build_agentic_warmup_config. The profiling "
"phase itself is unaffected.",
),
]


# =============================================================================
# RATE-CONTROLLED PHASES
Expand Down
67 changes: 67 additions & 0 deletions src/aiperf/config/schema/aiperf-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,20 @@
"description": "AGENTIC_REPLAY only: grace period in seconds the auto-synthesized warmup barrier waits for in-flight priming requests after the warmup burst sends. Read off the profiling phase by ``timing.config._build_agentic_warmup_config`` (the agentic warmup is not a user-declared phase, so it does not inherit ``--warmup-grace-period``, which requires ``--warmup-duration``). None waits indefinitely (the agentic warmup must complete every primed trajectory before profiling starts).",
"title": "Agenticwarmupgraceperiod"
},
"agenticWarmupConcurrencyRampDuration": {
"anyOf": [
{
"exclusiveMinimum": 0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "AGENTIC_REPLAY only: duration in seconds to ramp the auto-synthesized warmup's session concurrency from 1 to the profiling target. Populated by --warmup-concurrency-ramp-duration under an agentic scenario and read by timing.config._build_agentic_warmup_config. The profiling phase itself is unaffected.",
"title": "Agenticwarmupconcurrencyrampduration"
},
"adaptive_scale": {
"description": "Enable single-run adaptive scale control for this phase. Accepts either a boolean or a nested adaptive-scale configuration block.",
"title": "Adaptivescale",
Expand Down Expand Up @@ -5214,6 +5228,20 @@
"description": "AGENTIC_REPLAY only: grace period in seconds the auto-synthesized warmup barrier waits for in-flight priming requests after the warmup burst sends. Read off the profiling phase by ``timing.config._build_agentic_warmup_config`` (the agentic warmup is not a user-declared phase, so it does not inherit ``--warmup-grace-period``, which requires ``--warmup-duration``). None waits indefinitely (the agentic warmup must complete every primed trajectory before profiling starts).",
"title": "Agenticwarmupgraceperiod"
},
"agenticWarmupConcurrencyRampDuration": {
"anyOf": [
{
"exclusiveMinimum": 0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "AGENTIC_REPLAY only: duration in seconds to ramp the auto-synthesized warmup's session concurrency from 1 to the profiling target. Populated by --warmup-concurrency-ramp-duration under an agentic scenario and read by timing.config._build_agentic_warmup_config. The profiling phase itself is unaffected.",
"title": "Agenticwarmupconcurrencyrampduration"
},
"adaptive_scale": {
"description": "Enable single-run adaptive scale control for this phase. Accepts either a boolean or a nested adaptive-scale configuration block.",
"title": "Adaptivescale",
Expand Down Expand Up @@ -8205,6 +8233,20 @@
"description": "AGENTIC_REPLAY only: grace period in seconds the auto-synthesized warmup barrier waits for in-flight priming requests after the warmup burst sends. Read off the profiling phase by ``timing.config._build_agentic_warmup_config`` (the agentic warmup is not a user-declared phase, so it does not inherit ``--warmup-grace-period``, which requires ``--warmup-duration``). None waits indefinitely (the agentic warmup must complete every primed trajectory before profiling starts).",
"title": "Agenticwarmupgraceperiod"
},
"agenticWarmupConcurrencyRampDuration": {
"anyOf": [
{
"exclusiveMinimum": 0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "AGENTIC_REPLAY only: duration in seconds to ramp the auto-synthesized warmup's session concurrency from 1 to the profiling target. Populated by --warmup-concurrency-ramp-duration under an agentic scenario and read by timing.config._build_agentic_warmup_config. The profiling phase itself is unaffected.",
"title": "Agenticwarmupconcurrencyrampduration"
},
"adaptive_scale": {
"description": "Enable single-run adaptive scale control for this phase. Accepts either a boolean or a nested adaptive-scale configuration block.",
"title": "Adaptivescale",
Expand Down Expand Up @@ -11639,6 +11681,31 @@
"title": "Agenticwarmupgraceperiod",
"x-jinja2-supported": true
},
"agenticWarmupConcurrencyRampDuration": {
"anyOf": [
{
"exclusiveMinimum": 0,
"type": "number"
},
{
"type": "null"
},
{
"type": "string",
"pattern": ".*\\{\\{.*\\}\\}.*",
"description": "Jinja2 template (e.g., '{{ variable }}')."
},
{
"type": "string",
"pattern": ".*\\$\\{[A-Za-z_][A-Za-z0-9_]*(?::[^}]*)?\\}.*",
"description": "Environment variable (e.g., '${VAR}' or '${VAR:default}')."
}
],
"default": null,
"description": "AGENTIC_REPLAY only: duration in seconds to ramp the auto-synthesized warmup's session concurrency from 1 to the profiling target. Populated by --warmup-concurrency-ramp-duration under an agentic scenario and read by timing.config._build_agentic_warmup_config. The profiling phase itself is unaffected.",
"title": "Agenticwarmupconcurrencyrampduration",
"x-jinja2-supported": true
},
"adaptive_scale": {
"description": "Enable single-run adaptive scale control for this phase. Accepts either a boolean or a nested adaptive-scale configuration block.",
"title": "Adaptivescale",
Expand Down
3 changes: 3 additions & 0 deletions src/aiperf/timing/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,9 @@ def _build_agentic_warmup_config(phase: PhaseConfig) -> CreditPhaseConfig | None
arrival_smoothness=getattr(phase, "smoothness", None),
seamless=False,
grace_period_sec=grace_period if grace_period is not None else float("inf"),
concurrency_ramp_duration_sec=getattr(
phase, "agentic_warmup_concurrency_ramp_duration", None
),
agentic_cache_warmup_duration_sec=cache_warmup_duration,
warmup_requests_per_lane=requests_per_lane,
)
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/config/test_converter_profiling_phase_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,23 @@ def test_agentic_warmup_grace_does_not_require_duration(self):
prof = build_profiling(user)
assert prof["agentic_warmup_grace_period"] == 0.0

def test_agentic_warmup_concurrency_ramp_routes_to_synthesized_phase(self):
"""The agentic scenario synthesizes warmup from the profiling phase,
so preserve the warmup-only ramp there without ramping profiling.
"""
loadgen = CLIConfig(
scenario="inferencex-agentx-mvp",
concurrency=768,
benchmark_duration=900,
warmup_concurrency_ramp_duration=60.0,
)
user = _make_user(loadgen=loadgen)

prof = build_profiling(user)

assert prof["agentic_warmup_concurrency_ramp_duration"] == 60.0
assert "concurrency_ramp" not in prof


class TestSystemIdleGapCapRouting:
def test_system_idle_gap_cap_routes_onto_profiling_phase(self) -> None:
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/timing/test_phase_config_agentic_replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,34 @@ def test_warmup_config_total_expected_requests_tracks_concurrency() -> None:
assert warmup.total_expected_requests == concurrency


def test_warmup_config_propagates_agentic_concurrency_ramp() -> None:
"""The warmup-only CLI ramp reaches the auto-synthesized phase without
changing the profiling phase's concurrency schedule.
"""
phase = _PHASE_ADAPTER.validate_python(
{
"name": "profiling",
"type": "concurrency",
"concurrency": 768,
"duration": 900,
"timing_mode": TimingMode.AGENTIC_REPLAY,
"agentic_warmup_concurrency_ramp_duration": 60.0,
}
)

warmup = _build_agentic_warmup_config(phase)
profiling = _build_profiling_config(
phase,
default_cancellation=RequestCancellationConfig(),
phase_index=0,
profiling_index=0,
)

assert warmup is not None
assert warmup.concurrency_ramp_duration_sec == 60.0
assert profiling.concurrency_ramp_duration_sec is None


def test_warmup_grace_defaults_to_infinity() -> None:
"""With no ``agentic_warmup_grace_period`` set, the warmup barrier waits indefinitely (inf) until every primed trajectory returns."""
phase = _ar_profiling_phase()
Expand Down
Loading