故障予防・熱対策の最新記事

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

これ以外に、いくつか事象・現象が発生していました。
  • /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を終了)

 

 

AppNapライクにSafari,Firefoxをコントロール(cputhrottle & applescript)v3.0
サブコンテンツ

コメント

comments powered by Disqus

2018.12.15 macyarounanoka(管理者)のメールアドレスを失って、disqusにログインできなくなっていました。 そのためmacyarounanoka-2で返信するように変わっています。 エキサイトのフリーメールアドレス使っていたことに気がつけませんでした。 ちょっとやってしまいました感がありますOrz。 記事へのコメントはいままで通りdisqusでお願いします。 個別のお問い合わせはお問い合わせからお願いします。
2013.8.19 DISQUS(外部コメントサービス)の利用を開始しました。
Facebook, google, Twitter等のアカウントで投稿可能です。


↓↓Office365 Soloは年間契約がお得です↓↓
Microsoft Public Affiliate Program (JP)

  • 祝!初マック(mac book retina 13インチ)!retina美しいです^^マックに関係するTips、情報、はまったことの解決策等
  • Mac野郎なのか
  • プロフィール

このページの先頭へ

×

この広告は30日以上新しい記事の更新がないブログに表示されております。