system.diagnostics.pp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2023 the Free Pascal development team.
  4. Delphi compatibility unit to provide a stopwatch.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. // Todo: better resolution for non-windows, non-linux:
  12. // macos should have mach_absolute_time somewhere.
  13. // FreeBSD should have clock_gettime routines, but they seem not to be exposed in FPC units?
  14. unit system.diagnostics;
  15. {$mode objfpc}
  16. {$modeswitch advancedrecords}
  17. interface
  18. uses System.TimeSpan;
  19. const
  20. StopWatchResolution = 10*1000*1000; // 0.1 microsecond
  21. TicksPerMillisecond = 10*1000;
  22. TicksPerSecond = StopWatchResolution;
  23. type
  24. { TStopwatch }
  25. TStopwatch = record
  26. private
  27. class var _Frequency: Int64;
  28. class var _IsHighResolution: Boolean;
  29. class var _TickFrequency: Double;
  30. Class procedure _Init; static;
  31. private
  32. FElapsed: Int64;
  33. FRunning: Boolean;
  34. FStartTimeStamp: Int64;
  35. function GetElapsedTimespanTicks: Int64; inline;
  36. function GetElapsed: TTimeSpan;
  37. function GetElapsedMilliseconds: Int64;
  38. function GetElapsedTicks: Int64;
  39. public
  40. class function Create: TStopwatch; static;
  41. class function GetTimeStamp: Int64; static;
  42. class function StartNew: TStopwatch; static;
  43. class property Frequency: Int64 read _Frequency;
  44. class property IsHighResolution: Boolean read _IsHighResolution;
  45. public
  46. procedure Reset;
  47. procedure Start;
  48. procedure Stop;
  49. property Elapsed: TTimeSpan read GetElapsed;
  50. property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
  51. property ElapsedTicks: Int64 read GetElapsedTicks;
  52. property IsRunning: Boolean read FRunning;
  53. end;
  54. implementation
  55. uses
  56. {$IFDEF FPC_DOTTEDUNITS}
  57. {$IFDEF WINDOWS}
  58. Winapi.Windows,
  59. {$ELSE}
  60. {$IFDEF LINUX}
  61. UnixApi.Types,
  62. LinuxApi,
  63. {$ENDIF LINUX}
  64. {$ENDIF WINDOWS}
  65. System.SysUtils;
  66. {$ELSE FPC_DOTTEDUNITS}
  67. {$IFDEF WINDOWS}
  68. Windows,
  69. {$ELSE}
  70. {$IFDEF LINUX}
  71. UnixType,
  72. Linux,
  73. {$ENDIF LINUX}
  74. {$ENDIF WINDOWS}
  75. SysUtils;
  76. {$ENDIF FPC_DOTTEDUNITS}
  77. { TStopwatch }
  78. function TStopwatch.GetElapsedTimespanTicks: Int64;
  79. begin
  80. Result:=ElapsedTicks;
  81. if _IsHighResolution then
  82. Result:=Trunc(Result*_TickFrequency);
  83. end;
  84. function TStopwatch.GetElapsed: TTimeSpan;
  85. begin
  86. Result:=TTimeSpan.Create(GetElapsedTimeSpanTicks);
  87. end;
  88. function TStopwatch.GetElapsedMilliseconds: Int64;
  89. begin
  90. Result:=GetElapsedTimeSpanTicks div TicksPerMillisecond;
  91. end;
  92. function TStopwatch.GetElapsedTicks: Int64;
  93. begin
  94. Result:=FElapsed;
  95. if Not FRunning then
  96. exit;
  97. Result:=Result+GetTimeStamp-FStartTimeStamp;
  98. end;
  99. class function TStopwatch.Create: TStopwatch;
  100. begin
  101. Result.Reset;
  102. end;
  103. class function TStopwatch.StartNew: TStopwatch;
  104. begin
  105. Result.Reset;
  106. Result.Start;
  107. end;
  108. procedure TStopwatch.Reset;
  109. begin
  110. FElapsed:=0;
  111. FRunning:=False;
  112. FStartTimeStamp:=0;
  113. end;
  114. procedure TStopwatch.Start;
  115. begin
  116. if FRunning then
  117. exit;
  118. FRunning:=True;
  119. FStartTimeStamp:=GetTimeStamp;
  120. end;
  121. procedure TStopwatch.Stop;
  122. begin
  123. if Not FRunning then
  124. exit;
  125. FRunning:=False;
  126. Inc(FElapsed,(GetTimeStamp-FStartTimeStamp));
  127. end;
  128. {$IFDEF LINUX}
  129. class function TStopwatch.GetTimeStamp: Int64;
  130. var
  131. res: timespec;
  132. begin
  133. clock_gettime(CLOCK_MONOTONIC, @res);
  134. Result:=((Int64(1000000000)*res.tv_sec)+res.tv_nsec) div 100;
  135. end;
  136. class procedure TStopwatch._Init;
  137. begin
  138. _IsHighResolution:=True;
  139. _Frequency:=StopWatchResolution;
  140. _TickFrequency:=1;
  141. end;
  142. {$ELSE UNIX}
  143. {$IFDEF WINDOWS}
  144. class function TStopwatch.GetTimeStamp: Int64;
  145. begin
  146. if _IsHighResolution then
  147. QueryPerformanceCounter(Result)
  148. else
  149. Result:=GetTickCount64*TicksPerMillisecond;
  150. end;
  151. class procedure TStopWatch._Init;
  152. begin
  153. _IsHighResolution:=QueryPerformanceFrequency(_Frequency);
  154. if _IsHighResolution then
  155. TStopWatch._TickFrequency:=StopWatchResolution/_Frequency
  156. else
  157. begin
  158. _TickFrequency:=1;
  159. _Frequency:=TicksPerSecond;
  160. end;
  161. end;
  162. {$ELSE WINDOWS}
  163. class procedure TStopWatch._Init;
  164. begin
  165. _IsHighResolution:=False;
  166. _TickFrequency:=1;
  167. _Frequency:=TicksPerSecond;
  168. end;
  169. class function TStopwatch.GetTimeStamp: Int64;
  170. begin
  171. Result:=GetTickCount*TicksPerMillisecond;
  172. end;
  173. {$ENDIF WINDOWS}
  174. {$ENDIF UNIX}
  175. initialization
  176. TStopWatch._Init;
  177. end.