// Call CollectCPUData to refresh information about CPU usage procedure CollectCPUData; // Call it to obtain the number of CPU's in the system function GetCPUCount: integer; // Call it to obtain the % of usage for given CPU function GetCPUUsage(Index: integer): double; // For Win9x only: call it to stop CPU usage monitoring and free system resources procedure ReleaseCPUData;
type AInt64F = array[0..$FFFF] of TInt64F; PAInt64F = ^AInt64F;
var _PerfData: PPERF_DATA_BLOCK; _BufferSize: integer; _POT: PPERF_OBJECT_TYPE; _PCD: PPerf_Counter_Definition; _ProcessorsCount: integer; _Counters: PAInt64F; _PrevCounters: PAInt64F; _SysTime: TInt64F; _PrevSysTime: TInt64F; _IsWinNT: boolean; _W9xCollecting: boolean; _W9xCpuUsage: DWORD; _W9xCpuKey: HKEY; //------------------------------------------------------------------------------ function GetCPUCount: integer; begin if _IsWinNT then begin if _ProcessorsCount < 0 then CollectCPUData; Result := _ProcessorsCount; end else begin Result := 1; end; end; //------------------------------------------------------------------------------ procedure ReleaseCPUData; var H: HKEY; R: DWORD; dwDataSize, dwType: DWORD; begin if _IsWinNT then exit; if not _W9xCollecting then exit; _W9xCollecting := False; RegCloseKey(_W9xCpuKey); R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats\StopStat', 0, KEY_ALL_ACCESS, H); if R <> ERROR_SUCCESS then exit; dwDataSize := sizeof(DWORD); RegQueryValueEx(H, 'KERNEL\CPUUsage', nil, @dwType, PBYTE(@_W9xCpuUsage), @dwDataSize); RegCloseKey(H); end; //------------------------------------------------------------------------------ function GetCPUUsage(Index: integer): double; begin if _IsWinNT then begin if _ProcessorsCount < 0 then CollectCPUData; if (Index >= _ProcessorsCount) or (Index < 0) then raise Exception.Create('CPU index out of bounds'); if _PrevSysTime = _SysTime then Result := 0 else Result := 1 - (_Counters[index] - _PrevCounters[index]) / (_SysTime - _PrevSysTime); end else begin if Index <> 0 then raise Exception.Create('CPU index out of bounds'); if not _W9xCollecting then CollectCPUData; Result := _W9xCpuUsage / 100; end; end;
var VI: TOSVERSIONINFO; //------------------------------------------------------------------------------ procedure CollectCPUData; var BS: integer; i: integer; _PCB_Instance: PPERF_COUNTER_BLOCK; _PID_Instance: PPERF_INSTANCE_DEFINITION; ST: TFileTime; var H: HKEY; R: DWORD; dwDataSize, dwType: DWORD; begin if _IsWinNT then begin BS := _BufferSize; while RegQueryValueEx(HKEY_PERFORMANCE_DATA, Processor_IDX_Str, nil, nil, PByte(_PerfData), @BS) = ERROR_MORE_DATA do begin // Get a buffer that is big enough. Inc(_BufferSize, $1000); BS := _BufferSize; ReallocMem(_PerfData, _BufferSize); end; // Locate the performance object _POT := PPERF_OBJECT_TYPE(DWORD(_PerfData) + _PerfData.HeaderLength); for i := 1 to _PerfData.NumObjectTypes do begin if _POT.ObjectNameTitleIndex = Processor_IDX then Break; _POT := PPERF_OBJECT_TYPE(DWORD(_POT) + _POT.TotalByteLength); end; // Check for success if _POT.ObjectNameTitleIndex <> Processor_IDX then raise Exception.Create( 'Unable to locate the "Processor" performance object'); if _ProcessorsCount < 0 then begin _ProcessorsCount := _POT.NumInstances; GetMem(_Counters, _ProcessorsCount * SizeOf(TInt64)); GetMem(_PrevCounters, _ProcessorsCount * SizeOf(TInt64)); end; // Locate the "% CPU usage" counter definition _PCD := PPERF_Counter_DEFINITION(DWORD(_POT) + _POT.HeaderLength); for i := 1 to _POT.NumCounters do begin if _PCD.CounterNameTitleIndex = CPUUsageIDX then break; _PCD := PPERF_COUNTER_DEFINITION(DWORD(_PCD) + _PCD.ByteLength); end; // Check for success if _PCD.CounterNameTitleIndex <> CPUUsageIDX then raise Exception.Create( 'Unable to locate the "% of CPU usage" performance counter'); // Collecting coutners _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_POT) + _POT.DefinitionLength); for i := 0 to _ProcessorsCount - 1 do begin _PCB_Instance := PPERF_COUNTER_BLOCK(DWORD(_PID_Instance) + _PID_Instance.ByteLength); _PrevCounters[i] := _Counters[i]; _Counters[i] := FInt64(PInt64(DWORD(_PCB_Instance) + _PCD.CounterOffset)^); _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_PCB_Instance) + _PCB_Instance.ByteLength); end; _PrevSysTime := _SysTime; SystemTimeToFileTime(_PerfData.SystemTime, ST); _SysTime := FInt64(TInt64(ST)); end else begin if not _W9xCollecting then begin R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats\StartStat', 0, KEY_ALL_ACCESS, H); if R <> ERROR_SUCCESS then raise Exception.Create('Unable to start performance monitoring'); dwDataSize := sizeof(DWORD); RegQueryValueEx(H, 'KERNEL\CPUUsage', nil, @dwType, PBYTE(@_W9xCpuUsage), @dwDataSize); RegCloseKey(H); R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats\StatData', 0, KEY_READ, _W9xCpuKey); if R <> ERROR_SUCCESS then raise Exception.Create('Unable to read performance data'); _W9xCollecting := True; end; dwDataSize := sizeof(DWORD); RegQueryValueEx(_W9xCpuKey, 'KERNEL\CPUUsage', nil, @dwType, PBYTE(@_W9xCpuUsage), @dwDataSize); end; end;
initialization _ProcessorsCount := -1; _BufferSize := $2000; _PerfData := AllocMem(_BufferSize); VI.dwOSVersionInfoSize := SizeOf(VI); if not GetVersionEx(VI) then raise Exception.Create('Can''t get the Windows version'); _IsWinNT := VI.dwPlatformId = VER_PLATFORM_WIN32_NT;