-
Notifications
You must be signed in to change notification settings - Fork 36
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 TypeManager.function/TypeManager.virtual_function fetch speed by using cache. #479
base: master
Are you sure you want to change the base?
Conversation
… by using cache and setattr.
m_func.__doc__ = doc | ||
|
||
# Set the MemberFunction as an attribute to the instance. | ||
setattr(obj, fget_self.name, m_func) |
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.
This is going to cause obj
to leak forever.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
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.
OK, that doesn't really make much sense. Forget about it.
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.
This was discarded. Here are the new test results.
Output :
TypeManager.function Test
4.355441149324179 Test._spawn
4.830625455826521 test._spawn
4.801660872995853 Test()._spawn
↓
0.023133378475904465 Test._spawn
0.29126785323023796 test._spawn
0.293557733297348 Test()._spaw
TypeManager.virtual_function Test
0.5497394129633904 test.blind
0.5683586820960045 make_object(Test, pointer).blind
↓
0.46108797565102577 test.blind
0.4727563001215458 make_object(Test, pointer).blind
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.
So there is no way to set MemberFunction to the instance. Can't we just use types.MethodType, for example, and set the method to the instance with a name like _function_name, with the exception for normal function call?
As you figured already, you would get the same leak with MethodType
. In fact, any objects inheriting from Boost.Python.instance
are never traversed for circular references. Basically, if any objects contained into its __dict__
strongly reference the object it belongs to it will be kept hostage by the circular references. For example, the following would leak:
ptr = alloc(1024)
ptr.self = ptr
Because the refcount of ptr
will never reach zero, and will never be traversed by the cyclic collection. EntityMemFuncWrapper
workaround this by storing a weak proxy instead of a strong reference:
self.wrapped_self = proxy(wrapped_self) |
An easy workaround here, could be to simply set MemberFunction._this
to obj
's pointer instead of obj
itself since that is all MemberFunction
really need to forward the calls. Though, we should probably address the issue at the root, but I'm not sure of the overall implications.
EDIT: This seems to address the issue: ab33bc8
from gc import collect, is_tracked
from weakref import ref
from memory import alloc
ptr = alloc(1024)
# ptr should not be tracked, because it has no __dict__
assert not is_tracked(ptr)
ptr.self = ptr
# Now that ptr has a __dict__, it should be tracked
assert is_tracked(ptr)
r = ref(ptr)
# Our ref should be alive because ptr is still referenced
assert r()
del ptr
collect()
# Now that ptr has been deleted and collected, our ref should be dead
assert not r()
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.
Are there any other issues with this pull request?
I haven't tested, but based on the code, I can tell you that the _ptr()
call on L628 is redundant since ptr
is already a Pointer
. That said, I think virtual_function
could probably make great use of CachedProperty
.
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 haven't tested, but based on the code, I can tell you that the
_ptr()
call on L628 is redundant sinceptr
is already aPointer
.
Done.
That said, I think
virtual_function
could probably make great use ofCachedProperty
.
Using CachedProperty
leaks ptr/_this
. Is there a way to use CachedProperty
without causing leaks?
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.
Using
CachedProperty
leaksptr/_this
. Is there a way to useCachedProperty
without causing leaks?
Technically this is what unbound
is meant for. But now that I think about it, it seems flawed because this introduce a triangular reference that even ab33bc8 would theoretically not address.
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.
Yes, it does not work regardless of the value of unbound.
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.
Yes, it does not work regardless of the value of unbound.
Yeah, and it makes sense. Meaning that cached_result
suffers from this regardless of 6d594fb. I don't remember specifically what testing I performed at the time that led me to believe otherwise but, if I had to guess, I probably used Player.is_bot
with non-cached objects. This is misleading because it inherits from Entity.__hash__
meaning that the same value is re-used for every objects that are allocated for the same player.
Changed virtual_function to be cached as well.
c197899
to
094c66b
Compare
a27f20f
to
07e7bba
Compare
Entity has a mechanism to speed up the retrieval of dynamic_attributes/server_classes, but TypeManager itself does not. With this improvement, instances created by TypeManager can speed up the retrieval of function/virtual_function.
In virtual_function, I tried to improve the performance by using type_info and caching, but it did not improve the performance.
Test Code (CS:GO/Linux):
Since the implementation has changed, the test results have also changed.
Output :