CCPUUsage

http://toshi.my.land.to/table/ccpuusage/
* トップ ページ - プログラムのテーブル - CCPUUsage :: 概要 / コード / メソッド / 解説

概要

CPU 使用率を取得するクラスです。
Windows 2000 / XP / Vista でのみ動作します。

コード

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
Declare Function NtQuerySystemInformation Lib "ntdll.dll" (dwInfoType As DWord,ByRef lpStructure As SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION,dwSize As DWord,dwReserved As DWord) As DWord

Type SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION

    IdleTime As Int64
    KernelTime As Int64
    UserTime As Int64
    Reserved1[ELM(2)] As Int64
    Reserved2 As DWord

End Type

Const GetReverseFlag(Flag)=1-Flag

Class CCPUUsage

Private

    SPPI[ELM(2)] As SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
    SPPIFlag As Long

    Sub GetSPPI()
        NtQuerySystemInformation(8,SPPI[SPPIFlag],Len(SPPI[SPPIFlag]),NULL)
    End Sub

    Sub TurnFlag(ByRef Flag As Long)
        Flag=1-Flag
    End Sub

    Sub CalculateTime(SystemTime As *Int64,IdleTime As *Int64,KernelTime As *Int64)
        GetSPPI()

        If SystemTime Then
            SetQWord(SystemTime,(SPPI[SPPIFlag].UserTime   - SPPI[GetReverseFlag(SPPIFlag)].UserTime)   + _
                                (SPPI[SPPIFlag].KernelTime - SPPI[GetReverseFlag(SPPIFlag)].KernelTime))
        End If

        If IdleTime Then
            SetQWord(IdleTime,SPPI[        SPPIFlag        ].IdleTime - _
                              SPPI[GetReverseFlag(SPPIFlag)].IdleTime)
        End If

        If KernelTime Then
            SetQWord(KernelTime,SPPI[        SPPIFlag        ].KernelTime - _
                                SPPI[GetReverseFlag(SPPIFlag)].KernelTime)
        End If

        TurnFlag(SPPIFlag)
    End Sub

Public

    Sub CCPUUsage()
        GetSPPI()
        TurnFlag(SPPIFlag)
    End Sub

    Function Get() As DWord
        Dim SystemTime As Int64
        Dim IdleTime As Int64

        CalculateTime(VarPtr(SystemTime),VarPtr(IdleTime),NULL)

        Return (SystemTime-IdleTime)/SystemTime*100
    End Function

    Function Get(KernelUsage As *DWord) As DWord
        Dim SystemTime As Int64
        Dim IdleTime As Int64
        Dim KernelTime As Int64

        CalculateTime(VarPtr(SystemTime),VarPtr(IdleTime),VarPtr(KernelTime))
        SetDWord(KernelUsage,(KernelTime-IdleTime)/SystemTime*100)

        Return (SystemTime-IdleTime)/SystemTime*100
    End Function

End Class

メソッド

Get
現在の CPU 使用率を返します。

引数

引数はありません。

戻り値

現在の CPU 使用率が DWord 型で返ります。

Get
現在の CPU 使用率およびカーネル モードの CPU 使用率を返します。

引数

KernelUsage As *DWord
カーネル モードの CPU 使用率を格納する DWord 型変数へのポインタを指定します。

戻り値

現在の CPU 使用率が DWord 型で返ります。

解説

Windows 2000 / XP / Vista にのみ存在する NtQuerySystemInformation API を使用しています。
この API は様々なシステム情報を返してくれるものであり、
ここではその中の「CPU に関する情報」を利用することになります。
API の第 1 引数には、本来はどんなシステム情報を取得するのかが定義された定数を渡すところですが、
面倒なので直接数値を渡しています。
(この API は将来変更される可能性があるということなので、
このクラスはいずれ使えなくなるかもしれませんがご了承ください)

これにより、ユーザー時間・カーネル時間・アイドル時間を取得することが出来ます。
これらは時間が経つごとにどんどん蓄積されていきます。なので、
時間を空け、同じようにもう一度 API を呼び出して値を取得して、
そこで取得した値最初に呼んだときに取得した値との差を取ると、
最初に呼んだときもう一度呼んだときの間の時間において、
ユーザー時間・カーネル時間・アイドル時間がどのくらい増えたかを割り出すことが出来ます。
分かりにくいですね。。。

ユーザー時間・カーネル時間・アイドル時間とは、
それぞれ CPU が
・ユーザー モードで動作した時間
・カーネル モードで動作した時間
・アイドルになっていた時間
のことを指します。
そして、ユーザー時間とカーネル時間の和がシステム時間
CPU が動作した時間の総合計です。
単位はいずれも 100 ナノ秒です。
1000 ナノ秒は 1 マイクロ秒、1000 マイクロ秒は 1 ミリ秒、1000 ミリ秒は 1 秒なので、
1 秒の間を空けて NtQuerySystemInformation API を呼んだとすると、
その差を取ることによって割り出されるシステム時間は 10000000 に近い値となるはずです。

上述のように、CPU 使用率を取得するためには NtQuerySystemInformation API を
複数回呼ばなければならないため、コンストラクタで既に呼ぶようにしています。
TurnFlag メソッドはフラグを反転するものです。
複数個の SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 構造体を切り替えて
値を取得する必要があるので、フラグを使用しています。
そして CalculateTime メソッドで差を取り、システム時間を求めて、次の式に当てはめます。

CPU 使用率=(システム時間−アイドル時間)÷システム時間×100

システム時間からアイドル時間を引いた時間が「CPU が働いた時間(CPU 時間)」なので、
それがシステム時間に対してどのくらいの割合なのかを求め、
百分率で表現するために 100 を掛けます。

ここで、書いている私も訳が分からなくなりそうなので、図を使います。
時間
アイドル時間はカーネル モードなので、カーネル時間に含まれます。
その残りはカーネル モードで Windows が何らかの処理を行った時間となります。
タスク マネージャで表示出来るカーネル時間は、実際にはこの残りの時間のことです。
この時間とユーザー時間の和が CPU 時間というわけです。ややこしいですね......。
2 番目の Get メソッドでは、このカーネル時間の CPU 使用率も求めています。
行っている処理と上図を見比べれば、どんなことをしているか分かると思います。

補足。
デュアル プロセッサ環境やデュアル コア プロセッサ環境には対応していません。
というのも、SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 構造体は、
搭載されている CPU の数(コアの数)だけ必要になってくるからです。
つまり CPU 使用率をそれぞれ毎に取得することが出来ます。
改良によってこれに対応させることも可能です。
私はそういった環境が無い為動作確認を行えませんので、是非やってみてください。

ページの先頭へ戻る
プログラムのテーブルへ戻る
トップ ページへ戻る

* トップ ページ - プログラムのテーブル - CCPUUsage :: 概要 / コード / メソッド / 解説
http://toshi.my.land.to/table/ccpuusage/
(C) 2005 - 2010 Toshi, All Rights Reserved.