Hello, I would like to propose two patches to speedup the bindings of PyGObject through introspection.
Profiling my code with cProfile in Python, I notice that some getattr routines are called a huge number of time. Indeed, looking closer, it comes from the fact that Python is looking for a __path__ attribute each time getattr() is called. So my first proposed patch add a __path__ attribute in IntrospectionModule and DynamicModule classes: https://bugzilla.gnome.org/show_bug.cgi?id=630807 Then, I notice that __getattr__ of DynamicModule is always called when accessing a method or an attribute, while this method or attribute may be found in override or in the introspection itself. The second patch I suggest is a bit more intrusive and propose to move the setattr() from the IntrospectionModule or the Override to the DynamicModule itself. Currently, we have the following scheme: from gi.repository import foo a = foo.bar() b = foo.bar() will expand in: getattr(foo, "bar") is None so a = foo.introspection_module.__getattr__("bar") and register "bar" as a method of foo.introspection_module getattr(foo, "bar") is still None so b = getattr(foo.introspection_module, "bar") while, the proposed patch will give: getattr(foo, "bar") is None so a = foo.introspection_module.__getattr__("bar") and register "bar" as method of foo b = getattr(foo, "bar") I.e. we save one getattr() call. Here is the patch: https://bugzilla.gnome.org/show_bug.cgi?id=630810 I give you the following profiling information: Current HEAD: ============ ncalls tottime cumtime filename:lineno(function) 1 0.000 7.758 <string>:1(<module>) 886600 0.618 3.483 module.py:226(__getattr__) 443301 0.914 2.269 module.py:92(__getattr__) 4 0.000 0.000 types.py:37(Function) 63726 0.046 2.300 types.py:39(function) 886600 0.596 2.865 {getattr} 443301 1.355 1.355 {method 'find_by_name' of 'gi.Repository' 63726 1.476 2.254 {method 'invoke' of 'gi.FunctionInfo' Adding __path__ attribute in DynamicModule and IntrospectionModule: ================================================================== ncalls tottime cumtime filename:lineno(function) 1 0.000 3.864 <string>:1(<module>) 443300 0.331 0.427 module.py:228(__getattr__) 1 0.000 0.000 module.py:93(__getattr__) 4 0.000 0.000 types.py:37(Function) 63726 0.048 1.425 types.py:39(function) 443300 0.096 0.096 {getattr} 1 0.000 0.000 {method 'find_by_name' of 'gi.Repository' 63726 1.277 1.377 {method 'invoke' of 'gi.FunctionInfo' Registering attributes and methods in the DynamicModule instead of in its introspection_module attribute: ================================================================== ncalls tottime cumtime filename:lineno(function) 1 0.000 2.629 <string>:1(<module>) 1 0.000 0.000 module.py:227(__getattr__) 1 0.000 0.000 module.py:93(__getattr__) 4 0.000 0.000 types.py:37(Function) 63726 0.050 1.109 types.py:39(function) 1 0.000 0.000 {method 'find_by_name' of 'gi.Repository' 63726 1.059 1.059 {method 'invoke' of 'gi.FunctionInfo' One can see that half of the __getattr__ (and all find_by_name) are removed by the __path__ patch and that the other half of __getattr__ is removed by the second patch. I ran make check and make chek.valgrind, everything is fine. What's your opinion on this optimisation ? Damien. _______________________________________________ pygtk mailing list [email protected] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/
