X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FMLRsearch%2Fconfig.py;fp=resources%2Flibraries%2Fpython%2FMLRsearch%2Fconfig.py;h=7aa8ed75a81047f218a56006e25c46d4af31c3f3;hb=e5dbe10d9599b9a53fa07e6fadfaf427ba6d69e3;hp=0000000000000000000000000000000000000000;hpb=c6dfb6c09c5dafd1d522f96b4b86c5ec5efc1c83;p=csit.git diff --git a/resources/libraries/python/MLRsearch/config.py b/resources/libraries/python/MLRsearch/config.py new file mode 100644 index 0000000000..7aa8ed75a8 --- /dev/null +++ b/resources/libraries/python/MLRsearch/config.py @@ -0,0 +1,179 @@ +# Copyright (c) 2023 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Module defining Config class.""" + +from collections.abc import Iterable +from dataclasses import dataclass +from typing import Optional + +from .dataclass import DataclassProperty +from .search_goal import SearchGoal +from .search_goal_tuple import SearchGoalTuple + + +@dataclass +class Config: + """Structure containing several static config items. + + The main MLRsearch algorithm uses multiple customizable values. + Pylint complains if the values appear as long argument lists + or multiple local variables. + + This class offers a storage for values which do not contain + internally mutable state and are set at an unknown time + before the search starts. This way users can override only some values, + and do it over multiple calls. + All "official" user inputs are contained here. + + Properties are defined to enforce the requirements on allowed values. + All fields have default values, so instances can be created without any. + It is still recommended to set all values after instantiation, + as the defaults may change in the next version. + + As some relations between values of different fields are required, + users must take care to set them in the correct order. + + For example, min_load has to be set to a value smaller + than the current value of max_load. + """ + + # Externally visible "fields" (but in fact redefined as properties). + goals: SearchGoalTuple = SearchGoalTuple((SearchGoal(),)) + """Container holding search goals.""" + min_load: float = 9001.0 + """Each trial measurement must have intended load at least this [tps].""" + max_load: float = 1e9 + """Each trial measurement must have intended load at most this [tps].""" + search_duration_max: float = 1200.0 + """The search will end as a failure this long [s] after it is started.""" + warmup_duration: float = 1.0 + """If specified, one trial at max load and this duration is performed + before the usual search starts. None converts to zero and means no warmup. + The results of that one trial are ignored.""" + + @DataclassProperty + def goals(self) -> SearchGoalTuple: + """Return the reference to the current container of goals. + + :returns: The current container instance. + :rtype: SearchGoalTuple + """ + return self._goals + + @goals.setter + def goals(self, goals: Iterable[SearchGoal]) -> None: + """Create and store the goal container. + + :param goals: Search goals to add to the container to store. + :type goals: Iterable[SearchGoal] + :raises ValueError: If there are no goals. + :raises TypeError: If any of the goals is not a SearchGoal. + """ + self._goals = SearchGoalTuple(goals) + + @DataclassProperty + def min_load(self) -> float: + """Getter for min load, no logic here. + + :returns: Currently set minimal intended load [tps]. + :rtype: float + """ + return self._min_load + + @min_load.setter + def min_load(self, load: float) -> None: + """Set min load after converting type and checking value. + + :param load: Minimal intended load [tps] to set. + :type load: float + :raises ValueError: If the argument is found invalid. + """ + load = float(load) + if load <= 0.0: + raise ValueError(f"Min load {load} must be positive.") + # At the time init is first called, _max_load is not set yet. + if hasattr(self, "_max_load") and load >= self.max_load: + raise ValueError(f"Min load {load} must be smaller.") + self._min_load = load + + @DataclassProperty + def max_load(self) -> float: + """Getter for max load, no logic here. + + :returns: Currently set maximal intended load [tps]. + :rtype: float + """ + return self._max_load + + @max_load.setter + def max_load(self, load: float) -> None: + """Set max load after converting type and checking value. + + :param load: Minimal intended load [tps] to set. + :type load: float + :raises ValueError: If the argument is found invalid. + """ + load = float(load) + if load <= self.min_load: + raise ValueError(f"Max load {load} must be bigger.") + self._max_load = load + + @DataclassProperty + def search_duration_max(self) -> float: + """Getter for max search duration, no logic here. + + :returns: Currently set max search duration [s]. + :rtype: float + """ + return self._search_duration_max + + @search_duration_max.setter + def search_duration_max(self, duration: float) -> None: + """Set max search duration after converting and checking value. + + :param duration: Search duration maximum [s] to set. + :type duration: float + :raises ValueError: If the argument is found invalid. + """ + duration = float(duration) + if duration <= 0.0: + raise ValueError(f"Search duration max too small: {duration}") + self._search_duration_max = duration + + @DataclassProperty + def warmup_duration(self) -> float: + """Getter for warmup duration, no logic here. + + :returns: Currently set max search duration [s]. + :rtype: float + """ + return self._warmup_duration + + @warmup_duration.setter + def warmup_duration(self, duration: Optional[float]) -> None: + """Set warmup duration after converting and checking value. + + Zero duration is treated as None, meaning no warmup trial. + + :param duration: Warmup duration [s] to set. + :type duration: Optional(float) + :raises ValueError: If the argument is found invalid. + """ + if duration: + duration = float(duration) + if duration < 0.0: + raise ValueError(f"Warmup duration too small: {duration}") + else: + duration = 0.0 + self._warmup_duration = duration