fpc/tests/bench/bdiv.pp
2024-07-26 21:48:20 +02:00

717 lines
18 KiB
ObjectPascal

{ %OPT=-O2 }
program bdiv;
{$mode objfpc}{$H+}
uses
SysUtils;
{ Utility functions }
function GetRealTime(const st: TSystemTime): Real;
begin
Result := st.Hour*3600.0 + st.Minute*60.0 + st.Second + st.MilliSecond/1000.0;
end;
{$push}
{$warn 5057 off}
function GetRealTime : Real;
var
st:TSystemTime;
begin
GetLocalTime(st);
result:=GetRealTime(st);
end;
{$pop}
const
{$if defined(cpuarm) or defined(cpuavr) or defined(cpui8086) or defined(cpum68k) or defined(cpumips) or defined(cpuz80) or defined(cpuriscv32)}
{$define slowcpu}
{$endif}
{$ifdef slowcpu}
ITERATIONS = 32768;
{$else slowcpu}
ITERATIONS = 524288;
{$endif slowcpu}
INTERNAL_LOOPS = 64;
{ TTestAncestor }
type
TTestAncestor = class
private
FStartTime: Real;
FEndTime: Real;
FAvgTime: Real;
procedure SetStartTime;
procedure SetEndTime;
protected
procedure DoTestIteration(Iteration: Integer); virtual; abstract;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Run;
function TestTitle: shortstring; virtual; abstract;
function WriteResults: Boolean; virtual; abstract;
property RunTime: Real read FAvgTime;
end;
TTestClass = class of TTestAncestor;
TUInt16DivTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Word;
FResultArray: array[$00..$FF] of Word;
function GetDivisor: Word; virtual; abstract;
function DoVariableDiv(Numerator: Word): Word; inline;
public
function WriteResults: Boolean; override;
end;
TUInt16ModTest = class(TUInt16DivTest)
protected
function DoVariableMod(Numerator: Word): Word; inline;
public
function WriteResults: Boolean; override;
end;
TUInt32DivTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Cardinal;
FResultArray: array[$00..$FF] of Cardinal;
function GetDivisor: Cardinal; virtual; abstract;
function DoVariableDiv(Numerator: Cardinal): Cardinal; inline;
public
function WriteResults: Boolean; override;
end;
TUInt32ModTest = class(TUInt32DivTest)
protected
function DoVariableMod(Numerator: Cardinal): Cardinal; inline;
public
function WriteResults: Boolean; override;
end;
TSInt32DivTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Integer;
FResultArray: array[$00..$FF] of Integer;
function GetDivisor: Integer; virtual; abstract;
function DoVariableDiv(Numerator: Integer): Integer; inline;
public
function WriteResults: Boolean; override;
end;
TSInt32ModTest = class(TSInt32DivTest)
protected
function DoVariableMod(Numerator: Integer): Integer; inline;
public
function WriteResults: Boolean; override;
end;
TUInt64DivTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of QWord;
FResultArray: array[$00..$FF] of QWord;
function GetDivisor: QWord; virtual; abstract;
function DoVariableDiv(Numerator: QWord): QWord; inline;
public
function WriteResults: Boolean; override;
end;
TUInt64ModTest = class(TUInt64DivTest)
protected
function DoVariableMod(Numerator: QWord): QWord; inline;
public
function WriteResults: Boolean; override;
end;
TSInt64DivTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Int64;
FResultArray: array[$00..$FF] of Int64;
function GetDivisor: Int64; virtual; abstract;
function DoVariableDiv(Numerator: Int64): Int64; inline;
public
function WriteResults: Boolean; override;
end;
TSInt64ModTest = class(TSInt64DivTest)
protected
function DoVariableMod(Numerator: Int64): Int64; inline;
public
function WriteResults: Boolean; override;
end;
TUInt32ModCmpTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Cardinal;
FResultArray: array[$00..$FF] of Boolean;
function GetDivisor: Cardinal; virtual; abstract;
function DoMod0(Numerator: Cardinal): Boolean; inline;
public
function WriteResults: Boolean; override;
end;
TSInt32ModCmpTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Integer;
FResultArray: array[$00..$FF] of Boolean;
function GetDivisor: Integer; virtual; abstract;
function DoMod0(Numerator: Integer): Boolean; inline;
public
function WriteResults: Boolean; override;
end;
TUInt64ModCmpTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of QWord;
FResultArray: array[$00..$FF] of Boolean;
function GetDivisor: QWord; virtual; abstract;
function DoMod0(Numerator: QWord): Boolean; inline;
public
function WriteResults: Boolean; override;
end;
TSInt64ModCmpTest = class(TTestAncestor)
protected
FInputArray: array[$00..$FF] of Int64;
FResultArray: array[$00..$FF] of Boolean;
function GetDivisor: Int64; virtual; abstract;
function DoMod0(Numerator: Int64): Boolean; inline;
public
function WriteResults: Boolean; override;
end;
{$I bdiv_u16.inc}
{$I bdiv_u32.inc}
{$I bdiv_u64.inc}
{$I bdiv_s32.inc}
{$I bdiv_s64.inc}
{ TTestAncestor }
constructor TTestAncestor.Create;
begin
FStartTime := 0;
FEndTime := 0;
FAvgTime := 0;
end;
destructor TTestAncestor.Destroy;
begin
inherited Destroy;
end;
procedure TTestAncestor.SetStartTime;
begin
FStartTime := GetRealTime();
end;
procedure TTestAncestor.SetEndTime;
begin
FEndTime := GetRealTime();
if FEndTime < FStartTime then { Happens if the test runs past midnight }
FEndTime := FEndTime + 86400.0;
end;
procedure TTestAncestor.Run;
var
X: Integer;
begin
SetStartTime;
for X := 0 to ITERATIONS - 1 do
DoTestIteration(X);
SetEndTime;
FAvgTime := FEndTime - FStartTime;
end;
{ TUInt16DivTest }
function TUInt16DivTest.DoVariableDiv(Numerator: Word): Word;
begin
Result := Numerator div GetDivisor;
end;
function TUInt16DivTest.WriteResults: Boolean;
var
X: Integer;
Expected: Word;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableDiv(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt16ModTest }
function TUInt16ModTest.DoVariableMod(Numerator: Word): Word;
begin
Result := Numerator mod GetDivisor;
end;
function TUInt16ModTest.WriteResults: Boolean;
var
X: Integer;
Expected: Word;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableMod(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt32DivTest }
function TUInt32DivTest.DoVariableDiv(Numerator: Cardinal): Cardinal;
begin
Result := Numerator div GetDivisor;
end;
function TUInt32DivTest.WriteResults: Boolean;
var
X: Integer;
Expected: Cardinal;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableDiv(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt32ModTest }
function TUInt32ModTest.DoVariableMod(Numerator: Cardinal): Cardinal;
begin
Result := Numerator mod GetDivisor;
end;
function TUInt32ModTest.WriteResults: Boolean;
var
X: Integer;
Expected: Cardinal;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableMod(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt32DivTest }
function TSInt32DivTest.DoVariableDiv(Numerator: Integer): Integer;
begin
Result := Numerator div GetDivisor;
end;
function TSInt32DivTest.WriteResults: Boolean;
var
X: Integer;
Expected: Integer;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableDiv(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt32ModTest }
function TSInt32ModTest.DoVariableMod(Numerator: Integer): Integer;
begin
Result := Numerator mod GetDivisor;
end;
function TSInt32ModTest.WriteResults: Boolean;
var
X: Integer;
Expected: Integer;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableMod(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt64DivTest }
function TUInt64DivTest.DoVariableDiv(Numerator: QWord): QWord;
begin
Result := Numerator div GetDivisor;
end;
function TUInt64DivTest.WriteResults: Boolean;
var
X: Integer;
Expected: QWord;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableDiv(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt64ModTest }
function TUInt64ModTest.DoVariableMod(Numerator: QWord): QWord;
begin
Result := Numerator mod GetDivisor;
end;
function TUInt64ModTest.WriteResults: Boolean;
var
X: Integer;
Expected: QWord;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableMod(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt64DivTest }
function TSInt64DivTest.DoVariableDiv(Numerator: Int64): Int64;
begin
Result := Numerator div GetDivisor;
end;
function TSInt64DivTest.WriteResults: Boolean;
var
X: Integer;
Expected: Int64;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableDiv(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt64ModTest }
function TSInt64ModTest.DoVariableMod(Numerator: Int64): Int64;
begin
Result := Numerator mod GetDivisor;
end;
function TSInt64ModTest.WriteResults: Boolean;
var
X: Integer;
Expected: Int64;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoVariableMod(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt32ModCmpTest }
function TSInt32ModCmpTest.DoMod0(Numerator: Integer): Boolean;
begin
Result := (Numerator mod GetDivisor) = 0;
end;
function TSInt32ModCmpTest.WriteResults: Boolean;
var
X: Integer;
Expected: Boolean;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoMod0(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - (', FInputArray[X], ' mod ', GetDivisor, ') = 0; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt32ModCmpTest }
function TUInt32ModCmpTest.DoMod0(Numerator: Cardinal): Boolean;
begin
Result := (Numerator mod GetDivisor) = 0;
end;
function TUInt32ModCmpTest.WriteResults: Boolean;
var
X: Integer;
Expected: Boolean;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoMod0(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - (', FInputArray[X], ' mod ', GetDivisor, ') = 0; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TSInt64ModCmpTest }
function TSInt64ModCmpTest.DoMod0(Numerator: Int64): Boolean;
begin
Result := (Numerator mod GetDivisor) = 0;
end;
function TSInt64ModCmpTest.WriteResults: Boolean;
var
X: Integer;
Expected: Boolean;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoMod0(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - (', FInputArray[X], ' mod ', GetDivisor, ') = 0; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ TUInt64ModCmpTest }
function TUInt64ModCmpTest.DoMod0(Numerator: QWord): Boolean;
begin
Result := (Numerator mod GetDivisor) = 0;
end;
function TUInt64ModCmpTest.WriteResults: Boolean;
var
X: Integer;
Expected: Boolean;
begin
Result := True;
for X := 0 to 255 do
begin
Expected := DoMod0(FInputArray[X]);
if FResultArray[X] <> Expected then
begin
WriteLn('FAIL - (', FInputArray[X], ' mod ', GetDivisor, ') = 0; expected ', Expected, ' got ', FResultArray[X]);
Result := False;
Exit;
end;
end;
end;
{ Main function }
const
TestClasses: array[0..84] of TTestClass = (
TUInt16Bit1Test,
TUInt16Bit1ModTest,
TUInt16Bit2Test,
TUInt16Bit2ModTest,
TUInt16Bit3Test,
TUInt16Bit3ModTest,
TUInt16Bit7Test,
TUInt16Bit7ModTest,
TUInt16Bit10Test,
TUInt16Bit10ModTest,
TUInt16Bit100Test,
TUInt16Bit100ModTest,
TUInt16Bit1000Test,
TUInt16Bit1000ModTest,
TUInt32Bit1Test,
TUInt32Bit1ModTest,
TUInt32Bit2Test,
TUInt32Bit2ModTest,
TUInt32Bit3Test,
TUInt32Bit3ModTest,
TUInt32Bit7Test,
TUInt32Bit7ModTest,
TUInt32Bit10Test,
TUInt32Bit10ModTest,
TUInt32Bit100Test,
TUInt32Bit100ModTest,
TUInt32Bit1000Test,
TUInt32Bit1000ModTest,
TUInt32Bit60000Test,
TUInt32Bit60000ModTest,
TUInt32Bit146097Test,
TUInt32Bit146097ModTest,
TUInt32Bit3600000Test,
TUInt32Bit3600000ModTest,
TUInt64Bit1Test,
TUInt64Bit1ModTest,
TUInt64Bit2Test,
TUInt64Bit2ModTest,
TUInt64Bit3Test,
TUInt64Bit3ModTest,
TUInt64Bit7Test,
TUInt64Bit7ModTest,
TUInt64Bit10Test,
TUInt64Bit10ModTest,
TUInt64Bit100Test,
TUInt64Bit100ModTest,
TUInt64Bit1000000000Test,
TUInt64Bit1000000000ModTest,
TSInt32Bit1Test,
TSInt32Bit1ModTest,
TSInt32Bit100Test,
TSInt32Bit100ModTest,
TSInt64Bit1Test,
TSInt64Bit1ModTest,
TSInt64Bit10Test,
TSInt64Bit10ModTest,
TSInt64Bit18Test,
TSInt64Bit18ModTest,
TSInt64Bit24Test,
TSInt64Bit24ModTest,
TSInt64Bit100Test,
TSInt64Bit100ModTest,
TSInt64Bit153Test,
TSInt64Bit153ModTest,
TSInt64Bit1461Test,
TSInt64Bit1461ModTest,
TSInt64Bit10000Test,
TSInt64Bit10000ModTest,
TSInt64Bit86400000Test,
TSInt64Bit86400000ModTest,
TUInt32Bit3ModCmpTest,
TSInt32Bit3ModCmpTest,
TUInt32Bit10ModCmpTest,
TSInt32Bit10ModCmpTest,
TUInt32Bit100ModCmpTest,
TSInt32Bit100ModCmpTest,
TUInt32Bit400ModCmpTest,
TUInt32Bit1000ModCmpTest,
TUInt64Bit3ModCmpTest,
TSInt64Bit3ModCmpTest,
TUInt64Bit10ModCmpTest,
TSInt64Bit10000ModCmpTest,
TUInt64Bit100ModCmpTest,
TSInt64Bit86400000ModCmpTest,
TUInt64Bit1000000000ModCmpTest
);
var
CurrentObject: TTestAncestor;
Failed: Boolean;
X: Integer;
SummedUpAverageDuration, AverageDuration : Double;
begin
SummedUpAverageDuration := 0.0;
Failed := False;
WriteLn('Division compilation and timing test (using constants from System and Sysutils)');
WriteLn('-------------------------------------------------------------------------------');
for X := Low(TestClasses) to High(TestClasses) do
begin
try
CurrentObject := TestClasses[X].Create;
try
Write(CurrentObject.TestTitle:43, ' - ');
CurrentObject.Run;
if CurrentObject.WriteResults then
begin
AverageDuration := ((CurrentObject.RunTime * 1000000000.0) / (ITERATIONS * INTERNAL_LOOPS));
WriteLn('Pass - average iteration duration: ', AverageDuration:1:3, ' ns');
SummedUpAverageDuration := SummedUpAverageDuration + AverageDuration;
end
else
{ Final average isn't processed if a test failed, so there's no need
to calculate and add the average duration to it }
Failed := True;
finally
CurrentObject.Free;
end;
except on E: Exception do
begin
WriteLn('Exception "', E.ClassName, '" raised while running test object of class "', TestClasses[X].ClassName, '"');
Failed := True;
end;
end;
end;
if Failed then
Halt(1);
WriteLn(#10'ok');
WriteLn('- Sum of average durations: ', SummedUpAverageDuration:1:3, ' ns');
WriteLn('- Overall average duration: ', (SummedUpAverageDuration / Length(TestClasses)):1:3, ' ns');
end.