Skip to content
Merged
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
24 changes: 21 additions & 3 deletions components/src/dynamo/profiler/profile_sla.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
from dynamo.profiler.utils.config_modifiers.protocol import apply_dgd_overrides
from dynamo.profiler.utils.defaults import SearchStrategy
from dynamo.profiler.utils.dgd_generation import generate_dgd_config_with_planner
from dynamo.profiler.utils.dgdr_v1beta1_types import DynamoGraphDeploymentRequestSpec
from dynamo.profiler.utils.dgdr_v1beta1_types import (
BackendType,
DynamoGraphDeploymentRequestSpec,
)
from dynamo.profiler.utils.dgdr_validate import (
run_gate_checks,
validate_dgdr_for_profiler,
Expand All @@ -51,11 +54,23 @@

logger = logging.getLogger(__name__)

_CONCRETE_BACKENDS = ["trtllm", "sglang", "vllm"]


def _check_auto_backend_support(model: str, system: str) -> bool:
"""
Return True if *any* concrete backend is AIC-supported for this model/system.
TODO: move this function to AIC and handle partially supported model x backend x hardware
"""
return any(
check_model_hardware_support(model, system, b) for b in _CONCRETE_BACKENDS
)


def _extract_profiler_params(dgdr: DynamoGraphDeploymentRequestSpec) -> tuple:
"""Pull all profiler parameters from dgdr and log them."""
model = dgdr.model
backend = dgdr.backend.value.lower()
backend = BackendType(dgdr.backend).value.lower()
system = dgdr.hardware.gpuSku.lower()
total_gpus = dgdr.hardware.totalGpus
isl = dgdr.workload.isl
Expand Down Expand Up @@ -313,7 +328,10 @@ async def run_profile(
picking_mode,
) = _extract_profiler_params(dgdr)

aic_supported = check_model_hardware_support(model, system, backend)
if backend == "auto":
aic_supported = _check_auto_backend_support(model, system)
else:
aic_supported = check_model_hardware_support(model, system, backend)
run_gate_checks(dgdr, aic_supported, search_strategy, backend)

(
Expand Down
21 changes: 19 additions & 2 deletions components/src/dynamo/profiler/rapid.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,19 @@ def _generate_dgd_from_pick(
if best_config_df is None or best_config_df.empty:
return None

row = best_config_df.iloc[0]

tc = task_configs.get(chosen_exp)
# TODO: temporary workaround — when backend="auto", AIC's
# merge_experiment_results_by_mode collapses e.g. "agg_vllm" into "agg",
# but task_configs retains the original keys. Reconstruct the key from
# the winning row's backend column. Proper fix: AIC should return the
# original task config key alongside the merged chosen experiment name.
if tc is None and "backend" in row.index:
tc = task_configs.get(f"{chosen_exp}_{row['backend']}")
if tc is None:
return None

row = best_config_df.iloc[0]

original_total_gpus = tc.total_gpus
if "total_gpus_needed" in row.index and row["total_gpus_needed"] > 0:
tc.total_gpus = int(row["total_gpus_needed"])
Expand Down Expand Up @@ -87,6 +94,10 @@ def _generate_dgd_from_pick(
return None


# in naive mode, use vllm as the default backend
_DEFAULT_NAIVE_BACKEND = "vllm"


def _run_naive_fallback(
dgdr: DynamoGraphDeploymentRequestSpec,
model: str,
Expand All @@ -95,6 +106,12 @@ def _run_naive_fallback(
backend: str,
) -> dict:
"""Handle the AIC-unsupported path via naive config generation."""
if backend == "auto":
backend = _DEFAULT_NAIVE_BACKEND
logger.info(
"Auto backend resolved to '%s' for naive fallback.",
backend,
)
logger.info(
"AIC does not support this combo — falling back to naive config generation."
)
Expand Down
10 changes: 10 additions & 0 deletions tests/profiler/configs/11_auto_rapid_no_planner_no_load.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# Case 11: Auto backend, rapid, without planner, no input load
model: "Qwen/Qwen3-32B"
image: "hongkuanz196/trtllm-runtime:hzhou-0224"
hardware:
gpuSku: h200_sxm
totalGpus: 8
numGpusPerNode: 8
19 changes: 19 additions & 0 deletions tests/profiler/test_profile_sla_dgdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,25 @@ def test_thorough_auto_backend_rejected(self, tmp_path):
asyncio.run(run_profile(dgdr, ops))


class TestAutoBackend:
"""Rapid strategy with auto backend resolution."""

@pytest.mark.pre_merge
@pytest.mark.gpu_0
def test_no_planner_no_load(self, tmp_path):
"""Case 11: auto backend, rapid, no planner, no target load."""
dgdr = _load_dgdr(CONFIGS_DIR / "11_auto_rapid_no_planner_no_load.yaml")
assert dgdr.backend == BackendType.Auto
ops = _make_ops(tmp_path)
asyncio.run(run_profile(dgdr, ops))

output = tmp_path / "profiling_results" / "final_config.yaml"
assert output.exists()
config = yaml.safe_load(output.read_text())
assert config, "final_config.yaml should not be empty"
assert "spec" in config


class TestThoroughEdgeCases:
"""Edge cases for thorough mode."""

Expand Down
Loading