Skip to content

Commit eee31ed

Browse files
authored
test: allow selection of CoreAI compute unit during inference (#21)
* test(export): select CoreAI compute unit in MLIRConverter inference * test(export): add --compute-unit-kind pytest option
1 parent 367dfd5 commit eee31ed

2 files changed

Lines changed: 103 additions & 1 deletion

File tree

tests/conftest.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,49 @@
3636

3737
_DEFAULT_SEED: int = 42
3838

39+
_COMPUTE_UNIT_KIND_CHOICES = ("interpreter", "cpu", "gpu", "neural_engine")
40+
_COMPUTE_UNIT_KIND_DEFAULT = "interpreter"
41+
42+
43+
def pytest_addoption(parser: pytest.Parser) -> None:
44+
"""Register CLI options."""
45+
parser.addoption(
46+
"--compute-unit-kind",
47+
choices=list(_COMPUTE_UNIT_KIND_CHOICES),
48+
default=_COMPUTE_UNIT_KIND_DEFAULT,
49+
help=(
50+
"Compute unit used by MLIRConverter inference:\n"
51+
" interpreter (default) - bundled runtime (USE_LOCAL_COREAI=1)\n"
52+
" cpu - SpecializationOptions.cpu_only() (BNNS)\n"
53+
" gpu - preferred ComputeUnitKind.gpu() (MPSGraph)\n"
54+
" neural_engine - preferred ComputeUnitKind.neural_engine()\n"
55+
"Anything other than 'interpreter' unsets USE_LOCAL_COREAI so the OS\n"
56+
"runtime is used."
57+
),
58+
)
59+
60+
61+
def pytest_configure(config: pytest.Config) -> None:
62+
"""Publish the selected compute unit to the export test utils.
63+
64+
For ``--compute-unit-kind=interpreter`` we pin ``USE_LOCAL_COREAI=1`` so the
65+
bundled runtime is used. For any real compute unit (cpu/gpu/neural_engine)
66+
we drop the env var so the OS runtime — which actually exposes those compute
67+
units — gets picked up.
68+
"""
69+
compute_unit_kind = config.getoption("--compute-unit-kind")
70+
if compute_unit_kind == "interpreter":
71+
os.environ.setdefault("USE_LOCAL_COREAI", "1")
72+
else:
73+
os.environ.pop("USE_LOCAL_COREAI", None)
74+
75+
# Imported here — after the env var is adjusted — because export_utils imports
76+
# coreai_torch at module load, and coreai_torch reads USE_LOCAL_COREAI at
77+
# dlopen time. Importing earlier would lock in the wrong runtime.
78+
from tests.export.export_utils import set_test_compute_unit_kind # noqa: PLC0415
79+
80+
set_test_compute_unit_kind(compute_unit_kind)
81+
3982

4083
@pytest.fixture(autouse=True)
4184
def seed_every_test(request: pytest.FixtureRequest) -> None:

tests/export/export_utils.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""Utilities for converting and verifying PyTorch models for export testing."""
77

88
import asyncio
9+
import platform
910
import sys
1011
import tempfile
1112
from abc import ABC, abstractmethod
@@ -25,10 +26,66 @@
2526
from coreai_opt import CoreMLExportError, ExportBackend
2627
from tests.test_utils.general import verify_snr_psnr as _verify_snr_psnr
2728

29+
if platform.system() == "Darwin":
30+
from coreai.runtime import ComputeUnitKind, SpecializationOptions
31+
2832
# Substring of the dtype guard message raised by the CoreML export validation. Shared so
2933
# test files asserting the rejection don't drift from one another.
3034
COREML_DTYPE_REJECTION_MATCH = "CoreML export does not support"
3135

36+
# Compute unit selection driven by the --compute-unit-kind pytest option (see
37+
# tests/conftest.py). Default is "interpreter" so a plain `pytest` run uses the
38+
# bundled runtime.
39+
_COMPUTE_UNIT_KIND: str = "interpreter"
40+
41+
42+
def set_test_compute_unit_kind(name: str) -> None:
43+
"""Set the compute unit used by ``MLIRConverter`` inference.
44+
45+
Called from tests/conftest.py::pytest_configure based on --compute-unit-kind.
46+
47+
Args:
48+
name (str): One of "interpreter", "cpu", "gpu", or "neural_engine".
49+
"""
50+
global _COMPUTE_UNIT_KIND
51+
_COMPUTE_UNIT_KIND = name
52+
53+
54+
def _get_test_specialization_options() -> "SpecializationOptions | None":
55+
"""Translate the configured compute unit into ``SpecializationOptions`` (or None).
56+
57+
On non-macOS platforms only ``interpreter`` is supported — the runtime does
58+
not expose ``SpecializationOptions`` outside Darwin.
59+
60+
Returns:
61+
SpecializationOptions | None: ``None`` for the interpreter (bundled
62+
runtime); otherwise the options selecting the requested delegate.
63+
64+
Raises:
65+
RuntimeError: If a real compute unit is requested off macOS.
66+
ValueError: If the configured compute unit kind is unknown.
67+
"""
68+
if _COMPUTE_UNIT_KIND == "interpreter":
69+
return None
70+
if platform.system() != "Darwin":
71+
msg = (
72+
f"--compute-unit-kind={_COMPUTE_UNIT_KIND} is only supported on macOS; "
73+
"use --compute-unit-kind=interpreter on this platform."
74+
)
75+
raise RuntimeError(msg)
76+
if _COMPUTE_UNIT_KIND == "cpu":
77+
return SpecializationOptions.cpu_only()
78+
if _COMPUTE_UNIT_KIND == "gpu":
79+
return SpecializationOptions.from_preferred_compute_unit_kind(
80+
compute_unit_kind=ComputeUnitKind.gpu(),
81+
)
82+
if _COMPUTE_UNIT_KIND == "neural_engine":
83+
return SpecializationOptions.from_preferred_compute_unit_kind(
84+
compute_unit_kind=ComputeUnitKind.neural_engine(),
85+
)
86+
msg = f"Unknown compute unit kind: {_COMPUTE_UNIT_KIND!r}"
87+
raise ValueError(msg)
88+
3289

3390
def assert_coreml_finalize_rejects_unsupported_dtype(finalizer: Any) -> None:
3491
"""Assert ``finalizer.finalize(backend=CoreML)`` rejects an unsupported dtype.
@@ -403,7 +460,9 @@ async def _run_inference_async(
403460
suffix=".aimodel",
404461
) as tmpdir:
405462
asset = converted_model.save_asset(Path(tmpdir))
406-
async with asset.executable() as ai_model:
463+
async with asset.executable(
464+
specialization_options=_get_test_specialization_options(),
465+
) as ai_model:
407466
rt_func = ai_model.load_function("main")
408467

409468
input_names = rt_func.desc.input_names

0 commit comments

Comments
 (0)