download
program
A Microseconds Timer in Delphi


Introduction
Delphi has a function gettickcount to obtain the value of a milliseconds clock.
One millisecond is a very long time for most processes so, to obtain accurate time measurements,
processes have to be repeated thousends of times.

However, the Pentium processor has an internal 64 bit clock, that updates on each clock cycle.
So, by combining -once- the milliseconds clock and the clock cycle counter, we can calculate
the processors clock frequency.
And once the clock speed is known, execution times can be measured almost accurate to the nanosecond,
by using the clock speed as a correction factor.

Say, we count the number of clock cycles during 500milliseconds. Let's call this count c500.
Then clockspeed = c500 * 2*10-6 cycles / microsecond.

To measure the duration of a process, before and after this proces the 64 bit cycle count is loaded
in variables t1 and t2.
Then actual processing time in microseconds is (t2 - t1) / clockspeed.

Data format
Older versions of Delphi do not support the 64 bit integer format.
Therefore, a new data type is introduced to hold the 64 bits:
   type TI64 = array[0..8] of byte;
Bits 0..7 of byte -0- hold bits 0..7 of the clock cycle count,
byte -1- holds bits 8..15 of the clock counter etc.
An extra byte -8- is added to facilitate integer divide by 10, to convert the
number to a decimal string.

Variables, Function and Procedure calls
var
 CPUClock: extended;  //floating point value holding cycles per microsecond

procedure GetCPUTicks(var i64 : TI64);//store CPU ticks in array[0..7]
function diff64(v1,v2 : TI64) : TI64; //calculate v2 - v1
function I64tofloat(I64 : TI64) : extended; //convert 64 bit integer to floating point format
function I64toStr(I64 : TI64) : string; //converts 64 bit integer to a string
function CyclesPerMicroSecond : extended;//calculate the clock speed
Function and Procedures
procedure GetCPUTicks(var i64 : TI64);
//store CPU ticks in array[0..7]
var i : byte;
label loop1,loop2;
begin
 asm
   mov ECX,i64 //save address
   DB $0F,$31  // RDTSC command
               // put CPU clock count in EAX (bits 0..31) and EDX (bits 32..63)
   mov i,4
loop1:
   mov [ECX],AL
   shr EAX,8
   inc ECX
   dec i
   jnz loop1
   mov i,4
loop2:
   mov [ECX],DL
   shr EDX,8
   inc ECX
   dec i
   jnz loop2
 end;
end;
function I64tofloat(I64 : TI64) : extended;
var i : byte;
    w : extended;
begin
 result := 0;
 w := 1;
 for i := 0 to 7 do
  begin
   result := result + I64[i]*w;
   w := w * 256;
  end;
end;
function diff64(v1,v2 : TI64) : TI64;
//difference v2 - v1 of 2 64 bit integers
var borrow,i : Byte;
begin
 borrow := 0;
 for i := 0 to 7 do
  begin
   if v2[i] < v1[i]+borrow then
    begin
     result[i] := 256 + v2[i] - v1[i] - borrow;
     borrow := 1;
    end
    else begin
          result[i] := v2[i] - v1[i] - borrow;
          borrow := 0;
         end;
  end;
end;
The following function is not really necessary, since values can be converted to
floating point and then to a character string.
It is only usefull to directly make a string from the clock count.
Figure 1. below shows the idea: The 64 bits are shifted 1 place to te left.
Then a (trial) subtract of 10 decimal (binary 1010) is done.
If succesfull, a "1" is inserted in bit 0 of byte -0-.
After 64 shifts and trial subtracts, byte -8- holds the remainder and
the lower bytes hold the quotient.
Then the remainder is stored as the first digit of the result string and byte -8- is cleared.
above process is repeated until the quotient equals zero.

function I64toStr(I64 : TI64) : string;
//convert a 64 bit integer to a string
const d = 10;
      hb = $80;
      msk = $7f;
var i,j,b,c : byte;
    sum : word;
begin
 result := '';
 repeat
   I64[8] := 0;
   for i := 1 to 64 do
    begin
     for j := 8 downto 1 do
      begin
       c := I64[j-1] shr 7;
       I64[j] := ((I64[j] and msk) shl 1) or c;
      end;//for j
      if I64[8] >= d then begin
                           b := 1;
                           I64[8] := I64[8] - d;
                           end
      else b := 0;
     I64[0] := ((I64[0] and msk) shl 1) or b;
    end;//for i
   insert(chr(ord('0') + I64[8]),result,0);
  sum := 0;
  for j := 0 to 7 do inc(sum,I64[j]);
 until sum = 0;
end;
Process below calculates the clock frequency of the processor.
function CyclesPerMicroSecond : extended;
//calculate the clock speed
var t1,t2 : TI64;
    t : DWORD;
begin
 t := GetTickCount;//get the milliseconds clock count
 while t=GetTickCount do;//wait for increment, start of new count
 GetCPUTicks(t1); //get the proc. cycles counter
 t := t + 500;//set t to end time
 while GetTickCount < t  do;   // wait ....
 GetCPUTicks(t2);  // cycle counter after 500millisecs
 t1 := Diff64(t1,t2);
 result := I64ToFloat(t1)*2e-6;
end;
When 64 bit integers are supported (type Int64)
Some websites list function below, however, this code does not work in Delphi-7

function GetCPUTicks: Int64;
asm
   RDTSC;   // = DB $0F,$31  
end;
Code below does work:

procedure getCPUticks(var i : int64);
begin
 asm
  mov ECX,i;
  RDTSC;       //cpu clock in EAX,EDX
  mov [ECX],EAX;
  mov [ECX+4],EDX;
 end;
end;
The other functions above (except "cyclespermicrosecond") are obsolete in this case.

Application
Store clock frequency in CPUclock
Show frequency in statictext1

procedure TForm1.Button1Click(Sender: TObject);
begin
 CPUclock := CyclesperMicroSecond;
 statictext1.caption := 'CPU clock= '+formatfloat('####0.00',cpuclock) + 'Mhz');
end; 
 
Measure the speed of a process.
The clock cycles are stored in statictext2.
Microseconds are stored in statictext3.

procedure TForm1.Button2Click(Sender: TObject);
//CPUclock must be set
var t1,t2 : TI64;
   sum, i : LongInt;
       et : extended;
	s : string;
begin	  
 sum := 0;
 getCPUTicks(t1);
 for i := 0 to  1000000 do inc(sum,i);//this is the process to measure
 getCPUTicks(t2);
 t1 := Diff64(t1,t2);
 s := I64toStr(t1);
 et := I64ToFloat(t1)/CPUclock;
 statictext2.Caption := s;
 statictext3.caption := formatfloat('####0.000',et);
end;