123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2023 the Free Pascal development team.
- Delphi compatibility unit to provide a stopwatch.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- // Todo: better resolution for non-windows, non-linux:
- // macos should have mach_absolute_time somewhere.
- // FreeBSD should have clock_gettime routines, but they seem not to be exposed in FPC units?
- unit system.diagnostics;
- {$mode objfpc}
- {$modeswitch advancedrecords}
- interface
- uses System.TimeSpan;
- const
- StopWatchResolution = 10*1000*1000; // 0.1 microsecond
- TicksPerMillisecond = 10*1000;
- TicksPerSecond = StopWatchResolution;
- type
- { TStopwatch }
- TStopwatch = record
- private
- class var _Frequency: Int64;
- class var _IsHighResolution: Boolean;
- class var _TickFrequency: Double;
- Class procedure _Init; static;
- private
- FElapsed: Int64;
- FRunning: Boolean;
- FStartTimeStamp: Int64;
- function GetElapsedTimespanTicks: Int64; inline;
- function GetElapsed: TTimeSpan;
- function GetElapsedMilliseconds: Int64;
- function GetElapsedTicks: Int64;
- public
- class function Create: TStopwatch; static;
- class function GetTimeStamp: Int64; static;
- class function StartNew: TStopwatch; static;
- class property Frequency: Int64 read _Frequency;
- class property IsHighResolution: Boolean read _IsHighResolution;
- public
- procedure Reset;
- procedure Start;
- procedure Stop;
- property Elapsed: TTimeSpan read GetElapsed;
- property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
- property ElapsedTicks: Int64 read GetElapsedTicks;
- property IsRunning: Boolean read FRunning;
- end;
- implementation
- uses
- {$IFDEF FPC_DOTTEDUNITS}
- {$IFDEF WINDOWS}
- Winapi.Windows,
- {$ELSE}
- {$IFDEF LINUX}
- UnixApi.Types,
- LinuxApi,
- {$ENDIF LINUX}
- {$ENDIF WINDOWS}
- System.SysUtils;
- {$ELSE FPC_DOTTEDUNITS}
- {$IFDEF WINDOWS}
- Windows,
- {$ELSE}
- {$IFDEF LINUX}
- UnixType,
- Linux,
- {$ENDIF LINUX}
- {$ENDIF WINDOWS}
- SysUtils;
- {$ENDIF FPC_DOTTEDUNITS}
- { TStopwatch }
- function TStopwatch.GetElapsedTimespanTicks: Int64;
- begin
- Result:=ElapsedTicks;
- if _IsHighResolution then
- Result:=Trunc(Result*_TickFrequency);
- end;
- function TStopwatch.GetElapsed: TTimeSpan;
- begin
- Result:=TTimeSpan.Create(GetElapsedTimeSpanTicks);
- end;
- function TStopwatch.GetElapsedMilliseconds: Int64;
- begin
- Result:=GetElapsedTimeSpanTicks div TicksPerMillisecond;
- end;
- function TStopwatch.GetElapsedTicks: Int64;
- begin
- Result:=FElapsed;
- if Not FRunning then
- exit;
- Result:=Result+GetTimeStamp-FStartTimeStamp;
- end;
- class function TStopwatch.Create: TStopwatch;
- begin
- Result.Reset;
- end;
- class function TStopwatch.StartNew: TStopwatch;
- begin
- Result.Reset;
- Result.Start;
- end;
- procedure TStopwatch.Reset;
- begin
- FElapsed:=0;
- FRunning:=False;
- FStartTimeStamp:=0;
- end;
- procedure TStopwatch.Start;
- begin
- if FRunning then
- exit;
- FRunning:=True;
- FStartTimeStamp:=GetTimeStamp;
- end;
- procedure TStopwatch.Stop;
- begin
- if Not FRunning then
- exit;
- FRunning:=False;
- Inc(FElapsed,(GetTimeStamp-FStartTimeStamp));
- end;
- {$IFDEF LINUX}
- class function TStopwatch.GetTimeStamp: Int64;
- var
- res: timespec;
- begin
- clock_gettime(CLOCK_MONOTONIC, @res);
- Result:=((StopWatchResolution*res.tv_sec)+res.tv_nsec) div 100;
- end;
- class procedure TStopwatch._Init;
- begin
- _IsHighResolution:=True;
- _Frequency:=StopWatchResolution;
- _TickFrequency:=1;
- end;
- {$ELSE UNIX}
- {$IFDEF WINDOWS}
- class function TStopwatch.GetTimeStamp: Int64;
- begin
- if _IsHighResolution then
- QueryPerformanceCounter(Result)
- else
- Result:=GetTickCount64*TicksPerMillisecond;
- end;
- class procedure TStopWatch._Init;
- begin
- _IsHighResolution:=QueryPerformanceFrequency(_Frequency);
- if _IsHighResolution then
- TStopWatch._TickFrequency:=StopWatchResolution/_Frequency
- else
- begin
- _TickFrequency:=1;
- _Frequency:=TicksPerSecond;
- end;
- end;
- {$ELSE WINDOWS}
- class procedure TStopWatch._Init;
- begin
- _IsHighResolution:=False;
- _TickFrequency:=1;
- _Frequency:=TicksPerSecond;
- end;
- class function TStopwatch.GetTimeStamp: Int64;
- begin
- Result:=GetTickCount*TicksPerMillisecond;
- end;
- {$ENDIF WINDOWS}
- {$ENDIF UNIX}
- initialization
- TStopWatch._Init;
- end.
|