|
5 | 5 | from __future__ import annotations |
6 | 6 |
|
7 | 7 | import dataclasses |
8 | | -import functools |
9 | 8 | from collections.abc import Sequence |
10 | 9 | from typing import TYPE_CHECKING |
11 | 10 |
|
12 | 11 | from cuda.core._utils.cuda_utils import driver |
13 | 12 | from cuda.core._utils.pycompat import StrEnum |
| 13 | +from cuda.core._utils.version import binding_version |
14 | 14 |
|
15 | 15 | if TYPE_CHECKING: |
16 | 16 | from cuda.core._device import Device |
@@ -94,39 +94,46 @@ def __post_init__(self): |
94 | 94 |
|
95 | 95 | def _to_driver_enum(self) -> int: |
96 | 96 | """Return the driver CUmemcpySrcAccessOrder value.""" |
97 | | - return _src_access_order_to_cu()[MemcpySrcAccessOrder(self.src_access_order)] |
| 97 | + if not _SRC_ACCESS_ORDER_TO_DRIVER: |
| 98 | + raise NotImplementedError(_CUDA13_REQUIRED) |
| 99 | + return _SRC_ACCESS_ORDER_TO_DRIVER[MemcpySrcAccessOrder(self.src_access_order)] |
98 | 100 |
|
99 | 101 | def _to_driver_flags(self) -> int: |
100 | 102 | """Return the driver CUmemcpyFlags value.""" |
101 | | - return _overlap_mode_to_cu()[MemcpyOverlapMode(self.overlap_mode)] |
| 103 | + if not _OVERLAP_MODE_TO_DRIVER: |
| 104 | + raise NotImplementedError(_CUDA13_REQUIRED) |
| 105 | + return _OVERLAP_MODE_TO_DRIVER[MemcpyOverlapMode(self.overlap_mode)] |
102 | 106 |
|
103 | 107 |
|
104 | | -# Bridges between the public StrEnums and the driver integer values. Built on |
105 | | -# first use rather than at import: the CUmemcpy* enums only exist on toolkits |
106 | | -# that ship the batched memcpy entry points, and importing cuda.core must not |
107 | | -# depend on them. |
| 108 | +_CUDA13_REQUIRED = "copy attributes require a CUDA 13 build of cuda-bindings" |
| 109 | + |
| 110 | +# CUmemcpySrcAccessOrder and CUmemcpyFlags are CUDA 13 additions, so these |
| 111 | +# maps are empty on a CUDA 12 build. Nothing reaches them there: copy_batch |
| 112 | +# refuses non-default CopyOptions when the batched entry point is absent. |
108 | 113 | # |
109 | | -# Keyed by ``str`` rather than by the enum: under ``python_version = "3.10"`` |
110 | | -# mypy resolves ``StrEnum`` to the unstubbed ``backports.strenum`` shim and so |
111 | | -# infers the members as plain ``str``. StrEnum members are ``str`` instances, |
112 | | -# so this annotation is accurate on every supported version. |
113 | | -@functools.cache |
114 | | -def _src_access_order_to_cu() -> dict[str, int]: |
115 | | - cu = driver.CUmemcpySrcAccessOrder |
116 | | - return { |
117 | | - MemcpySrcAccessOrder.STREAM: int(cu.CU_MEMCPY_SRC_ACCESS_ORDER_STREAM), |
118 | | - MemcpySrcAccessOrder.DURING_API_CALL: int(cu.CU_MEMCPY_SRC_ACCESS_ORDER_DURING_API_CALL), |
119 | | - MemcpySrcAccessOrder.ANY: int(cu.CU_MEMCPY_SRC_ACCESS_ORDER_ANY), |
| 114 | +# Keyed by ``str``: under ``python_version = "3.10"`` mypy resolves StrEnum to |
| 115 | +# the unstubbed backports shim and so infers the members as plain ``str``. |
| 116 | +# StrEnum members are ``str`` instances, so this holds on every version. The |
| 117 | +# values are wrapped in ``int()`` because the driver enums are untyped. |
| 118 | +_SRC_ACCESS_ORDER_TO_DRIVER: dict[str, int] |
| 119 | +_OVERLAP_MODE_TO_DRIVER: dict[str, int] |
| 120 | + |
| 121 | +if binding_version() >= (13, 0, 0): |
| 122 | + _src_order = driver.CUmemcpySrcAccessOrder |
| 123 | + _flags = driver.CUmemcpyFlags |
| 124 | + _SRC_ACCESS_ORDER_TO_DRIVER = { |
| 125 | + MemcpySrcAccessOrder.STREAM: int(_src_order.CU_MEMCPY_SRC_ACCESS_ORDER_STREAM), |
| 126 | + MemcpySrcAccessOrder.DURING_API_CALL: int(_src_order.CU_MEMCPY_SRC_ACCESS_ORDER_DURING_API_CALL), |
| 127 | + MemcpySrcAccessOrder.ANY: int(_src_order.CU_MEMCPY_SRC_ACCESS_ORDER_ANY), |
120 | 128 | } |
121 | | - |
122 | | - |
123 | | -@functools.cache |
124 | | -def _overlap_mode_to_cu() -> dict[str, int]: |
125 | | - cu = driver.CUmemcpyFlags |
126 | | - return { |
127 | | - MemcpyOverlapMode.DEFAULT: int(cu.CU_MEMCPY_FLAG_DEFAULT), |
128 | | - MemcpyOverlapMode.PREFER_OVERLAP_WITH_COMPUTE: int(cu.CU_MEMCPY_FLAG_PREFER_OVERLAP_WITH_COMPUTE), |
| 129 | + _OVERLAP_MODE_TO_DRIVER = { |
| 130 | + MemcpyOverlapMode.DEFAULT: int(_flags.CU_MEMCPY_FLAG_DEFAULT), |
| 131 | + MemcpyOverlapMode.PREFER_OVERLAP_WITH_COMPUTE: int(_flags.CU_MEMCPY_FLAG_PREFER_OVERLAP_WITH_COMPUTE), |
129 | 132 | } |
| 133 | + del _src_order, _flags |
| 134 | +else: |
| 135 | + _SRC_ACCESS_ORDER_TO_DRIVER = {} |
| 136 | + _OVERLAP_MODE_TO_DRIVER = {} |
130 | 137 |
|
131 | 138 |
|
132 | 139 | def _attr_run_starts(attrs: Sequence[CopyOptions]) -> list[int]: |
|
0 commit comments