test(bench): merge bench_strings + bench_objects into bench_lists
The multi-instance generic miscompile that forced the two-program
split is fixed (b6736d3), so the four workloads now run in a single
program: TStringList, TList<String>, TObjectList, TList<TObject>.
Add a fresh results entry on the post-fix compiler; timings are
within noise of the split run on the same hardware.
This commit is contained in:
parent
b6736d3925
commit
07b9b8ddbd
|
|
@ -6,32 +6,29 @@
|
||||||
See LICENSE file in the project root for full license terms.
|
See LICENSE file in the project root for full license terms.
|
||||||
}
|
}
|
||||||
|
|
||||||
program BenchStrings;
|
program BenchLists;
|
||||||
|
|
||||||
{ Temporary micro-benchmark — TStringList vs TList<String>.
|
{ Micro-benchmark — TStringList vs TList<String> and TObjectList vs
|
||||||
|
TList<TObject>.
|
||||||
|
|
||||||
For each container we measure:
|
For each container we measure:
|
||||||
1. Bulk insert — 1_000_000 Adds
|
1. Bulk insert — 1_000_000 Adds
|
||||||
2. Sequential read — Get(i) for every index
|
2. Sequential read — Get(i) for every index
|
||||||
3. Random read — 1_000_000 indexed reads in a pseudo-random pattern
|
3. Random read — 1_000_000 indexed reads in a pseudo-random pattern
|
||||||
4. Linear search — 1000 lookups on a 100_000-item list
|
4. Linear search — 1000 lookups; TList<T> uses a hand-rolled scan
|
||||||
(TList<T> has no IndexOf — hand-rolled scan)
|
since it has no IndexOf method
|
||||||
5. for..in iterate — checksum across all items
|
5. for..in iterate — full enumeration (strings workload only)
|
||||||
|
|
||||||
All times are wall-clock milliseconds via TInstant.Subtract.
|
All times are wall-clock milliseconds via TInstant.Subtract.
|
||||||
Run from the project root:
|
Run from the project root:
|
||||||
|
|
||||||
compiler/target/blaise --source tests/bench_strings.pas --output /tmp/bench_strings
|
compiler/target/blaise --source tests/bench_lists.pas --output /tmp/bench_lists
|
||||||
/tmp/bench_strings
|
/tmp/bench_lists
|
||||||
|
}
|
||||||
NOTE: this benchmark and tests/bench_objects.pas are split because the
|
|
||||||
compiler currently miscompiles a program that instantiates the same
|
|
||||||
generic class with two different concrete type arguments
|
|
||||||
(e.g. TList<String> and TList<TObject> in the same program) — a
|
|
||||||
pre-existing limitation tracked separately. }
|
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes,
|
Classes,
|
||||||
|
Contnrs,
|
||||||
Generics.Collections,
|
Generics.Collections,
|
||||||
DateUtils,
|
DateUtils,
|
||||||
SysUtils;
|
SysUtils;
|
||||||
|
|
@ -42,6 +39,11 @@ const
|
||||||
N_RANDOM = 1000000;
|
N_RANDOM = 1000000;
|
||||||
N_SEARCH = 1000;
|
N_SEARCH = 1000;
|
||||||
|
|
||||||
|
type
|
||||||
|
TItem = class
|
||||||
|
FValue: Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
GRand: Integer;
|
GRand: Integer;
|
||||||
|
|
||||||
|
|
@ -249,13 +251,161 @@ begin
|
||||||
WriteLn
|
WriteLn
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure BenchTObjectList;
|
||||||
|
var
|
||||||
|
OL: TObjectList;
|
||||||
|
I: Integer;
|
||||||
|
Idx: Integer;
|
||||||
|
T0: TInstant;
|
||||||
|
Item: TItem;
|
||||||
|
Sum: Int64;
|
||||||
|
Hits: Integer;
|
||||||
|
Needle: TItem;
|
||||||
begin
|
begin
|
||||||
WriteLn('=== Blaise list micro-benchmark - strings ===');
|
WriteLn('TObjectList(OwnsObjects=True)');
|
||||||
|
|
||||||
|
{ 1. Bulk insert }
|
||||||
|
OL := TObjectList.Create(True);
|
||||||
|
T0 := InstantNow;
|
||||||
|
for I := 0 to N_BIG - 1 do
|
||||||
|
begin
|
||||||
|
Item := TItem.Create;
|
||||||
|
Item.FValue := I;
|
||||||
|
OL.Add(Item)
|
||||||
|
end;
|
||||||
|
Report('insert 1_000_000', ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 2. Sequential read }
|
||||||
|
T0 := InstantNow;
|
||||||
|
Sum := 0;
|
||||||
|
for I := 0 to OL.Count - 1 do
|
||||||
|
begin
|
||||||
|
Item := TItem(OL.Get(I));
|
||||||
|
Sum := Sum + Item.FValue
|
||||||
|
end;
|
||||||
|
Report('sequential Get(i) x Count (sum=' + IntToStr(Sum) + ')',
|
||||||
|
ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 3. Random read }
|
||||||
|
SeedRand(42);
|
||||||
|
T0 := InstantNow;
|
||||||
|
Sum := 0;
|
||||||
|
for I := 0 to N_RANDOM - 1 do
|
||||||
|
begin
|
||||||
|
Idx := NextRand mod N_BIG;
|
||||||
|
Item := TItem(OL.Get(Idx));
|
||||||
|
Sum := Sum + Item.FValue
|
||||||
|
end;
|
||||||
|
Report('random Get(i) x 1_000_000', ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 4. IndexOf — search for known objects (pointer-equality match) }
|
||||||
|
SeedRand(7);
|
||||||
|
T0 := InstantNow;
|
||||||
|
Hits := 0;
|
||||||
|
for I := 0 to N_SEARCH - 1 do
|
||||||
|
begin
|
||||||
|
Idx := NextRand mod N_BIG;
|
||||||
|
Needle := TItem(OL.Get(Idx));
|
||||||
|
if OL.IndexOf(Needle) >= 0 then
|
||||||
|
Hits := Hits + 1
|
||||||
|
end;
|
||||||
|
Report('IndexOf x 1000 (hits=' + IntToStr(Hits) + ')',
|
||||||
|
ElapsedMs(T0));
|
||||||
|
|
||||||
|
OL.Free;
|
||||||
|
WriteLn
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure BenchGenericListObject;
|
||||||
|
var
|
||||||
|
L: TList<TObject>;
|
||||||
|
I: Integer;
|
||||||
|
J: Integer;
|
||||||
|
Idx: Integer;
|
||||||
|
T0: TInstant;
|
||||||
|
Obj: TObject;
|
||||||
|
Item: TItem;
|
||||||
|
Sum: Int64;
|
||||||
|
Hits: Integer;
|
||||||
|
Needle: TObject;
|
||||||
|
Found: Boolean;
|
||||||
|
begin
|
||||||
|
WriteLn('TList<TObject> (manual Free)');
|
||||||
|
|
||||||
|
{ 1. Bulk insert }
|
||||||
|
L := TList<TObject>.Create;
|
||||||
|
T0 := InstantNow;
|
||||||
|
for I := 0 to N_BIG - 1 do
|
||||||
|
begin
|
||||||
|
Item := TItem.Create;
|
||||||
|
Item.FValue := I;
|
||||||
|
L.Add(Item)
|
||||||
|
end;
|
||||||
|
Report('insert 1_000_000', ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 2. Sequential read }
|
||||||
|
T0 := InstantNow;
|
||||||
|
Sum := 0;
|
||||||
|
for I := 0 to L.Count - 1 do
|
||||||
|
begin
|
||||||
|
Item := TItem(L.Get(I));
|
||||||
|
Sum := Sum + Item.FValue
|
||||||
|
end;
|
||||||
|
Report('sequential Get(i) x Count (sum=' + IntToStr(Sum) + ')',
|
||||||
|
ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 3. Random read }
|
||||||
|
SeedRand(42);
|
||||||
|
T0 := InstantNow;
|
||||||
|
Sum := 0;
|
||||||
|
for I := 0 to N_RANDOM - 1 do
|
||||||
|
begin
|
||||||
|
Idx := NextRand mod N_BIG;
|
||||||
|
Item := TItem(L.Get(Idx));
|
||||||
|
Sum := Sum + Item.FValue
|
||||||
|
end;
|
||||||
|
Report('random Get(i) x 1_000_000', ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ 4. Hand-rolled IndexOf — pointer equality }
|
||||||
|
SeedRand(7);
|
||||||
|
T0 := InstantNow;
|
||||||
|
Hits := 0;
|
||||||
|
for I := 0 to N_SEARCH - 1 do
|
||||||
|
begin
|
||||||
|
Idx := NextRand mod N_BIG;
|
||||||
|
Needle := L.Get(Idx);
|
||||||
|
Found := False;
|
||||||
|
for J := 0 to L.Count - 1 do
|
||||||
|
if L.Get(J) = Needle then
|
||||||
|
begin
|
||||||
|
Found := True;
|
||||||
|
break
|
||||||
|
end;
|
||||||
|
if Found then
|
||||||
|
Hits := Hits + 1
|
||||||
|
end;
|
||||||
|
Report('hand-rolled scan x 1000 (hits=' + IntToStr(Hits) + ')',
|
||||||
|
ElapsedMs(T0));
|
||||||
|
|
||||||
|
{ Manually release each item since TList<TObject> is not owning. }
|
||||||
|
for I := 0 to L.Count - 1 do
|
||||||
|
begin
|
||||||
|
Obj := L.Get(I);
|
||||||
|
Obj.Free
|
||||||
|
end;
|
||||||
|
L.Free;
|
||||||
|
WriteLn
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
WriteLn('=== Blaise list micro-benchmark ===');
|
||||||
WriteLn('N_BIG=' + IntToStr(N_BIG) +
|
WriteLn('N_BIG=' + IntToStr(N_BIG) +
|
||||||
' N_MID=' + IntToStr(N_MID) +
|
' N_MID=' + IntToStr(N_MID) +
|
||||||
' N_RANDOM=' + IntToStr(N_RANDOM) +
|
' N_RANDOM=' + IntToStr(N_RANDOM) +
|
||||||
' N_SEARCH=' + IntToStr(N_SEARCH));
|
' N_SEARCH=' + IntToStr(N_SEARCH));
|
||||||
WriteLn;
|
WriteLn;
|
||||||
BenchTStringList;
|
BenchTStringList;
|
||||||
BenchGenericListString
|
BenchGenericListString;
|
||||||
|
BenchTObjectList;
|
||||||
|
BenchGenericListObject
|
||||||
end.
|
end.
|
||||||
|
|
@ -2,14 +2,13 @@ Blaise list micro-benchmark — results log
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
Each entry records the median of two consecutive runs of
|
Each entry records the median of two consecutive runs of
|
||||||
tests/bench_strings.pas and tests/bench_objects.pas, taken on the
|
tests/bench_lists.pas, taken on the machine identified in the entry
|
||||||
machine identified in the entry header. Add new entries below the
|
header. Add new entries below the previous one (newest at the
|
||||||
previous one (newest at the bottom) so the file forms a chronological
|
bottom) so the file forms a chronological trend.
|
||||||
trend.
|
|
||||||
|
|
||||||
Workloads:
|
Workloads (all in one program):
|
||||||
- bench_strings: TStringList vs TList<String>
|
- TStringList vs TList<String>
|
||||||
- bench_objects: TObjectList vs TList<TObject>
|
- TObjectList vs TList<TObject>
|
||||||
|
|
||||||
Phases (all ms wall-clock):
|
Phases (all ms wall-clock):
|
||||||
insert 1,000,000 Adds (item_<i> strings or fresh TItem instances)
|
insert 1,000,000 Adds (item_<i> strings or fresh TItem instances)
|
||||||
|
|
@ -57,3 +56,31 @@ Phases (all ms wall-clock):
|
||||||
(e.g. TList<String> and TList<TObject> in one program) — that is
|
(e.g. TList<String> and TList<TObject> in one program) — that is
|
||||||
why the benchmark is split into two files. (Fixed in a later
|
why the benchmark is split into two files. (Fixed in a later
|
||||||
commit via per-instance AST body cloning.)
|
commit via per-instance AST body cloning.)
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
2026-05-21 — Graeme @ AMD Ryzen 7 5800X (Linux 6.14)
|
||||||
|
Blaise compiler v0.9.0-dev
|
||||||
|
Commit: b6736d3 (fix semantic: clone method bodies per generic instance)
|
||||||
|
|
||||||
|
--- merged into a single program (tests/bench_lists.pas) ---
|
||||||
|
TStringList TList<String>
|
||||||
|
insert 1_000_000 99 ms 89 ms
|
||||||
|
sequential Get(i) x Count 10 ms 10 ms
|
||||||
|
random Get(i) x 1_000_000 20 ms 19 ms
|
||||||
|
for..in over 1_000_000 15 ms 11 ms
|
||||||
|
IndexOf / hand-rolled scan x 1000 681 ms 287 ms
|
||||||
|
|
||||||
|
TObjectList TList<TObject>
|
||||||
|
insert 1_000_000 36 ms 40 ms
|
||||||
|
sequential Get(i) x Count 4 ms 6 ms
|
||||||
|
random Get(i) x 1_000_000 9 ms 13 ms
|
||||||
|
IndexOf / hand-rolled scan x 1000 16 ms 131 ms
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* Multi-instance generic miscompile is fixed — TList<String> and
|
||||||
|
TList<TObject> now co-exist in one program, so the two split
|
||||||
|
benchmarks have been merged into tests/bench_lists.pas.
|
||||||
|
* Numbers are within noise of the previous split-program run on
|
||||||
|
the same hardware; combining the workloads does not perturb
|
||||||
|
timings.
|
||||||
|
|
|
||||||
|
|
@ -1,257 +0,0 @@
|
||||||
{
|
|
||||||
Blaise - An Object Pascal Compiler
|
|
||||||
Copyright (c) 2026 Graeme Geldenhuys
|
|
||||||
SPDX-License-Identifier: Apache-2.0 WITH Swift-exception
|
|
||||||
Licensed under the Apache License v2.0 with Runtime Library Exception.
|
|
||||||
See LICENSE file in the project root for full license terms.
|
|
||||||
}
|
|
||||||
|
|
||||||
program BenchObjects;
|
|
||||||
|
|
||||||
{ Temporary micro-benchmark — TObjectList vs TList<TObject>.
|
|
||||||
|
|
||||||
For each container we measure:
|
|
||||||
1. Bulk insert — 1_000_000 Adds of fresh TItem instances
|
|
||||||
2. Sequential read — Get(i) + read FValue for every index
|
|
||||||
3. Random read — 1_000_000 indexed reads in a pseudo-random pattern
|
|
||||||
4. Linear search — 1000 lookups on the 1M-item list (we look for
|
|
||||||
objects we know are present; pointer equality)
|
|
||||||
5. for..in iterate — checksum across all items (TObjectList only;
|
|
||||||
TList<TObject>.GetEnumerator returns Current as
|
|
||||||
the element type which round-trips fine here)
|
|
||||||
|
|
||||||
All times are wall-clock milliseconds via TInstant.Subtract.
|
|
||||||
Run from the project root:
|
|
||||||
|
|
||||||
compiler/target/blaise --source tests/bench_objects.pas --output /tmp/bench_objects
|
|
||||||
/tmp/bench_objects
|
|
||||||
|
|
||||||
NOTE: split from tests/bench_strings.pas — see that file's header for
|
|
||||||
the compiler limitation that forces the split. }
|
|
||||||
|
|
||||||
uses
|
|
||||||
Contnrs,
|
|
||||||
Generics.Collections,
|
|
||||||
DateUtils,
|
|
||||||
SysUtils;
|
|
||||||
|
|
||||||
const
|
|
||||||
N_BIG = 1000000;
|
|
||||||
N_RANDOM = 1000000;
|
|
||||||
N_SEARCH = 1000;
|
|
||||||
|
|
||||||
type
|
|
||||||
TItem = class
|
|
||||||
FValue: Integer;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
|
||||||
GRand: Integer;
|
|
||||||
|
|
||||||
procedure SeedRand(S: Integer);
|
|
||||||
begin
|
|
||||||
GRand := S
|
|
||||||
end;
|
|
||||||
|
|
||||||
function NextRand: Integer;
|
|
||||||
begin
|
|
||||||
GRand := GRand * 1103515245 + 12345;
|
|
||||||
Result := (GRand shr 16) and $7FFFFFFF
|
|
||||||
end;
|
|
||||||
|
|
||||||
function ElapsedMs(Start: TInstant): Int64;
|
|
||||||
var
|
|
||||||
Now: TInstant;
|
|
||||||
D: TDuration;
|
|
||||||
begin
|
|
||||||
Now := InstantNow;
|
|
||||||
D := Now.Subtract(Start);
|
|
||||||
Result := D.TotalMilliseconds
|
|
||||||
end;
|
|
||||||
|
|
||||||
function PadRight(const S: string; Width: Integer): string;
|
|
||||||
var
|
|
||||||
N: Integer;
|
|
||||||
begin
|
|
||||||
Result := S;
|
|
||||||
N := Width - Length(S);
|
|
||||||
while N > 0 do
|
|
||||||
begin
|
|
||||||
Result := Result + ' ';
|
|
||||||
N := N - 1
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
function PadLeft(const S: string; Width: Integer): string;
|
|
||||||
var
|
|
||||||
N: Integer;
|
|
||||||
begin
|
|
||||||
Result := S;
|
|
||||||
N := Width - Length(S);
|
|
||||||
while N > 0 do
|
|
||||||
begin
|
|
||||||
Result := ' ' + Result;
|
|
||||||
N := N - 1
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure Report(const ALabel: string; AMs: Int64);
|
|
||||||
begin
|
|
||||||
WriteLn(' ' + PadRight(ALabel, 50) + PadLeft(IntToStr(AMs), 6) + ' ms')
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure BenchTObjectList;
|
|
||||||
var
|
|
||||||
OL: TObjectList;
|
|
||||||
I: Integer;
|
|
||||||
Idx: Integer;
|
|
||||||
T0: TInstant;
|
|
||||||
Item: TItem;
|
|
||||||
Sum: Int64;
|
|
||||||
Hits: Integer;
|
|
||||||
Needle: TItem;
|
|
||||||
begin
|
|
||||||
WriteLn('TObjectList(OwnsObjects=True)');
|
|
||||||
|
|
||||||
{ 1. Bulk insert }
|
|
||||||
OL := TObjectList.Create(True);
|
|
||||||
T0 := InstantNow;
|
|
||||||
for I := 0 to N_BIG - 1 do
|
|
||||||
begin
|
|
||||||
Item := TItem.Create;
|
|
||||||
Item.FValue := I;
|
|
||||||
OL.Add(Item)
|
|
||||||
end;
|
|
||||||
Report('insert 1_000_000', ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 2. Sequential read }
|
|
||||||
T0 := InstantNow;
|
|
||||||
Sum := 0;
|
|
||||||
for I := 0 to OL.Count - 1 do
|
|
||||||
begin
|
|
||||||
Item := TItem(OL.Get(I));
|
|
||||||
Sum := Sum + Item.FValue
|
|
||||||
end;
|
|
||||||
Report('sequential Get(i) x Count (sum=' + IntToStr(Sum) + ')',
|
|
||||||
ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 3. Random read }
|
|
||||||
SeedRand(42);
|
|
||||||
T0 := InstantNow;
|
|
||||||
Sum := 0;
|
|
||||||
for I := 0 to N_RANDOM - 1 do
|
|
||||||
begin
|
|
||||||
Idx := NextRand mod N_BIG;
|
|
||||||
Item := TItem(OL.Get(Idx));
|
|
||||||
Sum := Sum + Item.FValue
|
|
||||||
end;
|
|
||||||
Report('random Get(i) x 1_000_000', ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 4. IndexOf — search for known objects (pointer-equality match) }
|
|
||||||
SeedRand(7);
|
|
||||||
T0 := InstantNow;
|
|
||||||
Hits := 0;
|
|
||||||
for I := 0 to N_SEARCH - 1 do
|
|
||||||
begin
|
|
||||||
Idx := NextRand mod N_BIG;
|
|
||||||
Needle := TItem(OL.Get(Idx));
|
|
||||||
if OL.IndexOf(Needle) >= 0 then
|
|
||||||
Hits := Hits + 1
|
|
||||||
end;
|
|
||||||
Report('IndexOf x 1000 (hits=' + IntToStr(Hits) + ')',
|
|
||||||
ElapsedMs(T0));
|
|
||||||
|
|
||||||
OL.Free;
|
|
||||||
WriteLn
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure BenchGenericListObject;
|
|
||||||
var
|
|
||||||
L: TList<TObject>;
|
|
||||||
I: Integer;
|
|
||||||
J: Integer;
|
|
||||||
Idx: Integer;
|
|
||||||
T0: TInstant;
|
|
||||||
Obj: TObject;
|
|
||||||
Item: TItem;
|
|
||||||
Sum: Int64;
|
|
||||||
Hits: Integer;
|
|
||||||
Needle: TObject;
|
|
||||||
Found: Boolean;
|
|
||||||
begin
|
|
||||||
WriteLn('TList<TObject> (manual Free)');
|
|
||||||
|
|
||||||
{ 1. Bulk insert }
|
|
||||||
L := TList<TObject>.Create;
|
|
||||||
T0 := InstantNow;
|
|
||||||
for I := 0 to N_BIG - 1 do
|
|
||||||
begin
|
|
||||||
Item := TItem.Create;
|
|
||||||
Item.FValue := I;
|
|
||||||
L.Add(Item)
|
|
||||||
end;
|
|
||||||
Report('insert 1_000_000', ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 2. Sequential read }
|
|
||||||
T0 := InstantNow;
|
|
||||||
Sum := 0;
|
|
||||||
for I := 0 to L.Count - 1 do
|
|
||||||
begin
|
|
||||||
Item := TItem(L.Get(I));
|
|
||||||
Sum := Sum + Item.FValue
|
|
||||||
end;
|
|
||||||
Report('sequential Get(i) x Count (sum=' + IntToStr(Sum) + ')',
|
|
||||||
ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 3. Random read }
|
|
||||||
SeedRand(42);
|
|
||||||
T0 := InstantNow;
|
|
||||||
Sum := 0;
|
|
||||||
for I := 0 to N_RANDOM - 1 do
|
|
||||||
begin
|
|
||||||
Idx := NextRand mod N_BIG;
|
|
||||||
Item := TItem(L.Get(Idx));
|
|
||||||
Sum := Sum + Item.FValue
|
|
||||||
end;
|
|
||||||
Report('random Get(i) x 1_000_000', ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ 4. Hand-rolled IndexOf — pointer equality }
|
|
||||||
SeedRand(7);
|
|
||||||
T0 := InstantNow;
|
|
||||||
Hits := 0;
|
|
||||||
for I := 0 to N_SEARCH - 1 do
|
|
||||||
begin
|
|
||||||
Idx := NextRand mod N_BIG;
|
|
||||||
Needle := L.Get(Idx);
|
|
||||||
Found := False;
|
|
||||||
for J := 0 to L.Count - 1 do
|
|
||||||
if L.Get(J) = Needle then
|
|
||||||
begin
|
|
||||||
Found := True;
|
|
||||||
break
|
|
||||||
end;
|
|
||||||
if Found then
|
|
||||||
Hits := Hits + 1
|
|
||||||
end;
|
|
||||||
Report('hand-rolled scan x 1000 (hits=' + IntToStr(Hits) + ')',
|
|
||||||
ElapsedMs(T0));
|
|
||||||
|
|
||||||
{ Manually release each item since TList<TObject> is not owning. }
|
|
||||||
for I := 0 to L.Count - 1 do
|
|
||||||
begin
|
|
||||||
Obj := L.Get(I);
|
|
||||||
Obj.Free
|
|
||||||
end;
|
|
||||||
L.Free;
|
|
||||||
WriteLn
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
WriteLn('=== Blaise list micro-benchmark - objects ===');
|
|
||||||
WriteLn('N_BIG=' + IntToStr(N_BIG) +
|
|
||||||
' N_RANDOM=' + IntToStr(N_RANDOM) +
|
|
||||||
' N_SEARCH=' + IntToStr(N_SEARCH));
|
|
||||||
WriteLn;
|
|
||||||
BenchTObjectList;
|
|
||||||
BenchGenericListObject
|
|
||||||
end.
|
|
||||||
Loading…
Reference in a new issue