Friday, March 6, 2020

High Performance Timer in Delphi - TStopWatch

High Performance Timer in Delphi - TStopWatch For routine desktop database applications, adding a single second to a tasks execution time rarely makes a difference to end users - but when you need to process millions of tree leaves or generate billions of unique random numbers, speed-of-execution becomes more important. Timing Out Your Code In some applications, very accurate, high-precision time measurement methods are important and luckily Delphi provides a high-performance counter to qualify  these times. Using RTLs Now  Function One option uses the Now function. Now, defined in the SysUtils unit, returns the current system date and time. A few lines of code measure elapsed time between the start and stop of some process: var   Ã‚  start, stop, elapsed : TDateTime;​ begin   Ã‚  start : Now;   Ã‚  //TimeOutThis();   Ã‚  stop : Now;   Ã‚  elapsed : stop - start; end; The Now function returns the current system date and time that is accurate up to 10 milliseconds (Windows NT and later) or 55 milliseconds (Windows 98). For very small intervals the precision of Now is sometimes not enough. Using Windows API GetTickCount For even more precise data, use the GetTickCount Windows API function. GetTickCount retrieves the number of milliseconds that have elapsed since the system was started, but the function only has the precision of 1 ms and may not always be accurate if the computer remains powered-up for long periods of time. The elapsed time is stored as a DWORD (32-bit) value. Therefore, the time will wrap around to zero if Windows is run continuously for 49.7 days. var   Ã‚  start, stop, elapsed : cardinal; begin   Ã‚  start : GetTickCount;   Ã‚  //TimeOutThis();   Ã‚  stop : GetTickCount;   Ã‚  elapsed : stop - start; //millisecondsend; GetTickCount is also limited to the accuracy of the system timer (10 / 55 ms). High Precision Timing Out Your Code If your PC supports a high-resolution performance counter, use the QueryPerformanceFrequency Windows API function to express the frequency, in counts per second. The value of the count is processor dependent. The QueryPerformanceCounter function retrieves the current value of the high-resolution performance counter. By calling this function at the beginning and end of a section of code, an application uses the counter as a high-resolution timer. The accuracy of high-resolution timers is around a few hundred nanoseconds. A nanosecond is a unit of time representing 0.000000001 seconds or 1 billionth of a second. TStopWatch: Delphi Implementation of a High-Resolution Counter With a nod to .Net naming conventions, a counter like TStopWatch offers a high-resolution Delphi solution for precise time measurements. TStopWatch measures elapsed time by counting timer ticks in the underlying timer mechanism. The IsHighResolution property indicates 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 total elapsed time in timer ticks. unit StopWatch;interface uses Windows, SysUtils, DateUtils;type TStopWatch class   Ã‚  private   Ã‚  Ã‚  Ã‚  fFrequency : TLargeInteger;   Ã‚  Ã‚  Ã‚  fIsRunning: boolean;   Ã‚  Ã‚  Ã‚  fIsHighResolution: boolean;   Ã‚  Ã‚  Ã‚  fStartCount, fStopCount : TLargeInteger;   Ã‚  Ã‚  Ã‚  procedure SetTickStamp(var lInt : TLargeInteger) ;  Ã‚  Ã‚  Ã‚  function GetElapsedTicks: TLargeInteger;  Ã‚  Ã‚  Ã‚  function GetElapsedMilliseconds: TLargeInteger;  Ã‚  Ã‚  Ã‚  function GetElapsed: string;  Ã‚  public   Ã‚  Ã‚  Ã‚  constructor Create(const startOnCreate : boolean false) ;  Ã‚  Ã‚  Ã‚  procedure Start;  Ã‚  Ã‚  Ã‚  procedure Stop;  Ã‚  Ã‚  Ã‚  property IsHighResolution : boolean read fIsHighResolution;  Ã‚  Ã‚  Ã‚  property ElapsedTicks : TLargeInteger read GetElapsedTicks;  Ã‚  Ã‚  Ã‚  property ElapsedMilliseconds : TLargeInteger read GetElapsedMilliseconds;  Ã‚  Ã‚  Ã‚  property Elapsed : string read GetElapsed;  Ã‚  Ã‚  Ã‚  property IsRunning : b oolean read fIsRunning;  Ã‚  end;implementation constructor TStopWatch.Create(const startOnCreate : boolean false) ;begin   Ã‚  inherited Create;   Ã‚  fIsRunning : false;   Ã‚  fIsHighResolution : QueryPerformanceFrequency(fFrequency) ;   Ã‚  if NOT fIsHighResolution then fFrequency : MSecsPerSec;  Ã‚  if startOnCreate then Start;end;function TStopWatch.GetElapsedTicks: TLargeInteger;begin   Ã‚  result : fStopCount - fStartCount; end;procedure TStopWatch.SetTickStamp(var lInt : TLargeInteger) ;begin   Ã‚  if fIsHighResolution then   Ã‚  Ã‚  Ã‚  QueryPerformanceCounter(lInt)   Ã‚  else   Ã‚  Ã‚  Ã‚  lInt : MilliSecondOf(Now) ; end;function TStopWatch.GetElapsed: string;var   Ã‚  dt : TDateTime; begin   Ã‚  dt : ElapsedMilliseconds / MSecsPerSec / SecsPerDay;   Ã‚  result : Format(%d days, %s, [trunc(dt), FormatDateTime(hh:nn:ss.z, Frac(dt))]) ; end;function TStopWatch.GetElapsedMilliseconds: TLargeInteger;begin   Ã‚  result : (MSecsPerSec * (fStopCount - fStartCount)) div fFrequency; end;procedure TStopWatch.Start;begin   Ã‚  SetTickStamp(fStartCount) ;   Ã‚  fIsRunning : true; end;procedure TStopWatch.Stop;begin   Ã‚  SetTickStamp(fStopCount) ;   Ã‚  fIsRunning : false; end;end. Heres an example of usage: var   Ã‚  sw : TStopWatch;   Ã‚  elapsedMilliseconds : cardinal; begin   Ã‚  sw : TStopWatch.Create() ;   Ã‚  try   Ã‚  Ã‚  Ã‚  sw.Start;   Ã‚  Ã‚  Ã‚  //TimeOutThisFunction()   Ã‚  Ã‚  Ã‚  sw.Stop;   Ã‚  Ã‚  Ã‚  elapsedMilliseconds : sw.ElapsedMilliseconds;   Ã‚  finally   Ã‚  Ã‚  Ã‚  sw.Free;   Ã‚  end;end;

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.