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,212 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This module defines a JIT runtime for the universal sparse tensor (UST).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["launch_kernel"]
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
from nvmath.internal import utils
|
|
15
|
+
|
|
16
|
+
# TODO: support cuda.core >=0.5.0
|
|
17
|
+
try:
|
|
18
|
+
from cuda.core import (
|
|
19
|
+
LaunchConfig,
|
|
20
|
+
Linker,
|
|
21
|
+
LinkerOptions,
|
|
22
|
+
ObjectCode,
|
|
23
|
+
Program,
|
|
24
|
+
ProgramOptions,
|
|
25
|
+
launch,
|
|
26
|
+
)
|
|
27
|
+
except ImportError:
|
|
28
|
+
from cuda.core.experimental import (
|
|
29
|
+
LaunchConfig,
|
|
30
|
+
Linker,
|
|
31
|
+
LinkerOptions,
|
|
32
|
+
ObjectCode,
|
|
33
|
+
Program,
|
|
34
|
+
ProgramOptions,
|
|
35
|
+
launch,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _check_numba_available():
|
|
40
|
+
try:
|
|
41
|
+
import numba # noqa: F401
|
|
42
|
+
except ModuleNotFoundError as e:
|
|
43
|
+
raise RuntimeError("Numba is required to compile user-defined Python functions provided to the UST APIs.") from e
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def compile_python_function(
|
|
47
|
+
function,
|
|
48
|
+
function_name,
|
|
49
|
+
signature,
|
|
50
|
+
*,
|
|
51
|
+
representation="ltoir",
|
|
52
|
+
compute_capability=None,
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Compile the Python function to an intermediate representation using Numba.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
function: The Python function to compile.
|
|
59
|
+
function_name: The symbol to use for the function name.
|
|
60
|
+
signature: the function signature as a sequence (return_type, *parameter_types). The
|
|
61
|
+
type names should correspond to the C type names recognized by Numba.
|
|
62
|
+
representation: the intermediate representation ("ltoir", "ptx").
|
|
63
|
+
compute_capability: the device compute capability. If not specified, the
|
|
64
|
+
current devices CC will be used.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The compiled IR.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
_check_numba_available()
|
|
71
|
+
|
|
72
|
+
import numba
|
|
73
|
+
import numba.cuda
|
|
74
|
+
|
|
75
|
+
user_return_type, *user_arg_types = signature
|
|
76
|
+
|
|
77
|
+
return_type = getattr(numba.cuda.types.types, user_return_type)
|
|
78
|
+
|
|
79
|
+
arg_types = []
|
|
80
|
+
for arg_type in user_arg_types:
|
|
81
|
+
m = re.match(r"(\w+)((\[:\])|( *(\*)))?", arg_type)
|
|
82
|
+
assert m is not None, "Internal error."
|
|
83
|
+
t = getattr(numba.cuda.types.types, m.group(1))
|
|
84
|
+
if m.group(2) is not None:
|
|
85
|
+
if m.group(3) == "[:]":
|
|
86
|
+
t = t[:]
|
|
87
|
+
elif m.group(5) == "*":
|
|
88
|
+
t = numba.cuda.types.types.voidptr
|
|
89
|
+
else:
|
|
90
|
+
raise AssertionError("Internal error.")
|
|
91
|
+
arg_types.append(t)
|
|
92
|
+
|
|
93
|
+
signature = numba.core.typing.signature(return_type, *arg_types)
|
|
94
|
+
|
|
95
|
+
return numba.cuda.compile(
|
|
96
|
+
function,
|
|
97
|
+
signature,
|
|
98
|
+
debug=None,
|
|
99
|
+
lineinfo=False,
|
|
100
|
+
device=True,
|
|
101
|
+
fastmath=False,
|
|
102
|
+
cc=compute_capability,
|
|
103
|
+
opt=True,
|
|
104
|
+
abi="c",
|
|
105
|
+
abi_info={"abi_name": function_name},
|
|
106
|
+
output=representation,
|
|
107
|
+
forceinline=False,
|
|
108
|
+
launch_bounds=None,
|
|
109
|
+
)[0]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def compile_cpp_and_link(
|
|
113
|
+
*,
|
|
114
|
+
src_code=None,
|
|
115
|
+
object_code=None,
|
|
116
|
+
function_name,
|
|
117
|
+
compiler_options=None,
|
|
118
|
+
linker_options=None,
|
|
119
|
+
intermediate_type="ltoir",
|
|
120
|
+
target_type="cubin",
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Compile the source code (if provided) and link with the intermediate code (if provided).
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
src_code: A string or sequence of strings containing the C++ source code.
|
|
127
|
+
object_code: A byte-string or sequence of byte-string objects to be linked
|
|
128
|
+
along with the source code.
|
|
129
|
+
function_name: symbol name to use for the compiled and linked function.
|
|
130
|
+
compiler_options: the compiler options to use as a
|
|
131
|
+
:class:`cuda.core.ProgramOptions` object. Alternatively, a dictionary containing
|
|
132
|
+
the options can be provided.
|
|
133
|
+
linker_options: the linker options to use as a
|
|
134
|
+
:class:`cuda.core.LinkerOptions` object. Alternatively, a dictionary containing
|
|
135
|
+
the options can be provided.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
The linked kernel.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
assert not (src_code is None and object_code is None), "Internal error."
|
|
142
|
+
|
|
143
|
+
compiler_options = utils.check_or_create_options(ProgramOptions, compiler_options, "Compiler Options")
|
|
144
|
+
linker_options = utils.check_or_create_options(LinkerOptions, linker_options, "Linker Options")
|
|
145
|
+
|
|
146
|
+
if isinstance(src_code, str):
|
|
147
|
+
src_code = [src_code]
|
|
148
|
+
else:
|
|
149
|
+
if src_code is not None and not isinstance(src_code, Sequence):
|
|
150
|
+
raise TypeError("The source code type 'type(src_code)' must be a string or a sequence of strings.")
|
|
151
|
+
|
|
152
|
+
# Handle the case where no source code is provided.
|
|
153
|
+
if src_code is None:
|
|
154
|
+
src_code = []
|
|
155
|
+
|
|
156
|
+
# Compile source code to LTO-IR.
|
|
157
|
+
compiled_code = [Program(s, "c++", options=compiler_options).compile(intermediate_type) for s in src_code]
|
|
158
|
+
|
|
159
|
+
if isinstance(object_code, bytes):
|
|
160
|
+
object_code = [object_code]
|
|
161
|
+
else:
|
|
162
|
+
if object_code is not None and not isinstance(object_code, Sequence):
|
|
163
|
+
raise TypeError(
|
|
164
|
+
"The intermediate code type 'type(object_code)' must be a byte-string or a sequence of byte-strings."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
assert intermediate_type == "ltoir", "Internal error."
|
|
168
|
+
|
|
169
|
+
# Handle the case where no object code is provided.
|
|
170
|
+
if object_code is None:
|
|
171
|
+
object_code = []
|
|
172
|
+
|
|
173
|
+
object_code = [ObjectCode.from_ltoir(o) for o in object_code]
|
|
174
|
+
|
|
175
|
+
# Link all objects together.
|
|
176
|
+
linker = Linker(*(compiled_code + object_code), options=linker_options)
|
|
177
|
+
linked_code = linker.link(target_type=target_type)
|
|
178
|
+
|
|
179
|
+
# Extract kernel entry by function name.
|
|
180
|
+
return linked_code.get_kernel(function_name)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# TODO: take grid instead of problem size.
|
|
184
|
+
def launch_kernel(kernel, parameters, problem_size, *, device_id, stream_holder, blocking=True):
|
|
185
|
+
"""
|
|
186
|
+
Launch the kernel on the specified device and stream.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
kernel: the CUDA kernel to launch.
|
|
190
|
+
parameters: the kernel arguments as a sequence or None.
|
|
191
|
+
problem_size: the size of the problem (work to divide among threads).
|
|
192
|
+
device_id: the device ID on which to launch the kernel.
|
|
193
|
+
stream_holder: a `nvmath.internal.utils.StreamHolder` object encapsulating the
|
|
194
|
+
stream to use.
|
|
195
|
+
blocking: if True, the call blocks.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
if problem_size == 0:
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# Prepare grid.
|
|
202
|
+
threads_per_block = min(1024, problem_size)
|
|
203
|
+
batch_size = (problem_size + threads_per_block - 1) // threads_per_block
|
|
204
|
+
grid = LaunchConfig(grid=batch_size, block=threads_per_block)
|
|
205
|
+
|
|
206
|
+
# Launch the kernel.
|
|
207
|
+
with utils.device_ctx(device_id):
|
|
208
|
+
launch(stream_holder.obj, grid, kernel, *parameters)
|
|
209
|
+
|
|
210
|
+
# TODO: make this non-blocking by default.
|
|
211
|
+
if blocking:
|
|
212
|
+
stream_holder.obj.sync()
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This module defines a kernel generator for various sparse tensor operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"KernelGen",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
import time
|
|
14
|
+
|
|
15
|
+
from cuda import pathfinder
|
|
16
|
+
|
|
17
|
+
from ._utils import COMPLEX_PRECISION, Cache, type_str
|
|
18
|
+
from .semiring_ops import (
|
|
19
|
+
epilog_impl,
|
|
20
|
+
prolog_a_impl,
|
|
21
|
+
prolog_b_impl,
|
|
22
|
+
prolog_c_impl,
|
|
23
|
+
prolog_epilog_decl,
|
|
24
|
+
semiring_add_impl,
|
|
25
|
+
semiring_atomic_add_impl,
|
|
26
|
+
semiring_mul_impl,
|
|
27
|
+
semiring_ops_decl,
|
|
28
|
+
)
|
|
29
|
+
from .tensor_emitter import emit_matmul
|
|
30
|
+
from .tensor_jit import compile_cpp_and_link
|
|
31
|
+
|
|
32
|
+
# Maps matmul(a,b,c) to pre-defined kernel source code. All kernels should adhere to the
|
|
33
|
+
# parameter passing conventions for each of the three UST parameters.
|
|
34
|
+
_tensor_matmul_kernels = {
|
|
35
|
+
# (format_a, format_b, format_c, transpose_a, transpose_b)
|
|
36
|
+
("DIAI", "DenseVector", "DenseVector", False, False): """
|
|
37
|
+
extern "C" __global__ void matmul(
|
|
38
|
+
const POS* __restrict__ pos0,
|
|
39
|
+
const CRD* __restrict__ diags,
|
|
40
|
+
const VAL* __restrict__ A,
|
|
41
|
+
unsigned long m,
|
|
42
|
+
unsigned long n,
|
|
43
|
+
unsigned long l0,
|
|
44
|
+
unsigned long l1,
|
|
45
|
+
const VAL *__restrict__ B,
|
|
46
|
+
VAL *__restrict__ C) {
|
|
47
|
+
const unsigned long tidx = threadIdx.x;
|
|
48
|
+
const unsigned long bidx = blockIdx.x;
|
|
49
|
+
const unsigned long i = bidx * blockDim.x + tidx;
|
|
50
|
+
if (i < m) {
|
|
51
|
+
CTP acc = prolog_c(static_cast<CTP>(C[i]));
|
|
52
|
+
const POS numDiags = pos0[1];
|
|
53
|
+
for (unsigned long d = 0, di = i; d < numDiags; d++, di += m) {
|
|
54
|
+
const long j = i + diags[d];
|
|
55
|
+
if (0 <= j && j < n) {
|
|
56
|
+
acc = add(acc, mul(prolog_a(static_cast<CTP>(A[di])),
|
|
57
|
+
prolog_b(static_cast<CTP>(B[j]))));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
C[i] = static_cast<VAL>(epilog(acc));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
""",
|
|
64
|
+
("DIAJ", "DenseVector", "DenseVector", False, False): """
|
|
65
|
+
extern "C" __global__ void matmul(
|
|
66
|
+
const POS* __restrict__ pos0,
|
|
67
|
+
const CRD* __restrict__ diags,
|
|
68
|
+
const VAL* __restrict__ A,
|
|
69
|
+
unsigned long m,
|
|
70
|
+
unsigned long n,
|
|
71
|
+
unsigned long l0,
|
|
72
|
+
unsigned long l1,
|
|
73
|
+
const VAL *__restrict__ B,
|
|
74
|
+
VAL *__restrict__ C) {
|
|
75
|
+
const unsigned long tidx = threadIdx.x;
|
|
76
|
+
const unsigned long bidx = blockIdx.x;
|
|
77
|
+
const unsigned long i = bidx * blockDim.x + tidx;
|
|
78
|
+
if (i < m) {
|
|
79
|
+
CTP acc = prolog_c(static_cast<CTP>(C[i]));
|
|
80
|
+
const POS numDiags = pos0[1];
|
|
81
|
+
for (unsigned long d = 0, di = 0; d < numDiags; d++, di += n) {
|
|
82
|
+
const long j = i + diags[d];
|
|
83
|
+
if (0 <= j && j < n) {
|
|
84
|
+
acc = add(acc, mul(static_cast<CTP>(prolog_a(A[di + j])),
|
|
85
|
+
static_cast<CTP>(prolog_b(B[j]))));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
C[i] = static_cast<VAL>(epilog(acc));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
""",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _set_user_or_default_code(*, user_code, default_code, default_prolog, src_code_list, obj_code_list):
|
|
96
|
+
"""
|
|
97
|
+
Args:
|
|
98
|
+
user_code: The user-provided LTO-IR as a bytes object or CUDA C++ source code
|
|
99
|
+
string.
|
|
100
|
+
default_code: The CUDA C++ source code that will be used if the user-provided
|
|
101
|
+
code is None.
|
|
102
|
+
default_prolog: The prolog to the CUDA C++ source code that will be used if the
|
|
103
|
+
user-provided code is None.
|
|
104
|
+
src_code_list: The list to which the source code will be appended to.
|
|
105
|
+
obj_code_list: The list to which the LTO-IR code will be appended to.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The pair (src_code_list, obj_code_list)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
if user_code is not None:
|
|
112
|
+
if isinstance(user_code, str):
|
|
113
|
+
target = src_code_list
|
|
114
|
+
elif isinstance(user_code, bytes):
|
|
115
|
+
target = obj_code_list
|
|
116
|
+
else:
|
|
117
|
+
raise AssertionError("Internal error.")
|
|
118
|
+
target.append(user_code)
|
|
119
|
+
return src_code_list, obj_code_list
|
|
120
|
+
|
|
121
|
+
assert default_code is not None and isinstance(default_code, str), "Internal error."
|
|
122
|
+
|
|
123
|
+
source_code = f"{default_prolog} {default_code}"
|
|
124
|
+
src_code_list.append(source_code)
|
|
125
|
+
|
|
126
|
+
return src_code_list, obj_code_list
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class KernelGen:
|
|
130
|
+
"""
|
|
131
|
+
This class defines a kernel generator for various sparse tensor operations.
|
|
132
|
+
The generated kernels can be JITted on-demand. Caching avoids recompilation
|
|
133
|
+
on subsequent uses.
|
|
134
|
+
|
|
135
|
+
The generation uses:
|
|
136
|
+
(1) kernel lookup from a collection of pre-defined kernels
|
|
137
|
+
(2) kernel generated by a sparse emitter
|
|
138
|
+
|
|
139
|
+
Clients can easily add new pre-defined kernels in the table above (for example,
|
|
140
|
+
by hand optimizing the automatically generated cuda code from the sparse emitter).
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(self, debug=False):
|
|
144
|
+
self._matmul_kernels_cache = Cache()
|
|
145
|
+
self._debug = debug
|
|
146
|
+
|
|
147
|
+
def generate_matmul(
|
|
148
|
+
self,
|
|
149
|
+
a,
|
|
150
|
+
b,
|
|
151
|
+
c,
|
|
152
|
+
compute_type,
|
|
153
|
+
prologs=None,
|
|
154
|
+
epilog=None,
|
|
155
|
+
semiring=None,
|
|
156
|
+
transpose_a=False,
|
|
157
|
+
transpose_b=False,
|
|
158
|
+
arch=None,
|
|
159
|
+
):
|
|
160
|
+
"""
|
|
161
|
+
Matmul semantics:
|
|
162
|
+
|
|
163
|
+
Dot Product: If both inputs are 1-dimensional, it computes the dot
|
|
164
|
+
product (inner product).
|
|
165
|
+
|
|
166
|
+
Matrix-Vector Product: If the first input is a 2D tensor (matrix) and
|
|
167
|
+
the second is a 1D tensor (vector), it performs a matrix-vector
|
|
168
|
+
multiplication.
|
|
169
|
+
|
|
170
|
+
Vector-Matrix Product: If the first input is a 1D tensor and the second
|
|
171
|
+
is a 2D tensor, it performs a vector-matrix multiplication.
|
|
172
|
+
|
|
173
|
+
Matrix-Matrix Product: If both inputs are 2D tensors, it performs
|
|
174
|
+
standard matrix multiplication, requiring the number of columns in
|
|
175
|
+
the first matrix to equal the number of rows in the second.
|
|
176
|
+
|
|
177
|
+
Batched Matrix Product: If either input has more than two dimensions,
|
|
178
|
+
the extra leading dimensions are treated as "batch dimensions" and it
|
|
179
|
+
performs a batched matrix multiplication over the last two dimensions.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
format_a = a.tensor_format.name
|
|
183
|
+
format_b = b.tensor_format.name
|
|
184
|
+
format_c = c.tensor_format.name
|
|
185
|
+
vtp = type_str(a.dtype)
|
|
186
|
+
itp = type_str(a.index_type)
|
|
187
|
+
# Get user code.
|
|
188
|
+
if semiring is None:
|
|
189
|
+
user_mul, user_add, user_atomic_add = None, None, None
|
|
190
|
+
else:
|
|
191
|
+
user_mul, user_add, user_atomic_add = semiring.get("mul"), semiring.get("add"), semiring.get("atomic_add")
|
|
192
|
+
if prologs is None:
|
|
193
|
+
user_prolog_a, user_prolog_b, user_prolog_c = None, None, None
|
|
194
|
+
else:
|
|
195
|
+
user_prolog_a, user_prolog_b, user_prolog_c = prologs.get("a"), prologs.get("b"), prologs.get("c")
|
|
196
|
+
# Try cache lookup.
|
|
197
|
+
key = (
|
|
198
|
+
format_a,
|
|
199
|
+
format_b,
|
|
200
|
+
format_c,
|
|
201
|
+
vtp,
|
|
202
|
+
itp,
|
|
203
|
+
compute_type,
|
|
204
|
+
user_mul,
|
|
205
|
+
user_add,
|
|
206
|
+
user_atomic_add,
|
|
207
|
+
user_prolog_a,
|
|
208
|
+
user_prolog_b,
|
|
209
|
+
user_prolog_c,
|
|
210
|
+
epilog,
|
|
211
|
+
transpose_a,
|
|
212
|
+
transpose_b,
|
|
213
|
+
arch,
|
|
214
|
+
)
|
|
215
|
+
kernel = self._matmul_kernels_cache.get(key)
|
|
216
|
+
if kernel is None:
|
|
217
|
+
# Nothing in cache, try kernel lookup.
|
|
218
|
+
typeless_key = (format_a, format_b, format_c, transpose_a, transpose_b)
|
|
219
|
+
code = _tensor_matmul_kernels.get(typeless_key)
|
|
220
|
+
|
|
221
|
+
# Prepare prolog.
|
|
222
|
+
ctp = type_str(compute_type)
|
|
223
|
+
if a.dtype in ["float8_e4m3fn", "float8_e5m2"]:
|
|
224
|
+
prolog = f"#include <cuda_fp8.h>\nusing ATP = {ctp};\nusing CTP = {ctp};\n" # TODO: ATP=vtp
|
|
225
|
+
elif a.dtype == "float16":
|
|
226
|
+
prolog = f"#include <cuda_fp16.h>\nusing ATP = {vtp};\nusing CTP = {ctp};\n"
|
|
227
|
+
elif a.dtype == "bfloat16":
|
|
228
|
+
prolog = f"#include <cuda_bf16.h>\nusing ATP = {vtp};\nusing CTP = {ctp};\n"
|
|
229
|
+
elif a.dtype in ["complex64", "complex128"]:
|
|
230
|
+
prolog = f"#include <cuda/std/complex>\nusing ATP = {COMPLEX_PRECISION[a.dtype]};\nusing CTP = {ctp};\n"
|
|
231
|
+
else:
|
|
232
|
+
prolog = f"using ATP = {vtp};\nusing CTP = {ctp};\n"
|
|
233
|
+
|
|
234
|
+
# Use kernel lookup or emitter.
|
|
235
|
+
if code is not None:
|
|
236
|
+
# (1) Kernel lookup successful. Inject types into the typeless kernel.
|
|
237
|
+
source = (
|
|
238
|
+
f"{prolog}\nusing VAL = {vtp};\nusing POS = {itp};\n"
|
|
239
|
+
f"using CRD = {itp};\n{semiring_ops_decl}{prolog_epilog_decl}{code}"
|
|
240
|
+
)
|
|
241
|
+
else:
|
|
242
|
+
if user_prolog_c is not None or epilog is not None:
|
|
243
|
+
raise NotImplementedError(
|
|
244
|
+
"The code generation (emitter) path does not currently support \
|
|
245
|
+
prolog for the `c` operand or epilog."
|
|
246
|
+
)
|
|
247
|
+
# (2) Sparse emitter. Emits proper types.
|
|
248
|
+
source = emit_matmul(a, b, c, ctp, transpose_a, transpose_b)
|
|
249
|
+
|
|
250
|
+
# The source and object code lists.
|
|
251
|
+
src_code_list, obj_code_list = [source], []
|
|
252
|
+
|
|
253
|
+
# User-provided or default semiring mul operation.
|
|
254
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
255
|
+
user_code=user_mul,
|
|
256
|
+
default_code=semiring_mul_impl,
|
|
257
|
+
default_prolog=prolog,
|
|
258
|
+
src_code_list=src_code_list,
|
|
259
|
+
obj_code_list=obj_code_list,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# User-provided or default semiring add operation.
|
|
263
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
264
|
+
user_code=user_add,
|
|
265
|
+
default_code=semiring_add_impl,
|
|
266
|
+
default_prolog=prolog,
|
|
267
|
+
src_code_list=src_code_list,
|
|
268
|
+
obj_code_list=obj_code_list,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# User-provided or default semiring atomic add operation.
|
|
272
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
273
|
+
user_code=user_atomic_add,
|
|
274
|
+
default_code=semiring_atomic_add_impl,
|
|
275
|
+
default_prolog=prolog,
|
|
276
|
+
src_code_list=src_code_list,
|
|
277
|
+
obj_code_list=obj_code_list,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# User-provided or default prolog operation on A.
|
|
281
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
282
|
+
user_code=user_prolog_a,
|
|
283
|
+
default_code=prolog_a_impl,
|
|
284
|
+
default_prolog=prolog,
|
|
285
|
+
src_code_list=src_code_list,
|
|
286
|
+
obj_code_list=obj_code_list,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# User-provided or default prolog operation on B.
|
|
290
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
291
|
+
user_code=user_prolog_b,
|
|
292
|
+
default_code=prolog_b_impl,
|
|
293
|
+
default_prolog=prolog,
|
|
294
|
+
src_code_list=src_code_list,
|
|
295
|
+
obj_code_list=obj_code_list,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# User-provided or default prolog operation on C.
|
|
299
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
300
|
+
user_code=user_prolog_c,
|
|
301
|
+
default_code=prolog_c_impl,
|
|
302
|
+
default_prolog=prolog,
|
|
303
|
+
src_code_list=src_code_list,
|
|
304
|
+
obj_code_list=obj_code_list,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# User-provided or default epilog operation.
|
|
308
|
+
src_code_list, obj_code_list = _set_user_or_default_code(
|
|
309
|
+
user_code=epilog,
|
|
310
|
+
default_code=epilog_impl,
|
|
311
|
+
default_prolog=prolog,
|
|
312
|
+
src_code_list=src_code_list,
|
|
313
|
+
obj_code_list=obj_code_list,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if self._debug:
|
|
317
|
+
print("\n==> Compiling matmul()\n")
|
|
318
|
+
for s in src_code_list:
|
|
319
|
+
print(s)
|
|
320
|
+
print("/////////////////////\n")
|
|
321
|
+
t1 = time.perf_counter_ns()
|
|
322
|
+
|
|
323
|
+
# Compile and link matmul function. Cache the result.
|
|
324
|
+
complex_path = pathfinder.find_nvidia_header_directory("cccl")
|
|
325
|
+
narrow_prec_path = pathfinder.find_nvidia_header_directory("cudart")
|
|
326
|
+
compiler_options = {
|
|
327
|
+
"std": "c++17",
|
|
328
|
+
"link_time_optimization": True,
|
|
329
|
+
"arch": arch,
|
|
330
|
+
"include_path": [complex_path, narrow_prec_path],
|
|
331
|
+
}
|
|
332
|
+
linker_options = {"link_time_optimization": True}
|
|
333
|
+
kernel = compile_cpp_and_link(
|
|
334
|
+
src_code=src_code_list,
|
|
335
|
+
object_code=obj_code_list,
|
|
336
|
+
function_name="matmul",
|
|
337
|
+
compiler_options=compiler_options,
|
|
338
|
+
linker_options=linker_options,
|
|
339
|
+
)
|
|
340
|
+
assert kernel is not None, "Internal error."
|
|
341
|
+
self._matmul_kernels_cache[key] = kernel
|
|
342
|
+
|
|
343
|
+
if self._debug:
|
|
344
|
+
t2 = time.perf_counter_ns()
|
|
345
|
+
tt = (t2 - t1) / 1000.0 # ns -> us
|
|
346
|
+
print(f"<== Compiled matmul() in {tt:10.2f} us.\n")
|
|
347
|
+
|
|
348
|
+
return kernel
|