Сон и пробуждение

Питание и ACPI #acpi #linux #notebook #power #suspend

Сон и пробуждение

Ноутбук закрыли — он уснул. Открыли — вернулся рабочий стол. Обычно это работает незаметно, но иногда система не просыпается: экран застыл, клавиатура и мышь не отвечают. Эта статья — про то, какие бывают состояния сна, чем отличается s2idle от deep и как понять, что случилось, если ноутбук завис при пробуждении.

Состояния системы

ACPI описывает состояния питания всей системы, обозначая их буквой S. В документации ядра Linux они сопоставлены так:

Состояние Что происходит В Linux
S0 система работает обычный режим
S1 лёгкий сон, контекст сохраняется standby (shallow)
S2 в ACPI есть, на практике почти не используется —
S3 сон в оперативную память (Suspend-to-RAM) mem с вариантом deep
S4 гибернация: образ памяти на диск disk
S5 выключено, питание остаётся на кнопку выключение

В Linux интерфейс один — каталог /sys/power/:

cat /sys/power/state      # freeze mem disk
cat /sys/power/mem_sleep  # s2idle [deep]

state — какие состояния поддерживает ядро. mem_sleep — какой вариант используется для mem; текущий выделен квадратными скобками.

s2idle и deep

Это два разных способа «уснуть» под одним именем mem.

Suspend-to-Idle (s2idle) — чисто программный сон. Ядро замораживает пользовательские процессы, останавливает учёт времени, переводит устройства в состояния низкого потребления, а процессоры проводят время в самых глубоких idle-состояниях. Система формально остаётся в рабочем состоянии S0, поэтому проснуться может от любого прерывания. Этот вариант работает почти на любом железе.

Suspend-to-RAM (deep, S3) — настоящий сон: содержимое памяти сохраняется за счёт self-refresh, почти всё остальное питание отключается, а последний шаг делает прошивка. Энергии тратится существенно меньше, но и просыпается система дольше.

Что важно на практике:

  • по умолчанию ядро выбирает deep на большинстве систем, где S3 поддерживается, но на части ACPI-платформ — s2idle, даже если S3 есть;
  • выбор можно переопределить параметром ядра mem_sleep_default=deep (или s2idle);
  • включить/выключить прямо сейчас, без перезагрузки:
cat /sys/power/mem_sleep          # s2idle [deep]
echo s2idle | sudo tee /sys/power/mem_sleep

На современных платформах Intel у s2idle есть «железная» основа — состояния низкого энергопотребления S0ix: процессорный пакет уходит в PKG C10, а хаб (PCH) — в SLP_S0. Ядро умеет показывать, сколько времени система провела в этих состояниях:

cat /sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us
cat /sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us

Если S0ix на конкретной машине работает плохо, s2idle может как расходовать батарею, так и зависать при пробуждении. Тогда разумная альтернатива — deep.

Кто инициирует сон

В обычной системе решение принимает systemd-logind. Его настройки — в /etc/systemd/logind.conf и logind.conf.d/:

  • HandleLidSwitch= — что делать при закрытии крышки; по умолчанию suspend;
  • HandleLidSwitchExternalPower= — то же на внешнем питании; по умолчанию значение не задано и игнорируется (используется HandleLidSwitch);
  • HandleLidSwitchDocked= — когда ноутбук в док-станции или подключено несколько мониторов; по умолчанию ignore;
  • HandlePowerKey=, HandleSuspendKey=, HandleHibernateKey= — кнопки.

Само усыпление выполняет systemd-suspend.service: он пишет строку mem в /sys/power/state. Что именно писать — настраивается в /etc/systemd/sleep.conf (SuspendState=, а с systemd 256 — ещё и MemorySleepMode=).

Непосредственно перед сном и сразу после пробуждения systemd выполняет все программы из /usr/lib/systemd/system-sleep/, передавая им два аргумента: pre или post и тип операции (suspend, hibernate, …). Важная деталь: во время их работы user.slice заморожен, поэтому хуки не могут общаться с пользовательскими процессами. Сама документация systemd называет такие хуки «хаками» и советует приложениям использовать inhibitor-локи.

Inhibitors: кто запрещает спать

Программа может попросить не уходить в сон или не выключаться. Список держателей:

systemd-inhibit --list

Инхибиторы бывают двух видов: delay (подождать немного) и block (запретить). Типичный пример block — несохранённый документ в текстовом редакторе: GNOME не даёт выключить компьютер, пока вы не сохраните работу.

Как проверить, что сон действительно был

Самый надёжный след — сообщения ядра:

journalctl -b 0 -k | grep -E 'PM: suspend (entry|exit)'

Здоровая картина на машине с S3 выглядит так (наш замер, 8 ноября 2026):

16:43:31 PM: suspend entry (deep)
         ACPI: PM: Preparing to enter system sleep state S3
         ...
16:48:51 PM: suspend exit
         ACPI: PM: Low-level resume complete

После suspend exit в журнале должны появиться NetworkManager, fprintd (если включён вход по отпечатку), оболочка — всё это за секунды. Если журнал обрывается сразу после выхода из сна, система зависла.

Если ноутбук завис при пробуждении

По логам такое зависание выглядит как обрыв: последние строки — середина пробуждения, дальше ничего, а при следующей загрузке journald сообщает, что журнал не был корректно закрыт.

Что делать по шагам:

  1. Убедиться, что система вообще работала. Если после сбоя на диск не записалось ни одного файла, значит, система встала именно в этот момент (а не была выключена раньше):
find / -xdev -newermt '2026-11-06 15:10' ! -newermt '2026-11-08 15:47' -type f | head
  1. Посмотреть хвост журнала прошлой загрузки — он покажет, на каком шаге оборвалось:
journalctl -b -1 --no-pager | tail -40
journalctl -b -1 -k --no-pager | tail -40
  1. Проверить дамп паники, если он есть (нужен root):
sudo ls -la /sys/fs/pstore
  1. Попробовать другой режим сна. Если стоит s2idle, переключиться на deep и понаблюдать несколько циклов. Если не помогло — следующий подозреваемый обычно графика: на Intel отключают Panel Self Refresh параметром ядра i915.enable_psr=0.

  2. Для отладки железа у ядра есть /sys/power/pm_trace: при значении 1 метка последнего шага сна/пробуждения пишется в память RTC и переживает жёсткую перезагрузку. Это позволяет найти драйвер, на котором система встала.

Наш случай

6 ноября 2026 ноутбук (Dell Latitude 7400, UHD 620, Ubuntu 26.04) уснул 4 ноября и проснулся 6-го в 15:09:25. Через 0,4 секунды после PM: suspend exit журнал оборвался: система замерла на экране блокировки, пароль не вводился. На диск после этого не записалось ничего — ноутбук простоял так двое суток, пока его не выключили кнопкой.

Причина — зависание на выходе из s2idle. Лечение: переключение на deep параметром ядра mem_sleep_default=deep и обновление системы. Первое пробуждение на S3 прошло штатно: 5 минут сна, выход без ошибок. Точную подсистему, которая заклинила, по логам установить нельзя — в момент зависания перестают писаться и journald, и rsyslog.

Источники

Оценка статьи 0

Комментарии

Пока комментариев нет.