Question

We are in the process of migrating our application suite to 64 bit using Delphi XE5. In our about boxes we display the CPU speed. The routine we currently use is 32 bit assembly and therefore will not compile under 64 bit.

Is there a native way to retrieve CPU speed from within Delphi 64 bit?

Was it helpful?

Solution

If your platform is windows and you want the advertised CPU speed then you can simply check the HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0\~MHz DWORD value in the Registry:

program SO21757165;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Registry,
  Windows,
  System.SysUtils;

function GetCPUSpeed : String;

var
  Reg : TRegistry;

begin
 Reg := TRegistry.Create(KEY_QUERY_VALUE);
 try
  Reg.RootKey := HKEY_LOCAL_MACHINE;
  if Reg.OpenKeyReadOnly('HARDWARE\DESCRIPTION\System\CentralProcessor\0') then
   begin
    Result := Format('CPU Speed is %dMHz', [Reg.ReadInteger('~MHz')]);
    Reg.CloseKey;
   end;
 finally
  Reg.Free;
 end;
end;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    Writeln(GetCPUSpeed);
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

EDIT

rewrote above code snippet to a compileable example. This example has been verified in XE7and works in 32bit and 64 bit environments (with UAC enabled)

OTHER TIPS

The registry isn't a good solution because it might be altered and may be subject to user permission (read registry).

The following code can be compiled under Delphi XE-8 both 32-bit and 64-bit, following the SAME principle, so this should give you consistent values in both 32-bit and 64-bit.

{$IFDEF CPUX64}
function GetCpuClockCycleCount: Int64; assembler; register;
asm
    dw 310Fh // rdtsc
    shl rdx, 32
    or rax, rdx
end;
{$ENDIF}

function GetCPUSpeed: double;
{$IFDEF CPUX86}
const
  DelayTime = 500; // measure time in ms
var
  TimerHi, TimerLo: DWOrd;
  PriorityClass, Priority: Integer;
begin
  PriorityClass := GetPriorityClass(GetCurrentProcess);
  Priority := GetthreadPriority(GetCurrentthread);
  SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
  SetthreadPriority(GetCurrentthread, thread_PRIORITY_TIME_CRITICAL);
  Sleep(10);
  asm
    dw 310Fh // rdtsc
    mov TimerLo, eax
    mov TimerHi, edx
  end;
  Sleep(DelayTime);
  asm
    dw 310Fh // rdtsc
    sub eax, TimerLo
    sbb edx, TimerHi
    mov TimerLo, eax
    mov TimerHi, edx
  end;
  SetthreadPriority(GetCurrentthread, Priority);
  SetPriorityClass(GetCurrentProcess, PriorityClass);
  Result := TimerLo / (1000.0 * DelayTime);
end;
{$ELSE}
const
  DelayTime = 500;
var
  x, y: UInt64;
  PriorityClass, Priority: Integer;
begin
  PriorityClass := GetPriorityClass(GetCurrentProcess);
  Priority      := GetThreadPriority(GetCurrentThread);
  SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
  SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
  Sleep(10);
  x := GetCpuClockCycleCount;
  Sleep(DelayTime);
  y := GetCpuClockCycleCount;
  SetThreadPriority(GetCurrentThread, Priority);
  SetPriorityClass(GetCurrentProcess, PriorityClass);
  Result := ((y - x) and $FFFFFFFF) / (1000 * DelayTime);
end;
{$ENDIF}

I think you can access this information using WMI.

GLibWMI components can be found on this website (http://neftali.clubdelphi.com) or sourceforge (http://sourceforge.net/projects/glibwmi/). The current version is 1.8b and has a component called TProcessorInfo with which you can get this information.

It has properties like (CurrentclockSpeed or MaxClockSpeed).

One of the samples that comes with the library is about this class (TProcessorInfo).

enter image description here

The source code is available so you can expand it to access other WMI classes if necessary.

If you don't want to use Components, you can get code neccesary to get this properties using te tool "WMI Delphi code Creator" created by Rodrigo Ruz.

enter image description here

Regards.

Well technically each core in your CPU can operate at a different frequency you can use this WMI example to get the frequency of each "Core" although it counts Logical cores and not physical.

Here is a VCL example

uses : ComObj,ActiveX;

procedure  GetProcessorPerformanceInfo;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  Form5.ListBox1.Clear;
  Form5.Tfreq.Clear;
  Form5.Tusage.Clear;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\WMI', WbemUser, WbemPassword);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM ProcessorPerformance','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Form5.ListBox1.Items.Add(Format('frequency   %d',[Integer(FWbemObject.frequency)])+Format('%s',[String(FWbemObject.InstanceName)]));// Uint32
    FWbemObject:=Unassigned;
  end;
end;  

There is a very good tool you can use to create these, this was made using Delphi WMI Code generator from https://theroadtodelphi.wordpress.com/wmi-delphi-code-creator/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top