![]() |
![]() |
|||||
Er is een nieuw artikel waarin een timer component wordt beschreven, kijk [ HIER ] Klik [hier] voor het Delphi project als 64 bits integers worden ondersteund (Int64) Klik [hier] voor het Delphi project als geen 64 bits integers worden ondersteund Inleiding In Delphi programma's kan voor tijdmeting gebruik worden gemaakt van een milliseconden teller.Deze 32 variable van het type cardinal levert de tijd in milliseconden vanaf het opstarten van windows. (Er treedt dus een overflow op na 49 dagen) De nauwkeurigheid is niet erg goed, omdat de teller niet elke milliseconde wordt verhoogd, maar slechts 60 maal per seconde. Het volgende programmaatje toont dit gedrag van de milliseconde teller: procedure TForm1.Button1Click(Sender: TObject); var t : cardinal; begin t := gettickcount; while gettickcount = t do; label1.Caption := inttostr(gettickcount-t); end;Zoals blijkt, toont label1 meestal een waarde van 16 en soms van 15. De meeste processen duren minder dan milliseconden, zodat voor een nauwkeurige tijdmeting een proces honderden malen herhaald moet worden. De Pentium processor heeft echter ook een 64 bit teller, die elke clock cycle wordt verhoogd. De RDTSC instructie (code $0F,$31) kopieert bits 0..31 naar register EAX en bits 32..63 naar register EDX. Hiermee is nauwkeurige tijdmeting mogelijk van kort durende processen. Maar er is nog een probleempje: de CPU kloksnelheid kan per systeem verschillen. Om tijd te kunnen meten, moet eerst de klokfrequentie worden berekend. Hiervoor maken we éénmalig gebruik van de milliseconde teller. Dat gaat als volgt: Lees het 64 bit CPU klokregister, wacht 500 milliseconden en lees het 64 bit register opnieuw. Door het klokverschil * 0,001 te delen door 500 ontstaat de kloksnelheid in megahertz. Is eenmaal de kloksnelheid bekend, dat wordt tijdsduur gemeten door:
- het te meten proces uit te voeren - de CPU klok opnieuw te lezen - het verschil van de klokwaardes te berekenen - dit verschil om te zetten naar "double" floating point formaat - dit verschil te delen door de berekende klokfrequentie
2. de Delphi versie ondersteunt geen 64 bit integers Support van 64 bit integers zie de listing hieronder:
unit Unit1;
{
a microseconds clock for Delphi versions
that support 64 bit integers (type = Int64)
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
StaticText1: TStaticText;
Button2: TButton;
StaticText2: TStaticText;
Label1: TLabel;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
CPUclock : double; //CPU clock speed in MHz
implementation
{$R *.dfm}
procedure getCPUticks(var count: Int64);
//store 64 bits CPU clock in variable count
begin
asm
mov ECX,count;
RDTSC; //lower 32 bits --> EAX, upper 32 bits ---> EDX
//RDTSC = DB $0F,$31
mov [ECX],EAX;
add ECX,4;
mov [ECX],EDX;
end;
end;
procedure setCPUclock;
//set variable CPUclock
//call this procedure before measuring any process time
var t1,t2 : cardinal; //system clock ticks
cput1,cput2 : Int64; //CPU clock ticks
begin
t1 := getTickCount; //get milliseconds clock
while getTickCount = t1 do; //sync with start of 1 millisec interval
getCPUticks(cput1); //get CPU clock count
t1 := gettickcount;
repeat
getCPUticks(cput2); //get CPU clock count
t2 := gettickcount;
until t2-t1 >= 500;
CPUclock := (cput2-cput1)/((t2-t1)*1e3); //set CPU clock in microsecs
form1.statictext2.caption := formatfloat('####',CPUclock)+' MHz';
end;
procedure TForm1.Button1Click(Sender: TObject);
//button1 enables display of CPU ticks in statictext1
var count: Int64;
begin
getCPUticks(count);
statictext1.Caption := inttostr(count);
end;
procedure TForm1.Button2Click(Sender: TObject);
//a process of which time is measured
var t1,t2 : Int64;
i : integer;
x,y : double;
begin
getCPUticks(t1);
x := 1000; //process starts here
y := 1;
for i := 1 to 1000 do
begin
x := (x + y)2;
y := 1000x;
end; //process ends here
getCPUticks(t2);
statictext1.Caption := formatfloat('####.####',(t2-t1)/CPUclock) + ' microsecs';
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
application.ProcessMessages;
setCPUclock;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
application.ProcessMessages;
setCPUclock;
end;
end.
64 bit integers niet ondersteund In dit geval wordt een 64 bit integertype genaamd I64 gedefinieerd.type I64 = array[0..1] of cardinal function I64ToFloat(a : I64) : double converteert het nieuwe I64 formaat naar floating point double. procedure Diff64(t2,t1 : I64) berekent het verschil t2 := t2 - t1 Hier staat de source code
unit Unit1;
{
a microseconds clock for Delphi versions
that do not support 64 bit integers
a type I64 = array[0..1] of cardinal is used instead
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
StaticText1: TStaticText;
Button2: TButton;
StaticText2: TStaticText;
Label1: TLabel;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
I64 = array[0..1] of cardinal; //64 bit integer
var
Form1: TForm1;
CPUclock : double; //CPU clock speed in MHz
implementation
{$R *.dfm}
procedure getCPUticks(var count: I64);
//store 64 bits CPU clock in variable count
begin
asm
mov ECX,count;
RDTSC; //lower 32 bits --> EAX, upper 32 bits ---> EDX
//RDTSC = DB $0F,$31
mov [ECX],EAX;
add ECX,4;
mov [ECX],EDX;
end;
end;
procedure diff64(var a,b : I64);
//set a to a-b
begin
asm
mov ECX,a;
mov EAX,[ECX];
mov EDX,[ECX+4];
mov ECX,b
sub EAX,[ECX]; //subtract
sbb EDX,[ECX+4]; //subtract with borrow
mov ECX,a;
mov [ECX],EAX;
mov [ECX+4],EDX;
end;
end;
function I64ToFloat(const a : I64) : double;
//convert I64 integer to floating point double
begin
result := a[0] + a[1]*4294967296;
end;
function I64ToHex(a : I64) : string;
//convert 64 bits integer to hexadecimal string
const v : array[0..15] of char =
('0','1','2','3','4','5','6','7',
'8','9','a','b','c','d','e','f');
var i,j : byte;
begin
result := '';
for i := 1 downto 0 do
for j := 7 downto 0 do
result := result + v[(a[i] shr (j*4)) and $f];
end;
procedure setCPUclock;
//set variable CPUclock
//call this procedure before measuring any process time
var t1,t2 : cardinal; //system clock ticks
cput1,cput2 : I64; //CPU clock ticks
begin
t1 := getTickCount; //get milliseconds clock
while getTickCount = t1 do; //sync with update of 1 millisec interval
getCPUticks(cput1); //get CPU clock count
t1 := gettickcount; //get millisecs clock time
repeat
getCPUticks(cput2); //get CPU clock count
t2 := gettickcount;
until t2-t1 >= 500;
diff64(cput2,cput1);
CPUclock := I64ToFloat(cput2)/((t2-t1)*1e3); //set CPU clock in microsecs
form1.statictext2.caption := formatfloat('####',CPUclock)+' MHz';
end;
procedure TForm1.Button1Click(Sender: TObject);
//button1 enables display of CPU ticks in statictext1
var count: I64;
begin
getCPUticks(count);
statictext1.Caption := I64ToHex(count);
end;
procedure TForm1.Button2Click(Sender: TObject);
//a process of which time is measured
var t1,t2 : I64;
i : integer;
x,y,z : double;
begin
getCPUticks(t1);
x := 1000; //process starts here
y := 1;
for i := 1 to 1000 do
begin
x := (x + y)2;
y := 1000x;
end; //process ends here
getCPUticks(t2);
diff64(t2,t1); //t2 := t2 - t1
z := I64ToFloat(t2);
statictext1.Caption := formatfloat('####.####',z/CPUclock) + ' microsecs';
end;
procedure TForm1.FormActivate(Sender: TObject);
//calculate CPU clock speed
begin
application.processmessages;
setCPUclock;
end;
procedure TForm1.Button3Click(Sender: TObject);
//recalculate the CPU clock
begin
application.processmessages;
setCPUclock;
end;
end.
De projecten (Delphi-7) De CPU kloksnelheid wordt berekend na het event formactivate.Gebruik hiervoor niet formcreate want dit levert een te lage waarde op om een of andere reden. De projecten berekenen de tijdsduur van een simpel proces en tonen ook de CPU klokwaarden. Merk op, dat de kloksnelheid meestal binnen 0,1% nauwkeurig wordt berekend. Maar in zeldzame gevallen is de berekende kloksnelheid lager omdat blijkbaar tijdens het meetproces een taak van windows werd afgehandeld.
|
||||||
![]() |
![]() |