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