45

I would like to use the hybrid suspend method instead of suspend when closing the lid or selecting "Suspend" from the menu.

I can imagine to change the pm-suspend script to do so automatically, but there might be a more maintainable / easier way.

8 Answers 8

48
+200

Indirect hybrid sleep

This is the older method: first suspend and then wake up to hibernate after a delay (15 minutes by default). Use this with a Linux kernel before 3.6, or if you like that it does not use any power after 15 minutes any more.

Add the file /etc/pm/config.d/00-use-suspend-hybrid:

# Always use suspend_hybrid instead of suspend
if [ "$METHOD" = "suspend" ]; then
  METHOD=suspend_hybrid
fi
# The delay after which hibernation gets triggered (default: 900 seconds, 15 minutes):
PM_HIBERNATE_DELAY=900

You might want to make sure that the hybrid method is supported on your system via the following code. If it says "0" it should work:

sudo pm-is-supported --suspend-hybrid && echo $?

Real hybrid suspending with Linux 3.6+

If you have a Linux 3.6 kernel, you can use the following, which will suspend to both disk and RAM from the beginning.

Add the file /etc/pm/config.d/00-use-suspend-hybrid:

# WORKAROUND: always set the default hibernate mode first (normal mode)
# (not required if you have the patch mentioned by Rohan below (http://askubuntu.com/a/344879/169))
HIBERNATE_MODE=platform

# Always use hibernate instead of suspend, but with "suspend to both"
if [ "$METHOD" = "suspend" ]; then
  METHOD=hibernate
  HIBERNATE_MODE=suspend
fi

# Make sure to use the kernel's method, in case uswsusp is installed etc.
SLEEP_MODULE=kernel

This will always write the image to disk and then suspend to RAM, having the benefits that resuming will always be fast (as long as the battery does not run out) and that the machine will not wake up for a short time (after PM_HIBERNATE_DELAY) to hibernate for real.

The drawback is that the process takes longer (because it always hibernates to disk), and that your battery might run out in the long run (e.g. after 12 hours).

