<div dir="ltr"><div class="gmail_default" style="font-size:small">Hello,</div><div class="gmail_default" style="font-size:small">recently I have been playing a bit with cpyext, so see if there are low haning fruits to be taken to improve the performance.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">I didn't get any real result but I think it's interesting to share my findings. </div><div class="gmail_default" style="font-size:small">The benchmark I'm using is here:</div><div class="gmail_default"><a href="https://github.com/antocuni/cpyext-benchmarks">https://github.com/antocuni/cpyext-benchmarks</a><br></div><div class="gmail_default"><br></div><div class="gmail_default">it contains a simple C extension defining three methods, one for each METH_NOARGS, METH_O and METH_VARARGS flags.</div><div class="gmail_default"><br></div><div class="gmail_default">So first, the results with CPython and PyPy 5.8:</div><div class="gmail_default"><div class="gmail_default"><br></div><div class="gmail_default">$ python bench.py </div><div class="gmail_default">noargs : 0.78 secs</div><div class="gmail_default">onearg : 0.89 secs</div><div class="gmail_default">varargs: 1.05 secs</div><div><br></div><div><div>$ pypy bench.py </div><div>noargs : 1.67 secs</div><div>onearg : 2.13 secs</div><div>varargs: 4.89 secs</div></div><div><br></div><div>Then, I tried my cpyext-jit branch; this branch does two things:</div><div>1) it makes cpyext visible to the JIT, and add enough @jit.dont_look_inside so that it actually compiles</div><div>2) merges part of the cpyext-callopt branch, up to rev 9cbc8bd76297 (more on this later): this adds fast paths for METH_NOARGS and METH_O to avoid going through the slow __args__.unpack():</div><div><br></div><div><div>$ pypy-cpyext-jit bench.py</div><div>noargs : 0.30 secs</div><div>onearg : 0.31 secs</div><div>varargs: 4.90 secs</div></div><div><br></div><div>So, apparently this is enough to greatly speedup the calls, and be even faster than CPython. Note that "onearg" calls "simple.onearg(None)".</div><div><br></div><div>However, things become more complicated as soon as I start passing various kind of objects to onearg():</div><div><br></div><div><div>$ pypy bench_oneargs.py   # pypy 5.8</div><div>onearg(None): 2.09 secs</div><div>onearg(1)   : 2.07 secs</div><div>onearg(i)   : 4.98 secs</div><div>onearg(i%2) : 4.92 secs</div><div>onearg(X)   : 2.13 secs</div><div>onearg((1,)): 2.30 secs</div><div>onearg((i,)): 9.80 secs</div></div><div><br></div><div><br></div><div><div>$ pypy-cpyext-jit bench_oneargs.py </div><div>onearg(None): 0.30 secs</div><div>onearg(1)   : 0.30 secs</div><div>onearg(i)   : 2.52 secs</div><div>onearg(i%2) : 2.56 secs</div><div>onearg(X)   : 0.30 secs</div><div>onearg((1,)): 0.30 secs</div><div>onearg((i,)): 7.45 secs</div></div><div><br></div><div><br></div><div>so, the call optimization still helps, but as soon as we need to convert one object from pypy to cpython we are horribly slow. However, it is interesting to note that:</div><div>1) if we pass a constant object, we are fast: None, 1, (1,)</div><div>2) if we pass X (which is a global X=100), we are still fast</div><div>3) any other object which is created on the fly is slow</div><div><br></div><div>Looking at the traces, they look more or less the same in the three cases, so I don't really understand what is the difference.</div><div><br></div><div>Finally, about the branch cpyext-callopt, which was started in Leysin by Richard, Armin and me: I am not sure to fully understand the purpose of dbba78b270fd: apparently, the optimization done in 9cbc8bd76297 seems to work well, so what am I missing?</div><div><br></div><div>ciao,</div><div>Anto</div></div></div>