Chienomi

お手軽CPU Governor切り替え

開発::util

今でもThinkPad X1 Carbon Gen5が最高の記事を書いているときに思ったのだけど、最近のラップトップはpowersave governorとperformanceもしくはschedutil governorの性能差がすごく激しくなってきていて、もっと手軽に切り替えられないとその性能を活かせないなと思った。

別にZshの履歴からサクッと切り替えられはするのだけど、より簡単にしないと切り替えないので、より簡単にすることを目指したのがCPU Governor Controller

最初

めちゃくちゃ雑に書いた。

#!/bin/bash

MENU_COMMAND='Performace!gksu cpupower frequency-set -g performance |Powersave!gksu cpupower frequency-set -g powersave'

show_current() {
  notify-send $(cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor)
}
export -f show_current
show_current

yad --notification --image="cpu" --menu="$MENU_COMMAND" --command="bash -c show_current"

一応動く。

yadのトレイから右クリックでメニューが出て、そこから変更できる。

クリーンアップ

#!/bin/zsh

SUDO_COMMAND=pkexec
#SUDO_COMMAND=gksu
#SUDO_COMMAND=kdesu

avilable_governors=($(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors))
#avilable_governors=(powersave performance)
#avilable_governors=(powersave schedutil performance)

governors=()
for i in $avilable_governors
do
  governors+=("$i"'!'"$SUDO_COMMAND"' cpupower frequency-set -g '"$i")
done
MENU_COMMAND="${(j:|:)governors}"

yad --notification --image="cpu" --menu="$MENU_COMMAND" --command="zsh -c 'notify-send \$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)'"

きれいに書き直した。

でもなぜか、Cinnamonの自動起動からだとpkexecが起動しない。 そこで、単純なコマンドをピン留めする作戦に切り替えた。

ランチャーコマンド

#!/bin/zsh

SUDO_COMMAND=pkexec
#SUDO_COMMAND=gksu
#SUDO_COMMAND=kdesu
#SUDO_COMMAND=sudo

avilable_governors=($(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors))
#avilable_governors=(powersave performance)
#avilable_governors=(powersave schedutil performance)

gov=$(yad --title="CPU Govornor Controller" --window-icon=cpu --width=300 --height=500 --text="current governor is [$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)]" --list --column=governor $avilable_governors)

if (( ? == 0 ))
then
  $SUDO_COMMAND cpupower frequency-set -g ${gov%%|*}
fi

しかし、Cinnamonは.desktopファイルがないとピン留めできないようだ。 というか、ランチャーどこいったの?

あと、別に使いやすくない。 アプリ起動してメニューから選ぶの、履歴から打つよりむしろ手間。

コマンド一発でいいのでは?

というか、短いコマンドで打てるようにすれば良いだけではないだろうか。 例えば

sudo cpupower frequency-set -g powersave

cpu up

になればそれで良いのでは?

特にAlt+F2から打てればより簡単になる。 ついでにめんどいポイントとしてパスワード入力があるけど、sudoers

harukamy ALL=(ALL:ALL) NOPASSWD: /usr/bin/cpupower

とか書いておけば良いではある。 ちなみに、

%wheel ALL=(ALL:ALL) NOPASSWD: /usr/bin/cpupower

/etc/sudoersに書くと、Manjaroでは/etc/sudoers.d/10-installerで上書きされてしまうので注意が必要。

ただ、さすがにそれは微妙かもしれないと思って、ちょっと書く。

cpuコマンド

#!/bin/zsh

SUDO_COMMAND=pkexec
#SUDO_COMMAND=gksu
#SUDO_COMMAND=kdesu
#SUDO_COMMAND=sudo

if [[ -n $1 ]]
then
  case "$1" in
    high|power)
      $SUDO_COMMAND cpupower frequency-set -g performance
      ;;
    up)
      if grep -qF schedutil /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
      then
        $SUDO_COMMAND cpupower frequency-set -g schedutil
      else
        $SUDO_COMMAND cpupower frequency-set -g performance
      fi
      ;;
    down)
      $SUDO_COMMAND cpupower frequency-set -g powersave
      ;;
    *)
      notify-send -i cpu -a "CPU Governor Controller" -t 3 -u low -e $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
      ;;
  esac
else
  avilable_governors=($(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors))
  #avilable_governors=(powersave performance)
  #avilable_governors=(powersave schedutil performance)

  gov=$(yad --title="CPU Govornor Controller" --window-icon=cpu --width=300 --height=500 --text="current governor is [$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)]" --list --column=governor $avilable_governors)

  if (( ? == 0 ))
  then
    $SUDO_COMMAND cpupower frequency-set -g ${gov%%|*}
  fi
fi

upschedutilまたはperformance(schedutilがあるかどうか確認している)、highまたはpowerperformanceは打ちやすさとわかりやすさから悪くないと思う。

引数なしで前のやつみたいにyadのダイアログで選択、showとか打てば現在のgovernorが確認できる。

cpu-governor-controller-tray.zsh

cpuのほうはコマンド打ちするから短いけど、こっちは長い名前。

#!/bin/zsh

CHECK_INTERVAL=20

typeset -A icons=(
  performance face-devilish
  schedutil face-in-love
  ondemand face-in-love
  conservative face-quiet
  powersave face-sleeping
  userspace face-cool
)

(while sleep $CHECK_INTERVAL
do
  gov=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
  print "icon:${icons[$gov]}"
  print "tooltip:$gov"
done) | yad --notification --image="${icons[$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)]}" --listen

本当はsystrayに文字を表示したかったのだけど、色々調べたけど良い方法が見つからず、Yadでアイコンを使う方式にした。 intervalごとにgovernorをチェックし、アイコンを更新する。

問題は、アイコンに何があるかはシステムに何を入れているかに依存するということ。 この例ではEmoteしか入っていないが、最新版では色々コメントアウトしていて、Progressがデフォルト。

さらに、最新版は右クリックメニューからcpuコマンドを呼んだり、クリックでnotify-sendしたりの全部入り。