Making Python faster¶
The Julia website has a set of benchmarks to show how fast it is. These
are for toy functions, but serve as a nice set of examples for the
basics of using cython
and numba
in Python.
These examples are adapted from here
In [2]:
benchmarks = pd.read_pickle('julia_benchmarks.pic')
benchmarks.ix[:, :6]
Out[2]:
Fortran | Julia | Python | R | Matlab | ||
---|---|---|---|---|---|---|
1 | fib | 0.70 | 2.11 | 77.76 | 533.52 | 26.89 |
2 | parse_int | 5.05 | 1.45 | 17.02 | 45.73 | 802.52 |
3 | quicksort | 1.31 | 1.15 | 32.89 | 264.54 | 4.92 |
4 | mandel | 0.81 | 0.79 | 15.32 | 53.16 | 7.58 |
5 | pi_sum | 1.00 | 1.00 | 21.99 | 9.56 | 1.00 |
6 | rand_mat_stat | 1.45 | 1.66 | 17.93 | 14.56 | 14.52 |
7 | rand_mat_mul | 3.48 | 1.02 | 1.14 | 1.57 | 1.12 |
In [145]:
import time
import random
import numpy as np
In [119]:
from numba import njit, jit
In [120]:
%load_ext cython
The cython extension is already loaded. To reload it, use:
%reload_ext cython
Timing and reproting functions
In [121]:
def timer(f, *args, **kwargs):
start = time.clock()
ans = f(*args, **kwargs)
return ans, time.clock() - start
In [130]:
def report(fs, *args, **kwargs):
ans, t = timer(fs[0], *args, **kwargs)
print('%s: %.1f' % (fs[0].__name__, 1.0))
for f in fs[1:]:
ans_, t_ = timer(f, *args, **kwargs)
print('%s: %.1f' % (f.__name__, t/t_))
Fib¶
In [63]:
def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)
In [64]:
fib(20)
Out[64]:
6765
In [113]:
%timeit fib(20)
100 loops, best of 3: 5.84 ms per loop
In [68]:
from functools import lru_cache
@lru_cache()
def fib_lru(n):
if n<2:
return n
return fib(n-1)+fib(n-2)
In [114]:
%timeit fib_lru(20)
The slowest run took 92.76 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 213 ns per loop
In [115]:
%%cython -a
cpdef long fib_cython(int n):
if n<2:
return n
return fib_cython(n-1) + fib_cython(n-2)
Out[115]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
1:
+2: cpdef long fib_cython(int n):
static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/ static long __pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(int __pyx_v_n, CYTHON_UNUSED int __pyx_skip_dispatch) { long __pyx_r; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("fib_cython", 0); /* … */ /* function exit code */ __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } /* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/ static PyObject *__pyx_pw_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_1fib_cython(PyObject *__pyx_self, PyObject *__pyx_arg_n) { int __pyx_v_n; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("fib_cython (wrapper)", 0); assert(__pyx_arg_n); { __pyx_v_n = __Pyx_PyInt_As_int(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; __Pyx_AddTraceback("_cython_magic_a7383439b4d9daca4b8a6d569c53a027.fib_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; __pyx_r = __pyx_pf_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(__pyx_self, ((int)__pyx_v_n)); int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("fib_cython", 0); __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython(__pyx_v_n, 0)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_cython_magic_a7383439b4d9daca4b8a6d569c53a027.fib_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
+3: if n<2:
__pyx_t_1 = ((__pyx_v_n < 2) != 0); if (__pyx_t_1) { /* … */ }
+4: return n
__pyx_r = __pyx_v_n; goto __pyx_L0;
+5: return fib_cython(n-1) + fib_cython(n-2)
__pyx_r = (__pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython((__pyx_v_n - 1), 0) + __pyx_f_46_cython_magic_a7383439b4d9daca4b8a6d569c53a027_fib_cython((__pyx_v_n - 2), 0)); goto __pyx_L0;
In [116]:
%timeit fib_cython(20)
10000 loops, best of 3: 129 µs per loop
In [82]:
@njit
def fib_numba(n):
a, b = 0, 1
for i in range(n-1):
a, b = b, a + b
return b
In [83]:
%timeit -r3 -n3 fib_numba(20)
The slowest run took 49263.70 times longer than the fastest. This could mean that an intermediate result is being cached
3 loops, best of 3: 501 ns per loop
In [84]:
%load_ext cython
In [123]:
%%cython -a
def fib_cython_seq(int n):
cdef int i
cdef long a, b, tmp
a = 0
b = 1
for i in range(n-1):
tmp = a
a = b
b += tmp
return b
Out[123]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
01:
+02: def fib_cython_seq(int n):
/* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/ static PyMethodDef __pyx_mdef_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq = {"fib_cython_seq", (PyCFunction)__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq, METH_O, 0}; static PyObject *__pyx_pw_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq(PyObject *__pyx_self, PyObject *__pyx_arg_n) { int __pyx_v_n; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("fib_cython_seq (wrapper)", 0); assert(__pyx_arg_n); { __pyx_v_n = __Pyx_PyInt_As_int(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; __Pyx_AddTraceback("_cython_magic_106e06d591bbaf06dba1a9e2a3411245.fib_cython_seq", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; __pyx_r = __pyx_pf_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_fib_cython_seq(__pyx_self, ((int)__pyx_v_n)); int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_fib_cython_seq(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) { CYTHON_UNUSED int __pyx_v_i; long __pyx_v_a; long __pyx_v_b; long __pyx_v_tmp; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("fib_cython_seq", 0); /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_3); __Pyx_AddTraceback("_cython_magic_106e06d591bbaf06dba1a9e2a3411245.fib_cython_seq", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_tuple_ = PyTuple_Pack(6, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_tmp); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple_); __Pyx_GIVEREF(__pyx_tuple_); /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_106e06d591bbaf06dba1a9e2a3411245_1fib_cython_seq, NULL, __pyx_n_s_cython_magic_106e06d591bbaf06db); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_fib_cython_seq, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
03: cdef int i
04: cdef long a, b, tmp
+05: a = 0
__pyx_v_a = 0;
+06: b = 1
__pyx_v_b = 1;
+07: for i in range(n-1):
__pyx_t_1 = (__pyx_v_n - 1); for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) { __pyx_v_i = __pyx_t_2;
+08: tmp = a
__pyx_v_tmp = __pyx_v_a;
+09: a = b
__pyx_v_a = __pyx_v_b;
+10: b += tmp
__pyx_v_b = (__pyx_v_b + __pyx_v_tmp); }
+11: return b
__Pyx_XDECREF(__pyx_r); __pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v_b); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_r = __pyx_t_3; __pyx_t_3 = 0; goto __pyx_L0;
In [124]:
%timeit fib_cython_seq(20)
The slowest run took 15.42 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 122 ns per loop
In [131]:
report([fib, fib_lru, fib_cython, fib_numba, fib_cython_seq], 20)
fib: 1.0
fib_lru: 1151.4
fib_cython: 26.0
fib_numba: 639.7
fib_cython_seq: 1919.0
In [442]:
fs = fib, fib_lru, fib_cython, fib_numba, fib_cython_seq
for f in fs:
print(f(20))
6765
6765
6765
6765
6765
Parse_int¶
In [158]:
def parse_int():
for i in range(1,1000):
n = random.randint(0,2**31-1)
s = hex(n)
# if s[-1]=='L':
# s = s[0:-1]
m = int(s,16)
assert m == n
In [142]:
%timeit parse_int()
100 loops, best of 3: 4.56 ms per loop
In [159]:
def parse_int_numpy():
for i in range(1,1000):
n = np.random.randint(0,2**31-1)
s = hex(n)
m = int(s,16)
assert m == n
In [160]:
%timeit parse_int_numpy()
1000 loops, best of 3: 1.51 ms per loop
In [169]:
%%cython -a
import cython
import numpy as np
cimport numpy as np
def parse_int_cython():
cdef int i, n, m
for i in range(1,1000):
n = np.random.randint(0,2**31-1)
m = int(hex(n),16)
assert m == n
Out[169]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
01:
+02: import cython
__pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+03: import numpy as np
__pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
04: cimport numpy as np
05:
+06: def parse_int_cython():
/* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyMethodDef __pyx_mdef_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython = {"parse_int_cython", (PyCFunction)__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython, METH_NOARGS, 0}; static PyObject *__pyx_pw_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("parse_int_cython (wrapper)", 0); __pyx_r = __pyx_pf_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_parse_int_cython(__pyx_self); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_parse_int_cython(CYTHON_UNUSED PyObject *__pyx_self) { CYTHON_UNUSED int __pyx_v_i; int __pyx_v_n; int __pyx_v_m; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("parse_int_cython", 0); /* … */ /* function exit code */ __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_AddTraceback("_cython_magic_2d3f37e15c7a44b97af38354a036490d.parse_int_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_tuple__8 = PyTuple_Pack(3, __pyx_n_s_i, __pyx_n_s_n, __pyx_n_s_m); if (unlikely(!__pyx_tuple__8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__8); __Pyx_GIVEREF(__pyx_tuple__8); /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_2d3f37e15c7a44b97af38354a036490d_1parse_int_cython, NULL, __pyx_n_s_cython_magic_2d3f37e15c7a44b97a); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_parse_int_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
07: cdef int i, n, m
+08: for i in range(1,1000):
for (__pyx_t_1 = 1; __pyx_t_1 < 0x3E8; __pyx_t_1+=1) { __pyx_v_i = __pyx_t_1;
+09: n = np.random.randint(0,2**31-1)
__pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_random); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_randint); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_v_n = __pyx_t_4; /* … */ __pyx_tuple_ = PyTuple_Pack(2, __pyx_int_0, __pyx_int_2147483647); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple_); __Pyx_GIVEREF(__pyx_tuple_);
+10: m = int(hex(n),16)
__pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_hex, __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __Pyx_INCREF(__pyx_int_16); __Pyx_GIVEREF(__pyx_int_16); PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_16); __pyx_t_3 = 0; __pyx_t_3 = __Pyx_PyObject_Call(((PyObject *)(&PyInt_Type)), __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_v_m = __pyx_t_4;
+11: assert m == n
#ifndef CYTHON_WITHOUT_ASSERTIONS if (unlikely(!Py_OptimizeFlag)) { if (unlikely(!((__pyx_v_m == __pyx_v_n) != 0))) { PyErr_SetNone(PyExc_AssertionError); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } } #endif }
In [170]:
%timeit parse_int_cython()
1000 loops, best of 3: 1.13 ms per loop
In [175]:
report([parse_int, parse_int_numpy, parse_int_cython])
parse_int: 1.0
parse_int_numpy: 2.7
parse_int_cython: 3.2
Quicksort¶
In [171]:
def qsort_kernel(a, lo, hi):
i = lo
j = hi
while i < hi:
pivot = a[(lo+hi) // 2]
while i <= j:
while a[i] < pivot:
i += 1
while a[j] > pivot:
j -= 1
if i <= j:
a[i], a[j] = a[j], a[i]
i += 1
j -= 1
if lo < j:
qsort_kernel(a, lo, j)
lo = i
j = hi
return a
In [190]:
def benchmark_qsort():
lst = [ random.random() for i in range(1,5000) ]
qsort_kernel(lst, 0, len(lst)-1)
In [191]:
%timeit benchmark_qsort()
10 loops, best of 3: 23.8 ms per loop
In [214]:
%%cython -a
import cython
import numpy as np
@cython.boundscheck(False)
@cython.wraparound(False)
cdef double[:] qsort_kernel_cython(double[:] a, int lo, int hi):
cdef int i, j
cdef double pivot
i = lo
j = hi
while i < hi:
pivot = a[(lo+hi) // 2]
while i <= j:
while a[i] < pivot:
i += 1
while a[j] > pivot:
j -= 1
if i <= j:
a[i], a[j] = a[j], a[i]
i += 1
j -= 1
if lo < j:
qsort_kernel_cython(a, lo, j)
lo = i
j = hi
return a
def benchmark_qsort_cython():
lst = np.random.random(5000)
qsort_kernel_cython(lst, 0, len(lst)-1)
Out[214]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
01:
+02: import cython
__pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+03: import numpy as np
__pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
04:
05: @cython.boundscheck(False)
06: @cython.wraparound(False)
+07: cdef double[:] qsort_kernel_cython(double[:] a, int lo, int hi):
static __Pyx_memviewslice __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__Pyx_memviewslice __pyx_v_a, int __pyx_v_lo, int __pyx_v_hi) { int __pyx_v_i; int __pyx_v_j; double __pyx_v_pivot; __Pyx_memviewslice __pyx_r = { 0, 0, { 0 }, { 0 }, { 0 } }; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("qsort_kernel_cython", 0); /* … */ /* function exit code */ __pyx_L1_error:; __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1); __pyx_r.data = NULL; __pyx_r.memview = NULL; __Pyx_AddTraceback("_cython_magic_2e0923d1649b2de5c2ff7f8deca79258.qsort_kernel_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); goto __pyx_L2; __pyx_L0:; if (unlikely(!__pyx_r.memview)) { PyErr_SetString(PyExc_TypeError,"Memoryview return value is not initialized"); } __pyx_L2:; __Pyx_RefNannyFinishContext(); return __pyx_r; }
08: cdef int i, j
09: cdef double pivot
10:
+11: i = lo
__pyx_v_i = __pyx_v_lo;
+12: j = hi
__pyx_v_j = __pyx_v_hi;
+13: while i < hi:
while (1) { __pyx_t_1 = ((__pyx_v_i < __pyx_v_hi) != 0); if (!__pyx_t_1) break;
+14: pivot = a[(lo+hi) // 2]
__pyx_t_2 = __Pyx_div_long((__pyx_v_lo + __pyx_v_hi), 2); __pyx_v_pivot = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_2 * __pyx_v_a.strides[0]) )));
+15: while i <= j:
while (1) { __pyx_t_1 = ((__pyx_v_i <= __pyx_v_j) != 0); if (!__pyx_t_1) break;
+16: while a[i] < pivot:
while (1) { __pyx_t_3 = __pyx_v_i; __pyx_t_1 = (((*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_3 * __pyx_v_a.strides[0]) ))) < __pyx_v_pivot) != 0); if (!__pyx_t_1) break;
+17: i += 1
__pyx_v_i = (__pyx_v_i + 1); }
+18: while a[j] > pivot:
while (1) { __pyx_t_4 = __pyx_v_j; __pyx_t_1 = (((*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_4 * __pyx_v_a.strides[0]) ))) > __pyx_v_pivot) != 0); if (!__pyx_t_1) break;
+19: j -= 1
__pyx_v_j = (__pyx_v_j - 1); }
+20: if i <= j:
__pyx_t_1 = ((__pyx_v_i <= __pyx_v_j) != 0); if (__pyx_t_1) { /* … */ } }
+21: a[i], a[j] = a[j], a[i]
__pyx_t_5 = __pyx_v_j; __pyx_t_6 = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_5 * __pyx_v_a.strides[0]) ))); __pyx_t_7 = __pyx_v_i; __pyx_t_8 = (*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_7 * __pyx_v_a.strides[0]) ))); __pyx_t_9 = __pyx_v_i; *((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_9 * __pyx_v_a.strides[0]) )) = __pyx_t_6; __pyx_t_10 = __pyx_v_j; *((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_10 * __pyx_v_a.strides[0]) )) = __pyx_t_8;
+22: i += 1
__pyx_v_i = (__pyx_v_i + 1);
+23: j -= 1
__pyx_v_j = (__pyx_v_j - 1);
+24: if lo < j:
__pyx_t_1 = ((__pyx_v_lo < __pyx_v_j) != 0); if (__pyx_t_1) { /* … */ }
+25: qsort_kernel_cython(a, lo, j)
__pyx_t_11 = __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__pyx_v_a, __pyx_v_lo, __pyx_v_j); if (unlikely(!__pyx_t_11.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
+26: lo = i
__pyx_v_lo = __pyx_v_i;
+27: j = hi
__pyx_v_j = __pyx_v_hi; }
+28: return a
__PYX_INC_MEMVIEW(&__pyx_v_a, 0); __pyx_r = __pyx_v_a; goto __pyx_L0;
29:
+30: def benchmark_qsort_cython():
/* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyMethodDef __pyx_mdef_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython = {"benchmark_qsort_cython", (PyCFunction)__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython, METH_NOARGS, 0}; static PyObject *__pyx_pw_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("benchmark_qsort_cython (wrapper)", 0); __pyx_r = __pyx_pf_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_benchmark_qsort_cython(__pyx_self); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_benchmark_qsort_cython(CYTHON_UNUSED PyObject *__pyx_self) { PyObject *__pyx_v_lst = NULL; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("benchmark_qsort_cython", 0); /* … */ /* function exit code */ __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __PYX_XDEC_MEMVIEW(&__pyx_t_3, 1); __PYX_XDEC_MEMVIEW(&__pyx_t_5, 1); __Pyx_AddTraceback("_cython_magic_2e0923d1649b2de5c2ff7f8deca79258.benchmark_qsort_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XDECREF(__pyx_v_lst); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_tuple__15 = PyTuple_Pack(1, __pyx_n_s_lst); if (unlikely(!__pyx_tuple__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__15); __Pyx_GIVEREF(__pyx_tuple__15); /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_1benchmark_qsort_cython, NULL, __pyx_n_s_cython_magic_2e0923d1649b2de5c2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_benchmark_qsort_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(0, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_cliburn_ipython_cython__c, __pyx_n_s_benchmark_qsort_cython, 30, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+31: lst = np.random.random(5000)
__pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_random); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_random); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_v_lst = __pyx_t_2; __pyx_t_2 = 0; /* … */ __pyx_tuple_ = PyTuple_Pack(1, __pyx_int_5000); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple_); __Pyx_GIVEREF(__pyx_tuple_);
+32: qsort_kernel_cython(lst, 0, len(lst)-1)
__pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_v_lst); if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_4 = PyObject_Length(__pyx_v_lst); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_5 = __pyx_f_46_cython_magic_2e0923d1649b2de5c2ff7f8deca79258_qsort_kernel_cython(__pyx_t_3, 0, (__pyx_t_4 - 1)); if (unlikely(!__pyx_t_5.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __PYX_XDEC_MEMVIEW(&__pyx_t_3, 1); __PYX_XDEC_MEMVIEW(&__pyx_t_5, 1);
In [215]:
%timeit benchmark_qsort_cython()
The slowest run took 4.02 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 735 µs per loop
In [216]:
report([benchmark_qsort, benchmark_qsort_cython])
benchmark_qsort: 1.0
benchmark_qsort_cython: 25.6
Mandel¶
In [217]:
def mandel(z):
maxiter = 80
c = z
for n in range(maxiter):
if abs(z) > 2:
return n
z = z*z + c
return maxiter
def mandelperf():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
return [mandel(complex(r, i)) for r in r1 for i in r2]
In [219]:
%timeit mandelperf()
100 loops, best of 3: 6.9 ms per loop
In [259]:
@jit
def mandel_numba(z):
maxiter = 80
c = z
for n in range(maxiter):
if abs(z) > 2:
return n
z = z*z + c
return maxiter
@jit
def mandelperf_numba():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
res = np.empty((26, 21), dtype='int')
for i in range(26):
for j in range(21):
res[i, j] = mandel_numba(complex(r1[i], r2[j]))
return res
In [260]:
%timeit mandelperf_numba()
The slowest run took 2568.37 times longer than the fastest. This could mean that an intermediate result is being cached
1 loops, best of 3: 156 µs per loop
In [268]:
%%cython -a
cimport cython
import numpy as np
cimport numpy as np
cdef extern from "complex.h":
double cabs(double complex)
cdef int mandel_cython(double complex z):
cdef int n
cdef int max_iter
cdef double complex c
maxiter = 80
c = z
for n in range(maxiter):
if cabs(z) > 2:
return n
z = z*z + c
return maxiter
@cython.boundscheck(False)
@cython.wraparound(False)
def mandelperf_cython():
cdef int i, j
cdef double[:] r1 = np.linspace(-2.0, 0.5, 26)
cdef double[:] r2 = np.linspace(-1.0, 1.0, 21)
cdef int[:,:] res = np.empty((26,21), dtype=np.int32)
for i in range(26):
for j in range(21):
res[i,j] = mandel_cython(r1[i] + r2[j]*1j)
return res
Out[268]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
01:
+02: cimport cython
__pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+03: import numpy as np
__pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
04: cimport numpy as np
05:
06: cdef extern from "complex.h":
07: double cabs(double complex)
08:
+09: cdef int mandel_cython(double complex z):
static int __pyx_f_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandel_cython(__pyx_t_double_complex __pyx_v_z) { int __pyx_v_n; __pyx_t_double_complex __pyx_v_c; long __pyx_v_maxiter; int __pyx_r; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("mandel_cython", 0); /* … */ /* function exit code */ __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; }
10: cdef int n
11: cdef int max_iter
12: cdef double complex c
+13: maxiter = 80
__pyx_v_maxiter = 80;
+14: c = z
__pyx_v_c = __pyx_v_z;
+15: for n in range(maxiter):
__pyx_t_1 = __pyx_v_maxiter; for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) { __pyx_v_n = __pyx_t_2;
+16: if cabs(z) > 2:
__pyx_t_3 = ((cabs(__pyx_v_z) > 2.0) != 0); if (__pyx_t_3) { /* … */ }
+17: return n
__pyx_r = __pyx_v_n; goto __pyx_L0;
+18: z = z*z + c
__pyx_v_z = __Pyx_c_sum(__Pyx_c_prod(__pyx_v_z, __pyx_v_z), __pyx_v_c); }
+19: return maxiter
__pyx_r = __pyx_v_maxiter; goto __pyx_L0;
20:
21: @cython.boundscheck(False)
22: @cython.wraparound(False)
+23: def mandelperf_cython():
/* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyMethodDef __pyx_mdef_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython = {"mandelperf_cython", (PyCFunction)__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython, METH_NOARGS, 0}; static PyObject *__pyx_pw_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("mandelperf_cython (wrapper)", 0); __pyx_r = __pyx_pf_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandelperf_cython(__pyx_self); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandelperf_cython(CYTHON_UNUSED PyObject *__pyx_self) { int __pyx_v_i; int __pyx_v_j; __Pyx_memviewslice __pyx_v_r1 = { 0, 0, { 0 }, { 0 }, { 0 } }; __Pyx_memviewslice __pyx_v_r2 = { 0, 0, { 0 }, { 0 }, { 0 } }; __Pyx_memviewslice __pyx_v_res = { 0, 0, { 0 }, { 0 }, { 0 } }; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("mandelperf_cython", 0); /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __PYX_XDEC_MEMVIEW(&__pyx_t_3, 1); __Pyx_XDECREF(__pyx_t_4); __Pyx_XDECREF(__pyx_t_5); __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1); __Pyx_AddTraceback("_cython_magic_49b54927ec0b1cfc50dc062249bda68a.mandelperf_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __PYX_XDEC_MEMVIEW(&__pyx_v_r1, 1); __PYX_XDEC_MEMVIEW(&__pyx_v_r2, 1); __PYX_XDEC_MEMVIEW(&__pyx_v_res, 1); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_tuple__24 = PyTuple_Pack(5, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_r1, __pyx_n_s_r2, __pyx_n_s_res); if (unlikely(!__pyx_tuple__24)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__24); __Pyx_GIVEREF(__pyx_tuple__24); /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_1mandelperf_cython, NULL, __pyx_n_s_cython_magic_49b54927ec0b1cfc50); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_mandelperf_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(0, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_cliburn_ipython_cython__c, __pyx_n_s_mandelperf_cython, 23, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
24: cdef int i, j
25:
+26: cdef double[:] r1 = np.linspace(-2.0, 0.5, 26)
__pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_linspace); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_1); if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_v_r1 = __pyx_t_3; __pyx_t_3.memview = NULL; __pyx_t_3.data = NULL; /* … */ __pyx_tuple_ = PyTuple_Pack(3, __pyx_float_neg_2_0, __pyx_float_0_5, __pyx_int_26); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple_); __Pyx_GIVEREF(__pyx_tuple_);
+27: cdef double[:] r2 = np.linspace(-1.0, 1.0, 21)
__pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_linspace); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_3 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_1); if (unlikely(!__pyx_t_3.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_v_r2 = __pyx_t_3; __pyx_t_3.memview = NULL; __pyx_t_3.data = NULL; /* … */ __pyx_tuple__2 = PyTuple_Pack(3, __pyx_float_neg_1_0, __pyx_float_1_0, __pyx_int_21); if (unlikely(!__pyx_tuple__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__2); __Pyx_GIVEREF(__pyx_tuple__2);
+28: cdef int[:,:] res = np.empty((26,21), dtype=np.int32)
__pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* … */ __pyx_tuple__3 = PyTuple_Pack(2, __pyx_int_26, __pyx_int_21); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__3); __Pyx_GIVEREF(__pyx_tuple__3); __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_int32); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__4, __pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dsds_int(__pyx_t_5); if (unlikely(!__pyx_t_6.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_v_res = __pyx_t_6; __pyx_t_6.memview = NULL; __pyx_t_6.data = NULL; __pyx_tuple__4 = PyTuple_Pack(1, __pyx_tuple__3); if (unlikely(!__pyx_tuple__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple__4); __Pyx_GIVEREF(__pyx_tuple__4);
29:
+30: for i in range(26):
for (__pyx_t_7 = 0; __pyx_t_7 < 26; __pyx_t_7+=1) { __pyx_v_i = __pyx_t_7;
+31: for j in range(21):
for (__pyx_t_8 = 0; __pyx_t_8 < 21; __pyx_t_8+=1) { __pyx_v_j = __pyx_t_8;
+32: res[i,j] = mandel_cython(r1[i] + r2[j]*1j)
__pyx_t_9 = __pyx_v_i; __pyx_t_10 = __pyx_v_j; __pyx_t_11 = __pyx_v_i; __pyx_t_12 = __pyx_v_j; *((int *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_res.data + __pyx_t_11 * __pyx_v_res.strides[0]) ) + __pyx_t_12 * __pyx_v_res.strides[1]) )) = __pyx_f_46_cython_magic_49b54927ec0b1cfc50dc062249bda68a_mandel_cython(__Pyx_c_sum(__pyx_t_double_complex_from_parts((*((double *) ( /* dim=0 */ (__pyx_v_r1.data + __pyx_t_9 * __pyx_v_r1.strides[0]) ))), 0), __Pyx_c_prod(__pyx_t_double_complex_from_parts((*((double *) ( /* dim=0 */ (__pyx_v_r2.data + __pyx_t_10 * __pyx_v_r2.strides[0]) ))), 0), __pyx_t_double_complex_from_parts(0, 1.0)))); } }
+33: return res
__Pyx_XDECREF(__pyx_r); __pyx_t_5 = __pyx_memoryview_fromslice(__pyx_v_res, 2, (PyObject *(*)(char *)) __pyx_memview_get_int, (int (*)(char *, PyObject *)) __pyx_memview_set_int, 0);; if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); __pyx_r = __pyx_t_5; __pyx_t_5 = 0; goto __pyx_L0;
In [269]:
%timeit mandelperf_cython()
1000 loops, best of 3: 222 µs per loop
In [271]:
report([mandelperf, mandelperf_numba, mandelperf_cython])
mandelperf: 1.0
mandelperf_numba: 19.7
mandelperf_cython: 15.4
In [454]:
for f in mandelperf, mandelperf_numba, mandelperf_cython:
print(np.reshape(f(), (26,21)), "\n")
[[ 0 0 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 1 1 2 2 3 3 80 3 3 2 2 1 1 0 0 0 0]
[ 0 0 1 1 2 2 2 3 3 3 80 3 3 3 2 2 2 1 1 0 0]
[ 1 1 2 2 2 2 2 3 3 5 80 5 3 3 2 2 2 2 2 1 1]
[ 1 2 2 2 2 2 2 3 4 5 80 5 4 3 2 2 2 2 2 2 1]
[ 1 2 2 2 2 2 3 4 4 6 80 6 4 4 3 2 2 2 2 2 1]
[ 2 2 2 2 2 2 4 4 5 11 80 11 5 4 4 2 2 2 2 2 2]
[ 2 2 2 2 2 3 6 6 7 13 80 13 7 6 6 3 2 2 2 2 2]
[ 2 2 2 2 2 4 6 15 17 80 80 80 17 15 6 4 2 2 2 2 2]
[ 2 2 2 2 3 4 6 11 80 80 80 80 80 11 6 4 3 2 2 2 2]
[ 2 2 2 3 3 4 6 34 80 80 80 80 80 34 6 4 3 3 2 2 2]
[ 2 2 3 3 4 4 6 10 80 80 80 80 80 10 6 4 4 3 3 2 2]
[ 2 3 3 3 4 5 6 8 14 80 80 80 14 8 6 5 4 3 3 3 2]
[ 2 3 3 4 5 7 10 23 80 80 80 80 80 23 10 7 5 4 3 3 2]
[ 3 3 3 6 11 11 80 80 80 80 80 80 80 80 80 11 11 6 3 3 3]
[ 3 3 4 7 80 80 80 80 80 80 80 80 80 80 80 80 80 7 4 3 3]
[ 3 4 5 7 25 80 80 80 80 80 80 80 80 80 80 80 25 7 5 4 3]
[ 4 5 7 9 80 80 80 80 80 80 80 80 80 80 80 80 80 9 7 5 4]
[ 6 8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 8 6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23 8]
[80 7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17 7 80]
[ 3 4 5 8 80 80 80 80 80 80 80 80 80 80 80 80 80 8 5 4 3]
[ 3 3 4 5 11 80 80 80 80 80 80 80 80 80 80 80 11 5 4 3 3]
[ 2 3 4 5 14 80 80 80 80 80 11 80 80 80 80 80 14 5 4 3 2]
[ 2 2 3 4 14 6 8 14 30 7 6 7 30 14 8 6 14 4 3 2 2]
[ 1 2 2 3 3 4 4 5 4 4 4 4 4 5 4 4 3 3 2 2 1]]
[[ 0 0 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 1 1 2 2 3 3 80 3 3 2 2 1 1 0 0 0 0]
[ 0 0 1 1 2 2 2 3 3 3 80 3 3 3 2 2 2 1 1 0 0]
[ 1 1 2 2 2 2 2 3 3 5 80 5 3 3 2 2 2 2 2 1 1]
[ 1 2 2 2 2 2 2 3 4 5 80 5 4 3 2 2 2 2 2 2 1]
[ 1 2 2 2 2 2 3 4 4 6 80 6 4 4 3 2 2 2 2 2 1]
[ 2 2 2 2 2 2 4 4 5 11 80 11 5 4 4 2 2 2 2 2 2]
[ 2 2 2 2 2 3 6 6 7 13 80 13 7 6 6 3 2 2 2 2 2]
[ 2 2 2 2 2 4 6 15 17 80 80 80 17 15 6 4 2 2 2 2 2]
[ 2 2 2 2 3 4 6 11 80 80 80 80 80 11 6 4 3 2 2 2 2]
[ 2 2 2 3 3 4 6 34 80 80 80 80 80 34 6 4 3 3 2 2 2]
[ 2 2 3 3 4 4 6 10 80 80 80 80 80 10 6 4 4 3 3 2 2]
[ 2 3 3 3 4 5 6 8 14 80 80 80 14 8 6 5 4 3 3 3 2]
[ 2 3 3 4 5 7 10 23 80 80 80 80 80 23 10 7 5 4 3 3 2]
[ 3 3 3 6 11 11 80 80 80 80 80 80 80 80 80 11 11 6 3 3 3]
[ 3 3 4 7 80 80 80 80 80 80 80 80 80 80 80 80 80 7 4 3 3]
[ 3 4 5 7 25 80 80 80 80 80 80 80 80 80 80 80 25 7 5 4 3]
[ 4 5 7 9 80 80 80 80 80 80 80 80 80 80 80 80 80 9 7 5 4]
[ 6 8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 8 6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23 8]
[80 7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17 7 80]
[ 3 4 5 8 80 80 80 80 80 80 80 80 80 80 80 80 80 8 5 4 3]
[ 3 3 4 5 11 80 80 80 80 80 80 80 80 80 80 80 11 5 4 3 3]
[ 2 3 4 5 14 80 80 80 80 80 11 80 80 80 80 80 14 5 4 3 2]
[ 2 2 3 4 14 6 8 14 30 7 6 7 30 14 8 6 14 4 3 2 2]
[ 1 2 2 3 3 4 4 5 4 4 4 4 4 5 4 4 3 3 2 2 1]]
[[ 0 0 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 1 1 2 2 3 3 80 3 3 2 2 1 1 0 0 0 0]
[ 0 0 1 1 2 2 2 3 3 3 80 3 3 3 2 2 2 1 1 0 0]
[ 1 1 2 2 2 2 2 3 3 5 80 5 3 3 2 2 2 2 2 1 1]
[ 1 2 2 2 2 2 2 3 4 5 80 5 4 3 2 2 2 2 2 2 1]
[ 1 2 2 2 2 2 3 4 4 6 80 6 4 4 3 2 2 2 2 2 1]
[ 2 2 2 2 2 2 4 4 5 11 80 11 5 4 4 2 2 2 2 2 2]
[ 2 2 2 2 2 3 6 6 7 13 80 13 7 6 6 3 2 2 2 2 2]
[ 2 2 2 2 2 4 6 15 17 80 80 80 17 15 6 4 2 2 2 2 2]
[ 2 2 2 2 3 4 6 11 80 80 80 80 80 11 6 4 3 2 2 2 2]
[ 2 2 2 3 3 4 6 34 80 80 80 80 80 34 6 4 3 3 2 2 2]
[ 2 2 3 3 4 4 6 10 80 80 80 80 80 10 6 4 4 3 3 2 2]
[ 2 3 3 3 4 5 6 8 14 80 80 80 14 8 6 5 4 3 3 3 2]
[ 2 3 3 4 5 7 10 23 80 80 80 80 80 23 10 7 5 4 3 3 2]
[ 3 3 3 6 11 11 80 80 80 80 80 80 80 80 80 11 11 6 3 3 3]
[ 3 3 4 7 80 80 80 80 80 80 80 80 80 80 80 80 80 7 4 3 3]
[ 3 4 5 7 25 80 80 80 80 80 80 80 80 80 80 80 25 7 5 4 3]
[ 4 5 7 9 80 80 80 80 80 80 80 80 80 80 80 80 80 9 7 5 4]
[ 6 8 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 8 6]
[ 8 23 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 23 8]
[80 7 17 12 80 80 80 80 80 80 80 80 80 80 80 80 80 12 17 7 80]
[ 3 4 5 8 80 80 80 80 80 80 80 80 80 80 80 80 80 8 5 4 3]
[ 3 3 4 5 11 80 80 80 80 80 80 80 80 80 80 80 11 5 4 3 3]
[ 2 3 4 5 14 80 80 80 80 80 11 80 80 80 80 80 14 5 4 3 2]
[ 2 2 3 4 14 6 8 14 30 7 6 7 30 14 8 6 14 4 3 2 2]
[ 1 2 2 3 3 4 4 5 4 4 4 4 4 5 4 4 3 3 2 2 1]]
Pi_sum¶
In [272]:
def pisum(t):
sum = 0.0
for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum
In [273]:
%timeit pisum(10000)
1 loops, best of 3: 1.33 s per loop
In [282]:
@jit
def pisum_numba(t):
sum = 0.0
for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum
In [283]:
%timeit pisum_numba(10000)
10 loops, best of 3: 35.8 ms per loop
In [298]:
%%cython -a
cimport cython
@cython.cdivision(True)
def pisum_cython(int t):
cdef double sum
cdef int j, k
for j in range(1, 501):
sum = 0.0
for k in range(1, t+1):
sum += 1.0/(k*k)
return sum
Out[298]:
Generated by Cython 0.23.4
Yellow lines hint at Python interaction.
Click on a line that starts with a "+
" to see the C code that Cython generated for it.
01:
02: cimport cython
03:
04: @cython.cdivision(True)
+05: def pisum_cython(int t):
/* Python wrapper */ static PyObject *__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython(PyObject *__pyx_self, PyObject *__pyx_arg_t); /*proto*/ static PyMethodDef __pyx_mdef_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython = {"pisum_cython", (PyCFunction)__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython, METH_O, 0}; static PyObject *__pyx_pw_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython(PyObject *__pyx_self, PyObject *__pyx_arg_t) { int __pyx_v_t; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("pisum_cython (wrapper)", 0); assert(__pyx_arg_t); { __pyx_v_t = __Pyx_PyInt_As_int(__pyx_arg_t); if (unlikely((__pyx_v_t == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; __Pyx_AddTraceback("_cython_magic_39bd6be55fc470028b8a8a158c919aa6.pisum_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; __pyx_r = __pyx_pf_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_pisum_cython(__pyx_self, ((int)__pyx_v_t)); int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_pisum_cython(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_t) { double __pyx_v_sum; CYTHON_UNUSED int __pyx_v_j; int __pyx_v_k; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("pisum_cython", 0); /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_4); __Pyx_AddTraceback("_cython_magic_39bd6be55fc470028b8a8a158c919aa6.pisum_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* … */ __pyx_tuple_ = PyTuple_Pack(5, __pyx_n_s_t, __pyx_n_s_t, __pyx_n_s_sum, __pyx_n_s_j, __pyx_n_s_k); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_tuple_); __Pyx_GIVEREF(__pyx_tuple_); /* … */ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_39bd6be55fc470028b8a8a158c919aa6_1pisum_cython, NULL, __pyx_n_s_cython_magic_39bd6be55fc470028b); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_pisum_cython, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
06: cdef double sum
07: cdef int j, k
08:
+09: for j in range(1, 501):
for (__pyx_t_1 = 1; __pyx_t_1 < 0x1F5; __pyx_t_1+=1) { __pyx_v_j = __pyx_t_1;
+10: sum = 0.0
__pyx_v_sum = 0.0;
+11: for k in range(1, t+1):
__pyx_t_2 = (__pyx_v_t + 1); for (__pyx_t_3 = 1; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { __pyx_v_k = __pyx_t_3;
+12: sum += 1.0/(k*k)
__pyx_v_sum = (__pyx_v_sum + (1.0 / (__pyx_v_k * __pyx_v_k))); } }
+13: return sum
__Pyx_XDECREF(__pyx_r); __pyx_t_4 = PyFloat_FromDouble(__pyx_v_sum); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __pyx_r = __pyx_t_4; __pyx_t_4 = 0; goto __pyx_L0;
In [299]:
%timeit pisum_cython(10000)
10 loops, best of 3: 35.8 ms per loop
In [286]:
report([pisum, pisum_numba, pisum_cython], 10000)
pisum: 1.0
pisum_numba: 35.6
pisum_cython: 35.6
In [455]:
for f in pisum, pisum_numba, pisum_cython:
print(f(10000))
1.6448340718480652
1.6448340718480652
1.6448340718480652
Rand_mat_stat¶
In [287]:
def randmatstat(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)
for i in range(1,t):
a = np.random.randn(n, n)
b = np.random.randn(n, n)
c = np.random.randn(n, n)
d = np.random.randn(n, n)
P = np.matrix(np.hstack((a, b, c, d)))
Q = np.matrix(np.vstack((np.hstack((a, b)), np.hstack((c, d)))))
v[i] = np.trace(np.linalg.matrix_power(np.transpose(P)*P, 4))
w[i] = np.trace(np.linalg.matrix_power(np.transpose(Q)*Q, 4))
return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))
In [288]:
%timeit randmatstat(1000)
1 loops, best of 3: 260 ms per loop
In [391]:
def randmatstat_numba(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)
for i in range(1,t):
a, b, c, d = np.random.randn(4, n, n)
P = np.hstack((a, b, c, d))
Q = np.vstack((np.hstack((a, b)), np.hstack((c, d))))
PTP = P.T.dot(P)
QTQ = Q.T.dot(Q)
v[i] = np.trace(PTP @ PTP @ PTP @ PTP)
w[i] = np.trace(QTQ @ QTQ @ QTQ @ QTQ)
return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))
In [393]:
def randmatstat_alt(t):
n = 5
v = np.zeros(t)
w = np.zeros(t)
for i in range(1,t):
a, b, c, d = np.random.randn(4, n, n)
P = np.hstack((a, b, c, d))
Q = np.vstack((np.hstack((a, b)), np.hstack((c, d))))
P1 = P.T @ P
P2 = P1 @ P1
P4 = P2 @ P2
Q1 = Q.T @ Q
Q2 = Q1 @ Q1
Q4 = Q2 @ Q2
v[i] = np.trace(P4)
w[i] = np.trace(Q4)
return (np.std(v)/np.mean(v), np.std(w)/np.mean(w))
In [394]:
%timeit randmatstat_alt(1000)
10 loops, best of 3: 131 ms per loop
In [396]:
report([randmatstat, randmatstat_alt], 1000)
randmatstat: 1.0
randmatstat_alt: 2.1
In [458]:
for f in randmatstat, randmatstat_alt:
np.random.seed(123)
print(f(1000))
(0.72398346943567571, 0.7713214961017032)
(0.72398346943567571, 0.7713214961017032)
Rand_mat_mul¶
In [289]:
def randmatmul(n):
A = np.random.rand(n,n)
B = np.random.rand(n,n)
return np.dot(A,B)
In [290]:
%timeit randmatmul(1000)
10 loops, best of 3: 81 ms per loop
Comparison¶
These benchmarks don’t mean very much - they were constructed by the Julia team presumably to show off Julia’s strengths, and are used here just to illustrate basic Python optimization techniques. In some case (quicksort, mandel, pi_sum), this gives dramatic performance improvements but in other cases (parse_int, rand_mat_stat) there is less improvement. For fib, the speed depends on the algorithm used for calculation, and whether caching is enabled in the recursive case. The final test rand_mat_mul basically depends on the linear algebra library installed (blas, mkl, atlas) and is not really a comparison across languages.
Julia certainly does look promising, and we might include mix in some Julia code in future courses.
In [459]:
benchmarks['P2J'] = benchmarks.Python / benchmarks.Julia
benchmarks['SU'] = [1919.0, 3.2, 25.6, 19.7, 35.6, 2.1, 1.0]
pd.options.display.float_format = '{:.2f}'.format
benchmarks.ix[:, [0,2,3,-2,-1]]
Out[459]:
Julia | Python | P2J | SU | ||
---|---|---|---|---|---|
1 | fib | 2.11 | 77.76 | 36.85 | 1919.00 |
2 | parse_int | 1.45 | 17.02 | 11.74 | 3.20 |
3 | quicksort | 1.15 | 32.89 | 28.60 | 25.60 |
4 | mandel | 0.79 | 15.32 | 19.39 | 19.70 |
5 | pi_sum | 1.00 | 21.99 | 21.99 | 35.60 |
6 | rand_mat_stat | 1.66 | 17.93 | 10.80 | 2.10 |
7 | rand_mat_mul | 1.02 | 1.14 | 1.12 | 1.00 |
In [ ]: