![]() |
AW: RTTI: generische TObjectList erkennen
Das sieht doch mal gut aus, herzlichen Dank :thumb:. Bleibt nur zu hoffen, dass Name und Typ der Property List sich künftig nicht auch noch ändern.
|
AW: RTTI: generische TObjectList erkennen
Diese .List Property ist ja schon immer™ der Zugriff auf das interne Array gewesen.
Auch schon bei der alten System.Classes.TList. Nutze ich in der Regel auch in Schleifen, wenn von 0 bis Count - 1 iteriert wird, um die GetItem-Funktion zu umgehen. Die mag zwar je nach Delphi-Version zwar inline markiert sein, aber es wird unnötig Index >= FCount geprüft. |
AW: RTTI: generische TObjectList erkennen
Zitat:
Code:
Sollte man übrigens runtime packages nutzen, fällt das inlining weg und der Zugriff auf .List wird nicht mehr geinlined und jedesmal aufgerufen, was diesen Ansatz ca 10mal langsamer macht, der nicht mehr geinlinete Getter hingegen kostet nur ca 50% mehr. Dieselbe Benchmark mit rtl als runtime package:
-------------------------------------------------------
Benchmark Time CPU Iterations ------------------------------------------------------------- RTL-getter/10 9,31 ns 9,28 ns 64000000 RTL-getter/100 114 ns 115 ns 6400000 RTL-getter/1000 1150 ns 1147 ns 640000 RTL-getter/10000 11550 ns 11475 ns 64000 RTL-getter/100000 115873 ns 117188 ns 5600 RTL-list/10 9,16 ns 9,21 ns 74666667 RTL-list/100 113 ns 115 ns 6400000 RTL-list/1000 1151 ns 1144 ns 560000 RTL-list/10000 11577 ns 11719 ns 64000 RTL-list/100000 115813 ns 117188 ns 6400
Code:
Benchmark Code:
-------------------------------------------------------
Benchmark Time CPU Iterations ------------------------------------------------------------- RTL-getter/10 16,9 ns 16,9 ns 40727273 RTL-getter/100 169 ns 169 ns 4072727 RTL-getter/1000 1639 ns 1650 ns 407273 RTL-getter/10000 16257 ns 16392 ns 44800 RTL-getter/100000 163355 ns 161122 ns 4073 RTL-list/10 146 ns 146 ns 4480000 RTL-list/100 1461 ns 1475 ns 497778 RTL-list/1000 14593 ns 14300 ns 44800 RTL-list/10000 145201 ns 142997 ns 4480 RTL-list/100000 1452860 ns 1443273 ns 498
Delphi-Quellcode:
uses
Spring.Benchmark, Generics.Collections; procedure RTLGetter(const state: TState); var list: TList<Integer>; count, i: Integer; sum: Integer; begin list := TList<Integer>.Create; count := state[0]; for i := 1 to count do list.Add(i); sum := 0; while state.KeepRunning do begin sum := 0; for i := 0 to list.Count - 1 do Inc(sum, list[i]); end; state.Counters['sum'] := sum; list.Free; end; procedure RTLList(const state: TState); var list: TList<Integer>; count, i: Integer; sum: Integer; begin list := TList<Integer>.Create; count := state[0]; for i := 1 to count do list.Add(i); sum := 0; while state.KeepRunning do begin sum := 0; for i := 0 to list.Count - 1 do Inc(sum, list.List[i]); end; state.Counters['sum'] := sum; list.Free; end; begin Benchmark(RTLGetter, 'RTL-getter').RangeMultiplier(10).Range(10, 100000); Benchmark(RTLList, 'RTL-list').RangeMultiplier(10).Range(10, 100000); Benchmark_Main(); end. |
AW: RTTI: generische TObjectList erkennen
Da messe ich mit Hausmitteln mit D10.4 auf einen i5-7600 in Debug Win32 anderes:
Code:
RTL-Getter -> sum: 5000000050000000 calculated in 205,2559 ms
RTL-list -> sum: 5000000050000000 calculated in 192,9382 ms ---------------- RTL-Getter -> sum: 5000000050000000 calculated in 204,5107 ms RTL-list -> sum: 5000000050000000 calculated in 191,9137 ms ---------------- RTL-Getter -> sum: 5000000050000000 calculated in 205,1316 ms RTL-list -> sum: 5000000050000000 calculated in 191,7222 ms ----------------
Delphi-Quellcode:
Richtig spannend wird's aber mit Release Win64, da muss ich mal in mich gehen und drüber nachdenken warum das sich so eklatant umkehrt.
program Project6;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Diagnostics, Generics.Collections; const cCount: Integer = 100000000; var W: TStopwatch; procedure RTLGetter; var list: TList<Integer>; count, i: Integer; sum: Int64; begin list := TList<Integer>.Create; count := cCount; for i := 1 to count do list.Add(i); sum := 0; W := TStopwatch.StartNew; for i := 0 to list.Count - 1 do Inc(sum, list[i]); W.Stop; Writeln('RTL-Getter -> ','sum: ', sum, ' calculated in ', W.Elapsed.TotalMilliseconds.ToString, ' ms'); list.Free; end; procedure RTLList; var list: TList<Integer>; count, i: Integer; sum: int64; begin list := TList<Integer>.Create; count := cCount; for i := 1 to count do list.Add(i); sum := 0; W := TStopwatch.StartNew; for i := 0 to list.Count - 1 do Inc(sum, list.List[i]); W.Stop; Writeln('RTL-list -> ', 'sum: ', sum, ' calculated in ', W.Elapsed.TotalMilliseconds.ToString, ' ms'); list.Free; end; procedure Benchmark_Main(); begin RTLList; RTLGetter; Writeln('----------------'); end; begin try for var I := 1 to 3 do Benchmark_Main(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
Code:
RTL-Getter -> sum: 5000000050000000 calculated in 65,1854 ms
RTL-list -> sum: 5000000050000000 calculated in 108,6827 ms ---------------- RTL-Getter -> sum: 5000000050000000 calculated in 58,9665 ms RTL-list -> sum: 5000000050000000 calculated in 108,7423 ms ---------------- RTL-Getter -> sum: 5000000050000000 calculated in 60,7217 ms RTL-list -> sum: 5000000050000000 calculated in 105,2705 ms ---------------- |
AW: RTTI: generische TObjectList erkennen
Zitat:
|
AW: RTTI: generische TObjectList erkennen
Zitat:
|
AW: RTTI: generische TObjectList erkennen
Ich sehe bei deinem Win32 Ergebnis nix groß anders - deine Ergebnisse sind ~7% voneinander entfernt - außerdem ist Debug witzlos, um irgendwelche Performancemessungen durchzuführen.
Außerdem habe ich mir schon was dabei gedacht, meine sum Variable als Integer zu deklarieren (die ist nur dafür da, dass der Listenzugriff nicht wegoptimiert wird) und nicht Int64. Eine Int64 Addition auf Win32 kostet nämlich genug, um in diesem Benchmark einen erheblichen Ausschlag zu geben. Zitat:
Außer, dass der Delphi Compiler Schrott ist und oftmals viel zu viel register herumgemove produziert, ist es komplett egal, ob da die "Index in Range" Überprüfung ausgeführt wird. Was außerdem öfters (mal wieder, weil der Compiler dämlich ist) Auswirkung hat, ist die Größe der Integer Variablen. Bei einem direktzugriff auf ein Array mag der Compiler lieber die native Bittigkeit, wohingegen bei dem Getter Index ja vom Typ Integer ist. Spiel mal mit dem Typen für i herum und schau, wie sich die Ergebnisse ändern. |
AW: RTTI: generische TObjectList erkennen
Zitat:
|
AW: RTTI: generische TObjectList erkennen
Zitat:
Zitat:
In diesem speziellen Fall kann es außerdem sein, dass man Microbenchmarkabweichungen zwischen den beiden Methoden haben kann, die die Unterschiede erklären. Hierzu empfehle ich dieses Video: ![]() Es kommt außerdem oftmals auch auf die CPU an, denn die machen inzwischen so fancy sachen wie "move elimination", bei denen manchmal das vom Compiler generierte Rumgegurke einfach wegfliegt, da die CPU sieht, dass es nur Hin- und Hergeschiebe ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:34 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz