Dynamic Tick Timer

dyn-tick(Linux用Dynamic Tick Timer)は、HZを動的に変化させるものである。dyn-tickを使用すると、負荷がある間はフルのHZでシステムは動作する。 そしてアイドル時に可能であればTickをスキップする。

これは長いアイドル時に、さらなる省電力機構を実現できる。PCでは、HZをアイドル時の6Hzと負荷時の1000Hzの間で変化させることができる。dyn-tickは元々、TIのOMAP ARMアーキテクチャ用に実装され、2004年10月以来ずっと、OMAP用のlinux-omapツリーで使用されている。dyn-tickは早くから、Linux高解像度タイマ・プロジェクトの2.4のVSTパッチのほとんどと、2.6のs390 NO_IDLE_HZパッチという、同様な実装をベースにしている。

今回は、最近何回かLKMLでアナウンスされている、このdyn-tick(Dynamic Tick Timer)について取り上げる。

Dynamic tick for x86 version 050602-1

dyn-tickを開発しているTony Lindgrenは、今年の1月から、たびたびdyn-tickに関するパッチをLKML(Linux Kernel Mailing List)に投稿していた。6月1日には、「[PATCH] Dynamic tick for x86 version 050602-1」というタイトルでポストした。

やあ皆さん、これは最新バージョンのDynamic Tickのパッチである。これはほとんど今までを一掃して書き直し、 John Stultzに指摘されたように、標準のmonotonic_clock()ファンクションを使用している。このパッチに何か問題があれば、知らせて欲しい。

私は、さらにこれの整理を行い続けるつもりだが、基本的な機能の実装は終っていると思う。Thomas、ACPIアイドル・パッチの最新バージョンはどこにあるのだろうか? 私は、dyn-tick(Dynamic Tick)のページにそれも加えたい。

古いパッチといくつかの関連リンクは次にある。

http://muru.com/linux/dyntick/

Zwane Mwaikamboが早速聞いた。

このバージョンでは、様々なtimer sourceに関する「既知の問題」があるのだろうか?

というのは恐らく、1月と4月に公開したバージョンでは様々な問題が報告されていたからだ。これにTonyが答えた。

私が知る限りでは、残っている問題は以下の通りである。

サポートされているタイマは、ACPI PMタイマと、TSCのタイマである。CONFIG_HPETのサポートはまだない。HPETサポートを追加させたい者は誰かいるのだろうか?私は、HPETのマシンは持っていないのだが。

削ったTickのコードでは現在、timer_pm.cとtimer_tsc.cの中の#ifndef CONFIG_NO_IDLE_HZで無効にしてある。これは代わりに、変数ベースで実装されるべきである。

KconfigオプションのDYN_TICK_USE_APICは、それだけがP4ではなくP3で動作するように見えるので、コマンドライン・オプションに変換されるべきである。

したがって実際の所、いくつかの部分については、基本的な機能の実装は終ってないと言おう :) しかしこれらを直すのは、かなり簡単に違いない。

Christian Hesseが聞いた。

テストしようと思ったのだが、いくつかのトラブルがある。パッチはきれいに当たって、コンパイルは全てうまくいったが、リンクで失敗する。

Tonyが答えた。

ヘッダファイルでは、ローカルAPICのないUP(Uni Processor)システムの機能として定義していたのですぐに直そう。次のバージョンを試めすことはできるか?

他にも、Pavel Machekらがコメントした。Pavel Machekは、パッチのマクロの書き方がおかしいと次のように指摘したのだが、Tonyには問題点がわからなかった。

> +#define arch_has_safe_halt() 0
> +#define dyn_tick_reprogram_timer() {}

do {} while (0)
を使わないと、さもなければ(else)どこかで誰かを罠にかけてしまうよ。

これについては、Kyle Moffettが親切に教えてくれた。

#define myfunc1() {}
#define myfunc2() {}
があった場合、

if (a && b) myfunc1();
else myfunc2();

というような記述は次のように変換され、コンパイルエラーとなる。

if (a && b) {};
else {};

暫く経った7日にJonathan Corbetは、コメントした。

再び的外れな指摘かもしれないが、このパッチの塊は、4K stackの場合にうまくいくように見えない。4K stackが使用されている場合、dyn_tick->interrupt()は割込みスタックがすでに使用されているというような、割込みが入れ子の場合にだけ呼ばれるだろう。つまり、__do_IRQ()は同じ割込みのために2度呼ばれるだろうという事だ。

Venkatesh Pallipadiが答えた。

良い指摘だ。これは、確かにバグのように見える。私は050602-1のバージョンで、期待の2倍のtimer_interruptルーチンの呼び出し回数を確認している。全CPUが完全にBUSYの場合、/proc/interruptsに2*HZ回のタイマ割込みが見える。私の修正パッチを載せる。

これにTonyが答えた。

クールだね。私のハードドライブが昨日の朝クラッシュしたので、すぐに答えられなくて申し訳ない。さらに故障したディスクから、データを回復しようとして、予備のコンピュータのマザーボードを飛ばしてしまったし ;) 明日最新のパッチをポストするようにしよう。

version 050609-2

翌日、Tony LindgrenはLKMLに「[PATCH] Dynamic tick for x86 version 050609-2」というタイトルでポストした。

