Re-implement Python -fastproxy option.

The previous implementation failed with Python 3 and abstract base clases.
The new implementation replaces the Python 2 implementation using new.instancemethod with C API PyMethod_New to match the equivalent Python 3 implementation which uses PyInstanceMethod_New.

Closes #1310
This commit is contained in:
William S Fulton 2018-08-17 23:34:29 +01:00
commit c9cac931c7
6 changed files with 144 additions and 32 deletions

View file

@ -71,6 +71,10 @@
<li><a href="#Python_nn42">Adding additional Python code</a>
<li><a href="#Python_nn43">Class extension with %extend</a>
<li><a href="#Python_nn44">Exception handling with %exception</a>
<li><a href="#Python_optimization">Optimization options</a>
<ul>
<li><a href="#Python_fastproxy">-fastproxy</a>
</ul>
</ul>
<li><a href="#Python_nn45">Tips and techniques</a>
<ul>
@ -3797,6 +3801,99 @@ The language-independent <tt>exception.i</tt> library file can also be used
to raise exceptions. See the <a href="Library.html#Library">SWIG Library</a> chapter.
</p>
<H3><a name="Python_optimization">38.6.5 Optimization options</a></H3>
<H4><a name="Python_fastproxy">38.6.5.1 -fastproxy</a></H4>
<p>
The <tt>-fastproxy</tt> command line option enables faster method calling as the call is made directly into the C/C++ layer rather than going through a method wrapper.
</p>
<p>
Consider wrapping a C++ class:
</p>
<div class="code">
<pre>
struct Go {
void callme0() {}
void callme4(int a, int b, int c, int d) {}
void callme8(double a, double b, double c, double d, double e, double f, double g, double i) {}
};
</pre>
</div>
<p>
The default generated proxy class is:
</p>
<div class="targetlang">
<pre>
class Go(object):
def callme0(self):
return _example.Go_callme0(self)
def callme4(self, a, b, c, d):
return _example.Go_callme4(self, a, b, c, d)
def callme8(self, a, b, c, d, e, f, g, i):
return _example.Go_callme8(self, a, b, c, d, e, f, g, i)
...
</pre>
</div>
<p>
The generated code when using <tt>-fastproxy</tt> is:
</p>
<div class="targetlang">
<pre>
%module example
class Go(_object):
callme0 = _swig_new_instance_method(_example.Go_callme0)
callme4 = _swig_new_instance_method(_example.Go_callme4)
callme8 = _swig_new_instance_method(_example.Go_callme8)
...
</pre>
</div>
<p>
where <tt>_swig_new_instance_method</tt> adds the method to the proxy class via C API calls.
The overhead calling into C/C++ from Python is reduced slightly using <tt>-fastproxy</tt>.
Below are some timings in microseconds calling the 3 functions in the example above:
</p>
<table summary="Python fastproxy performance">
<tr>
<th>Method name</th>
<th>Without -proxy</th>
<th>With -proxy</th>
</tr>
<tr>
<td>callme0</td>
<td>0.57</td>
<td>0.48</td>
</tr>
<tr>
<td>callme4</td>
<td>0.64</td>
<td>0.54</td>
</tr>
<tr>
<td>callme8</td>
<td>0.73</td>
<td>0.57</td>
</tr>
</table>
<p>
Although the <tt>-fastproxy</tt> option results in faster code, the generated proxy code is not as user-friendly
as docstring/doxygen comments and functions with default values are not visible in the generated python proxy class.
</p>
<H2><a name="Python_nn45">38.7 Tips and techniques</a></H2>