type
TRegisters=record
case Integer of
0:(EAX,EBX,ECX,EDX:LongWord);
1:(Str1,Str2,Str3,Str4:array[0..3] of AnsiChar );
2:(Str:array[0..15] of AnsiChar );
end;
procedure GetCPUID(Param:Cardinal; var Registers:TRegisters); register;
function IsCPUID_Available:Boolean; register;
function GetExtendeCPUInfo: AnsiString;
function GetCPUInfo: T_CPU_Info;
function GetCPUName: AnsiString;
function GetCPUUsage: real;
function GetProcessMem: Integer;
implementation
function NtQuerySystemInformation (
SystemInformationClass : DWORD; // information type flag
SystemInformation : Pointer; // buffer
SystemInformationLength : DWORD; // fuffer size
var ReturnLength : DWORD // count of bytes to be returned or needed
) : DWORD; stdcall; external 'ntdll.dll';
function IsCPUID_Available:Boolean; register;
{$IFDEF CPUX64}
asm // x64 version
// FLAGS register in x64 has 64bits, i.e. QWORD,
// PUSHFQ/POPFQ instead of PUSHFD/POPFD for DWORD in x32.
.noframe
PUSHFQ
POP RAX
MOV RBX, RAX
XOR EAX, $200000;
PUSH RAX
POPFQ
PUSHFQ
POP RAX
XOR EAX, EDX
SETNZ AL
end;
{$ELSE}
asm // x32 version
PUSHFD
POP EAX
MOV EDX, EAX
XOR EAX, $200000;
PUSH EAX
POPFD
PUSHFD
POP EAX
XOR EAX, EDX
SETNZ AL
end;
{$ENDIF}
procedure GetCPUID(Param:Cardinal; var Registers:TRegisters); register;
{$IFDEF CPUX64}
asm // X64 version
.noframe
PUSH RBX
PUSH RDI
MOV RDI, Registers
MOV EAX, Param
XOR EBX, EBX
XOR ECX, ECX
XOR EDX, EDX
CPUID
MOV TRegisters(EDI).&EAX, EAX
MOV TRegisters(EDI).&EBX, EBX
MOV TRegisters(EDI).&ECX, ECX
MOV TRegisters(EDI).&EDX, EDX
POP RDI
POP RBX
end;
{$ELSE}
asm // x32 version
PUSH EBX
PUSH EDI
MOV EDI, Registers
XOR EBX, EBX
XOR ECX, ECX
XOR EDX, EDX
CPUID
MOV TRegisters(EDI).&EAX, EAX
MOV TRegisters(EDI).&EBX, EBX
MOV TRegisters(EDI).&ECX, ECX
MOV TRegisters(EDI).&EDX, EDX
POP EDI
POP EBX
end;
{$ENDIF}
res := GetLogicalProcessorInformationEx(
RelationshipType,
nil,
@ByteCount
);
GetMem(Buffer, ByteCount);
res := GetLogicalProcessorInformationEx(
RelationshipType,
@(Buffer^),
@ByteCount
);
offset := 0;
while (offset < ByteCount) do
begin
current_info := PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX( UInt64(buffer) + offset);
offset := offset + current_info^.size;
if Current_info.Relationship = RelationProcessorCore
then
inc(Result.physical_cores);
if current_info.Relationship = RelationCache then
begin
case current_info.Cache.Level of
1: Result.L1CacheSize := Result.L1CacheSize + current_info.Cache.CacheSize;
2: Result.L2CacheSize := Result.L2CacheSize + current_info.Cache.CacheSize;
3: Result.L3CacheSize := Result.L3CacheSize + current_info.Cache.CacheSize;
end; // of CASE
end;
function GetCPUName: AnsiString;
var
Registers:TRegisters;
_EAX: LongWord;
FamilyID, ExtFamilyID, ModelID, ExtModelID, ProcType, Stepping: LongWord;
begin
Result:='';
if not IsCPUID_Available then begin
Result := 'CPUID not supported';
Exit;
end;
// get general CPU info
GetCPUID( $00000000,Registers );
// Its fantastic! general info stored at mixed order: EBX:EDX:ECX
Result := Result + Registers.Str2+Registers.Str4+Registers.Str3 + ': ';
// Get extended info string
for _EAX := $80000002 to $80000004 do
begin
GetCPUID( _EAX ,Registers);
Result := Result + Registers.Str;
end;
end;
function GetExtendeCPUInfo: AnsiString;
var
Registers:TRegisters;
MaxEAX,_EAX: LongWord;
FamilyID, ExtFamilyID, ModelID, ExtModelID, ProcType, Stepping: LongWord;
begin
// get Family, Model and Stepping of CPU
Result:='';
if not IsCPUID_Available then begin
Result := 'CPUID not supported';
Exit;
end;
// steppings are stored at $00000001 "offset"
GetCPUID($00000001,Registers);
Stepping := (Registers.EAX shr 0 ) and $0F;
ModelID := (Registers.EAX shr 4 ) and $0F;
FamilyID := (Registers.EAX shr 8 ) and $0F;
ProcType := (Registers.EAX shr 12) and $03;
ExtModelID := (Registers.EAX shr 16) and $0F;
ExtFamilyID := (Registers.EAX shr 20) and $FF;
Result := Result + Format('Family %x(%x), Model %x(%x), ID %x, Stepping %x',
[FamilyID, ExtFamilyID, ModelID, ExtModelID,
ProcType, Stepping] )
end;