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