Coverage for mlos_bench/mlos_bench/tests/optimizers/mlos_core_opt_df_test.py: 100%
34 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
1#
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4#
5"""Unit tests for internal methods of the `MlosCoreOptimizer`."""
8import pandas
9import pytest
11from mlos_bench.optimizers.mlos_core_optimizer import MlosCoreOptimizer
12from mlos_bench.tests import SEED
13from mlos_bench.tunables.tunable_groups import TunableGroups
15# pylint: disable=redefined-outer-name, protected-access
18@pytest.fixture
19def mlos_core_optimizer(tunable_groups: TunableGroups) -> MlosCoreOptimizer:
20 """An instance of a mlos_core optimizer (FLAML-based)."""
21 test_opt_config = {
22 "optimizer_type": "FLAML",
23 "max_suggestions": 10,
24 "seed": SEED,
25 "optimization_targets": {
26 "latency": "min",
27 "throughput": "max",
28 },
29 }
30 return MlosCoreOptimizer(tunable_groups, test_opt_config)
33def test_df(mlos_core_optimizer: MlosCoreOptimizer, mock_configs: list[dict]) -> None:
34 """Test `MlosCoreOptimizer._to_df()` method on tunables that have special values."""
35 df_config = mlos_core_optimizer._to_df(mock_configs)
36 assert isinstance(df_config, pandas.DataFrame)
37 assert df_config.shape == (4, 6)
38 assert set(df_config.columns) == {
39 "kernel_sched_latency_ns",
40 "kernel_sched_migration_cost_ns",
41 "kernel_sched_migration_cost_ns!type",
42 "kernel_sched_migration_cost_ns!special",
43 "idle",
44 "vmSize",
45 }
46 assert df_config.to_dict(orient="records") == [
47 {
48 "idle": "halt",
49 "kernel_sched_latency_ns": 1000000,
50 "kernel_sched_migration_cost_ns": 50000,
51 "kernel_sched_migration_cost_ns!special": None,
52 "kernel_sched_migration_cost_ns!type": "range",
53 "vmSize": "Standard_B4ms",
54 },
55 {
56 "idle": "halt",
57 "kernel_sched_latency_ns": 2000000,
58 "kernel_sched_migration_cost_ns": 40000,
59 "kernel_sched_migration_cost_ns!special": None,
60 "kernel_sched_migration_cost_ns!type": "range",
61 "vmSize": "Standard_B4ms",
62 },
63 {
64 "idle": "mwait",
65 "kernel_sched_latency_ns": 3000000,
66 "kernel_sched_migration_cost_ns": None, # The value is special!
67 "kernel_sched_migration_cost_ns!special": -1,
68 "kernel_sched_migration_cost_ns!type": "special",
69 "vmSize": "Standard_B4ms",
70 },
71 {
72 "idle": "mwait",
73 "kernel_sched_latency_ns": 4000000,
74 "kernel_sched_migration_cost_ns": 200000,
75 "kernel_sched_migration_cost_ns!special": None,
76 "kernel_sched_migration_cost_ns!type": "range",
77 "vmSize": "Standard_B2s",
78 },
79 ]
82def test_df_str(mlos_core_optimizer: MlosCoreOptimizer, mock_configs: list[dict]) -> None:
83 """Test `MlosCoreOptimizer._to_df()` type coercion on tunables with string
84 values.
85 """
86 df_config_orig = mlos_core_optimizer._to_df(mock_configs)
87 df_config_str = mlos_core_optimizer._to_df(
88 [{key: str(val) for (key, val) in config.items()} for config in mock_configs]
89 )
90 assert df_config_orig.equals(df_config_str)
93def test_adjust_signs_df(mlos_core_optimizer: MlosCoreOptimizer) -> None:
94 """Test `MlosCoreOptimizer._adjust_signs_df()` on different types of inputs."""
95 df_scores_input = pandas.DataFrame(
96 {
97 "latency": [88.88, 66.66, 99.99, None],
98 "throughput": [111, 222, 333, None],
99 }
100 )
102 df_scores_output = pandas.DataFrame(
103 {
104 "latency": [88.88, 66.66, 99.99, float("NaN")],
105 "throughput": [-111, -222, -333, float("NaN")],
106 }
107 )
109 # Make sure we adjust the signs for minimization.
110 df_scores = mlos_core_optimizer._adjust_signs_df(df_scores_input)
111 assert df_scores.equals(df_scores_output)
113 # Check that the same operation works for string inputs.
114 df_scores = mlos_core_optimizer._adjust_signs_df(df_scores_input.astype(str))
115 assert df_scores.equals(df_scores_output)
118def test_adjust_signs_df_nan(mlos_core_optimizer: MlosCoreOptimizer) -> None:
119 """Test `MlosCoreOptimizer._adjust_signs_df()` handling None, NaN, and Inf
120 values.
121 """
122 df_scores = mlos_core_optimizer._adjust_signs_df(
123 pandas.DataFrame(
124 {
125 "latency": ["88.88", "NaN", "Inf", "-Inf", None],
126 "throughput": ["111", "NaN", "Inf", "-Inf", None],
127 }
128 )
129 )
131 assert df_scores.equals(
132 pandas.DataFrame(
133 {
134 "latency": [88.88, float("NaN"), float("Inf"), float("-Inf"), float("NaN")],
135 "throughput": [-111, float("NaN"), float("-Inf"), float("Inf"), float("NaN")],
136 }
137 )
138 )
141def test_adjust_signs_df_invalid(mlos_core_optimizer: MlosCoreOptimizer) -> None:
142 """Test `MlosCoreOptimizer._adjust_signs_df()` on invalid inputs."""
143 with pytest.raises(ValueError):
144 mlos_core_optimizer._adjust_signs_df(
145 pandas.DataFrame(
146 {
147 "latency": ["INVALID"],
148 "throughput": ["no input"],
149 }
150 )
151 )
153 with pytest.raises(ValueError):
154 mlos_core_optimizer._adjust_signs_df(
155 pandas.DataFrame(
156 {
157 "latency": ["88.88", ""],
158 "throughput": ["111", ""],
159 }
160 )
161 )