Closed lahma closed 1 year ago
Now indexing is as fast as spans or even faster for small lists (0-1), spans start to shine when iterating more items.
💡 We maybe should consider converting visitors to use foreach + span.
Sounds like it's worth a try. Thanks to our source generation magic, probably it wouldn't be too tedious. So, I'm looking forward to the new benchmark results! ;)
OK, I've reverted most of the PR and should now only contain the gist of indexing improvements. main vs this branch:
Diff | Method | Toolchain | Mean | Error | Allocated |
---|---|---|---|---|---|
Old | For_DirectIndexing | Default | 5,839,201.953 ns | 15,907.3791 ns | 7 B |
New | Default | 2,683,663.854 ns (-54%) | 6,805.3141 ns | 3 B (-57%) | |
Old | For_SpanIndexing | Default | 2,629,126.875 ns | 9,483.2562 ns | 4 B |
New | Default | 2,636,007.338 ns (0%) | 3,330.0859 ns | 4 B (0%) | |
Old | ForEach_Span | Default | 2,634,116.172 ns | 19,719.2877 ns | 4 B |
New | Default | 2,626,229.010 ns (0%) | 8,729.7299 ns | 3 B (-25%) | |
Old | For_DirectIndexing | Default | 1,776.865 ns | 0.1620 ns | 0 B |
New | Default | 682.067 ns (-62%) | 0.7556 ns | 0 B | |
Old | For_SpanIndexing | Default | 683.543 ns | 1.5607 ns | 0 B |
New | Default | 672.859 ns (-2%) | 0.8225 ns | 0 B | |
Old | ForEach_Span | Default | 686.167 ns | 4.9590 ns | 0 B |
New | Default | 666.897 ns (-3%) | 0.5036 ns | 0 B | |
Old | For_DirectIndexing | Default | 18.818 ns | 0.1431 ns | 0 B |
New | Default | 4.997 ns (-73%) | 0.0213 ns | 0 B | |
Old | For_SpanIndexing | Default | 4.758 ns | 0.0104 ns | 0 B |
New | Default | 4.390 ns (-8%) | 0.0057 ns | 0 B | |
Old | ForEach_Span | Default | 4.756 ns | 0.0056 ns | 0 B |
New | Default | 4.405 ns (-7%) | 0.0071 ns | 0 B |
FWIW, ReadOnlySpan<T>
ctor does less checks than Span<T>
ctor.
I assume that spans' worse performance for smaller lists is caused by the initial cost of constructing a span. So, for read-only iteration ReadOnlySpan<T>
is a tiny bit better.
Thanks for helping out and getting this finalized!
I was checking how much faster it is to use span instead of indexing (Jint uses indexing at the moment) and I though that it shouldn't have that much difference as it had so tweaked code a bit.
nameof(something)
to causeldstring
, more fine-grained ThrowHelper to the rescueEnsureCapacity
as single method to resizeTrimExcess
as I didn't see much point in it performance wiseResults
Modified benchmark (no boxing for result) was used against both
main
and this PR. The couple byte allocations in 0 size test case ForLoopBenchmark is quite curious, but didn't find out the reason. Now indexing is as fast as spans or even faster for small lists (0-1), spans start to shine when iterating more items.💡 We maybe should consider converting visitors to use foreach + span.
Esprima.Benchmark.AstTreeWalkBenchmark
Esprima.Benchmark.FileParsingBenchmark
Esprima.Benchmark.NodeListEnumerationBenchmark
Esprima.Benchmark.VisitorBenchmark