понедельник, 9 января 2012 г.

Настройка энергопотребления ThinkPad x220 в Ubuntu 12.04

Куратор темы на ixbt о ноутбуке ThinkPad x220 попросил написать меня статью об оптимизации потребления на ThinkPad x220, что я и сделал.
На мой взгляд статья получилась хорошей, но ixbt устроен так, что я не могу делать там обновления.
Поэтому я публикую ее в моем блоге. Здесь будут вноситься изменения, если таковые появятся.
А когда будет время поправлю структуру и ссылки в основной статье об экономии электричества в линуксе.

На все про все, если вы делаете это в первый раз, запаситесь примерно 2-мя часами.

Потребление замеряется в idle и с уровнем подсветки дисплея 20%. Когда систему "успокоилась" и переходные процессы завершены.

Каждый раздел оптимизации не зависит от другого и может быть применен отдельно.

  1. Установка и настройка pm-utils
    1. Установить необходимые программы: apmd, pm-utils и т.п. $ sudo apt-get install apmd pm-utils hdparm libnotify-bin
    2. Создадим скрип управления энергопотреблением: $ sudo gedit /usr/lib/pm-utils/power.d/99-savings.sh В появившемся окне редактора копипастим следующий текст
      ######################################################################################
      # A script to aggressively toggle power management between high 
      # performance and very low power consumption.
      # For more information on each of these options, see http://www.lesswatts.org
      # Last version script see http://axa-ru.blogspot.com/2012/01/thinkpad-x220-powersaving.html
      ################# Changes history ###################################################
      #VERSION=0.12   # 31.08.2010 Testing Ubuntu 10.04. Small changes for Wi-Fi control
      #VERSION=0.13   # 21.09.2010 Adding services control: 
                      #   evolution-alarm-notify, 
                      #   postfix, 
                      #   rsyslog
      #VERSION=0.2    # 23.07.2011 Modified for Ubintu 11.04 for Thinkpad x220 4290rw1
      #VERSION=0.23   # 27.07.2011 Added store value (Brightness, user, etc ) to /tmp/powersave.ini
                      #   Fix notify-send message
                      #   Added CPU core disabling. Disable cores not affected for power saving
      #VERSION=0.23.1 # 07.01.2012 Fix ethtool parameters in aLan procedure
                      #     
      #VERSION=0.23.2 # 07.01.2012 Fix aBrightness procedure
      VERSION=0.24    # 08.01.2012 Added start/stop conky monitor
      
      #
      # To install:
      #
      # sudo apt-get install apmd pm-utils expect hdparm libnotify-bin
      #
      # Save this file to /usr/lib/pm-utils/power.d/99-savings.sh
      # cd /usr/lib/pm-utils/power.d
      # sudo install 99-savings.sh /etc/pm/sleep.d
      # sudo install 99-savings.sh /etc/pm/power.d
      #
      
      INI_DIR=/tmp
      INI_FILE=powersave.ini
      INI=${INI_DIR}/${INI_FILE}
      
      aUsb()
      {
        #################################################
        ## USB Subsystem
        ##
        # 0.7-0.8 W
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "on" > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "auto" > $i
            done
      
            for i in /sys/bus/usb/devices/*/power/autosuspend
            do
              echo 1 > $i
            done
      
            echo 1 > /sys/module/usbcore/parameters/autosuspend
            ;;
        esac
      }
      
      aSata()
      {
        case "$1" in
          false)  #ac_power
            # Set the SATA to max performance
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo max_performance > $i
            done
            ;;
      
          true)  #batt_power
            # Set SATA to minimum power
            # 0.7 W
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo min_power > $i
            done
            ;;
        esac
      }
      
      aPci()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aI2c()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aHdd()
      {
        case "$1" in
          false)  #ac_power
            # Set the drive to mostly stay awake.  Some may want to change -B 200
            # to -B 255 to avoid accumulating Load_Cycle_Counts
            # -S 240 => put in standby after 20 minutes idle
            # -B 200 => do not permit spindown
            # -M => not supported by my drive
            hdparm -B 200 -S 240 -M 254 /dev/sda
      
            # Remount ext3/4 filesystems so the journal commit only happens every 60
            # seconds.  By default this is 5 but, I prefer to reduce the disk
            # activity a bit.
            mount -o remount,commit=60,atime /
            ;;
      
          true)  #batt_power
            hdparm -B 1 -S 4 -M 128 /dev/sda
            mount -o remount,noatime,commit=600 /
      
            ;;
        esac
      }
      
      aSsd()
      {
      
      # add these commands in the /etc/rc.local
      #  echo deadline > /sys/block/sda/queue/scheduler
      #  echo 1 > /sys/block/sda/queue/iosched/fifo_batch
      #  sysctl -w vm.swappiness=1            # Strongly discourage swapping
      #  sysctl -w vm.vfs_cache_pressure=50   # Don't shrink the inode cache aggressively
        case "$1" in
          false)  #ac_power
            ;;
      
          true)  #batt_power
            ;;
        esac
      }
      
      aI915()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/i915/parameters/powersave
            ;;
      
          true)  #batt_power
            echo 1 > /sys/module/i915/parameters/powersave
            ;;
        esac
      }
      
      aWlan()
      {
            # WiFi power savings.
        case "$1" in
          false)  #ac_power
            /sbin/iwconfig wlan0 power off txpower 14
            ;;
      
          true)  #batt_power
            /sbin/iwconfig wlan0 power on txpower 4
            ;;
        esac
      }
      
      aLan()
      {
        case "$1" in
          false)  #ac_power
            # set the ethernet max speed.
            ethtool -s eth0 speed 1000 duplex full autoneg on wol d
            ;;
          true)  #batt_power
            # set the ethernet power savings.
            # ~ 0.4 W
            ethtool -s eth0 speed 10 duplex half autoneg off wol d
            ;;
        esac
      }
      
      aCpu()
      {
        #################################################
        ## CPU
        ##
      
        case "$1" in
          false)  #ac_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo performance > $i
            done
      
            # Enable All Core CPU
            for i in /sys/devices/system/cpu/cpu*/online
            do
              echo 1 > $i
            done
      
            # Set max freq 2.7 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 2701000 > $i
      #      done
      
            # Shedule Multitreading
            echo 0 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
      
          true)  #batt_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo powersave > $i
            done
      
            # Set max freq 1 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 1000000 > $i
      #      done
      
      #      Disable cores not affected for power saving
      #      for i in /sys/devices/system/cpu/cpu*/online
      #      do
      #        echo 0 > $i
      #      done
      
            echo 1 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
        esac
      }
      
      aSnd()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
      
          true)  #batt_power
            # Turn off sound card power savings
            # < 0.1 W
            echo 10 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
        esac
      }
      
      aBt()
      {
        case "$1" in
          false)  #ac_power
            # Enable the bluetooth driver
            rfkill unblock bluetooth
            ;;
      
          true)  #batt_power
            # Remove the bluetooth driver
            # 0.3-0.4 W
            rfkill block bluetooth
            ;;
        esac
      }
      
      aDaemons()
      {
        #################################################
        ## demons, services
        ##
      
        case "$1" in
          false)  #ac_power
            # 1. Evolution alarm and integrations
            /usr/lib/evolution/2.32/evolution-alarm-notify &
            #/usr/lib/evolution/e-calendar-factory &
            #/usr/lib/evolution/e-addressbook-factory &
      
            # 2. Starting Sendmail server 
            #postfix start 
      
            # 3. Starting CouchDB & desktopcouch
            dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort
      
            # 4. Starting conky
            if [ ${CONKY_RUN} -eq 1 ]; then
              su $vUSER -c "/usr/bin/conky --display=:0 &"
            fi
            ;;
      
          true)  #batt_power
            # 1. Evolution alarm
            killall evolution-alarm-notify
            #killall e-calendar-factory
            #killall e-addressbook-factory
      
            # 2. Stopping Sendmail server 
            #postfix stop
      
            # 3. Stoping CouchDB & desktopcouch
            killall beam.smp
            killall desktopcouch-service
      
            # Stoping conky ~1W
            killall conky
            ;;
        esac
      }
      
      # < 0.1 W
      aWebcam()
      {
        case "$1" in
          false)  #ac_power
            # Enable the webcam driver
            modprobe uvcvideo
            ;;
      
          true)  #batt_power
            # Remove the webcam driver
            modprobe -r uvcvideo
            ;;
        esac
      }
      
      aMemory()
      {
        case "$1" in
          false)  #ac_power
            # Set kernel dirty page value back to default
            echo 10 > /proc/sys/vm/dirty_ratio
            echo 5 > /proc/sys/vm/dirty_background_ratio
      
            # Only wakeup every 60 seconds to see if we need to write dirty pages
            # By default this is every 5 seconds but, I prefer 60 to reduce disk
            # activity.
            echo 6000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
      
          true)  #batt_power
            # Reduce disk activity by waiting up to 10 minutes before doing writes
            echo 90 > /proc/sys/vm/dirty_ratio
            echo 1 > /proc/sys/vm/dirty_background_ratio
            echo 60000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
        esac
      }
      
      aBrightness()
      {
        case "$1" in
          false)  #ac_power
            # Setup maximum brigthness
            # Thinkpad x220, Ubuntu 11.04
            vBAT_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vAC_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
      
          true)  #batt_power
            # Setup brigthness 30%
            vAC_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vBAT_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
        esac
      }
      
      aMisk()
      {
        case "$1" in
          false)  #ac_power
            # Turn off the laptop mode disk optimization
            echo 0 > /proc/sys/vm/laptop_mode
            echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource
      
            # enable logging
            service rsyslog start
      
            # ZiXEL nbg460n. Set maximum wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 1; fi
      
            # enable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind start; fi
      
            # Powersave pci express
            echo performance > /sys/module/pcie_aspm/parameters/policy
            ;;
      
          true)  #batt_power
            # Set laptop disk write mode
            echo 5 > /proc/sys/vm/laptop_mode
            echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource
            # disable logging
            service rsyslog stop
      
            # ZiXEL nbg460n. Set standard wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 0; fi
      
            # disable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind stop ; fi
      
            echo powersave > /sys/module/pcie_aspm/parameters/policy
            ;;
        esac
      }
      
      aNotify()
      {
        case "$1" in
          false) #ac_power
            MSGH="AC" 
            MSGT="Maximum Performance Mode"
            MSGI="ac-adapter"
            ;;
          true)  #battery_power 
            MSGH="BATT" 
            MSGT="Battery Power Saving"
            MSGI="battery"
          ;;
        esac
      
        vUSER=`ps -C gnome-session -o user=` #find UID user who start gnome-session
        vPIDS=`pgrep -u $vUSER gnome-session` #find PID
        for PID in $vPIDS; do
          vDBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ \
          | sed -e 's/DBUS_SESSION_BUS_ADDRESS=//')
          DBUS_SESSION_BUS_ADDRESS=$vDBUS_SESSION_BUS_ADDRESS DISPLAY=:0.0 sudo -u $vUSER notify-send "$MSGH" "$MSGT" -i "$MSGI"
        done
      }
      
      aLoadini()
      {
        if [ -e $INI ]; 
          then 
            echo "Restore Value"
            while read LINE
            do
              PARM=$(echo "$LINE" | awk '{print $1}')
              KEY=$(echo "$LINE" | awk '{print $2}')
              case $PARM in
                "AC_BRI")
                  vAC_BRI=$KEY
                  ;;
                "BAT_BRI")
                  vBAT_BRI=$KEY
                  ;;
                "USER")
                  vUSER=$KEY
                  ;;
                "PIDS")
                  vPIDS=$KEY
                  ;;
                "CONKY")
                  CONKY_RUN=$KEY
                  ;;
                "DBUS_SESSION_BUS_ADDRESS")
                  vDBUS_SESSION_BUS_ADDRESS=$KEY
                  ;;
              esac
              echo "$PARM $KEY"
            done < $INI
          else
            echo "Reset Value"
            # Conky is Running Check
            CONKY_RUN=$(ps -ef | grep -c /usr/bin/conky)
            ((CONKY_RUN-=1))
      
            vAC_BRI=15
            vBAT_BRI=8
            vUSER=""
            vPIDS=""
            vDBUS_SESSION_BUS_ADDRESS=""
        fi
      }
      
      aSaveini()
      {
        echo "AC_BRI $vAC_BRI" > $INI
        echo "BAT_BRI $vBAT_BRI" >> $INI
        echo "USER $vUSER" >> $INI
        echo "PIDS $vPIDS" >> $INI
        echo "CONKY $CONKY_RUN" >> $INI
        echo "DBUS_SESSION_BUS_ADDRESS $vDBUS_SESSION_BUS_ADDRESS" >> $INI
      }
      
      
      ##########################################################
      ## Apply settings
      ##
      aLoadini
      
      aCpu $1
      aUsb $1
      aI2c $1
      aSata $1
      aPci $1
      if [ $(hdparm -i /dev/sda | grep Model | awk '{print substr($2,1,3)}') = "SSD" ]; 
        then 
          aSsd $1
        else
          aHdd $1
      fi
      aI915 $1
      aWlan $1
      aLan $1
      aSnd $1
      aBt $1
      aWebcam $1
      aMemory $1
      aDaemons $1
      aBrightness $1
      aMisk $1
      aNotify $1
      
      aSaveini
      

      Сохраняем скрипт и закрываем редактор
    3. Подключаем скрипт к событиям power и sleep $ cd /usr/lib/pm-utils/power.d $ sudo chmod 755 99-savings.sh $ sudo install 99-savings.sh /etc/pm/sleep.d $ sudo install 99-savings.sh /etc/pm/power.d
    4. Проверяем
      Вытаскиваем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим сохранения энергии Вставяем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим максимального быстродействия

  2. Устанавливаем ядро 3.63.3.7
  3. У меня иногда с ядром 3.6 процессор переходит в Turbo mode и начинает сильно нагреваться. Powertop показывает частоту 3 GHz. htop не показывает никакого криминала. А процессоры находятся в состоянии powersave. Разбираюсь. Возможно это баг.
    Если у вас будет то же самое отпишите, плз.

    Можно не мудрствуя лукаво поставить из http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/ if [ ! -d "$HOME/kernel" ]; then mkdir $HOME/kernel; fi cd "$HOME/kernel" rm *.deb wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307_3.3.7-030307.201205211535_all.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-image-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb sudo dpkg -i *.deb

  4. Устанавливаем параметры загрузки Ubuntu в Grub
  5. В терминале с помощью редактора gedit $ sudo gedit /etc/default/grub Заменяем строку
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    
    на
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i915.i915_enable_rc6=1 i915.lvds_downclock=1 i915_enable_fbc=1 drm.vblankoffdelay=1 pcie_aspm=force reboot=pci"
    
    Обновляем grub $ sudo update-grub Перезагружаемся и проверяем энергопотребление.

  6. Success Story

  7. Евгений Попов прислал скриншот, на котором видно, что он смог снизить минимальное потребление до 4,77 Вт (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).

    Участник с ником unr форума Ubuntu получил потребление около 5,5 Вт на ядре 3.2.5 (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).


  8. Indicator

  9. Я самоуверенно дал программе название, которое уже присвоено другой утилите. К выходным переобзову и сделаю новый deb пакет.

    Не прошло и года, как я сделал простой индикатор, позволяющий выбирать (пока) один из двух режимов PowerSaving.

    Остальные пункты меню представляют собой заглушки. Надеюсь скоро их активизирую.
    Скачать индикатор можно по ссылке: powerman_0.1_amd64.deb
    Устанавливается, как обычный deb пакет. sudo dpkg --install powerman_0.1_amd64.deb После чего можно добавить запуск индикатора в Startup Applications:
    /usr/bin/powerman -t 10
    
    где -t 10 задает время задержки старта.

    И последним штрихом добавляем в sudoers команды, разрешающие запуск скрипта управления питанием без ввода пароля. sudo visudo
    # User alias specification
    # Change %axa to your Users Grup. Замените %axa на название группы, куда входит пользователь
    User_Alias USERS = %axa
    
    # Cmnd alias specification
    Cmnd_Alias PWR_SAVE =  /etc/pm/power.d/99-savings.sh
    
    # All User can run Power Saving script
    USERS ALL=NOPASSWD: PWR_SAVE
    

  10. Планы на развитие
  11. В планах убрать установку всех скриптов и модификацию управляющих файлов внутрь deb пакета.

Полезные ссылки:



03.10.2012 - добавил раздел установки индикатора
06.10.2012 - временно убрал раздел компиляции ядра и добавил раздел установки ядра 3.6 из ubuntu.kernel