5
  • 2
    one small note, instead of 'sudo pm-is-supported --suspend-hybrid && echo $?', use 'sudo pm-is-supported --suspend-hybrid ; echo $?' as the return value of pm-is-supported is 0 for is supported, and 1 for is not. Aug 3, 2012 at 17:50
  • 1
    @JamesCaccese: In shellscript world, 0 means "true" and anything else means "false". Your scriptlet would work, but the original poster's scriptlet would work as intended as well, printing a '0' on supported and nothing on unsupported. If you want something that will always say supported or unsupported, try 'sudo pm-is-supported --suspend-hybrid && echo "supported" || echo "unsupported"'
    – zanfur
    Oct 28, 2012 at 4:01
  • @zanfur - While I like your subsequent supplied solution for printing both states (and nothing for whatever unexpected reason pm-is-supported doesn't execute as expected, that would do unknown things to the error state), I appreciate James Caccese's mention of that caveat, for the aforementioned reason.
    – user66001
    Jun 8, 2013 at 13:16
  • If you're using 16.04 see this answer below.
    – kapad
    Jun 11, 2016 at 21:52
  • The only missing piece for me was resume argument in /etc/default/grub.conf. Also as nvidia user I had to set nomodeset. So resulting grub entry in my case is: GRUB_CMDLINE_LINUX_DEFAULT="nomodeset resume=UUID=uuidofswappartition". Don't forget grub-update. And also some modules has to be unloaded so created file /etc/pm/config.d/00-unload_modules with line SUSPEND_MODULES="ath5k r8169" and just to make sure I also renamed 00-use-suspend-hybrid to 10-use-suspend-hybrid
    – mauron85
    Oct 7, 2016 at 11:16
46
+300

Ubuntu 18.04 has a timed option

In Ubuntu 18.04 has a new timed option. In systemd, there is available a new mode suspend-then-hibernate. This will start with the sleep mode and then transition to the hibernate mode after a fixed time.

In the hybrid-sleep mode, the hibernate part gets effective only when the battery is critically low and the system shuts down.

To start using this function you need to create a file /etc/systemd/sleep.conf with the next content:

[Sleep]
HibernateDelaySec=3600

This will go from sleep to hibernate after 1 hour of sleep. You can edit HibernateDelaySec to change the delay to hibernate.

First, test if suspend-then-hibernate works using systemd

Open a terminal by pressing Ctrl+Alt+T and enter:

sudo systemctl suspend-then-hibernate

If it works make it permanent.

  • The following works when I close the lid.

Open the file /etc/systemd/logind.conf using your preferred editor. You will need to invoke your administrative power by sudo, gksudo or pkexec to edit this file.

Find the two lines:

#HandleSuspendKey=suspend
#HandleLidSwitch=suspend

Note, These lines are commented out with # in front of them. The suspend is the default action. Remove the # and change suspend to suspend-then-hibernate in these two lines so that they look like this:

HandleSuspendKey=suspend-then-hibernate
HandleLidSwitch=suspend-then-hibernate

Save the file. Log out and log back in or restart logind service by the command:

systemctl restart systemd-logind.service

warning! your user session will be restarted

Source: Lid Closed Suspend then Hibernate

Ubuntu 16.04 and above

The solution by blueyed for Real hybrid suspending with Linux 3.6+ did not work for me. I suspect this is because Ubuntu 16.04 uses systemd and does not use the file /etc/pm/config.d/00-use-suspend-hybrid.

First, test if hibernate and hybrid-sleep works using systemd

Open a terminal by pressing Ctrl+Alt+T and enter:

sudo systemctl hibernate

This should get your computer to hibernate. To try hybrid-sleep, enter:

sudo systemctl hybrid-sleep

If it works make it permanent.

  • The following works when I close the lid.

Open the file /etc/systemd/logind.conf using your preferred editor. You will need to invoke your administrative power by sudo, gksudo or pkexec to edit this file.

Find the two lines:

#HandleSuspendKey=suspend
#HandleLidSwitch=suspend

Note, These lines are commented out with # in front of them. The suspend is the default action. Remove the # and change suspend to hybrid-sleep in these two lines so that they look like this:

HandleSuspendKey=hybrid-sleep
HandleLidSwitch=hybrid-sleep

Save the file. Log out and log back in.

Note:

  • Other than suspend or hybrid-sleep there is a third option, hibernate.
  • My laptop does not have a physical sleep button. So I could not test it.
  • Clicking on the Suspend from the cog menu puts the computer to normal suspend not hybrid-sleep.

Source: https://superuser.com/questions/719447/how-to-use-systemd-hybrid-sleep-instead-of-suspend-under-gnome-in-linux

I hope this helps

5
  • 2
    This answer needs more upvotes. Fixed issues for me in 16.04. Thanks.
    – kapad
    Jun 11, 2016 at 21:51
  • You are welcome. Now that I have moved from 14.04 to 16.04, I am finding the new systemd way of doing things, slowly over time.
    – user68186
    Jun 12, 2016 at 4:12
  • 1
    Also works with Ubuntu GNOME 16.04.1 Jan 30, 2017 at 17:46
  • Hello. Do you know how to mute my computer when it goes from sleep to hibernate? After the timeout ends, my laptop turns on momentarily and goes into hibernation mode. When that happens it makes the welcome noise that my distro has.
    – Maccer
    Dec 4, 2020 at 20:31
  • @Maccer I don't know. Which distro are you using? My computer does not do that.
    – user68186
    Dec 4, 2020 at 22:29
4

In 12.04 I noticed that when hibernation is triggered (using PM_HIBERNATE_DELAY=XX), the resume/thaw the shell scripts do not unset the grub recordfail variable. Therefore grub does not autoboot.

Timeout is set to -1 and it awaits user selection. I am guessing this requires some editing of scripts in /etc/pm/sleep.d/10_grub-common. Am a novice so I haven't dabbled to figure out the exact change unfortunately.

2
  • 1
    Would be worth a bug report probably and/or testing if it works in 12.10+.
    – blueyed
    Nov 16, 2012 at 17:21
  • I see the same problem in 12.10
    – MDCore
    Dec 16, 2012 at 10:09
3

This question comes up frequently enough in Google that I think it's worth bumping. The method described here is (imo) not hybrid suspend. It is "hibernate after X minutes in suspend". True hybrid suspend writes your RAM out to disk and then goes in low-power state (sleep mode). While it takes longer, the resume is instant while the machine has battery left, otherwise resumes form hard disk. This behaviour is what most people know as hybrid sleep, and used by default in the newer Windows and Mac laptops.

Here's how to enable the real hybrid suspend:

  • Follow the first part of the top answer. This overrides "suspend" call to do a "hybrid_suspend" in pm-utils.
    % cat /etc/pm/config.d/00-use-suspend-hybrid
    # Always use suspend_hybrid instead of suspend
    if [ "$METHOD" = "suspend" ]; then
        METHOD=suspend_hybrid
    fi
  • Make a backup of /usr/lib/pm-utils/pm-functions
  • Get the patch from here: https://bugs.freedesktop.org/attachment.cgi?id=68712
    • This patch enables hybrid suspend if available (i.e. on kernels 3.6+)
  • Either apply it using 'patch -p0' or manually merge it if that fails

This method works for me on my Sony Vaio SVS.

PS: Reproducing the patch here in case the file is deleted in the future:

diff --git a/pm/pm-functions.in b/pm/pm-functions.in
--- a/pm/pm-functions.in
+++ b/pm/pm-functions.in
@@ -316,8 +316,28 @@ if [ -z "$HIBERNATE_MODULE" ] && \
    {
        [ -n "${HIBERNATE_MODE}" ] && \
        grep -qw "${HIBERNATE_MODE}" /sys/power/disk && \
+       HIBERNATE_MODE_SAVE=$(cat /sys/power/disk) && \
+       HIBERNATE_MODE_SAVE="${HIBERNATE_MODE_SAVE##*[}" && \
+       HIBERNATE_MODE_SAVE="${HIBERNATE_MODE_SAVE%%]*}" && \
        echo -n "${HIBERNATE_MODE}" > /sys/power/disk
        echo -n "disk" > /sys/power/state
+       RET=$?
+       echo -n "$HIBERNATE_MODE_SAVE" > /sys/power/disk
+       return "$RET"
+   }
+fi
+
+# for kernels that support suspend to both (i.e. hybrid suspend)
+# since kernel 3.6
+if [ -z "$SUSPEND_HYBRID_MODULE" ] && \
+   [ -f /sys/power/disk ] && \
+   grep -q disk /sys/power/state && \
+   grep -q suspend /sys/power/disk; then
+   SUSPEND_HYBRID_MODULE="kernel"
+   do_suspend_hybrid()
+   {
+       HIBERNATE_MODE="suspend"
+       do_hibernate
    }
 fi

Sources:

2
  • 1
    You are right about hybrid-suspend. I have recently changed my snippet myself. You can get (quite) the same result by using METHOD=hibernate and HIBERNATE_MODE=suspend. I am setting HIBERNATE_MODE=platform at the top of the file, instead of saving and restoring the previous version (what the patch does). I will update my answer above.
    – blueyed
    Oct 8, 2013 at 23:56
  • That looks great, thanks for the edit, @blueyed Oct 18, 2013 at 1:30
1

There's another solution without adding any file in config.d, just using wakealarm in /sys/class/rtc/rtc0. Make use obsolete code in pm-functions (/usr/lib/pm-utils) after the comments #since the kernel does not directly support ... , ('cos the current kernel (after 3.6 something) does directly support). Revert that code and put in do_suspend() part instead of do_suspend_hybrid(), and use the patch for pm-functions ('til they fix it).

Obsolete code (suspend then hibernate when suspend_hybrid is called):

# since the kernel does not directly support hybrid sleep, we do
# something else -- suspend and schedule an alarm to go into
# hibernate if we have slept long enough.
# Only do this if we do not need to do any special video hackery on resume
# from hibernate, though.
if [ -z "$SUSPEND_HYBRID_MODULE" -a -w "$PM_RTC/wakealarm" ] && \
    check_suspend && check_hibernate && ! is_set $HIBERNATE_RESUME_POST_VIDEO; \
    then
    SUSPEND_HYBRID_MODULE="kernel"
    do_suspend_hybrid() {
    WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
    echo >"$PM_RTC/wakealarm"
    echo $WAKETIME > "$PM_RTC/wakealarm"
    if do_suspend; then
        NOW=$(cat "$PM_RTC/since_epoch")
        if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ]; then
        log "Woken by RTC alarm, hibernating."
        # if hibernate fails for any reason, go back to suspend.
        do_hibernate || do_suspend
        else
        echo > "$PM_RTC/wakealarm"
        fi
    else
        # if we cannot suspend, just try to hibernate.
        do_hibernate
    fi
    }
