如何有效地检测逻辑和物理处理器的数量?

时间:2017-09-07 10:10:44

标签: delphi delphi-7

目前我正在使用此功能。它工作正常,但每个查询大约需要1秒。所以在我的情况下,我在我的申请中浪费了3秒钟。目前我正在考虑使用3个线程在一秒钟内获取所有信息。

function GetWMIstring (wmiHost, wmiClass, wmiProperty : string):string;
var  // These are all needed for the WMI querying process
  Locator:  ISWbemLocator;
  Services: ISWbemServices;
  SObject:  ISWbemObject;
  ObjSet:   ISWbemObjectSet;
  SProp:    ISWbemProperty;
  Enum:     IEnumVariant;
  Value:    Cardinal;
  TempObj:  OleVariant;
  SN: string;
begin
  Result := '';
  try
  Locator := CoSWbemLocator.Create;  // Create the Location object
  // Connect to the WMI service, with the root\cimv2 namespace
  Services := Locator.ConnectServer(wmiHost, 'root\cimv2', '', '', '','', 0, nil);
  ObjSet := Services.ExecQuery('SELECT * FROM '+wmiClass, 'WQL',
    wbemFlagReturnImmediately and wbemFlagForwardOnly , nil);
  Enum := (ObjSet._NewEnum) as IEnumVariant;
  while Enum.Next(1, TempObj, Value) = S_OK do
  begin
    try SObject := IUnknown(TempObj) as ISWBemObject; except SObject := nil; end;
    TempObj := Unassigned;  // Always need to free interface in TempObj
    if SObject <> nil then
    begin
      SProp := SObject.Properties_.Item(wmiProperty, 0);
      SN := SProp.Get_Value;
      if not VarIsNull(SN) then
      begin
        Result :=  SN;
        Break;
      end;
    end;
  end;
  except // Trap any exceptions (Not having WMI installed will cause one!)
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

  CoInitializeEx(nil,COINIT_MULTITHREADED) ; //required !!! Otherwise "EOleSysError: CoInitialize has not been called" occurs   (Microsoft recommends CoInitializeEx instead of CoInitialize)

  CPU_PROCESSOR_COUNT := StrToInt( getWMIstring('','Win32_ComputerSystem','NumberOfProcessors') );   // number of cpu on mainboard
  CPU_PHYSICAL_CORES := StrToInt( getWMIstring('','Win32_Processor','NumberOfCores') );      // number of phisical cores
  CPU_LOGICAL_CORES := StrToInt( getWMIstring('','Win32_Processor','NumberOfLogicalProcessors') );     //number of logical cores

  CoUninitialize; //required !!!

end;

2 个答案:

答案 0 :(得分:1)

以下是使用GetLogicalProcessorInformation的示例:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

type
  TLogicalProcessorInformation = record
    LogicalProcessorCount : integer;
    NumaNodeCount : integer;
    ProcessorCoreCount : integer;
    ProcessorL1CacheCount : integer;
    ProcessorL2CacheCount : integer;
    ProcessorL3CacheCount : integer;
    ProcessorPackageCount : integer;
  end;

function CountSetBits(bitMask : NativeUInt) : integer;
var
  lShift, i : integer;
  bitTest : NativeUInt;
begin
  lShift := SizeOf(NativeUInt)*8 - 1;
  result := 0;
  bitTest := 1 shl lShift;    
  for i := 0 to lShift do begin
    if (bitMask and bitTest) <> 0 then Inc(result);
    bitTest := bitTest shr 1;
  end;
end;

function GetLogicalProcessorInfo : TLogicalProcessorInformation;
var
  i: Integer;
  ReturnLength: DWORD;
  Buffer: array of TSystemLogicalProcessorInformation;
begin
  result.LogicalProcessorCount := 0;
  result.NumaNodeCount := 0;
  result.ProcessorCoreCount := 0;
  result.ProcessorL1CacheCount := 0;
  result.ProcessorL2CacheCount := 0;
  result.ProcessorL3CacheCount := 0;
  result.ProcessorPackageCount := 0;
  SetLength(Buffer, 256);
  if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
  begin
    if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin
      SetLength(Buffer,
        ReturnLength div SizeOf(TSystemLogicalProcessorInformation) + 1);
      if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
        RaiseLastOSError;
    end else
      RaiseLastOSError;
  end;
  SetLength(Buffer, ReturnLength div SizeOf(TSystemLogicalProcessorInformation));

  for i := 0 to High(Buffer) do begin
    case Buffer[i].Relationship of
        RelationNumaNode: Inc(result.NumaNodeCount);
        RelationProcessorCore:
          begin
            Inc(result.ProcessorCoreCount);
            result.LogicalProcessorCount := result.LogicalProcessorCount + CountSetBits(Buffer[i].ProcessorMask);
          end;
        RelationCache:
          begin
            if (Buffer[i].Cache.Level = 1) then Inc(result.ProcessorL1CacheCount)
            else if (Buffer[i].Cache.Level = 2) then Inc(result.ProcessorL2CacheCount)
            else if (Buffer[i].Cache.Level = 3) then Inc(result.ProcessorL3CacheCount);
          end;
        RelationProcessorPackage: Inc(result.ProcessorPackageCount);
        else
          raise Exception.Create('Error: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value.');
    end;
  end;
end;

var
  LProcInfo : TLogicalProcessorInformation;
begin
  LProcInfo := GetLogicalProcessorInfo;
  WriteLn('Logical processor count = ', LProcInfo.LogicalProcessorCount);
  WriteLn('NUMA Node count = ', LProcInfo.NumaNodeCount);
  WriteLn('Processor Core count = ', LProcInfo.ProcessorCoreCount);
  WriteLn('L1 Cache count = ', LProcInfo.ProcessorL1CacheCount);
  WriteLn('L2 Cache count = ', LProcInfo.ProcessorL2CacheCount);
  WriteLn('L3 Cache count = ', LProcInfo.ProcessorL3CacheCount);
  WriteLn('Package count = ', LProcInfo.ProcessorPackageCount);
  ReadLn;
end.

对于XE2及更高版本,这些WinAPI定义包含在RTL中。否则,可以手动包括定义。示例实现can be found here

例如,对于桌面i7工作站,输出:

  

逻辑处理器计数= 8
  NUMA节点数= 1
  处理器核心数= 4
  L1缓存计数= 8
  L2缓存计数= 4
  L3缓存计数= 1
  套餐数量= 1

逻辑核心数包括超线程虚拟核,处理器核心数是核的物理数,包计数返回物理CPU数,NUMA节点计数返回处理器节点数(对于大型集群计算机)。

如果您希望在较大的群集上运行,请注意以下文档:

  

在具有超过64个逻辑处理器的系统上,GetLogicalProcessorInformation函数检索有关当前为其分配调用线程的处理器组中的处理器的逻辑处理器信息。使用GetLogicalProcessorInformationEx函数检索有关系统上所有处理器组中处理器的信息。

答案 1 :(得分:1)

如果您对逻辑处理器的数量感兴趣-例如出于线程调度的目的,可以使用更简单,更早的 GetSystemInfo 函数:

function GetNumberOfProcessors: Integer;
var
   si: TSystemInfo; //Windows.pas
begin
   GetSystemInfo({var}si);
   Result := si.dwNumberOfProcessors;
end;

几乎所有目的:

  • 它们是单独的物理CPU无关紧要
  • 或者如果它们是核心
  • 或每个具有多个内核的多个物理CPU
  • 或者它们是否对虚拟内核超线程

您想要 GetSystemInfo 提供的内容。