寝付きの悪いMacBookにすやすや眠ってもらう
いつの頃からか、MacBookの寝付きが悪くなってしまった。スリープさせても1、2時間(ひどい時は数分)で勝手に目を覚ましてしまう...。スリープ解除後は、モニタのみ消灯して、OS環境は普通に稼働している。
もちろん、モニタを閉じれば確実にスリープすることは分かっている。しかし、現状の自分のMacBookは、サーバーを兼用した以下のような利用環境である。
利用環境
- 白MacBook(2008 late)
- OSX 10.6.8
- システム環境設定 >> 省エネルギー >> 「ネットワークアクセスによってスリープを解除」にチェック入りの設定。
- モニタは閉じずにスリープ。(アップルメニューからスリープ、あるいは電源ボタン-Sでスリープさせた状態)
つまり、Wake on Demand が有効な状態でMacBookを運用しているのだ。
- Wake on Demand を活用すれば、有線・無線に関係なく、ネットーワークに接続されたスリープ中のMacBookに、いつでも接続して共有サービスを利用できるのだ。
- 共有サービスとは、システム環境設定 >> 共有で表示される、ファイル共有・画面共有・Web共有...などである。
- これでMacBookは、賢いサーバーになる。
- 使わない時は必要最小限の電力で待機(スリープ)して、使う時にはすぐに反応してくれる。
...のはずなんだが、省エネルギー環境設定のとおりにスリープしてくれないのが今の悩み。これからの季節、数百万台のmacが一斉にちゃんとスリープしたら、多少の節電効果もありそうな気がする。確実にスリープする設定を求めて、試行錯誤してみた。
調査
- まず、どのタイミングで勝手にスリープが解除されてしまうのか?調べてみた。
- そうゆうことは、たいていログに記録されているはずである。
- コンソール.appを起動して、スリープが解除された瞬間のログを探してみた。
- ログリストを「すべてのメッセージ」にして、それらしきログを目で追ってみた。
- しばらく遡ると、以下の記述が見つかった。
...(中略)... 11/07/05 7:32:22 kernel System Sleep 11/07/05 7:45:27 kernel Wake reason = UHC3 11/07/05 7:45:27 kernel System Wake ...(中略)...
- それにしても「すべてのメッセージ」だと、余分なログが多くて読みにくい...。
- 送信元がkernelとなっているので、kernel.logを開いてみた。
スリープが解除される理由
- kernel.logを開くと、もっと効率的にスリープとその解除を追うことができた。
...(中略)... Apr 30 08:33:35 bebe-MacBook kernel[0]: System Sleep Apr 30 08:33:35 bebe-MacBook kernel[0]: Wake reason = RTC Apr 30 08:33:35 bebe-MacBook kernel[0]: RTC: maintenance alarm 2011/4/30 00:12:15, sleep 2011/4/29 23:33:34 Apr 30 09:12:15 bebe-MacBook kernel[0]: System Wake Apr 30 09:12:15 bebe-MacBook kernel[0]: Previous Sleep Cause: 5 Apr 30 09:12:15 bebe-MacBook kernel[0]: AirPort: Link Down on en1. Reason 4 (Disassociated due to inactivity). Apr 30 09:12:15 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 12 Apr 30 09:12:17 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 13 Apr 30 09:12:17 bebe-MacBook kernel[0]: Ethernet [AppleYukon2]: Link up on en0, 1-Gigabit, Full-duplex, Symmetric flow-control, Debug [796d,af08,0de1,0200,cde1,2800] Apr 30 09:12:20 bebe-MacBook kernel[0]: Auth result for: 00:1f:5b:89:37:ed MAC AUTH succeeded Apr 30 09:12:20 bebe-MacBook kernel[0]: AirPort: Link Up on en1 Apr 30 09:12:20 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 13 Apr 30 09:12:20 bebe-MacBook kernel[0]: AirPort: RSN handshake complete on en1 Apr 30 09:12:21 bebe-MacBook kernel[0]: IOPMrootDomain: idle revert Apr 30 09:12:23 bebe-MacBook kernel[0]: R-state changed 2->0 Apr 30 09:12:23 bebe-MacBook kernel[0]: AFPSleepWakeHandler: waking up Apr 30 09:12:25 bebe-MacBook kernel[0]: utun_ctl_connect: creating interface utun0 Apr 30 18:15:02 bebe-MacBook kernel[0]: AFPSleepWakeHandler: going to sleep Apr 30 18:15:02 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 14 Apr 30 18:15:03: --- last message repeated 1 time --- Apr 30 18:15:03 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 15 Apr 30 18:15:06: --- last message repeated 1 time --- Apr 30 18:15:06 bebe-MacBook kernel[0]: enet_event_func - vendor 1, class 1, subclass 2, event code 12 Apr 30 18:15:06 bebe-MacBook kernel[0]: PM mode before entering WoW is 1 and PM allowed state is 1 Apr 30 18:15:06 bebe-MacBook kernel[0]: System Sleep Apr 30 18:43:35 bebe-MacBook kernel[0]: Wake reason = RTC Apr 30 18:43:35 bebe-MacBook kernel[0]: RTC: maintenance alarm 2011/4/30 09:43:35, sleep 2011/4/30 09:15:06 Apr 30 18:43:35 bebe-MacBook kernel[0]: System Wake ...(中略)...
- 上記ログはその一部だが、地道に追跡すると、スリープが解除されるタイミングが見えてきた。
- どうやら勝手にスリープが解除される時は必ず「Wake reason = RTC」のログがきっかけになっている。
- 日本語訳すると「目を覚ます理由 = RTC」ということ。
- RTCは何かというと、その下のログに書いてある。
- 「RTC: maintenance alarm 2011/4/30 09:43:35, sleep 2011/4/30 09:15:06」
- RTCとはメンテナンスアラームらしい。(時間が9時間ズレているのは、おそらくその部分だけ協定世界時 UTC で記述されているためと思われる)
- 検索してみると、MacBookは2時間に1回(正確には1時間47、48分ごとだった)スリープを解除する仕様のようだ。
- その理由は、Wake on Demand なスリープ中であっても、ネットワーク上にその存在を継続して通知するため。
- 「Wake reason = RTC」で勝手にスリープが解除されるのは正常な仕様である。
- そして仕様では、その後は速やかに再びスリープするはず。
- しかし現状では、その後Sleepすることなく、Wake状態になってしまっている。
再びsleepさせるAppleScript
- なぜ再びスリープしてくれないのか、その原因は分からない。
- しかし、AppleScriptを使えば、強制的にスリープさせることは簡単にできる。
- 1分ごとに「Wake reason = RTC」ログを監視して、
- そのログが変化した時、強制的にスリープするようにしてみた。
property wake_log : ""
on run
set wake_log to my wake_reason_rtc() end run
on idle
set current_log to my wake_reason_rtc() if current_log ≠ "" and current_log ≠ wake_log then
set wake_log to current_log
reopen
end if
return 60
end idle
on reopen
my alert_going_to_sleep() my mac_sleep() end reopen
on wake_reason_rtc() do shell script "grep -e 'Wake reason = RTC' '/var/log/kernel.log'"
end wake_reason_rtc
on alert_going_to_sleep() my system_sound("Submarine.aiff") activate
display dialog "15秒後にスリープします。" with icon note giving up after 15
end alert_going_to_sleep
on mac_sleep() tell application "Finder" to sleep
--do shell script "pmset sleepnow >& /dev/null &"
end mac_sleep
on system_sound(fname) do shell script "(sleep 0; afplay /System/Library/Sounds/" & fname & ") >& /dev/null &"
end system_sound
それでも寝不足気味
原因追求
- 問題ありそうなプロセスを強制終了させたり、条件を変えてスリープさせる中で少しずつ分かってきた。
- どうも、AppleScriptからスリープさせた時に問題が発生しているようなのだ。
- しかも、目の前で実験するとうまくいくのに、見ていない所では異常な動作。(何だか量子論的な謎の振る舞い)
delay 70
tell application "Finder" to sleep
- 60秒後にディスプレイがスリープして、70秒後にコンピュータがスリープするはずなのだが、
- 実行してみると、70秒後のコンピュータのスリープは実現されない...。
- 一方、delay 60にして再度実行すると、こちらはちゃんとコンピュータがスリープする。
delay 60
tell application "Finder" to sleep
つまり、ディスプレイがスリープした状態では、上記AppleScriptからのスリープが正常に機能しないのだ!(自分の環境では)
確実にスリープさせるコード
- 実験の結果、ディスプレイがスリープ中だと、以下のスクリプトはことごとくスリープに失敗した。
tell application "Finder" to sleep
tell application "System Events" to sleep
tell application "loginwindow" to «event aevtslep»
- そして、唯一どんな条件でも確実にスリープさせる書き方も一つ見つかった。
do shell script "pmset sleepnow"
- 早速、現在活用しているAppleScriptのスリープさせる部分のコードを「pmset sleepnow」方式にすべて書き直した。
これで、勝手に目覚めてしまうスリープ問題はひとまず解決。
共有サービスが使えなくなってしまう症状も発生しなくなった。
自動スリープ
そもそも、もう一つ重要なスリープ問題があった。
- 省エネルギー環境設定で、コンピュータのスリープを1分にしてみる。
- 何も操作しないで1分間じっと我慢すると、ディスプレイはスリープする。
- しかし、コンピュータはいつまで経ってもスリープしないのだ...。
- もちろん、映像や音楽を再生していない状態である。
- 外付けハードディスクに最新のOSX 10.6.8をインストールしてみた。
- サードパーティのソフトウェアは一切インストールなしの純粋な状態で起動してみた。
- にもかかわらず、自動スリープしてくれない。終わっとる...。(外付けHDだから? )
- またしてもAppleScriptで自動スリープさせるかと考えたが、何も操作をしない状態をAppleScriptで検出するのって、結構難しそうだ。
- ところで、この自動スリープしない問題は、多くのユーザーの悩みらしく、検索してみると多くの話題がヒットする。
- 世界は広く、達人はどこかに居いる。この問題を解決する素晴らしいアプリケーションが既に開発されていた。
PleaseSleep
- 起動しておくだけで、省エネルギー環境設定のとおりに、自動スリープするようになる。
- Dcokには表示されず、メニューバーに表示されるバックグラウンドなアプリケーション。
PleaseSleep、優秀過ぎる!
- 先に作ったsleep_keeper(AppleScript)の代替にもなるかもしれない。(自動スリープの間隔を短くしておけば良いのだ)
以上で、MacBookは放っておいても勝手にすやすや眠るようになったのであった。