nvmath-python 0.9.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +383 -0
- nvmath/_utils.py +150 -0
- nvmath/bindings/__init__.py +51 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +47 -0
- nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +277 -0
- nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +179 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +746 -0
- nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1337 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +219 -0
- nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +86 -0
- nvmath/bindings/cudss.pyi +282 -0
- nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +241 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +260 -0
- nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +159 -0
- nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +242 -0
- nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +416 -0
- nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +338 -0
- nvmath/bindings/cusparse.pyi +659 -0
- nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +198 -0
- nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +294 -0
- nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +684 -0
- nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1055 -0
- nvmath/bindings/cycublasMp.pxd +183 -0
- nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +224 -0
- nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +326 -0
- nvmath/bindings/cycufftMp.pxd +334 -0
- nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +154 -0
- nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +446 -0
- nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +470 -0
- nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +150 -0
- nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +192 -0
- nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1244 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
- nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +85 -0
- nvmath/bindings/nvpl/blas.pyi +122 -0
- nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +166 -0
- nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +92 -0
- nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +179 -0
- nvmath/device/__init__.py +21 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +313 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +310 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1805 -0
- nvmath/device/cublasdx_backend.py +807 -0
- nvmath/device/cublasdx_numba.py +1612 -0
- nvmath/device/cufftdx.py +510 -0
- nvmath/device/cufftdx_backend.py +196 -0
- nvmath/device/cufftdx_numba.py +196 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2690 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +1624 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +445 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +147 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +205 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +302 -0
- nvmath/distributed/_internal/tensor_ifc.py +67 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
- nvmath/distributed/_internal/tensor_wrapper.py +78 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution.py +770 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +79 -0
- nvmath/distributed/fft/fft.py +2801 -0
- nvmath/distributed/linalg/__init__.py +12 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +166 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1256 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +109 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +2903 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +12 -0
- nvmath/internal/_device_utils.py +54 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +10 -0
- nvmath/internal/memory.pyi +46 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +7 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
- nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
- nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/data_layout.pxd +72 -0
- nvmath/internal/ndbuffer/data_layout.pyi +23 -0
- nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/jit.pxd +7 -0
- nvmath/internal/ndbuffer/jit.pyi +6 -0
- nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
- nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
- nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/package_utils.pxd +11 -0
- nvmath/internal/ndbuffer/package_utils.pyi +12 -0
- nvmath/internal/package_ifc.py +147 -0
- nvmath/internal/package_ifc_cuda.py +49 -0
- nvmath/internal/package_ifc_cupy.py +49 -0
- nvmath/internal/package_ifc_torch.py +31 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +194 -0
- nvmath/internal/tensor_ifc_cupy.py +241 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
- nvmath/internal/tensor_ifc_numpy.py +183 -0
- nvmath/internal/tensor_ifc_torch.py +176 -0
- nvmath/internal/tensor_wrapper.py +157 -0
- nvmath/internal/typemaps.py +162 -0
- nvmath/internal/utils.py +771 -0
- nvmath/linalg/__init__.py +46 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +217 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +134 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +149 -0
- nvmath/linalg/advanced/_configuration.py +349 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1348 -0
- nvmath/linalg/advanced/matmulmod.py +3937 -0
- nvmath/linalg/generic/__init__.py +43 -0
- nvmath/linalg/generic/_configuration/__init__.py +37 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +609 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +1060 -0
- nvmath/memory.py +282 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +144 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +445 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +230 -0
- nvmath/sparse/advanced/direct_solver.py +1884 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2426 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +378 -0
- nvmath/sparse/ust/_drawer.py +552 -0
- nvmath/sparse/ust/_emitter.py +553 -0
- nvmath/sparse/ust/_jit.py +212 -0
- nvmath/sparse/ust/_kernel.py +346 -0
- nvmath/sparse/ust/_semiring.py +71 -0
- nvmath/sparse/ust/_utils.py +102 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/semiring_ops.py +71 -0
- nvmath/sparse/ust/tensor.py +1027 -0
- nvmath/sparse/ust/tensor_drawer.py +552 -0
- nvmath/sparse/ust/tensor_emitter.py +558 -0
- nvmath/sparse/ust/tensor_format.py +935 -0
- nvmath/sparse/ust/tensor_jit.py +212 -0
- nvmath/sparse/ust/tensor_kernel.py +348 -0
- nvmath/sparse/ust/tensor_utils.py +380 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +95 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
- nvmath/tensor/_internal/cutensor_utils.py +162 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1861 -0
- nvmath_python-0.9.0.dist-info/METADATA +127 -0
- nvmath_python-0.9.0.dist-info/RECORD +309 -0
- nvmath_python-0.9.0.dist-info/WHEEL +5 -0
- nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import abc
|
|
6
|
+
import contextlib
|
|
7
|
+
import dataclasses
|
|
8
|
+
import logging
|
|
9
|
+
from collections.abc import MutableSequence
|
|
10
|
+
from logging import Logger
|
|
11
|
+
from typing import ClassVar, Final, Generic, Literal, TypeVar
|
|
12
|
+
|
|
13
|
+
from nvmath import memory
|
|
14
|
+
from nvmath.internal import utils
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
18
|
+
class ExecutionCUDA:
|
|
19
|
+
"""
|
|
20
|
+
A data class for providing GPU execution options.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
device_id: CUDA device ordinal (only used if the operand resides on the CPU). The
|
|
24
|
+
default value is 0.
|
|
25
|
+
|
|
26
|
+
.. seealso::
|
|
27
|
+
:class:`ExecutionCPU`
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name: ClassVar[Literal["cuda"]] = "cuda"
|
|
31
|
+
device_id: int = 0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
35
|
+
class ExecutionCPU:
|
|
36
|
+
"""
|
|
37
|
+
A data class for providing CPU execution options.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
num_threads: The number of CPU threads used to execute the operation.
|
|
41
|
+
If not specified, defaults to the number of CPU cores available to the
|
|
42
|
+
process.
|
|
43
|
+
|
|
44
|
+
.. seealso::
|
|
45
|
+
:class:`ExecutionCUDA`
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
name: ClassVar[Literal["cpu"]] = "cpu"
|
|
49
|
+
num_threads: int | None = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def copy_operand_perhaps(
|
|
53
|
+
internal_operand: utils.TensorHolder | None,
|
|
54
|
+
operand: utils.TensorHolder,
|
|
55
|
+
stream_holder: utils.StreamHolder | None,
|
|
56
|
+
execution_device_id: int | Literal["cpu"],
|
|
57
|
+
operands_device_id: int | Literal["cpu"],
|
|
58
|
+
) -> tuple[utils.TensorHolder, utils.TensorHolder | None]:
|
|
59
|
+
"""Private implementation of memory space management for tensor operands.
|
|
60
|
+
|
|
61
|
+
The `copy_operand_perhaps` function facilitates transitions of tensor operands between
|
|
62
|
+
different memory spaces, ensuring compatibility with execution requirements. Its role is
|
|
63
|
+
to determine whether a tensor operand needs to be copied to accommodate differing
|
|
64
|
+
execution and operand memory spaces, while preserving the original operand for cases
|
|
65
|
+
requiring in-place operations.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
internal_operand: Represents an internal tensor for in-place
|
|
69
|
+
memory operations, or `None` if not applicable.
|
|
70
|
+
|
|
71
|
+
operand: Tensor to possibly copied to the execution memory space.
|
|
72
|
+
|
|
73
|
+
stream_holder: Manages the CUDA stream for device operations.
|
|
74
|
+
|
|
75
|
+
execution_device_id: Specifies the target execution space.
|
|
76
|
+
|
|
77
|
+
operands_device_id: Specifies the current operand memory space.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
A tuple containing:
|
|
81
|
+
- The operand copied to the execution space, or the original operand if
|
|
82
|
+
no copy is necessary.
|
|
83
|
+
- The original operand, or `None` if no copy occurred.
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
if execution_device_id == operands_device_id:
|
|
87
|
+
return operand, None
|
|
88
|
+
else:
|
|
89
|
+
# Copy the `operand` to memory that matches the exec space
|
|
90
|
+
# and keep the original `operand` to handle `options.inplace=True`
|
|
91
|
+
if internal_operand is None:
|
|
92
|
+
exec_space_copy = operand.to(execution_device_id, stream_holder)
|
|
93
|
+
return exec_space_copy, operand
|
|
94
|
+
else:
|
|
95
|
+
# In-place copy to existing pointer
|
|
96
|
+
internal_operand.copy_(src=operand, stream_holder=stream_holder)
|
|
97
|
+
return internal_operand, operand
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
101
|
+
class StatefulAPIOptions:
|
|
102
|
+
"""A dataclass for providing options to a :class:`StatefulAPI` object.
|
|
103
|
+
|
|
104
|
+
Attributes:
|
|
105
|
+
allocator: An object that supports the :class:`BaseCUDAMemoryManager` protocol, used
|
|
106
|
+
to draw device memory. If an allocator is not provided, a memory allocator from
|
|
107
|
+
the library package will be used (:func:`torch.cuda.caching_allocator_alloc` for
|
|
108
|
+
PyTorch operands, :func:`cupy.cuda.alloc` otherwise).
|
|
109
|
+
|
|
110
|
+
blocking: A flag specifying the behavior of the stream-ordered functions and
|
|
111
|
+
methods. When ``blocking`` is `True`, the stream-ordered methods do not return
|
|
112
|
+
until the operation is complete. When ``blocking`` is ``"auto"``, the methods
|
|
113
|
+
return immediately when the inputs are on the GPU. The stream-ordered methods
|
|
114
|
+
always block when the operands are on the CPU to ensure that the user doesn't
|
|
115
|
+
inadvertently use the result before it becomes available. The default is
|
|
116
|
+
``"auto"``.
|
|
117
|
+
|
|
118
|
+
logger: Python Logger object. The root logger will be used if a
|
|
119
|
+
logger object is not provided.
|
|
120
|
+
|
|
121
|
+
.. seealso::
|
|
122
|
+
:class:`StatefulAPI`
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
allocator: memory.BaseCUDAMemoryManager | memory.BaseCUDAMemoryManagerAsync | None = None
|
|
126
|
+
blocking: Literal[True, "auto"] = "auto"
|
|
127
|
+
logger: Logger = dataclasses.field(default_factory=logging.getLogger)
|
|
128
|
+
|
|
129
|
+
def __post_init__(self):
|
|
130
|
+
if self.blocking not in (True, "auto"):
|
|
131
|
+
raise ValueError("The value specified for blocking must be either True or 'auto'.")
|
|
132
|
+
|
|
133
|
+
if self.allocator is not None and not isinstance(
|
|
134
|
+
self.allocator, memory.BaseCUDAMemoryManager | memory.BaseCUDAMemoryManagerAsync
|
|
135
|
+
):
|
|
136
|
+
raise TypeError("The allocator must be an object of type that fulfills the BaseCUDAMemoryManager protocol.")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
OptionsPlaceholder = TypeVar("OptionsPlaceholder", bound=StatefulAPIOptions)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class StatefulAPI(contextlib.AbstractContextManager, Generic[OptionsPlaceholder]):
|
|
143
|
+
"""A base class for APIs which amortize setup costs across multiple executions.
|
|
144
|
+
|
|
145
|
+
StatefulAPIs separate planning (``plan()``) and setup (``__init__()``) actions from
|
|
146
|
+
execution (``_execute()``), so that plans may be reused with different operands. The
|
|
147
|
+
``reset_operands()`` method allows changing the operands of the API without replanning
|
|
148
|
+
when the input and execution space do not match (the user does not have a reference to
|
|
149
|
+
the execution space buffers). If the execution and input space match, we expect the
|
|
150
|
+
user to be able update the operands by overwriting their buffers in-place.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
# options is declared Final in __init__() because mypy issue #8982 is not fixed yet.
|
|
154
|
+
# options: Final[OptionsPlaceholder]
|
|
155
|
+
# See docstring for StatefulAPIOptions
|
|
156
|
+
_allocator: Final[memory.BaseCUDAMemoryManager | memory.BaseCUDAMemoryManagerAsync | None]
|
|
157
|
+
_blocking: Final[bool]
|
|
158
|
+
_logger: Final[logging.Logger]
|
|
159
|
+
|
|
160
|
+
# Metadata related to execution space
|
|
161
|
+
execution: Final[ExecutionCPU | ExecutionCUDA]
|
|
162
|
+
"""A class which describes the execution space parameters."""
|
|
163
|
+
_internal_op_package: Final[str]
|
|
164
|
+
"""The package of the operands in the execution space."""
|
|
165
|
+
_operands: MutableSequence[utils.TensorHolder]
|
|
166
|
+
"""A copy of the operands in execution space."""
|
|
167
|
+
_result_class: Final[type[utils.TensorHolder]]
|
|
168
|
+
"""The type of TensorHolder to use for the execution space result."""
|
|
169
|
+
|
|
170
|
+
# Metadata about the input/output tensors
|
|
171
|
+
_operands_backup: MutableSequence[utils.TensorHolder | None]
|
|
172
|
+
"""A reference to original operands in their input space."""
|
|
173
|
+
_operands_device_id: Final[int | Literal["cpu"]]
|
|
174
|
+
"""The device_id of the input space."""
|
|
175
|
+
_operands_package: Final[str]
|
|
176
|
+
"""The package of the operands in the input space."""
|
|
177
|
+
|
|
178
|
+
_call_prologue: Final[str]
|
|
179
|
+
"""Stores a message for logging about blocking behavior"""
|
|
180
|
+
|
|
181
|
+
_has_plan: bool
|
|
182
|
+
"""True if plan has been called."""
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def options(self) -> OptionsPlaceholder:
|
|
186
|
+
"""The options object used to construct this class."""
|
|
187
|
+
# This is a workaround for mypy issue #8982, where we cannot declare options as
|
|
188
|
+
# Final in the class definition, but we still want it to appear in the docs as an
|
|
189
|
+
# attribute.
|
|
190
|
+
return self._options
|
|
191
|
+
|
|
192
|
+
def __init__(
|
|
193
|
+
self,
|
|
194
|
+
operands: MutableSequence[utils.TensorHolder],
|
|
195
|
+
*,
|
|
196
|
+
options: OptionsPlaceholder,
|
|
197
|
+
execution: ExecutionCPU | ExecutionCUDA | None | Literal["cuda", "cpu"] = None,
|
|
198
|
+
stream: utils.AnyStream | int | None = None,
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Copy operands to the execution space and setup options.
|
|
201
|
+
|
|
202
|
+
When inheriting from this class, you must create valid operands and options in
|
|
203
|
+
the child class before calling StatefulAPI.__init__( ... ).
|
|
204
|
+
"""
|
|
205
|
+
self._options: Final[OptionsPlaceholder] = options
|
|
206
|
+
self._logger = self._options.logger
|
|
207
|
+
|
|
208
|
+
self._logger.info("= SPECIFICATION PHASE =")
|
|
209
|
+
|
|
210
|
+
operands_device_id = utils.get_operands_device_id(operands)
|
|
211
|
+
|
|
212
|
+
match execution, operands_device_id:
|
|
213
|
+
case (None | "cuda", int()):
|
|
214
|
+
execution = ExecutionCUDA(device_id=operands_device_id)
|
|
215
|
+
case ("cuda", "cpu"):
|
|
216
|
+
execution = ExecutionCUDA()
|
|
217
|
+
case (None, "cpu") | ("cpu", _):
|
|
218
|
+
execution = ExecutionCPU()
|
|
219
|
+
case (ExecutionCUDA(), int()):
|
|
220
|
+
# If operands are on a CUDA device, use the same device for execution.
|
|
221
|
+
execution = dataclasses.replace(execution, device_id=operands_device_id)
|
|
222
|
+
case (ExecutionCPU(), _) | (ExecutionCUDA(), "cpu"):
|
|
223
|
+
pass
|
|
224
|
+
case _:
|
|
225
|
+
raise ValueError(
|
|
226
|
+
f"{self.__class__.__name__}.execution must be one of ExecutionCUDA, ExecutionCPU, None, 'cuda', or 'cpu'."
|
|
227
|
+
)
|
|
228
|
+
assert isinstance(execution, (ExecutionCPU, ExecutionCUDA))
|
|
229
|
+
self.execution = execution
|
|
230
|
+
|
|
231
|
+
self._operands_device_id = operands_device_id
|
|
232
|
+
self._operands_package = utils.get_operands_package(operands)
|
|
233
|
+
self._internal_op_package = self._internal_operand_package(self._operands_package)
|
|
234
|
+
exec_stream_holder, operand_stream_holder = self._get_or_create_stream_maybe(stream)
|
|
235
|
+
|
|
236
|
+
self._logger.info(
|
|
237
|
+
f"The input tensors are located on device {operands_device_id}, and the execution space "
|
|
238
|
+
f"is {self.execution.name}, with device {getattr(self.execution, 'device_id', 'cpu')}."
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
self._logger.info(
|
|
242
|
+
f"The specified stream for the {self.__class__.__name__} constructor is "
|
|
243
|
+
f"{(exec_stream_holder or operand_stream_holder) and getattr(exec_stream_holder or operand_stream_holder, 'obj', None)}." # noqa: E501
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
operands_backup: list[utils.TensorHolder | None] = [None] * len(operands)
|
|
247
|
+
for i in range(len(operands)):
|
|
248
|
+
# Copy the operand to execution_space's device if needed.
|
|
249
|
+
operands[i], operands_backup[i] = copy_operand_perhaps(
|
|
250
|
+
None,
|
|
251
|
+
operands[i],
|
|
252
|
+
operand_stream_holder,
|
|
253
|
+
getattr(self.execution, "device_id", "cpu"),
|
|
254
|
+
self._operands_device_id,
|
|
255
|
+
)
|
|
256
|
+
self._operands = operands
|
|
257
|
+
self._operands_backup = operands_backup
|
|
258
|
+
|
|
259
|
+
# The result's package and device.
|
|
260
|
+
self._result_class = self._operands[0].__class__
|
|
261
|
+
|
|
262
|
+
# Set blocking or non-blocking behavior.
|
|
263
|
+
self._blocking = self._options.blocking != "auto" or self._operands_device_id == "cpu" or self.execution.name == "cpu"
|
|
264
|
+
if self._blocking:
|
|
265
|
+
call_prologue = "This call is blocking and will return only after the operation is complete."
|
|
266
|
+
else:
|
|
267
|
+
call_prologue = (
|
|
268
|
+
"This call is non-blocking and will return immediately after the operation is launched on the device."
|
|
269
|
+
)
|
|
270
|
+
self._call_prologue = call_prologue
|
|
271
|
+
|
|
272
|
+
# Set memory allocator.
|
|
273
|
+
allocator: memory.BaseCUDAMemoryManager | memory.BaseCUDAMemoryManagerAsync | None
|
|
274
|
+
match self.execution:
|
|
275
|
+
case ExecutionCUDA():
|
|
276
|
+
allocator = (
|
|
277
|
+
memory._MEMORY_MANAGER[self._internal_op_package](self.execution.device_id, self._logger)
|
|
278
|
+
if self._options.allocator is None
|
|
279
|
+
else self._options.allocator
|
|
280
|
+
)
|
|
281
|
+
case ExecutionCPU() | _:
|
|
282
|
+
allocator = None # currently, the nvpl/fftw does not support custom workspace allocation
|
|
283
|
+
self._allocator = allocator
|
|
284
|
+
|
|
285
|
+
self._has_plan = False
|
|
286
|
+
|
|
287
|
+
def _internal_operand_package(self, package_name: str) -> str:
|
|
288
|
+
if self.execution.name == "cuda":
|
|
289
|
+
return package_name if package_name != "numpy" else "cuda"
|
|
290
|
+
else:
|
|
291
|
+
return package_name if package_name != "cupy" else "cupy_host"
|
|
292
|
+
|
|
293
|
+
def _get_or_create_stream_maybe(
|
|
294
|
+
self, stream: utils.AnyStream
|
|
295
|
+
) -> tuple[utils.StreamHolder | None, utils.StreamHolder | None]:
|
|
296
|
+
"""Return a 2-tuple of Stream | None: one for execution space, one for input space.
|
|
297
|
+
|
|
298
|
+
The first stream should be used for everything in the execution space: doing work,
|
|
299
|
+
allocating workspace, allocating input/output buffers.
|
|
300
|
+
|
|
301
|
+
The second stream should be used whenever data is being moved between the input and
|
|
302
|
+
output spaces: copying data to/from the input/output tensors.
|
|
303
|
+
|
|
304
|
+
NOTE: If two streams are returned, they will be the same stream.
|
|
305
|
+
"""
|
|
306
|
+
if self.execution.name == "cuda":
|
|
307
|
+
stream_holder = utils.get_or_create_stream(self.execution.device_id, stream, self._internal_op_package)
|
|
308
|
+
return stream_holder, stream_holder
|
|
309
|
+
elif isinstance(self._operands_device_id, int):
|
|
310
|
+
operand_device_steam = utils.get_or_create_stream(self._operands_device_id, stream, self._operands_package)
|
|
311
|
+
return None, operand_device_steam
|
|
312
|
+
else:
|
|
313
|
+
return None, None
|
|
314
|
+
|
|
315
|
+
# input checks
|
|
316
|
+
|
|
317
|
+
def _check_valid_operands(self, *args, **kwargs):
|
|
318
|
+
"""
|
|
319
|
+
Check if the operands are available for the operation.
|
|
320
|
+
"""
|
|
321
|
+
what = kwargs["what"]
|
|
322
|
+
if self._operands is None:
|
|
323
|
+
raise RuntimeError(
|
|
324
|
+
f"{what} cannot be performed if the operands have been set to None. Use reset_operands() to set the "
|
|
325
|
+
f"desired input before using performing the {what.lower()}."
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
def _check_planned(self, *args, **kwargs):
|
|
329
|
+
what = kwargs["what"]
|
|
330
|
+
if not self._has_plan:
|
|
331
|
+
raise RuntimeError(f"{what} cannot be performed before plan() has been called.")
|
|
332
|
+
|
|
333
|
+
# execution
|
|
334
|
+
|
|
335
|
+
@abc.abstractmethod
|
|
336
|
+
def _execute(self):
|
|
337
|
+
"""Perform the main functionality of this :class:`StatefulAPI` instance without
|
|
338
|
+
safety checks."""
|
|
339
|
+
msg = f"{self.__name__}._execute() is not implemented."
|
|
340
|
+
raise NotImplementedError(msg)
|
|
341
|
+
|
|
342
|
+
@abc.abstractmethod
|
|
343
|
+
def plan(self):
|
|
344
|
+
"""Plan the main functionality of this :class:`StatefulAPI` instance."""
|
|
345
|
+
msg = f"{self.__class__.__name__}.plan() is not implemented."
|
|
346
|
+
raise NotImplementedError(msg)
|
|
347
|
+
|
|
348
|
+
@abc.abstractmethod
|
|
349
|
+
def reset_operands(self):
|
|
350
|
+
"""Reset the operands held by this :class:`StatefulAPI` instance."""
|
|
351
|
+
msg = f"{self.__class__.__name__}.reset_operands() is not implemented."
|
|
352
|
+
raise NotImplementedError(msg)
|
|
353
|
+
|
|
354
|
+
def free(self):
|
|
355
|
+
"""Free resources held by this :class:`StatefulAPI` instance.
|
|
356
|
+
|
|
357
|
+
This method releases references to operands to ensure proper reference counting.
|
|
358
|
+
Subclasses should call super().free() if they override this method to add
|
|
359
|
+
additional cleanup logic.
|
|
360
|
+
"""
|
|
361
|
+
# Release references to operands to ensure proper reference counting
|
|
362
|
+
self._operands = []
|
|
363
|
+
self._operands_backup = []
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class HasWorkspaceMemory(contextlib.AbstractContextManager):
|
|
367
|
+
"""A base class for APIs which need to allocate a working buffer in memory."""
|
|
368
|
+
|
|
369
|
+
def _allocate_workspace_memory_perhaps(self, stream_holder: utils.StreamHolder):
|
|
370
|
+
"""
|
|
371
|
+
Allocate workspace memory using the specified allocator, if it hasn't already been
|
|
372
|
+
done.
|
|
373
|
+
"""
|
|
374
|
+
raise NotImplementedError
|
|
375
|
+
|
|
376
|
+
def _release_workspace_memory_perhaps(self, release_workspace: bool):
|
|
377
|
+
raise NotImplementedError
|
|
378
|
+
|
|
379
|
+
@abc.abstractmethod
|
|
380
|
+
def free(self):
|
|
381
|
+
"""Free the resources of this :class:`StatefulAPI` instance."""
|
|
382
|
+
msg = f"{self.__name__}.free() is not implemented."
|
|
383
|
+
raise NotImplementedError(msg)
|
nvmath/_utils.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
from enum import IntEnum
|
|
9
|
+
from functools import cache
|
|
10
|
+
|
|
11
|
+
from cuda import pathfinder
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger()
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Note: This module should not depend on anything from the nvmath namespace!
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# The (subset of) compute types below are shared by cuStateVec and cuTensorNet
|
|
21
|
+
class ComputeType(IntEnum):
|
|
22
|
+
"""An enumeration of CUDA compute types."""
|
|
23
|
+
|
|
24
|
+
COMPUTE_DEFAULT = 0
|
|
25
|
+
COMPUTE_16F = 1 << 0
|
|
26
|
+
COMPUTE_32F = 1 << 2
|
|
27
|
+
COMPUTE_64F = 1 << 4
|
|
28
|
+
COMPUTE_8U = 1 << 6
|
|
29
|
+
COMPUTE_8I = 1 << 8
|
|
30
|
+
COMPUTE_32U = 1 << 7
|
|
31
|
+
COMPUTE_32I = 1 << 9
|
|
32
|
+
COMPUTE_16BF = 1 << 10
|
|
33
|
+
COMPUTE_TF32 = 1 << 12
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# TODO: use those exposed by CUDA Python instead, but before removing these
|
|
37
|
+
# duplicates, check if they are fixed to inherit IntEnum instead of Enum.
|
|
38
|
+
class CudaDataType(IntEnum):
|
|
39
|
+
"""An enumeration of `cudaDataType_t`."""
|
|
40
|
+
|
|
41
|
+
CUDA_R_16F = 2
|
|
42
|
+
CUDA_C_16F = 6
|
|
43
|
+
CUDA_R_16BF = 14
|
|
44
|
+
CUDA_C_16BF = 15
|
|
45
|
+
CUDA_R_32F = 0
|
|
46
|
+
CUDA_C_32F = 4
|
|
47
|
+
CUDA_R_64F = 1
|
|
48
|
+
CUDA_C_64F = 5
|
|
49
|
+
CUDA_R_4I = 16
|
|
50
|
+
CUDA_C_4I = 17
|
|
51
|
+
CUDA_R_4U = 18
|
|
52
|
+
CUDA_C_4U = 19
|
|
53
|
+
CUDA_R_8I = 3
|
|
54
|
+
CUDA_C_8I = 7
|
|
55
|
+
CUDA_R_8U = 8
|
|
56
|
+
CUDA_C_8U = 9
|
|
57
|
+
CUDA_R_16I = 20
|
|
58
|
+
CUDA_C_16I = 21
|
|
59
|
+
CUDA_R_16U = 22
|
|
60
|
+
CUDA_C_16U = 23
|
|
61
|
+
CUDA_R_32I = 10
|
|
62
|
+
CUDA_C_32I = 11
|
|
63
|
+
CUDA_R_32U = 12
|
|
64
|
+
CUDA_C_32U = 13
|
|
65
|
+
CUDA_R_64I = 24
|
|
66
|
+
CUDA_C_64I = 25
|
|
67
|
+
CUDA_R_64U = 26
|
|
68
|
+
CUDA_C_64U = 27
|
|
69
|
+
CUDA_R_8F_E4M3 = 28
|
|
70
|
+
CUDA_R_8F_E5M2 = 29
|
|
71
|
+
CUDA_R_4F_E2M1 = 33 # FP4 (supported on SM >= 10.0)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class LibraryPropertyType(IntEnum):
|
|
75
|
+
"""An enumeration of library version information."""
|
|
76
|
+
|
|
77
|
+
MAJOR_VERSION = 0
|
|
78
|
+
MINOR_VERSION = 1
|
|
79
|
+
PATCH_LEVEL = 2
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
del IntEnum
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
PLATFORM_LINUX = sys.platform.startswith("linux")
|
|
86
|
+
PLATFORM_WIN = sys.platform.startswith("win32")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def module_init_force_cupy_lib_load():
|
|
90
|
+
"""
|
|
91
|
+
Attempt to preload libraries at module import time. We want to do it before
|
|
92
|
+
cupy, since it does not know how to properly search for libraries:
|
|
93
|
+
https://github.com/cupy/cupy/issues/9127
|
|
94
|
+
Fail silently if preload fails.
|
|
95
|
+
"""
|
|
96
|
+
from nvmath.bindings import _internal
|
|
97
|
+
|
|
98
|
+
libs = ("cublas", "cufft", "curand", "cusolverDn", "cusparse", "cutensor")
|
|
99
|
+
for lib in libs:
|
|
100
|
+
try:
|
|
101
|
+
mod = getattr(_internal, lib)
|
|
102
|
+
mod._inspect_function_pointers()
|
|
103
|
+
except (_internal.utils.NotSupportedError, RuntimeError):
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
pathfinder.load_nvidia_dynamic_lib("nvrtc")
|
|
108
|
+
except pathfinder.DynamicLibNotFoundError:
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@cache
|
|
113
|
+
def get_nvrtc_build_id(minimal=True) -> int:
|
|
114
|
+
try:
|
|
115
|
+
from cuda.core import ObjectCode, Program, ProgramOptions
|
|
116
|
+
except ImportError:
|
|
117
|
+
from cuda.core.experimental import ObjectCode, Program, ProgramOptions
|
|
118
|
+
|
|
119
|
+
code = r"""
|
|
120
|
+
extern "C" __global__ void get_build_id(int* build_id) {
|
|
121
|
+
|
|
122
|
+
*build_id = __CUDACC_VER_BUILD__;
|
|
123
|
+
}
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
prog = Program(code, "c++", ProgramOptions(std="c++17", minimal=minimal, arch="compute_75"))
|
|
127
|
+
obj = prog.compile("ptx")
|
|
128
|
+
assert isinstance(obj, ObjectCode)
|
|
129
|
+
|
|
130
|
+
pattern = re.compile(r"mov\.u32\s+%\w+,\s+(\d+)")
|
|
131
|
+
m = pattern.search(obj.code.decode())
|
|
132
|
+
assert m is not None
|
|
133
|
+
|
|
134
|
+
return int(m.group(1))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@cache
|
|
138
|
+
def get_nvrtc_version() -> tuple[int, int, int]:
|
|
139
|
+
"""
|
|
140
|
+
Returns the NVRTC version as a tuple of (major, minor, build).
|
|
141
|
+
"""
|
|
142
|
+
from cuda.bindings import nvrtc
|
|
143
|
+
|
|
144
|
+
err, major, minor = nvrtc.nvrtcVersion()
|
|
145
|
+
if err != nvrtc.nvrtcResult.NVRTC_SUCCESS:
|
|
146
|
+
raise RuntimeError(f"nvrtcVersion error: {err}")
|
|
147
|
+
# minimal support was added in CUDA 12.4
|
|
148
|
+
# https://docs.nvidia.com/cuda/archive/12.4.0/cuda-toolkit-release-notes/index.html#cuda-compilers
|
|
149
|
+
build = get_nvrtc_build_id(minimal=major >= 12 and minor >= 4)
|
|
150
|
+
return major, minor, build
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# type: ignore
|
|
6
|
+
|
|
7
|
+
from nvmath.bindings import cublas
|
|
8
|
+
from nvmath.bindings import cublasLt
|
|
9
|
+
from nvmath.bindings import cudss
|
|
10
|
+
from nvmath.bindings import cufft
|
|
11
|
+
from nvmath.bindings import curand
|
|
12
|
+
from nvmath.bindings import cusolver
|
|
13
|
+
from nvmath.bindings import cusolverDn
|
|
14
|
+
from nvmath.bindings import cusparse
|
|
15
|
+
from nvmath.bindings import cusparseLt
|
|
16
|
+
from nvmath.bindings import cutensor
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
# cufftMp is Linux-only.
|
|
20
|
+
from nvmath.bindings import cufftMp
|
|
21
|
+
except ImportError:
|
|
22
|
+
cufftMp = None
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
# nvshmem is Linux-only.
|
|
26
|
+
from nvmath.bindings import nvshmem
|
|
27
|
+
except ImportError:
|
|
28
|
+
nvshmem = None
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
# cublasMp is Linux-only.
|
|
32
|
+
from nvmath.bindings import cublasMp
|
|
33
|
+
except ImportError:
|
|
34
|
+
cublasMp = None
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"cublas",
|
|
38
|
+
"cublasLt",
|
|
39
|
+
"cublasMp",
|
|
40
|
+
"cudss",
|
|
41
|
+
"cufft",
|
|
42
|
+
"cufftMp",
|
|
43
|
+
"curand",
|
|
44
|
+
"cusolver",
|
|
45
|
+
"cusolverDn",
|
|
46
|
+
"cusparse",
|
|
47
|
+
"cusparseLt",
|
|
48
|
+
"cutensor",
|
|
49
|
+
"nvpl",
|
|
50
|
+
"nvshmem",
|
|
51
|
+
]
|
|
File without changes
|
|
File without changes
|
|
Binary file
|