fi

Recommended. Even easier to use uswsusp while the same time maximize the benefit of s2both i.e. s2both when suspend. Put the reverted code in do_suspend() part of uswsusp module (/usr/lib/pm-utils/module.d).

Reverted code (suspend_hybrid when suspend is called):

        WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
        echo >"$PM_RTC/wakealarm"
        echo $WAKETIME > "$PM_RTC/wakealarm"
        if do_suspend_hybrid; then
            NOW=$(cat "$PM_RTC/since_epoch")
            if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ];             then
            log "Woken by RTC alarm, hibernating."
            # if hibernate fails for any reason, go back to suspend_hybrid.
            do_hibernate || do_suspend_hybrid
            else
            echo > "$PM_RTC/wakealarm"
            fi
        else
            # when do_suspend is being called, convert to suspend_hybrid.
            do_suspend_hybrid
        fi      

With uswsusp, we can see the progress of suspend/hibernate and the reverse process displayed in text, even we can abort it by pressing backspace. Without uswsusp, suspend/hibernate just appear-disappear annoyingly, especially when wakealarm is triggered and execute hibernate (s2disk in uswsusp). Set the period of sleep before hibernate in the usual place on pm-functions file.

# variables to handle hibernate after suspend support
PM_HIBERNATE_DELAY=900  # 15 minutes
PM_RTC=/sys/class/rtc/rtc0

