Linux - lepsze sterowanie zarządzaniem energii ACPI i fglrx.

21 listopada, 2008

Jakiś czas temu pisałem o fglrx i oszczędzaniu energii. Stwierdziłem, że znaczne ulepszenie istniejącego skryptu jest proste. Poniżej efekty w postaci dobrego zarządzania.

Jak pisałem, poprzednio były tylko dwa tryby: low power (przy pracy na zamkniętej pokrywie i na baterii), oraz default. Na dodatek wartości dobierane były na sztywno na podstwie tego, co aticonfig --lsp zwraca jako default i low.

Obecnie definiowane są 3 wartości:

  1. Praca przy zamkniętej pokrywie
  2. Praca na baterii i otwartej pokrywie
  3. Praca na zasilaczu i otwartej pokrywie

Wartości definiuje się wprost w pliku /etc/default/fglrx:

FGLRX_ACPI_SWITCH_POWERSTATES=true
FGLRX_ACPI_LIDCLOSE_MODE=1
FGLRX_ACPI_BATTERY_MODE=2
FGLRX_ACPI_AC_MODE=3

Cyfry to oczywiście numery trybu zwracane przez aticonfig --lsp. W powyższym ustawieniu: jeśli zamykamy pokrywę (czyt. nie korzystamy z grafiki), to maksymalnie ją spowalniamy (jedyny powód, by tego nie robić to ogrzewanie mieszkania grafiką - pomijam), jeśli pracujemy na baterii, to pracujemy na średniej wydajności, a jeśli mamy prąd, to bierzemy ile fabryka dała. Oczywiście nie ma przeciwskazań, by ustawić np. wszędzie 1 (ja tak mam).

Największe modyfikacje to plik /etc/acpi/fglrx-powermode.sh. Obecnie wygląda on tak:

#!/bin/bash

. /etc/default/fglrx
if [ x$FGLRX_ACPI_SWITCH_POWERSTATES != xtrue ]; then
  exit;
fi

getXuser() {
        user=`finger| grep -m1 ":$displaynum " | awk '{print $1}'`
        if [ x"$user" = x"" ]; then
                user=`finger| grep -m1 ":$displaynum" | awk '{print $1}'`
        fi
        if [ x"$user" != x"" ]; then
                userhome=`getent passwd $user | cut -d: -f6`
                export XAUTHORITY=$userhome/.Xauthority
        else
                export XAUTHORITY=""
        fi
}

grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ]; then
 lid_closed=1
else
 lid_closed=0
fi

grep -q off-line /proc/acpi/ac_adapter/*/state
if [ $? = 0 ]; then
   on_dc=1
else
   on_dc=0
fi

if [ ${lid_closed} -eq 1 ]; then
    echo "fglrx: setting low power"
    for x in /tmp/.X11-unix/*; do
        displaynum=`echo $x | sed s#/tmp/.X11-unix/X##`
        getXuser;
        if [ x"$XAUTHORITY" != x"" ]; then
            export DISPLAY=":$displaynum"
            powermode=$FGLRX_ACPI_LIDCLOSE_MODE
            if [ x"$powermode" != x"" ]; then
                su $user -c "/usr/bin/aticonfig --set-powerstate=$powermode --effective=now" &>/dev/null
            fi
        fi
    done
else

  if [ ${on_dc} -eq 0 ]; then
    echo "fglrx: setting AC powermode"
    for x in /tmp/.X11-unix/*; do
       displaynum=`echo $x | sed s#/tmp/.X11-unix/X##`
       getXuser;
       if [ x"$XAUTHORITY" != x"" ]; then
           export DISPLAY=":$displaynum"
            powermode=$FGLRX_ACPI_AC_MODE
           if [ x"$powermode" != x"" ]; then
               su $user -c "/usr/bin/aticonfig --set-powerstate=$powermode --effective=now" &>/dev/null
           fi
       fi
    done
  else
    echo "fglrx: setting battery powermode"
    for x in /tmp/.X11-unix/*; do
       displaynum=`echo $x | sed s#/tmp/.X11-unix/X##`
       getXuser;
       if [ x"$XAUTHORITY" != x"" ]; then
           export DISPLAY=":$displaynum"
            powermode=$FGLRX_ACPI_BATTERY_MODE
           if [ x"$powermode" != x"" ]; then
               su $user -c "/usr/bin/aticonfig --set-powerstate=$powermode --effective=now" &>/dev/null
           fi
       fi
    done
  fi
fi

Skrypt nie był testowany na okoliczność błędów typu niezdefiniowana czy błędna wartość dla któregoś trybu, poza tym wygląda, że działa OK. Zachęcam do poprawek/uwag.