https://bugs.freedesktop.org/show_bug.cgi?id=102646
--- Comment #71 from bmilreu@gmail.com --- (In reply to George Scorer from comment #70)
Building on julien tempel's workaround, here's a somewhat more complex script to manage the memory p-state jumps. It switches between low and high memory p-states very reluctantly, so minimizing instances of flickering. I'm not a bash expert so please excuse the clumsy coding, but this works for me.
#!/bin/bash
# Each memory p-state switch causes a screen flicker. Tweak these variables to match # your personal 'flicker aversion' vs efficiency trade-off. CORE_P_STATE_UP=6 # The gpu core p-state at which we should jump up to memory p-state 2 CORE_P_STATE_DOWN=1 # The gpu core p-state at which we should drop down to low memory p-state UP_DELAY=2 # in seconds. How long to stay in low memory p-state before checking whether we can jump up to 2. DOWN_DELAY=10 # in seconds. How long to stay in memory p-state 2 before checking whether we can drop down to low. SLEEP_INTERVAL=1 # in seconds. How frequently we should poll the core p-state. LOW_MEM_STATE=0 # Choose between 0 & 1
# Sysfs paths here are hardcoded for one amdgpu card at card0; adjust as needed. FILE_PERF_LEVEL=/sys/class/drm/card0/device/power_dpm_force_performance_level FILE_MEM_P_STATE=/sys/class/drm/card0/device/pp_dpm_mclk FILE_CORE_P_STATE=/sys/class/drm/card0/device/pp_dpm_sclk
# check for root privileges if [ $UID -ne 0 ] then echo "Writing to sysfs requires root privileges; relaunch as root" exit 1 fi
# Set gpu performance level control to manual # echo "Setting performance level control to manual" echo "manual" > "$FILE_PERF_LEVEL"
# Read the current core p-state and set a corresponding initial memory p-state
CORE_P_STATE="$(grep -F '*' $FILE_CORE_P_STATE)" CORE_P_STATE=${CORE_P_STATE:0:1}
if [ "$CORE_P_STATE" -ge "$CORE_P_STATE_UP" ]; then MEM_P_STATE=2 else MEM_P_STATE=$LOW_MEM_STATE fi
echo "$MEM_P_STATE" > "$FILE_MEM_P_STATE" PROPOSED_MEM_P_STATE=$MEM_P_STATE
function check_core_p_state {
CORE_P_STATE="$(grep -F '*' $FILE_CORE_P_STATE)" CORE_P_STATE=${CORE_P_STATE:0:1}
# Propose what the corresponding memory p-state should be OLD_PROPOSED_MEM_P_STATE=$PROPOSED_MEM_P_STATE PROPOSED_MEM_P_STATE=$MEM_P_STATE if [ "$CORE_P_STATE" -ge "$CORE_P_STATE_UP" ]; then PROPOSED_MEM_P_STATE=2 elif [ "$CORE_P_STATE" -le "$CORE_P_STATE_DOWN" ]; then PROPOSED_MEM_P_STATE=$LOW_MEM_STATE fi
if [ "$PROPOSED_MEM_P_STATE" -ne "$MEM_P_STATE" ]; then # We want to change so determine where we are in the countdown. if [ "$PROPOSED_MEM_P_STATE" -ne "$OLD_PROPOSED_MEM_P_STATE" ]; then if [ "$PROPOSED_MEM_P_STATE" -eq 2 ]; then CHANGE_COUNTDOWN=$UP_DELAY else CHANGE_COUNTDOWN=$DOWN_DELAY fi fi (( CHANGE_COUNTDOWN = $CHANGE_COUNTDOWN - $SLEEP_INTERVAL ))
if [ $CHANGE_COUNTDOWN -le 0 ]; then
# The countdown has reached 0 so change the memory p-state. MEM_P_STATE=$PROPOSED_MEM_P_STATE echo "$MEM_P_STATE" > "$FILE_MEM_P_STATE" fi # else # we don't want to change. fi
# echo "Old Prop Mem Core Countdown" # echo " $OLD_PROPOSED_MEM_P_STATE $PROPOSED_MEM_P_STATE $MEM_P_STATE $CORE_P_STATE $CHANGE_COUNTDOWN" # echo "" }
function reset_on_fail { echo "Exiting, setting memory p-state to 2" echo "manual" > "$FILE_PERF_LEVEL" echo "2" > "$FILE_MEM_P_STATE" exit 1 }
# always try to fix memory p-state 2 on failure trap "reset_on_fail" SIGINT SIGTERM
function run_daemon { while :; do sleep $SLEEP_INTERVAL check_core_p_state done }
# start the loop
run_daemon
Thanks for the script, it doesn't work 100% of the time but the flickers are very rare. Good thing about it is that you still save power when idle since it reclocks back. I'd guess similar logic could be used to fix the driver while still having the feature working, just reclocking less agressively.