To know how to get the information on the exact execution time of an operation in your Windows and cross platform apps can be useful in all sorts of circumstances. 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 a particular operation while you optimize the software. A high accuracy and dependable timer can be a key part of this 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 still one of the most crucial requirements for the application.
Understanding the quickest and slowest parts of your executable code is part of the concept of software metrics – measuring things. Getting a full understanding of this and other metrics such as maximum memory usage, network traffic throughput, data operations, and so on, allows you to plan future development and identify areas where there is room for improvement.
There are several ways to check the execution time of operations in Delphi. In this article, we examine several possible ways to do it.
Table of Contents
How do I use the Now() function to time areas of my app?
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:
1 2 3 4 5 6 7 8 9 10 |
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.
How can I use the Windows API and the GetTickCount() function to time areas of my app?
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:
1 2 3 4 5 6 7 8 |
var Start, Stop: cardinal; Elapsed: cardinal; begin Start:=GetTickCount; //mark the start of the operation DoSomething;//execute the operation 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.
How do I use the QueryPerformanceCounter and QueryPerformanceFrequency functions to time functions in my app?
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:
1 2 3 4 5 6 7 8 9 10 11 12 |
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.
How to use the capacities of Delphi. System.Diagnostics module to time functions in my app?
The System.Diagnostics
module was introduced in Delphi rather long ago. The module provides only one record – TStopwatch
. It is essentially a convenient “wrapper” for using high-resolution timers in your cross-platform apps. 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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 ofTTimeSpan
.
Is there an example of using a TStopWatch to time functions in my app?
It is quite simple to use the capabilities of TStopwatch
. For example, you can do it the following way:
1 2 3 4 5 6 7 8 9 10 11 12 |
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.
What is the best way to record the execution time of functions in my application?
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 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 – in a Windows application, then we recommend using either a combination of the
QueryPerformanceCounter()
andQueryPerformanceFrequency()
functions. - Finally, the most convenient method is the use of
TStopwatch
in theSystem.Diagnostics
module. This is the most suitable for cross-platform apps since it works on anything including Windows, Linux, iOS, Android, and macOS.
Do you want to try some of these examples for yourself? Why not download a free trial of the latest version of RAD Studio with Delphi?
This article was written by Embarcadero Tech Partner Softacom. Softacom specialize in all sorts of software development focused on Delphi. Read more about their services on the Softacom website.
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition