Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a plugin for amdgpu tuning of the panel_power_savings attribute #601

Merged
merged 4 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions profiles/accelerator-performance/tuned.conf
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ sched_min_granularity_ns = 10000000
# and reduces their over-scheduling. Synchronous workloads will still
# have immediate wakeup/sleep latencies.
sched_wakeup_granularity_ns = 15000000

[video]
panel_power_savings=0
1 change: 1 addition & 0 deletions profiles/balanced/tuned.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ timeout=10

[video]
radeon_powersave=dpm-balanced, auto
panel_power_savings=0

[disk]
# Comma separated list of devices, all devices if commented out.
Expand Down
3 changes: 3 additions & 0 deletions profiles/latency-performance/tuned.conf
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ vm.dirty_background_ratio=3
# 100 tells the kernel to aggressively swap processes out of physical memory
# and move them to swap cache
vm.swappiness=10

[video]
panel_power_savings=0
1 change: 1 addition & 0 deletions profiles/powersave/tuned.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ timeout=10

[video]
radeon_powersave=dpm-battery, auto
panel_power_savings=3

[disk]
# Comma separated list of devices, all devices if commented out.
Expand Down
3 changes: 3 additions & 0 deletions profiles/throughput-performance/tuned.conf
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,6 @@ type=sysctl
uname_regex=aarch64
cpuinfo_regex=${thunderx_cpuinfo_regex}
kernel.numa_balancing=0

[video]
panel_power_savings=0
84 changes: 72 additions & 12 deletions tuned/plugins/plugin_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
class VideoPlugin(base.Plugin):
"""
`video`::

Sets various powersave levels on video cards. Currently, only the
Radeon cards are supported. The powersave level can be specified

Sets various power saving features on video cards.
Radeon cards are supported.
The powersave level can be specified
by using the [option]`radeon_powersave` option. Supported values are:
+
--
Expand All @@ -40,17 +41,27 @@ class VideoPlugin(base.Plugin):
radeon_powersave=high
----
====

Mobile hardware with amdgpu driven eDP panels can be configured
with the [option]`panel_power_savings` option.
This accepts a value range from 0 to 4, where 4 is the highest power savings
but will trade off color accuracy.
"""

def __init__(self, *args, **kwargs):
super(VideoPlugin, self).__init__(*args, **kwargs)

def _init_devices(self):
self._devices_supported = True
self._free_devices = set()
self._assigned_devices = set()

# FIXME: this is a blind shot, needs testing
for device in self._hardware_inventory.get_devices("drm").match_sys_name("card*").match_property("DEVTYPE", "drm_minor"):
self._free_devices.add(device.sys_name)

# Add any radeon and amdgpu hardware with /any/ supported attributes present
for device in self._hardware_inventory.get_devices("drm").match_sys_name("card*-*"):
attrs = self._files(device.sys_name)
for attr in attrs:
if os.path.exists(attrs[attr]):
self._free_devices.add(device.sys_name)
self._cmd = commands()

def _get_device_objects(self, devices):
Expand All @@ -60,6 +71,7 @@ def _get_device_objects(self, devices):
def _get_config_options(self):
return {
"radeon_powersave" : None,
"panel_power_savings": None,
}

def _instance_init(self, instance):
Expand All @@ -69,20 +81,42 @@ def _instance_init(self, instance):
def _instance_cleanup(self, instance):
pass

def _radeon_powersave_files(self, device):
def _files(self, device):
return {
"method" : "/sys/class/drm/%s/device/power_method" % device,
"profile": "/sys/class/drm/%s/device/power_profile" % device,
"dpm_state": "/sys/class/drm/%s/device/power_dpm_state" % device
"dpm_state": "/sys/class/drm/%s/device/power_dpm_state" % device,
"panel_power_savings": "/sys/class/drm/%s/amdgpu/panel_power_savings" % device,
}

def apply_panel_power_saving_target(self, device, target, sim=False):
"""Apply the target value to the panel_power_savings file if it doesn't already have it"""

# if we don't have the file, we might be radeon not amdgpu
if not os.path.exists(self._files(device)["panel_power_savings"]):
return None

# make sure the value is different (avoids unnecessary kernel modeset)
current = int(self._get_panel_power_savings(device))
if current == target:
log.info(
"panel_power_savings for %s already %s" % (device, target)
)
return target

# flush it out
log.info("%s panel_power_savings -> %s" % (device, target))
if sim or self._cmd.write_to_file(self._files(device)["panel_power_savings"], target):
return target
return None

@command_set("radeon_powersave", per_device=True)
def _set_radeon_powersave(self, value, device, sim, remove):
sys_files = self._radeon_powersave_files(device)
sys_files = self._files(device)
va = str(re.sub(r"(\s*:\s*)|(\s+)|(\s*;\s*)|(\s*,\s*)", " ", value)).split()
if not os.path.exists(sys_files["method"]):
if not sim:
log.warn("radeon_powersave is not supported on '%s'" % device)
log.debug("radeon_powersave is not supported on '%s'" % device)
return None
for v in va:
if v in ["default", "auto", "low", "mid", "high"]:
Expand Down Expand Up @@ -114,7 +148,10 @@ def _set_radeon_powersave(self, value, device, sim, remove):

@command_get("radeon_powersave")
def _get_radeon_powersave(self, device, ignore_missing = False):
sys_files = self._radeon_powersave_files(device)
sys_files = self._files(device)
if not os.path.exists(sys_files["method"]):
log.debug("radeon_powersave is not supported on '%s'" % device)
return None
method = self._cmd.read_file(sys_files["method"], no_error=ignore_missing).strip()
if method == "profile":
return self._cmd.read_file(sys_files["profile"]).strip()
Expand All @@ -124,3 +161,26 @@ def _get_radeon_powersave(self, device, ignore_missing = False):
return "dpm-" + self._cmd.read_file(sys_files["dpm_state"]).strip()
else:
return None

@command_set("panel_power_savings", per_device=True)
def _set_panel_power_savings(self, value, device, sim, remove):
superm1 marked this conversation as resolved.
Show resolved Hide resolved
"""Set the panel_power_savings value"""
try:
value = int(value, 10)
except ValueError:
log.warn("Invalid value %s for panel_power_savings" % value)
return None
if value in range(0, 5):
return self.apply_panel_power_saving_target(device, value, sim)
else:
log.warn("Invalid value %s for panel_power_savings" % value)
return None

@command_get("panel_power_savings")
def _get_panel_power_savings(self, device, ignore_missing=False):
"""Get the current panel_power_savings value"""
if not os.path.exists(self._files(device)["panel_power_savings"]):
log.debug("panel_power_savings is not supported on '%s'" % device)
return None
fname = self._files(device)["panel_power_savings"]
return self._cmd.read_file(fname, no_error=ignore_missing).strip()