Home

If you find any mistakes here or anywhere else on my website, email website@CoryHufford.com.

Manually Setting GPU Performance Level in Linux to Fix Crashes

August 13, 2026

Several years ago I bought an AMD RX 7900 XTX GPU. Since then, across many Linux kernel and driver versions and two distributions (Pop OS and, currently, EndeavourOS), I've had occasional GPU driver crashes during GPU-intensive tasks. The crashes cause these symptoms, in order:

  1. All diplays freeze for several seconds
  2. All displays go black for several seconds
  3. All display return, but with much stuttering and artifacting

I've done some sporadic troubleshooting of the issue over the years, and the only thing that seems to eliminate the crashes completely is manually setting the performance level of the GPU. You can get or set the GPU performance level by reading or writing a power_dpm_force_performance_level file in /sys/class/drm/. This directory contains a card[0-9] subdirectory for each AMD GPU; since I also have an AMD CPU with an integrated GPU, I have card0/ and card1 subdirectories. Each of these contains a device/ subdirectory with files for getting and setting various GPU parameters. The file structure, only including things relevant to setting the performance level, looks like:

/sys/class/drm/
 |- card0/
 |   |- device/
 |       |- device
 |       |- power_dpm_force_performance_level
 |       |- vendor
 |
 |- card1/
     |- device/
         |- device
         |- power_dpm_force_performance_level
         |- vendor

Note that the numbers assigned to devices in /sys/class/drm/ are not stable and can change on reboot. For identifying which GPU is card0 and which is card1, the vendor and device files can be used. These files contain hexadecimal PCI IDs, and the PCI ID Repository has tables of known IDs. AMD's vendor ID is 1002 and AMD device ID 744c is for consumer Navi 31 GPUs (7900 XT/XTX/GRE and 7900M).

The power_dpm_force_performance_level file can be read to get the current performance level and written to to set the performance level. Valid values, according to the Arch wiki at the time of writing, are:

auto
Dynamically select the optimal power profile for current conditions in the driver.
low
Clocks are forced to the lowest power state.
high
Clocks are forced to the highest power state.
manual
User can manually adjust which power states are enabled for each clock domain.
profile_standard
profile_min_sclk
profile_min_mclk
profile_peak
Clock and power gating are disabled and the clocks are set for different profiling cases. This mode is recommended for profiling specific workloads.

On my machine, auto is the default mode and the problematic one. Setting the performance level to low or high prevents the crashes described above.

Below is the Bash script I use to identify the correct GPU and toggle its performance level. Use it at your own risk.


#!/usr/bin/env bash

set -euo pipefail

VENDOR_ID="0x1002"  # AMD
DEVICE_ID="0x744c"  # Consumer Navi 31 (RX 7900 XT/XTX/GRE, RX 7900M)

target=""
for card in /sys/class/drm/card[0-9]*; do
	dev="${card}/device"
	[[ -r "${dev}/vendor" && -r "${dev}/device" ]] || continue
	if [[ \
		"$(cat "${dev}/vendor")" == "${VENDOR_ID}" && \
		"$(cat "${dev}/device")" == "${DEVICE_ID}" \
	]]; then
		target="${dev}/power_dpm_force_performance_level"
		echo "Found GPU at ${card}"
		break
	fi
done

if [[ -z "${target}" || ! -e "${target}" ]]; then
	echo "GPU not found, or the performance level file is missing" >&2
	exit 1
fi

current="$(cat "${target}")"
case "${current}" in
	high) next="low" ;;
	*)    next="high" ;;
esac

echo "Current: ${current}"
echo "Next   : ${next}"

read -rp "Change? [y/N] " reply
if [[ "${reply}" =~ ^[Yy]([Ee][Ss])?$ ]]; then
	echo "${next}" | sudo tee "${target}" > /dev/null
	echo "Now: $(cat "${target}")"
fi

I don't do much Bash scripting, so to help me read this script in the future, a summary of some of the commands and Bash features used follows.

The options for the set builtin used are:

-e
Exit immediately if a command fails
-o <option-name>
Sets an option; pipefail makes a pipeline fail if any command in it fails (normally only the status of the last command is considered)
-u
Treat unset variables as an error when performing expansion

The Bash conditional expressions used are:

-e <file>
True if <file> exists
-r <file>
True if <file> exists and is readable
-z <string>
True if the length of <string> is zero

The -r argument for read prevents backslashes from escaping any characters. -p is just to provide a prompt.

Back to top