Skip to content

Commit 0a0dc50

Browse files
committed
refactor backend selection
1 parent ca7aa6c commit 0a0dc50

File tree

7 files changed

+70
-34
lines changed

7 files changed

+70
-34
lines changed

docs/development/ADRs/0015-Test_Exclusion_Matrices.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
2-
tags: []
2+
tags: [testing]
33
---
44

55
# Test-Exclusion Matrices
66

77
- **Status**: valid
88
- **Authors**: Edoardo Paone (@edopao), Enrique G. Paredes (@egparedes)
99
- **Created**: 2023-09-21
10-
- **Updated**: 2023-09-21
10+
- **Updated**: 2024-01-25
1111

1212
In the context of Field View testing, lacking support for specific ITIR features while a certain backend
1313
is being developed, we decided to use `pytest` fixtures to exclude unsupported tests.
@@ -33,7 +33,7 @@ In the example below, `test_offset_field` requires the backend to support dynami
3333
def test_offset_field(cartesian_case):
3434
```
3535

36-
In order to selectively enable the backends, the dictionary `next_tests.exclusion_matrices.BACKEND_SKIP_TEST_MATRIX`
36+
In order to selectively enable the backends, the dictionary `next_tests.definitions.BACKEND_SKIP_TEST_MATRIX`
3737
lists for each backend the features that are not supported.
3838
The fixture will check if the annotated feature is present in the exclusion-matrix for the selected backend.
3939
If so, the exclusion matrix will also specify the action `pytest` should take (e.g. `SKIP` or `XFAIL`).

src/gt4py/next/allocators.py

+13
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def __init__(self) -> None:
231231

232232
device_allocators[core_defs.DeviceType.CPU] = StandardCPUFieldBufferAllocator()
233233

234+
234235
assert is_field_allocator(device_allocators[core_defs.DeviceType.CPU])
235236

236237

@@ -349,3 +350,15 @@ def allocate(
349350
device_id=device.device_id,
350351
aligned_index=aligned_index,
351352
)
353+
354+
355+
def __getattr__(name: str) -> Any:
356+
if name == "default_cpu_allocator":
357+
return device_allocators[core_defs.DeviceType.CPU]
358+
if name == "default_gpu_allocator":
359+
if CUPY_DEVICE is core_defs.DeviceType.CUDA:
360+
return device_allocators[core_defs.DeviceType.CUDA]
361+
elif CUPY_DEVICE is core_defs.DeviceType.ROCM:
362+
return device_allocators[core_defs.DeviceType.ROCM]
363+
# else: fall through
364+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

tests/next_tests/definitions.py

+3-14
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
import pytest
2121

22-
from gt4py.next import allocators as next_allocators
23-
2422

2523
# Skip definitions
2624
XFAIL = pytest.xfail
@@ -46,11 +44,6 @@ def short_id(self, num_components: int = 2) -> str:
4644
return ".".join(self.value.split(".")[-num_components:])
4745

4846

49-
class _PythonObjectIdMixinForAllocator(_PythonObjectIdMixin):
50-
def short_id(self, num_components: int = 1) -> str:
51-
return "None-" + super().short_id(num_components)
52-
53-
5447
class ProgramBackendId(_PythonObjectIdMixin, str, enum.Enum):
5548
GTFN_CPU = "gt4py.next.program_processors.runners.gtfn.run_gtfn"
5649
GTFN_CPU_IMPERATIVE = "gt4py.next.program_processors.runners.gtfn.run_gtfn_imperative"
@@ -62,13 +55,9 @@ class ProgramBackendId(_PythonObjectIdMixin, str, enum.Enum):
6255
DOUBLE_ROUNDTRIP = "gt4py.next.program_processors.runners.double_roundtrip.backend"
6356

6457

65-
cpu_allocator = next_allocators.StandardCPUFieldBufferAllocator()
66-
gpu_allocator = next_allocators.StandardGPUFieldBufferAllocator()
67-
68-
69-
class AllocatorId(_PythonObjectIdMixinForAllocator, str, enum.Enum):
70-
CPU_ALLOCATOR = "next_tests.definitions.cpu_allocator"
71-
GPU_ALLOCATOR = "next_tests.definitions.gpu_allocator"
58+
class AllocatorId(_PythonObjectIdMixin, str, enum.Enum):
59+
CPU_ALLOCATOR = "gt4py.next.allocators.default_cpu_allocator"
60+
GPU_ALLOCATOR = "gt4py.next.allocators.default_gpu_allocator"
7261

7362

7463
class OptionalProgramBackendId(_PythonObjectIdMixin, str, enum.Enum):

tests/next_tests/integration_tests/cases.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -482,18 +482,18 @@ def verify_with_default_data(
482482
@pytest.fixture
483483
def cartesian_case(fieldview_backend): # noqa: F811 # fixtures
484484
yield Case(
485-
fieldview_backend if isinstance(fieldview_backend, ppi.ProgramExecutor) else None,
485+
fieldview_backend.executor,
486486
offset_provider={"Ioff": IDim, "Joff": JDim, "Koff": KDim},
487487
default_sizes={IDim: 10, JDim: 10, KDim: 10},
488488
grid_type=common.GridType.CARTESIAN,
489-
allocator=fieldview_backend,
489+
allocator=fieldview_backend.allocator,
490490
)
491491

492492

493493
@pytest.fixture
494494
def unstructured_case(reduction_setup, fieldview_backend): # noqa: F811 # fixtures
495495
yield Case(
496-
fieldview_backend if isinstance(fieldview_backend, ppi.ProgramExecutor) else None,
496+
fieldview_backend.executor,
497497
offset_provider=reduction_setup.offset_provider,
498498
default_sizes={
499499
Vertex: reduction_setup.num_vertices,
@@ -502,7 +502,7 @@ def unstructured_case(reduction_setup, fieldview_backend): # noqa: F811 # fixtu
502502
KDim: reduction_setup.k_levels,
503503
},
504504
grid_type=common.GridType.UNSTRUCTURED,
505-
allocator=fieldview_backend,
505+
allocator=fieldview_backend.allocator,
506506
)
507507

508508

tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py

+35-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# SPDX-License-Identifier: GPL-3.0-or-later
1515

1616
from collections import namedtuple
17-
from typing import Any, TypeVar
17+
from typing import Any, Optional, TypeVar
1818

1919
import numpy as np
2020
import pytest
@@ -52,6 +52,23 @@ def no_backend(program: itir.FencilDefinition, *args: Any, **kwargs: Any) -> Non
5252
)
5353
),
5454

55+
_ExecutorAndAllocator = namedtuple("_ExecutorAndAllocator", ["executor", "allocator"])
56+
57+
58+
def _backend_name(
59+
p: next_tests.definitions._PythonObjectIdMixin
60+
| tuple[
61+
Optional[next_tests.definitions._PythonObjectIdMixin],
62+
next_tests.definitions._PythonObjectIdMixin,
63+
]
64+
):
65+
if isinstance(p, tuple):
66+
executor = p[0].short_id() if p[0] is not None else "None"
67+
allocator = p[1].short_id()
68+
return f"{executor}-{allocator}"
69+
else:
70+
return p.short_id()
71+
5572

5673
@pytest.fixture(
5774
params=[
@@ -63,13 +80,13 @@ def no_backend(program: itir.FencilDefinition, *args: Any, **kwargs: Any) -> Non
6380
next_tests.definitions.ProgramBackendId.GTFN_GPU, marks=pytest.mark.requires_gpu
6481
),
6582
# will use the default (embedded) execution, but input/output allocated with the provided allocator
66-
next_tests.definitions.AllocatorId.CPU_ALLOCATOR,
83+
(None, next_tests.definitions.AllocatorId.CPU_ALLOCATOR),
6784
pytest.param(
68-
next_tests.definitions.AllocatorId.GPU_ALLOCATOR, marks=pytest.mark.requires_gpu
85+
(None, next_tests.definitions.AllocatorId.GPU_ALLOCATOR), marks=pytest.mark.requires_gpu
6986
),
7087
]
7188
+ OPTIONAL_PROCESSORS,
72-
ids=lambda p: p.short_id() if p is not None else "None",
89+
ids=_backend_name,
7390
)
7491
def fieldview_backend(request):
7592
"""
@@ -79,17 +96,27 @@ def fieldview_backend(request):
7996
Check ADR 15 for details on the test-exclusion matrices.
8097
"""
8198
backend_or_allocator_id = request.param
82-
backend_or_allocator = backend_or_allocator_id.load()
99+
if isinstance(backend_or_allocator_id, tuple):
100+
backend_id, allocator_id = backend_or_allocator_id
101+
assert backend_id is None # revisit if we have need for backend_id != None
102+
executor = None
103+
allocator = allocator_id.load()
104+
exclusion_matrix_id = backend_or_allocator_id[1]
105+
else:
106+
backend = backend_or_allocator_id.load()
107+
executor = backend.executor
108+
allocator = backend
109+
exclusion_matrix_id = backend_or_allocator_id
83110

84111
for marker, skip_mark, msg in next_tests.definitions.BACKEND_SKIP_TEST_MATRIX.get(
85-
backend_or_allocator_id, []
112+
exclusion_matrix_id, []
86113
):
87114
if request.node.get_closest_marker(marker):
88-
skip_mark(msg.format(marker=marker, backend=backend_or_allocator_id))
115+
skip_mark(msg.format(marker=marker, backend=_backend_name(backend_or_allocator_id)))
89116

90117
backup_backend = decorator.DEFAULT_BACKEND
91118
decorator.DEFAULT_BACKEND = no_backend
92-
yield backend_or_allocator
119+
yield _ExecutorAndAllocator(executor, allocator)
93120
decorator.DEFAULT_BACKEND = backup_backend
94121

95122

tests/next_tests/integration_tests/feature_tests/test_util_cases.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
cartesian_case,
2525
fieldview_backend,
2626
)
27+
from next_tests.integration_tests.feature_tests.ffront_tests import ffront_test_utils
2728

2829

2930
@gtx.field_operator
@@ -70,7 +71,13 @@ def test_allocate_const(cartesian_case): # noqa: F811 # fixtures
7071
assert b == 42.0
7172

7273

73-
@pytest.mark.parametrize("fieldview_backend", [~definitions.ProgramBackendId.ROUNDTRIP])
74+
_roundtrip_executor_and_allocator = ffront_test_utils._ExecutorAndAllocator(
75+
definitions.ProgramBackendId.ROUNDTRIP.load().executor,
76+
definitions.ProgramBackendId.ROUNDTRIP.load(),
77+
)
78+
79+
80+
@pytest.mark.parametrize("fieldview_backend", [_roundtrip_executor_and_allocator])
7481
def test_verify_fails_with_wrong_reference(cartesian_case): # noqa: F811 # fixtures
7582
a = cases.allocate(cartesian_case, addition, "a")()
7683
b = cases.allocate(cartesian_case, addition, "b")()
@@ -81,7 +88,7 @@ def test_verify_fails_with_wrong_reference(cartesian_case): # noqa: F811 # fixt
8188
cases.verify(cartesian_case, addition, a, b, out=out, ref=wrong_ref)
8289

8390

84-
@pytest.mark.parametrize("fieldview_backend", [~definitions.ProgramBackendId.ROUNDTRIP])
91+
@pytest.mark.parametrize("fieldview_backend", [_roundtrip_executor_and_allocator])
8592
def test_verify_fails_with_wrong_type(cartesian_case): # noqa: F811 # fixtures
8693
a = cases.allocate(cartesian_case, addition, "a").dtype(np.float32)()
8794
b = cases.allocate(cartesian_case, addition, "b")()
@@ -91,7 +98,7 @@ def test_verify_fails_with_wrong_type(cartesian_case): # noqa: F811 # fixtures
9198
cases.verify(cartesian_case, addition, a, b, out=out, ref=a + b)
9299

93100

94-
@pytest.mark.parametrize("fieldview_backend", [~definitions.ProgramBackendId.ROUNDTRIP])
101+
@pytest.mark.parametrize("fieldview_backend", [_roundtrip_executor_and_allocator])
95102
def test_verify_with_default_data_fails_with_wrong_reference(
96103
cartesian_case, # noqa: F811 # fixtures
97104
):

tests/next_tests/integration_tests/multi_feature_tests/ffront_tests/test_icon_like_scan.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ def reference(
196196
@pytest.fixture
197197
def test_setup(fieldview_backend):
198198
test_case = cases.Case(
199-
fieldview_backend if isinstance(fieldview_backend, ppi.ProgramExecutor) else None,
199+
fieldview_backend.executor,
200200
offset_provider={"Koff": KDim},
201201
default_sizes={Cell: 14, KDim: 10},
202202
grid_type=common.GridType.UNSTRUCTURED,
203-
allocator=fieldview_backend,
203+
allocator=fieldview_backend.allocator,
204204
)
205205

206206
@dataclasses.dataclass(frozen=True)

0 commit comments

Comments
 (0)