type
TApicId = record
Physical: integer; // Id of the physical processor
Logical : integer; // Id of the logical processor
end;
TCacheInfo = record
cType : integer; // Cache type (i.e. instruction, data, unified)
cLevel : integer; // Cache level (1 to n)
cSize : integer; // Size of the cache in bytes
cThreads: integer; // Number of threads sharing the cache
end;
TCpuHTInfo = record
MaxCPUIDBasicInput: integer; // Maximum basic input supported by CPUID
bHTTechnology: BOOL; // Signifies support for HT Technology
id: TApicId;
aCacheInfo: array[0..4] of TCacheInfo;
end;
THTCPUID = class
private
m_ProcessMask: Word;
m_cProcessors: integer;
protected
{ Detects and returns the processor information using CPUID. }
function GetCPUIDInfo(var HTInfo: TCpuHTInfo): BOOL; virtual;
{ These functions contain OS specific APIs. }
function GetProcessMask: Word;
function SetProcessMask(const BitMask: Word): BOOL;
public
constructor Create; virtual;
destructor Destroy; override;
{ Initialize the array of CPUHTInfo structures. }
function Initialize: BOOL; virtual;
{ Returns the number of processors in the system. }
function GetProcessorCount: Word;
{ Returns the detetced processor info for each processor. }
function GetProcessorInfo(Index: Word; var HTInfo: TCpuHTInfo): BOOL; virtual;
end;
var
HTCPUID: THTCPUID;
procedure ShowHTInfo(StrGrid: TStringGrid);
implementation
function cpu_id: DWORD;
asm
db 0fh // Hardcoded CPUID instruction
db 0a2h
end;
procedure ShowHTInfo(StrGrid: TStringGrid);
type
Str3 = array[0..2] of Char;
Str8 = array[0..11] of Char;
var
HTInfo: TCpuHTInfo;
CPU, j, maxJ, c, r,
cProcessors: integer;
cStr: Str8;
const
BoolStr: array[False..True] of Str3= ('No', 'Yes');
szHeader: array[0..8] of ShortString= (
'CPU', 'Max. CPUID Input', 'HT Support', 'Physical', 'Logical',
'Type', 'Level', 'Size', 'Threads');
begin
HTCPUID:= THTCPUID.Create;
try
with HTCPUID, StrGrid do
if Initialize then
begin
RowCount:= 2;
for c:= 0 to 8 do
Cells[c, 0]:= szHeader[c];
{ Get the number of processors and initialize an array to hold the data. }
cProcessors:= GetProcessorCount;
//RowCount:= RowCount - 1;
r:= 0;
for CPU:= 0 to cProcessors - 1 do
begin
Inc(r);
RowCount:= r+1;
{ Get the information for the processor. }
GetProcessorInfo(CPU, HTInfo);
{ Display the processor information. }
maxJ:= SizeOf(HTInfo.aCacheInfo) div SizeOf(HTInfo.aCacheInfo[0]);
for j:= 0 to maxJ - 1 do
if (HTInfo.aCacheInfo[j].cLevel = 2) then
Break;
if HTInfo.aCacheInfo[j].cType = CACHETYPE_NULL then
cStr:= 'Null';
if HTInfo.aCacheInfo[j].cType = CACHETYPE_DATA then
cStr:= 'Data';
if HTInfo.aCacheInfo[j].cType = CACHETYPE_INSTRUCTION then
cStr:= 'Instruction';
if HTInfo.aCacheInfo[j].cType = CACHETYPE_UNIFIED then
cStr:= 'Unified';
Cells[0, r]:= IntToStr(CPU);
Cells[1, r]:= IntToStr(HTInfo.MaxCPUIDBasicInput);
Cells[2, r]:= BoolStr[HTInfo.bHTTechnology];
if HTInfo.bHTTechnology then
begin
Cells[3, r]:= IntToStr(HTInfo.Id.Physical);
Cells[4, r]:= IntToStr(HTInfo.Id.Logical);
Cells[5, r]:= cStr;
Cells[6, r]:= IntToStr(HTInfo.aCacheInfo[j].cLevel);
Cells[7, r]:= IntToStr(HTInfo.aCacheInfo[j].cSize shr 10);
Cells[8, r]:= IntToStr(HTInfo.aCacheInfo[j].cThreads);
end else
begin
for c:= 3 to 8 do
Cells[c, r]:= 'n/a';
end;
end;
end else
begin
MessageDlg('Error in detection.', mtError, [mbOK], 0);
end;
finally
HTCPUID.Free;
end;
end;
constructor THTCPUID.Create;
begin
m_ProcessMask:= 0;
m_cProcessors:= 0;
end;
destructor THTCPUID.Destroy;
begin
inherited Destroy;
end;
function THTCPUID.Initialize: BOOL;
var
Mask: Word;
i, cBits: integer;
begin
result:= False;
{ Get the processor mask for the process. }
m_ProcessMask:= GetProcessMask;
if m_ProcessMask > 0 then
begin
{ Count the number of bits in the mask. }
Mask:= m_ProcessMask;
cBits:= SizeOf(m_ProcessMask) * 8;
for i:= 0 to cBits - 1 do
begin
if BOOL(Mask and 1) then
Inc(m_cProcessors);
Mask:= Mask shr 1;
end;
result:= True;
end;
end;
function THTCPUID.GetProcessorCount: Word;
begin
result:= m_cProcessors;
end;
function THTCPUID.GetProcessorInfo(Index: Word; var HTInfo: TCpuHTInfo): BOOL;
var
Bit: Word;
i, cBits: integer;
CurrIndex: integer;
begin
result:= False;
if BOOL(m_ProcessMask and Index < m_cProcessors) then
begin
{ Search through the bits to find the index selected. }
Bit:= 1;
cBits:= SizeOf(m_ProcessMask) * 8;
CurrIndex:= -1;
for i:= 0 to cBits - 1 do
begin
{ A bit exists in the spot, so increment the current index. }
if BOOL(m_ProcessMask and Bit) then
Inc(CurrIndex);
{ The current index is equal to the index so this is the one we process. }
if (CurrIndex = Index) then
begin
SetProcessMask( Bit );
GetCPUIDInfo(HTInfo);
SetProcessMask( m_ProcessMask );
break;
end;
Bit:= Bit shl 1;
end;
result:= True;
end;
end;
function THTCPUID.GetCPUIDInfo(var HTInfo: TCpuHTInfo): BOOL;
const
szIntelId: array[0..11] of Char= 'GenuineIntel';
var
CacheInfoSize: integer;
bSuccessful: BOOL;
iCacheInfo: integer;
begin
CacheInfoSize:= SizeOf(TCacheInfo);
bSuccessful:= False;
iCacheInfo:= 0;
ZeroMemory(@HTInfo, SizeOf(TCpuHTInfo));
try
asm
{ Get the initial basic information (CPUID.0). }
mov eax, 0
call cpu_id
{ Check for an Intel processor. }
mov edi, offset szIntelId
cmp ebx, [edi]
jne @Quit
cmp edx, [edi+4]
jne @Quit
cmp ecx, [edi+8]
jne @Quit
{ Set to successful since this is an Intel processor. }
mov bSuccessful, 1
{ Save the maximum CPUID basic information level supported. }
mov esi, HTInfo
mov TCpuHTInfo[esi].MaxCPUIDBasicInput, eax
{ Get the basic CPU information (CPUID.1). }
cmp TCpuHTInfo[esi].MaxCPUIDBasicInput, 1
jl @Quit
mov eax, 1
call cpu_id
{ Check for HT Technology }
test edx, MASK_HTT
jz @Quit
mov TCpuHTInfo[esi].bHTTechnology, 1
{ Calculate the APIC ID. }
mov eax, ebx
and eax, MASK_NUMLOGICALS
shr eax, SHFT_NUMLOGICALS
and ebx, MASK_APICID
shr ebx, SHFT_APICID
mov edi, 1
mov edx, $FF // Physical id mask
xor ecx, ecx // Physical id shift
@GetApicId:
cmp edi, eax
jge @EndApicId
shl edi, 1
shl edx, 1
add ecx, 1
jmp @GetApicId
@EndApicId:
lea edi, TCpuHTInfo[esi].Id
mov eax, ebx
and ebx, edx
shr ebx, cl
mov TCpuHTInfo[edi].Id.Physical, ebx
not edx
and eax, edx
mov TCpuHTInfo[edi].Id.Logical, eax
{ Get the cache size and sharing information (CPUID.4) }
cmp TCpuHTInfo[esi].MaxCPUIDBasicInput, 4
jl @Quit
lea edi, TCpuHTInfo[esi].aCacheInfo
@GetCacheInfo:
mov eax, 4
mov ecx, iCacheInfo
call cpu_id
{ Check for end of descriptors (0 cache type). }
test eax, MASK_CACHETYPE
jz @EndCacheInfo
mov edx, eax
{ Get the cache type. }
and eax, MASK_CACHETYPE
mov TCacheInfo[edi].cType, eax
{ Get the cache level. }
mov eax,edx
and eax, MASK_CACHELEVEL
shr eax, SHFT_CACHELEVEL
mov TCacheInfo[edi].cLevel, eax
{ Get the number of threads sharing this cache. }
and edx, MASK_CACHETHREADS
shr edx, SHFT_CACHETHREADS
add edx, 1
mov TCacheInfo[edi].cThreads, edx
{ Calculate the size of the cache. }
mov eax, ebx
xor edx, edx
and eax, MASK_CACHELINESIZE
add eax, 1
add ecx, 1
mul ecx
mov ecx, ebx
and ebx, MASK_CACHEPARTITIONS
shr ebx, SHFT_CACHEPARTITIONS
add ebx, 1
mul ebx
and ecx, MASK_CACHEWAYS
shr ecx, SHFT_CACHEWAYS
add ecx, 1
mul ecx
mov TCacheInfo[edi].cSize, eax
{ Go to the next cache. }
add edi, CacheInfoSize
add iCacheInfo, 1
jmp @GetCacheInfo
@EndCacheInfo:
function THTCPUID.GetProcessMask: Word;
var
ProcessAffinityMask,
SystemAffinityMask: DWORD;
begin
if(GetProcessAffinityMask(GetCurrentProcess, ProcessAffinityMask, SystemAffinityMask)) then
result:= Word(ProcessAffinityMask) else
result:= 0;
end;
function THTCPUID.SetProcessMask(const BitMask: Word): BOOL;
var
ProcessAffinityMask: DWORD;
begin
ProcessAffinityMask:= BitMask;
if (SetProcessAffinityMask(GetCurrentProcess, ProcessAffinityMask)) then
begin
Sleep(0);
result:= True;
end else
result:= False;
end;
CPU 核心数:
function CpuCoreNumber: word;
var
_ebx: Longword;
dimm: string;
begin
asm
mov eax,1
db $0F,$A2
mov _ebx,ebx
end;
result:=lo(_ebx shr 16);
end;