From 094c66b5799271801eb9141120d0869a982e98d6 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:52:18 +0900 Subject: [PATCH 1/5] Improve TypeManager.function/TypeManager.virtual_function fetch speed by using cache and setattr. --- .../packages/source-python/memory/manager.py | 81 ++++++++++++------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/addons/source-python/packages/source-python/memory/manager.py b/addons/source-python/packages/source-python/memory/manager.py index b09649420..218709c09 100755 --- a/addons/source-python/packages/source-python/memory/manager.py +++ b/addons/source-python/packages/source-python/memory/manager.py @@ -619,21 +619,34 @@ def virtual_function( if return_type not in DataType.values: return_type = self.create_converter(return_type) - def fget(ptr): - """Return the virtual function.""" - # Create the virtual function - func = ptr.make_virtual_function( - index, - convention, - args, - return_type - ) + class fget(object): + def __set_name__(fget_self, owner, name): + fget_self.name = name + + def __get__(fget_self, obj, cls=None): + """Return the virtual function.""" + if obj is None: + return fget_self + + # Create the virtual function + func = obj.make_virtual_function( + index, + convention, + args, + return_type + ) + + # Wrap it using MemberFunction, so we don't have to pass the this + # pointer anymore + func = MemberFunction(self, return_type, func, obj) + func.__doc__ = doc - # Wrap it using MemberFunction, so we don't have to pass the this - # pointer anymore - return MemberFunction(self, return_type, func, ptr) + # Set the MemberFunction as an attribute to the instance. + setattr(obj, fget_self.name, func) - return property(fget, None, None, doc) + return func + + return fget() def function( self, identifier, args=(), return_type=DataType.VOID, @@ -646,34 +659,48 @@ def function( if return_type not in DataType.values: return_type = self.create_converter(return_type) + # Store the function cache + func = None + class fget(object): + def __set_name__(fget_self, owner, name): + fget_self.name = name + def __get__(fget_self, obj, cls=None): + nonlocal func if cls is None: if obj is None: return fget_self else: cls = obj.__class__ - if cls._binary is None: - raise ValueError('_binary was not specified.') + if func is None: + if cls._binary is None: + raise ValueError('_binary was not specified.') - # Create a binary object - binary = find_binary(cls._binary, cls._srv_check) + # Create a binary object + binary = find_binary(cls._binary, cls._srv_check) - # Create the function object - func = binary[identifier].make_function( - convention, - args, - return_type - ) + # Create the function object and cache it + func = binary[identifier].make_function( + convention, + args, + return_type + ) + func.__doc__ = doc # Called with a this pointer? if obj is not None: - # Wrap the function using MemberFunction, so we don't have - # to pass the this pointer anymore - func = MemberFunction(self, return_type, func, obj) + # Wrap the function using MemberFunction, + # so we don't have to pass the this pointer anymore + m_func = MemberFunction(self, return_type, func, obj) + m_func.__doc__ = doc + + # Set the MemberFunction as an attribute to the instance. + setattr(obj, fget_self.name, m_func) + + return m_func - func.__doc__ = doc return func return fget() From db804ed955a21b48270776ae47804a389588b018 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sun, 18 Jun 2023 00:31:59 +0900 Subject: [PATCH 2/5] Removed MemberFunction as an attribute. Changed virtual_function to be cached as well. --- .../packages/source-python/memory/manager.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/addons/source-python/packages/source-python/memory/manager.py b/addons/source-python/packages/source-python/memory/manager.py index 218709c09..9c9f2fd9f 100755 --- a/addons/source-python/packages/source-python/memory/manager.py +++ b/addons/source-python/packages/source-python/memory/manager.py @@ -619,6 +619,8 @@ def virtual_function( if return_type not in DataType.values: return_type = self.create_converter(return_type) + funcs = {} + class fget(object): def __set_name__(fget_self, owner, name): fget_self.name = name @@ -628,22 +630,26 @@ def __get__(fget_self, obj, cls=None): if obj is None: return fget_self - # Create the virtual function - func = obj.make_virtual_function( - index, - convention, - args, - return_type - ) + # Get the vtable address + address = obj._ptr().get_pointer().address + # Search function cache by vtable address + func = funcs.get(address, None) + + if func is None: + # Create the virtual function cache it + func = obj.make_virtual_function( + index, + convention, + args, + return_type + ) + funcs[address] = func # Wrap it using MemberFunction, so we don't have to pass the this # pointer anymore func = MemberFunction(self, return_type, func, obj) func.__doc__ = doc - # Set the MemberFunction as an attribute to the instance. - setattr(obj, fget_self.name, func) - return func return fget() @@ -696,9 +702,6 @@ def __get__(fget_self, obj, cls=None): m_func = MemberFunction(self, return_type, func, obj) m_func.__doc__ = doc - # Set the MemberFunction as an attribute to the instance. - setattr(obj, fget_self.name, m_func) - return m_func return func From 3d5311d32fa431f44bf388916db989c78d4b3a75 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Sun, 18 Jun 2023 01:00:22 +0900 Subject: [PATCH 3/5] Minor fixes. --- .../packages/source-python/memory/manager.py | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/addons/source-python/packages/source-python/memory/manager.py b/addons/source-python/packages/source-python/memory/manager.py index 9c9f2fd9f..0fee5479d 100755 --- a/addons/source-python/packages/source-python/memory/manager.py +++ b/addons/source-python/packages/source-python/memory/manager.py @@ -619,40 +619,34 @@ def virtual_function( if return_type not in DataType.values: return_type = self.create_converter(return_type) + # Store the function cache funcs = {} - class fget(object): - def __set_name__(fget_self, owner, name): - fget_self.name = name - - def __get__(fget_self, obj, cls=None): - """Return the virtual function.""" - if obj is None: - return fget_self - - # Get the vtable address - address = obj._ptr().get_pointer().address - # Search function cache by vtable address - func = funcs.get(address, None) - - if func is None: - # Create the virtual function cache it - func = obj.make_virtual_function( - index, - convention, - args, - return_type - ) - funcs[address] = func + def fget(ptr): + """Return the virtual function.""" + # Get the vtable address + address = ptr._ptr().get_pointer().address + # Search function cache by vtable address + func = funcs.get(address, None) + + if func is None: + # Create the virtual function cache it + func = ptr.make_virtual_function( + index, + convention, + args, + return_type + ) + funcs[address] = func - # Wrap it using MemberFunction, so we don't have to pass the this - # pointer anymore - func = MemberFunction(self, return_type, func, obj) - func.__doc__ = doc + # Wrap it using MemberFunction, so we don't have to pass the this + # pointer anymore + m_func = MemberFunction(self, return_type, func, ptr) + m_func.__doc__ = doc - return func + return m_func - return fget() + return property(fget, None, None, doc) def function( self, identifier, args=(), return_type=DataType.VOID, @@ -669,9 +663,6 @@ def function( func = None class fget(object): - def __set_name__(fget_self, owner, name): - fget_self.name = name - def __get__(fget_self, obj, cls=None): nonlocal func if cls is None: @@ -697,8 +688,8 @@ def __get__(fget_self, obj, cls=None): # Called with a this pointer? if obj is not None: - # Wrap the function using MemberFunction, - # so we don't have to pass the this pointer anymore + # Wrap the function using MemberFunction, so we don't have + # to pass the this pointer anymore m_func = MemberFunction(self, return_type, func, obj) m_func.__doc__ = doc From 07e7bba3ecee6bcb3b3e4e241c13d2b7e6e0e56f Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Wed, 21 Jun 2023 22:10:42 +0900 Subject: [PATCH 4/5] Changed virtual_function to use a function cache that already exists. --- .../source-python/packages/source-python/memory/manager.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/source-python/packages/source-python/memory/manager.py b/addons/source-python/packages/source-python/memory/manager.py index 0fee5479d..71b2f481d 100755 --- a/addons/source-python/packages/source-python/memory/manager.py +++ b/addons/source-python/packages/source-python/memory/manager.py @@ -637,6 +637,11 @@ def fget(ptr): args, return_type ) + for func_cache in funcs.values(): + if func_cache == func: + func = func_cache + break + funcs[address] = func # Wrap it using MemberFunction, so we don't have to pass the this From 60808eac1f57474a6de19da3caec952ab83c66ba Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Mon, 26 Jun 2023 01:39:10 +0900 Subject: [PATCH 5/5] Removed unnecessary _ptr call. --- addons/source-python/packages/source-python/memory/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/source-python/packages/source-python/memory/manager.py b/addons/source-python/packages/source-python/memory/manager.py index 71b2f481d..4f07056ab 100755 --- a/addons/source-python/packages/source-python/memory/manager.py +++ b/addons/source-python/packages/source-python/memory/manager.py @@ -625,7 +625,7 @@ def virtual_function( def fget(ptr): """Return the virtual function.""" # Get the vtable address - address = ptr._ptr().get_pointer().address + address = ptr.get_pointer().address # Search function cache by vtable address func = funcs.get(address, None)