bdiv.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. { %OPT=-O2 }
  2. program bdiv;
  3. {$mode objfpc}{$H+}
  4. uses
  5. SysUtils;
  6. { Utility functions }
  7. function GetRealTime(const st: TSystemTime): Real;
  8. begin
  9. Result := st.Hour*3600.0 + st.Minute*60.0 + st.Second + st.MilliSecond/1000.0;
  10. end;
  11. {$push}
  12. {$warn 5057 off}
  13. function GetRealTime : Real;
  14. var
  15. st:TSystemTime;
  16. begin
  17. GetLocalTime(st);
  18. result:=GetRealTime(st);
  19. end;
  20. {$pop}
  21. const
  22. ITERATIONS = 524288;
  23. INTERNAL_LOOPS = 64;
  24. { TTestAncestor }
  25. type
  26. TTestAncestor = class
  27. private
  28. FStartTime: Real;
  29. FEndTime: Real;
  30. FAvgTime: Real;
  31. procedure SetStartTime;
  32. procedure SetEndTime;
  33. protected
  34. procedure DoTestIteration(Iteration: Integer); virtual; abstract;
  35. public
  36. constructor Create; virtual;
  37. destructor Destroy; override;
  38. procedure Run;
  39. function TestTitle: shortstring; virtual; abstract;
  40. function WriteResults: Boolean; virtual; abstract;
  41. property RunTime: Real read FAvgTime;
  42. end;
  43. TTestClass = class of TTestAncestor;
  44. TUInt32DivTest = class(TTestAncestor)
  45. protected
  46. FInputArray: array[$00..$FF] of Cardinal;
  47. FResultArray: array[$00..$FF] of Cardinal;
  48. function GetDivisor: Cardinal; virtual; abstract;
  49. function DoVariableDiv(Numerator: Cardinal): Cardinal; inline;
  50. public
  51. function WriteResults: Boolean; override;
  52. end;
  53. TUInt32ModTest = class(TUInt32DivTest)
  54. protected
  55. function DoVariableMod(Numerator: Cardinal): Cardinal; inline;
  56. public
  57. function WriteResults: Boolean; override;
  58. end;
  59. TSInt32DivTest = class(TTestAncestor)
  60. protected
  61. FInputArray: array[$00..$FF] of Integer;
  62. FResultArray: array[$00..$FF] of Integer;
  63. function GetDivisor: Integer; virtual; abstract;
  64. function DoVariableDiv(Numerator: Integer): Integer; inline;
  65. public
  66. function WriteResults: Boolean; override;
  67. end;
  68. TSInt32ModTest = class(TSInt32DivTest)
  69. protected
  70. function DoVariableMod(Numerator: Integer): Integer; inline;
  71. public
  72. function WriteResults: Boolean; override;
  73. end;
  74. TUInt64DivTest = class(TTestAncestor)
  75. protected
  76. FInputArray: array[$00..$FF] of QWord;
  77. FResultArray: array[$00..$FF] of QWord;
  78. function GetDivisor: QWord; virtual; abstract;
  79. function DoVariableDiv(Numerator: QWord): QWord; inline;
  80. public
  81. function WriteResults: Boolean; override;
  82. end;
  83. TUInt64ModTest = class(TUInt64DivTest)
  84. protected
  85. function DoVariableMod(Numerator: QWord): QWord; inline;
  86. public
  87. function WriteResults: Boolean; override;
  88. end;
  89. TSInt64DivTest = class(TTestAncestor)
  90. protected
  91. FInputArray: array[$00..$FF] of Int64;
  92. FResultArray: array[$00..$FF] of Int64;
  93. function GetDivisor: Int64; virtual; abstract;
  94. function DoVariableDiv(Numerator: Int64): Int64; inline;
  95. public
  96. function WriteResults: Boolean; override;
  97. end;
  98. TSInt64ModTest = class(TSInt64DivTest)
  99. protected
  100. function DoVariableMod(Numerator: Int64): Int64; inline;
  101. public
  102. function WriteResults: Boolean; override;
  103. end;
  104. {$I bdiv_u32.inc}
  105. {$I bdiv_u64.inc}
  106. {$I bdiv_s32.inc}
  107. {$I bdiv_s64.inc}
  108. { TTestAncestor }
  109. constructor TTestAncestor.Create;
  110. begin
  111. FStartTime := 0;
  112. FEndTime := 0;
  113. FAvgTime := 0;
  114. end;
  115. destructor TTestAncestor.Destroy;
  116. begin
  117. inherited Destroy;
  118. end;
  119. procedure TTestAncestor.SetStartTime;
  120. begin
  121. FStartTime := GetRealTime();
  122. end;
  123. procedure TTestAncestor.SetEndTime;
  124. begin
  125. FEndTime := GetRealTime();
  126. if FEndTime < FStartTime then { Happens if the test runs past midnight }
  127. FEndTime := FEndTime + 86400.0;
  128. end;
  129. procedure TTestAncestor.Run;
  130. var
  131. X: Integer;
  132. begin
  133. SetStartTime;
  134. for X := 0 to ITERATIONS - 1 do
  135. DoTestIteration(X);
  136. SetEndTime;
  137. FAvgTime := FEndTime - FStartTime;
  138. end;
  139. { TUInt32DivTest }
  140. function TUInt32DivTest.DoVariableDiv(Numerator: Cardinal): Cardinal;
  141. begin
  142. Result := Numerator div GetDivisor;
  143. end;
  144. function TUInt32DivTest.WriteResults: Boolean;
  145. var
  146. X: Integer;
  147. Expected: Cardinal;
  148. begin
  149. Result := True;
  150. for X := 0 to 255 do
  151. begin
  152. Expected := DoVariableDiv(FInputArray[X]);
  153. if FResultArray[X] <> Expected then
  154. begin
  155. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  156. Result := False;
  157. Exit;
  158. end;
  159. end;
  160. end;
  161. { TUInt32ModTest }
  162. function TUInt32ModTest.DoVariableMod(Numerator: Cardinal): Cardinal;
  163. begin
  164. Result := Numerator mod GetDivisor;
  165. end;
  166. function TUInt32ModTest.WriteResults: Boolean;
  167. var
  168. X: Integer;
  169. Expected: Cardinal;
  170. begin
  171. Result := True;
  172. for X := 0 to 255 do
  173. begin
  174. Expected := DoVariableMod(FInputArray[X]);
  175. if FResultArray[X] <> Expected then
  176. begin
  177. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  178. Result := False;
  179. Exit;
  180. end;
  181. end;
  182. end;
  183. { TSInt32DivTest }
  184. function TSInt32DivTest.DoVariableDiv(Numerator: Integer): Integer;
  185. begin
  186. Result := Numerator div GetDivisor;
  187. end;
  188. function TSInt32DivTest.WriteResults: Boolean;
  189. var
  190. X: Integer;
  191. Expected: Integer;
  192. begin
  193. Result := True;
  194. for X := 0 to 255 do
  195. begin
  196. Expected := DoVariableDiv(FInputArray[X]);
  197. if FResultArray[X] <> Expected then
  198. begin
  199. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  200. Result := False;
  201. Exit;
  202. end;
  203. end;
  204. end;
  205. { TSInt32ModTest }
  206. function TSInt32ModTest.DoVariableMod(Numerator: Integer): Integer;
  207. begin
  208. Result := Numerator mod GetDivisor;
  209. end;
  210. function TSInt32ModTest.WriteResults: Boolean;
  211. var
  212. X: Integer;
  213. Expected: Integer;
  214. begin
  215. Result := True;
  216. for X := 0 to 255 do
  217. begin
  218. Expected := DoVariableMod(FInputArray[X]);
  219. if FResultArray[X] <> Expected then
  220. begin
  221. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  222. Result := False;
  223. Exit;
  224. end;
  225. end;
  226. end;
  227. { TUInt64DivTest }
  228. function TUInt64DivTest.DoVariableDiv(Numerator: QWord): QWord;
  229. begin
  230. Result := Numerator div GetDivisor;
  231. end;
  232. function TUInt64DivTest.WriteResults: Boolean;
  233. var
  234. X: Integer;
  235. Expected: QWord;
  236. begin
  237. Result := True;
  238. for X := 0 to 255 do
  239. begin
  240. Expected := DoVariableDiv(FInputArray[X]);
  241. if FResultArray[X] <> Expected then
  242. begin
  243. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  244. Result := False;
  245. Exit;
  246. end;
  247. end;
  248. end;
  249. { TUInt64ModTest }
  250. function TUInt64ModTest.DoVariableMod(Numerator: QWord): QWord;
  251. begin
  252. Result := Numerator mod GetDivisor;
  253. end;
  254. function TUInt64ModTest.WriteResults: Boolean;
  255. var
  256. X: Integer;
  257. Expected: QWord;
  258. begin
  259. Result := True;
  260. for X := 0 to 255 do
  261. begin
  262. Expected := DoVariableMod(FInputArray[X]);
  263. if FResultArray[X] <> Expected then
  264. begin
  265. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  266. Result := False;
  267. Exit;
  268. end;
  269. end;
  270. end;
  271. { TSInt64DivTest }
  272. function TSInt64DivTest.DoVariableDiv(Numerator: Int64): Int64;
  273. begin
  274. Result := Numerator div GetDivisor;
  275. end;
  276. function TSInt64DivTest.WriteResults: Boolean;
  277. var
  278. X: Integer;
  279. Expected: Int64;
  280. begin
  281. Result := True;
  282. for X := 0 to 255 do
  283. begin
  284. Expected := DoVariableDiv(FInputArray[X]);
  285. if FResultArray[X] <> Expected then
  286. begin
  287. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  288. Result := False;
  289. Exit;
  290. end;
  291. end;
  292. end;
  293. { TSInt64ModTest }
  294. function TSInt64ModTest.DoVariableMod(Numerator: Int64): Int64;
  295. begin
  296. Result := Numerator mod GetDivisor;
  297. end;
  298. function TSInt64ModTest.WriteResults: Boolean;
  299. var
  300. X: Integer;
  301. Expected: Int64;
  302. begin
  303. Result := True;
  304. for X := 0 to 255 do
  305. begin
  306. Expected := DoVariableMod(FInputArray[X]);
  307. if FResultArray[X] <> Expected then
  308. begin
  309. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  310. Result := False;
  311. Exit;
  312. end;
  313. end;
  314. end;
  315. { Main function }
  316. const
  317. TestClasses: array[0..53] of TTestClass = (
  318. TUInt32Bit1Test,
  319. TUInt32Bit1ModTest,
  320. TUInt32Bit2Test,
  321. TUInt32Bit2ModTest,
  322. TUInt32Bit3Test,
  323. TUInt32Bit3ModTest,
  324. TUInt32Bit10Test,
  325. TUInt32Bit10ModTest,
  326. TUInt32Bit100Test,
  327. TUInt32Bit100ModTest,
  328. TUInt32Bit1000Test,
  329. TUInt32Bit1000ModTest,
  330. TUInt32Bit60000Test,
  331. TUInt32Bit60000ModTest,
  332. TUInt32Bit146097Test,
  333. TUInt32Bit146097ModTest,
  334. TUInt32Bit3600000Test,
  335. TUInt32Bit3600000ModTest,
  336. TUInt64Bit1Test,
  337. TUInt64Bit1ModTest,
  338. TUInt64Bit2Test,
  339. TUInt64Bit2ModTest,
  340. TUInt64Bit3Test,
  341. TUInt64Bit3ModTest,
  342. TUInt64Bit5Test,
  343. TUInt64Bit5ModTest,
  344. TUInt64Bit10Test,
  345. TUInt64Bit10ModTest,
  346. TUInt64Bit100Test,
  347. TUInt64Bit100ModTest,
  348. TUInt64Bit1000000000Test,
  349. TUInt64Bit1000000000ModTest,
  350. TSInt32Bit1Test,
  351. TSInt32Bit1ModTest,
  352. TSInt32Bit100Test,
  353. TSInt32Bit100ModTest,
  354. TSInt64Bit1Test,
  355. TSInt64Bit1ModTest,
  356. TSInt64Bit10Test,
  357. TSInt64Bit10ModTest,
  358. TSInt64Bit18Test,
  359. TSInt64Bit18ModTest,
  360. TSInt64Bit24Test,
  361. TSInt64Bit24ModTest,
  362. TSInt64Bit100Test,
  363. TSInt64Bit100ModTest,
  364. TSInt64Bit153Test,
  365. TSInt64Bit153ModTest,
  366. TSInt64Bit1461Test,
  367. TSInt64Bit1461ModTest,
  368. TSInt64Bit10000Test,
  369. TSInt64Bit10000ModTest,
  370. TSInt64Bit86400000Test,
  371. TSInt64Bit86400000ModTest
  372. );
  373. var
  374. CurrentObject: TTestAncestor;
  375. Failed: Boolean;
  376. X: Integer;
  377. SummedUpAverageDuration, AverageDuration : Double;
  378. begin
  379. SummedUpAverageDuration := 0.0;
  380. Failed := False;
  381. WriteLn('Division compilation and timing test (using constants from System and Sysutils)');
  382. WriteLn('-------------------------------------------------------------------------------');
  383. for X := Low(TestClasses) to High(TestClasses) do
  384. begin
  385. try
  386. CurrentObject := TestClasses[X].Create;
  387. try
  388. Write(CurrentObject.TestTitle:43, ' - ');
  389. CurrentObject.Run;
  390. if CurrentObject.WriteResults then
  391. begin
  392. AverageDuration := ((CurrentObject.RunTime * 1000000000.0) / (ITERATIONS * INTERNAL_LOOPS));
  393. WriteLn('Pass - average iteration duration: ', AverageDuration:1:3, ' ns');
  394. SummedUpAverageDuration := SummedUpAverageDuration + AverageDuration;
  395. end
  396. else
  397. { Final average isn't processed if a test failed, so there's no need
  398. to calculate and add the average duration to it }
  399. Failed := True;
  400. finally
  401. CurrentObject.Free;
  402. end;
  403. except on E: Exception do
  404. begin
  405. WriteLn('Exception "', E.ClassName, '" raised while running test object of class "', TestClasses[X].ClassName, '"');
  406. Failed := True;
  407. end;
  408. end;
  409. end;
  410. if Failed then
  411. Halt(1);
  412. WriteLn(#10'ok');
  413. WriteLn('- Sum of average durations: ', SummedUpAverageDuration:1:3, ' ns');
  414. WriteLn('- Overall average duration: ', (SummedUpAverageDuration / Length(TestClasses)):1:3, ' ns');
  415. end.