(******************************************************************************) (* NtCpuTim - Measure total processor time (percent) on Windows NT *) (* Shorter Path Free Components *) (* *) (* Copyright (c) 2003 Shorter Path Software *) (* http://develop.shorterpath.com *) (* KOL version (c) 2003, 2005, Thaddy de Koning *) (******************************************************************************) unit kolntcputime; interface uses Windows, Kol; { GetProcessorTimePct returns the percentage of time that the processor is executing application or operating system processes other than Idle. This counter is a primary indicator of processor activity. It is calculated by measuring the time that the processor spends executing the thread of the Idle process in each sample interval, and subtracting that value from 100%. Each processor has an Idle thread which consumes cycles when no other threads are ready to run. The function returns a single value for all processors in a multi-processor system. The function is based on comparing the current activity with the previous activity. The result is therefore only meaningful when the function is called for the second time. With each call, the result is stored in a global variable. Because of this, the function is not thread safe. Note that calling the function can affect the result, since the function measures CPU activity. It is recommended to call the function at a one second interval, at least. } function GetProcessorTimePct: Integer; implementation type PPerfDataBlock = ^TPerfDataBlock; TPerfDataBlock = record Signature: array[0..3] of WCHAR; LittleEndian: DWORD; Version: DWORD; Revision: DWORD; TotalByteLength: DWORD; HeaderLength: DWORD; NumObjectTypes: DWORD; DefaultObject: Longint; SystemTime: TSystemTime; PerfTime: TLargeInteger; PerfFreq: TLargeInteger; PerfTime100nSec: TLargeInteger; SystemNameLength: DWORD; SystemNameOffset: DWORD; end; PPerfObjectType = ^TPerfObjectType; TPerfObjectType = record TotalByteLength: DWORD; DefinitionLength: DWORD; HeaderLength: DWORD; ObjectNameTitleIndex: DWORD; ObjectNameTitle: LPWSTR; ObjectHelpTitleIndex: DWORD; ObjectHelpTitle: LPWSTR; DetailLevel: DWORD; NumCounters: DWORD; DefaultCounter: Longint; NumInstances: Longint; CodePage: DWORD; PerfTime: TLargeInteger; PerfFreq: TLargeInteger; end; PPerfCounterDefinition = ^TPerfCounterDefinition; TPerfCounterDefinition = record ByteLength: DWORD; CounterNameTitleIndex: DWORD; CounterNameTitle: LPWSTR; CounterHelpTitleIndex: DWORD; CounterHelpTitle: LPWSTR; DefaultScale: Longint; DetailLevel: DWORD; CounterType: DWORD; CounterSize: DWORD; CounterOffset: DWORD; end; PPerfInstanceDefinition = ^TPerfInstanceDefinition; TPerfInstanceDefinition = record ByteLength: DWORD; ParentObjectTitleIndex: DWORD; ParentObjectInstance: DWORD; UniqueID: Longint; NameOffset: DWORD; NameLength: DWORD; end; PPerfCounterBlock = ^TPerfCounterBlock; TPerfCounterBlock = record ByteLength: DWORD; end; function GetProcessorTimeCounter(var CurValue, PerfTime100nSec: TLargeInteger): Boolean; var PerfData: PPerfDataBlock; PerfObj: PPerfObjectType; PerfInst: PPerfInstanceDefinition; PerfCntr, CurCntr: PPerfCounterDefinition; PtrToCntr: PPerfCounterBlock; BufferSize: Integer; i, j, k: Integer; s: string; pData: PLargeInteger; { Navigation helpers } function FirstObject(PerfData: PPerfDataBlock): PPerfObjectType; begin Result := PPerfObjectType(DWORD(PerfData) + PerfData.HeaderLength); end; function NextObject(PerfObj: PPerfObjectType): PPerfObjectType; begin Result := PPerfObjectType(DWORD(PerfObj) + PerfObj.TotalByteLength); end; function FirstInstance(PerfObj: PPerfObjectType): PPerfInstanceDefinition; begin Result := PPerfInstanceDefinition(DWORD(PerfObj) + PerfObj.DefinitionLength); end; function NextInstance(PerfInst: PPerfInstanceDefinition): PPerfInstanceDefinition; var PerfCntrBlk: PPerfCounterBlock; begin PerfCntrBlk := PPerfCounterBlock(DWORD(PerfInst) + PerfInst.ByteLength); Result := PPerfInstanceDefinition(DWORD(PerfCntrBlk) + PerfCntrBlk.ByteLength); end; function FirstCounter(PerfObj: PPerfObjectType): PPerfCounterDefinition; begin Result := PPerfCounterDefinition(DWORD(PerfObj) + PerfObj.HeaderLength); end; function NextCounter(PerfCntr: PPerfCounterDefinition): PPerfCounterDefinition; begin Result := PPerfCounterDefinition(DWORD(PerfCntr) + PerfCntr.ByteLength); end; begin Result := False; // Allocate initial buffer for object information BufferSize := 65536; GetMem(PerfData, BufferSize); // retrieve data while RegQueryValueEx(HKEY_PERFORMANCE_DATA, '238', // Processor object nil, nil, Pointer(PerfData), @BufferSize) = ERROR_MORE_DATA do begin // buffer is too small Inc(BufferSize, 1024); ReallocMem(PerfData, BufferSize); end; RegCloseKey(HKEY_PERFORMANCE_DATA); // Get the first object type PerfObj := FirstObject(PerfData); // Process all objects for i := 0 to PerfData.NumObjectTypes-1 do begin // Check for Processor object if PerfObj.ObjectNameTitleIndex = 238 then begin // Get the first counter PerfCntr := FirstCounter(PerfObj); if PerfObj.NumInstances > 0 then begin // Get the first instance PerfInst := FirstInstance(PerfObj); // Retrieve all instances for k := 0 to PerfObj.NumInstances-1 do begin CurCntr := PerfCntr; // Check instance name for "_Total" s := WideCharToString(PWideChar(DWORD(PerfInst) + PerfInst.NameOffset)); if (AnsiCompareText(s, '_Total') = 0) then // Retrieve all counters for j := 0 to PerfObj.NumCounters-1 do begin PtrToCntr := PPerfCounterBlock(DWORD(PerfInst) + PerfInst.ByteLength); // Check for % Process Time counter if CurCntr.CounterNameTitleIndex = 6 then begin pData := Pointer(DWORD(PtrToCntr) + CurCntr.CounterOffset); CurValue := pData^; PerfTime100nSec := PerfData.PerfTime100nSec; Result := True; end; // Get the next counter CurCntr := NextCounter(CurCntr); end; // Get the next instance. PerfInst := NextInstance(PerfInst); end; end; end; // Get the next object type PerfObj := NextObject(PerfObj); end; // Release buffer FreeMem(PerfData); end; var LastProcessorTimeCounter: TLargeInteger = 0; LastPerfTime100nSec: TLargeInteger = 0; function GetProcessorTimePct: Integer; var CurValue, PerfTime100nSec: TLargeInteger; p: Extended; begin Result := 0; if Winver < WvNT then Exit; if GetProcessorTimeCounter(CurValue, PerfTime100nSec) then begin if LastProcessorTimeCounter <> 0 then begin p := (CurValue - LastProcessorTimeCounter) / (PerfTime100nSec - LastPerfTime100nSec); Result := Trunc(100 * (1 - p)); end; LastProcessorTimeCounter := CurValue; LastPerfTime100nSec := PerfTime100nSec; end; end; end.