If a Delphi record type contains managed fields Delphi uses special initialization and finalization routines for the record instances. Unfortunately these routines use some kind of RTTI information and slow; they could be made much faster.
I have written a simple benchmark to find out how the built-in record initialization/finalization routines can possibly slow down my BigInteger implementation:
program CustomBench; {$APPTYPE CONSOLE} uses SysUtils; type TIRec = record II: IInterface; end; TPRec = record PP: Pointer; end; procedure ITest(const AI: IInterface); var IR: TIRec; begin IR.II:= AI; end; procedure PTest(const AI: IInterface); var PR: TPRec; begin PR.PP:= nil; // custom initialization try IInterface(PR.PP):= AI; finally IInterface(PR.PP):= nil; // custom finalization; end; end; procedure TestI(const AI: IInterface; Count: Integer); begin while Count > 0 do begin ITest(AI); Dec(Count); end; end; procedure TestP(const AI: IInterface; Count: Integer); begin while Count > 0 do begin PTest(AI); Dec(Count); end; end; procedure BenchMark(Count: Integer); const MillisPerDay = 24 * 60 * 60 * 1000; var II: IInterface; StartTime: TDateTime; ElapsedMillis1: Integer; ElapsedMillis2: Integer; begin II:= TInterfacedObject.Create; StartTime:= Now; TestI(II, Count); ElapsedMillis1:= Round((Now - StartTime) * MillisPerDay); Writeln('Built-in initialization/finalization: ', ElapsedMillis1, ' ms.'); StartTime:= Now; TestP(II, Count); ElapsedMillis2:= Round((Now - StartTime) * MillisPerDay); Writeln('Custom initialization/finalization: ', ElapsedMillis2, ' ms.'); Writeln('Built-in slowdown: ', Round((ElapsedMillis1/ElapsedMillis2 - 1) * 100), '%'); II:= nil; end; begin try BenchMark(10000000); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; ReadLn; end.
The typical result I am getting on my laptop (Delphi XE, 32 bits) is:
Not a showstopper, the actual slowdown for a real code which is doing something will be significantly less, still the slowdown is not negligible.