-
-
Notifications
You must be signed in to change notification settings - Fork 23.3k
Add reserve()
to Dictionary
, apply to constructors on GDScript VM
#110709
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
base: master
Are you sure you want to change the base?
Conversation
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.
Great idea! reserve
is especially useful for hashing types because on growth, it needs to re-hash, leading to a lot of wasted cpu cycles.
I just got one interface design comment, otherwise I think we should move forwards with this.
"Why not?" is never a good reason to add something to Core. While the code is minimal, it has no reason to be exposed to end users in the first place. It just adds another entry to the API that users will never touch. If sizing Dictionaries is a bottleneck, then you are already using the wrong data structure and no amount of calling This is exactly the sort of improvement contemplated by the first two of our contributor best practices: |
You might have understood things wrong. Dictionary is used in countless places within the engine that can benefit from this.
Except it isn't? It's only exposed for internal use within the engine where beneficial. My apologies if using the word "expose" led to wrong conclusions. I did a bit of rewording. |
That's my bad. I didn't notice that there wasn't any binding code touched. That takes away my concern about this being exposed to end users. Adding something like this for internal use is a lot less of a problem. That being said, if it's truly a benefit. Then this PR should be using it somewhere where dictionary allocations were a problem. Remember, the problem always needs to come first. We don't add solutions to the engine and then plan on finding problems. We start by identifying a problem, then we make changes to solve that problem. This may very well be the correct solution to a problem, but in order to merge it, we need to know what that problem is. It isn't enough to say that some places could benefit from this change. Show me what places do benefit from this change by profiling them before and after the change. |
That seems like a bit of a nonsensical take on this particular feature. I would consider this a core library feature for
You do know what that problem is. Churn in a |
There are numerous situations within the engine where known final size dictionaries could be built faster for basically free by reserving. Isn't this a problem? The point is that doing everything inside a single PR would be hard to keep track of. Take #105928 for example, which does the same thing but for The reason I did apply on the GDScript VM was mostly because that case was able to be reproduced and benchmarked within GDScript. |
a602026
to
3e17771
Compare
Sure, find one and show me. If there are numerous it should not be hard. I'm really not asking for much.
Sure, don't do everything then. Just solve the low hanging fruit issues. As it stands this PR does nothing, I am asking for it to do something before merging. |
@Shadows-of-Fire Dictionary isn't our standard map in the engine, Hashmap is. By design we don't use Dictionary in any performance sensitive areas. Which is why I said above, if we find Dictionary in a performance sensitive areas, we are likely using the wrong data structure. As I said above, if it's so obvious that this will fix a problem somewhere, then just find that problem and point it out. I'm not saying we shouldn't merge this, quite the contrary, I'm saying we should merge it after we have identified the problem it is solving and then used it to solve that problem. If the problem is so obvious, you should have no problem finding it. To be blunt, don't waste your time arguing about whether something is useful in theory. I'm certain that 'reserve()' is useful in theory. Instead, spend your time showing where it is useful 'in practice' |
A few cases I could find in
The one case I applied
... |
@clayjohn Growth is especially costly for hashing types, so In general though, while we don't use |
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.
In my opinion, this is needed. But I'd like to clear up concerns with @clayjohn before merge.
"Expose" is a very strong word in Godot, as you can see. I would suggest renaming the commit and title to something else. Maybe "Allow |
I'd say "Add reserve and use in GDScriptVM" |
3e17771
to
0628323
Compare
reserve()
to Dictionary
, use it on the GDScript VMreserve()
to Dictionary
, apply to constructors on GDScript VM
|
I'd keep that separately, that would only work for the C++ side due to overrides etc. so it's less critical, we don't have it for |
0628323
to
8a7a0fa
Compare
Rebased on top of #110717 changes. I also noticed that |
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.
Re-approving after changes.
HashMap
has areserve()
function, so I thought: why not expose it toDictionary
? There is a lot of places within the engine we could use it to reduce bottleneck.Additionally, implementing is quite simple since all needed is to call the
HashMap
's ownreserve()
, much like howclear()
inDictionary
is mostly a wrapper to its internalHashMap
'sclear()
.I noticed in the GDScript VM that the constructor for both untyped and typed
Dictionary
uses a for loop with known final size, so that was possibly the best candidate for a stress test. The test consists in declaring aDictionary
with 63 elements mid-function 2²¹ times.Script
I made two template release builds, with and without this PR, and ran the script.
Before:
After:
There are countless places where
reserve()
could be used, so this is just a beginning.