Emit 〜命がけの旅〜

うちのネットワークでは,ファイルサーバとメールサーバ兼用のサーバ機が1台稼働しています.24時間稼働させるため,普段生活するスペースに置いておくと何となく音が気になります.そこで追いやられた先は物置同然に使われている部屋の片隅でした.空調もない過酷な環境で,彼は今日も黙々と働いています.
最近暑い日が続いています.今日はふと気になって,サーバの各種温度をモニタリングしてみました.インターネット上で公開されている温度モニターソフトをいくつか試してみたところ,CPU温度もさることながらケース内温度が50度近くの値を示しています.応急処置としてケースの蓋を取って扇風機を貼り付けておきました.
このサーバ,ミスキャストも甚だしいことにPentium 4の3.06GHzを使っています.FSB533MHzのシリーズでHyperThreadingをサポートしているのがこのクロックだけだったので仕方なくこうなりました.並列プログラミングや非同期処理は最近興味があるところで,テスト環境を増やしておきたいという思惑があったのですが,テスト環境はデスクトップPCに任せてサーバは信頼性に重きを置いた方が良かったかと今更ながらに後悔気味です.
さて,Windowsのタスクマネージャが表示するCPU使用率は,マルチプロセッサ環境では各(論理)CPU使用率の平均になります.シングルプロセッサ環境からマルチプロセッサ環境になることで,CPU使用率という指標に現実と乖離した側面が色々見えてきます.一例として,HyperThreading環境では論理CPU間のパフォーマンスに強い相関が発生するため,CPUごとの使用率が独立なパラメータと考えることも難しくなるといったことが挙げられます.
まあいずれにせよ,事件はクーラーの効いた快適なサーバルームではなく,うちの殺人的暑さの密室で起きているわけです.ここではタスクマネージャに見られるCPU使用率ではなく,CPUのコア温度そのものに注目してみましょう.
プログラムを2つ用意します.いずれも単純なウェイトループでCPUリソースを消費しています.これらを上からプログラムA,Bとして,まずAを2つ同時に実行しCPU温度の変化を測定し,次にBを2つ同時に実行しCPU温度の変化を測定しました.

using System;

class A
{
    static void Main(string[] args)
    {
        while( true )
        {
            for( int i =0; i < 1024*1024; ++i )
            {
                ;
            }
        }
    }
}
using System;
using System.Threading;

class B
{
    static void Main(string[] args)
    {
        while( true )
        {
            Thread.SpinWait( 1024*1024 );
        }
    }
}

結果は以下の通りです.

プログラムA
プログラムB

横軸は時間で縦軸は温度です.横軸の縮尺はほぼ同じにしてあります.プログラムBで使っているThread.SpinWaitメソッドですが,今回は内部でIntel x86系で言うところのPAUSE命令(REP NOP)が呼び出されると期待しています.PAUSE命令はHyperThreading環境で論理CPUにWaitを入れる時に推奨されている命令です.
http://www.atmarkit.co.jp/fsys/kaisetsu/013ht_pentium4/ht_pentium402.html
プログラム実行中は,プログラムAもBもタスクマネージャのCPU使用率は100%に張り付きます.しかしグラフのようにCPU温度は異なります.個人的にはPAUSE命令はもうちょっと(熱的に)軽いかと予想していたのですが,それなりに熱は発生するようでした.ちなみにプログラムAは最終的に70℃付近までCPUコア温度が上昇していますが,これはIntelの保証範囲ぎりぎりの値です.単純なforループを行っただけでこれですから,SSE2などで構成されたループだとさらに発熱量が増えるかもしれません.全力で空ループを回しても数分しか持たないこのサーバ,やはり色々考え直さないといけないようでした.