15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Как определить скорость процессора

Вариант 1 (ассемблерная версия):

function GetCPUSpeed: real;

  function IsCPUID_Available: Boolean; assembler; register;
  asm
            PUSHFD                { прямой доступ к флагам невозможен, только через стек }
            POP    EAX            { флаги в EAX }
            MOV    EDX,EAX        { сохраняем текущие флаги }
            XOR    EAX,$200000    { бит ID не нужен }
            PUSH    EAX           { в стек }
            POPFD                { из стека в флаги, без бита ID }
            PUSHFD                { возвращаем в стек }
            POP    EAX            { обратно в EAX }
            XOR    EAX,EDX        { проверяем, появился ли бит ID }
            JZ      @exit         { нет, CPUID не доступен }
            MOV    AL,True        { Result=True }
            @exit:
  end;

  function hasTSC: Boolean;
  var
    Features: Longword;
  begin
    asm
              MOV    Features,0    { Features = 0 }

              PUSH    EBX
              XOR    EAX,EAX
              DW      $A20F
              POP    EBX

              CMP    EAX,$01
              JL      @Fail

              XOR    EAX,EAX
              MOV    EAX,$01
              PUSH    EBX
              DW      $A20F
              MOV    Features,EDX
              POP    EBX
              @Fail:
    end;

    hasTSC := (Features and $10) <> 0;
  end;

const
  DELAY = 500;
var
  TimerHi, TimerLo: Integer;
  PriorityClass, Priority: Integer;
begin
  Result := 0;
  if not (IsCPUID_Available and hasTSC) then Exit;
  PriorityClass := GetPriorityClass(GetCurrentProcess);
  Priority := GetThreadPriority(GetCurrentThread);

  SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
  SetThreadPriority(GetCurrentThread,
    THREAD_PRIORITY_TIME_CRITICAL);

  SleepEx(10, FALSE);

  asm
            DB      $0F           { $0F31 op-code for RDTSC Pentium инструкции }
            DB      $31           { возвращает 64-битное целое (Integer) }
            MOV    TimerLo,EAX
            MOV    TimerHi,EDX
  end;

  SleepEx(DELAY, FALSE);

  asm
            DB      $0F           { $0F31 op-code для RDTSC Pentium инструкции }
            DB      $31           { возвращает 64-битное целое (Integer) }
            SUB    EAX,TimerLo
            SBB    EDX,TimerHi
            MOV    TimerLo,EAX
            MOV    TimerHi,EDX
  end;

  SetThreadPriority(GetCurrentThread, Priority);
  SetPriorityClass(GetCurrentProcess, PriorityClass);
  Result := TimerLo / (1000 * DELAY);
end;

 

-----------------------------------------------------------------------------------------------------------

Вариант 2 (Тоже с ассемблерной вставкой, но проще и вдобавок сразу получаем MHz):

Program ....;
  ..
..
  

const
ID_BIT=$200000; // EFLAGS ID bit

function GetCPUSpeed: Double;
const
  DelayTime = 500;
var
  TimerHi, TimerLo: DWORD;
  PriorityClass, Priority: Integer;
begin
try
  PriorityClass := GetPriorityClass(GetCurrentProcess);
  Priority := GetThreadPriority(GetCurrentThread);

  SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriorit(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);
  except end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var cpuspeed:string;
begin
cpuspeed:=Format('%f MHz', [GetCPUSpeed]);
edit1.text := cpuspeed;
end;

 

-----------------------------------------------------------------------------------------------------------

Вариант 3 (WinApi):

function RdTSC : int64; register;
asm
  db   $0f, $31
end;                                                 

function GetCyclesPerSecond : int64;
var
  hF, T, et, sc : int64;
begin
  QueryPerformanceFrequency(hF);                          // HiTicks / second
  QueryPerformanceCounter(T);                        // Determine start HiTicks
  et := T + hF;           // (Cycles are passing, but we can still USE them!)
  sc := RdTSC;                                                          // Get start cycles
  repeat                                    // Use Hi Perf Timer to loop for 1 second
    QueryPerformanceCounter(T);                            // Check ticks NOW
  until (T >= et);                    //  Break the moment we equal or exceed et
  Result := RdTSC - sc;                // Get stop cycles and calculate result
end;