bdiv.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  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. TUInt16DivTest = class(TTestAncestor)
  45. protected
  46. FInputArray: array[$00..$FF] of Word;
  47. FResultArray: array[$00..$FF] of Word;
  48. function GetDivisor: Word; virtual; abstract;
  49. function DoVariableDiv(Numerator: Word): Word; inline;
  50. public
  51. function WriteResults: Boolean; override;
  52. end;
  53. TUInt16ModTest = class(TUInt16DivTest)
  54. protected
  55. function DoVariableMod(Numerator: Word): Word; inline;
  56. public
  57. function WriteResults: Boolean; override;
  58. end;
  59. TUInt32DivTest = class(TTestAncestor)
  60. protected
  61. FInputArray: array[$00..$FF] of Cardinal;
  62. FResultArray: array[$00..$FF] of Cardinal;
  63. function GetDivisor: Cardinal; virtual; abstract;
  64. function DoVariableDiv(Numerator: Cardinal): Cardinal; inline;
  65. public
  66. function WriteResults: Boolean; override;
  67. end;
  68. TUInt32ModTest = class(TUInt32DivTest)
  69. protected
  70. function DoVariableMod(Numerator: Cardinal): Cardinal; inline;
  71. public
  72. function WriteResults: Boolean; override;
  73. end;
  74. TSInt32DivTest = class(TTestAncestor)
  75. protected
  76. FInputArray: array[$00..$FF] of Integer;
  77. FResultArray: array[$00..$FF] of Integer;
  78. function GetDivisor: Integer; virtual; abstract;
  79. function DoVariableDiv(Numerator: Integer): Integer; inline;
  80. public
  81. function WriteResults: Boolean; override;
  82. end;
  83. TSInt32ModTest = class(TSInt32DivTest)
  84. protected
  85. function DoVariableMod(Numerator: Integer): Integer; inline;
  86. public
  87. function WriteResults: Boolean; override;
  88. end;
  89. TUInt64DivTest = class(TTestAncestor)
  90. protected
  91. FInputArray: array[$00..$FF] of QWord;
  92. FResultArray: array[$00..$FF] of QWord;
  93. function GetDivisor: QWord; virtual; abstract;
  94. function DoVariableDiv(Numerator: QWord): QWord; inline;
  95. public
  96. function WriteResults: Boolean; override;
  97. end;
  98. TUInt64ModTest = class(TUInt64DivTest)
  99. protected
  100. function DoVariableMod(Numerator: QWord): QWord; inline;
  101. public
  102. function WriteResults: Boolean; override;
  103. end;
  104. TSInt64DivTest = class(TTestAncestor)
  105. protected
  106. FInputArray: array[$00..$FF] of Int64;
  107. FResultArray: array[$00..$FF] of Int64;
  108. function GetDivisor: Int64; virtual; abstract;
  109. function DoVariableDiv(Numerator: Int64): Int64; inline;
  110. public
  111. function WriteResults: Boolean; override;
  112. end;
  113. TSInt64ModTest = class(TSInt64DivTest)
  114. protected
  115. function DoVariableMod(Numerator: Int64): Int64; inline;
  116. public
  117. function WriteResults: Boolean; override;
  118. end;
  119. {$I bdiv_u16.inc}
  120. {$I bdiv_u32.inc}
  121. {$I bdiv_u64.inc}
  122. {$I bdiv_s32.inc}
  123. {$I bdiv_s64.inc}
  124. { TTestAncestor }
  125. constructor TTestAncestor.Create;
  126. begin
  127. FStartTime := 0;
  128. FEndTime := 0;
  129. FAvgTime := 0;
  130. end;
  131. destructor TTestAncestor.Destroy;
  132. begin
  133. inherited Destroy;
  134. end;
  135. procedure TTestAncestor.SetStartTime;
  136. begin
  137. FStartTime := GetRealTime();
  138. end;
  139. procedure TTestAncestor.SetEndTime;
  140. begin
  141. FEndTime := GetRealTime();
  142. if FEndTime < FStartTime then { Happens if the test runs past midnight }
  143. FEndTime := FEndTime + 86400.0;
  144. end;
  145. procedure TTestAncestor.Run;
  146. var
  147. X: Integer;
  148. begin
  149. SetStartTime;
  150. for X := 0 to ITERATIONS - 1 do
  151. DoTestIteration(X);
  152. SetEndTime;
  153. FAvgTime := FEndTime - FStartTime;
  154. end;
  155. { TUInt16DivTest }
  156. function TUInt16DivTest.DoVariableDiv(Numerator: Word): Word;
  157. begin
  158. Result := Numerator div GetDivisor;
  159. end;
  160. function TUInt16DivTest.WriteResults: Boolean;
  161. var
  162. X: Integer;
  163. Expected: Word;
  164. begin
  165. Result := True;
  166. for X := 0 to 255 do
  167. begin
  168. Expected := DoVariableDiv(FInputArray[X]);
  169. if FResultArray[X] <> Expected then
  170. begin
  171. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  172. Result := False;
  173. Exit;
  174. end;
  175. end;
  176. end;
  177. { TUInt16ModTest }
  178. function TUInt16ModTest.DoVariableMod(Numerator: Word): Word;
  179. begin
  180. Result := Numerator mod GetDivisor;
  181. end;
  182. function TUInt16ModTest.WriteResults: Boolean;
  183. var
  184. X: Integer;
  185. Expected: Word;
  186. begin
  187. Result := True;
  188. for X := 0 to 255 do
  189. begin
  190. Expected := DoVariableMod(FInputArray[X]);
  191. if FResultArray[X] <> Expected then
  192. begin
  193. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  194. Result := False;
  195. Exit;
  196. end;
  197. end;
  198. end;
  199. { TUInt32DivTest }
  200. function TUInt32DivTest.DoVariableDiv(Numerator: Cardinal): Cardinal;
  201. begin
  202. Result := Numerator div GetDivisor;
  203. end;
  204. function TUInt32DivTest.WriteResults: Boolean;
  205. var
  206. X: Integer;
  207. Expected: Cardinal;
  208. begin
  209. Result := True;
  210. for X := 0 to 255 do
  211. begin
  212. Expected := DoVariableDiv(FInputArray[X]);
  213. if FResultArray[X] <> Expected then
  214. begin
  215. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  216. Result := False;
  217. Exit;
  218. end;
  219. end;
  220. end;
  221. { TUInt32ModTest }
  222. function TUInt32ModTest.DoVariableMod(Numerator: Cardinal): Cardinal;
  223. begin
  224. Result := Numerator mod GetDivisor;
  225. end;
  226. function TUInt32ModTest.WriteResults: Boolean;
  227. var
  228. X: Integer;
  229. Expected: Cardinal;
  230. begin
  231. Result := True;
  232. for X := 0 to 255 do
  233. begin
  234. Expected := DoVariableMod(FInputArray[X]);
  235. if FResultArray[X] <> Expected then
  236. begin
  237. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  238. Result := False;
  239. Exit;
  240. end;
  241. end;
  242. end;
  243. { TSInt32DivTest }
  244. function TSInt32DivTest.DoVariableDiv(Numerator: Integer): Integer;
  245. begin
  246. Result := Numerator div GetDivisor;
  247. end;
  248. function TSInt32DivTest.WriteResults: Boolean;
  249. var
  250. X: Integer;
  251. Expected: Integer;
  252. begin
  253. Result := True;
  254. for X := 0 to 255 do
  255. begin
  256. Expected := DoVariableDiv(FInputArray[X]);
  257. if FResultArray[X] <> Expected then
  258. begin
  259. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  260. Result := False;
  261. Exit;
  262. end;
  263. end;
  264. end;
  265. { TSInt32ModTest }
  266. function TSInt32ModTest.DoVariableMod(Numerator: Integer): Integer;
  267. begin
  268. Result := Numerator mod GetDivisor;
  269. end;
  270. function TSInt32ModTest.WriteResults: Boolean;
  271. var
  272. X: Integer;
  273. Expected: Integer;
  274. begin
  275. Result := True;
  276. for X := 0 to 255 do
  277. begin
  278. Expected := DoVariableMod(FInputArray[X]);
  279. if FResultArray[X] <> Expected then
  280. begin
  281. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  282. Result := False;
  283. Exit;
  284. end;
  285. end;
  286. end;
  287. { TUInt64DivTest }
  288. function TUInt64DivTest.DoVariableDiv(Numerator: QWord): QWord;
  289. begin
  290. Result := Numerator div GetDivisor;
  291. end;
  292. function TUInt64DivTest.WriteResults: Boolean;
  293. var
  294. X: Integer;
  295. Expected: QWord;
  296. begin
  297. Result := True;
  298. for X := 0 to 255 do
  299. begin
  300. Expected := DoVariableDiv(FInputArray[X]);
  301. if FResultArray[X] <> Expected then
  302. begin
  303. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  304. Result := False;
  305. Exit;
  306. end;
  307. end;
  308. end;
  309. { TUInt64ModTest }
  310. function TUInt64ModTest.DoVariableMod(Numerator: QWord): QWord;
  311. begin
  312. Result := Numerator mod GetDivisor;
  313. end;
  314. function TUInt64ModTest.WriteResults: Boolean;
  315. var
  316. X: Integer;
  317. Expected: QWord;
  318. begin
  319. Result := True;
  320. for X := 0 to 255 do
  321. begin
  322. Expected := DoVariableMod(FInputArray[X]);
  323. if FResultArray[X] <> Expected then
  324. begin
  325. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  326. Result := False;
  327. Exit;
  328. end;
  329. end;
  330. end;
  331. { TSInt64DivTest }
  332. function TSInt64DivTest.DoVariableDiv(Numerator: Int64): Int64;
  333. begin
  334. Result := Numerator div GetDivisor;
  335. end;
  336. function TSInt64DivTest.WriteResults: Boolean;
  337. var
  338. X: Integer;
  339. Expected: Int64;
  340. begin
  341. Result := True;
  342. for X := 0 to 255 do
  343. begin
  344. Expected := DoVariableDiv(FInputArray[X]);
  345. if FResultArray[X] <> Expected then
  346. begin
  347. WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  348. Result := False;
  349. Exit;
  350. end;
  351. end;
  352. end;
  353. { TSInt64ModTest }
  354. function TSInt64ModTest.DoVariableMod(Numerator: Int64): Int64;
  355. begin
  356. Result := Numerator mod GetDivisor;
  357. end;
  358. function TSInt64ModTest.WriteResults: Boolean;
  359. var
  360. X: Integer;
  361. Expected: Int64;
  362. begin
  363. Result := True;
  364. for X := 0 to 255 do
  365. begin
  366. Expected := DoVariableMod(FInputArray[X]);
  367. if FResultArray[X] <> Expected then
  368. begin
  369. WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
  370. Result := False;
  371. Exit;
  372. end;
  373. end;
  374. end;
  375. { Main function }
  376. const
  377. TestClasses: array[0..69] of TTestClass = (
  378. TUInt16Bit1Test,
  379. TUInt16Bit1ModTest,
  380. TUInt16Bit2Test,
  381. TUInt16Bit2ModTest,
  382. TUInt16Bit3Test,
  383. TUInt16Bit3ModTest,
  384. TUInt16Bit7Test,
  385. TUInt16Bit7ModTest,
  386. TUInt16Bit10Test,
  387. TUInt16Bit10ModTest,
  388. TUInt16Bit100Test,
  389. TUInt16Bit100ModTest,
  390. TUInt16Bit1000Test,
  391. TUInt16Bit1000ModTest,
  392. TUInt32Bit1Test,
  393. TUInt32Bit1ModTest,
  394. TUInt32Bit2Test,
  395. TUInt32Bit2ModTest,
  396. TUInt32Bit3Test,
  397. TUInt32Bit3ModTest,
  398. TUInt32Bit7Test,
  399. TUInt32Bit7ModTest,
  400. TUInt32Bit10Test,
  401. TUInt32Bit10ModTest,
  402. TUInt32Bit100Test,
  403. TUInt32Bit100ModTest,
  404. TUInt32Bit1000Test,
  405. TUInt32Bit1000ModTest,
  406. TUInt32Bit60000Test,
  407. TUInt32Bit60000ModTest,
  408. TUInt32Bit146097Test,
  409. TUInt32Bit146097ModTest,
  410. TUInt32Bit3600000Test,
  411. TUInt32Bit3600000ModTest,
  412. TUInt64Bit1Test,
  413. TUInt64Bit1ModTest,
  414. TUInt64Bit2Test,
  415. TUInt64Bit2ModTest,
  416. TUInt64Bit3Test,
  417. TUInt64Bit3ModTest,
  418. TUInt64Bit7Test,
  419. TUInt64Bit7ModTest,
  420. TUInt64Bit10Test,
  421. TUInt64Bit10ModTest,
  422. TUInt64Bit100Test,
  423. TUInt64Bit100ModTest,
  424. TUInt64Bit1000000000Test,
  425. TUInt64Bit1000000000ModTest,
  426. TSInt32Bit1Test,
  427. TSInt32Bit1ModTest,
  428. TSInt32Bit100Test,
  429. TSInt32Bit100ModTest,
  430. TSInt64Bit1Test,
  431. TSInt64Bit1ModTest,
  432. TSInt64Bit10Test,
  433. TSInt64Bit10ModTest,
  434. TSInt64Bit18Test,
  435. TSInt64Bit18ModTest,
  436. TSInt64Bit24Test,
  437. TSInt64Bit24ModTest,
  438. TSInt64Bit100Test,
  439. TSInt64Bit100ModTest,
  440. TSInt64Bit153Test,
  441. TSInt64Bit153ModTest,
  442. TSInt64Bit1461Test,
  443. TSInt64Bit1461ModTest,
  444. TSInt64Bit10000Test,
  445. TSInt64Bit10000ModTest,
  446. TSInt64Bit86400000Test,
  447. TSInt64Bit86400000ModTest
  448. );
  449. var
  450. CurrentObject: TTestAncestor;
  451. Failed: Boolean;
  452. X: Integer;
  453. SummedUpAverageDuration, AverageDuration : Double;
  454. begin
  455. SummedUpAverageDuration := 0.0;
  456. Failed := False;
  457. WriteLn('Division compilation and timing test (using constants from System and Sysutils)');
  458. WriteLn('-------------------------------------------------------------------------------');
  459. for X := Low(TestClasses) to High(TestClasses) do
  460. begin
  461. try
  462. CurrentObject := TestClasses[X].Create;
  463. try
  464. Write(CurrentObject.TestTitle:43, ' - ');
  465. CurrentObject.Run;
  466. if CurrentObject.WriteResults then
  467. begin
  468. AverageDuration := ((CurrentObject.RunTime * 1000000000.0) / (ITERATIONS * INTERNAL_LOOPS));
  469. WriteLn('Pass - average iteration duration: ', AverageDuration:1:3, ' ns');
  470. SummedUpAverageDuration := SummedUpAverageDuration + AverageDuration;
  471. end
  472. else
  473. { Final average isn't processed if a test failed, so there's no need
  474. to calculate and add the average duration to it }
  475. Failed := True;
  476. finally
  477. CurrentObject.Free;
  478. end;
  479. except on E: Exception do
  480. begin
  481. WriteLn('Exception "', E.ClassName, '" raised while running test object of class "', TestClasses[X].ClassName, '"');
  482. Failed := True;
  483. end;
  484. end;
  485. end;
  486. if Failed then
  487. Halt(1);
  488. WriteLn(#10'ok');
  489. WriteLn('- Sum of average durations: ', SummedUpAverageDuration:1:3, ' ns');
  490. WriteLn('- Overall average duration: ', (SummedUpAverageDuration / Length(TestClasses)):1:3, ' ns');
  491. end.