Here's the uswsusp mod: (remember, this module is called from pm-functions so the inserted variables are the same)

#!/bin/sh

# disable processing of 90chvt and 99video.
# s2ram and s2disk handle all this stuff internally.
uswsusp_hooks()
{
    disablehook 99video "disabled by uswsusp"
}

# Since we disabled 99video, we need to take responsibility for proper
# quirk handling.  s2ram handles all common video quirks internally,
# so all we have to do is translate the HAL standard options to s2ram options.
uswsusp_get_quirks()
{
    OPTS=""
    ACPI_SLEEP=0
    for opt in $PM_CMDLINE; do
        case "${opt##--quirk-}" in # just quirks, please
            dpms-on)       ;; # no-op
            dpms-suspend)      ;; # no-op
            radeon-off)        OPTS="$OPTS --radeontool" ;;
            reset-brightness)  ;; # no-op
            s3-bios)       ACPI_SLEEP=$(($ACPI_SLEEP + 1)) ;;
            s3-mode)       ACPI_SLEEP=$(($ACPI_SLEEP + 2)) ;;
            vbe-post)      OPTS="$OPTS --vbe_post" ;;
            vbemode-restore)   OPTS="$OPTS --vbe_mode" ;;
            vbestate-restore)  OPTS="$OPTS --vbe_save" ;;
            vga-mode-3)        ;; # no-op
            save-pci)          OPTS="$OPTS --pci_save" ;;
            none)          QUIRK_NONE="true" ;;
            *) continue ;;
        esac
    done
    [ $ACPI_SLEEP -ne 0 ] && OPTS="$OPTS --acpi_sleep $ACPI_SLEEP"
    # if we were told to ignore quirks, do so.
    # This is arguably not the best way to do things, but...
    [ "$QUIRK_NONE" = "true" ] && OPTS=""
}

