Commit 4679be99b35 by Pierre Augier

Add 2 functions useful for benchmarks

parent 0c9b413615a
......@@ -31,39 +31,24 @@ broadcast_loops_numba = boost(backend="numba")(broadcast_loops)
if __name__ == "__main__":
import numba
import pythran
from transonic import __version__
from transonic.util import timeit
from transonic.util import print_versions, timeit_verbose
print_versions()
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)
loc = locals()
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")
print()
norm = timeit_verbose("broadcast(a, b, out)", globals=loc)
for backend in ("numba", "pythran"):
bench(f"broadcast_{backend}(a, b, out)", norm=norm)
bench(f"broadcast_loops_{backend}(a, b, out)", norm=norm)
timeit_verbose(f"broadcast_{backend}(a, b, out)", globals=loc, norm=norm)
timeit_verbose(f"broadcast_loops_{backend}(a, b, out)", globals=loc, norm=norm)
......@@ -3,18 +3,27 @@ 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
This example uses the ``boost`` decorator, so the Python file needs to be
transpiled by Transonic and the accelerator files need to be compiled. You can
for example run from the directory ``doc/examples/bench_proj_perp``::
make clean
make
python bench.py
The last command gives something like::
Transonic 0.4.1
Pythran 0.9.3post1
Numba 0.46.0
Cython 0.29.13
broadcast : 1.000 * norm
norm = 1.55e-04 s
broadcast_numba : 0.462 * norm
broadcast_loops_numba : 0.433 * norm
broadcast_pythran : 0.270 * norm
broadcast_loops_pythran : 0.408 * norm
For the solution with loops, the 2 backends are equally good.
......
import numpy as np
from transonic import boost, Array, Type
......@@ -14,7 +13,9 @@ def proj(vx: A, vy: A, vz: A, kx: Af, ky: Af, kz: Af, inv_k_square_nozero: Af):
vz -= kz * tmp
def proj_loop(vx: A, vy: A, vz: A, kx: Af, ky: Af, kz: Af, inv_k_square_nozero: Af):
def proj_loop(
vx: A, vy: A, vz: A, kx: Af, ky: Af, kz: Af, inv_k_square_nozero: Af
):
# type annotations only useful for Cython
n0: int
......@@ -47,26 +48,22 @@ proj_cython = boost(backend="cython")(proj)
proj_loop_pythran = boost(backend="pythran")(proj_loop)
proj_loop_numba = boost(backend="numba")(proj_loop)
proj_loop_cython = boost(backend="cython", boundscheck=False, wraparound=False)(proj_loop)
proj_loop_cython = boost(backend="cython", boundscheck=False, wraparound=False)(
proj_loop
)
if __name__ == "__main__":
from textwrap import dedent
import numba
import pythran
from transonic import __version__
from transonic.util import timeit
from transonic.util import print_versions, timeit_verbose
print(
f"transonic {__version__}\n"
f"pythran {pythran.__version__}\n"
f"numba {numba.__version__}\n"
)
loc = locals()
setup = dedent("""
print_versions()
setup = dedent(
"""
shape = n0, n1, n2 = 64, 512, 512
k0 = np.linspace(0, 100, n0)
k1 = np.linspace(0, 100, n1)
......@@ -83,23 +80,26 @@ if __name__ == "__main__":
vx = np.ones(shape)
vy = np.ones(shape)
vz = np.ones(shape)
"""
)
""")
loc = locals()
def bench(call, norm=None):
ret = result = timeit(call, setup=setup, globals=loc)
if norm is None:
norm = result
result /= norm
print(f"{call.split('(')[0]:33s}: {result:.2f}")
return ret
norm = bench("proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)")
print(f"norm = {norm:.2e} s")
print()
norm = timeit_verbose(
"proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)",
setup=setup,
globals=loc,
)
for backend in ("cython", "numba", "pythran"):
bench(f"proj_{backend}(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)", norm=norm)
bench(f"proj_loop_{backend}(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)", norm=norm)
\ No newline at end of file
timeit_verbose(
f"proj_{backend}(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)",
setup=setup,
globals=loc,
norm=norm,
)
timeit_verbose(
f"proj_loop_{backend}(vx, vy, vz, kx, ky, kz, inv_k_square_nozero)",
setup=setup,
globals=loc,
norm=norm,
)
......@@ -3,20 +3,30 @@ Benchmark projection vector
.. literalinclude:: bench.py
which gives::
This example uses the ``boost`` decorator, so the Python file needs to be
transpiled by Transonic and the accelerator files need to be compiled. You can
for example run from the directory ``doc/examples/bench_proj_perp``::
transonic 0.4.1
pythran 0.9.3post1
numba 0.46.0
make clean
make
python bench.py
proj : 1.00
The last command gives something like::
Transonic 0.4.1
Pythran 0.9.3post1
Numba 0.46.0
Cython 0.29.13
proj : 1.00 * norm
norm = 5.76e-01 s
proj_cython : 1.26
proj_loop_cython : 0.18
proj_numba : 1.34
proj_loop_numba : 0.15
proj_pythran : 0.42
proj_loop_pythran : 0.14
proj_cython : 1.26 * norm
proj_loop_cython : 0.18 * norm
proj_numba : 1.34 * norm
proj_loop_numba : 0.15 * norm
proj_pythran : 0.42 * norm
proj_loop_pythran : 0.14 * norm
For the solution with loops, the 3 backends are equally good.
......
......@@ -34,37 +34,24 @@ fxfy_loops_numba = boost(backend="numba")(fxfy_loops)
if __name__ == "__main__":
import numba
import pythran
from transonic import __version__
from transonic.util import timeit
from transonic.util import print_versions, timeit_verbose
print_versions()
theta = np.linspace(0, 2 * np.pi, 10000)
ft = 2.5 * theta
fv = 1.5 * theta
loc = locals()
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")
print()
norm = timeit_verbose("fxfy(ft, fv, theta)", globals=loc)
for backend in ("numba", "pythran"):
bench(f"fxfy_{backend}(ft, fv, theta)", norm=norm)
bench(f"fxfy_loops_{backend}(ft, fv, theta)", norm=norm)
timeit_verbose(f"fxfy_{backend}(ft, fv, theta)", globals=loc, norm=norm)
timeit_verbose(
f"fxfy_loops_{backend}(ft, fv, theta)", globals=loc, norm=norm
)
......@@ -42,55 +42,62 @@
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Transonic 0.4.1\n",
"Pythran 0.9.3post1\n",
"Numba 0.46.0\n",
"Cython 0.29.13\n"
]
}
],
"source": [
"from transonic import wait_for_all_extensions\n",
"from transonic.util import print_versions, timeit_verbose\n",
"\n",
"print_versions()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"theta = np.linspace(0, 2 * np.pi, 10000)\n",
"ft = 2.5 * theta\n",
"fv = 1.5 * theta\n",
"loc = locals()\n",
"\n",
"out = fxfy(ft, fv, theta)\n",
"out_loops = fxfy_loops(ft, fv, theta)\n",
"assert np.allclose(out, out_loops)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[32mINFO \u001b[0m \u001b[34mSchedule pythranization of file /home/pierre/.transonic/pythran/__jit__/__ipython__6ca57c6e93778ae96e3e4b88a3e893ab/fxfy.py\u001b[0m\n",
"\u001b[32mINFO \u001b[0m \u001b[34mSchedule pythranization of file /home/pierre/.transonic/pythran/__jit__/__ipython__6ca57c6e93778ae96e3e4b88a3e893ab/fxfy_loops.py\u001b[0m\n"
"INFO: Schedule pythranization of file /home/users/augier3pi/.transonic/pythran/__jit__/__ipython__6ca57c6e93778ae96e3e4b88a3e893ab/fxfy.py\n",
"INFO: Schedule pythranization of file /home/users/augier3pi/.transonic/pythran/__jit__/__ipython__6ca57c6e93778ae96e3e4b88a3e893ab/fxfy_loops.py\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"transonic 0.4.1\n",
"pythran 0.9.3post1\n",
"numba 0.46.0\n",
"\n",
"compile extension\n",
"compile extension\n"
]
}
],
"source": [
"import numba\n",
"import pythran\n",
"from transonic import __version__, wait_for_all_extensions\n",
"from transonic.util import timeit\n",
"\n",
"theta = np.linspace(0, 2 * np.pi, 10000)\n",
"ft = 2.5 * theta\n",
"fv = 1.5 * theta\n",
"out = fxfy(ft, fv, theta)\n",
"out_loops = fxfy_loops(ft, fv, theta)\n",
"assert np.allclose(out, out_loops)\n",
"\n",
"print(\n",
" f\"transonic {__version__}\\n\"\n",
" f\"pythran {pythran.__version__}\\n\"\n",
" f\"numba {numba.__version__}\\n\"\n",
")\n",
"\n",
"loc = locals()\n",
"\n",
"def bench(call, norm=None):\n",
" ret = result = timeit(call, globals=loc)\n",
" if norm is None:\n",
" norm = result\n",
" result /= norm\n",
" print(f\"{call.split('(')[0]:33s}: {result:.3f} * norm\")\n",
" return ret\n",
"\n",
"# warmup\n",
"fxfy_pythran(ft, fv, theta)\n",
"fxfy_loops_pythran(ft, fv, theta)\n",
......@@ -102,7 +109,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 5,
"metadata": {},
"outputs": [
{
......@@ -110,21 +117,23 @@
"output_type": "stream",
"text": [
"fxfy : 1.000 * norm\n",
"norm = 2.68e-04 s\n",
"fxfy_numba : 0.956 * norm\n",
"fxfy_loops_numba : 0.917 * norm\n",
"fxfy_pythran : 0.217 * norm\n",
"fxfy_loops_pythran : 0.918 * norm\n"
"norm = 6.90e-04 s\n",
"fxfy_numba : 0.952 * norm\n",
"fxfy_loops_numba : 0.776 * norm\n",
"fxfy_pythran : 0.152 * norm\n",
"fxfy_loops_pythran : 0.784 * norm\n"
]
}
],
"source": [
"norm = bench(\"fxfy(ft, fv, theta)\")\n",
"norm = timeit_verbose(\"fxfy(ft, fv, theta)\", globals=loc)\n",
"print(f\"norm = {norm:.2e} s\")\n",
"\n",
"for backend in (\"numba\", \"pythran\"):\n",
" bench(f\"fxfy_{backend}(ft, fv, theta)\", norm=norm)\n",
" bench(f\"fxfy_loops_{backend}(ft, fv, theta)\", norm=norm)"
" timeit_verbose(f\"fxfy_{backend}(ft, fv, theta)\", globals=loc, norm=norm)\n",
" timeit_verbose(\n",
" f\"fxfy_loops_{backend}(ft, fv, theta)\", globals=loc, norm=norm\n",
" )"
]
}
],
......@@ -144,7 +153,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
"version": "3.7.5"
}
},
"nbformat": 4,
......
......@@ -3,18 +3,27 @@ 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
This example uses the ``boost`` decorator, so the Python file needs to be
transpiled by Transonic and the accelerator files need to be compiled. You can
for example run from the directory ``doc/examples/bench_proj_perp``::
make clean
make
python bench.py
The last command gives something like::
Transonic 0.4.1
Pythran 0.9.3post1
Numba 0.46.0
Cython 0.29.13
fxfy : 1.000 * norm
norm = 6.76e-04 s
fxfy_numba : 0.969 * norm
fxfy_loops_numba : 0.792 * norm
fxfy_pythran : 0.123 * norm
fxfy_loops_pythran : 0.787 * norm
For the solution with loops, the 2 backends are equally good.
......
......@@ -46,6 +46,8 @@ doc =
dev =
%(doc)s
%(test)s
flake8
pylint
[flake8]
ignore = E501,E225,E226,E303,E201,E202,E203,W503
......
from transonic import util
from transonic.util import query_yes_no, timeit
from transonic.util import query_yes_no, timeit, print_versions, timeit_verbose
def test_query_yes_no():
......@@ -20,3 +20,14 @@ def test_timeit():
a = 1
b = 2
timeit("a + b", total_duration=0.001, globals=locals())
def test_timeit_verbose():
a = 1
b = 2
norm = timeit_verbose("a + b", total_duration=0.001, globals=locals())
timeit_verbose("a + b", total_duration=0.001, globals=locals(), norm=norm)
def test_print_versions():
print_versions()
......@@ -89,6 +89,7 @@ try:
except ImportError:
pass
from transonic import __version__
from transonic.analyses import extast
from transonic.compiler import (
......@@ -127,6 +128,35 @@ def can_import_accelerator(backend: str = backend_default):
return True
def print_versions(accelerators=None):
print(f"Transonic {__version__}")
if accelerators is None or "pythran" in accelerators:
try:
import pythran
except ImportError:
print("Pythran not importable")
else:
print(f"Pythran {pythran.__version__}")
if accelerators is None or "numba" in accelerators:
try:
import numba
except ImportError:
print("Numba not importable")
else:
print(f"Numba {numba.__version__}")
if accelerators is None or "cython" in accelerators:
try:
import Cython
except ImportError:
print("Cython not importable")
else:
print(f"Cython {Cython.__version__}")
def find_module_name_from_path(path_py: Path):
"""Find the module name from the path of a Python file
......@@ -456,3 +486,16 @@ def timeit(stmt="pass", setup="pass", total_duration=2, globals=None):
duration = min(timer.repeat(repeat=repeat, number=number))
return duration / number
def timeit_verbose(stmt, setup="pass", total_duration=2, globals=None, norm=None):
ret = result = timeit(
stmt, setup=setup, total_duration=total_duration, globals=globals
)
if norm is None:
norm = result
result /= norm
print(f"{stmt.split('(')[0]:33s}: {result:.3f} * norm")
if result == 1.0:
print(f"norm = {norm:.2e} s")
return ret
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