1
0
Fork 0

Add intel uncore plugin

Add simplistic intel uncore plugin to so that uncore maximum and
minimum frequency can be set.

For example lowering uncore maximum frequency can have significant
impact on the total power consummation of SoC.

Refer to the following link to get details:
https://docs.kernel.org/admin-guide/pm/intel_uncore_frequency_scaling.html

When system with TPMI (Topology Aware Register and PM Capsule Interface)
is detected only devices configured via TPMI are used, since configuring
via deprecated (package/die) interface create conflict on new systems.

Plugin allow to configure frequency per individual uncore units, example
profile config options can look like this:

[intel_uncore_all0] # power save
type=intel_uncore
devices=uncore0*
max_freq_khz=2000000

[intel_uncore_10] # performance
type=intel_uncore
devices=uncore10
min_freq_khz=4000000

[intel_uncore] # for all others save power with little performance cost
max_freq_khz=4600000

For systems where maximum/minimum configured frequency is above/below
the system limits, values are capped to the limit. Wrong configuration
i.e. maximum frequency below minimum frequency is skipped and errors
are logged.

TODO:

- Create matching functions in (tuned/profiles/functions) to allow
  to identify cpus belongs to uncore unit as well uncore TPMI unit
  based on power domain/package/die.
- Add uncore frequency configuration to basics or specialistic profiles.

Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
This commit is contained in:
Stanislaw Gruszka 2024-01-18 06:34:59 -05:00
parent 95be4c0d68
commit 2055284ba0

View file

@ -0,0 +1,174 @@
from . import hotplug
from .decorators import *
import tuned.logs
from tuned.utils.commands import commands
import os
import fnmatch
log = tuned.logs.get()
cmd = commands()
SYSFS_DIR = "/sys/devices/system/cpu/intel_uncore_frequency/"
IS_MIN = 0
IS_MAX = 1
class IntelUncorePlugin(hotplug.Plugin):
"""
`intel_uncore`::
`max_freq_khz, min_freq_khz`:::
Limit the maximum and minumum uncore frequency.
====
----
[intel_uncore]
max_freq_khz=4000000
----
Using this options *TuneD* will limit maximum frequency of all uncore units
in the system to 4 GHz
====
"""
def _init_devices(self):
self._devices_supported = True
self._assigned_devices = set()
self._free_devices = set()
self._is_tpmi = False
try:
devices = os.listdir(SYSFS_DIR)
except OSError:
return
# For new TPMI interface use only uncore devices
tpmi_devices = fnmatch.filter(devices, 'uncore*')
if len(tpmi_devices) > 0:
self._is_tpmi = True # Not used at present but can be usefull in future
devices = tpmi_devices
for d in devices:
self._free_devices.add(d)
log.debug("devices: %s", str(self._free_devices))
def _instance_init(self, instance):
instance._has_static_tuning = True
instance._has_dynamic_tuning = False
def _instance_cleanup(self, instance):
pass
def _device_module_name(self, device):
return "intel_uncore_frequency"
def _get(self, dev_dir, file):
sysfs_file = SYSFS_DIR + dev_dir + "/" + file
value = cmd.read_file(sysfs_file)
if len(value) > 0:
return int(value)
return None
def _set(self, dev_dir, file, value):
sysfs_file = SYSFS_DIR + dev_dir + "/" + file
if cmd.write_to_file(sysfs_file, "%u" % value):
return value
return None
@classmethod
def _get_config_options(cls):
return {
"max_freq_khz": None,
"min_freq_khz": None,
}
def _validate_value(self, device, min_or_max, value):
try:
freq_khz = int(value)
except ValueError:
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")
return None
if min_or_max == IS_MAX:
if freq_khz < min_freq_khz:
log.error("%s max_freq_khz %d value below min_freq_khz %d" % (device, freq_khz, min_freq_khz))
return None
if freq_khz > initial_max_freq_khz:
log.info("%s: max_freq_khz %d above initial_max_freq_khz - capped to %d" % (device, freq_khz, initial_max_freq_khz))
freq_khz = initial_max_freq_khz
elif min_or_max == IS_MIN:
if freq_khz > max_freq_khz:
log.error("%s: min_freq_khz %d value above max_freq_khz %d" % (device, freq_khz, max_freq_khz))
return None
if freq_khz < initial_min_freq_khz:
log.info("%s: min_freq_khz %d below initial_max_freq_khz - capped to %d" % (device, freq_khz, initial_min_freq_khz))
freq_khz = initial_min_freq_khz
else:
return None
return freq_khz
@command_set("max_freq_khz", per_device = True)
def _set_max_freq_khz(self, value, device, sim):
max_freq_khz = self._validate_value(device, IS_MAX, value)
if max_freq_khz is None:
return None
if sim:
return max_freq_khz
log.debug("%s: set max_freq_khz %d" % (device, max_freq_khz))
return self._set(device, "max_freq_khz", max_freq_khz)
@command_get("max_freq_khz")
def _get_max_freq_khz(self, device, ignore_missing=False):
if ignore_missing and not os.path.isdir(SYSFS_DIR):
return None
try:
max_freq_khz = self._get(device, "max_freq_khz")
except (OSError, IOError):
log.error("fail to read uncore frequency values")
return None
log.debug("%s: get max_freq_khz %d" % (device, max_freq_khz))
return max_freq_khz
@command_set("min_freq_khz", per_device = True)
def _set_min_freq_khz(self, value, device, sim):
min_freq_khz = self._validate_value(device, IS_MIN, value)
if min_freq_khz is None:
return None
if sim:
return min_freq_khz
log.debug("%s: set min_freq_khz %d" % (device, min_freq_khz))
return self._set(device, "min_freq_khz", min_freq_khz)
@command_get("min_freq_khz")
def _get_min_freq_khz(self, device, ignore_missing=False):
if ignore_missing and not os.path.isdir(SYSFS_DIR):
return None
try:
min_freq_khz = self._get(device, "min_freq_khz")
except (OSError, IOError):
log.error("fail to read uncore frequency values")
return None
log.debug("%s: get min_freq_khz %d" % (device, min_freq_khz))
return min_freq_khz