From dcc2640583a4015e9dd40823331589fd8294d0ee Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 11 Mar 2024 13:08:07 +0100 Subject: [PATCH] uncore: Allow to configure frequency limits using percent Using direct frequency values in only useful in specialistic profiles where we know target platform. Add 'max_freq_pct' and 'min_freq_pct' parameters that allow to specify limit of uncore frequency as percent of hardware maximum/minimum frequency. Such parameters can be used in generic profiles like 'balanced' in portable way, for example: [uncore] max_freq_pct=90 Signed-off-by: Stanislaw Gruszka --- tuned/plugins/plugin_uncore.py | 121 +++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/tuned/plugins/plugin_uncore.py b/tuned/plugins/plugin_uncore.py index 76af767d..b4fee7e5 100644 --- a/tuned/plugins/plugin_uncore.py +++ b/tuned/plugins/plugin_uncore.py @@ -75,11 +75,25 @@ def _set(self, dev_dir, file, value): return value return None + def _get_all(self, device): + try: + initial_max_freq_khz = self._get(device, "initial_max_freq_khz") + initial_min_freq_khz = self._get(device, "initial_min_freq_khz") + max_freq_khz = self._get(device, "max_freq_khz") + min_freq_khz = self._get(device, "min_freq_khz") + except (OSError, IOError): + log.error("fail to read uncore frequency values") + return None + return (initial_max_freq_khz, initial_min_freq_khz, max_freq_khz, min_freq_khz) + @classmethod def _get_config_options(cls): return { "max_freq_khz": None, "min_freq_khz": None, + + "max_freq_pct": None, + "min_freq_pct": None, } def _validate_value(self, device, min_or_max, value): @@ -89,14 +103,10 @@ def _validate_value(self, device, min_or_max, value): log.error("value '%s' is not integer" % value) return None - try: - initial_max_freq_khz = self._get(device, "initial_max_freq_khz") - initial_min_freq_khz = self._get(device, "initial_min_freq_khz") - max_freq_khz = self._get(device, "max_freq_khz") - min_freq_khz = self._get(device, "min_freq_khz") - except (OSError, IOError): - log.error("fail to read inital uncore frequency values") + values = self._get_all(device) + if values is None: return None + (initial_max_freq_khz, initial_min_freq_khz, max_freq_khz, min_freq_khz) = values if min_or_max == IS_MAX: if freq_khz < min_freq_khz: @@ -121,6 +131,19 @@ def _validate_value(self, device, min_or_max, value): return freq_khz + def _validate_percent_value(self, value): + try: + pct = int(value) + except ValueError: + log.error("value '%s' is not integer" % value) + return None + + if pct < 0 or pct > 100: + log.error("percent value '%s' is not within [0..100] range" % value) + return None + + return pct + @command_set("max_freq_khz", per_device = True) def _set_max_freq_khz(self, value, device, sim, remove): max_freq_khz = self._validate_value(device, IS_MAX, value) @@ -172,3 +195,87 @@ def _get_min_freq_khz(self, device, ignore_missing=False): log.debug("%s: get min_freq_khz %d" % (device, min_freq_khz)) return min_freq_khz + + @command_set("max_freq_pct", per_device = True) + def _set_max_freq_pct(self, value, device, sim, remove): + pct = self._validate_percent_value(value) + if pct is None: + return None + + values = self._get_all(device) + if values is None: + return None + (initial_max_freq_khz, initial_min_freq_khz, _, _) = values + + khz = pct * (initial_max_freq_khz - initial_min_freq_khz) / 100 + max_freq_khz = khz + initial_min_freq_khz + + if self._validate_value(device, IS_MAX, max_freq_khz) != max_freq_khz: + return None + + if sim: + return pct + + if self._set(device, "max_freq_khz", max_freq_khz) != max_freq_khz: + return None + + log.debug("%s: set max_freq_pct %d" % (device, pct)) + return pct + + @command_get("max_freq_pct") + def _get_max_freq_pct(self, device, ignore_missing=False): + if ignore_missing and not os.path.isdir(SYSFS_DIR): + return None + + values = self._get_all(device) + if values is None: + return None + (initial_max_freq_khz, initial_min_freq_khz, max_freq_khz, _) = values + + khz = max_freq_khz - initial_min_freq_khz + pct = 100 * khz / (initial_max_freq_khz - initial_min_freq_khz) + + log.debug("%s: get max_freq_pct %d" % (device, pct)) + return pct + + @command_set("min_freq_pct", per_device = True) + def _set_min_freq_pct(self, value, device, sim, remove): + pct = self._validate_percent_value(value) + if pct is None: + return None + + values = self._get_all(device) + if values is None: + return None + (initial_max_freq_khz, initial_min_freq_khz, _, _) = values + + khz = pct * (initial_max_freq_khz - initial_min_freq_khz) / 100 + min_freq_khz = khz + initial_min_freq_khz + + if self._validate_value(device, IS_MIN, min_freq_khz) != min_freq_khz: + return None + + if sim: + return pct + + if self._set(device, "min_freq_khz", min_freq_khz) != min_freq_khz: + return None + + log.debug("%s: set min_freq_pct %d" % (device, pct)) + return pct + + @command_get("min_freq_pct") + def _get_min_freq_pct(self, device, ignore_missing=False): + if ignore_missing and not os.path.isdir(SYSFS_DIR): + return None + + values = self._get_all(device) + if values is None: + return None + (initial_max_freq_khz, initial_min_freq_khz, _, min_freq_khz) = values + + khz = min_freq_khz - initial_min_freq_khz + pct = 100 * khz / (initial_max_freq_khz - initial_min_freq_khz) + + log.debug("%s: get min_freq_pct %d" % (device, pct)) + return pct