Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ keywords = ["llm", "genai", "inference", "nvidia", "distributed"]

[workspace.dependencies]
# Published separately by https://github.com/ai-dynamo/aisimulate.
aisimulate-core = { version = "=0.1.0-dev.2" }
aisimulate-core = { version = "=0.12.0-dev.1" }

# Local crates
dynamo-runtime = { path = "lib/runtime", version = "1.5.0" }
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ classifiers = [
]

dependencies = [
"aisimulate==0.1.0.dev2; python_version >= '3.11' and python_version < '3.14'",
"aisimulate==0.12.0.dev1; python_version >= '3.11' and python_version < '3.14'",
"aiperf==0.10.0",
"matplotlib",
"networkx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _config() -> PlannerConfig:
hf_id="Qwen/Qwen3-32B",
system="h200_sxm",
backend="vllm",
backend_version="0.19.0",
backend_version="0.24.0",
prefill_pick=pick,
decode_pick=pick,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_rapid_task_v2_build_and_execute_contract() -> None:
total_gpus=2,
system="h200_sxm",
backend="vllm",
backend_version="0.19.0",
backend_version="0.24.0",
isl=128,
osl=8,
ttft=100_000.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,21 +310,21 @@ def test_injects_all_required_flags(self):
assert out[out.index("--aic-attention-dp-size") + 1] == "8"
# trtllm is not a mocker engine_type; leave --engine-type alone.
assert "--engine-type" not in out
assert out[out.index("--aic-backend-version") + 1] == "1.3.0rc10"
assert out[out.index("--aic-backend-version") + 1] == "current"

def test_matches_engine_type_for_vllm(self):
spec = self._spec("vllm")
out = _inject_mocker_aic_args([], spec, spec.prefill_pick)
assert out[out.index("--engine-type") + 1] == "vllm"
assert out[out.index("--aic-backend") + 1] == "vllm"
assert out[out.index("--aic-backend-version") + 1] == "0.14.0"
assert out[out.index("--aic-backend-version") + 1] == "current"

def test_matches_engine_type_for_sglang(self):
spec = self._spec("sglang")
out = _inject_mocker_aic_args([], spec, spec.decode_pick)
assert out[out.index("--engine-type") + 1] == "sglang"
assert out[out.index("--aic-backend") + 1] == "sglang"
assert out[out.index("--aic-backend-version") + 1] == "0.5.6.post2"
assert out[out.index("--aic-backend-version") + 1] == "current"


class TestBuildPlannerConfigEmbedsAicSpec:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
AIC_PARITY_MODEL = "Qwen/Qwen3-32B"
AIC_PARITY_SYSTEM = "h200_sxm"
AIC_PARITY_VERSIONS = {
"vllm": "0.19.0",
"sglang": "0.5.6.post2",
"vllm": "0.24.0",
"sglang": "current",
Comment thread
tedzhouhk marked this conversation as resolved.
Resolved
}
AIC_PARITY_BACKENDS = [
pytest.param("vllm", id="vllm"),
Expand Down
9 changes: 3 additions & 6 deletions components/src/dynamo/profiler/utils/dgd_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import numpy as np
import yaml

from dynamo._internal.aic import (
DEFAULT_BACKEND_VERSIONS as _MOCKER_AIC_BACKEND_VERSIONS,
)
from dynamo.common.utils.paths import get_workspace_dir
from dynamo.planner.config.aic_interpolation_spec import AICInterpolationSpec
from dynamo.planner.config.backend_components import (
Expand Down Expand Up @@ -57,15 +60,9 @@
needs_mocker_aic_perf_model,
needs_profile_data,
)
from dynamo.profiler.utils.replay_optimize.constants import AIC_BACKEND_VERSIONS

logger = logging.getLogger(__name__)

_MOCKER_AIC_BACKEND_VERSIONS = {
**AIC_BACKEND_VERSIONS,
"trtllm": "1.3.0rc10",
}


def _load_latest_database_version() -> Optional[Callable[..., Optional[str]]]:
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

import os

from dynamo._internal.aic import DEFAULT_BACKEND_VERSIONS

AIC_BACKEND_VERSIONS = {
"vllm": "0.14.0",
"sglang": "0.5.6.post2",
backend: DEFAULT_BACKEND_VERSIONS[backend] for backend in ("vllm", "sglang")
}

DEFAULT_OVERLAP_SCORE_CREDITS = (1.0,)
Expand Down
8 changes: 8 additions & 0 deletions components/src/dynamo/replay/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from aisimulate.aic import materialize_aic_num_gpu_blocks

from dynamo._internal.aic import resolve_backend_version
from dynamo.mocker import MockEngineArgs
from dynamo.mocker.args import (
resolve_planner_profile_data as _resolve_mocker_planner_profile_data,
Expand All @@ -26,6 +27,13 @@ class PlannerProfileDataResult(Protocol):
def resolve_aic_num_gpu_blocks(raw: dict[str, Any]) -> None:
"""Materialize AIC KV capacity in-place for SDK compatibility."""

if (
raw.get("aic_backend") is not None
or raw.get("aic_attention_dp_size") is not None
):
raw["aic_backend_version"] = resolve_backend_version(
raw.get("aic_backend") or "vllm", raw.get("aic_backend_version")
)
lowered = materialize_aic_num_gpu_blocks(raw)
raw.clear()
raw.update(lowered)
Expand Down
4 changes: 2 additions & 2 deletions components/src/dynamo/replay/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from numbers import Real
from typing import Any

from aisimulate.aic import materialize_aic_num_gpu_blocks
from aisimulate.sweeper.provider import JSONValue, RuntimeHookSpec
from aisimulate.sweeper.replay import (
HookCapability,
Expand All @@ -30,6 +29,7 @@
from dynamo.llm import AicPerfConfig, KvRouterConfig
from dynamo.mocker import MockEngineArgs
from dynamo.replay.api import run_synthetic_trace_replay, run_trace_replay
from dynamo.replay.config import resolve_aic_num_gpu_blocks

_PLANNER_HOOK = HookCapability(
provider="dynamo.planner",
Expand Down Expand Up @@ -260,7 +260,7 @@ def _engine_args(payload: dict[str, JSONValue] | None) -> MockEngineArgs:
"aic_model_path",
):
lowered.pop(name, None)
lowered = materialize_aic_num_gpu_blocks(lowered)
resolve_aic_num_gpu_blocks(lowered)
# Pipeline parallelism is already represented in the public parallel
# mapping and used for AIC capacity. MockEngineArgs has no PP field.
lowered.pop("aic_pp_size", None)
Expand Down
2 changes: 1 addition & 1 deletion components/src/dynamo/replay/tests/test_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def test_fixed_timing_keeps_aic_identity_out_of_runtime_args(monkeypatch) -> Non
monkeypatch.setattr(simulation, "MockEngineArgs", _FakeEngineArgs)
monkeypatch.setattr(
simulation,
"materialize_aic_num_gpu_blocks",
"resolve_aic_num_gpu_blocks",
lambda payload: payload,
)
engine_args = simulation.DynamoReplayRunner._engine_args(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def test_sweeper_runs_real_dynamo_replay_in_spawned_workers() -> None:
include_router=True,
)

candidates = Sweeper(
result = Sweeper(
runner_factory=DynamoReplayRunnerFactory(),
providers={
"dynamo.planner": create_planner_provider(),
Expand All @@ -245,7 +245,9 @@ def test_sweeper_runs_real_dynamo_replay_in_spawned_workers() -> None:
show_progress=False,
).run(config)

candidates = result.candidates
assert len(candidates) == 2
assert all(candidate.status == "feasible" for candidate in candidates)
assert all(
candidate.metrics["output_throughput_tok_s"] > 0.0 for candidate in candidates
)
Expand Down
2 changes: 1 addition & 1 deletion container/deps/requirements.aisimulate.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# SPDX-License-Identifier: Apache-2.0

# Published AISimulate wheel staged into planner and framework runtime wheelhouses.
aisimulate==0.1.0.dev2
aisimulate==0.12.0.dev1
5 changes: 3 additions & 2 deletions lib/bindings/kvbm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions lib/bindings/python/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/bindings/python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ request-trace-s3 = ["dynamo-llm/request-trace-s3"]
# former AIC crate surface. The `python` feature is required for
# AicEngineBuilder; this extension supplies the interpreter, so the dependency
# must not enable `extension-module`.
aisimulate-core = { version = "=0.1.0-dev.2", optional = true, features = ["python"] }
aisimulate-core = { version = "=0.12.0-dev.1", optional = true, features = ["python"] }
dynamo-runtime = { path = "../../runtime" }
dynamo-mocker = { path = "../../mocker" }
dynamo-parsers = { version = "8.1.0" }
Expand Down
10 changes: 5 additions & 5 deletions lib/bindings/python/src/dynamo/_internal/aic.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
# Dynamo's historical default when conditional acceptance rates are omitted.
_DEFAULT_NEXTN_ACCEPT_RATES = [0.85, 0.3, 0.0, 0.0, 0.0]

# Default backend versions match the AIC-core v0.11.0 perf DB.
# Resolve defaults through the queryable slots in the pinned AISimulate perf DB.
DEFAULT_BACKEND_VERSIONS = {
"vllm": "0.19.0",
"sglang": "0.5.10",
"trtllm": "1.3.0rc10",
"vllm": "current",
"sglang": "current",
"trtllm": "current",
Comment thread
tedzhouhk marked this conversation as resolved.
Resolved
}
_KV_CAPACITY_BACKENDS = frozenset(DEFAULT_BACKEND_VERSIONS)
DEFAULT_STATIC_STRIDE = 32
Expand All @@ -39,7 +39,7 @@ def _validate_kv_capacity_backend(backend_name: str) -> None:


def resolve_backend_version(backend_name: str, backend_version: str | None) -> str:
"""Return the pinned backend version used for AIC perf lookups."""
"""Preserve explicit versions; otherwise use the release database current slot."""
Comment thread
tedzhouhk marked this conversation as resolved.
Resolved
if backend_version is not None:
return backend_version
return DEFAULT_BACKEND_VERSIONS.get(backend_name, DEFAULT_BACKEND_VERSIONS["vllm"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def fake_estimate_num_gpu_blocks(**kwargs):
"gpu_memory_utilization": 0.8,
"mem_fraction_static": None,
"free_gpu_memory_fraction": None,
"backend_version": None,
"backend_version": "current",
"pp_size": 1,
"moe_tp_size": None,
"moe_ep_size": None,
Expand Down
23 changes: 21 additions & 2 deletions lib/bindings/python/tests/replay/test_replay_aic_integration.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Offline, network-free coverage of Dynamo replay against AIC 0.11."""
"""Offline, network-free coverage of Dynamo replay against the pinned AISimulate release."""

from __future__ import annotations

import pytest

from dynamo.replay.config import load_engine_args

pytestmark = [
pytest.mark.aiconfigurator,
pytest.mark.gpu_0,
Expand All @@ -17,7 +19,7 @@

AIC_MODEL = "Qwen/Qwen3-32B"
AIC_SYSTEM = "h200_sxm"
AIC_BACKEND_VERSION = "0.19.0"
AIC_BACKEND_VERSION = "0.24.0"


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -61,6 +63,23 @@ def test_real_aic_memory_estimates_gpu_blocks() -> None:
assert blocks > 0


def test_default_aic_capacity_uses_queryable_version() -> None:
args = load_engine_args(
{
"aic_backend": "vllm",
"aic_system": AIC_SYSTEM,
"aic_model_path": AIC_MODEL,
"aic_tp_size": 1,
"block_size": 64,
"max_num_batched_tokens": 4096,
"max_num_seqs": 128,
}
)
assert args is not None
assert args.num_gpu_blocks > 0
assert args.aic_backend_version == "current"


def test_aggregated_replay_uses_native_aic_engine() -> None:
from aiconfigurator_core.sdk.engine import compile_engine

Expand Down
5 changes: 5 additions & 0 deletions lib/bindings/python/tests/test_aic_capacity.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ def broken_memory_module(name, *args, **kwargs):
assert exc_info.value is missing_dependency


@pytest.mark.parametrize("backend", ["vllm", "sglang", "trtllm"])
def test_default_version_uses_queryable_slot(backend):
assert resolve_backend_version(backend, None) == "current"


def test_trtllm_version_resolution():
assert resolve_backend_version("trtllm", "0.20.0") == "0.20.0"

Expand Down
12 changes: 11 additions & 1 deletion lib/mocker/src/common/protocols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@ struct MockEngineArgsSerde {
enable_local_indexer: OptionalConfigValue<bool>,
bootstrap_port: OptionalConfigValue<u16>,
handoff_session_timeout_ms: OptionalConfigValue<u64>,
#[serde(alias = "kv_transfer_bytes_per_token")]
kv_bytes_per_token: OptionalConfigValue<usize>,
kv_cache_bytes_per_token: OptionalConfigValue<usize>,
kv_transfer_bandwidth: OptionalConfigValue<f64>,
kv_transfer_timing_mode: OptionalConfigValue<String>,
reasoning: OptionalConfigValue<ReasoningConfig>,
Expand Down Expand Up @@ -703,11 +705,16 @@ pub struct MockEngineArgs {
#[validate(range(min = 1))]
pub handoff_session_timeout_ms: u64,

/// KV cache bytes per token, auto-computed from model config by Python CLI.
/// Bytes transferred per token, auto-computed from model config by Python CLI.
/// Formula: num_layers * 2 * num_kv_heads * head_dim * dtype_bytes
#[builder(default = "None")]
pub kv_bytes_per_token: Option<usize>,

/// Physical KV-cache bytes occupied by one token, independent of transfer geometry.
#[builder(default = "None")]
#[serde(skip_serializing_if = "Option::is_none")]
pub kv_cache_bytes_per_token: Option<usize>,

/// KV cache transfer bandwidth in GB/s for disaggregated serving latency simulation.
/// Default: 64.0 (inter-node InfiniBand). Set to 0 to disable KV transfer delay.
/// For intra-node NVLink, typical value is ~450.
Expand Down Expand Up @@ -1047,6 +1054,9 @@ impl TryFrom<MockEngineArgsSerde> for MockEngineArgs {
if let Some(kv_bytes_per_token) = compat.kv_bytes_per_token.into_nullable() {
builder = builder.kv_bytes_per_token(kv_bytes_per_token);
}
if let Some(kv_cache_bytes_per_token) = compat.kv_cache_bytes_per_token.into_nullable() {
builder = builder.kv_cache_bytes_per_token(kv_cache_bytes_per_token);
}
if let Some(kv_transfer_bandwidth) = compat.kv_transfer_bandwidth.into_nullable() {
builder = builder.kv_transfer_bandwidth(kv_transfer_bandwidth);
}
Expand Down
Loading
Loading