Содержание материала

 

Пример взят из рассылки: СообЧА. Программирование на Delphi (https://Subscribe.Ru/)

Code:

function GetCPUSpeed: Double;

const DelayTime = 500;

var TimerHi : DWORD;

    TimerLo : DWORD;

    PriorityClass : Integer;

    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;

 

// Usage ...

 

LabelCPUSpeed.Caption := Format('CPU speed: %f MHz', [GetCPUSpeed]);

 


Code:

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;

 


 

 

Code:

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;

 

 


 

Code:

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;

 


Данная тема уже обсуждалась, но у меня есть своя реализация сабжа. Начиная с Pentium MMX, Intel ввели в процессор счетчик тактов на 64 бита (Присутствуэт точно и в К6). Для того чтобы посотреть на его содержание, была введена команда "rdtsc" (подробное описание в интеловской мануале). Эту возможность можно использовать для реализации сабжа. Посоку Делфя не вкурсе насчет rdtsc, то пришлось юзать опкод (0F31). Привожу простенький примерчик юзания, Вы уж извините - немножко кривоват получился, да и ошибка компалера какая-то вылезла :( (V4 Bld5.104 Upd 2). Кому интересно, поделитесь своими соображениями по этому поводу. Особенно интерисует работа в режиме когда меняется частота процессора (Duty Cycle, StandBy).

Code:

// (C) 1999 ISV

unit Unit1;

 

interface

 

uses

Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms,Dialogs,  StdCtrls, Buttons, ExtCtrls;

 

type TForm1 = class(TForm)

   Label1: TLabel;

   Timer1: TTimer;

   Label2: TLabel;

   Label3: TLabel;

   Button1: TButton;

   Button2: TButton;

   Label4: TLabel;

   procedure Timer1Timer(Sender: TObject);

   procedure FormActivate(Sender: TObject);

   procedure Button1Click(Sender: TObject);

   procedure Button2Click(Sender: TObject);

private   

{ Private declarations }

public   

{ Public declarations }

   Counter:integer;

     //Счетчик срабатывания таймера   

Start:int64;             

//Начало роботы   

Previous:int64;       

//Предыдущее значение   

PStart,PStop:int64;

//Для примера выч. времени  

CurRate:integer;

    //Текущая частота проца   

function GetCPUClick:int64;   

function GetTime(Start,Stop:int64):double;

end;

var Form1: TForm1;implementation{$R *.DFM}

// Функция работает на пнях ММХ или выше а

// также проверялась на К6

function TForm1.GetCPUClick:int64;

begin

asm    db  0fh,31h  

// Опкод для команды rdtsc

// mov dword ptr result,eax

// mov dword ptr result[4],edx

end;

// Не смешно :(. Без ?той штуки

// Компайлер выдает Internal error C1079 

Result:=Result;

end;

// Время в секундах между старт и стоп

function TForm1.GetTime(Start,Stop:int64):double;

begin

try    result:=(Stop-Start)/CurRate  except    result:=0;

end;

end;

// Обработчик таймера считает текущую частоту, выводит ее, а также

// усредненную частоту, текущий такт с момента старта процессора.

// При постоянной частоте процессора желательно интервал братьпобольше

// 1-5с для точного прощета частоты процессора.

procedure TForm1.Timer1Timer(Sender: TObject);

var    i:int64;

begin

i:=GetCPUClick;

if Counter=0    then Start:=i    else

begin

     Label2.Caption:=Format('Частота общая:%2f',

      [(i-Start)/(Counter*Timer1.Interval*1000)]);

     Label3.Caption:=Format('Частота текущая:%2f',

      [(i-Previous)/(Timer1.Interval*1000)]);

     CurRate:=Round(((i-Previous)*1000)/(Timer1.Interval));

   end;

Label1.Cap примера

procedure TForm1.Button1Click(Sender: TObject);

begin

PStart:=GetCPUClick;

end;

// Останавливаем отсчет времени и показуем соко

// прошло секунд

procedure TForm1.Button2Click(Sender: TObject);

begin

PStop:=GetCPUClick;

Label4.Caption:=Format!

('Время между нажатиями:%gсек',[GetTime(PStart,PStop)])

end;

end.

  

Проверялось под еНТями на Пне 2 333.


 

Code:

uses registry;

...

 

function GetCpuMhz: Word;

begin

with tregistry.Create do

begin

   rootkey := HKEY_LOCAL_MACHINE;

   openkey('\hardware\description\system\centralprocessor\0\', false);

   result := readinteger('~mhz');

   free;

end;

end;

Автор: Shady

 

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить