The fan won't stop spinning
You just finished a heavy compile or a video render on your Fedora desktop. The machine cools down, but the CPU fans keep screaming at full speed. Or maybe you are on a laptop, the battery drains in two hours, and you suspect the processor is stuck at maximum frequency even when you are just browsing the web. You open a terminal to check what is happening, but top only shows idle percentages. The kernel is managing the clock speed behind the scenes, and you need to see the actual scaling policy.
What the kernel is actually doing
Modern CPUs do not run at a single fixed speed. They adjust their clock frequency and voltage based on workload. This process is called dynamic frequency scaling. The kernel handles the heavy lifting through a hardware driver, but it needs a policy to decide when to step up or step down. That policy is the governor.
Think of the governor like a cruise control system in a car. The hardware driver is the engine and transmission. The governor tells the engine how aggressively to respond to changes in road grade. A performance governor floors the accelerator to maintain peak speed regardless of terrain. A powersave governor eases off the pedal to conserve fuel, accepting slower acceleration. The schedutil governor watches the scheduler queue length and adjusts frequency in real time to match actual demand.
Fedora ships with the scaling driver enabled by default. The kernel chooses schedutil on most modern hardware because it ties directly into the CPU scheduler. You do not need to compile custom kernels or patch firmware to change the policy. The cpupower utility reads the sysfs interface and translates your commands into kernel parameters. The sysfs path /sys/devices/system/cpu/cpu*/cpufreq/ exposes the actual hardware state. Every governor change you make writes a string to that directory.
Run journalctl -xe if the system behaves strangely after a kernel update. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style. Read the actual error before guessing.
Check your current scaling state
Before changing anything, you need to know what the system is currently doing. The cpupower command reads directly from the sysfs interface. It shows the active driver, the available frequency range, and the current governor assignment for each core. Fedora packages the utility inside linux-tools, which is version-locked to your running kernel. This prevents ABI mismatches between the tool and the kernel headers.
Here is how to check whether the kernel is using the expected scaling driver and what policy is active right now.
sudo dnf install linux-tools-$(uname -r)
# WHY: Installs the cpupower binary that matches your exact kernel version.
# WHY: Fedora splits linux-tools per kernel release to avoid header mismatches.
# WHY: The $(uname -r) substitution ensures you get the correct package variant.
Once the package is present, query the scaling subsystem.
cpupower frequency-info
# WHY: Reads /sys/devices/system/cpu/ to show the active driver,
# available frequency steps, and the current governor per core.
# WHY: The output confirms whether hardware limits or software
# policies are capping your clock speed.
Look for the governor line in the output. If it says schedutil, the kernel is already adjusting frequency based on scheduler load. If it says performance, the cores are locked to the maximum boost frequency. If you see userspace, something external is manually setting the frequency, which usually indicates a misconfigured monitoring tool or an old script.
dnf upgrade --refresh is the normal weekly maintenance command. dnf system-upgrade is for crossing major Fedora releases. They are different commands. Don't conflate them. Keep your tools updated so the scaling driver matches the kernel.
Reboot before you debug. Half the time the symptom is gone.
Change the governor on the fly
You can switch policies instantly without rebooting. The change applies to all online cores unless you specify a CPU mask. This is useful for testing how a workload behaves under different scaling constraints. The kernel applies the new policy immediately by writing to the sysfs governor file.
Here is how to lock all cores to maximum frequency for a benchmark or compile job.
sudo cpupower frequency-set -g performance
# WHY: Writes 'performance' to /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor.
# WHY: Bypasses dynamic scaling and forces the hardware to run at
# the highest supported clock speed until changed again.
If you want the system to balance responsiveness and power draw, switch back to the scheduler-driven policy.
sudo cpupower frequency-set -g schedutil
# WHY: Hands control back to the kernel scheduler.
# WHY: Frequency now scales proportionally to the number of
# runnable tasks in the runqueue, reducing idle power draw.
The powersave governor exists on older kernels and specific hardware. It does not mean the CPU will run slowly all the time. It means the kernel will prioritize efficiency over immediate responsiveness. Modern hardware usually handles powersave well, but schedutil is the preferred default on Fedora 38 and newer. The scheduler knows exactly how many tasks are waiting. It adjusts frequency in microseconds instead of polling a timer.
Trust the package manager. Manual file edits drift, snapshots stay.
Make the setting survive a reboot
Changes made with cpupower are temporary. The kernel resets the governor to the compiled-in default when the system boots. If you need a specific policy to apply automatically, you need a persistent mechanism. Editing kernel boot parameters works, but a systemd service is cleaner and easier to audit. Systemd units run in a predictable order and log their output to the journal.
Here is how to create a drop-in service that applies your chosen governor after the system reaches multi-user state.
[Unit]
Description=Apply custom CPU frequency governor at boot
After=multi-user.target
# WHY: Ensures the service runs after basic system services are up.
# WHY: Prevents race conditions where cpupower runs before the
# sysfs cpu directories are fully populated.
[Service]
Type=oneshot
ExecStart=/usr/bin/cpupower frequency-set -g performance
RemainAfterExit=yes
# WHY: Runs the command once and marks the service as active.
# WHY: RemainAfterExit keeps systemd tracking the unit so you
# can disable it later without losing the applied state.
[Install]
WantedBy=multi-user.target
# WHY: Hooks the service into the standard boot sequence.
# WHY: Allows standard systemctl enable/disable commands to work.
Save the file to /etc/systemd/system/cpufreq.service. Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. Run sudo systemctl daemon-reload after creating the file, then enable it.
sudo systemctl enable --now cpufreq.service
# WHY: Creates the symlink in multi-user.target.wants for boot persistence.
# WHY: The --now flag starts the service immediately so you can
# verify the governor changed without waiting for a reboot.
Test the service with sudo systemctl restart cpufreq.service before you reboot. Verify the governor changed, then trust the boot sequence.
Verify the change took effect
You need confirmation that the policy is actually applied and that the hardware is responding. The cpupower command shows the requested policy, but the actual frequency might be limited by thermal throttling or hardware constraints. The governor sets the target. The hardware driver enforces it within physical limits.
Here is how to monitor real-time frequency changes while a workload runs.
watch -n 1 "cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq"
# WHY: Polls the sysfs interface every second to show actual MHz.
# WHY: Reveals whether the governor is actively stepping up or
# staying flat due to thermal or power limits.
Run a stress test like yes > /dev/null & or a short compile job while watching the output. If the numbers jump to the maximum supported frequency, the governor is working. If they stay low, check your thermal limits with sensors or look for thermal throttling messages in journalctl -k. The k flag filters kernel ring buffer messages. It isolates hardware events from user-space noise.
Run cpupower frequency-info again after the test. The current CPU frequency line should reflect the active state. If the governor says performance but the frequency is low, your hardware is hitting a power or temperature wall. Adjust your cooling solution or lower the power limit in the BIOS before blaming the governor.
Run journalctl first. Read the actual error before guessing.
Common pitfalls and what the error looks like
The most common issue is trying to set a governor that the hardware driver does not support. The kernel exposes only the policies compiled into the cpufreq subsystem and supported by your specific CPU driver. Legacy governors like ondemand and conservative were removed from modern Intel and AMD drivers.
If you run sudo cpupower frequency-set -g conservative and see this error:
Error setting new values.
Invalid argument
The driver does not recognize conservative. Modern Intel and AMD drivers on Fedora drop legacy governors in favor of schedutil. Check the available governors line in cpupower frequency-info to see what your hardware actually supports.
SELinux rarely blocks cpupower because the binary is part of the base linux-tools package and runs with the correct context. If you do see an AVC denial, it usually means you are running a custom script that calls cpupower from an unconfined context. Check journalctl -t setroubleshoot for a one-line summary. Fix the script context instead of disabling SELinux. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux.
Another trap is editing /usr/lib/systemd/system/ files directly. Package updates will overwrite your changes. Always use /etc/systemd/system/ for custom units or drop-ins. Manual file edits drift, snapshots stay.
If the boot menu is gone, GRUB rescue is your friend, not your enemy.
Pick the right governor for your workload
Use schedutil when you want the kernel to balance responsiveness and power draw automatically. Use performance when you are running benchmarks, compiling large codebases, or processing media and need consistent maximum clock speeds. Use powersave when you are running headless servers, battery-powered laptops, or noise-sensitive environments where efficiency matters more than peak throughput. Stick with the default Fedora configuration if you only deviate from the standard setup occasionally.