[C#]パフォーマンスカウンタから取得した値の履歴を,一定件数覚えておく

Windowsに標準で搭載されているコントロールパネルやパフォーマンスモニタでは、PCの現在の状態を表示しつつ、グラフで一定時間(直近30sec分など)の履歴を表示しているものがあります。
このような表示方法だと、現在の状況を確認しつつデータが増加・減少傾向のどちらにあるのかの、トレンドも同時に把握する事ができるので便利です。


[コントロールパネルによるCPU負荷履歴の表示]


今回は、パフォーマンスカウンタから値を取得し、その履歴を一定件数覚えておく処理を作成します。

以下が、今回のサンプルコードです。

// 取得データの履歴
const int MAX_HISTORY  = 40;
Queue<int> countHistory = new Queue<int>();
 
// CPU使用率の取得用カウンタ
PerformanceCounter pc = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
 
 
//***************************************************************************
/// <summary>   タイマー処理
///             CPU負荷を一定周期で取得する
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//***************************************************************************
private void timer1_Tick( object sender, EventArgs e ) {
 
    //---------------------------------
    // CPUの使用率を取得し、履歴に登録
    //---------------------------------
    int value = (int)pc.NextValue();
    countHistory.Enqueue( value );
 
    //------------------------------------------------
    // 履歴の最大数を超えていたら、古いものを削除する
    //------------------------------------------------
    while ( countHistory.Count > MAX_HISTORY ) {
        countHistory.Dequeue();
    }
 
    //------------------------------------------------
    // グラフを再描画する
    //------------------------------------------------
    showChart( chart2 );
}





それでは、サンプルのコードを順に確認していきます。


まずは、履歴を覚えておく領域の確保です。

const int MAX_HISTORY  = 40;
Queue<int> countHistory = new Queue<int>();



一定のデータを覚えておくために、System.CollectionsパッケージにあるQueueクラスを利用します。
Queueは、最新のデータをEnqueue()で登録しておき、一方で最も古いデータをDequeue()するだけで破棄出来るため、今回の目的には最適です。

また、Queueに何件分の履歴を覚えておくかを,MAX_HISTORYの定数に定義しておきます。



次は、パフォーマンスカウンタからの値取得です。

// CPU使用率の取得用カウンタ
PerformanceCounter pc = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);



パフォーマンスカウンタからの値を取得には、System.DiagnosticsパッケージのPerformanceCounterクラスを利用します。
上記の例では、CPUの使用率を取得しています。PerformanceCounterのコンストラクタ引数に何を指定できるかは、perfmon.exeを実行し、カウンターの追加ダイアログを表示する事で簡単に確認できます。


また、今回の例では省略されていますが、PerformanceCounterをnewした際は、使用後にpc.Dispose()をコールして、リソースの開放を行う必要があります。



データの保存先と取得元が確保できたら、次はデータの取得処理です。

private void timer1_Tick( object sender, EventArgs e ) {
 
    //---------------------------------
    // CPUの使用率を取得し、履歴に登録
    //---------------------------------
    int value = (int)pc.NextValue();
    countHistory.Enqueue( value );
 
    //------------------------------------------------
    // 履歴の最大数を超えていたら、古いものを削除する
    //------------------------------------------------
    while ( countHistory.Count > MAX_HISTORY ) {
        countHistory.Dequeue();
    }
}



データの取得には、今回Timerコントロールを使用します。

PerformanceCounterからは短時間でデータ取得が可能なのでTimerで十分ですが、データ取得に時間が掛かる場合(外部デバイスから値を取る等)は、データ取得中に画面を操作する事ができなくなる為、操作性が悪くなってしまいます。このような場合は、BackgroundWorkerコントロールを利用を検討します。



int value = (int)pc.NextValue();


パフォーマンスカウンタからのデータ取得はNextValue()のメソッドをコールするだけです。
NextValue()メソッドの初回の呼び出しでは、必ず0を返す仕様となっているため、このオブジェクトをデータ計測の度にnewしてしまうと期待する値が取得できない事に注意してください。



countHistory.Enqueue( value );


取得した値は、Queue#Enqueue()を利用してキューに追加しておきます。



while ( countHistory.Count > MAX_HISTORY ) {
    countHistory.Dequeue();
}


Enqueueしただけでは、時間と共に履歴情報が膨大になってしまいメモリを消費するので、一定量を超えた分は破棄します。今回のサンプルコードだけを見ると、この処理はwhileではなくifでも十分なように見えますが、プログラムのバグにより、本処理以外で誤って値がEnqueueされてしまった場合でもキューの情報が肥大化しないようにしています。


データの取得をタイマー処理で行い一定件数の履歴を保存しているので、上記例の場合、タイマーを1秒おきに実行すれば直近40秒分の履歴が取れる事になります。

関連記事

コメントを残す

メールアドレスが公開されることはありません。