После приобретения обновки в виде Asus P31SD и последующей установки на него Linux было очень обидно увидеть всего 6 часов автономной работы вместо желаемых 10-12. На Windows обратно вернуться не удалось (тут даже cywgin не помог), поэтому было решено запастись кофе и занять ближайшие выходные решением этих проблем.
Рассматриваем решение на примере Ubuntu 11.10.
P.S. В теории гайд подходит для всех ноутбуков с Sandybridge и Nvidia Optimus.
Важная, для нас, часть конфигурации ноутбука:
Процессор: Intel Core i3-2310M (Sandybridge)
Видеоадаптер: Nvidia Geforce 520M (Nvidia Optimus)
Итак, сразу после установки Linux мы видим следующие проблемы:
- Сумасшедшая яркость.
- Повышенное потребление энергии — наша основная цель.
- Не работает режим сна — для облегчения жизни заставим его работать
Яркость
Симптом: подсветкой пытаются одновременно управлять хардварный модуль и программный модуль из DE в результате чего случаются скачки в случайном направлении.
Проблемы с яркостью в ноутбуках очень распространены и разнообразны но практически все решаются одним методом: добавлением в параметры загрузки ядра
acpi_backlight=vendor
, который сигнализирует, что управлением яркостью занимается железо и програмно лезть туда не стоит.Открываем
/etc/default/grub
и вписываем параметр в GRUB_CMDLINE_LINUX
, получится:GRUB_CMDLINE_LINUX="acpi_backlight=vendor"
Сохраняем, обновляем конфигурацию grub (
sudo update-grub
), перезагружаемся и радуемся адекватному поведению подсветки.Режим сна
Симптом: при отправке ноутбука в сон устройство яростно сопротивляется и, в конечном итоге, зависает.
После недолгих поисков находим виновников: плохо-засыпающие USB-хабы. И рядом находим решение, хук для
pm-utils
:/etc/pm/sleep.d/20_custom-asus-u31sd:
#!/bin/sh
BUSES="0000:00:1a.0 0000:00:1d.0"
case "${1}" in
hibernate|suspend)
# Switch USB buses off
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
done
;;
resume|thaw)
# Switch USB buses back on
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
done
;;
esac
Сохраняем, делаем исполняемым (
sudo chmod +x /etc/pm/sleep.d/20_custom-asus-u31sd
), проверяем.Работает? Почти. После выходи из сна яркость дисплея падает до минимума… Поправить оплошность можно в этом же хуке. Достать значение яркости можно где-то из /sys. Большинство драйверов называют параметры банально поэтому просто поищем там backlight:
$ find /sys -name backlight
/sys/devices/platform/asus-nb-wmi/backlight
Нашлось! После изучения внутренностей значение яркости оказалось в
/sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness
. Допишем в предыдущий хук его сохранение и восстановление:
#!/bin/sh
BUSES="0000:00:1a.0 0000:00:1d.0"
case "${1}" in
hibernate|suspend)
# Switch USB buses off
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
done
# Saving brightness to /tmp/br
cat /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness > /tmp/br
;;
resume|thaw)
# Switch USB buses back on
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
done
# Restoring brightness from /tmp/br
cat /tmp/br > /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness
;;
esac
Снова проверяем и… работает! Теперь приступим к основному противнику, энергопотреблению.
Повышенное потребление энергии
Сбивать аппетиты Linux будем аж в 3 этапа.
1. Дискретная графика
Ноутбук оборудован двумя видеоадаптерами: интегрированной (Intel) и дискретной (Nvidia). Но не простой Nvidia, а работающей по технологии Nvidia Optimus. Той самой Optimus, поддержки которой в обозримом будущем в Linux не предвидится.
Но слава open-sourc'у мир полон энтузиастов. Борьбой (а иногда и дружбой) с Optimus занимается Bumblebee. Они достигли хорошего прогресса:
- Bumblebee умеет включать/отключать дискретную карту в зависимости от потребностей
- Bumblebee умеет заставлять приложения использовать дискретную карту
Естественно проект полон костылей, но это все же лучше чем ничего.
Займемся установкой:
$ sudo add-apt-repository ppa:bumblebee/stable
$ sudo apt-get update
$ sudo apt-get install bumblebee
К сожалению практически на каждом ноутбуке разная ACPI-команда включения/отключения видеокарты (большая таблица собрана здесь), поэтому управление питанием в Bumblebee по умолчанию выключено. Из таблицы выше берем команды и записываем их в
/etc/bumblebee/cardoff
и /etc/bumblebee/cardon
соответственно:/etc/bumblebee/cardoff:
\_SB.PCI0.PEG0.GFX0.DOFF
/etc/bumblebee/cardon:
\_SB.PCI0.PEG0.GFX0.DON
Затем в
/etc/bumblebee/bumblebee.conf
включаем управление питанием:ENABLE_POWER_MANAGEMENT=Y
и заставляем сервис завершаться (и соответственно выключать дискретную видеокарту) если его никто не использует:
STOP_SERVICE_ON_EXIT=Y
Сохраняем, перезагружаемся, смотрим на потребление энергии — ощутимо уменьшилось.
Прежде чем пойти дальше починим снова ждущий режим: дело в том, что при переходе в сон активный видеодрайвер (nvidia или nouveau) будет пытаться подготовить карту, но карта то у нас выключена. Решим просто и «в лоб»: в выше использованный хук добавим 2 команды:
- Будем включать карту перед засыпанием.
- Будем выключать карту после просыпания.
Хук примет следующий вид:
#!/bin/sh
BUSES="0000:00:1a.0 0000:00:1d.0"
case "${1}" in
hibernate|suspend)
# Switch USB buses off
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/unbind
done
cat /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness > /tmp/br
# Switch optimus back on before going to sleep, avoids the "constant on"
# bug that occurs after 2 suspend/resume cycles (thanks kos888)
echo `cat /etc/bumblebee/cardon` | tee /proc/acpi/call
;;
resume|thaw)
# Switch USB buses back on
for bus in $BUSES; do
echo -n $bus | tee /sys/bus/pci/drivers/ehci_hcd/bind
done
cat /tmp/br > /sys/devices/platform/asus-nb-wmi/backlight/asus-nb-wmi/brightness
# Switch optimus off before resuming, avoids unneccessary power draw
echo `cat /etc/bumblebee/cardoff` | tee /proc/acpi/call
;;
esac
2. Интегрированная видеокарта
Игравшись с разными версиями ядер я случайно заметил уменьшенное энергопотребление на версиях до 2.6.39 включительно. Бросившись в поиск по этим параметрам я в своей догадке не ошибся.
Проблема была обнаружена: виноват патч принятый в драйвер i915 в 3.0 ядре. Но, к счастью, его можно обойти без последствий.
В уже известный
/etc/default/grub
дописываем параметр i915.i915_enable_rc6=1
. Строка расширится до:
GRUB_CMDLINE_LINUX="acpi_backlight=vendor i915.i915_enable_rc6=1"
Обновляем конфигурацию grub, перезагружаемся и смотрим на показания батареи. Теперь можно жить. А можно уменьшить еще!
3. Дополнительные мелкие твики
Запустив powertop и применив все рекомендованные твики можно выжать еще 0,5-1 Wh, что на данном железе может дополнительно дать до часа автономной работы. Но не играться же каждый раз с powertop? Автоматизируем все это дело через pm-utils. У нас получиться 4 отдельных скрипта:
1. Один из главных твиков, по неизвестным причинам не включенный в стандартную поставку. Меняем режим управления частотой процессора:
/etc/pm/power.d/cpu-governor
#!/bin/bash
cpu_powersave() {
for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo $1 > $i && echo Done. || echo Failed.
done
}
case $1 in
true) cpu_powersave "ondemand" ;;
false) cpu_powersave "performance" ;;
*) exit $NA
esac
exit 0
2. Меняем режим управления питанием USB-устройств:
/etc/pm/power.d/usb-autosuspend
#!/usr/bin/env python
from os import listdir, path
from sys import argv
status = argv[1]
USB_PATH = '/sys/bus/usb/devices/'
def powersave(status):
devices = listdir(USB_PATH)
devices = filter(lambda x: ':' not in x, devices)
for device in devices:
b = listdir(path.join(USB_PATH, device))
b = filter(lambda x: ':' in x, b)
is_mouse = False
for i in b:
if open(path.join(USB_PATH, device, i, 'bInterfaceProtocol')).read().strip() == '02':
is_mouse = True
break
if not is_mouse:
open(path.join(USB_PATH, device, 'power/control'), 'w').write(status)
if status == 'true':
powersave('auto')
elif status == 'false':
powersave('on')
Скрипт умеет определять мыши и гасить их не будет.
3, 4. Меняем режим управления питанием у остальных устройств:
/etc/pm/power.d/scsi_host-link_power_management
#!/bin/bash
powersave() {
for i in /sys/class/scsi_host/host?/link_power_management_policy; do
echo $1 > $i && echo Done. || echo Failed.
done
}
case $1 in
true) powersave "min_power" ;;
false) powersave "max_performance" ;;
*) exit $NA
esac
exit 0
/etc/pm/power.d/pci-power-control
#!/bin/bash
powersave() {
for i in /sys/bus/pci/devices/*/power/control; do
echo $1 > $i && echo Done. || echo Failed.
done
}
case $1 in
true) powersave "auto" ;;
false) powersave "on" ;;
*) exit $NA
esac
exit 0
Делаем данные файлы исполняемыми и применяем одним махом:
sudo pm-powersave true
.Настройка окончена. Официальный пруф:
И результаты диаграммой: