Commit bfd747581ce by Pierre Augier

More benchmarks

parent d6b7bc4944f
......@@ -30,7 +30,7 @@ There are different methods to choose which backend is used:
.. toctree::
:maxdepth: 2
examples/row_sum/txt
examples/bench_row_sum/txt
backends/pythran
backends/cython
backends/other
NAME=bench.py
all: pythran other
pythran:
transonic $(NAME) -b pythran -pf "-march=native -DUSE_XSIMD -Ofast"
other:
transonic $(NAME) -b numba
clean:
rm -rf __cython__ __python__ __numba__ __pythran__
bench:
python bench.py
import numpy as np
from transonic import boost, Array
A = Array[float, "3d"]
A1 = Array[float, "1d"]
def expr(a, b):
return np.arctan2(2 * np.exp(a) ** 2 + 4 * np.log(a * b) ** 3, 2 / a)
def broadcast(a: A, b: A1, out: A):
out[:] = expr(a, b)
def broadcast_loops(a: A, b: A1, out: A):
n0, n1, n2 = a.shape
for i0 in range(n0):
for i1 in range(n1):
for i2 in range(n2):
out[i0, i1, i2] = expr(a[i0, i1, i2], b[i2])
broadcast_pythran = boost(backend="pythran")(broadcast)
broadcast_numba = boost(backend="numba")(broadcast)
broadcast_loops_pythran = boost(backend="pythran")(broadcast_loops)
broadcast_loops_numba = boost(backend="numba")(broadcast_loops)
if __name__ == "__main__":
import numba
import pythran
from transonic import __version__
from transonic.util import timeit
shape = (4, 4, 64)
a = np.linspace(1, 100, np.prod(shape)).reshape(shape)
b = np.linspace(1, 100, shape[-1])
out = np.empty_like(a)
broadcast(a, b, out)
out_loops = np.empty_like(a)
broadcast_loops(a, b, out_loops)
assert np.allclose(out, out_loops)
print(
f"transonic {__version__}\n"
f"pythran {pythran.__version__}\n"
f"numba {numba.__version__}\n"
)
loc = locals()
def bench(call, norm=None):
ret = result = timeit(call, globals=loc)
if norm is None:
norm = result
result /= norm
print(f"{call.split('(')[0]:33s}: {result:.3f}")
return ret
norm = bench("broadcast(a, b, out)")
print(f"norm = {norm:.2e} s")
for backend in ("numba", "pythran"):
bench(f"broadcast_{backend}(a, b, out)", norm=norm)
bench(f"broadcast_loops_{backend}(a, b, out)", norm=norm)
Benchmark expression broadcast
==============================
.. literalinclude:: bench.py
which gives::
transonic 0.4.1
pythran 0.9.3post1
numba 0.46.0
broadcast : 1.000
norm = 1.53e-04 s
broadcast_numba : 0.469
broadcast_loops_numba : 0.439
broadcast_pythran : 0.280
broadcast_loops_pythran : 0.416
For the solution with loops, the 2 backends are equally good.
For Pythran, it is even faster with the high level implementation!
NAME=proj.py
NAME=bench.py
all: pythran cython other
pythran:
transonic $(NAME) -b pythran -pf "-DUSE_XSIMD -Ofast"
transonic $(NAME) -b pythran -pf "-march=native -DUSE_XSIMD -Ofast"
cython:
transonic $(NAME) -b cython -pf "-Ofast "
transonic $(NAME) -b cython -pf "-march=native -Ofast"
other:
transonic $(NAME) -b numba
......@@ -16,4 +16,4 @@ clean:
rm -rf __cython__ __python__ __numba__ __pythran__
bench:
python proj.py
python $(NAME)
Benchmark projection vector
===========================
.. literalinclude:: proj.py
.. literalinclude:: bench.py
which gives::
......@@ -10,14 +10,13 @@ which gives::
numba 0.46.0
proj : 1.00
norm = 4.46e-01 s
norm = 5.76e-01 s
proj_cython : 1.26
proj_loop_cython : 0.23
proj_numba : 1.09
proj_loop_numba : 0.22
proj_pythran : 0.46
proj_loop_pythran : 0.22
proj_loop_cython : 0.18
proj_numba : 1.34
proj_loop_numba : 0.15
proj_pythran : 0.42
proj_loop_pythran : 0.14
For the solution with loops, the 3 backends are equally good.
......
NAME=bench.py
all: pythran other
pythran:
transonic $(NAME) -b pythran -pf "-march=native -DUSE_XSIMD -Ofast"
other:
transonic $(NAME) -b numba
clean:
rm -rf __cython__ __python__ __numba__ __pythran__
bench:
python bench.py
import numpy as np
from transonic import boost, Array
A = Array[float, "1d"]
def fxfy(ft: A, fn: A, theta: A):
sin_theta = np.sin(theta)
cos_theta = np.cos(theta)
fx = cos_theta * ft - sin_theta * fn
fy = sin_theta * ft + cos_theta * fn
return fx, fy
def fxfy_loops(ft: A, fn: A, theta: A):
n0 = theta.size
fx = np.empty_like(ft)
fy = np.empty_like(fn)
for index in range(n0):
sin_theta = np.sin(theta[index])
cos_theta = np.cos(theta[index])
fx[index] = cos_theta * ft[index] - sin_theta * fn[index]
fy[index] = sin_theta * ft[index] + cos_theta * fn[index]
return fx, fy
fxfy_pythran = boost(backend="pythran")(fxfy)
fxfy_numba = boost(backend="numba")(fxfy)
fxfy_loops_pythran = boost(backend="pythran")(fxfy_loops)
fxfy_loops_numba = boost(backend="numba")(fxfy_loops)
if __name__ == "__main__":
import numba
import pythran
from transonic import __version__
from transonic.util import timeit
theta = np.linspace(0, 2 * np.pi, 10000)
ft = 2.5 * theta
fv = 1.5 * theta
out = fxfy(ft, fv, theta)
out_loops = fxfy_loops(ft, fv, theta)
assert np.allclose(out, out_loops)
print(
f"transonic {__version__}\n"
f"pythran {pythran.__version__}\n"
f"numba {numba.__version__}\n"
)
loc = locals()
def bench(call, norm=None):
ret = result = timeit(call, globals=loc)
if norm is None:
norm = result
result /= norm
print(f"{call.split('(')[0]:33s}: {result:.3f}")
return ret
norm = bench("fxfy(ft, fv, theta)")
print(f"norm = {norm:.2e} s")
for backend in ("numba", "pythran"):
bench(f"fxfy_{backend}(ft, fv, theta)", norm=norm)
bench(f"fxfy_loops_{backend}(ft, fv, theta)", norm=norm)
Benchmark rotation vector
=========================
.. literalinclude:: bench.py
which gives::
transonic 0.4.1
pythran 0.9.3post1
numba 0.46.0
fxfy : 1.000
norm = 6.69e-04 s
fxfy_numba : 0.978
fxfy_loops_numba : 0.797
fxfy_pythran : 0.123
fxfy_loops_pythran : 0.800
For the solution with loops, the 2 backends are equally good.
For Pythran, it is much faster with the high level implementation!
......@@ -9,8 +9,10 @@ Other examples can be found here:
.. toctree::
:maxdepth: 2
../row_sum/txt
../proj_perp/txt
../bench_row_sum/txt
../bench_trigo/txt
../bench_proj_perp/txt
../bench_expr_broadcast/txt
Comparison Numba vs Pythran (JIT)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment