diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json index 1e26be0d..19c9771c 100644 --- a/benchmarks/asv.conf.json +++ b/benchmarks/asv.conf.json @@ -19,6 +19,6 @@ "build_cache_size": 2, "default_benchmark_timeout": 500, "regressions_thresholds": { - ".*": 0.3 + ".*": 0.2 } } diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py index 9b89c10b..556c4d9c 100644 --- a/benchmarks/benchmarks/__init__.py +++ b/benchmarks/benchmarks/__init__.py @@ -4,6 +4,8 @@ import psutil +from ._patch_setup import _apply_patches + _MIN_THREADS = 4 # minimum physical cores required for multi-threaded mode @@ -19,3 +21,6 @@ def _thread_count(): _THREADS = os.environ.get("MKL_NUM_THREADS", _thread_count()) os.environ["MKL_NUM_THREADS"] = _THREADS + +_apply_patches() +del _apply_patches diff --git a/benchmarks/benchmarks/_patch_setup.py b/benchmarks/benchmarks/_patch_setup.py new file mode 100644 index 00000000..54f02ca2 --- /dev/null +++ b/benchmarks/benchmarks/_patch_setup.py @@ -0,0 +1,67 @@ +"""MKL patch setup — executed once per ASV worker process at import time. + +Patches NumPy FFT with the Intel MKL FFT implementation. +Hard-fails with a descriptive RuntimeError if mkl_fft is missing or the +patch does not take effect, so benchmarks never silently run on stock NumPy. +""" + +_PATCH_MAP = [ + ("mkl_fft", "patch_numpy_fft"), +] + + +def _apply_patches(): + import importlib + + import numpy as np + + patched = {} + + for mod_name, patch_fn_name in _PATCH_MAP: + try: + mod = importlib.import_module(mod_name) + except ImportError as exc: + raise RuntimeError( + f"[mkl-patch] Cannot import {mod_name}: {exc}\n" + f" Ensure the conda env contains {mod_name} " + f"from the Intel channel.\n" + " Required channels: " + "https://software.repos.intel.com/python/conda" + ) from exc + + patch_fn = getattr(mod, patch_fn_name, None) + if patch_fn is None: + raise RuntimeError( + f"[mkl-patch] {mod_name} has no {patch_fn_name}(). " + f"Upgrade {mod_name} to a version that exposes " + "the stock-numpy patch API." + ) + + try: + patch_fn() + except Exception as exc: + raise RuntimeError( + f"[mkl-patch] {mod_name}.{patch_fn_name}() raised: {exc!r}" + ) from exc + + is_patched_fn = getattr(mod, "is_patched", None) + if callable(is_patched_fn) and not is_patched_fn(): + raise RuntimeError( + f"[mkl-patch] {mod_name}.is_patched() returned False " + "after patching. NumPy may have been imported before " + "patching in a conflicting state." + ) + + patched[mod_name] = mod + + _attr_checks = { + "mkl_fft": lambda: np.fft.fft.__module__, + } + for mod_name in patched: + try: + attr = _attr_checks[mod_name]() + except Exception: + attr = "unknown" + print(f"[mkl-patch] {mod_name}: numpy.fft dispatch -> {attr}") + + print("[mkl-patch] ALL OK -- mkl_fft active") diff --git a/benchmarks/requirements.txt b/benchmarks/requirements.txt new file mode 100644 index 00000000..04566f48 --- /dev/null +++ b/benchmarks/requirements.txt @@ -0,0 +1,2 @@ +psutil +scipy