"docs/vscode:/vscode.git/clone" did not exist on "ebd06a1f320ac5ac23d979dc8ee53d419be2719b"
Unverified Commit 95c45509 authored by Hongkuan Zhou's avatar Hongkuan Zhou Committed by GitHub
Browse files

refactor: restructure planner package into subpackage hierarchy (#7689)


Signed-off-by: default avatarhongkuanz <hongkuanz@nvidia.com>
parent 68628976
......@@ -68,7 +68,7 @@ sys.path.insert(0, str(_components_src))
# dynamo itself must be a namespace-like package (has __path__) so that
# Python's import machinery can traverse down to dynamo.profiler from the
# filesystem. dynamo.planner is pre-registered as a stub to skip its heavy
# __init__.py, while still allowing dynamo.planner.utils.* to load normally.
# __init__.py, while still allowing dynamo.planner.config.* to load normally.
# ---------------------------------------------------------------------------
_dynamo_path = str(_components_src / "dynamo")
_planner_path = str(_components_src / "dynamo" / "planner")
......
......@@ -302,7 +302,7 @@ type KVRouterSpec struct {
// FeaturesSpec controls optional Dynamo platform features in the generated deployment.
type FeaturesSpec struct {
// Planner is the raw SLA planner configuration passed to the planner service.
// Its schema is defined by dynamo.planner.utils.planner_config.PlannerConfig.
// Its schema is defined by dynamo.planner.config.planner_config.PlannerConfig.
// Go treats this as opaque bytes; the Planner service validates it at startup.
// The presence of this field (non-null) enables the planner in the generated DGD.
// +optional
......
......@@ -564,7 +564,7 @@ spec:
planner:
description: |-
Planner is the raw SLA planner configuration passed to the planner service.
Its schema is defined by dynamo.planner.utils.planner_config.PlannerConfig.
Its schema is defined by dynamo.planner.config.planner_config.PlannerConfig.
Go treats this as opaque bytes; the Planner service validates it at startup.
The presence of this field (non-null) enables the planner in the generated DGD.
type: object
......
......@@ -661,7 +661,7 @@ class SystemInfo(NodeInfo):
"""Suppress Prometheus endpoint warnings from planner module during import testing."""
# The planner module logs a warning about Prometheus endpoint when imported
# outside of a Kubernetes cluster. Suppress this for cleaner output.
planner_logger = logging.getLogger("dynamo.planner.defaults")
planner_logger = logging.getLogger("dynamo.planner.config.defaults")
planner_logger.setLevel(logging.ERROR)
# Also suppress the defaults._get_default_prometheus_endpoint logger
defaults_logger = logging.getLogger("defaults._get_default_prometheus_endpoint")
......
......@@ -1462,7 +1462,7 @@ _Appears in:_
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `planner` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#rawextension-runtime-pkg)_ | Planner is the raw SLA planner configuration passed to the planner service.<br />Its schema is defined by dynamo.planner.utils.planner_config.PlannerConfig.<br />Go treats this as opaque bytes; the Planner service validates it at startup.<br />The presence of this field (non-null) enables the planner in the generated DGD. | | Type: object <br />Optional: \{\} <br /> |
| `planner` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#rawextension-runtime-pkg)_ | Planner is the raw SLA planner configuration passed to the planner service.<br />Its schema is defined by dynamo.planner.config.planner_config.PlannerConfig.<br />Go treats this as opaque bytes; the Planner service validates it at startup.<br />The presence of this field (non-null) enables the planner in the generated DGD. | | Type: object <br />Optional: \{\} <br /> |
| `mocker` _[MockerSpec](#mockerspec)_ | Mocker configures the simulated (mocker) backend for testing without GPUs. | | Optional: \{\} <br /> |
......
......@@ -9,7 +9,7 @@ import pytest
from dynamo.global_planner.scale_handler import ScaleRequestHandler
from dynamo.planner import SubComponentType, TargetReplica
from dynamo.planner.scale_protocol import ScaleRequest
from dynamo.planner.connectors.protocol import ScaleRequest
pytestmark = [
pytest.mark.gpu_0,
......
......@@ -15,15 +15,13 @@ from unittest.mock import Mock, patch
import pytest
from dynamo.planner.utils.decode_planner import DecodePlanner
from dynamo.planner.utils.planner_config import PlannerConfig
from dynamo.planner.utils.planner_core import (
PlannerSharedState,
_apply_global_gpu_budget,
)
from dynamo.planner.utils.prefill_planner import PrefillPlanner
from dynamo.planner.utils.prometheus import Metrics
from dynamo.planner.worker_info import WorkerInfo
from dynamo.planner.config.planner_config import PlannerConfig
from dynamo.planner.core.budget import _apply_global_gpu_budget
from dynamo.planner.core.decode import DecodePlanner
from dynamo.planner.core.prefill import PrefillPlanner
from dynamo.planner.core.state import PlannerSharedState
from dynamo.planner.monitoring.traffic_metrics import Metrics
from dynamo.planner.monitoring.worker_info import WorkerInfo
pytestmark = [pytest.mark.pre_merge, pytest.mark.gpu_0]
......@@ -176,7 +174,7 @@ def planner():
mock_runtime = Mock()
# Patch Prometheus Gauge to avoid registry conflicts
with patch("dynamo.planner.utils.planner_core.Gauge") as mock_gauge:
with patch("dynamo.planner.monitoring.planner_metrics.Gauge") as mock_gauge:
mock_gauge.return_value = Mock()
shared_state = PlannerSharedState()
......
......@@ -19,20 +19,22 @@ from unittest.mock import MagicMock, patch
import pytest
from kubernetes import client
from dynamo.planner.kube import KubernetesAPI
from dynamo.planner.utils.exceptions import DynamoGraphDeploymentNotFoundError
from dynamo.planner.connectors.kubernetes_api import KubernetesAPI
from dynamo.planner.errors import DynamoGraphDeploymentNotFoundError
@pytest.fixture
def mock_config():
with patch("dynamo.planner.kube.config") as mock:
with patch("dynamo.planner.connectors.kubernetes_api.config") as mock:
mock.load_incluster_config = MagicMock()
yield mock
@pytest.fixture
def mock_custom_api():
with patch("dynamo.planner.kube.client.CustomObjectsApi") as mock:
with patch(
"dynamo.planner.connectors.kubernetes_api.client.CustomObjectsApi"
) as mock:
yield mock.return_value
......
......@@ -18,13 +18,9 @@ from unittest.mock import AsyncMock, Mock, call, patch
import pytest
from dynamo.planner.defaults import (
Service,
SubComponentType,
get_service_from_sub_component_type_or_name,
)
from dynamo.planner.kubernetes_connector import KubernetesConnector, TargetReplica
from dynamo.planner.utils.exceptions import (
from dynamo.planner.config.defaults import SubComponentType, TargetReplica
from dynamo.planner.connectors.kubernetes import KubernetesConnector
from dynamo.planner.errors import (
DeploymentModelNameMismatchError,
DeploymentValidationError,
DuplicateSubComponentError,
......@@ -33,6 +29,10 @@ from dynamo.planner.utils.exceptions import (
ModelNameNotFoundError,
SubComponentNotFoundError,
)
from dynamo.planner.monitoring.dgd_services import (
Service,
get_service_from_sub_component_type_or_name,
)
@pytest.fixture
......@@ -56,7 +56,7 @@ def mock_kube_api_class(mock_kube_api):
def kubernetes_connector(mock_kube_api_class, monkeypatch):
# Patch the KubernetesAPI class before instantiating the connector
monkeypatch.setattr(
"dynamo.planner.kubernetes_connector.KubernetesAPI", mock_kube_api_class
"dynamo.planner.connectors.kubernetes.KubernetesAPI", mock_kube_api_class
)
with patch.dict(os.environ, {"DYN_PARENT_DGD_K8S_NAME": "test-graph"}):
connector = KubernetesConnector("test-dynamo-namespace")
......
......@@ -16,8 +16,8 @@
import argparse
import logging
from dynamo.planner.utils.dryrun import run_sla_planner_dryrun
from dynamo.planner.utils.planner_config import PlannerConfig
from dynamo.planner.config.planner_config import PlannerConfig
from dynamo.planner.offline.dryrun import run_sla_planner_dryrun
logger = logging.getLogger(__name__)
......
......@@ -17,16 +17,16 @@ from dynamo.common.forward_pass_metrics import (
ScheduledRequestMetrics,
encode,
)
from dynamo.planner.utils.decode_planner import DecodePlanner
from dynamo.planner.utils.fpm_regression import (
from dynamo.planner.config.planner_config import PlannerConfig
from dynamo.planner.core.decode import DecodePlanner
from dynamo.planner.core.load.fpm_regression import (
AggRegressionModel,
DecodeRegressionModel,
PrefillRegressionModel,
)
from dynamo.planner.utils.planner_config import PlannerConfig
from dynamo.planner.utils.planner_core import PlannerSharedState
from dynamo.planner.utils.prefill_planner import PrefillPlanner
from dynamo.planner.worker_info import WorkerInfo
from dynamo.planner.core.prefill import PrefillPlanner
from dynamo.planner.core.state import PlannerSharedState
from dynamo.planner.monitoring.worker_info import WorkerInfo
pytestmark = [
pytest.mark.gpu_0,
......@@ -233,7 +233,7 @@ class TestAggRegressionModel:
@pytest.fixture(autouse=True)
def mock_prometheus_metrics():
with patch("dynamo.planner.utils.planner_core.Gauge") as mock_gauge:
with patch("dynamo.planner.monitoring.planner_metrics.Gauge") as mock_gauge:
mock_gauge.return_value = Mock()
yield
......
......@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for load predictor classes in dynamo.planner.utils.load_predictor."""
"""Unit tests for load predictor classes in dynamo.planner.core.load.predictors."""
import math
from datetime import datetime, timedelta
......@@ -22,7 +22,7 @@ from unittest.mock import MagicMock, patch
import pandas as pd
import pytest
from dynamo.planner.utils.load_predictor import (
from dynamo.planner.core.load.predictors import (
ConstantPredictor,
KalmanPredictor,
ProphetPredictor,
......@@ -175,7 +175,7 @@ class TestProphetPredictorTimestamp:
mock_model.predict.side_effect = fake_predict
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
predictor.predict_next()
......@@ -212,7 +212,7 @@ class TestProphetPredictorTimestamp:
mock_model.predict.side_effect = fake_predict
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
predictor.predict_next()
......@@ -248,7 +248,7 @@ class TestProphetPredictorTimestamp:
mock_model.predict.side_effect = fake_predict
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
predictor.predict_next()
......@@ -283,7 +283,7 @@ class TestProphetPredictorTimestamp:
mock_model.predict.return_value = self._mock_forecast_df(-5.0)
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
result = predictor.predict_next()
......@@ -301,7 +301,7 @@ class TestProphetPredictorTimestamp:
mock_model.predict.return_value = self._mock_forecast_df(-100.0)
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
result = predictor.predict_next()
......@@ -395,7 +395,7 @@ class TestProphetPredictorMultipleStepSizes:
mock_model.predict.side_effect = fake_predict
with patch(
"dynamo.planner.utils.load_predictor.Prophet",
"dynamo.planner.core.load.predictors.Prophet",
return_value=mock_model,
):
predictor.predict_next()
......
......@@ -6,7 +6,7 @@
import pytest
from pydantic import ValidationError
from dynamo.planner.utils.planner_config import PlannerConfig
from dynamo.planner.config.planner_config import PlannerConfig
pytestmark = [
pytest.mark.gpu_0,
......
......@@ -20,7 +20,7 @@ from unittest.mock import MagicMock, patch
import pytest
from dynamo import prometheus_names
from dynamo.planner.utils.prometheus import (
from dynamo.planner.monitoring.traffic_metrics import (
FrontendMetric,
FrontendMetricContainer,
PrometheusAPIClient,
......
......@@ -13,10 +13,10 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from dynamo.planner import SubComponentType, TargetReplica
from dynamo.planner.global_planner_connector import GlobalPlannerConnector
from dynamo.planner.remote_planner_client import RemotePlannerClient
from dynamo.planner.scale_protocol import ScaleRequest, ScaleResponse, ScaleStatus
from dynamo.planner.utils.exceptions import EmptyTargetReplicasError
from dynamo.planner.connectors.global_planner import GlobalPlannerConnector
from dynamo.planner.connectors.protocol import ScaleRequest, ScaleResponse, ScaleStatus
from dynamo.planner.connectors.remote_client import RemotePlannerClient
from dynamo.planner.errors import EmptyTargetReplicasError
async def _async_responses(*items):
......@@ -231,7 +231,7 @@ async def test_connector_initialization(connector, connector_runtime):
assert connector.remote_client is None
with patch(
"dynamo.planner.global_planner_connector.RemotePlannerClient"
"dynamo.planner.connectors.global_planner.RemotePlannerClient"
) as mock_client_class:
mock_client = MagicMock()
mock_client_class.return_value = mock_client
......
......@@ -9,11 +9,13 @@ from unittest.mock import Mock, patch
import pytest
from dynamo.planner.utils.decode_planner import DecodePlanner
from dynamo.planner.utils.exceptions import DeploymentValidationError
from dynamo.planner.utils.planner_config import PlannerConfig
from dynamo.planner.utils.planner_core import PlannerSharedState, _initialize_gpu_counts
from dynamo.planner.utils.prefill_planner import PrefillPlanner
from dynamo.planner.config.planner_config import PlannerConfig
from dynamo.planner.core.budget import _initialize_gpu_counts
from dynamo.planner.core.decode import DecodePlanner
from dynamo.planner.core.prefill import PrefillPlanner
from dynamo.planner.core.state import PlannerSharedState
from dynamo.planner.errors import DeploymentValidationError
from dynamo.planner.offline.dryrun import run_sla_planner_dryrun
pytestmark = [
pytest.mark.gpu_0,
......@@ -26,7 +28,7 @@ pytestmark = [
@pytest.fixture(autouse=True)
def mock_prometheus_metrics():
with patch("dynamo.planner.utils.planner_core.Gauge") as mock_gauge:
with patch("dynamo.planner.monitoring.planner_metrics.Gauge") as mock_gauge:
mock_gauge.return_value = Mock()
yield
......@@ -418,8 +420,6 @@ class TestDryrunGpuDefaults:
def test_dryrun_defaults_gpu_counts_when_none(self):
"""Test that dryrun sets default GPU counts of 1 when None"""
from dynamo.planner.utils.dryrun import run_sla_planner_dryrun
config = self._build_dryrun_config(
prefill_engine_num_gpu=None, decode_engine_num_gpu=None
)
......@@ -434,7 +434,6 @@ class TestDryrunGpuDefaults:
def test_dryrun_preserves_cli_gpu_counts(self):
"""Test that dryrun preserves GPU counts provided via config"""
from dynamo.planner.utils.dryrun import run_sla_planner_dryrun
config = self._build_dryrun_config(
prefill_engine_num_gpu=2, decode_engine_num_gpu=4
......
......@@ -20,7 +20,7 @@ project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
try:
from dynamo.planner.utils.planner_config import (
from dynamo.planner.config.planner_config import (
PlannerConfig,
PlannerPreDeploymentSweepMode,
)
......@@ -821,7 +821,7 @@ class TestRunProfileSkipsInterpolationForAggConfig:
import asyncio
from unittest.mock import AsyncMock, patch
from dynamo.planner.utils.planner_config import (
from dynamo.planner.config.planner_config import (
PlannerPreDeploymentSweepMode,
)
from dynamo.profiler.profile_sla import run_profile
......@@ -919,7 +919,7 @@ class TestRunProfileSkipsInterpolationForAggConfig:
import asyncio
from unittest.mock import AsyncMock, patch
from dynamo.planner.utils.planner_config import (
from dynamo.planner.config.planner_config import (
PlannerPreDeploymentSweepMode,
)
from dynamo.profiler.profile_sla import run_profile
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment