Cry about...
Delphi Programming
How to time a block of code
These notes cover two different techniques for timing a block of code
using Delphi.
Contents
Its a common requirement to try to make code run faster, and this is
when we start optimising and tweaking our code. Unfortunately it is very
easy to spend time optimising code without any real idea of where most
of the processing time is being spent - and thus which bits of code
ought to be optimised (and which aren't worth spending the time on).
This is a common reason for timing code. It provides a means of
determining how much time a given block of code is taking to execute,
and should we start optimising that code it gives us an indication of
how effective our optimisations are.
Probably the easiest way of timing a block of code is to call the
function Now()
before entering the code block and calling it again on exit from the
code block. The different is the length of time the code took to
execute.
For example:
var
startTime, endTime, elapsedTime: TDateTime;
begin
startTime := Now();
FunctionToTime();
endTime := Now();
elapsedTime := endTime - startTime;
Using Now() is very simple (as this example
demonstrates) but suffers because it is not very precise. Historically
the internal clock was updated about every 55ms, which gives a maximum
precision of 55ms. This is fine for timing code that takes a long time,
but not for code where you need to know the number of milliseconds.
Newer versions of Windows, possibly depending on system hardware, may
obtain the time differently, so on some systems there is the potential
that the accuracy may approach 1ms.
A more accurate means of timing code is to use the high resolution
timers provided by Windows - QueryPerformanceCounter and
QueryPerformanceFrequency.
The function QueryPerformanceFrequncy(var lpFrequency Int64)
returns 0 if the system does not support a high resolution timer. If the
system does support a high resolution timer (and I've yet to use this on
a system that didn't) then the lpFrequency argument will be updated to
hold the frequency of the timer. This is the number of "ticks" per
seconds, or put another way it is the amount that the counter will
increment in a second. Use QueryPerformanceCounter(var
lpPerformanceCount Int64) to obtain the current counter value.
For example:
var
startTime64, endTime64, frequency64: Int64;
elapsedSeconds: single;
begin
QueryPerformanceFrequency(frequency64);
QueryPreformanceCounter(startTime64);
FunctionToTime();
QueryPerformanceCounter(endTime64);
elapsedSeconds := (endTime64 - startTime64) / frequency64;
One thing to remember (and this affects the use of Now for timing
too) is that there are always other processes running on your PC and
because of this timings may vary from one run to the next.
Given that QueryPerformanceCounter is so easy to use, and its much
greater accuracy, its a much better choice when timing code.
These notes are believed to be correct for Delphi 6
and Delphi 7 on
Windows XP and may apply to other versions as well.
|