Luis Artola Luis Artola Engineer. Entrepreneur.

Solving the Framework Laptop Battery Drain Issue

2022-01-09  · 6 min read

The Framework Laptop with Ubuntu 21.10 is a great combination for development. However, the battery drains very quickly during sleep with the vanilla installation. A solution that works great is to enable deep sleep and hibernate. My system can now hibernate for weeks without depleting the battery. Because fine tuning a Linux system is not effortless, I hope this guide make it easier and straighforward to configure and give it a try.

Drain speed

The vanilla installation is configured with light sleep. It sleeps and wakes up very quickly. But, my battery was completely depleted in less that 24 hours of sleep. After enabling deep sleep, it was able to sleep just under 48 hours before depleting the battery completely. Not great.

After configuring hibernate I noticed that it drain just about 2% in 3 days of hibernation. If power loss is linear, then it can go for weeks before depleting completely. Back-of-the-envelope calculation estimates 20% in a month. Not too shabby! Obviously, real world usage would normally include a few breaks when the computer goes to deep sleep and hibernation. As a matter of fact, Linux systemctl allows you to:

  • suspend for deep sleep when you are taking a break during your work stretch and expect to come back to actually work on it.
  • hibernate for when you are done for the day or the week. Or, when you are going on vacation and taking an extended break from your computer. Or, when you are traveling and about to jump on an airplane.
  • suspend-then-hibernate gives you the best of two worlds. The system enters deep sleep for 2 hours (default config compiled into the kernel and configurable if you want to recompile it) and then enters hibernation automatically if sleep is uninterrupted. I don’t know for a fact, but this is likely what the macOS kernel is doing to preserve battery life during sleep.

Wake up speed

Waking up from deep sleep takes a couple of seconds if not faster. Waking from hibernation takes about 8 seconds in my system. Whether this is acceptable or too slow is likely a matter of personal opinion and debate. Pragmatically speaking though, it is not an issue and it’s fast enough. And, if my Framework can sleep for weeks when not in use without depleting the battery completely, even better!

Hibernate

How does hibernate work? In simple terms, the system takes a snapshot of your entire RAM and saves it to a swap file on disk. The file has to be large enough to fit your entire RAM. Then, when the system “wakes up”, it actually boots restoring the state by copying the entire contents of the swapfile to RAM. And voila!

Configuring deep sleep and hibernate is straightforward. It boils down to updating one line in your GRUB and initramfs configurations with the right sleep parameter, the disk UUID and swap file offset for saving and restoring the system state when entering and waking up from hibernation.

Configuration

This is how I did it. I consolidated information from some sources cited below to simplify and streamline the process. Be careful when making changes. While it’s straightforward, typos and mistakes could render your system unusable or make it difficult to restore.

It all boils down to ensuring that you have a swap file large enough for your RAM and adding the following parameters to GRUB_CMDLINE_LINUX_DEFAULT in your /etc/default/grub configuration file:

  1. mem_sleep_default=deep
  2. resume=UUID=012345ab-00a0-000a-a000-00aa000aa0a0
    resume_offset=123456789
    The disk UUID and offset are placeholders. You’ll make a note of the ones for your system running some commands below.

1. Resize swap file

Resize the swapfile. My system has 32 GB of RAM. I configured the swap file with 34 GB just to be safe. My disk has 1 TB so space is not an issue. Adjust according to your system.

sudo swapoff /swapfile  
sudo rm  /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1M count=34816
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

2. Get UUID and offset

Get UUID of the disk containing the swap file. My system has only one disk. If you have more than one, make sure it’s the one where the swap file resides. Take note of the UUID. You’ll use it later.

blkid

Get physical offset of the swapfile. The number you are looking for is fourth column from the left in the row for ext: 0 under physical_offset:. Take note of this value. You’ll use it later.

sudo filefrag -v /swapfile

For example, in my system it is 136611840:

Filesystem type is: ef53
File size of /swapfile is 35651584000 (8704000 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  227327:  136611840.. 136839167: 227328:            
...

3. Update GRUB

Use the UUID and physical offsets to enable deep sleep and resume location from hibernate during boot time. Add the following lines to your /etc/default/grub configuration file. This way, you can easily choose which method to use. Use the values from your system to customize line 1. below. Note that there are no quotes around the UUID:

# 1. Deep sleep + resume from hibernate to /swapfile: Drains more normally.
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep resume=UUID=012345ab-00a0-000a-a000-00aa000aa0a0 resume_offset=123456789"

# 2. Deep sleep: Wakes up fast but drains fast.
#GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep"

# 3. Light sleep: Wakes up fast but drains very fast.
#GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

Update GRUB and reboot:

sudo update-grub
sudo reboot

4. Update initramfs

Use your system’s UUID and physical offsets to customize and add the following line to your /etc/initramfs-tools/conf.d/resume file:

resume=UUID=012345ab-00a0-000a-a000-00aa000aa0a0 resume_offset=123456789

Update initramfs and reboot:

sudo update-initramfs -c -k all
sudo reboot

5. Aliases

I couldn’t figure out yet how to put a Hibernate option in the Power off/Logout Menu. But, since I always have a terminal open, I created two handy shortcuts:

alias hibernate='echo "Hibernate" && sudo systemctl hibernate'
alias suspend='echo "Suspend then Hibernate" && sudo systemctl suspend-then-hibernate'

6. Verify and enjoy!

You now have options:

  • Hibernate

    At this point, you should be able to run hibernate, enter your password and put the computer in hibernation mode. Leave all your windows and work open to verify that it restores the state exactly as you left it. To wake up, press the power button. It will take a few seconds to wake up. When you unlock the screen, you should get your entire session restored exactly as it was before.

  • Suspend then Hibernate

    Run suspend and enter your password to put your system in deep sleep mode. After 2 hours, it should automatically enter hibernation mode.

  • Deep sleep

    Simply closing the lid will put it in deep sleep mode. It should be possible to update the system to suspend-then-hibernate when closing the lid. But, I haven’t tried it yet.

References


 

Disclaimer: Opinions are my own.