ここで紹介するサンプルコードは、一部OSでしか動作しません。 一応、CPU使用率測定のサンプルはWindows 2000またはWindows XP、及びその双方で動作することをを確認し、Windows Meでは動作しないことをしました。
System.Diagnostics名前空間にあるPerformanceCounterクラスを使用すると、システムパフォーマンスに関する様々な情報を測定することができます。 まずは、その使用方法の説明を兼ねてCPU使用率の測定をしてみようと思います。 次のコードはそれを行うものです。
Option Strict On Module PerformanceCounter Sub Main() ' PerformanceCounterクラスのインスタンスを作成 Dim pc As New System.Diagnostics.PerformanceCounter() ' プロパティを設定 With pc .CategoryName = "Processor" .CounterName = "% Processor Time" .InstanceName = "_Total" End With ' 1秒おきに測定 Do ' 得られた値を百分率にする Dim value As Single = pc.NextValue() / 100.0F ' 表示 Console.WriteLine("{0:P2}", value) System.Threading.Thread.Sleep(1000) Loop End Sub End Module
0.00% 59.63% 23.76% 28.00% 26.00% 31.00% 33.00% 19.61% 23.00% 26.00% 29.00% 26.00% 21.00% 19.00% 41.90% 47.00% 45.00%
このコードは無限にループを繰り返すので、手動で停止してください。 この結果だけでは本当に測定できているかわからないので、実際にご自分のマシン上でこのコードを実行し、出力される値とシステムモニタで示される値とを比較すると良いかと思います。
ソースコードの簡単な説明をすると、まず8行目でPerformanceCounterクラスのインスタンスを作成します。 続いて、いくつかのプロパティ、つまりCategoryName、CounterName、InstanceNameを指定します。 これらを簡単に説明すると、 CategoryNameにはCPU、メモリ、プロセスなどを指定し、CounterNameにはカテゴリで指定したものに対して計測する量を指定し、 InstanceNameにはカテゴリがインスタンスに分割されている場合に指定します。
今回の場合は、計測する対象が「Processor(CPU)」、計測する値が「% Processor Time(プロセッサ時間[%])」、計測する対象のインスタンスは「Total(合計)」になります。 もしCPUを複数搭載したPC上で起動した場合、InstanceNameにCPUのインデックス、つまり"0"や"1"などを指定すれば、CPU毎の使用率を取得することもできます。
NextValue()メソッドが実際に計測値を取得するメソッドですが、この結果で一番はじめの計測値が「0.00%」になっているのは、NextValue()メソッドが「現在の値と以前の値の差を計測間隔時間で割ったもの」を算出結果として返すためです。 バグでは無いので注意してください。
先ほどのコードでは直接CPU使用率を測定していましたが、アイドル時間(CPU非使用率)から逆算することができるので、次のコードでそれをやってみます。 比較のためにCPU使用率を直接取得した場合の結果も併記してみます。
Option Strict On Module PerformanceCounter Sub Main() ' PerformanceCounterクラスのインスタンスを作成 Dim pc1 As New System.Diagnostics.PerformanceCounter() Dim pc2 As New System.Diagnostics.PerformanceCounter() ' プロパティを設定 With pc1 .CategoryName = "Processor" .CounterName = "% Processor Time" .InstanceName = "_Total" End With With pc2 .CategoryName = "Processor" .CounterName = "% Idle Time" .InstanceName = "_Total" End With ' 1秒おきに測定 Do ' 得られた値を百分率にする Dim value1 As Single = pc1.NextValue() / 100.0F Dim value2 As Single = pc2.NextValue() / 100.0F ' 使用率[%] = 1.0 - 非使用率[%] value2 = 1.0F - value2 ' 表示 Console.WriteLine("{0:P2}, {1:P2}", value1, value2) System.Threading.Thread.Sleep(1000) Loop End Sub End Module
0.00%, 100.00% 54.13%, 52.38% 22.77%, 22.77% 19.00%, 19.00% 19.00%, 19.00% 23.00%, 23.00% 28.00%, 28.00% 26.00%, 26.00% 25.00%, 25.00% 19.00%, 19.00% 24.00%, 24.00% 38.00%, 38.00% 48.04%, 48.04% 37.00%, 37.00% 23.00%, 23.00% 28.00%, 28.71% 23.00%, 23.00% 31.68%, 31.00%
ソースコードはPerformanceCounterのインスタンスを一つ増やしたことと、1(全体)からアイドル時間を引けば使用率になることをのぞけばすべて前のコードと一緒なので大丈夫かと思います。 実行結果で最初だけ100%になるのは先ほど説明したことが原因であるので、これも説明は省略します。
CounterNameプロパティに「User(ユーザー)」を指定することで、ユーザー自身が実際に使用している分のCPUの使用率を取得できます。
Option Strict On Module PerformanceCounter Sub Main() ' PerformanceCounterクラスのインスタンスを作成 Dim pc1 As New System.Diagnostics.PerformanceCounter() Dim pc2 As New System.Diagnostics.PerformanceCounter() ' プロパティを設定 With pc1 .CategoryName = "Processor" .CounterName = "% Processor Time" .InstanceName = "0" End With With pc2 .CategoryName = "Processor" .CounterName = "% User Time" .InstanceName = "0" End With ' 1秒おきに測定 Do ' 得られた値を百分率にする Dim value1 As Single = pc1.NextValue() / 100.0F Dim value2 As Single = pc2.NextValue() / 100.0F ' 表示 Console.WriteLine("{0:P2}, {1:P2}", value1, value2) System.Threading.Thread.Sleep(1000) Loop End Sub End Module
0.00%, 0.00% 19.42%, 10.58% 21.78%, 12.00% 21.00%, 12.00% 26.00%, 16.00% 31.00%, 24.00% 28.00%, 17.00% 24.00%, 14.00% 30.00%, 16.83% 59.41%, 33.00% 47.57%, 25.96% 44.55%, 19.00% 23.00%, 15.00% 24.00%, 13.00% 24.00%, 13.86% 48.51%, 29.63% 43.12%, 26.47% 28.71%, 14.00%
左が合計の使用率、右がユーザーの使用率です。
CategoryName、CounterName、InstanceNameに適当な値を指定することで、様々な値を取得できるので、CPU使用率以外の値も計測することができます。 次のコードは、ハンドル、スレッド、プロセスの各合計値を取得するものです。 今回はプロパティではなくコンストラクタでカテゴリ等をしています。 コンストラクタで指定する場合は、左のパラメータから「カテゴリ」、「計測量」、「インスタンス」の順で指定していきます。
Option Strict On Module PerformanceCounter Sub Main() ' PerformanceCounterクラス Dim handle As System.Diagnostics.PerformanceCounter Dim threads As System.Diagnostics.PerformanceCounter Dim processes As System.Diagnostics.PerformanceCounter ' インスタンスを作成 handle = New System.Diagnostics.PerformanceCounter("Process", "Handle Count", "_Total") threads = New System.Diagnostics.PerformanceCounter("System", "Threads", "") processes = New System.Diagnostics.PerformanceCounter("System", "Processes", "") ' 項目名を表示 Console.WriteLine("ハンドル スレッド プロセス") ' 1秒おきに測定 Do Dim h As Integer = CInt(handle.NextValue()) Dim th As Integer = CInt(threads.NextValue()) Dim p As Integer = CInt(processes.NextValue()) ' 表示 Console.WriteLine(" {0:D5} {1:D3} {2:D3}", h, th, p) System.Threading.Thread.Sleep(1000) Loop End Sub End Module
ハンドル スレッド プロセス 09911 498 044 09938 500 045 09980 499 045 10028 500 046 10041 499 046 09924 498 045 09928 498 045 09929 497 044 09947 498 045 09899 497 044 09903 497 044 09907 497 044 09911 497 044 09915 497 044 09919 497 044
これらの値は「Windwosタスクマネージャ」で確認することができます。 実行結果と同じになるかを確認してみると良いでしょう。 さらにこのほかの値を取得する方法については次で説明します。
PerformanceCounterはフォームデザイナからも配置できます。 配置する場合は、ツールボックスの「コンポーネント」から「PerformanceCounter」を選択し、フォーム上の適当な場所に配置します。 PerformanceCounterはGUIを持たないので、配置してもフォーム上には現れません。
次に、CategoryName、CounterName等のプロパティ値を指定します。 まず、カテゴリの一覧から適切なものをクリックすると、そのカテゴリに含まれる計測値がCounterNameの一覧として表示されます。 この中から計測したい値を選択します。
これで計測を行う準備は整いました。 当然、カテゴリ、カウンタ名によってはインスタンスも指定する必要があるので忘れずに指定してください。 プロパティ設定が終わったら、後は適宜NextValue()メソッドを呼び出して値を取得するだけです。
それでは早速サンプルを作ってみることにします。 次のコードでは一定間隔おきにフォーム上のラベルにCPU使用率を表示しています。 performanceCounterはPerformanceCounter型の変数で、CategoryNameには「Processor」、 CounterNameには「% Processor Time」、InstanceNameには「_Total」を指定しています。
Option Strict On Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows フォーム デザイナで生成されたコード " #End Region Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim timer As New Timer() timer.Interval = 1000 AddHandler timer.Tick, AddressOf timer_Tick timer.Start() End Sub Private Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs) Dim value As Double = performanceCounter.NextValue / 100.0F labelPerformance.Text = "CPU使用率(合計): " + value.ToString("P2") End Sub End Class
なお、CategoryNameプロパティの選択項目を見ているとわかると思いますが、.NET Frameworkの言語共通ランタイム(CLR)のパフォーマンスも取得できることがわかると思います。