Last active
May 2, 2024 08:11
-
-
Save brentp/7e173302952b210aeaf3 to your computer and use it in GitHub Desktop.
compare call overhead of cffi and cython
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Compare speed of a cython wrapper vs a cffi wrapper to the same underlying | |
C-code with a fast function and a longer-running function. | |
This should run anywhere that has cffi and cython installed. | |
Ouput on my machine with python2.7: | |
brentp@liefless:/tmp$ python compare-wrappers.py | |
times for 1 million calls | |
adding 2 numbers with cffi wrapper: | |
0.147660017014 | |
adding 2 numbers with cython wrapper: | |
0.0891411304474 | |
summing numbers between 1 and 2000 with cffi wrapper: | |
1.6725051403 | |
summing numbers between 1 and 2000 with cython wrapper: | |
1.54648685455 | |
So Cython is twice as fast for a C-function that returns pretty much instantly. | |
That difference is nullified (so to speak) when the C function takes more time to run. | |
Time with pypy: | |
times for 1 million calls | |
adding 2 numbers with cffi wrapper: | |
0.0336790084839 | |
summing numbers between 1 and 2000 with cffi wrapper: | |
1.42473888397 | |
""" | |
from timeit import timeit | |
import cffi | |
import re | |
import os.path as op | |
import sys | |
PYPY = "pypy_version_info" in dir(sys) | |
ffi = cffi.FFI() | |
ffi.cdef(""" | |
int sum(int, int); | |
long sum_between(int, int); | |
""") | |
# here is the C code that we are wrapping. One quick running function and | |
# another potentially long-running function. | |
code = """ | |
int sum(int a, int b){ | |
return a + b; | |
} | |
long sum_between(int a, int b){ | |
long sum = 0; | |
int i; | |
for(i=a; i<=b; i++) sum += i; | |
return sum; | |
} | |
""" | |
C = ffi.verify(code) | |
if not PYPY: | |
import pyximport; pyximport.install() | |
with open('ccy.h', 'w') as fh: | |
fh.write(code) | |
# for cython, we also need to write the python callable wrappers. | |
cycode = """ | |
cdef extern from "%s/ccy.h": | |
int sum(int a, int b) | |
long sum_between(int a, int b) | |
cpdef int pysum(int a, int b): | |
return sum(a, b) | |
cpdef long pysum_between(int a, int b): | |
return sum_between(a, b) | |
""" % op.abspath(".") | |
with open('ccy.pyx', 'w') as fh: | |
fh.write(cycode) | |
import ccy | |
print "times for 1 million calls" | |
print "adding 2 numbers with cffi wrapper:" | |
print timeit("C.sum(55, 55)", setup="from __main__ import C", number=int(1e6)) | |
if not PYPY: | |
print "adding 2 numbers with cython wrapper:" | |
print timeit("ccy.pysum(55, 55)", setup="from __main__ import ccy") | |
print "summing numbers between 1 and 2000 with cffi wrapper:" | |
print timeit("C.sum_between(1, 2000)", setup="from __main__ import C") | |
if not PYPY: | |
print "summing numbers between 1 and 2000 with cython wrapper:" | |
print timeit("ccy.pysum_between(1, 2000)", setup="from __main__ import ccy") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment