CpuUsage.pas
上传用户:rickyhu
上传日期:2007-05-27
资源大小:842k
文件大小:10k
源码类别:

控制台编程

开发平台:

Delphi

  1. unit CpuUsage;
  2. interface
  3. uses
  4.     Windows, SysUtils;
  5. // Call CollectCpuData to refresh information about Cpu usage
  6. procedure CollectCpuData;
  7. // Call it to obtain the number of Cpu's in the system
  8. function GetCpuCount: Integer;
  9. // Call it to obtain the % of usage for given Cpu
  10. function GetCpuUsage(Index: Integer): Double;
  11. // For Win9x only: call it to stop Cpu usage monitoring and free system resources
  12. procedure ReleaseCpuData;
  13. implementation
  14. {$ifndef ver110}
  15.     {$ifndef ver90}
  16.     {$ifndef ver100}
  17.     {$define UseInt64}
  18.     {$endif}
  19.     {$endif}
  20.     {$ifdef UseInt64}
  21.     type TInt64 = Int64;
  22.     {$else}
  23.     type TInt64 = Comp;
  24.     {$endif}
  25. {$else}
  26.     type TInt64 = TLargeInteger;
  27. {$endif}
  28. type
  29.     PInt64 = ^TInt64;
  30. type
  31.     TPERF_DATA_BLOCK = record
  32.         Signature : array[0..4 - 1] of WCHAR;
  33.         LittleEndian : DWORD;
  34.         Version : DWORD;
  35.         Revision : DWORD;
  36.         TotalByteLength : DWORD;
  37.         HeaderLength : DWORD;
  38.         NumObjectTypes : DWORD;
  39.         DefaultObject : Longint;
  40.         SystemTime : TSystemTime;
  41.         Reserved: DWORD;
  42.         PerfTime : TInt64;
  43.         PerfFreq : TInt64;
  44.         PerfTime100nSec : TInt64;
  45.         SystemNameLength : DWORD;
  46.         SystemNameOffset : DWORD;
  47.     end;
  48.     PPERF_DATA_BLOCK = ^TPERF_DATA_BLOCK;
  49.     TPERF_OBJECT_TYPE = record
  50.         TotalByteLength : DWORD;
  51.         DefinitionLength : DWORD;
  52.         HeaderLength : DWORD;
  53.         ObjectNameTitleIndex : DWORD;
  54.         ObjectNameTitle : LPWSTR;
  55.         ObjectHelpTitleIndex : DWORD;
  56.         ObjectHelpTitle : LPWSTR;
  57.         DetailLevel : DWORD;
  58.         NumCounters : DWORD;
  59.         DefaultCounter : Longint;
  60.         NumInstances : Longint;
  61.         CodePage : DWORD;
  62.         PerfTime : TInt64;
  63.         PerfFreq : TInt64;
  64.     end;
  65.     PPERF_OBJECT_TYPE = ^TPERF_OBJECT_TYPE;
  66. type
  67.     TPERF_COUNTER_DEFINITION = record
  68.         ByteLength : DWORD;
  69.         CounterNameTitleIndex : DWORD;
  70.         CounterNameTitle : LPWSTR;
  71.         CounterHelpTitleIndex : DWORD;
  72.         CounterHelpTitle : LPWSTR;
  73.         DefaultScale : Longint;
  74.         DetailLevel : DWORD;
  75.         CounterType : DWORD;
  76.         CounterSize : DWORD;
  77.         CounterOffset : DWORD;
  78.     end;
  79.     PPERF_COUNTER_DEFINITION = ^TPERF_COUNTER_DEFINITION;
  80.     TPERF_COUNTER_BLOCK = record
  81.         ByteLength : DWORD;
  82.     end;
  83.     PPERF_COUNTER_BLOCK = ^TPERF_COUNTER_BLOCK;
  84.     TPERF_INSTANCE_DEFINITION = record
  85.         ByteLength : DWORD;
  86.         ParentObjectTitleIndex : DWORD;
  87.         ParentObjectInstance : DWORD;
  88.         UniqueID : Longint;
  89.         NameOffset : DWORD;
  90.         NameLength : DWORD;
  91.     end;
  92.     PPERF_INSTANCE_DEFINITION = ^TPERF_INSTANCE_DEFINITION;
  93. ////////////////////////////////////////////////////////////////////////////////
  94. ////////////////////////////////////////////////////////////////////////////////
  95. {$ifdef ver130}
  96. {$L-}         // The L+ causes internal error in Delphi 5 compiler
  97. {$O-}         // The O+ causes internal error in Delphi 5 compiler
  98. {$Y-}         // The Y+ causes internal error in Delphi 5 compiler
  99. {$endif}
  100. {$ifndef ver110}
  101. type
  102.     TInt64F = TInt64;
  103. {$else}
  104. type
  105.     TInt64F = Extended;
  106. {$endif}
  107. {$ifdef ver110}
  108. function FInt64(Value: TInt64): TInt64F;
  109. function Int64D(Value: DWORD): TInt64;
  110. {$else}
  111. type
  112.     FInt64 = TInt64F;
  113.     Int64D = TInt64;
  114. {$endif}
  115. {$ifdef ver110}
  116. function FInt64(Value: TInt64): TInt64F;
  117. var V: TInt64;
  118. begin
  119.     if (Value.HighPart and $80000000) = 0 then // positive value
  120.     begin
  121.         result:=Value.HighPart;
  122.         result:=result*$10000*$10000;
  123.         result:=result+Value.LowPart;
  124.     end else
  125.     begin
  126.         V.HighPart:=Value.HighPart xor $FFFFFFFF;
  127.         V.LowPart:=Value.LowPart xor $FFFFFFFF;
  128.         result:= -1 - FInt64(V);
  129.     end;
  130. end;
  131. function Int64D(Value: DWORD): TInt64;
  132. begin
  133.     result.LowPart:=Value;
  134.     result.HighPart := 0; // positive only
  135. end;
  136. {$endif}
  137. //------------------------------------------------------------------------------
  138. const
  139.     Processor_IDX_Str = '238';
  140.     Processor_IDX = 238;
  141.     CpuUsageIDX = 6;
  142. type
  143.     AInt64F = array[0..$FFFF] of TInt64F;
  144.     PAInt64F = ^AInt64F;
  145. var
  146.     _PerfData : PPERF_DATA_BLOCK;
  147.     _BufferSize: Integer;
  148.     _POT : PPERF_OBJECT_TYPE;
  149.     _PCD: PPerf_Counter_Definition;
  150.     _ProcessorsCount: Integer;
  151.     _Counters: PAInt64F;
  152.     _PrevCounters: PAInt64F;
  153.     _SysTime: TInt64F;
  154.     _PrevSysTime: TInt64F;
  155.     _IsWinNT: Boolean;
  156.     _W9xCollecting: Boolean;
  157.     _W9xCpuUsage: DWORD;
  158.     _W9xCpuKey: HKEY;
  159. function GetCpuCount: Integer;
  160. begin
  161.     if _IsWinNT then
  162.     begin
  163.         if _ProcessorsCount < 0 then CollectCpuData;
  164.         result:=_ProcessorsCount;
  165.     end else
  166.     begin
  167.         result:=1;
  168.     end;
  169. end;
  170. procedure ReleaseCpuData;
  171. var H: HKEY;
  172.     R: DWORD;
  173.     dwDataSize, dwType: DWORD;
  174. begin
  175.     if _IsWinNT then exit;
  176.     if not _W9xCollecting then exit;
  177.     _W9xCollecting:=False;
  178.     RegCloseKey(_W9xCpuKey);
  179.     R:=RegOpenKeyEx( HKEY_DYN_DATA, 'PerfStatsStopStat', 0, KEY_ALL_ACCESS, H );
  180.     if R <> ERROR_SUCCESS then exit;
  181.     dwDataSize:=sizeof(DWORD);
  182.     RegQueryValueEx ( H, 'KERNELCpuUsage', nil, @dwType, PBYTE(@_W9xCpuUsage), @dwDataSize);
  183.     RegCloseKey(H);
  184. end;
  185. function GetCpuUsage(Index: Integer): Double;
  186. begin
  187.     if _IsWinNT then
  188.     begin
  189.         if _ProcessorsCount < 0 then CollectCpuData;
  190.         if (Index >= _ProcessorsCount) or (Index < 0) then
  191.             raise Exception.Create('Cpu index out of bounds');
  192.         if _PrevSysTime = _SysTime then result:=0 else
  193.         result:=1-(_Counters[index] - _PrevCounters[index])/(_SysTime-_PrevSysTime);
  194.     end else
  195.     begin
  196.         if Index <> 0 then
  197.             raise Exception.Create('Cpu index out of bounds');
  198.         if not _W9xCollecting then CollectCpuData;
  199.         result:=_W9xCpuUsage / 100;
  200.     end;
  201. end;
  202. var VI: TOSVERSIONINFO;
  203. procedure CollectCpuData;
  204. var BS: integer;
  205.     i: Integer;
  206.     _PCB_Instance: PPERF_COUNTER_BLOCK;
  207.     _PID_Instance: PPERF_INSTANCE_DEFINITION;
  208.     ST: TFileTime;
  209. var H: HKEY;
  210.     R: DWORD;
  211.     dwDataSize, dwType: DWORD;
  212. begin
  213.     if _IsWinNT then
  214.     begin
  215.         BS:=_BufferSize;
  216.         while RegQueryValueEx( HKEY_PERFORMANCE_DATA, Processor_IDX_Str, nil, nil,
  217.                 PByte(_PerfData), @BS ) = ERROR_MORE_DATA do
  218.         begin
  219.             // Get a buffer that is big enough.
  220.             INC(_BufferSize,$1000);
  221.             BS:=_BufferSize;
  222.             ReallocMem( _PerfData, _BufferSize );
  223.         end;
  224.         // Locate the performance object
  225.         _POT := PPERF_OBJECT_TYPE(DWORD(_PerfData) + _PerfData.HeaderLength);
  226.         for i := 1 to _PerfData.NumObjectTypes do
  227.         begin
  228.             if _POT.ObjectNameTitleIndex = Processor_IDX then Break;
  229.             _POT := PPERF_OBJECT_TYPE(DWORD(_POT) + _POT.TotalByteLength);
  230.         end;
  231.         // Check for success
  232.         if _POT.ObjectNameTitleIndex <> Processor_IDX then
  233.             raise Exception.Create('Unable to locate the "Processor" performance object');
  234.         if _ProcessorsCount < 0 then
  235.         begin
  236.             _ProcessorsCount:=_POT.NumInstances;
  237.             GetMem(_Counters,_ProcessorsCount*SizeOf(TInt64));
  238.             GetMem(_PrevCounters,_ProcessorsCount*SizeOf(TInt64));
  239.         end;
  240.         // Locate the "% Cpu usage" counter definition
  241.         _PCD := PPERF_Counter_DEFINITION(DWORD(_POT) + _POT.HeaderLength);
  242.         for i := 1 to _POT.NumCounters do
  243.         begin
  244.             if _PCD.CounterNameTitleIndex = CpuUsageIDX then break;
  245.             _PCD := PPERF_COUNTER_DEFINITION(DWORD(_PCD) + _PCD.ByteLength);
  246.         end;
  247.         // Check for success
  248.         if _PCD.CounterNameTitleIndex <> CpuUsageIDX then
  249.             raise Exception.Create('Unable to locate the "% of Cpu usage" performance counter');
  250.         // Collecting coutners
  251.         _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_POT) + _POT.DefinitionLength);
  252.         for i := 0 to _ProcessorsCount-1 do
  253.         begin
  254.             _PCB_Instance := PPERF_COUNTER_BLOCK(DWORD(_PID_Instance) + _PID_Instance.ByteLength );
  255.             _PrevCounters[i]:=_Counters[i];
  256.             _Counters[i]:=FInt64(PInt64(DWORD(_PCB_Instance) + _PCD.CounterOffset)^);
  257.             _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_PCB_Instance) + _PCB_Instance.ByteLength);
  258.         end;
  259.         _PrevSysTime:=_SysTime;
  260.         SystemTimeToFileTime(_PerfData.SystemTime, ST);
  261.         _SysTime:=FInt64(TInt64(ST));
  262.     end else
  263.     begin
  264.         if not _W9xCollecting then
  265.         begin
  266.             R:=RegOpenKeyEx( HKEY_DYN_DATA, 'PerfStatsStartStat', 0, KEY_ALL_ACCESS, H );
  267.             if R <> ERROR_SUCCESS then
  268.                 raise Exception.Create('Unable to start performance monitoring');
  269.             dwDataSize:=sizeof(DWORD);
  270.             RegQueryValueEx( H, 'KERNELCpuUsage', nil, @dwType, PBYTE(@_W9xCpuUsage), @dwDataSize );
  271.             RegCloseKey(H);
  272.             R:=RegOpenKeyEx( HKEY_DYN_DATA, 'PerfStatsStatData', 0,KEY_READ, _W9xCpuKey );
  273.             if R <> ERROR_SUCCESS then
  274.                 raise Exception.Create('Unable to read performance data');
  275.             _W9xCollecting:=True;
  276.         end;
  277.         dwDataSize:=sizeof(DWORD);
  278.         RegQueryValueEx( _W9xCpuKey, 'KERNELCpuUsage', nil,@dwType, PBYTE(@_W9xCpuUsage), @dwDataSize );
  279.     end;
  280. end;
  281. initialization
  282.     _ProcessorsCount:= -1;
  283.     _BufferSize:= $2000;
  284.     _PerfData := AllocMem(_BufferSize);
  285.     VI.dwOSVersionInfoSize:=SizeOf(VI);
  286.     if not GetVersionEx(VI) then raise Exception.Create('Can''t get the Windows version');
  287.     _IsWinNT := VI.dwPlatformId = VER_PLATFORM_WIN32_NT;
  288. finalization
  289.     ReleaseCpuData;
  290.     FreeMem(_PerfData);
  291. end.