試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

cpufreqd 2.2系向けのプロファイル手動切り替えスクリプト

  1. スクリプト
  2. 出力形式の変更部分について
  3. SMP,SMTについて
    1. 挙動についての疑問
    2. 仕様

cpufreqd 2.2系のcpufreqd-getコマンドが出力するプロファイルリストの形式が微妙に変化していることが分かったので、これに対応したプロファイル手動切り替えスクリプトを作成した。cpufreqd 2.1系では使えないので注意。

スクリプト

[任意]ファイル名: ~/bin/cpufreqd-set-2.2.1-zenity.pl

#! /usr/bin/perl -w

use strict;

my @PROFILE = ();
my $CNT = 1;
my $ACTIVE = -1;
my $CMDLINE = "";
my $OUTPUT = -1;

# cpufreqd-getの出力を1行ずつ解析
open IN, "cpufreqd-get |";
while (<IN>)
{
  if (/^Name \(#([0-9]+)\):\t(.+)/)  # Name行
  {
    my ($no, $name) = ($1, $2);
    $PROFILE[$CNT][0] = $name;
    if (<IN> =~ /^Active/)  # Active行
    {
      $ACTIVE = $no;  # 現在アクティブなプロファイル番号
      <IN>;  # 次の(Governor)行を読む
    }
    if (/\t([a-z]+)/)  # Governor行($_には上のifで既に値が入っている)
    {
      $PROFILE[$CNT][1] = $1;
      if (<IN> =~ /([0-9]+)000$/)  # Min Freq行
      {
        $PROFILE[$CNT][2] = $1;
        if (<IN> =~ /([0-9]+)000$/)  # Max Freq行
        {
          $PROFILE[$CNT][3] = $1;
        }  # if (<IN> =~ /([0-9]+)000$/)
      }  # if (<IN> =~ /([0-9]+)000$/)
    }  # if (/\t([a-z]+)/)
    $CNT++;
  }  # if (/^Name \(#([0-9]+)\):\t(.+)/)
}  # while (<IN>)
close IN;

# アクティブなプロファイルが見つからないとエラーにする
if ($ACTIVE == -1)
{
  system "zenity --error --title 'エラー' --text 'アクティブなプロファイルが見つかりません\ncpufreqdの<span underline=\"double\">バージョン</span>、<span underline=\"double\">動作状態</span>、<span underline=\"double\">設定</span>を確認してください\n\nこのスクリプトは、cpufreqd <span foreground=\"darkred\" size=\"x-large\" weight=\"bold\">2.2.1</span>向けに書かれています'";
  exit 1;
}

# zenityのコマンド行を作る
$CMDLINE="zenity --list --title 'cpufreqdプロファイルの手動選択' --text 'プロファイルを選択してください' --width 500 --height 350  --radiolist --hide-column 2 --column '選択' --column dummy --column 'プロファイル名' --column 'Governor' --column '最低クロック' --column '最高クロック' false 'dynamic' 'ダイナミックモード' '動的に切り替え' '動的に切り替え' '動的に切り替え'";
for (my $i = 1; $i < $CNT; $i++)
{
  $CMDLINE = sprintf "%s '%s' '%s' '%s' '%s' '%s' '%s'",
                     $CMDLINE,
                     ($i == $ACTIVE) ? "true" : "false", $i,
                     $PROFILE[$i][0],
                     $PROFILE[$i][1],
                     $PROFILE[$i][2],
                     $PROFILE[$i][3];
}

# zenityを実行し、出力を取り出す
$OUTPUT = `$CMDLINE`;
if ($?) { exit 1; }  # キャンセルされた場合は終了

# dynamicモードに戻す場合以外は、一度manualモードを指定しておく必要がある
if ($OUTPUT ne "dynamic\n") { system "cpufreqd-set manual"; }

# 指定されたプロファイル(もしくはダイナミックモード)に切り替え
system sprintf "cpufreqd-set %s", $OUTPUT;

## [EOF] ##

出力形式の変更部分について

2.1系のcpufreqd-getの出力では、

  • Name行のプロファイル名の後ろに半角スペースが1文字入り、アクティブなプロファイルの場合に「*」が追加される(下の例では、#4のName行の最後にも半角スペースがある)
  • Active行は存在しない
Name (#3):	ondemand high *
Governor:	ondemand
Min freq:	1000000
Max freq:	2200000

Name (#4):	powersave low 
Governor:	powersave
Min freq:	1000000
Max freq:	1000000

となっていて、2.2系の場合は、

  • Name行の最後に半角スペースは無い
  • 「*」の代わりにActive行が入る
Name (#3):	ondemand high
Active on CPU#:	0
Governor:	ondemand
Min freq:	1000000
Max freq:	2200000

Name (#4):	powersave low
Governor:	powersave
Min freq:	1000000
Max freq:	1000000

というようになっている。

SMP,SMTについて

挙動についての疑問

Active on CPU#:	0

という表示があることからも分かるのだが、cpufreqd 2.2系ではSMP,SMTに対応しているようで、バージョン2.2.0のリリース時のコメントにも
[引用]cpufreqd本家サイトのコメントより

The most important improvement is complete SMP/SMT awareness: you can poll cpu usage indipendently (or mixed/average/whatever) and set different profiles for each available cpu. Support is still somewhat experimental as I don't own and SMP/SMT system but some gentle user comfirmed it's working on a 4 way AMD.

となっている。しかし、手元にはSMP環境もSMT環境もなく、マニュアルモードにしたときに全てのCPU(として認識されるもの)に対して同一のプロファイルが適用されるものなのかどうかを確かめることができない。cpufreqd-setの書式*1から察するに、CPUごとの手動設定はできなそうではあるが...
[引用]cpufreqd本家サイトのコメントより

and (you can) set different profiles for each available cpu.

とあるので、ダイナミックモードにおいては、CPUごとにプロファイルが自動的に決定されて動作するのだとは思うが、いずれにせよ確認ができない。

仕様
仮に、「cpufreqd-setでマニュアルモードにしたときには、全CPUに対して同じプロファイルを指定する」ものだとすると、cpufreqd-setで指定する部分に関しては、zenityから受け取った(1つの)値を使って、これまでどおりプロファイル番号を渡せばよいのだが、cpufreqd-getを実行してプロファイルのリストを処理する際、SMP/SMT環境の場合に

Name (#3):	ondemand high
Active on CPU#:	0
...

Name (#4):	powersave low
Active on CPU#:	1
...

のような出力がされるのであれば、現在のスクリプトでは、アクティブなプロファイルの内、最後に見つかったものが選択された状態でダイアログが開くことになるが、これは仕様。チェックリスト形式でアクティブなプロファイル全てを選択するという方法もあるが、ユーザが複数のチェックを入れた状態で決定すれば、当然複数の値が入ってきてしまい、その中からどれかを自動的に選ぶ必要が出るので難しい。

*1:cpufreqd-set [manual もしくは dynamic もしくは プロファイル番号]