やあ皆さん、たくさんのコメントをありがとう。これは最新バージョンのdyntickのパッチである。前回のパッチからの変更点は以下の通りである。
  • cpu_has_local_apic()のために失敗するためのBernard Blackhamからのパッチ
  • Pavel Machek、 Jonathan Corbet、と Venkatesh Pallipadiによって注意された割込みコードを修正した。
  • Russell Kingに指摘されたARMパッチのような以下のカーネル・コマンドライン・オプションを追加した。

    dyntick=enable

    APICを備えたdyntickで作動するP3システムならば以下も必要だ(P4では不要)

    forceapic

    また、ランタイム中にsysfsでdyntickを可能にすることができる

    # echo 1 > /sys/devices/system/timer/timer0/dyn_tick_state

  • デバッグ・コードは、オプションとして別のパッチに分離したので、以下から入手可能である。
    http://muru.com/linux/dyntick/

version 050610-1

再びTony Lindgrenは、LKMLに「[PATCH] Dynamic tick for x86 version 050610-1」というタイトルでポストした。

これは、より多くの整理をした別バージョンである。
  • タイマ測定をスキップするためのifdefを取り除いた。替わりのdyn_tick_enaled()ベースのスキップを行った。
  • Pavel Machekに指摘された点を修正した。

Hu Gangは、これのPowerPC用のパッチをポストした。

Dynamic Tick Timerを新しいプラットフォームに移植するのは簡単である。
  1. タイマインタフェイスの再プログラムをみつけること
  2. idle functionにフックすること
PowerBookG4で動いている。

それに対して、Benjamin Herrenschmidtが聞いた。

電力消費面での測定可能な得るものがあったのだろうか?私がこの前これをいじった時には、試さなかったが。

PowerPCへの移植について喜んで、Tonyが反応した。

恐らくdyntick単体だけは、省電力のためにはあまり寄与しないだろう。このトリックは、長い休止期間の間に何が切れるかをすべて考えることである。そして、ポーリングを減らすことにより休止期間をより長くしようとすることも可能だ。

Benjaminが答えた。

私は実際のところ、深い居眠りモードからたびたびCPUを呼び覚ますためのコスト回避により、セーブを増加させることを期待していた。

以前の実験はうまくなかったが、どれくらいの時間*実際に*スリープするかについて統計を持っていることは非常に有用だろう。例えば様々なタイミングで呼び起こされるネットワーク・スタックのようなものに、遅いタイマを使用してみてはどうか思っている。

Tonyが答えた。

アイドル時のセーブについてテストする一つの方法は、システムが測定時にアイドル中にとどまるように、一時的にタイマ割込みを無効にすることである。しかしながら、それは他のデバイスを助けない。実装上で最も多く(悪く)ポーリングする何かが、それで現われるのではないかと、私は考えている。たぶん、ポーリングのトップ(polltop)と呼ばれるものだ :)

dyn-tickの実際

Athlon XPのマシンでdyn-tickをカーネル2.6.12-rc6に入れて、実際に試してみたので報告する。

使用したのはhttp://muru.com/linux/dyntick/にある、次のファイルである。

patch-dynamic-tick-2.6.12-rc6-050610-1.gz
patch-dynamic-tick-debug-2.6.12-rc6-050610-1.gz
pmstats-0.2.gz
timetest.gz

デバッグパッチを入れる場合には、まず先にdyn-tick本体のパッチを導入しておく必要がある。カーネルのコンフィグに現われる、

Processor type and featuresのDynamic Tick Timer - Skip timer ticks during idle

を有効にしてコンパイルする必要がある。試してないが、前述のやりとりによればP3環境では「Use APIC timer instead of PIT timer」を有効にする必要があるようだ。

まずdyn-tickを使うには、

# echo 1 > /sys/devices/system/timer/timer0/dyn_tick_state

として、dyn_tickを有効にする必要がある。これは、カーネルのコンフィグのHelpやLKMLの過去ログに書かれているだけで、READMEや使い方に関する情報ページは無い。

pmstatsは、PowerManagimentの状態を定期的に表示するPerlスクリプトだが、get_battery_status();の実行でエラーとなるので、これをコメントアウトして実行した。以下がテスト結果の例である。

Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 742HZ
Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 983HZ
Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 983HZ
Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 325HZ
Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 47HZ
Current: 0mA Voltage: 0.00V Power: 0.00W 0mAh Time: 00:00h Ticks: 42HZ

というように、システムの負荷状況に応じてだいたい1000Hzから40Hzの間で、動的にHZ値を変更しているのを確認した。もしdyn-tickが働いていない場合には、この結果は常時1000HZ前後になる。

timetestは、dyn-tickの実行によってずれるマシンクロックと標準時間とのずれを測るプログラムである。これを試すには、正確で反応が良いNTPサーバを同一セグメント内に用意して利用しないと、何を測っているかわからなくなるだろう。

Looking for host silver and service ntp
host found : silver
 1 Jul 09:53:58 ntpdate[2625]: step time server 192.168.51.19 offset 0.010283 sec
Looking for host silver and service ntp
host found : silver
 1 Jul 09:54:08 ntpdate[2627]: step time server 192.168.51.19 offset 0.009323 sec
Looking for host silver and service ntp
host found : silver
 1 Jul 09:54:18 ntpdate[2629]: step time server 192.168.51.19 offset 0.009485 sec
Looking for host silver and service ntp
host found : silver
 1 Jul 09:54:29 ntpdate[2631]: step time server 192.168.51.19 offset 0.009687 sec