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秒分の履歴が取れる事になります。
関連記事
コメントを残す