-
-
Notifications
You must be signed in to change notification settings - Fork 589
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
Unregister custom classes in reverse registration order #1047
Conversation
Maybe we can use a different data structure than |
I thought about that for a moment. Yet I have seen several queries being performed within the code. I'm unsure of the performance impact of changing the data structure on those operations. |
Do you have plans to update this PR or merge it? |
The complexity of querying Regarding the concept of The only overhead introduced by this PR is Of course the overhead could be eliminated by choosing other implementation, but even so we will need to save the insertion order as an independent data, if we are to preserve the querying efficiency. Such implementation and this PR's implementation would look very much alike. @akien-mga I can still reproduce the original issue on current master, and I need some fix to be deployed. Could we merge this PR? |
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 get a segfault when testing this PR - details below!
Other than that, I think the approach in this PR is good. Regarding @akien-mga's comment:
Maybe we can use a different data structure than std::unordered_map in the first place if we actually care about the order?
I didn't do any benchmarking, but a std::map
(which retains order) is slower to query than an std::unordered_map
, and we're mostly querying classes
.
See: https://www.geeksforgeeks.org/map-vs-unordered_map-c/
By adding an extra std::vector
, we're increasing memory usage, but not by very much: a StringName
is 8 bytes, and this vector only contains the custom classes registered in the given extension. If the extension registers 10 classes, that's only 80 bytes (plus whatever accounting is in std::vector
, like the size).
But, in exchange for the extra memory, we're maintaining query performance of the classes
unordered map. Since it's only this one time when uninitializing an extension that we care about the order, I think this an OK trade-off.
src/core/class_db.cpp
Outdated
@@ -341,13 +342,16 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) { | |||
} | |||
|
|||
void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { | |||
for (const std::pair<StringName, ClassInfo> pair : classes) { | |||
const ClassInfo &cl = pair.second; | |||
for (size_t i = class_register_order.size() - 1; i >= 0; i--) |
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 get a segfault when testing with this PR - the cause is the for loop here.
On my system at least, size_t
is unsigned. This loop will run so long as i >= 0
, which means that after i is 0
and it decrements again, it'll wrap around to the max value (rather than stopping the loop), and try to access beyond the length of the vector. And if the segfault didn't kill it, it would loop forever. :-)
If I change the loop to look like this:
for (std::vector<StringName>::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) {
const StringName &name = *i;
... then there is no segfault, and the bug this is attempting to fix is fixed!
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.
Added that change. Forgot to consider the case of no registered custom classes!
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.
Thanks!
FYI, this segfaults even when there are register custom classes, because i
will eventually decrement to 0
(but not stop because the condition is i >= 0
), and then i--
will flip it over to the maximum value rather than -1
, because size_t
is unsigned (at least on my system) and can't represent -1
. I'm assuming it works for you because size_t
is signed on your system?
In any case, with this change your PR is working great for me!
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.
As far as I know size_t
is a typedef
and it's always unsigned. To be honest, now that you mentioned it I have no idea why the loop worked!
This looks good to me! However, per Godot's PR workflow, you'll need squash this into a single commit. See the docs here for how to do that with an interactive rebase: https://docs.godotengine.org/en/stable/contributing/workflow/pr_workflow.html#the-interactive-rebase |
Will it be merged before the 4.1 release? |
Maybe! It's been on our list to discuss at GDExtension meetings for a while, we just haven't gotten to it. However, it'd definitely need to be rebased with the conflicts resolved in order for it to be merged. |
I can do the rebase myself. Should I do this? |
If the original author doesn't respond after awhile or isn't interested in rebasing, then, yes, you can rebase it in a new PR!
If you pull the branch this PR is based on, and do
You can re-write the commit message via |
Hello. Im deeply sorry for the amont of time it took for me to answer. Im out of town without access to my working machine. I will be back next saturday.
Yuri Sarudiansky
***@***.***
…________________________________
From: David Snopek ***@***.***>
Sent: Wednesday, June 14, 2023 4:02 PM
To: godotengine/godot-cpp ***@***.***>
Cc: Kehom ***@***.***>; Author ***@***.***>
Subject: Re: [godotengine/godot-cpp] Unregister custom classes in reverse registration order (PR #1047)
@DmitriySalnikov<https://github.com/DmitriySalnikov>:
I can do the rebase myself. Should I do this?
If the original author doesn't respond after awhile or isn't interested in rebasing, then, yes, you can rebase it in a new PR!
But I'm not sure how to specify a co-author.
If you pull the branch this PR is based on, and do git rebase, it should retain the original author on the commit. However, there is also this convention used on GitHub, where you put a line like this at the end of the commit message:
Co-authored-by: name ***@***.***>
You can re-write the commit message via git rebase or git commit --amend
—
Reply to this email directly, view it on GitHub<#1047 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEUTOPNUGFG76HM6NYXJFHLXLIDCTANCNFSM6AAAAAAU6IU7V4>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
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.
Discussed at the GDExtension meeting: we think using the seperate vector<T>
is fine, especially since there won't be too many classes (only the classes registered in this GDExtension). Approved pending the rebase!
Thanks! And congrats for your first merged Godot contribution 🎉 |
This should fix #914 , hopefully without any side effects.