-
-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve ArrayList and NodeList #396
Conversation
src/Esprima/ArrayList.cs
Outdated
if (value < (_items?.Length ?? 0)) | ||
{ | ||
T[] array = new T[value]; | ||
if (_count > 0) | ||
{ | ||
Array.Copy(_items, 0, array, 0, _count); | ||
} | ||
_items = array; | ||
} | ||
else | ||
{ | ||
_items = null; | ||
ThrowArgumentOutOfRangeException(nameof(value), value, null); | ||
} | ||
|
||
EnsureCapacity(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd stick to the original logic here because the change leads to a bit confusing API. For example:
var al = new ArrayList<int>(initialCapacity: 4);
al.Capacity = 5;
var c = al.Capacity;
c
is 8 instead of 5, which is kinda unexpected after explicitly setting Capacity
to 5 in the previous line. At least, BCL types like List<T>
don't have such behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I'll revert the capacity related changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had problems with the Capacity
property only, EnsureCapacity
seemed ok in other places. But I'm also ok with the original logic.
@@ -30,7 +28,7 @@ public void Setup() | |||
} | |||
|
|||
[Benchmark] | |||
public object For_DirectIndexing() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn, nice oversight on my part... This pretty much messed up the benchmark results.
Nice catch! 👍
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: Esprima.Benchmark.NodeListEnumerationBenchmark
|
* better indexer with less IL * encapsulate EnsureCapacity * remove TrimExcess
FWIW, I assume that spans' worse performance for smaller lists is caused by the initial cost of constructing a span. So, for read-only iteration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those indexer perf gains are serious. Kudos!
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