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