To know how to get the information on the exact execution time of an operation in Delphi can be useful in different cases. For example, it can be necessary when you need to show users the time spent on the execution of a long operation ( by the way, in such a situation, high accuracy is rarely required). Or you may need to know the exact time needed for executing this or that operation to get the possibility to optimize the software by identifying the most challenging places in the program where it “gets stuck” for a long period of time. Usually, the latter situation is typical when you are working on programs that use and process huge volumes of data, and the speed of operations may be not the highest priority but one of the most crucial requirements for the application.
There are several ways to check the execution time of operations in Delphi. In this article, you will find all possible ways to do it.
Method 1 – Use the Now() function
The simplest but the least accurate way to measure the time that is necessary to execute an operation in Delphi is to use the Now() function in the System.SysUtils module.
The source code may look as follows:
12345678910 | uses System.DateUtils;
….
var Start, Stop: TDateTime;
Elapsed: int64;
begin
Start:=Now; //mark the start of the operation
DoSomething;//execute the operation
Stop:=Now; //mark the end of the operation
Elapsed:=SecondsBetween(Start, Stop);//time in seconds
end; |
It is highly likely that you may have the following question: Why did we use SecondsBetween() in the example, and not, for instance, MilliSecondsBetween() that can ensure greater accuracy? We rely on the description of the Now() function in the official Delphi Help. It reads: “Although TDateTime values can represent milliseconds, Now is accurate only to the nearest second.” It means that if you use Now(), there is no sense in determining the time interval with an accuracy of milliseconds.
Method 2 – Use the Windows API and the GetTickCount() function
The GetTickCount() function has no parameters and retrieves the number of milliseconds that have elapsed since the system was started. According to Microsoft’s official documentation, the resolution of the GetTickCount() function is limited to the resolution of the system timer, which is typically in the range of 10 to 16 milliseconds. The millisecond counter will be reset if the system has been running for more than 49.7 days.
In general, the example of using this function is similar to the previous one:
12345678 | var Start, Stop: cardinal;
Elapsed: cardinal;
begin
Start:=GetTickCount; //mark the start of the operation
DoSomething;//execute the opertaion
Stop:=GetTickCount; //mark the end of the operation
Elapsed:=Stop-Start;//time in milliseconds
end; |
So, with the GetTickCount() function, we can track the execution time of an operation in Delphi with millisecond accuracy. If such accuracy does not suit you and you need to measure the time interval even more precisely, then the next method under consideration is for you.
Method 3 – Continue using the Windows API: QueryPerformanceCounter and QueryPerformanceFrequency Functions
QueryPerformanceCounter – Retrieves the current value of the performance counter, which is a high resolution (<1us) timestamp that can be used for time-interval measurements.
QueryPerformanceFrequency – Retrieves the frequency of the performance counter. The frequency of the performance counter is fixed at system boot and is consistent across all processors. That’s why you need to request the frequency only upon application initialization, and the result can be cached.
In order to use these functions to count the time interval needed for the execution of any operation in Delphi, we need to arrange the source code, for example, the following way:
123456789101112 | var iCounterPerSec: TLargeInteger;
T1, T2: TLargeInteger; //counter value BEFORE and AFTER the operation
begin
QueryPerformanceFrequency(iCounterPerSec);//determine the frequency of the counter
QueryPerformanceCounter(T1); //mark the start of the operation
DoSomething; //execute the operation
QueryPerformanceCounter(T2);//mark the end of the operation
ShowMessage(FormatFloat('0.0000', (T2 – T1)/iCounterPerSec) + ' сек.');//show the required number of seconds to complete the operation
end; |
You can work with the obtained values of T1 and T2 as you wish, for example, you can display minutes / seconds / milliseconds separately, etc. This depends on your needs and desires. In this article, I showed the simplest example of using a high-resolution counter in Delphi.
Method 4 – Use the capacities of Delphi. System.Diagnostics Module
The System.Diagnostics module was introduced in Delphi rather long ago. The module provides only one record – TStopwatch. It is nothing more than a convenient “wrapper” for using high-resolution timers from the example that you can see above. TStopwatch uses the functionality that depends on the operating system to access high-resolution timers if they are available. If high-resolution timers are not available in the OS, usual timers are used.
Even though TStopwatch is a record, you still need to call the Create or StartNew method to use it correctly.
The description of TStopwatch is the following one:
12345678910111213141516171819202122232425262728 | TStopwatch = record
strict private
class var FFrequency: Int64;
class var FIsHighResolution: Boolean;
class var TickFrequency: Double;
strict private
FElapsed: Int64;
FRunning: Boolean;
FStartTimeStamp: Int64;
function GetElapsed: TTimeSpan;
function GetElapsedDateTimeTicks: Int64;
function GetElapsedMilliseconds: Int64;
function GetElapsedTicks: Int64;
class procedure InitStopwatchType; static;
public
class function Create: TStopwatch; static;
class function GetTimeStamp: Int64; static;
procedure Reset;
procedure Start;
class function StartNew: TStopwatch; static;
procedure Stop;
property Elapsed: TTimeSpan read GetElapsed;
property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
property ElapsedTicks: Int64 read GetElapsedTicks;
class property Frequency: Int64 read FFrequency;
class property IsHighResolution: Boolean read FIsHighResolution;
property IsRunning: Boolean read FRunning;
end; |
- The IsHighResolution property specifies whether the timer is based on a high resolution performance counter.
- The Start() method starts measuring elapsed time.
- The Stop() method stops measuring elapsed time.
- The ElapsedMilliseconds property gets the total elapsed time in milliseconds.
- The Elapsed property gets the elapsed time in the form of TTimeSpan.
It is also quite simple to use the capacities of TStopwatch. For example, you can do it the following way:
123456789101112 | uses System.Diagnostics;
…
var SW: TStopwatch;
begin
SW:=TStopwatch.StartNew;
SW.Start;
DoSomething;
SW.Stop;
ShowMessage(SW.Elapsed.TotalMinutes.ToString);
end; |
In the example above, we used TStopwatch and displayed the number of minutes (with a fractional part) that were necessary for performing a particular operation. In general, using TStopwatch.Elapsed, you can display any values, limited only by the TTimeSpan features.
To measure the exact execution time of an operation in Delphi, first of all, you need to decide what accuracy suits you:
- If second accuracy is enough, you can use the usual, well-known Now () function. Yes, the accuracy is the lowest, but, on the other hand, this method is absolutely simple.
- If you want to reach millisecond accuracy, use GetTickCount(): it is simple and rather reliable (but only if you do not plan to measure a time interval that will be longer than 49.7 days).
- If you need to use the most accurate methods for measuring the execution time, then we recommend using either a combination of the QueryPerformanceCounter() and QueryPerformanceFrequency() functions, or a more convenient method that presupposes the use of TStopwatch in the System.Diagnostics module.