Speedup in execution
- From: Damien Caliste <damien caliste cea fr>
- To: pygtk <pygtk daa com au>, python-hackers-list <python-hackers-list gnome org>
- Subject: Speedup in execution
- Date: Tue, 28 Sep 2010 13:12:33 +0200
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.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]