Adaptive GPU governor for the AMD Cyan Skillfish APU.
It continuously tracks GPU load, maintains a target frequency, and adjusts GPU frequency when the deviation is large enough. It also supports burst behavior for sustained load and optional thermal throttling.
This version can set frequency/voltage using either:
- the SMU API (thanks to bc250collective)
- kernel sysfs controls
- Samples GPU load and computes a moving target frequency.
- Applies frequency changes only when meaningful (unless burst mode forces faster response).
- Optionally throttles with temperature limits.
- Optionally exposes a D-Bus interface to toggle a high-performance mode.
cyan-skillfish-governor-smu [-v|--verbose] [CONFIG]CONFIGis an optional TOML path.- If
CONFIGis omitted, internal defaults are used.
Prebuilt/community packaging references:
- AUR: https://aur.archlinux.org/packages/cyan-skillfish-governor-smu
- COPR (Fedora/Bazzite): https://copr.fedorainfracloud.org/coprs/filippor/bazzite/
- ARCHIVE: https://github.com/filippor/cyan-skillfish-governor/releases
Bazzite
Bazzite can consume the same COPR package source. On mutable setups, use the Fedora steps below.
On rpm-ostree based setups, layer the package and reboot:
sudo rpm-ostree install cyan-skillfish-governor-smu
systemctl rebootConfiguration file location:
/etc/cyan-skillfish-governor-smu/config.tomlFedora
Enable the COPR repository and install:
sudo dnf copr enable filippor/bazzite
sudo dnf install cyan-skillfish-governor-smuConfiguration file location:
/etc/cyan-skillfish-governor-smu/config.tomlArch
Install from AUR package cyan-skillfish-governor-smu with your preferred AUR helper:
paru -S cyan-skillfish-governor-smuConfiguration file location:
/etc/cyan-skillfish-governor-smu/config.tomlGeneric Linux
If your distribution is not listed above, you can install from a release archive.
-
Download the latest release archive from GitHub Releases.
-
Extract and enter the directory:
tar -xf cyan-skillfish-governor-*.tar.gz
cd cyan-skillfish-governor-*-
Make sure the binary is available in the extracted directory (for example by using a release archive that already contains
cyan-skillfish-governor-smu, or by building it withcargo build --release). -
Run the installer script:
chmod +x scripts/install.sh
sudo ./scripts/install.shInstalled configuration location:
/etc/cyan-skillfish-governor-smu/config.tomlBuild from sources
Clone the repository (smu branch), then build:
git clone --branch smu https://github.com/filippor/cyan-skillfish-governor.git
cd cyan-skillfish-governorBuild the binary with:
cargo build --releaseThen use the binary at:
./target/release/cyan-skillfish-governor-smuFor a manual run test with an explicit config file:
./target/release/cyan-skillfish-governor-smu ./config.tomlBefore enabling at boot, test one manual start and check logs:
systemctl start cyan-skillfish-governor-smuAfter that, run a real GPU workload (for example a benchmark or a game) for a few minutes and re-check service logs to confirm expected behavior under load. check log
systemctl status cyan-skillfish-governor-smu
sudo journalctl -u cyan-skillfish-governor-smu -n 100 --no-pagerIf everything looks good, then enable it:
systemctl enable cyan-skillfish-governor-smuafter configuration change restart the service with
systemctl restart cyan-skillfish-governor-smuTop-level keys:
-
gpu-usage(also accepts legacygpu_usage)fix-metrics(bool, default:true): enable GPU usage metrics patching.method("busy-flag"or"process", default:"busy-flag"): how load is sampled proces is more CPU intensive scan all process that use GPU.flush-every(integer, default:10): flush patched metrics every N update cycles.
-
gpuset-method("smu"or"kernel", default:"smu"): backend used to apply frequency/voltage.
-
dbusenabled(bool, default:false): enable D-Bus performance-mode service.
-
frequency-range(optional)min(optional integer, MHz): initial minimum frequency limit. Default: hardware minimum.max(optional integer, MHz): initial maximum frequency limit. Default: hardware maximum.- Both can be omitted for full range. Can be overridden at runtime via D-Bus.
-
timingintervals(microseconds)sample(default:2000): sampling period. Used bygpu-usage.method = "busy-flag".adjust(default:sample * 10): control-loop period.
burst-samples(optional integer1..=64, default: disabled): number of consecutive busy samples needed to enter burst mode.0, negative, out-of-range, or missing value disables burst mode.
down-events(integer, default:10): number of low-load events (belowload-target.lower) required before stepping down.ramp-rates(MHz/ms)normal(default:1.0): normal ramp rate.burst(default:200 * normal): burst ramp rate. Must be greater thannormal.
-
frequency-thresholdsadjust(MHz, default:10): minimum proposed frequency delta required to apply a non-burst change.
-
load-target(fraction)upper(default:0.95): load above which target frequency increases.lower(default:upper - 0.15): load below which target frequency decreases.
-
temperature(degrees C)throttling(optional integer0..=110, default when missing:85): above this temperature, max allowed frequency is reduced.throttling_recovery(optional): below this temperature, max frequency is restored.- Must be at least
1and strictly less thanthrottling. - Missing value keeps recovery disabled.
- Must be at least
-
safe-points- Array of
{ frequency, voltage }tables. frequencyin MHz,voltagein mV.- Must be non-empty when provided.
- For increasing frequency, voltage must not decrease.
- If missing entirely, conservative built-in defaults are used.
- Array of
Use default-config.toml as a baseline profile.
The configuration option dbus.enabled must be set to true.
Performance mode:
- Sets frequency to max by default,
- Reduces load-check overhead (and skips load calculation entirely when
gpu-usage.fix-metricsis disabled), - Keeps thermal throttling active.
The script communicates with the governor via D-Bus (see D-Bus Interface section).
Prerequisites:
- Governor service must be running and D-Bus enabled.
busctl(preferred) ordbus-sendavailable on the system.
- Toggle and set frequency:
cyan-skillfish-performance-mode --on
cyan-skillfish-performance-mode --fixed-frequency 1200
cyan-skillfish-performance-mode --range 500 1500
cyan-skillfish-performance-mode --off
cyan-skillfish-performance-mode --status- Wrap a command (auto-enable then auto-disable on exit):
cyan-skillfish-performance-mode mangohud %command%
cyan-skillfish-performance-mode --fixed-frequency 1200 mangohud %command%
cyan-skillfish-performance-mode --range 700 1500 some-game- Steam launch option example:
cyan-skillfish-performance-mode %command%
cyan-skillfish-performance-mode --fixed-frequency 1200 %command%If needed, you can pass -- before the wrapped command:
cyan-skillfish-performance-mode --fixed-frequency 1200 -- mangohud %command%In wrapper mode, the script installs a cleanup trap, so performance mode is disabled when the wrapped process exits (including Ctrl+C / TERM paths handled by the script).
D-Bus service exposed when dbus.enabled = true:
- Service:
com.cyan.SkillFishGovernor - Object:
/com/cyan/SkillFishGovernor - Interface:
com.cyan.SkillFishGovernor.PerformanceMode
Enable()— Enable performance mode (max frequency, reduced load overhead)Disable()— Disable performance mode (return to adaptive frequency control)SetFixedFrequency(frequency: u32)— Set fixed frequency in MHz (enables performance mode)SetRange(min: u32, max: u32)— Set frequency range limits (MHz). Use0for no limit:SetRange(0, 1500)— cap to 1500 MHzSetRange(500, 0)— floor to 500 MHzSetRange(500, 1500)— set both limitsSetRange(0, 0)— clear all limits (full range)- Thermal throttling still applies regardless of range
Enabled(bool, read/write) — Get or set performance mode enabled state
# Using busctl (preferred)
busctl --system call com.cyan.SkillFishGovernor /com/cyan/SkillFishGovernor com.cyan.SkillFishGovernor.PerformanceMode Enable
busctl --system call com.cyan.SkillFishGovernor /com/cyan/SkillFishGovernor com.cyan.SkillFishGovernor.PerformanceMode SetFixedFrequency u 1200
busctl --system call com.cyan.SkillFishGovernor /com/cyan/SkillFishGovernor com.cyan.SkillFishGovernor.PerformanceMode SetRange uu 500 1500
busctl --system call com.cyan.SkillFishGovernor /com/cyan/SkillFishGovernor com.cyan.SkillFishGovernor.PerformanceMode Disable
# Using dbus-send (if busctl unavailable)
dbus-send --system --dest=com.cyan.SkillFishGovernor /com/cyan/SkillFishGovernor com.cyan.SkillFishGovernor.PerformanceMode.SetRange uint32:500 uint32:1500If the service does not behave as expected, run the governor directly with verbose logging and an explicit config path:
sudo cyan-skillfish-governor-smu --verbose /etc/cyan-skillfish-governor-smu/config.tomlIf you are running from a local build tree instead of the installed binary:
./target/release/cyan-skillfish-governor-smu --verbose ./config.tomlThis helps isolate whether issues come from systemd startup or from configuration/runtime behavior.