nvmath-python 1.0.0__cp314-cp314t-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 +130 -0
- nvmath/_internal/threadsafe.py +106 -0
- nvmath/_internal/utils.py +43 -0
- nvmath/_internal/workspace.py +490 -0
- nvmath/_utils.py +147 -0
- nvmath/bindings/__init__.py +60 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/common_types.pxd +31 -0
- nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +54 -0
- nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusolverMp.pxd +71 -0
- nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverSp.pxd +75 -0
- nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +471 -0
- nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +174 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +812 -0
- nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1461 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +267 -0
- nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +98 -0
- nvmath/bindings/cudss.pyi +443 -0
- nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +301 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +326 -0
- nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +189 -0
- nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +320 -0
- nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +422 -0
- nvmath/bindings/cusolverMp.pxd +98 -0
- nvmath/bindings/cusolverMp.pyi +114 -0
- nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverSp.pxd +95 -0
- nvmath/bindings/cusolverSp.pyi +70 -0
- nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +546 -0
- nvmath/bindings/cusparse.pyi +1017 -0
- nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +252 -0
- nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +324 -0
- nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +664 -0
- nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1045 -0
- nvmath/bindings/cycublasMp.pxd +171 -0
- nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +277 -0
- nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +333 -0
- nvmath/bindings/cycufftMp.pxd +342 -0
- nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +141 -0
- nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +137 -0
- nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +443 -0
- nvmath/bindings/cycusolverMp.pxd +107 -0
- nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverSp.pxd +93 -0
- nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +679 -0
- nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +135 -0
- nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +189 -0
- nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +118 -0
- nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1562 -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.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
- nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +131 -0
- nvmath/bindings/nvpl/blas.pyi +168 -0
- nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +280 -0
- nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +93 -0
- nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +168 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +191 -0
- nvmath/device/__init__.py +38 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +315 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +300 -0
- nvmath/device/common_numba_cuda_mlir.py +202 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1606 -0
- nvmath/device/cublasdx_backend.py +860 -0
- nvmath/device/cublasdx_numba.py +1534 -0
- nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
- nvmath/device/cufftdx.py +373 -0
- nvmath/device/cufftdx_backend.py +220 -0
- nvmath/device/cufftdx_numba.py +140 -0
- nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2708 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +567 -0
- nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
- nvmath/device/cusolverdx_overload_backend.py +1029 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +441 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +138 -0
- nvmath/device/vector_types_numba.py +259 -0
- nvmath/distributed/__init__.py +200 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nccl.py +86 -0
- nvmath/distributed/_internal/nvshmem.py +307 -0
- nvmath/distributed/_internal/symmetric_memory.py +35 -0
- nvmath/distributed/_internal/tensor_ifc.py +70 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
- nvmath/distributed/_internal/tensor_wrapper.py +81 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution/__init__.py +30 -0
- nvmath/distributed/distribution/_configuration.py +39 -0
- nvmath/distributed/distribution/distributions.py +1024 -0
- nvmath/distributed/distribution/redistribute.py +1284 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +82 -0
- nvmath/distributed/fft/fft.py +2742 -0
- nvmath/distributed/linalg/__init__.py +22 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -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 +171 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
- nvmath/distributed/linalg/generic/__init__.py +8 -0
- nvmath/distributed/linalg/generic/_caching.py +66 -0
- nvmath/distributed/linalg/generic/_configuration.py +61 -0
- nvmath/distributed/linalg/generic/_factorization.py +172 -0
- nvmath/distributed/linalg/generic/_initialization.py +966 -0
- nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
- nvmath/distributed/linalg/generic/solvermod.py +1368 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +189 -0
- nvmath/fft/_exec_utils.py +82 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +3122 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +18 -0
- nvmath/internal/_device_utils.py +45 -0
- nvmath/internal/_layout/__init__.pxd +3 -0
- nvmath/internal/_layout/__init__.py +7 -0
- nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_layout/_layout.pxd +1303 -0
- nvmath/internal/_layout/_layout.pyi +1145 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +13 -0
- nvmath/internal/memory.pyi +50 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +9 -0
- nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
- nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_jit.pxd +7 -0
- nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
- nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -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 +242 -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/package_ifc.py +168 -0
- nvmath/internal/package_ifc_cuda.py +57 -0
- nvmath/internal/package_ifc_cupy.py +67 -0
- nvmath/internal/package_ifc_torch.py +69 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +179 -0
- nvmath/internal/tensor_ifc_cupy.py +234 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
- nvmath/internal/tensor_ifc_numpy.py +184 -0
- nvmath/internal/tensor_ifc_torch.py +178 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +113 -0
- nvmath/internal/utils.py +805 -0
- nvmath/linalg/__init__.py +56 -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 +234 -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/solver_utils.py +432 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +157 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +170 -0
- nvmath/linalg/advanced/_configuration.py +351 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1316 -0
- nvmath/linalg/advanced/matmulmod.py +3734 -0
- nvmath/linalg/generic/__init__.py +53 -0
- nvmath/linalg/generic/_configuration/__init__.py +39 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +734 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
- nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +2094 -0
- nvmath/linalg/generic/solvermod.py +1301 -0
- nvmath/memory.py +279 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +147 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +506 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +227 -0
- nvmath/sparse/advanced/direct_solver.py +2069 -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 +2353 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +422 -0
- nvmath/sparse/ust/_cpp.py +28 -0
- nvmath/sparse/ust/_drawer.py +565 -0
- nvmath/sparse/ust/_emitter.py +1033 -0
- nvmath/sparse/ust/_jit.py +188 -0
- nvmath/sparse/ust/_kernel.py +282 -0
- nvmath/sparse/ust/_utils.py +149 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/tensor.py +1016 -0
- nvmath/sparse/ust/tensor_format.py +957 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +120 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
- nvmath/tensor/_internal/cutensor_utils.py +230 -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 +1900 -0
- nvmath_python-1.0.0.dist-info/METADATA +134 -0
- nvmath_python-1.0.0.dist-info/RECORD +332 -0
- nvmath_python-1.0.0.dist-info/WHEEL +5 -0
- nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,1606 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"TransposeMode",
|
|
7
|
+
"Matmul",
|
|
8
|
+
"SharedStorageCalc",
|
|
9
|
+
"Accumulator",
|
|
10
|
+
"DevicePipeline",
|
|
11
|
+
"TilePipeline",
|
|
12
|
+
"compile_blas_execute",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
import itertools
|
|
16
|
+
import re
|
|
17
|
+
import weakref
|
|
18
|
+
from abc import abstractmethod
|
|
19
|
+
from collections.abc import Sequence
|
|
20
|
+
from functools import cached_property
|
|
21
|
+
from typing import Any, overload
|
|
22
|
+
from warnings import warn
|
|
23
|
+
|
|
24
|
+
import numpy
|
|
25
|
+
from cuda.core import (
|
|
26
|
+
Buffer,
|
|
27
|
+
Device,
|
|
28
|
+
LaunchConfig,
|
|
29
|
+
launch,
|
|
30
|
+
)
|
|
31
|
+
from cuda.core.utils import StridedMemoryView
|
|
32
|
+
|
|
33
|
+
from nvmath._utils import get_nvrtc_version
|
|
34
|
+
from nvmath.bindings import mathdx
|
|
35
|
+
from nvmath.device.common_opaque_tensor import _LIBMATHDX_RUNTIME, OpaqueLayout
|
|
36
|
+
from nvmath.internal.utils import docstring_decorator
|
|
37
|
+
|
|
38
|
+
from ._deprecated import deprecated
|
|
39
|
+
from .common import (
|
|
40
|
+
SHARED_DEVICE_DOCSTRINGS,
|
|
41
|
+
Layout,
|
|
42
|
+
OpaqueTensor,
|
|
43
|
+
check_code_type,
|
|
44
|
+
check_in,
|
|
45
|
+
pad_or_truncate,
|
|
46
|
+
parse_code_type,
|
|
47
|
+
parse_sm,
|
|
48
|
+
)
|
|
49
|
+
from .common_backend import MATHDX_TYPES_TO_NP, NP_TYPES_TO_MATHDX_TYPES, DescriptorWrapper, get_isa_version, get_lto
|
|
50
|
+
from .common_cuda import (
|
|
51
|
+
Code,
|
|
52
|
+
CodeType,
|
|
53
|
+
ComputeCapability,
|
|
54
|
+
Dim3,
|
|
55
|
+
get_current_device_cc,
|
|
56
|
+
get_default_code_type,
|
|
57
|
+
)
|
|
58
|
+
from .cublasdx_backend import (
|
|
59
|
+
MAX_ALIGNMENT, # noqa: F401
|
|
60
|
+
Alignment,
|
|
61
|
+
Arrangement,
|
|
62
|
+
LeadingDimension,
|
|
63
|
+
Precision,
|
|
64
|
+
TransposeMode,
|
|
65
|
+
_compile_blas_device_pipeline_destroy_kernel,
|
|
66
|
+
_compile_blas_device_pipeline_init_kernel,
|
|
67
|
+
generate_code,
|
|
68
|
+
generate_device_pipeline,
|
|
69
|
+
generate_function_code,
|
|
70
|
+
generate_function_with_pipelines_code,
|
|
71
|
+
generate_MM,
|
|
72
|
+
generate_tensor,
|
|
73
|
+
generate_tensor_like,
|
|
74
|
+
generate_tensors,
|
|
75
|
+
generate_tile_pipeline,
|
|
76
|
+
get_function_code,
|
|
77
|
+
get_int_traits,
|
|
78
|
+
get_str_trait,
|
|
79
|
+
get_tensor_traits,
|
|
80
|
+
validate,
|
|
81
|
+
validate_execute_api,
|
|
82
|
+
validate_tensor_types,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
CUBLASDX_DOCSTRING = SHARED_DEVICE_DOCSTRINGS.copy()
|
|
86
|
+
CUBLASDX_DOCSTRING.update(
|
|
87
|
+
{
|
|
88
|
+
"size": """\
|
|
89
|
+
A sequence of integers denoting the three dimensions ``(m, n, k)`` for the matrix multiplication
|
|
90
|
+
problem.""".replace("\n", " "),
|
|
91
|
+
#
|
|
92
|
+
"precision": """\
|
|
93
|
+
The computation precision, either a single numpy dtype or a 3-sequence of numpy dtypes ``(a, b, c)``
|
|
94
|
+
for the A, B, and C matrices. Supported dtypes are ``numpy.float16``, ``numpy.float32``, ``numpy.float64``
|
|
95
|
+
and the signed and unsigned integer dtypes of 8, 16, 32 or 64 bits.""".replace("\n", " "),
|
|
96
|
+
#
|
|
97
|
+
"data_type": """\
|
|
98
|
+
The data type of the input matrices, can be either ``'real'`` or ``'complex'``.""".replace("\n", " "),
|
|
99
|
+
#
|
|
100
|
+
"block_size": """\
|
|
101
|
+
The total block size, optional. If not provided or set to ``'suggested'``, will be set to a suggested value for 1D block
|
|
102
|
+
dim. """.replace("\n", " "),
|
|
103
|
+
#
|
|
104
|
+
"block_dim": """\
|
|
105
|
+
The block dimension for launching the CUDA kernel, optional. If not provided or set to ``'suggested'``, will be set to a
|
|
106
|
+
suggested value. Cannot be used when `block_size` is explicitly specified.""".replace("\n", " "),
|
|
107
|
+
#
|
|
108
|
+
"leading_dimension": """\
|
|
109
|
+
The leading dimensions for the input matrices, optional. If not provided, will be set to match the matrix row/column
|
|
110
|
+
dimension. Alternatively, if provided as ``'suggested'``, will be set to a suggested value for optimal performance.
|
|
111
|
+
""".replace("\n", " "),
|
|
112
|
+
#
|
|
113
|
+
"transpose_mode": """\
|
|
114
|
+
The transpose mode for all input matrices ;
|
|
115
|
+
transpose_mode or arrangement must be provided.""".replace("\n", " "),
|
|
116
|
+
#
|
|
117
|
+
"arrangement": """\
|
|
118
|
+
The arrangement for all input matrices ;
|
|
119
|
+
transpose_mode or arrangement must be provided.""".replace("\n", " "),
|
|
120
|
+
#
|
|
121
|
+
"alignment": """\
|
|
122
|
+
The alignment for the input matrices in shared memory.
|
|
123
|
+
Defines the alignments (in bytes) of the input matrices A, B, and C
|
|
124
|
+
(either arrays or wrapped in opaque tensors) that are passed to the
|
|
125
|
+
execute(...) method. The default alignment is equal to the element size of the
|
|
126
|
+
matrix. When a suggested layout is used, the alignment is greater than or equal
|
|
127
|
+
to the element size.""".replace("\n", " "),
|
|
128
|
+
#
|
|
129
|
+
"function": """\
|
|
130
|
+
A string specifying the name of the function. Currently supports ``'MM'`` (default) for matrix
|
|
131
|
+
multiplication.""".replace("\n", " "),
|
|
132
|
+
#
|
|
133
|
+
"static_block_dim": """\
|
|
134
|
+
If set to ``True``, cuBLASDx assumes the kernel is launched with a block dimension exactly equal to
|
|
135
|
+
``block_dim``, which enables additional optimizations. The default is ``False``.""".replace("\n", " "),
|
|
136
|
+
#
|
|
137
|
+
"with_pipeline": """\
|
|
138
|
+
If set to ``True``, the device function is generated for pipelined execution and must be used only
|
|
139
|
+
through :py:class:`nvmath.device.DevicePipeline` or :py:class:`nvmath.device.TilePipeline`
|
|
140
|
+
(see :py:meth:`nvmath.device.Matmul.suggest_device_pipeline`). Executing such a matmul with the
|
|
141
|
+
regular ``execute(...)`` interface is incorrect. The default is ``False``.""".replace("\n", " "),
|
|
142
|
+
#
|
|
143
|
+
"enable_input_streaming": """\
|
|
144
|
+
If set to ``True``, informs the library that no per-element load transforms are applied to the
|
|
145
|
+
inputs, which allows input data to be streamed from shared memory directly to the MMA units
|
|
146
|
+
without passing through registers. This may improve performance. The default is
|
|
147
|
+
``False``.""".replace("\n", " "),
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
#
|
|
152
|
+
# A set of knobs, potentially in-complete (ie not sufficient to generate a device functions)
|
|
153
|
+
#
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class SharedStorageCalc:
|
|
157
|
+
"""
|
|
158
|
+
Helper class to calculate shared storage size.
|
|
159
|
+
|
|
160
|
+
For further details, please refer to :cublasdx_doc:`cuBLASDx documentation
|
|
161
|
+
<index.html>`.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
_memory: int = 0
|
|
165
|
+
|
|
166
|
+
@overload
|
|
167
|
+
def add(self, alignment: int, matrix_size_bytes: int) -> None: ...
|
|
168
|
+
@overload
|
|
169
|
+
def add(self, alignment: int, elem_size: int, num_elements: int) -> None: ...
|
|
170
|
+
@overload
|
|
171
|
+
def add(self, alignment: int, elem_size: int, layout: Layout) -> None: ...
|
|
172
|
+
def add(self, *args):
|
|
173
|
+
assert len(args) in {2, 3}
|
|
174
|
+
|
|
175
|
+
if len(args) == 2:
|
|
176
|
+
[alignment, matrix_size_bytes] = args
|
|
177
|
+
|
|
178
|
+
assert matrix_size_bytes > 0
|
|
179
|
+
else:
|
|
180
|
+
[alignment, elem_size, num_elements] = args
|
|
181
|
+
|
|
182
|
+
if isinstance(num_elements, Layout):
|
|
183
|
+
num_elements = num_elements.cosize
|
|
184
|
+
|
|
185
|
+
assert elem_size > 0
|
|
186
|
+
assert num_elements > 0
|
|
187
|
+
|
|
188
|
+
matrix_size_bytes = elem_size * num_elements
|
|
189
|
+
|
|
190
|
+
assert alignment > 0
|
|
191
|
+
|
|
192
|
+
self._memory = ((self._memory + alignment - 1) // alignment) * alignment + matrix_size_bytes
|
|
193
|
+
|
|
194
|
+
def get(self):
|
|
195
|
+
return self._memory
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class Partitioner:
|
|
199
|
+
"""
|
|
200
|
+
Partitioner is an abstraction for partitioning a global memory tensor into a
|
|
201
|
+
partitioned tensor.
|
|
202
|
+
|
|
203
|
+
.. note:: Do not create directly, use ``suggest_accumulator()`` or
|
|
204
|
+
``get_accumulator()`` on a :py:class:`nvmath.device.Matmul` object
|
|
205
|
+
inside a kernel.
|
|
206
|
+
|
|
207
|
+
Refer to the cuBLASDx documentation for more details on how to use this class:
|
|
208
|
+
:cublasdx_doc:`api/other_tensors.html#partitioner-register-tensor-other-label`
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
def __init__(self, *args):
|
|
212
|
+
raise RuntimeError("Partitioner should not be called directly")
|
|
213
|
+
|
|
214
|
+
def partition_like_C(self, gmem_c: OpaqueTensor) -> OpaqueTensor:
|
|
215
|
+
"""
|
|
216
|
+
Partitions the given global memory tensor `gmem_c` into a partitioned tensor.
|
|
217
|
+
The partitioned tensor is used for accessing the C matrix when working
|
|
218
|
+
with register fragment.
|
|
219
|
+
|
|
220
|
+
.. note:: Not yet implemented, use :py:meth:`map_fragment_index` instead.
|
|
221
|
+
"""
|
|
222
|
+
raise RuntimeError("partition_like_C is a device function")
|
|
223
|
+
|
|
224
|
+
def map_fragment_index(self, fragment_index: int) -> tuple[int, int]:
|
|
225
|
+
"""
|
|
226
|
+
Maps the given fragment index to the (row, column) coordinate of the
|
|
227
|
+
corresponding C matrix element.
|
|
228
|
+
This is used to access the correct element in the partitioned tensor.
|
|
229
|
+
"""
|
|
230
|
+
raise RuntimeError("map_fragment_index is a device function")
|
|
231
|
+
|
|
232
|
+
def is_thread_active(self) -> bool:
|
|
233
|
+
"""
|
|
234
|
+
Checks if the current thread takes part in GEMM.
|
|
235
|
+
"""
|
|
236
|
+
raise RuntimeError("is_thread_active is a device function")
|
|
237
|
+
|
|
238
|
+
def is_predicated(self) -> bool:
|
|
239
|
+
"""
|
|
240
|
+
Checks if the current thread is predicated.
|
|
241
|
+
This is used to determine if the thread should execute the kernel.
|
|
242
|
+
"""
|
|
243
|
+
raise RuntimeError("is_predicated is a device function")
|
|
244
|
+
|
|
245
|
+
def is_index_in_bounds(self, index: int) -> bool:
|
|
246
|
+
"""
|
|
247
|
+
Checks if the given index is within the bounds of the partitioned tensor.
|
|
248
|
+
This is used to prevent out-of-bounds access in the kernel.
|
|
249
|
+
"""
|
|
250
|
+
raise RuntimeError("is_index_in_bounds is a device function")
|
|
251
|
+
|
|
252
|
+
def get_alignment(self) -> int:
|
|
253
|
+
raise NotImplementedError("not implemented")
|
|
254
|
+
|
|
255
|
+
def make_empty_fragment(self) -> OpaqueTensor:
|
|
256
|
+
"""Creates an empty fragment tensor in register memory. The fragment layout
|
|
257
|
+
is the same as the accumulator layout."""
|
|
258
|
+
raise RuntimeError("make_empty_fragment is a device function")
|
|
259
|
+
|
|
260
|
+
def partition_and_copy(self, src: OpaqueTensor, dst: OpaqueTensor):
|
|
261
|
+
"""Partition gmem tensor and copy to rmem fragment."""
|
|
262
|
+
raise RuntimeError("partition_and_copy is a device function")
|
|
263
|
+
|
|
264
|
+
def make_partition_and_copy(self, src: OpaqueTensor) -> OpaqueTensor:
|
|
265
|
+
"""Same as partition_and_copy but returns the partitioned rmem tensor."""
|
|
266
|
+
raise RuntimeError("make_partition_and_copy is a device function")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class Accumulator(Partitioner):
|
|
270
|
+
"""Accumulator is an abstraction that provides the link between the
|
|
271
|
+
global memory and register layouts. It offers operations like partitioning,
|
|
272
|
+
copying data, and mapping register indices to matrix coordinates.
|
|
273
|
+
|
|
274
|
+
Refer to the cuBLASDx documentation for more details on how to use this class:
|
|
275
|
+
:cublasdx_doc:`api/other_tensors.html#accumulator-and-register-fragment-tensors`
|
|
276
|
+
"""
|
|
277
|
+
|
|
278
|
+
def get_results(self, out=None) -> OpaqueTensor:
|
|
279
|
+
raise RuntimeError("get_results is a device function")
|
|
280
|
+
|
|
281
|
+
def partition_and_store(self, tensor: OpaqueTensor):
|
|
282
|
+
raise NotImplementedError("not implemented")
|
|
283
|
+
|
|
284
|
+
def clear(self):
|
|
285
|
+
raise NotImplementedError("not implemented")
|
|
286
|
+
|
|
287
|
+
def size(self):
|
|
288
|
+
raise NotImplementedError("not implemented")
|
|
289
|
+
|
|
290
|
+
def axpby(self):
|
|
291
|
+
raise NotImplementedError("not implemented")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _get_contiguous_strides(shape: tuple[int, ...]) -> tuple[int, ...]:
|
|
295
|
+
"""Calculate contiguous strides from shape in elements."""
|
|
296
|
+
s = []
|
|
297
|
+
curr = 1
|
|
298
|
+
for i in reversed(shape):
|
|
299
|
+
s.append(curr)
|
|
300
|
+
curr *= i
|
|
301
|
+
return tuple(reversed(s))
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class DevicePipeline:
|
|
305
|
+
"""DevicePipeline allows users to optimally configure kernel calls for pipelined
|
|
306
|
+
matrix multiplication. It also provides an access point for getting a
|
|
307
|
+
:class:`TilePipeline` object within a kernel. Input arrays 'a' and 'b' must
|
|
308
|
+
be on the current CUDA device.
|
|
309
|
+
|
|
310
|
+
Refer to the cuBLASDx documentation for more details on how to use this class:
|
|
311
|
+
:cublasdx_doc:`using_pipelines.html`
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
def __init__(self, mm: "Matmul", pipeline_depth: int, a: Any, b: Any):
|
|
315
|
+
self.mm = mm
|
|
316
|
+
self.pipeline_depth = pipeline_depth
|
|
317
|
+
|
|
318
|
+
self._a_view = StridedMemoryView.from_any_interface(a, stream_ptr=-1)
|
|
319
|
+
self._b_view = StridedMemoryView.from_any_interface(b, stream_ptr=-1)
|
|
320
|
+
|
|
321
|
+
if self._a_view.device_id != self._b_view.device_id:
|
|
322
|
+
raise ValueError(
|
|
323
|
+
f"Arrays 'a' and 'b' must be on the same device. "
|
|
324
|
+
f"Got a on {self._a_view.device_id} and b on {self._b_view.device_id}"
|
|
325
|
+
)
|
|
326
|
+
if self._a_view.device_id == -1:
|
|
327
|
+
raise ValueError("Arrays 'a' and 'b' must be on a CUDA device, not CPU.")
|
|
328
|
+
|
|
329
|
+
device = Device(None) # get the current device
|
|
330
|
+
if self._a_view.device_id != device.device_id:
|
|
331
|
+
raise ValueError(f"Arrays 'a' and 'b' are not on the current CUDA device {device.device_id}")
|
|
332
|
+
device.set_current()
|
|
333
|
+
|
|
334
|
+
h = _blas_device_pipeline_handle(self)
|
|
335
|
+
|
|
336
|
+
self._storage_bytes = int(mathdx.cublasdx_get_pipeline_trait_int64(h, mathdx.CublasdxPipelineTrait.STORAGE_BYTES))
|
|
337
|
+
self._storage_alignment_bytes = int(
|
|
338
|
+
mathdx.cublasdx_get_pipeline_trait_int64(h, mathdx.CublasdxPipelineTrait.STORAGE_ALIGNMENT_BYTES)
|
|
339
|
+
)
|
|
340
|
+
self._buffer_size = int(mathdx.cublasdx_get_pipeline_trait_int64(h, mathdx.CublasdxPipelineTrait.BUFFER_SIZE))
|
|
341
|
+
self._buffer_alignment_bytes = int(
|
|
342
|
+
mathdx.cublasdx_get_pipeline_trait_int64(h, mathdx.CublasdxPipelineTrait.BUFFER_ALIGNMENT_BYTES)
|
|
343
|
+
)
|
|
344
|
+
block_dim = numpy.zeros(3, dtype=numpy.int64)
|
|
345
|
+
mathdx.cublasdx_get_pipeline_trait_int64s(
|
|
346
|
+
h, mathdx.CublasdxPipelineTrait.BLOCK_DIM, len(block_dim), block_dim.ctypes.data
|
|
347
|
+
)
|
|
348
|
+
self._block_dim = Dim3(*block_dim.tolist())
|
|
349
|
+
|
|
350
|
+
# We do not need _storage_alignment_bytes here as device allocated
|
|
351
|
+
# memory is maximum aligned.
|
|
352
|
+
self._storage: Buffer = device.allocate(self._storage_bytes, stream=device.default_stream)
|
|
353
|
+
|
|
354
|
+
self._init_kernel_launch(a, b, device)
|
|
355
|
+
|
|
356
|
+
mm_descriptor = _blas_tensors_handle(self.mm)
|
|
357
|
+
pipeline_descriptor = _blas_device_pipeline_handle(self)
|
|
358
|
+
self._finalizer = weakref.finalize(
|
|
359
|
+
self, DevicePipeline._destruct_kernel_execute, mm_descriptor, pipeline_descriptor, self._storage, device
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def buffer_alignment(self) -> int:
|
|
364
|
+
return self._buffer_alignment_bytes
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def buffer_size(self) -> int:
|
|
368
|
+
return self._buffer_size
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def storage_bytes(self) -> int:
|
|
372
|
+
return self._storage_bytes
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def storage_alignment(self) -> int:
|
|
376
|
+
return self._storage_alignment_bytes
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def block_dim(self) -> Dim3:
|
|
380
|
+
return self._block_dim
|
|
381
|
+
|
|
382
|
+
def get_tile(self, smem: numpy.ndarray, blockIdx_x: int, blockIdx_y: int) -> "TilePipeline":
|
|
383
|
+
raise RuntimeError("get_tile is a device function")
|
|
384
|
+
|
|
385
|
+
def reset_tile(self, tile_pipeline: "TilePipeline", idx: int | tuple[int, int], idy: int | tuple[int, int]):
|
|
386
|
+
raise RuntimeError("reset_tile is a device function")
|
|
387
|
+
|
|
388
|
+
@cached_property
|
|
389
|
+
def a_strides(self):
|
|
390
|
+
if self._a_view.strides is not None:
|
|
391
|
+
return self._a_view.strides
|
|
392
|
+
|
|
393
|
+
return _get_contiguous_strides(self._a_view.shape)
|
|
394
|
+
|
|
395
|
+
@cached_property
|
|
396
|
+
def b_strides(self):
|
|
397
|
+
if self._b_view.strides is not None:
|
|
398
|
+
return self._b_view.strides
|
|
399
|
+
|
|
400
|
+
return _get_contiguous_strides(self._b_view.shape)
|
|
401
|
+
|
|
402
|
+
def _debug_print(self):
|
|
403
|
+
import cupy
|
|
404
|
+
|
|
405
|
+
vhex = numpy.vectorize(hex)
|
|
406
|
+
tma_cp = cupy.from_dlpack(self._storage).view(dtype=numpy.uint8)
|
|
407
|
+
|
|
408
|
+
print(f"A_ptr: 0x{int(self._a_view.ptr):x}")
|
|
409
|
+
print(f"B_ptr: 0x{int(self._b_view.ptr):x}")
|
|
410
|
+
print("Device pipeline buffer:", vhex(cupy.asnumpy(tma_cp)))
|
|
411
|
+
|
|
412
|
+
def _init_kernel_launch(self, a, b, device: Device):
|
|
413
|
+
mm_descriptor = _blas_tensors_handle(self.mm)
|
|
414
|
+
pipeline_descriptor = _blas_device_pipeline_handle(self)
|
|
415
|
+
kernel = _compile_blas_device_pipeline_init_kernel(
|
|
416
|
+
mm_descriptor, pipeline_descriptor, code_type=get_default_code_type()
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
# Create the launch configuration
|
|
420
|
+
config = LaunchConfig(grid=(1,), block=(1,))
|
|
421
|
+
ker_args = (int(self._storage.handle), int(self._a_view.ptr), int(self._b_view.ptr))
|
|
422
|
+
|
|
423
|
+
# Launch the kernel
|
|
424
|
+
launch(device.default_stream, config, kernel, *ker_args)
|
|
425
|
+
device.default_stream.sync()
|
|
426
|
+
|
|
427
|
+
@staticmethod
|
|
428
|
+
def _destruct_kernel_execute(mm_descriptor: int, pipeline_descriptor: int, storage: Buffer, device: Device):
|
|
429
|
+
kernel = _compile_blas_device_pipeline_destroy_kernel(
|
|
430
|
+
mm_descriptor, pipeline_descriptor, code_type=get_default_code_type()
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
# Create the launch configuration
|
|
434
|
+
config = LaunchConfig(grid=(1,), block=(1,))
|
|
435
|
+
ker_args = (int(storage.handle),)
|
|
436
|
+
|
|
437
|
+
# Launch the kernel
|
|
438
|
+
device.set_current()
|
|
439
|
+
launch(device.default_stream, config, kernel, *ker_args)
|
|
440
|
+
device.default_stream.sync()
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class TilePipeline:
|
|
444
|
+
"""TilePipeline allows users to execute a pipelined matrix multiplication
|
|
445
|
+
with partial tile results accumulated into an accumulator.
|
|
446
|
+
|
|
447
|
+
Refer to the cuBLASDx documentation for more details on how to use this class:
|
|
448
|
+
:cublasdx_doc:`using_pipelines.html`
|
|
449
|
+
"""
|
|
450
|
+
|
|
451
|
+
def __init__(self, device_pipeline: DevicePipeline):
|
|
452
|
+
self.device_pipeline = device_pipeline
|
|
453
|
+
|
|
454
|
+
MM_descriptor = _blas_tensors_handle(device_pipeline.mm)
|
|
455
|
+
device_pipeline_descriptor = _blas_device_pipeline_handle(device_pipeline)
|
|
456
|
+
h = generate_tile_pipeline(
|
|
457
|
+
MM_descriptor,
|
|
458
|
+
device_pipeline_descriptor,
|
|
459
|
+
)
|
|
460
|
+
self._storage_bytes = int(
|
|
461
|
+
mathdx.cublasdx_get_pipeline_trait_int64(h.descriptor, mathdx.CublasdxPipelineTrait.STORAGE_BYTES)
|
|
462
|
+
)
|
|
463
|
+
self._storage_alignment_bytes = int(
|
|
464
|
+
mathdx.cublasdx_get_pipeline_trait_int64(h.descriptor, mathdx.CublasdxPipelineTrait.STORAGE_ALIGNMENT_BYTES)
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
def _init(self, device_pipeline: DevicePipeline, smem, idx: int, idy: int):
|
|
468
|
+
raise RuntimeError("_init is a device function")
|
|
469
|
+
|
|
470
|
+
def _del(self):
|
|
471
|
+
raise RuntimeError("_del is a device function")
|
|
472
|
+
|
|
473
|
+
@property
|
|
474
|
+
def storage_bytes(self) -> int:
|
|
475
|
+
return self._storage_bytes
|
|
476
|
+
|
|
477
|
+
@property
|
|
478
|
+
def storage_alignment(self) -> int:
|
|
479
|
+
return self._storage_alignment_bytes
|
|
480
|
+
|
|
481
|
+
def execute(self, accumulator):
|
|
482
|
+
raise RuntimeError("execute is a device function")
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@docstring_decorator(CUBLASDX_DOCSTRING, skip_missing=False)
|
|
486
|
+
class Matmul:
|
|
487
|
+
"""
|
|
488
|
+
A class that encapsulates a partial Matmul device function. A partial device function
|
|
489
|
+
can be queried for available or optimal values for some knobs (such as
|
|
490
|
+
`leading_dimension` or `block_dim`).
|
|
491
|
+
|
|
492
|
+
.. versionchanged:: 0.7.0
|
|
493
|
+
`Matmul` has replaced `BlasOptions` and `BlasOptionsComplete`.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
size: {size}
|
|
497
|
+
|
|
498
|
+
precision: {precision}
|
|
499
|
+
|
|
500
|
+
data_type: {data_type}
|
|
501
|
+
|
|
502
|
+
sm (ComputeCapability): {sm}
|
|
503
|
+
|
|
504
|
+
block_size (int): {block_size}
|
|
505
|
+
|
|
506
|
+
block_dim (Dim3): {block_dim}
|
|
507
|
+
|
|
508
|
+
leading_dimension (LeadingDimension): {leading_dimension}
|
|
509
|
+
|
|
510
|
+
transpose_mode (TransposeMode): {transpose_mode}
|
|
511
|
+
|
|
512
|
+
arrangement (Arrangement): {arrangement}
|
|
513
|
+
|
|
514
|
+
alignment (Alignment): {alignment}
|
|
515
|
+
|
|
516
|
+
function (str): {function}
|
|
517
|
+
|
|
518
|
+
static_block_dim (bool): {static_block_dim}
|
|
519
|
+
|
|
520
|
+
execution (str): {execution}
|
|
521
|
+
|
|
522
|
+
with_pipeline (bool): {with_pipeline}
|
|
523
|
+
|
|
524
|
+
enable_input_streaming (bool): {enable_input_streaming}
|
|
525
|
+
|
|
526
|
+
.. seealso::
|
|
527
|
+
The attributes of this class provide a 1:1 mapping with the CUDA C++ cuBLASDx APIs.
|
|
528
|
+
For further details, please refer to :cublasdx_doc:`cuBLASDx documentation
|
|
529
|
+
<index.html>`.
|
|
530
|
+
"""
|
|
531
|
+
|
|
532
|
+
def __init__(
|
|
533
|
+
self,
|
|
534
|
+
size,
|
|
535
|
+
precision,
|
|
536
|
+
data_type,
|
|
537
|
+
*,
|
|
538
|
+
sm=None,
|
|
539
|
+
block_size=None,
|
|
540
|
+
block_dim=None,
|
|
541
|
+
leading_dimension=None,
|
|
542
|
+
transpose_mode=None,
|
|
543
|
+
arrangement=None,
|
|
544
|
+
alignment=None,
|
|
545
|
+
function="MM",
|
|
546
|
+
static_block_dim=False,
|
|
547
|
+
execution="Block",
|
|
548
|
+
with_pipeline: bool = False,
|
|
549
|
+
enable_input_streaming: bool = False,
|
|
550
|
+
):
|
|
551
|
+
sm = parse_sm(sm)
|
|
552
|
+
if sm.integer not in {900, 1000, 1030, 1100}:
|
|
553
|
+
# remove arch modifier
|
|
554
|
+
sm = ComputeCapability(sm.major, sm.minor)
|
|
555
|
+
|
|
556
|
+
if transpose_mode is not None:
|
|
557
|
+
warn(
|
|
558
|
+
"transpose_mode is deprecated and may be removed in future versions. Use arrangement instead",
|
|
559
|
+
category=DeprecationWarning,
|
|
560
|
+
)
|
|
561
|
+
if not isinstance(transpose_mode, Sequence) or len(transpose_mode) != 2:
|
|
562
|
+
raise ValueError(
|
|
563
|
+
"transpose_mode should be an instance of TransposeMode or a 2-tuple ; "
|
|
564
|
+
f"got transpose_mode = {transpose_mode}"
|
|
565
|
+
)
|
|
566
|
+
transpose_mode = TransposeMode(*transpose_mode)
|
|
567
|
+
if arrangement is not None:
|
|
568
|
+
if not isinstance(arrangement, Sequence) or len(arrangement) != 3:
|
|
569
|
+
raise ValueError(
|
|
570
|
+
f"arrangement should be an instance of Arrangement or a 3-tuple ; got arrangement = {arrangement}"
|
|
571
|
+
)
|
|
572
|
+
arrangement = Arrangement(*arrangement)
|
|
573
|
+
|
|
574
|
+
if alignment is not None:
|
|
575
|
+
if not isinstance(alignment, Sequence) or len(alignment) != 3:
|
|
576
|
+
raise ValueError(f"alignment should be an instance of Alignment or a 3-tuple ; got alignment = {alignment}")
|
|
577
|
+
alignment = Alignment(*alignment)
|
|
578
|
+
|
|
579
|
+
if leading_dimension is not None and leading_dimension != "suggested":
|
|
580
|
+
if not isinstance(leading_dimension, Sequence) or len(leading_dimension) != 3:
|
|
581
|
+
raise ValueError(
|
|
582
|
+
"leading_dimension should be a 3-tuple, an instance of LeadingDimension, 'suggested' or None ; "
|
|
583
|
+
f"got leading_dimension = {leading_dimension}"
|
|
584
|
+
)
|
|
585
|
+
else:
|
|
586
|
+
leading_dimension = LeadingDimension(*leading_dimension)
|
|
587
|
+
|
|
588
|
+
if isinstance(precision, Sequence):
|
|
589
|
+
if len(precision) != 3:
|
|
590
|
+
raise ValueError(
|
|
591
|
+
"precision should be a 3-len sequence, an instance of Precision, or a single value; "
|
|
592
|
+
f"got precision = {precision}"
|
|
593
|
+
)
|
|
594
|
+
else:
|
|
595
|
+
precision = (precision, precision, precision)
|
|
596
|
+
precision = Precision(*precision)
|
|
597
|
+
|
|
598
|
+
#
|
|
599
|
+
# Check that the knobs are, individually, valid
|
|
600
|
+
#
|
|
601
|
+
|
|
602
|
+
if block_size is not None and block_dim is not None:
|
|
603
|
+
raise ValueError(f"Both block_size ({block_size}) and block_dim ({block_dim}) cannot be specified.")
|
|
604
|
+
if block_size is not None:
|
|
605
|
+
check_in("block_dim", block_dim, [None])
|
|
606
|
+
if block_size == "suggested":
|
|
607
|
+
block_dim = "suggested"
|
|
608
|
+
else:
|
|
609
|
+
block_dim = Dim3(block_size, 1, 1)
|
|
610
|
+
if block_dim is not None and isinstance(block_dim, Sequence) and block_dim != "suggested":
|
|
611
|
+
if len(block_dim) != 3:
|
|
612
|
+
raise ValueError(
|
|
613
|
+
f"block_dim should be a 3-tuple, an instance of Dim3, 'suggested' or None ; got block_dim = {block_dim}"
|
|
614
|
+
)
|
|
615
|
+
else:
|
|
616
|
+
block_dim = Dim3(*block_dim)
|
|
617
|
+
|
|
618
|
+
validate(
|
|
619
|
+
size=size,
|
|
620
|
+
precision=precision,
|
|
621
|
+
data_type=data_type,
|
|
622
|
+
transpose_mode=transpose_mode,
|
|
623
|
+
arrangement=arrangement,
|
|
624
|
+
alignment=alignment,
|
|
625
|
+
sm=sm,
|
|
626
|
+
leading_dimension=leading_dimension,
|
|
627
|
+
block_dim=block_dim,
|
|
628
|
+
function=function,
|
|
629
|
+
execution=execution,
|
|
630
|
+
static_block_dim=static_block_dim,
|
|
631
|
+
with_pipeline=with_pipeline,
|
|
632
|
+
enable_input_streaming=enable_input_streaming,
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
#
|
|
636
|
+
# Traits set by input
|
|
637
|
+
#
|
|
638
|
+
|
|
639
|
+
self._size = size
|
|
640
|
+
self._precision = precision
|
|
641
|
+
self._data_type = data_type
|
|
642
|
+
self._transpose_mode = transpose_mode
|
|
643
|
+
self._arrangement = arrangement
|
|
644
|
+
self._alignment = alignment
|
|
645
|
+
self._sm = sm
|
|
646
|
+
self._block_dim = block_dim
|
|
647
|
+
self._function = function
|
|
648
|
+
self._execution = execution
|
|
649
|
+
self._leading_dimension = leading_dimension
|
|
650
|
+
self._static_block_dim = static_block_dim
|
|
651
|
+
self._with_pipeline = with_pipeline
|
|
652
|
+
self._enable_input_streaming = enable_input_streaming
|
|
653
|
+
|
|
654
|
+
#
|
|
655
|
+
# Update suggested traits
|
|
656
|
+
#
|
|
657
|
+
|
|
658
|
+
if leading_dimension == "suggested":
|
|
659
|
+
self._leading_dimension = self._suggested_leading_dimension
|
|
660
|
+
|
|
661
|
+
if block_dim == "suggested":
|
|
662
|
+
self._block_dim = self._suggested_block_dim
|
|
663
|
+
|
|
664
|
+
@cached_property
|
|
665
|
+
def _traits(self):
|
|
666
|
+
return _MatmulTraits(self)
|
|
667
|
+
|
|
668
|
+
@property
|
|
669
|
+
def precision(self) -> Precision:
|
|
670
|
+
"""{precision}"""
|
|
671
|
+
return self._precision
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def data_type(self) -> str:
|
|
675
|
+
"""{data_type}"""
|
|
676
|
+
return self._data_type
|
|
677
|
+
|
|
678
|
+
@property
|
|
679
|
+
def size(self) -> tuple[int, int, int]:
|
|
680
|
+
"""{size}"""
|
|
681
|
+
return self._size
|
|
682
|
+
|
|
683
|
+
@property
|
|
684
|
+
def execution(self) -> str:
|
|
685
|
+
"""{execution}"""
|
|
686
|
+
return self._execution
|
|
687
|
+
|
|
688
|
+
@property
|
|
689
|
+
@deprecated("transpose_mode trait is deprecated and may be removed in future versions. Use arrangement instead")
|
|
690
|
+
def transpose_mode(self) -> TransposeMode:
|
|
691
|
+
"""{transpose_mode}"""
|
|
692
|
+
return self._transpose_mode
|
|
693
|
+
|
|
694
|
+
@property
|
|
695
|
+
def arrangement(self) -> Arrangement:
|
|
696
|
+
"""{arrangement}"""
|
|
697
|
+
return self._arrangement
|
|
698
|
+
|
|
699
|
+
@property
|
|
700
|
+
def alignment(self) -> Alignment:
|
|
701
|
+
"""{alignment}"""
|
|
702
|
+
if self._alignment is None:
|
|
703
|
+
return self._traits.alignment
|
|
704
|
+
return self._alignment
|
|
705
|
+
|
|
706
|
+
@property
|
|
707
|
+
def sm(self):
|
|
708
|
+
"""{sm}"""
|
|
709
|
+
return self._sm
|
|
710
|
+
|
|
711
|
+
@property
|
|
712
|
+
def function(self) -> str:
|
|
713
|
+
"""{function}"""
|
|
714
|
+
return self._function
|
|
715
|
+
|
|
716
|
+
@property
|
|
717
|
+
def block_size(self) -> int:
|
|
718
|
+
"""{block_size}"""
|
|
719
|
+
return self.block_dim[0] * self.block_dim[1] * self.block_dim[2]
|
|
720
|
+
|
|
721
|
+
@property
|
|
722
|
+
def block_dim(self) -> Dim3:
|
|
723
|
+
"""{block_dim}"""
|
|
724
|
+
if self._block_dim is None:
|
|
725
|
+
return self._traits.block_dim
|
|
726
|
+
return self._block_dim
|
|
727
|
+
|
|
728
|
+
@property
|
|
729
|
+
def static_block_dim(self) -> bool:
|
|
730
|
+
"""{static_block_dim}"""
|
|
731
|
+
return self._static_block_dim
|
|
732
|
+
|
|
733
|
+
@property
|
|
734
|
+
def leading_dimension(self) -> LeadingDimension:
|
|
735
|
+
"""{leading_dimension}"""
|
|
736
|
+
if self._leading_dimension is None:
|
|
737
|
+
return self._traits.leading_dimension
|
|
738
|
+
return self._leading_dimension
|
|
739
|
+
|
|
740
|
+
@property
|
|
741
|
+
def with_pipeline(self) -> bool:
|
|
742
|
+
"""{with_pipeline}"""
|
|
743
|
+
return self._with_pipeline
|
|
744
|
+
|
|
745
|
+
@property
|
|
746
|
+
def enable_input_streaming(self) -> bool:
|
|
747
|
+
"""{enable_input_streaming}"""
|
|
748
|
+
return self._enable_input_streaming
|
|
749
|
+
|
|
750
|
+
#
|
|
751
|
+
# Extensions
|
|
752
|
+
#
|
|
753
|
+
|
|
754
|
+
def valid(self, *knobs):
|
|
755
|
+
return itertools.product(*[self._valid(knob) for knob in knobs])
|
|
756
|
+
|
|
757
|
+
#
|
|
758
|
+
# Private implementations
|
|
759
|
+
#
|
|
760
|
+
|
|
761
|
+
def _valid(self, knob):
|
|
762
|
+
if knob == "block_dim":
|
|
763
|
+
return [self._suggested_block_dim]
|
|
764
|
+
else:
|
|
765
|
+
raise ValueError("Unsupported knob")
|
|
766
|
+
|
|
767
|
+
@cached_property
|
|
768
|
+
def _suggested_leading_dimension(self):
|
|
769
|
+
# Generate special PTX for suggested_leading_dimension_of
|
|
770
|
+
descriptor = generate_MM(
|
|
771
|
+
size=self.size,
|
|
772
|
+
function=self.function,
|
|
773
|
+
precision=self.precision,
|
|
774
|
+
data_type=self.data_type,
|
|
775
|
+
sm=self.sm,
|
|
776
|
+
transpose_mode=self._transpose_mode,
|
|
777
|
+
arrangement=self._arrangement,
|
|
778
|
+
alignment=self._alignment,
|
|
779
|
+
block_dim=None,
|
|
780
|
+
static_block_dim=self._static_block_dim,
|
|
781
|
+
leading_dimension=None,
|
|
782
|
+
execution=self.execution,
|
|
783
|
+
with_pipeline=self._with_pipeline,
|
|
784
|
+
enable_input_streaming=self._enable_input_streaming,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
return LeadingDimension(*get_int_traits(descriptor.descriptor, mathdx.CublasdxTraitType.SUGGESTED_LEADING_DIMENSION, 3))
|
|
788
|
+
|
|
789
|
+
@cached_property
|
|
790
|
+
def _suggested_block_dim(self):
|
|
791
|
+
# Generate full PTX
|
|
792
|
+
descriptor = generate_MM(
|
|
793
|
+
size=self.size,
|
|
794
|
+
function=self.function,
|
|
795
|
+
precision=self.precision,
|
|
796
|
+
data_type=self.data_type,
|
|
797
|
+
sm=self.sm,
|
|
798
|
+
transpose_mode=self._transpose_mode,
|
|
799
|
+
arrangement=self._arrangement,
|
|
800
|
+
alignment=self._alignment,
|
|
801
|
+
block_dim=None,
|
|
802
|
+
static_block_dim=self._static_block_dim,
|
|
803
|
+
leading_dimension=None,
|
|
804
|
+
execution=self.execution,
|
|
805
|
+
with_pipeline=self._with_pipeline,
|
|
806
|
+
enable_input_streaming=self._enable_input_streaming,
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
return Dim3(*get_int_traits(descriptor.descriptor, mathdx.CublasdxTraitType.SUGGESTED_BLOCK_DIM, 3))
|
|
810
|
+
|
|
811
|
+
@property
|
|
812
|
+
def a_value_type(self):
|
|
813
|
+
return self._traits.value_types[0]
|
|
814
|
+
|
|
815
|
+
@property
|
|
816
|
+
def b_value_type(self):
|
|
817
|
+
return self._traits.value_types[1]
|
|
818
|
+
|
|
819
|
+
@property
|
|
820
|
+
def c_value_type(self):
|
|
821
|
+
return self._traits.value_types[2]
|
|
822
|
+
|
|
823
|
+
@cached_property
|
|
824
|
+
def a_dim(self) -> tuple[int, int]:
|
|
825
|
+
(m, _, k) = self.size
|
|
826
|
+
|
|
827
|
+
dim = (m, k)
|
|
828
|
+
if self._transpose_mode is not None and self._transpose_mode.a in {"transposed", "conj_transposed"}:
|
|
829
|
+
dim = dim[::-1]
|
|
830
|
+
|
|
831
|
+
return dim
|
|
832
|
+
|
|
833
|
+
@cached_property
|
|
834
|
+
def b_dim(self) -> tuple[int, int]:
|
|
835
|
+
(_, n, k) = self.size
|
|
836
|
+
|
|
837
|
+
dim = (k, n)
|
|
838
|
+
if self._transpose_mode is not None and self._transpose_mode.b in {"transposed", "conj_transposed"}:
|
|
839
|
+
dim = dim[::-1]
|
|
840
|
+
|
|
841
|
+
return dim
|
|
842
|
+
|
|
843
|
+
@cached_property
|
|
844
|
+
def c_dim(self) -> tuple[int, int]:
|
|
845
|
+
(m, n, _) = self.size
|
|
846
|
+
return (m, n)
|
|
847
|
+
|
|
848
|
+
def _calculate_abc_sizes(self, ld: LeadingDimension) -> tuple[int, int, int]:
|
|
849
|
+
if self._transpose_mode:
|
|
850
|
+
non_ld = (self.a_dim[1], self.b_dim[1], self.c_dim[1])
|
|
851
|
+
elif self._arrangement:
|
|
852
|
+
non_ld = (
|
|
853
|
+
self.a_dim[1 if self._arrangement.a == "col_major" else 0],
|
|
854
|
+
self.b_dim[1 if self._arrangement.b == "col_major" else 0],
|
|
855
|
+
self.c_dim[1 if self._arrangement.c == "col_major" else 0],
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
return tuple(x * y for x, y in zip(ld, non_ld, strict=True))
|
|
859
|
+
|
|
860
|
+
@cached_property
|
|
861
|
+
def _abc_sizes(self) -> tuple[int, int, int]:
|
|
862
|
+
return self._calculate_abc_sizes(self.leading_dimension)
|
|
863
|
+
|
|
864
|
+
@property
|
|
865
|
+
def a_size(self) -> int:
|
|
866
|
+
return self._abc_sizes[0]
|
|
867
|
+
|
|
868
|
+
@property
|
|
869
|
+
def b_size(self) -> int:
|
|
870
|
+
return self._abc_sizes[1]
|
|
871
|
+
|
|
872
|
+
@property
|
|
873
|
+
def c_size(self) -> int:
|
|
874
|
+
return self._abc_sizes[2]
|
|
875
|
+
|
|
876
|
+
@property
|
|
877
|
+
def max_threads_per_block(self):
|
|
878
|
+
return self.block_dim.x * self.block_dim.y * self.block_dim.z
|
|
879
|
+
|
|
880
|
+
def _get_shared_storage_size(self, *args, ab=False) -> int | None: # type: ignore
|
|
881
|
+
# Complex will be over-aligned (eg: f32x2 complex is aligned on 8B) with
|
|
882
|
+
# this logic (which is what we want - for performance and vectorization)
|
|
883
|
+
item_sizes = tuple(numpy.dtype(vt).itemsize for vt in self._traits.value_types)
|
|
884
|
+
|
|
885
|
+
alignment = self.alignment
|
|
886
|
+
sizes = None
|
|
887
|
+
|
|
888
|
+
if len(args) == 0:
|
|
889
|
+
sizes = (self.a_size, self.b_size, self.c_size)
|
|
890
|
+
elif all(isinstance(arg, int) for arg in args):
|
|
891
|
+
sizes = self._calculate_abc_sizes(LeadingDimension(*pad_or_truncate(list(args), 3)))
|
|
892
|
+
elif all(isinstance(arg, Layout) for arg in args):
|
|
893
|
+
sizes = tuple(arg.cosize for arg in args)
|
|
894
|
+
|
|
895
|
+
if sizes is None:
|
|
896
|
+
return None
|
|
897
|
+
|
|
898
|
+
smem_calc = SharedStorageCalc()
|
|
899
|
+
smem_calc.add(alignment[0], item_sizes[0], sizes[0])
|
|
900
|
+
smem_calc.add(alignment[1], item_sizes[1], sizes[1])
|
|
901
|
+
if not ab:
|
|
902
|
+
smem_calc.add(alignment[2], item_sizes[2], sizes[2])
|
|
903
|
+
return smem_calc.get()
|
|
904
|
+
|
|
905
|
+
@overload
|
|
906
|
+
def get_shared_storage_size(self) -> int: ...
|
|
907
|
+
@overload
|
|
908
|
+
def get_shared_storage_size(self, lda: int, ldb: int, ldc: int) -> int: ...
|
|
909
|
+
@overload
|
|
910
|
+
def get_shared_storage_size(self, matrix_a_layout: Layout, matrix_b_layout: Layout, matrix_c_layout: Layout) -> int: ...
|
|
911
|
+
def get_shared_storage_size(self, *args) -> int: # type: ignore
|
|
912
|
+
value_error = ValueError(
|
|
913
|
+
"get_shared_storage_size() takes either 0 or 3 arguments. If 3 "
|
|
914
|
+
"arguments are provided, they must be either all integers or "
|
|
915
|
+
"all Layout objects."
|
|
916
|
+
)
|
|
917
|
+
if len(args) not in {0, 3}:
|
|
918
|
+
raise value_error
|
|
919
|
+
if any(not isinstance(arg, Layout) for arg in args) and any(not isinstance(arg, int) for arg in args):
|
|
920
|
+
raise value_error
|
|
921
|
+
size = self._get_shared_storage_size(*args, ab=False)
|
|
922
|
+
if size is None:
|
|
923
|
+
raise value_error
|
|
924
|
+
return size
|
|
925
|
+
|
|
926
|
+
@overload
|
|
927
|
+
def get_shared_storage_size_ab(self) -> int: ...
|
|
928
|
+
@overload
|
|
929
|
+
def get_shared_storage_size_ab(self, lda: int, ldb: int) -> int: ...
|
|
930
|
+
@overload
|
|
931
|
+
def get_shared_storage_size_ab(self, matrix_a_layout: Layout, matrix_b_layout: Layout) -> int: ...
|
|
932
|
+
def get_shared_storage_size_ab(self, *args) -> int: # type: ignore
|
|
933
|
+
value_error = ValueError(
|
|
934
|
+
"get_shared_storage_size_ab() takes either 0 or 2 arguments. "
|
|
935
|
+
"If 2 arguments are provided, they must be either all integers "
|
|
936
|
+
"or all Layout objects."
|
|
937
|
+
)
|
|
938
|
+
if len(args) not in {0, 2}:
|
|
939
|
+
raise value_error
|
|
940
|
+
if any(not isinstance(arg, Layout) for arg in args) and any(not isinstance(arg, int) for arg in args):
|
|
941
|
+
raise value_error
|
|
942
|
+
size = self._get_shared_storage_size(*args, ab=True)
|
|
943
|
+
if size is None:
|
|
944
|
+
raise value_error
|
|
945
|
+
return size
|
|
946
|
+
|
|
947
|
+
def get_layout_gmem_a(self, leading_dimension: int | None = None) -> Layout:
|
|
948
|
+
return _BlasMatmulLayout(self, "get_layout_gmem_a", leading_dimension)
|
|
949
|
+
|
|
950
|
+
def get_layout_gmem_b(self, leading_dimension: int | None = None) -> Layout:
|
|
951
|
+
return _BlasMatmulLayout(self, "get_layout_gmem_b", leading_dimension)
|
|
952
|
+
|
|
953
|
+
def get_layout_gmem_c(self, leading_dimension: int | None = None) -> Layout:
|
|
954
|
+
return _BlasMatmulLayout(self, "get_layout_gmem_c", leading_dimension)
|
|
955
|
+
|
|
956
|
+
def get_layout_smem_a(self) -> Layout:
|
|
957
|
+
return _BlasMatmulLayout(self, "get_layout_smem_a")
|
|
958
|
+
|
|
959
|
+
def get_layout_smem_b(self) -> Layout:
|
|
960
|
+
return _BlasMatmulLayout(self, "get_layout_smem_b")
|
|
961
|
+
|
|
962
|
+
def get_layout_smem_c(self) -> Layout:
|
|
963
|
+
return _BlasMatmulLayout(self, "get_layout_smem_c")
|
|
964
|
+
|
|
965
|
+
def suggest_layout_smem_a(self) -> Layout:
|
|
966
|
+
return _BlasMatmulLayout(self, "suggest_layout_smem_a")
|
|
967
|
+
|
|
968
|
+
def suggest_layout_smem_b(self) -> Layout:
|
|
969
|
+
return _BlasMatmulLayout(self, "suggest_layout_smem_b")
|
|
970
|
+
|
|
971
|
+
def suggest_layout_smem_c(self) -> Layout:
|
|
972
|
+
return _BlasMatmulLayout(self, "suggest_layout_smem_c")
|
|
973
|
+
|
|
974
|
+
def suggest_layout_rmem_c(self) -> Layout:
|
|
975
|
+
return _BlasMatmulLayout(self, "suggest_layout_rmem_c")
|
|
976
|
+
|
|
977
|
+
def get_layout_rmem_c(self) -> Layout:
|
|
978
|
+
return _BlasMatmulLayout(self, "get_layout_rmem_c")
|
|
979
|
+
|
|
980
|
+
def _suggest_accumulator_c(self) -> Layout:
|
|
981
|
+
return _BlasMatmulLayout(self, "suggest_accumulator_c")
|
|
982
|
+
|
|
983
|
+
def _get_accumulator_c(self) -> Layout:
|
|
984
|
+
return _BlasMatmulLayout(self, "get_accumulator_c")
|
|
985
|
+
|
|
986
|
+
def get_accumulator(self) -> Accumulator:
|
|
987
|
+
raise RuntimeError("get_accumulator is a device function")
|
|
988
|
+
|
|
989
|
+
def suggest_accumulator(self) -> Accumulator:
|
|
990
|
+
raise RuntimeError("suggest_accumulator is a device function")
|
|
991
|
+
|
|
992
|
+
def suggest_device_pipeline(self, pipeline_depth: int, a: numpy.ndarray, b: numpy.ndarray) -> DevicePipeline:
|
|
993
|
+
cc = get_current_device_cc()
|
|
994
|
+
ctk_version = get_nvrtc_version()
|
|
995
|
+
if ctk_version < (13, 0, 0):
|
|
996
|
+
raise RuntimeError("DevicePipeline requires CUDA Toolkit 13.0 or higher.")
|
|
997
|
+
if cc.major >= 10 and ctk_version < (13, 1, 0):
|
|
998
|
+
raise RuntimeError("DevicePipeline on compute capability 10.0 and higher requires CUDA Toolkit 13.1 or higher.")
|
|
999
|
+
|
|
1000
|
+
return DevicePipeline(self, pipeline_depth, a, b)
|
|
1001
|
+
|
|
1002
|
+
def execute(self, *args):
|
|
1003
|
+
raise RuntimeError("execute should not be called directly outside of a jitted kernel.")
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
class _MatmulTraits:
|
|
1007
|
+
def __init__(self, mm: Matmul):
|
|
1008
|
+
h = generate_MM(
|
|
1009
|
+
size=mm._size,
|
|
1010
|
+
function=mm._function,
|
|
1011
|
+
precision=mm._precision,
|
|
1012
|
+
data_type=mm._data_type,
|
|
1013
|
+
sm=mm._sm,
|
|
1014
|
+
transpose_mode=mm._transpose_mode,
|
|
1015
|
+
arrangement=mm._arrangement,
|
|
1016
|
+
alignment=mm._alignment,
|
|
1017
|
+
block_dim=mm._block_dim,
|
|
1018
|
+
static_block_dim=mm._static_block_dim,
|
|
1019
|
+
leading_dimension=mm._leading_dimension,
|
|
1020
|
+
execution=mm._execution,
|
|
1021
|
+
with_pipeline=mm._with_pipeline,
|
|
1022
|
+
enable_input_streaming=mm._enable_input_streaming,
|
|
1023
|
+
).descriptor
|
|
1024
|
+
|
|
1025
|
+
self.value_types = tuple(MATHDX_TYPES_TO_NP[vt] for vt in get_int_traits(h, mathdx.CublasdxTraitType.VALUE_TYPE, 3))
|
|
1026
|
+
self.leading_dimension = LeadingDimension(*get_int_traits(h, mathdx.CublasdxTraitType.LEADING_DIMENSION, 3))
|
|
1027
|
+
self.block_dim = Dim3(*get_int_traits(h, mathdx.CublasdxTraitType.BLOCK_DIM, 3))
|
|
1028
|
+
self.alignment = Alignment(*get_int_traits(h, mathdx.CublasdxTraitType.ALIGNMENT, 3))
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
#
|
|
1032
|
+
# A compiled BLAS device function, with knobs and device function
|
|
1033
|
+
#
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
def compile_blas_execute(
|
|
1037
|
+
blas: Matmul, code_type: Any, execute_api: str | None = None, tensor_types: Sequence[str] | None = None
|
|
1038
|
+
) -> tuple[Code, str]:
|
|
1039
|
+
code_type = parse_code_type(code_type)
|
|
1040
|
+
check_code_type(code_type, "cuBLASDx")
|
|
1041
|
+
validate_execute_api(execute_api)
|
|
1042
|
+
tensors_api = execute_api == "tensors"
|
|
1043
|
+
if tensors_api:
|
|
1044
|
+
validate_tensor_types(tensor_types)
|
|
1045
|
+
|
|
1046
|
+
handle = generate_MM(
|
|
1047
|
+
size=blas.size,
|
|
1048
|
+
function=blas.function,
|
|
1049
|
+
precision=blas.precision,
|
|
1050
|
+
data_type=blas.data_type,
|
|
1051
|
+
sm=blas.sm,
|
|
1052
|
+
transpose_mode=blas.transpose_mode,
|
|
1053
|
+
arrangement=blas.arrangement,
|
|
1054
|
+
alignment=blas.alignment,
|
|
1055
|
+
block_dim=blas.block_dim,
|
|
1056
|
+
static_block_dim=blas._static_block_dim,
|
|
1057
|
+
# TODO: find better way to exclude ld operator for dynamic_leading_dimensions
|
|
1058
|
+
leading_dimension=blas._leading_dimension if execute_api == "static_leading_dimensions" else None,
|
|
1059
|
+
execution=blas._execution,
|
|
1060
|
+
execute_api=execute_api,
|
|
1061
|
+
tensor_types=tensor_types,
|
|
1062
|
+
with_pipeline=blas.with_pipeline,
|
|
1063
|
+
enable_input_streaming=blas.enable_input_streaming,
|
|
1064
|
+
)
|
|
1065
|
+
|
|
1066
|
+
# Now compile the LTO device function
|
|
1067
|
+
h = handle.descriptor
|
|
1068
|
+
|
|
1069
|
+
if tensors_api:
|
|
1070
|
+
resp = generate_tensors(h, tensor_types)
|
|
1071
|
+
target_tensors = resp.target
|
|
1072
|
+
code, symbol = generate_function_code(h, mathdx.CublasdxDeviceFunctionType.EXECUTE, target_tensors, code_type.cc)
|
|
1073
|
+
else:
|
|
1074
|
+
code = generate_code(h, code_type.cc)
|
|
1075
|
+
|
|
1076
|
+
# Compile
|
|
1077
|
+
lto_fn = get_lto(code.descriptor)
|
|
1078
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1079
|
+
|
|
1080
|
+
ltos = [Code(code_type, isa_version, lto_fn)]
|
|
1081
|
+
|
|
1082
|
+
if tensor_types:
|
|
1083
|
+
symbol = symbol
|
|
1084
|
+
else:
|
|
1085
|
+
symbol = get_str_trait(h, mathdx.CublasdxTraitType.SYMBOL_NAME)
|
|
1086
|
+
|
|
1087
|
+
return ltos[0], symbol
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
def _blas_handle(
|
|
1091
|
+
MM: Matmul,
|
|
1092
|
+
execute_api: str | None = None,
|
|
1093
|
+
):
|
|
1094
|
+
handle = generate_MM(
|
|
1095
|
+
size=MM.size,
|
|
1096
|
+
function=MM.function,
|
|
1097
|
+
precision=MM.precision,
|
|
1098
|
+
data_type=MM.data_type,
|
|
1099
|
+
sm=MM.sm,
|
|
1100
|
+
transpose_mode=MM.transpose_mode,
|
|
1101
|
+
arrangement=MM.arrangement,
|
|
1102
|
+
alignment=MM.alignment,
|
|
1103
|
+
block_dim=MM.block_dim,
|
|
1104
|
+
static_block_dim=MM._static_block_dim,
|
|
1105
|
+
execution=MM._execution,
|
|
1106
|
+
execute_api=execute_api,
|
|
1107
|
+
with_pipeline=MM._with_pipeline,
|
|
1108
|
+
enable_input_streaming=MM._enable_input_streaming,
|
|
1109
|
+
)
|
|
1110
|
+
return handle.descriptor
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
def _blas_tensors_handle(MM: Matmul):
|
|
1114
|
+
return _blas_handle(MM, execute_api="tensors")
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
def _blas_device_pipeline_handle(pipeline: DevicePipeline):
|
|
1118
|
+
MM_descriptor = _blas_tensors_handle(pipeline.mm)
|
|
1119
|
+
return generate_device_pipeline(
|
|
1120
|
+
MM_descriptor,
|
|
1121
|
+
pipeline.pipeline_depth,
|
|
1122
|
+
NP_TYPES_TO_MATHDX_TYPES[pipeline.mm.a_value_type],
|
|
1123
|
+
NP_TYPES_TO_MATHDX_TYPES[pipeline.mm.b_value_type],
|
|
1124
|
+
pipeline._a_view.shape,
|
|
1125
|
+
pipeline._b_view.shape,
|
|
1126
|
+
pipeline.a_strides,
|
|
1127
|
+
pipeline.b_strides,
|
|
1128
|
+
).descriptor
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
def _blas_tile_pipeline_handle(pipeline: TilePipeline):
|
|
1132
|
+
MM_descriptor = _blas_tensors_handle(pipeline.device_pipeline.mm)
|
|
1133
|
+
device_pipeline_descriptor = _blas_device_pipeline_handle(pipeline.device_pipeline)
|
|
1134
|
+
h = generate_tile_pipeline(MM_descriptor, device_pipeline_descriptor)
|
|
1135
|
+
return h.descriptor
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
def _parse_layout(layout: str) -> tuple[bool, bool, str, str]:
|
|
1139
|
+
"""Parse layout string to extract tensor type and memory type.
|
|
1140
|
+
|
|
1141
|
+
Returns: tuple of (suggest, accumulator, memory, tensor)
|
|
1142
|
+
suggest: bool, True if the layout is a suggested layout
|
|
1143
|
+
accumulator: bool, True if the layout is an accumulator
|
|
1144
|
+
memory: str, memory type ('s' for shared, 'g' for global,
|
|
1145
|
+
'r' for register, '' for accumulator)
|
|
1146
|
+
tensor: str, tensor type ('a', 'b', 'c')
|
|
1147
|
+
"""
|
|
1148
|
+
# extracting tensor type from layout
|
|
1149
|
+
pattern = re.compile(r"^(?:(suggest|get)_)?(layout|accumulator)_(?:([srg])mem_)?([abc])$")
|
|
1150
|
+
|
|
1151
|
+
match = pattern.match(layout)
|
|
1152
|
+
|
|
1153
|
+
assert match is not None
|
|
1154
|
+
|
|
1155
|
+
suggest, layout_type, memory, tensor = match.group(1, 2, 3, 4)
|
|
1156
|
+
|
|
1157
|
+
return suggest == "suggest", layout_type == "accumulator", memory, tensor
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
class _BaseBlasLayout(OpaqueLayout):
|
|
1161
|
+
_uid: int
|
|
1162
|
+
_logical_size: int
|
|
1163
|
+
_storage_bytes: int
|
|
1164
|
+
_alignment_bytes: int
|
|
1165
|
+
|
|
1166
|
+
_MM: Matmul
|
|
1167
|
+
|
|
1168
|
+
def __init__(self, MM: Matmul, shape: tuple[int, ...], strides: tuple[int, ...], dtype: numpy.number):
|
|
1169
|
+
super().__init__(shape, strides, dtype)
|
|
1170
|
+
self._MM = MM
|
|
1171
|
+
|
|
1172
|
+
@abstractmethod
|
|
1173
|
+
def _get_descriptor(self) -> DescriptorWrapper:
|
|
1174
|
+
pass
|
|
1175
|
+
|
|
1176
|
+
def _init_traits(self):
|
|
1177
|
+
d = self._get_descriptor()
|
|
1178
|
+
self._uid, self._logical_size, self._storage_bytes, self._alignment_bytes = get_tensor_traits(d.descriptor)
|
|
1179
|
+
|
|
1180
|
+
@property
|
|
1181
|
+
def MM(self) -> Matmul:
|
|
1182
|
+
return self._MM
|
|
1183
|
+
|
|
1184
|
+
@property
|
|
1185
|
+
def uid(self) -> int:
|
|
1186
|
+
return self._uid
|
|
1187
|
+
|
|
1188
|
+
@property
|
|
1189
|
+
def size(self) -> int:
|
|
1190
|
+
return self._logical_size
|
|
1191
|
+
|
|
1192
|
+
@property
|
|
1193
|
+
def storage_bytes(self) -> int:
|
|
1194
|
+
return self._storage_bytes
|
|
1195
|
+
|
|
1196
|
+
@cached_property
|
|
1197
|
+
def cosize(self) -> int:
|
|
1198
|
+
assert self._storage_bytes % numpy.dtype(self._dtype).itemsize == 0
|
|
1199
|
+
return self._storage_bytes // numpy.dtype(self._dtype).itemsize
|
|
1200
|
+
|
|
1201
|
+
@property
|
|
1202
|
+
def alignment(self) -> int:
|
|
1203
|
+
return self._alignment_bytes
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
class _BlasMatmulLayout(_BaseBlasLayout):
|
|
1207
|
+
"""BlasLayout for the OpaqueTensor"""
|
|
1208
|
+
|
|
1209
|
+
_layout: str
|
|
1210
|
+
_tensor_type: str
|
|
1211
|
+
_tensor_index: int
|
|
1212
|
+
_accumulator: bool
|
|
1213
|
+
_memory_space: str
|
|
1214
|
+
_tensor: str
|
|
1215
|
+
|
|
1216
|
+
_default_ld: int | None
|
|
1217
|
+
|
|
1218
|
+
def _get_descriptor(self) -> DescriptorWrapper:
|
|
1219
|
+
return generate_tensor(_blas_tensors_handle(self._MM), self._tensor_type)
|
|
1220
|
+
|
|
1221
|
+
def __init__(self, MM: Matmul, layout: str, leading_dimension: int | None = None):
|
|
1222
|
+
if not isinstance(MM, Matmul):
|
|
1223
|
+
raise ValueError("MM should be an instance of Matmul")
|
|
1224
|
+
|
|
1225
|
+
self._default_ld = leading_dimension
|
|
1226
|
+
self._suggested, self._accumulator, memory, tensor = _parse_layout(layout)
|
|
1227
|
+
self._tensor_index = ["a", "b", "c"].index(tensor)
|
|
1228
|
+
|
|
1229
|
+
if self._accumulator:
|
|
1230
|
+
tensor_type = f"accumulator_{tensor}"
|
|
1231
|
+
else:
|
|
1232
|
+
tensor_type = f"{memory}mem_{tensor}"
|
|
1233
|
+
|
|
1234
|
+
if self._suggested:
|
|
1235
|
+
tensor_type = "suggested_" + tensor_type
|
|
1236
|
+
|
|
1237
|
+
self._tensor_type = tensor_type
|
|
1238
|
+
|
|
1239
|
+
# Inheritance support
|
|
1240
|
+
if hasattr(self, "_dtype") and self._dtype is not None:
|
|
1241
|
+
dtype = self._dtype
|
|
1242
|
+
else:
|
|
1243
|
+
dtype = MM._traits.value_types[self._tensor_index]
|
|
1244
|
+
itemsize = numpy.dtype(dtype).itemsize
|
|
1245
|
+
|
|
1246
|
+
self._MM = MM
|
|
1247
|
+
|
|
1248
|
+
if memory == "g":
|
|
1249
|
+
self._uid = -1
|
|
1250
|
+
self._logical_size = MM._abc_sizes[self._tensor_index]
|
|
1251
|
+
self._storage_bytes = self._logical_size * itemsize
|
|
1252
|
+
# TODO: should we take it as an argument?
|
|
1253
|
+
self._alignment_bytes = itemsize
|
|
1254
|
+
|
|
1255
|
+
shape: tuple[int, ...] = tuple((MM.a_dim, MM.b_dim, MM.c_dim)[self._tensor_index])
|
|
1256
|
+
strides: tuple[int, ...] = (_LIBMATHDX_RUNTIME, 1)
|
|
1257
|
+
else:
|
|
1258
|
+
self._init_traits()
|
|
1259
|
+
shape, strides = (self.size,), (1,)
|
|
1260
|
+
assert self._storage_bytes % itemsize == 0
|
|
1261
|
+
self._cosize = self._storage_bytes // itemsize
|
|
1262
|
+
|
|
1263
|
+
self._memory_space = memory
|
|
1264
|
+
self._layout = layout
|
|
1265
|
+
self._tensor_type = tensor_type
|
|
1266
|
+
|
|
1267
|
+
super().__init__(MM, dtype=dtype, shape=shape, strides=strides)
|
|
1268
|
+
|
|
1269
|
+
@property
|
|
1270
|
+
def suggested(self) -> bool:
|
|
1271
|
+
return self._suggested
|
|
1272
|
+
|
|
1273
|
+
@property
|
|
1274
|
+
def layout(self) -> str:
|
|
1275
|
+
return self._layout
|
|
1276
|
+
|
|
1277
|
+
@property
|
|
1278
|
+
def accumulator(self) -> bool:
|
|
1279
|
+
return self._accumulator
|
|
1280
|
+
|
|
1281
|
+
@property
|
|
1282
|
+
def tensor_type(self) -> str:
|
|
1283
|
+
return self._tensor_type
|
|
1284
|
+
|
|
1285
|
+
@property
|
|
1286
|
+
def tensor_index(self) -> int:
|
|
1287
|
+
"""Tensor index is 0 for A, 1 for B and 2 for C."""
|
|
1288
|
+
return self._tensor_index
|
|
1289
|
+
|
|
1290
|
+
@property
|
|
1291
|
+
def memory_space(self) -> str:
|
|
1292
|
+
"""Memory space is 's' for shared, 'g' for global, 'r' for register,
|
|
1293
|
+
'' for accumulator."""
|
|
1294
|
+
return self._memory_space
|
|
1295
|
+
|
|
1296
|
+
@property
|
|
1297
|
+
def default_ld(self) -> int | None:
|
|
1298
|
+
"""Default leading dimension if provided during layout creation.
|
|
1299
|
+
Only available for gmem layouts created on the host side.
|
|
1300
|
+
Strides will be set to (_LIBMATHDX_RUNTIME,1).
|
|
1301
|
+
"""
|
|
1302
|
+
return self._default_ld
|
|
1303
|
+
|
|
1304
|
+
|
|
1305
|
+
class _BlasMatmulLikeLayout(_BlasMatmulLayout):
|
|
1306
|
+
"""BlasLayout for the OpaqueTensor created with make_fragment_like"""
|
|
1307
|
+
|
|
1308
|
+
_dtype_orig: numpy.number
|
|
1309
|
+
|
|
1310
|
+
def __init__(self, MM: Matmul, layout: str, dtype: numpy.number, leading_dimension: int | None = None):
|
|
1311
|
+
self._dtype = dtype
|
|
1312
|
+
super().__init__(MM, layout, leading_dimension)
|
|
1313
|
+
self._dtype_orig = MM._traits.value_types[self._tensor_index]
|
|
1314
|
+
|
|
1315
|
+
def _get_descriptor(self) -> DescriptorWrapper:
|
|
1316
|
+
mm_handle = _blas_tensors_handle(self._MM)
|
|
1317
|
+
src_tensor = generate_tensor(mm_handle, self._tensor_type)
|
|
1318
|
+
dst_tensor = generate_tensor_like(mm_handle, src_tensor.descriptor, self._dtype)
|
|
1319
|
+
|
|
1320
|
+
return dst_tensor
|
|
1321
|
+
|
|
1322
|
+
@property
|
|
1323
|
+
def dtype_orig(self) -> numpy.number:
|
|
1324
|
+
"""Original dtype of the tensor in the Matmul object."""
|
|
1325
|
+
return self._dtype_orig
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
def compile_blas_copy(
|
|
1329
|
+
src_tensor: _BlasMatmulLayout,
|
|
1330
|
+
dst_tensor: _BlasMatmulLayout,
|
|
1331
|
+
code_type: CodeType,
|
|
1332
|
+
alignment: int | None = None,
|
|
1333
|
+
):
|
|
1334
|
+
check_code_type(code_type, "cuBLASDx")
|
|
1335
|
+
assert src_tensor._MM is not None
|
|
1336
|
+
assert dst_tensor._MM is not None
|
|
1337
|
+
|
|
1338
|
+
src_MM_descriptor = _blas_tensors_handle(src_tensor._MM)
|
|
1339
|
+
src_tensor_descriptor = src_tensor._get_descriptor()
|
|
1340
|
+
dst_tensor_descriptor = dst_tensor._get_descriptor()
|
|
1341
|
+
|
|
1342
|
+
return get_function_code(
|
|
1343
|
+
src_MM_descriptor,
|
|
1344
|
+
mathdx.CublasdxDeviceFunctionType.COPY,
|
|
1345
|
+
[src_tensor_descriptor.descriptor, dst_tensor_descriptor.descriptor],
|
|
1346
|
+
code_type,
|
|
1347
|
+
)
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
def compile_blas_clear(
|
|
1351
|
+
tensor: _BlasMatmulLayout,
|
|
1352
|
+
code_type: CodeType,
|
|
1353
|
+
):
|
|
1354
|
+
check_code_type(code_type, "cuBLASDx")
|
|
1355
|
+
assert tensor._MM is not None
|
|
1356
|
+
|
|
1357
|
+
MM = tensor._MM
|
|
1358
|
+
|
|
1359
|
+
handle = _blas_tensors_handle(MM)
|
|
1360
|
+
tensor_handler = tensor._get_descriptor()
|
|
1361
|
+
|
|
1362
|
+
return get_function_code(handle, mathdx.CublasdxDeviceFunctionType.CLEAR, [tensor_handler.descriptor], code_type)
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
def compile_blas_axpby(
|
|
1366
|
+
x_tensor: _BlasMatmulLayout,
|
|
1367
|
+
y_tensor: _BlasMatmulLayout,
|
|
1368
|
+
code_type: CodeType,
|
|
1369
|
+
):
|
|
1370
|
+
check_code_type(code_type, "cuBLASDx")
|
|
1371
|
+
assert x_tensor._MM == y_tensor._MM
|
|
1372
|
+
assert x_tensor._MM is not None
|
|
1373
|
+
|
|
1374
|
+
MM = x_tensor._MM
|
|
1375
|
+
|
|
1376
|
+
handle = _blas_tensors_handle(MM)
|
|
1377
|
+
x_handler = x_tensor._get_descriptor()
|
|
1378
|
+
y_handler = y_tensor._get_descriptor()
|
|
1379
|
+
|
|
1380
|
+
return get_function_code(
|
|
1381
|
+
handle, mathdx.CublasdxDeviceFunctionType.AXPBY, [x_handler.descriptor, y_handler.descriptor], code_type
|
|
1382
|
+
)
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
def _compile_blas_partitioner_function(
|
|
1386
|
+
MM: Matmul,
|
|
1387
|
+
code_type: CodeType,
|
|
1388
|
+
function: mathdx.CublasdxDeviceFunctionType,
|
|
1389
|
+
):
|
|
1390
|
+
check_code_type(code_type, "cuBLASDx")
|
|
1391
|
+
|
|
1392
|
+
handle = _blas_tensors_handle(MM)
|
|
1393
|
+
tensor_handle = generate_tensor(handle, "suggested_rmem_c")
|
|
1394
|
+
|
|
1395
|
+
return get_function_code(handle, function, [tensor_handle.descriptor], code_type)
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
def compile_blas_map_idx2crd_partitioner(
|
|
1399
|
+
MM: Matmul,
|
|
1400
|
+
code_type: CodeType,
|
|
1401
|
+
):
|
|
1402
|
+
return _compile_blas_partitioner_function(
|
|
1403
|
+
MM,
|
|
1404
|
+
code_type,
|
|
1405
|
+
mathdx.CublasdxDeviceFunctionType.MAP_IDX2CRD_PARTITIONER,
|
|
1406
|
+
)
|
|
1407
|
+
|
|
1408
|
+
|
|
1409
|
+
def compile_blas_is_thread_active(
|
|
1410
|
+
MM: Matmul,
|
|
1411
|
+
code_type: CodeType,
|
|
1412
|
+
):
|
|
1413
|
+
return _compile_blas_partitioner_function(
|
|
1414
|
+
MM,
|
|
1415
|
+
code_type,
|
|
1416
|
+
mathdx.CublasdxDeviceFunctionType.IS_THREAD_ACTIVE,
|
|
1417
|
+
)
|
|
1418
|
+
|
|
1419
|
+
|
|
1420
|
+
def compile_blas_is_predicated(
|
|
1421
|
+
MM: Matmul,
|
|
1422
|
+
code_type: CodeType,
|
|
1423
|
+
):
|
|
1424
|
+
return _compile_blas_partitioner_function(
|
|
1425
|
+
MM,
|
|
1426
|
+
code_type,
|
|
1427
|
+
mathdx.CublasdxDeviceFunctionType.IS_PREDICATED,
|
|
1428
|
+
)
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
def compile_blas_is_index_in_bounds(
|
|
1432
|
+
MM: Matmul,
|
|
1433
|
+
code_type: CodeType,
|
|
1434
|
+
):
|
|
1435
|
+
return _compile_blas_partitioner_function(
|
|
1436
|
+
MM,
|
|
1437
|
+
code_type,
|
|
1438
|
+
mathdx.CublasdxDeviceFunctionType.IS_INDEX_IN_BOUNDS,
|
|
1439
|
+
)
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
def compile_blas_device_pipeline_destroy(
|
|
1443
|
+
pipeline: DevicePipeline,
|
|
1444
|
+
code_type: CodeType,
|
|
1445
|
+
) -> tuple[Code, str]:
|
|
1446
|
+
assert isinstance(pipeline, DevicePipeline)
|
|
1447
|
+
|
|
1448
|
+
MM_descriptor = _blas_tensors_handle(pipeline.mm)
|
|
1449
|
+
pipeline_descriptor = _blas_device_pipeline_handle(pipeline)
|
|
1450
|
+
|
|
1451
|
+
code, symbol = generate_function_with_pipelines_code(
|
|
1452
|
+
MM_descriptor,
|
|
1453
|
+
mathdx.CublasdxDeviceFunctionType.DESTROY,
|
|
1454
|
+
(),
|
|
1455
|
+
(pipeline_descriptor,),
|
|
1456
|
+
code_type.cc,
|
|
1457
|
+
)
|
|
1458
|
+
|
|
1459
|
+
# Compile
|
|
1460
|
+
lto_fn = get_lto(code.descriptor)
|
|
1461
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1462
|
+
|
|
1463
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1464
|
+
|
|
1465
|
+
return lto, symbol
|
|
1466
|
+
|
|
1467
|
+
|
|
1468
|
+
def compile_blas_tile_pipeline_init(
|
|
1469
|
+
pipeline: TilePipeline,
|
|
1470
|
+
code_type: CodeType,
|
|
1471
|
+
):
|
|
1472
|
+
assert isinstance(pipeline, TilePipeline)
|
|
1473
|
+
assert isinstance(code_type, CodeType)
|
|
1474
|
+
|
|
1475
|
+
MM_descriptor = _blas_tensors_handle(pipeline.device_pipeline.mm)
|
|
1476
|
+
pipeline_descriptor = _blas_tile_pipeline_handle(pipeline)
|
|
1477
|
+
|
|
1478
|
+
code, symbol = generate_function_with_pipelines_code(
|
|
1479
|
+
MM_descriptor,
|
|
1480
|
+
mathdx.CublasdxDeviceFunctionType.CREATE,
|
|
1481
|
+
(),
|
|
1482
|
+
(pipeline_descriptor,),
|
|
1483
|
+
code_type.cc,
|
|
1484
|
+
)
|
|
1485
|
+
|
|
1486
|
+
# Compile
|
|
1487
|
+
lto_fn = get_lto(code.descriptor)
|
|
1488
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1489
|
+
|
|
1490
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1491
|
+
|
|
1492
|
+
return lto, symbol
|
|
1493
|
+
|
|
1494
|
+
|
|
1495
|
+
def compile_blas_device_pipeline_reset_tile(
|
|
1496
|
+
device_pipeline: DevicePipeline,
|
|
1497
|
+
tile_pipeline: TilePipeline,
|
|
1498
|
+
code_type: CodeType,
|
|
1499
|
+
):
|
|
1500
|
+
assert isinstance(device_pipeline, DevicePipeline)
|
|
1501
|
+
assert isinstance(tile_pipeline, TilePipeline)
|
|
1502
|
+
assert isinstance(code_type, CodeType)
|
|
1503
|
+
|
|
1504
|
+
MM_descriptor = _blas_tensors_handle(tile_pipeline.device_pipeline.mm)
|
|
1505
|
+
tile_pipeline_descriptor = _blas_tile_pipeline_handle(tile_pipeline)
|
|
1506
|
+
device_pipeline_descriptor = _blas_device_pipeline_handle(device_pipeline)
|
|
1507
|
+
|
|
1508
|
+
code, symbol = generate_function_with_pipelines_code(
|
|
1509
|
+
MM_descriptor,
|
|
1510
|
+
mathdx.CublasdxDeviceFunctionType.RESET,
|
|
1511
|
+
(),
|
|
1512
|
+
(device_pipeline_descriptor, tile_pipeline_descriptor),
|
|
1513
|
+
code_type.cc,
|
|
1514
|
+
)
|
|
1515
|
+
|
|
1516
|
+
# Compile
|
|
1517
|
+
lto_fn = get_lto(code.descriptor)
|
|
1518
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1519
|
+
|
|
1520
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1521
|
+
|
|
1522
|
+
return lto, symbol
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
def compile_blas_tile_pipeline_destroy(
|
|
1526
|
+
pipeline: TilePipeline,
|
|
1527
|
+
code_type: CodeType,
|
|
1528
|
+
):
|
|
1529
|
+
assert isinstance(pipeline, TilePipeline)
|
|
1530
|
+
assert isinstance(code_type, CodeType)
|
|
1531
|
+
|
|
1532
|
+
MM_descriptor = _blas_tensors_handle(pipeline.device_pipeline.mm)
|
|
1533
|
+
pipeline_descriptor = _blas_tile_pipeline_handle(pipeline)
|
|
1534
|
+
|
|
1535
|
+
code, symbol = generate_function_with_pipelines_code(
|
|
1536
|
+
MM_descriptor,
|
|
1537
|
+
mathdx.CublasdxDeviceFunctionType.DESTROY,
|
|
1538
|
+
(),
|
|
1539
|
+
(pipeline_descriptor,),
|
|
1540
|
+
code_type.cc,
|
|
1541
|
+
)
|
|
1542
|
+
|
|
1543
|
+
# Compile
|
|
1544
|
+
lto_fn = get_lto(code.descriptor)
|
|
1545
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1546
|
+
|
|
1547
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1548
|
+
|
|
1549
|
+
return lto, symbol
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
def compile_blas_accumulator_init(
|
|
1553
|
+
layout: Layout,
|
|
1554
|
+
code_type: CodeType,
|
|
1555
|
+
):
|
|
1556
|
+
assert isinstance(layout, _BlasMatmulLayout)
|
|
1557
|
+
assert layout.accumulator
|
|
1558
|
+
assert isinstance(code_type, CodeType)
|
|
1559
|
+
|
|
1560
|
+
MM_descriptor = _blas_tensors_handle(layout._MM)
|
|
1561
|
+
opaque_tensor_descriptor = layout._get_descriptor()
|
|
1562
|
+
|
|
1563
|
+
code, symbol = generate_function_code(
|
|
1564
|
+
MM_descriptor,
|
|
1565
|
+
mathdx.CublasdxDeviceFunctionType.CREATE,
|
|
1566
|
+
[opaque_tensor_descriptor.descriptor],
|
|
1567
|
+
code_type.cc,
|
|
1568
|
+
)
|
|
1569
|
+
|
|
1570
|
+
# Compile
|
|
1571
|
+
lto_fn = get_lto(code.descriptor)
|
|
1572
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1573
|
+
|
|
1574
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1575
|
+
|
|
1576
|
+
return lto, symbol
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
def compile_blas_tile_pipeline_execute(
|
|
1580
|
+
pipeline: TilePipeline,
|
|
1581
|
+
accumulator: Layout,
|
|
1582
|
+
code_type: CodeType,
|
|
1583
|
+
):
|
|
1584
|
+
assert isinstance(accumulator, _BlasMatmulLayout)
|
|
1585
|
+
assert accumulator.accumulator
|
|
1586
|
+
assert isinstance(code_type, CodeType)
|
|
1587
|
+
|
|
1588
|
+
MM_descriptor = _blas_tensors_handle(pipeline.device_pipeline.mm)
|
|
1589
|
+
tile_pipeline_descriptor = _blas_tile_pipeline_handle(pipeline)
|
|
1590
|
+
tensor_descriptor = accumulator._get_descriptor().descriptor
|
|
1591
|
+
|
|
1592
|
+
code, symbol = generate_function_with_pipelines_code(
|
|
1593
|
+
MM_descriptor,
|
|
1594
|
+
mathdx.CublasdxDeviceFunctionType.EXECUTE,
|
|
1595
|
+
(tensor_descriptor,),
|
|
1596
|
+
(tile_pipeline_descriptor,),
|
|
1597
|
+
code_type.cc,
|
|
1598
|
+
)
|
|
1599
|
+
|
|
1600
|
+
# Compile
|
|
1601
|
+
lto_fn = get_lto(code.descriptor)
|
|
1602
|
+
isa_version = get_isa_version(code.descriptor)
|
|
1603
|
+
|
|
1604
|
+
lto = Code(code_type, isa_version, lto_fn)
|
|
1605
|
+
|
|
1606
|
+
return lto, symbol
|