Recent

Author Topic: [SOLVED]I found some really neat Delphi code on my disk, but forgot its author.  (Read 719 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 15545
  • Censorship about opinions does not belong here.
I found some really neat Delphi code on my disk, but forgot its author. Anybody?
I just adapted it to freepascal. "am" may stand for Anders Melander, but not sure:
Code: Pascal  [Select][+][-]
  1. program am_profiler;
  2. {$ifdef fpc}
  3. {$mode delphi}
  4.   {$modeswitch functionreferences}
  5.   {$modeswitch anonymousfunctions}
  6. {$Endif}
  7. {$APPTYPE CONSOLE}
  8.  
  9. uses
  10.   Windows, SysUtils;
  11.  
  12. type
  13. {$ifdef fpc delphi has these predefined in system.sysutils}
  14.   TFunc<T> = reference to function:T;
  15.   TProc = reference to procedure;
  16.   TProc<T1,T2> = reference to procedure(a:T1;b:T2);
  17. {$endif}
  18.   TBenchmarker = class
  19.   private
  20.     const
  21.       DefaultIterations = 3;
  22.       DefaultWarmups = 1;
  23.     var
  24.       FReportSink: TProc<string,Double>;
  25.       FWarmups: Integer;
  26.       FIterations: Integer;
  27.       FOverhead: Double;
  28.     class var
  29.       FFreq: Int64;
  30.     class procedure InitFreq;
  31.   public
  32.     constructor Create(const AReportSink: TProc<string,Double>);
  33.     class function Benchmark(const Code: TProc;
  34.       Iterations: Integer = DefaultIterations;
  35.       Warmups: Integer = DefaultWarmups): Double; overload;
  36.     procedure Benchmark(const Name: string; const Code: TProc); overload;
  37.     function Benchmark<T>(const Name: string; const Code: TFunc<T>): T; overload;
  38.     property Warmups: Integer read FWarmups write FWarmups;
  39.     property Iterations: Integer read FIterations write FIterations;
  40.   end;
  41.  
  42. { TBenchmarker }
  43.  
  44. constructor TBenchmarker.Create(const AReportSink: TProc<string, Double>);
  45. begin
  46.   InitFreq;
  47.   FReportSink := AReportSink;
  48.   FWarmups := DefaultWarmups;
  49.   FIterations := DefaultIterations;
  50.  
  51.   // Estimate overhead of harness
  52.   FOverhead := Benchmark(procedure begin end, 100, 3);
  53. end;
  54.  
  55. class procedure TBenchmarker.InitFreq;
  56. begin
  57.   if (FFreq = 0) and not QueryPerformanceFrequency(FFreq) then
  58.     raise Exception.Create('No high-performance counter available.');
  59. end;
  60.  
  61. procedure TBenchmarker.Benchmark(const Name: string; const Code: TProc);
  62. begin
  63.   FReportSink(Name, Benchmark(Code, Iterations, Warmups) - FOverhead);
  64. end;
  65.  
  66. class function TBenchmarker.Benchmark(const Code: TProc; Iterations,
  67.   Warmups: Integer): Double;
  68. var
  69.   start, stop: Int64;
  70.   i: Integer;
  71. begin
  72.   InitFreq;
  73.  
  74.   for i := 1 to Warmups do
  75.     Code;
  76.  
  77.   QueryPerformanceCounter(start);
  78.   for i := 1 to Iterations do
  79.     Code;
  80.   QueryPerformanceCounter(stop);
  81.  
  82.   Result := (stop - start) / FFreq / Iterations;
  83. end;
  84.  
  85. function TBenchmarker.Benchmark<T>(const Name: string; const Code: TFunc<T>): T;
  86. var
  87.   start, stop: Int64;
  88.   i: Integer;
  89. begin
  90.   for i := 1 to FWarmups do
  91.     Result := Code;
  92.  
  93.   QueryPerformanceCounter(start);
  94.   for i := 1 to FIterations do
  95.     Result := Code;
  96.   QueryPerformanceCounter(stop);
  97.  
  98.   FReportSink(Name, (stop - start) / FFreq / Iterations - FOverhead);
  99. end;
  100.  
  101. type
  102.   ISomeInterface = interface
  103.     procedure IntfCall(const Intf: ISomeInterface; depth: Integer);
  104.   end;
  105.  
  106.   TSomeClass = class(TInterfacedObject, ISomeInterface)
  107.   public
  108.     procedure VirtCall(Inst: TSomeClass; depth: Integer); virtual;
  109.     procedure StaticCall(Inst: TSomeClass; depth: Integer);
  110.     procedure IntfCall(const Intf: ISomeInterface; depth: Integer);
  111.   end;
  112.  
  113. { TSomeClass }
  114.  
  115. procedure TSomeClass.IntfCall(const Intf: ISomeInterface; depth: Integer);
  116. begin
  117.   if depth > 0 then
  118.     Intf.IntfCall(Intf, depth - 1);
  119. end;
  120.  
  121. procedure TSomeClass.StaticCall(Inst: TSomeClass; depth: Integer);
  122. begin
  123.   if depth > 0 then
  124.     StaticCall(Inst, depth - 1);
  125. end;
  126.  
  127. procedure TSomeClass.VirtCall(Inst: TSomeClass; depth: Integer);
  128. begin
  129.   if depth > 0 then
  130.     VirtCall(Inst, depth - 1);
  131. end;
  132.  
  133. procedure UseIt;
  134. const
  135.   CallDepth = 10000;
  136. var
  137.   b: TBenchmarker;
  138.   x: TSomeClass;
  139.   intf: ISomeInterface;
  140. begin
  141.   b := TBenchmarker.Create(procedure(Name: string; Time: Double)
  142.   begin
  143.     Writeln(Format('%-20s took %15.9f ms', [Name, Time * 1000]));
  144.   end);
  145.   try
  146.     b.Warmups := 100;
  147.     b.Iterations := 100;
  148.  
  149.     x := TSomeClass.Create;
  150.     intf := x;
  151.      
  152.     b.Benchmark('Static call', procedure
  153.     begin
  154.       x.StaticCall(x, CallDepth);
  155.     end);
  156.  
  157.     b.Benchmark('Virtual call', procedure
  158.     begin
  159.       x.VirtCall(x, CallDepth);
  160.     end);
  161.  
  162.     b.Benchmark('Interface call', procedure
  163.     begin
  164.       intf.IntfCall(intf, CallDepth);
  165.     end);
  166.    
  167.   finally
  168.     b.Free;
  169.   end;
  170. end;
  171.  
  172. begin
  173.   try
  174.     UseIt;
  175.   except
  176.     on E:Exception do
  177.       Writeln(E.Classname, ': ', E.Message);
  178.   end;
  179. end.
This is NOT my code - apart from making it compile in FPC trunk- and I would like to mention the author. Google does not help very much...
« Last Edit: August 10, 2024, 10:01:53 am by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.


Thaddy

  • Hero Member
  • *****
  • Posts: 15545
  • Censorship about opinions does not belong here.
http://blog.barrkel.com/2008/08/anonymous-methods-in-testing-profiling.html
Ah, Barry the wizzard! Thanks!  8-)
Glad to see that this code now compiles in FreePascal.
"am" stands for anonymous methods. Did not think of that.

