After commit ffe09b3 (nil-slot _ClassRelease elision), TList<TObject>
hand-rolled scan x 1000 went 131 ms -> 90 ms (~30% improvement) on
the same hardware as the previous entry. Smaller wins on sequential
and random Get for the same workload.
119 lines
6.2 KiB
Plaintext
119 lines
6.2 KiB
Plaintext
Blaise list micro-benchmark — results log
|
|
==========================================
|
|
|
|
Each entry records the median of two consecutive runs of
|
|
tests/bench_lists.pas, taken on the machine identified in the entry
|
|
header. Add new entries below the previous one (newest at the
|
|
bottom) so the file forms a chronological trend.
|
|
|
|
Workloads (all in one program):
|
|
- TStringList vs TList<String>
|
|
- TObjectList vs TList<TObject>
|
|
|
|
Phases (all ms wall-clock):
|
|
insert 1,000,000 Adds (item_<i> strings or fresh TItem instances)
|
|
sequential Get(i) over the full list (linear sweep)
|
|
random 1,000,000 indexed reads in a pseudo-random pattern
|
|
(deterministic LCG, seed=42)
|
|
for..in full enumeration via the for-in protocol
|
|
(strings benchmark only; objects benchmark omits this)
|
|
IndexOf/scan 1,000 lookups on the list (TList<T> uses a hand-rolled
|
|
linear scan since it has no IndexOf method). Note: the
|
|
string benchmark searches a 100,000-item list; the object
|
|
benchmark searches the full 1,000,000-item list.
|
|
|
|
|
|
------------------------------------------------------------------------
|
|
2026-05-21 — Graeme @ AMD Ryzen 7 5800X (Linux 6.14)
|
|
Blaise compiler v0.9.0-dev
|
|
Commit: 93358ed (fix codegen ARC for ^TClass writes)
|
|
|
|
--- bench_strings ---
|
|
TStringList TList<String>
|
|
insert 1_000_000 98 ms 90 ms
|
|
sequential Get(i) x Count 10 ms 10 ms
|
|
random Get(i) x 1_000_000 19 ms 19 ms
|
|
for..in over 1_000_000 15 ms 11 ms
|
|
IndexOf / hand-rolled scan x 1000 590 ms 277 ms
|
|
|
|
--- bench_objects ---
|
|
TObjectList TList<TObject>
|
|
insert 1_000_000 36 ms 41 ms
|
|
sequential Get(i) x Count 4 ms 6 ms
|
|
random Get(i) x 1_000_000 10 ms 13 ms
|
|
IndexOf / hand-rolled scan x 1000 16 ms 131 ms
|
|
|
|
Notes:
|
|
* TList<String> beats TStringList across every phase; the
|
|
TStringList.IndexOf cost includes sorted-mode/duplicates checks
|
|
the hand-rolled scan does not, hence the 2x gap.
|
|
* TObjectList beats TList<TObject> on writes and reads (raw pointer
|
|
storage vs. typed ^T with ARC), and is dramatically faster on
|
|
IndexOf because the call goes via a direct pointer scan in a
|
|
single function instead of one method call per element.
|
|
* The compiler currently miscompiles a program that instantiates
|
|
the same generic class with two different concrete arguments
|
|
(e.g. TList<String> and TList<TObject> in one program) — that is
|
|
why the benchmark is split into two files. (Fixed in a later
|
|
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.
|
|
|
|
|
|
------------------------------------------------------------------------
|
|
2026-05-21 — Graeme @ AMD Ryzen 7 5800X (Linux 6.14)
|
|
Blaise compiler v0.9.0-dev
|
|
Commit: ffe09b3 (perf codegen: elide _ClassRelease on provably-nil slots)
|
|
|
|
TStringList TList<String>
|
|
insert 1_000_000 96 ms 90 ms
|
|
sequential Get(i) x Count 11 ms 11 ms
|
|
random Get(i) x 1_000_000 19 ms 19 ms
|
|
for..in over 1_000_000 15 ms 11 ms
|
|
IndexOf / hand-rolled scan x 1000 600 ms 283 ms
|
|
|
|
TObjectList TList<TObject>
|
|
insert 1_000_000 37 ms 42 ms
|
|
sequential Get(i) x Count 4 ms 5 ms
|
|
random Get(i) x 1_000_000 9 ms 12 ms
|
|
IndexOf / hand-rolled scan x 1000 16 ms 90 ms
|
|
|
|
Notes:
|
|
* Big win on the TList<TObject> hand-rolled scan (~30% faster:
|
|
131 ms -> 90 ms). Source: nil-slot _ClassRelease elision in the
|
|
codegen — TList<T>.Get's `Result := Src^` no longer emits a
|
|
release-on-nil pair, saving one cross-TU call per Get.
|
|
* Smaller incidental wins on Sequential Get (6->5 ms) and Random
|
|
Get (13->12 ms) for TList<TObject> from the same change.
|
|
* TList<String> hand-rolled scan unchanged at 283 ms; the elision
|
|
applies to class-typed assignments only. Strings get the same
|
|
treatment if we extend the optimisation to strings in a follow-up.
|
|
* TStringList.IndexOf dropped 681->600 ms. Cause uncertain; may
|
|
just be run-to-run noise.
|