Benchmark
Output of the benchmark described in this tutorial:
init(pint): 2.75 s init(qunits): 0.11 s Speedup: 24.52x inplace(pint): 3.54 s inplace(qunits): 0.27 s Speedup: 12.99x units(pint): 2.65 s units(qunits): 2.08 s Speedup: 1.27x array_ops(pint): 1.24 s array_ops(qunits): 0.86 s Speedup: 1.43x conversion(pint): 1.40 s conversion(qunits): 0.06 s Speedup: 23.58x qunits dimension cache size: 26 qunits unit cache size: 202
This tutorial shows benchmark test of qunits compared to pint for different operations.
The tests are split into five categories: initialization, standard arithmetics, unit creation, array operations, and unit conversion.
First, we import the necessary modules and set up the unit registries.
import os import time import numpy as np from pint import UnitRegistry from qunits import Quantity, u from qunits.dimension import _dimension_cache from qunits.unit import _unit_cache pintcache = os.path.join(os.path.dirname(__file__), "__pintcache__") p = UnitRegistry(cache_folder=pintcache)
Next, we define the benchmark functions for each category. Each function takes the name of the library being tested, the unit registry, and the number of iterations to perform. The functions measure the time taken to perform a specific operation repeatedly and print the results.
def bench_init(name, ureg, n=100_000): m = ureg.m mm = ureg.mm t0 = time.perf_counter() for _ in range(n): _ = (3 * m) + (4 * mm) # type: ignore dt = time.perf_counter() - t0 print(f"init({name}): {dt:.2f} s") return dt def bench_inplace(name, ureg, n=100_000): m = ureg.m mm = ureg.mm a = 3 * m b = 4 * mm t0 = time.perf_counter() for _ in range(n): a += b a -= b a *= b a /= b dt = time.perf_counter() - t0 print(f"inplace({name}): {dt:.2f} s") return dt def bench_units(name, ureg, n=1_000_000): m = ureg.m s = ureg.s t0 = time.perf_counter() for _ in range(n): _ = m / s _ = m * s dt = time.perf_counter() - t0 print(f"units({name}): {dt:.2f} s") return dt def bench_array_ops(name, ureg, q, n=200): arr = np.ones(1_000_000) a = q(arr, ureg.m) b = q(arr, ureg.mm) t0 = time.perf_counter() for _ in range(n): _ = a + b _ = a - b _ = a * b _ = a / b dt = time.perf_counter() - t0 print(f"array_ops({name}): {dt:.2f} s") return dt def bench_conversion(name, ureg, q, n=100_000): m = ureg.m mm = ureg.mm a = q(5.0, mm) t0 = time.perf_counter() for _ in range(n): _ = a.to(m) _ = a.m_as(m) dt = time.perf_counter() - t0 print(f"conversion({name}): {dt:.2f} s") return dt
Finally, we run the benchmark tests for each category and print the results.
n_samples = 100_000 dt_pint = bench_init("pint", p, n=n_samples) dt_qunits = bench_init("qunits", u, n=n_samples) print(f"Speedup: {dt_pint / dt_qunits:.2f}x\n") n_samples = 100_000 dt_pint = bench_inplace("pint", p, n=n_samples) dt_qunits = bench_inplace("qunits", u, n=n_samples) print(f"Speedup: {dt_pint / dt_qunits:.2f}x\n") n_samples = 1_000_000 dt_pint = bench_units("pint", p, n=n_samples) dt_qunits = bench_units("qunits", u, n=n_samples) print(f"Speedup: {dt_pint / dt_qunits:.2f}x\n") n_samples = 200 dt_pint = bench_array_ops("pint", p, p.Quantity, n=n_samples) dt_qunits = bench_array_ops("qunits", u, Quantity, n=n_samples) print(f"Speedup: {dt_pint / dt_qunits:.2f}x\n") n_samples = 100_000 dt_pint = bench_conversion("pint", p, p.Quantity, n=n_samples) dt_qunits = bench_conversion("qunits", u, Quantity, n=n_samples) print(f"Speedup: {dt_pint / dt_qunits:.2f}x\n") print(f"qunits dimension cache size: {len(_dimension_cache)}") print(f"qunits unit cache size: {len(_unit_cache)}")