Now I remember why it is on my disk: after the feature anouncement I tried a lot of Barry's code.
Thank you very much, korba812!
« Last Edit: August 10, 2024, 07:23:58 pm by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

Thaddy

  • Hero Member
  • *****
  • Posts: 15545
  • Censorship about opinions does not belong here.
I made it cross-platform:
Code: Pascal  [Select][+][-]
  1. program am_profiler;
  2. { cross platform version of the am_profiler example by Barry Kelly.
  3.   http://blog.barrkel.com/2008/08/anonymous-methods-in-testing-profiling.html
  4.   Just added;
  5.   - defines
  6.   - QueryPerformanceFrequency for linux
  7.   - QueryPerformanceCounter for Linux.
  8.  
  9.   2024, Thaddy de Koning }
  10. {$ifdef fpc}
  11. {$if fpc_fullversion < 30301}{$error this code needs fpc 3.3.1 or higher}{$endif}
  12. {$mode delphi}
  13. {$modeswitch functionreferences}
  14. {$modeswitch anonymousfunctions}
  15. {$Endif}
  16. {$ifdef mswindows}{$apptype console}{$endif}
  17.  
  18. uses
  19.   {$ifdef unix}baseunix,linux,{$endif}{$ifdef mswindows}windows,{$endif} SysUtils;
  20.  
  21. type
  22.   TFunc<T> = reference to function:T;
  23.   TProc = reference to procedure;
  24.   TProc<T1,T2> = reference to procedure(a:T1;b:T2);
  25.   TBenchmarker = class
  26.   private
  27.     const
  28.       DefaultIterations = 3;
  29.       DefaultWarmups = 1;
  30.     var
  31.       FReportSink: TProc<string,Double>;
  32.       FWarmups: Integer;
  33.       FIterations: Integer;
  34.       FOverhead: Double;
  35.     class var
  36.       FFreq: Int64;
  37.     class procedure InitFreq;
  38.   public
  39.     constructor Create(const AReportSink: TProc<string,Double>);
  40.     class function Benchmark(const Code: TProc;
  41.       Iterations: Integer = DefaultIterations;
  42.       Warmups: Integer = DefaultWarmups): Double; overload;
  43.     procedure Benchmark(const Name: string; const Code: TProc); overload;
  44.     function Benchmark<T>(const Name: string; const Code: TFunc<T>): T; overload;
  45.     property Warmups: Integer read FWarmups write FWarmups;
  46.     property Iterations: Integer read FIterations write FIterations;
  47.   end;
  48.  
  49. {$ifdef unix}
  50. function QueryPerformanceFrequency(out value:int64):boolean;inline;
  51. begin
  52.   Result := true;
  53.   Value := 1000000000;
  54. end;
  55.  
  56. function QueryPerformanceCounter(out value:int64):int64;inline;
  57. var
  58.   t:Timespec;
  59. begin
  60.   result:=clock_gettime(CLOCK_THREAD_CPUTIME_ID{or clock_monotonic?},@t);
  61.   { assume call succeeds }
  62.   value := t.tv_nsec;
  63.   if result = -1 then
  64.   begin
  65.     { mimic windows error behavior, err=0 }
  66.     result :=0;
  67.     Value := 0
  68.   end;
  69. end;
  70. {$endif}
  71.  
  72. { TBenchmarker }
  73.  
  74. constructor TBenchmarker.Create(const AReportSink: TProc<string, Double>);
  75. begin
  76.   InitFreq;
  77.   FReportSink := AReportSink;
  78.   FWarmups := DefaultWarmups;
  79.   if (FFreq = 0) and not QueryPerformanceFrequency(FFreq) then
  80.     raise Exception.Create('No high-performance counter available.');
  81. end;
  82.  
  83. class procedure TBenchmarker.InitFreq;
  84. begin
  85.   if (FFreq = 0) and not QueryPerformanceFrequency(FFreq) then
  86.     raise Exception.Create('No high-performance counter available.');
  87. end;
  88.  
  89.  
  90. procedure TBenchmarker.Benchmark(const Name: string; const Code: TProc);
  91. begin
  92.   FReportSink(Name, Benchmark(Code, Iterations, Warmups) - FOverhead);
  93. end;
  94.  
  95. class function TBenchmarker.Benchmark(const Code: TProc; Iterations,
  96.   Warmups: Integer): Double;
  97. var
  98.   start, stop: Int64;
  99.   i: Integer;
  100. begin
  101.   InitFreq;
  102.  
  103.   for i := 1 to Warmups do
  104.     Code;
  105.  
  106.   QueryPerformanceCounter(start);
  107.   for i := 1 to Iterations do
  108.     Code;
  109.   QueryPerformanceCounter(stop);
  110.  
  111.   Result := (stop - start) / FFreq / Iterations;
  112. end;
  113.  
  114. function TBenchmarker.Benchmark<T>(const Name: string; const Code: TFunc<T>): T;
  115. var
  116.   start, stop: Int64;
  117.   i: Integer;
  118. begin
  119.   for i := 1 to FWarmups do
  120.     Result := Code;
  121.  
  122.   QueryPerformanceCounter(start);
  123.   for i := 1 to FIterations do
  124.     Result := Code;
  125.   QueryPerformanceCounter(stop);
  126.  
  127.   FReportSink(Name, (stop - start) / FFreq / Iterations - FOverhead);
  128. end;
  129.  
  130. type
  131.   ISomeInterface = interface
  132.     procedure IntfCall(const Intf: ISomeInterface; depth: Integer);
  133.   end;
  134.  
  135.   TSomeClass = class(TInterfacedObject, ISomeInterface)
  136.   public
  137.     procedure VirtCall(Inst: TSomeClass; depth: Integer); virtual;
  138.     procedure StaticCall(Inst: TSomeClass; depth: Integer);
  139.     procedure IntfCall(const Intf: ISomeInterface; depth: Integer);
  140.   end;
  141.  
  142. { TSomeClass }
  143.  
  144. procedure TSomeClass.IntfCall(const Intf: ISomeInterface; depth: Integer);
  145. begin
  146.   if depth > 0 then
  147.     Intf.IntfCall(Intf, depth - 1);
  148. end;
  149.  
  150. procedure TSomeClass.StaticCall(Inst: TSomeClass; depth: Integer);
  151. begin
  152.   if depth > 0 then
  153.     StaticCall(Inst, depth - 1);
  154. end;
  155.  
  156. procedure TSomeClass.VirtCall(Inst: TSomeClass; depth: Integer);
  157. begin
  158.   if depth > 0 then
  159.     VirtCall(Inst, depth - 1);
  160. end;
  161.  
  162. procedure UseIt;
  163. const
  164.   CallDepth = 10000;
  165. var
  166.   b: TBenchmarker;
  167.   x: TSomeClass;
  168.   intf: ISomeInterface;
  169. begin
  170.   b := TBenchmarker.Create(procedure(Name: string; Time: Double)
  171.   begin
  172.     Writeln(Format('%-20s took %15.6f ms', [Name, time * 1000]));
  173.   end);
  174.   try
  175.     b.Warmups := 100;
  176.     b.Iterations := 100;
  177.  
  178.     x := TSomeClass.Create;
  179.     intf := x;
  180.      
  181.     b.Benchmark('Static call', procedure
  182.     begin
  183.       x.StaticCall(x, CallDepth);
  184.     end);
  185.  
  186.     b.Benchmark('Virtual call', procedure
  187.     begin
  188.       x.VirtCall(x, CallDepth);
  189.     end);
  190.  
  191.     b.Benchmark('Interface call', procedure
  192.     begin
  193.       intf.IntfCall(intf, CallDepth);
  194.     end);
  195.    
  196.   finally
  197.     b.Free;
  198.   end;
  199. end;
  200.  
  201. begin
  202.   try
  203.     UseIt;
  204.   except
  205.     on E:Exception do
  206.       Writeln(E.Classname, ': ', E.Message);
  207.   end;
  208. end.
« Last Edit: August 10, 2024, 10:02:56 am by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

 

TinyPortal © 2005-2018