# Since we disabled 99video, we also need to handle displaying
# help info for the quirks we handle.
uswsusp_help()
{
    echo  # first echo makes it look nicer.
    echo "s2ram video quirk handler options:"
    echo
    echo "  --quirk-radeon-off"
    echo "  --quirk-s3-bios"
    echo "  --quirk-s3-mode"
    echo "  --quirk-vbe-post"
    echo "  --quirk-vbemode-restore"
    echo "  --quirk-vbestate-restore"
    echo "  --quirk-save-pci"
    echo "  --quirk-none"
}

# This idiom is used for all sleep methods.  Only declare the actual
# do_ method if:
# 1: some other sleep module has not already done so, and
# 2: this sleep method can actually work on this system.
#
# For suspend, if SUSPEND_MODULE is set then something else has already
# implemented do_suspend.  We could just check to see of do_suspend was
# already declared using command_exists, but using a dedicated environment
# variable makes it easier to debug when we have to know what sleep module
# ended up claiming ownership of a given sleep method.
if [ -z "$SUSPEND_MODULE" ] && command_exists s2ram && \
    ( grep -q mem /sys/power/state || \
        ( [ -c /dev/pmu ] && check_suspend_pmu; ); ); then
    SUSPEND_MODULE="uswsusp"
    do_suspend()
    {
        WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
        echo >"$PM_RTC/wakealarm"
        echo $WAKETIME > "$PM_RTC/wakealarm"
        if do_suspend_hybrid; then
            NOW=$(cat "$PM_RTC/since_epoch")
            if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ];             then
            log "Woken by RTC alarm, hibernating."
            # if hibernate fails for any reason, go back to suspend_hybrid.
            do_hibernate || do_suspend_hybrid
            else
            echo > "$PM_RTC/wakealarm"
            fi
        else
            # when do_suspend is being called, convert to suspend_hybrid.
            do_suspend_hybrid
        fi      
    }
fi

if [ -z "$HIBERNATE_MODULE" ] && \
    [ -f /sys/power/disk ] && \
    grep -q disk /sys/power/state && \
    [ -c /dev/snapshot ] &&
    command_exists s2disk; then
    HIBERNATE_MODULE="uswsusp"
    do_hibernate()
    {
        s2disk
    }
fi

if [ -z "$SUSPEND_HYBRID_MODULE" ] && 
    grep -q mem /sys/power/state && \
    command_exists s2both && \
    check_hibernate; then
    SUSPEND_HYBRID_MODULE="uswsusp"
    do_suspend_hybrid()
    {   
        uswsusp_get_quirks
        s2both --force $OPTS 
    }
    if [ "$METHOD" = "suspend_hybrid" ]; then
        add_before_hooks uswsusp_hooks
        add_module_help uswsusp_help
    fi
fi  
0

The answer by user68186 for Ubuntu 16.04 did not work for me. However, the solution here did.

First, ensure hibernation works. Then

Search for and install dconf Editor in Ubuntu Software. Then launch it and navigate to org -> gnome -> settings daemon -> plugins -> power.

Change the value of “lid-close-ac-action” and “lid-close-battery-action”.

In my power settings, these options show up as blank, but they work as intended.

0

In Ubuntu 18.04 it much more easer. In systemd is availiable a new mode suspend-then-hibernate. To start using this function you need to create a file /etc/systemd/sleep.conf with the next content:

[Sleep]
HibernateDelaySec=3600

Then you can test it by command:

sudo systemctl suspend-then-hibernate

(you can edit HibernateDelaySec to reduce delay to hibernate). If all works fine you can change Lid Close Action, to do it you need to edit the file /etc/systemd/logind.conf

You need to find option HandleLidSwitch=, uncomment it and change to HandleLidSwitch=suspend-then-hibernate. Then you need to restart logind service(wirning! you user session will be restarted) by the next command:

systemctl restart systemd-logind.service

Thats all! Now you can use this nice function.

0

Just add this 2 lines to /etc/systemd/sleep.conf:

SuspendMode=suspend
SuspendState=disk

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .