08月30日
AppNapライクにSafari,Firefoxをコントロール(cputhrottle & applescript)v3.0
Firefox, Safariが未使用時、CPU使用率を下げて発熱を抑えるAppNapもどき
スクリプトの改善版です。
AppNapライクにWebProcessをコントロール(cputhrottle & applescript)
AppNapライクにWebProcessをコントロール(cputhrottle & applescript)v2.0
v2.0 不定期にエラーが発生しています。
sh: -c: line 0: syntax error near unexpected token '('
sh: -c: line 0: 'logger -t appnap-browser -i
errorMessage: /bin/sh: line 0: kill: (1553) - No such process, errorNumber: 1'
エラーの内容からすると、
loggerコマンドでログを出力する際に
指定したログメッセージに誤りがあるようです。
(とかあるとエスケープされずにそのまま出力されてエラーになると予想できます。
quoted fromでログメッセージをエスケープ処理するように修正します。
do shell script "logger -t appnap-browser -i " & quoted form of logmsg
これ以外に、いくつか事象・現象が発生していました。
コマンド位置の変更と、cputhrottleの存在確認の修正を合わせて行いました。
cputhrottleは、こちら( AppNapライクにWebProcessをコントロール(cputhrottle & applescript) )を参考にしてください。
以下ソースをAppleScriptエディタにコピペします。
コピペ後、以下設定を書き換えてください。
ファイルフォーマット:アプリケーション、オプションとして「ハンドラの実行時に終了しない」を選んで、書き出します。
(ここではファイル名:appnap-browser.appを想定しています)
起動するとdockにappnap-browserアイコンが存在しています。
appnap-browserアイコンを選択後、
メニューから終了を選んでください。
(appnap-browser -> appnap-browserを終了)
loggerコマンドでログを出力する際に
指定したログメッセージに誤りがあるようです。
(とかあるとエスケープされずにそのまま出力されてエラーになると予想できます。
quoted fromでログメッセージをエスケープ処理するように修正します。
do shell script "logger -t appnap-browser -i " & quoted form of logmsg
これ以外に、いくつか事象・現象が発生していました。
- /tmp/にコマンドを置いていましたが、しばらくすると/tmp/のクリア処理が動作し、消去されて起動できなくなる事象
- sleep復帰後、たまにcputhrottleが落ちている現象
コマンド位置の変更と、cputhrottleの存在確認の修正を合わせて行いました。
appnap-webbrowser.app(applescript) v3.0
前提
- cputhrottleコマンドがインストールされている。
- スクリプトを実行するユーザは管理者権限を持っている
cputhrottleは、こちら( AppNapライクにWebProcessをコントロール(cputhrottle & applescript) )を参考にしてください。
ソース
以下ソースをAppleScriptエディタにコピペします。
コピペ後、以下設定を書き換えてください。
- myPassword to "-- 管理者パスワードに置き換えてください --" の行を修正してください。
- CPU_SLOW_COMMAND to "/path/to/unix"の行を修正してください。
cputhrottleコマンドをご自身の環境に合わせて修正してください。
ex) cputhrottleコマンドが/Users/Username/command/cputhrottleにある場合
set CPU_SLOW_COMMAND to "/Users/Username/command/cputhrottle"
と指定します。
ファイルフォーマット:アプリケーション、オプションとして「ハンドラの実行時に終了しない」を選んで、書き出します。
(ここではファイル名:appnap-browser.appを想定しています)
global CPU_SLOW_PERCENTAGE
global CPU_SLOW_COMMAND
global myProcessDataList
global myPassword
global process_monitor_interval
global process_monitor_counter
set myPassword to "-- 管理者パスワードに置き換えてください --" -- <- 管理者のパスワード
set CPU_SLOW_PERCENTAGE to "5" -- <- フォーカスがない場合:プロセスのCPU使用率をpercentで指定
-- cputhrottleコマンドの場所を指定
set CPU_SLOW_COMMAND to "/path/to/unix/cputhrottle"
-- cputhrottleコマンドの生存確認間隔を指定(秒)
set process_monitor_interval to 60 -- On idle が60回呼び出されたら
set myProcessDataList to {}
set process_monitor_counter to 0
-- ===========================
-- ProcessData
-- クラス
script ProcessData
property pid : -1
property procName : ""
on new(thePid, theProcName)
copy me to theData
set_pid(thePid) of theData
set_procName(theProcName) of theData
theData
end new
on set_pid(value)
set pid to value
end set_pid
on set_procName(value)
set procName to value
end set_procName
end script
-- ===========================================
-- FindProcessData
-- theList配列中のtheProcNameを検索する
-- 入力: theList ProcessDataの配列
-- theProcName 検索するプロセス名を指定
-- 出力: retList 検索した結果(ProcessData配列)
-- 返り値: 検索した結果(ProcessData配列)
on FindProcessDataList(theList, theProcName, retList)
repeat with v in theList
if procName of v is equal to theProcName then
set end of retList to v
end if
end repeat
return retList
end FindProcessDataList
-- ===========================================
-- DeleteProcessDataList
-- theList配列中のtheProcNameを配列から削除する
-- 入力: theList ProcessDataの配列
-- theProcName 削除するプロセス名を指定
-- 出力: retList 削除されなかったデータ配列(ProcessData配列)
-- 返り値: 削除されなかったデータ配列(ProcessData配列)
on DeleteProcessDataList(theList, theProcName)
set retList to {}
repeat with v in theList
if procName of v is not equal to theProcName then
set end of retList to v
end if
end repeat
return retList
end DeleteProcessDataList
-- ===========================================
-- StartBackgroundCpuControl
-- プロセスの使用率を下げる
-- 入力: theProcName 使用率を下げるプロセス名を指定
-- 出力: theControledList コントロール中のデータ配列(ProcessData配列)
-- 返り値: なし
on StartBackgroundCpuControl(theProcName, theControledList)
tell application "System Events"
set pList to (unix id of every process whose name contains theProcName)
if pList is not equal to {} then
-- syslog("StartBackgroundCpuControl " & theProcName & "") of me
repeat with unixID in pList
do shell script CPU_SLOW_COMMAND & " " & (unixID as string) & " " & CPU_SLOW_PERCENTAGE & " >/dev/null 2>&1 & echo $!" password myPassword with administrator privileges
set pid to result
syslog("start " & theProcName & " cputhrottle " & (unixID as string) & " " & CPU_SLOW_PERCENTAGE & ", PID=" & pid) of me
set end of theControledList to new(pid, theProcName) of ProcessData
end repeat
end if
end tell
end StartBackgroundCpuControl
-- ===========================================
-- StopBackgroundCpuControl
-- プロセスの使用率をもとに戻す
-- 入力: theControledList もとに戻すデータ配列(ProcessData配列)
-- 出力: なし
-- 返り値: なし
on StopBackgroundCpuControl(theControledList)
-- syslog("StopBackgroundCpuControl targetCount=" & (length of theControledList as string) & "") of me
repeat with v in theControledList
try
if IsExistsProcess(pid of v) of me is equal to true then
do shell script "kill -INT " & (pid of v as string) password myPassword with administrator privileges
syslog("stop " & (procName of v) & " cputhrottle , PID=" & (pid of v as string)) of me
end if
on error errorMessage number errorNumber
syslog("StopCpuControl errorMessage: " & errorMessage & ", errorNumber: " & errorNumber) of me
end try
end repeat
end StopBackgroundCpuControl
-- ===========================================
-- IsExistsProcess
-- プロセスの存在確認
-- 入力: thePid プロセスID
-- 出力: なし
-- 返り値: true 存在 false 存在しない
on IsExistsProcess(thePid)
try
set the_result to do shell script "ps -p " & (thePid as string) & " | awk '{print $1}' | grep " & (thePid as string)
if the_result is equal to (thePid as string) then
return true
else
return false
end if
on error errorMessage number errorNumber
return false
end try
end IsExistsProcess
-- ===========================================
-- CheckingBackgroundCpuProcess
-- プロセスの存在確認
-- 入力: theList 存在を確認するデータ配列(ProcessData配列)
-- 出力: なし
-- 返り値: 存在を確認したデータ配列(ProcessData配列)
on CheckingBackgroundCpuProcess(theList)
set retList to {}
repeat with v in theList
if IsExistsProcess(pid of v) of me is equal to false then
syslog("detect CPUSlowControlProcess down. pid=" & (pid of v as string) & " origin=" & (procName of v)) of me
else
set end of retList to v
end if
end repeat
return retList
end CheckingBackgroundCpuProcess
on idle
try
tell application "System Events"
set activeProcs to every process whose frontmost is true
set activeProc to item 1 of activeProcs
tell activeProc
set activeProcName to name
end tell
end tell
if process_monitor_counter = process_monitor_interval then
set process_monitor_counter to 0
set myProcessDataList to CheckingBackgroundCpuProcess(myProcessDataList)
else
set process_monitor_counter to process_monitor_counter + 1
end if
if activeProcName is equal to "Safari" then
set targetProcess to {}
set targetProcess to FindProcessDataList(myProcessDataList, "WebProcess", targetProcess)
if length of targetProcess is not equal to 0 then
StopBackgroundCpuControl(targetProcess)
set myProcessDataList to DeleteProcessDataList(myProcessDataList, "WebProcess")
end if
else if activeProcName is equal to "Firefox" then
set targetProcess to {}
set targetProcess to FindProcessDataList(myProcessDataList, "Firefox", targetProcess)
if length of targetProcess is not equal to 0 then
StopBackgroundCpuControl(targetProcess)
set myProcessDataList to DeleteProcessDataList(myProcessDataList, "Firefox")
end if
else
set targetProcess to {}
set targetProcess to FindProcessDataList(myProcessDataList, "WebProcess", targetProcess)
if length of targetProcess is equal to 0 then
-- 制御中は、再実行しない
StartBackgroundCpuControl("WebProcess", myProcessDataList)
end if
set targetProcess to {}
set targetProcess to FindProcessDataList(myProcessDataList, "Firefox", targetProcess)
if length of targetProcess is equal to 0 then
-- 制御中は、再実行しない
StartBackgroundCpuControl("Firefox", myProcessDataList)
end if
end if
return 1
on error errorMessage number errorNumber
syslog("onIdle errorMessage: " & errorMessage & ", errorNumber: " & errorNumber) of me
error
end try
end idle
on quit
set targetProcess to {}
set targetProcess to FindProcessDataList(myProcessDataList, "WebProcess", targetProcess)
set targetProcess to FindProcessDataList(myProcessDataList, "Firefox", targetProcess)
if length of targetProcess is not equal to 0 then
StopBackgroundCpuControl(targetProcess)
set myProcessDataList to {}
end if
syslog("appnap-browser closed.") of me
continue quit
end quit
on syslog(logmsg)
do shell script "logger -t appnap-browser -i " & quoted form of logmsg
end syslog
終了方法
起動するとdockにappnap-browserアイコンが存在しています。
appnap-browserアイコンを選択後、
メニューから終了を選んでください。
(appnap-browser -> appnap-browserを終了)
コメントシステムを利用したくない方は お問い合わせ からお願いします。
2013.8.19 DISQUS(外部コメントサービス)の利用を開始しました。
Facebook, google, Twitter等のアカウントで投稿可能です。