暴走プロセスをcpulimitで落ち着かせるAppleScript(主にOneDrive for Mac OSX)


MacOS上でOneDriveが暴走しCPUをブン回し続けてしまう事態がしばしば発生します。
どうやら同じ症状に見舞われている方は多いようで,対策として,たとえば暴走したプロセスをkillするシェルスクリプトをcrontabに登録する手法が紹介されています。
[Mac OS] OneDriveの暴走対策 - Qiita

しかし臆病な私はプロセスを強制終了させるのが怖い。killではなくたとえばCPU使用率の制限でどうにかならないものか。
うってつけの,cpulimitというコマンドがあるようです。

そこで,暴走を感じたときに手動でcpulimitを動作させて,頭を冷やしてもらうことにします。

cpulimitのインストール

$ brew install cpulimit
$ which cpulimit
/usr/local/bin/cpulimit #←筆者の環境の場合。あとで使う。

暴走中のプロセスにcpulimitを適用するAppleScript

なぜAppleScriptにするのかというと,スクリプト・メニューに登録してメニューバーから実行できるようにするためです。
cpulimitするべきプロセス,私の環境ではプロセス名distnotedが暴走する場合もあれば,プロセス名OneDriveが暴走する場合もある。
そこで,何でもいいから一番CPUを使っているプロセスにリミッターをかけることにしました。たぶんkillほど丁寧に考えなくていいし。

暴走プロセスcpulimit.scpt
set path_cpulimit to "/usr/local/bin/cpulimit" (* 上の$ which で得たパス *)

(* プロセスIDを取得 *)
set pid to (do shell script "ps -Aro pid | sed -n 2p") as number

(* 最大CPU使用率を30%に制限してみる。 *)
do shell script (path_cpulimit & " -l 30 -p " & pid)

AppleScriptからのdo shell scriptでは(ターミナルの標準シェルでパスを通しても)パスが通らないらしいので,あらかじめwhichでフルパスを調べた上で使います。
cpulimitコマンドは,CPU使用率とプロセスIDを指定して実行します。ここではCPU使用率は30%に決め打ちしてみましたが,プロセスIDは調べなきゃわからない。
そこで,psコマンドでプロセスIDをCPU使用率順に並べた上で(ps -Aro pid),その2行目(∵先頭行は見出し行)を抽出(sed -n 2p)することで,最もCPU使用率が高いプロセスのプロセスIDを取得します。

このスクリプトをスクリプト・メニューに登録して実行すると,下図のように,ずっとスクリプトが回り続けます⚙。これはおそらくcpulimitがプロセスを常駐させるコマンドだからで,閉じるボタン(x)をクリックしても反応しません。並列処理の&オプションをつけても同じでした。

仕方ないので,cpulimitは別のスクリプトから終了させることにします。

cpulimitを終了させるAppleScript

killall_cpulimit.scpt
do shell script "killall cpulimit"

固定のコマンドを実行するだけですが,AppleScriptにしておくことで,cpulimit発動時と同様にメニューバーから実行できます。
これを実行すると,動き続けていた暴走プロセスcpulimit.scptも終了します。おそらく,cpulimitの終了で処理に戻る結果,最後まで辿り着いて終了するのでしょう。

Enjoy!