Proudly made in Namek by serge-sans-paille & pbrunet
/me
$ whoami
sguelton
binary-trees source secs Python 3 152.06 C++ g++ 6.98
On the pidigits
benchmark, that uses BigInts
× source secs 1.0 Pascal 1.73 1.0 C gcc 1.73 1.0 Rust 1.74 1.1 Fortran 1.92 1.3 Python3 2.20 1.3 C++ g++ 2.29
On the spectral-norm
benchmark, that uses list and scalars
× source secs 1.0 C gcc 1.98 2.1 Java 4.26 8.0 Node.js 15.77 126 Python3 250.12
$ gcc sn.c -o sn -O3
$ time ./sn 5500
./sn 5500 4.86s user 0.00s system 99% cpu 4.864 total
$ pythran sn.py
$ python -m timeit 'import sn' 'sn.main(5500)'
10 loops, best of 3: 4.79 sec per loop
>>> import dis
>>> code = lambda x, y: x + y
>>> dis.dis(code)
1 0 LOAD_FAST 0 (x)
3 LOAD_FAST 1 (y)
6 BINARY_ADD
7 RETURN_VALUE
VS.
foo:
leal (%rdi,%rsi), %eax
ret
LOAD_FAST
⇒ array lookupBINARY_ADD
⇒ dict lookup
$ gcc sn.c -o sn -O0 -fsanitize=address -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=integer-divide-by-zero
$ time ./sn 5500
./a.out 5500 11.04s user 0.02s system 99% cpu 11.053 total
Many Native Library Wrappers
A Python packages for numeric computations
→ Keystone of the Python scientific ecosystem!
def pairwise(X):
M, N = X.shape
D = np.empty((M, M), dtype=np.float64)
for i in range(M):
for j in range(M):
d = 0.0
for k in range(N):
tmp = X[i, k] - X[j, k]
d += tmp * tmp
D[i, j] = sqrt(d)
return D
import numpy as np
def pairwise(X):
return np.sqrt(((X[:, None, :] - X) ** 2).sum(-1))
from mpi4py import MPI
import numpy as np
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
if rank == 0:
data = np.arange(100, dtype='i')
else:
data = np.empty(100, dtype='i')
comm.Bcast(data, root=0)
ctypes
>>> from ctypes import *
>>> libm = cdll.LoadLibrary('libm.so.6')
>>> sqrt = libm.sqrt
>>> sqrt.argtypes, sqrt.restype = (c_double,), c_double
>>> sqrt(4.)
cffi
>>> from cffi import FFI
>>> ffi = FFI()
>>> ffi.cdef('int add(int, int);')
>>> C = ffi.verify('int add(int x, int y) { return x+y;}')
>>> C.add(40, 2)
42
Cython
cimport cython
cpdef double add(double x, double y):
return x + y
Then
$ cython -a add.pyx
$ gcc `python-config --cflags --ldflags` -fPIC -shared add.c -o add.so
Pythran
#pythran export add(double, double)
def add(x, y):
return x + y
Then
$ pythran add.py
Through a custom compiler + interface file
Regular C++ code + runtime deps
Regular C++ code + modern compiler
#include
int add(int i, int j) {
return i + j;
}
namespace py = pybind11;
PYBIND11_PLUGIN(example) {
py::module m("example", "pybind11 example plugin");
m.def("add", &add, "A function which adds two numbers");
return m.ptr();
}
Pro:
Cons:
PyPy
cffi
compatibilityPromise: no code change
Numba
from numba import jit
@jit
def add(x, y): return x + y
Hope
from hope import jit
@jit
def add(x, y): return x + y
cProf
$ python -m cProfile -s cumtime myscript.py
timeit
$ python -m timeit -s 'import mymodule' 'mymodule.run(2)'
perf
$ perf run python myscript.py
$ perf report
valgrind
$ valgrind --tool=callgrind python myscript.py
$ kcachegrind callgrind.out.1982