linux 休眠进阶

挂起(suspend)和休眠(hibernate)是两个易混淆的词。因为要解释他俩的区别,还是要用到 suspend 这个词。通常,挂起指 suspend to ram(s2r),而休眠指 suspend to disk(s2d)。本文亦不例外。

现在的 linux,运气好的话,休眠是开箱即用的。本文所谓进阶,是以下两个技巧。如果对休眠的基本步骤有疑问,请参考各自发行版的 wiki(比如这里)。

一、如果休眠遇到问题

新人用 linux,最怕遇到硬件兼容问题。而一旦休眠遇到问题,那么八成是这机器的 acpi 支持很烂(对此没有概念的同学请学习本站《第二起跑线》三部曲)。如果你的机器在休眠过程中遇到诸如休眠死机、唤醒异常等情况,那么可以尝试此技巧:
echo shutdown > /sys/power/disk

至于这个“技巧”背后的故事,可以从内核文档 /Documentation/power/swsusp.txt 里找到线索(温馨提示,链接只是为了方便懒人,最新的内核文档应该在内核源代码包里找)。默认情况下,linux 假设 acpi 支持没有问题并使用 platform 休眠机制。改成 shutdown 机制的话,除非 linux 甚至无法正常关闭你的机器,否则都是没有问题的。副作用是你可能会失去一些酷酷的小功能(比如专门用于指示休眠的灯)。

以 lyman 的笔记本 Fujitsu MG75X/V 为例,全新启动的话,第一次休眠必然死机(死掉之后只能强行关机)。如果启动之后先“挂起并唤醒”,则之后的休眠就都没有问题。lyman 一直也都是用“全新启动一次就先挂起并唤醒”的办法来凑合的。采用了上述技巧之后,lyman 再也不用记得每次重启之后都先挂起一次了(忘记挂起的后果也是很严重的)。副作用是原来休眠之后翻开笔记本屏幕就自动唤醒的功能不见了,好在这个技巧并不影响挂起的同样功能。

二、调教休眠速度

或许你已经从无数大道小道消息中获知,想要顺利休眠,最好预留一个至少跟物理内存等大的 swap 分区——这无疑是最最安全的做法。

实际上,你可能已经发现,即使 swap 分区比物理内存小,也极少遇到休眠失败。那是因为,linux 在休眠的时候会按照一个预定值来裁减休眠镜像的尺寸。这个预定值记录在 /sys/power/image_size 中,从 2.6.16 起被设置为 500MB。

来看内核文档 /Documentation/power/interface.txt

/sys/power/image_size controls the size of the image created by the suspend-to-disk mechanism. It can be written a string representing a non-negative integer that will be used as an upper limit of the image size, in bytes. The suspend-to-disk mechanism will do its best to ensure the image size will not exceed that number. However, if this turns out to be impossible, it will try to suspend anyway using the smallest image possible. In particular, if "0" is written to this file, the suspend image will be as small as possible.

还是以 lyman 的本为例,4G 内存,平时内存使用量在 2~3G 之间徘徊,在没改过 /sys/power/image_size 之前,休眠镜像从未大于 500MB 过(lyman 猜测 90% 的桌面用户只要有一个大于 500M 的 swap 分区就不会遇到因为 swap 太小而无法休眠的情况)。

但是 lyman 也发现,有那么几次,当内存使用量接近 3G 的时候,休眠的耗时特别的长(2 分钟左右)。

其实,休眠过程中最占时间的两个步骤:一是生成休眠镜像,即内核尽量释放内存以争取减肥达标;二是将镜像写入磁盘。如果制定一个严格的减肥标准,内核花在减肥上的时间会增加,但是写磁盘的时间会减少;相反,如果标准宽松,减肥的时间短,写磁盘的时间就长。

所以,调教休眠的速度其实就是寻找一个合适的 image_size。这个值恰当与否,跟你的物理内存大小、平时内存的使用量、磁盘 IO 速度、已经分配了多大的 swap 分区都有关系。内核默认的 500MB,我猜应该是对“大多数”人都合理的一个统计结果。

对于 lyman 来说,默认的 500MB 明显偏少(休眠耗时从 45 秒到 2 分钟都有可能)。lyman 现在使用的 image_size 是 4GB(也是因为很保守的留了这么大的 swap)。通常休眠耗时 1 分钟上下,其中减肥时间基本可以忽略,至于磁盘写入——要是我这 ssd 写入也能上百(现在是 90 MB/s)就更好了……

评论

匿名说…
您好,我看到了您的blog,我的笔记本只有在image size设置为小于500mb的时候才可以正常休眠

我是1g内存,2gswap分区,休眠总失败提示
Feb 26 22:12:13 Alex-Nb kernel: [ 1022.320939] Adding 1036152k swap on /dev/sda7. Priority:-1 extents:1 across:1036152k
Feb 26 22:55:19 Alex-Nb kernel: [ 3607.911027] lattice[10108]: segfault at 200 ip b804ffed sp bfe57fd0 error 4 in ld-2.8.90.so[b803d000+1a000]
Feb 26 23:04:04 Alex-Nb kernel: [ 4133.692386] solarwinds[11041]: segfault at 200 ip b7f34fed sp bf93bb20 error 4 in ld-2.8.90.so[b7f22000+1a000]
Feb 27 01:02:57 Alex-Nb kernel: [11266.652217] b44: eth0: powering down PHY
我是参考了这个(http://ubuntuforums.org/archive/index.php/t-199952.html)将image size该小到free显示的swap大小解决的,你遇到过这个情况么?
Li Ruibo说…
没遇到过。我这正常使用的时候完全没 swap 什么事……

两个问题:
1、休眠之前 free 的输出是啥?
2、是不是用了 uswsusp 或者其他休眠程序?