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,553 @@
|
|
|
1
|
+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This module defines a CUDA emitter for the universal sparse tensor (UST).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = []
|
|
10
|
+
|
|
11
|
+
from enum import IntEnum
|
|
12
|
+
from io import StringIO
|
|
13
|
+
|
|
14
|
+
from ._semiring import prolog_epilog_decl, semiring_ops_decl
|
|
15
|
+
from ._utils import COMPLEX_PRECISION, type_str
|
|
16
|
+
from .tensor_format import Add, Dimension, Divide, LevelExpr, LevelFormat, Modulo, Subtract
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _EmitAction(IntEnum):
|
|
20
|
+
APPLY = 0 # apply value
|
|
21
|
+
DOT = 1 # c = A(i) b(i)
|
|
22
|
+
VM = 2 # c(j) = A(i) B(i,j)
|
|
23
|
+
VM_T = 3 # c(j) = A(i) B(i,j)^T
|
|
24
|
+
MV = 4 # c(i) = A(i,j) b(j)
|
|
25
|
+
BMM = 5 # C(i,k) = A(i,j) B(j,k) or C(b0.., i,k) = A(b0.., i,j) B(j,k)
|
|
26
|
+
BMM_T = 6 # C(i,k) = A(i,j) B(j,k)^T or C(b0.., i,k) = A(b0.., i,j) B(j,k)^T
|
|
27
|
+
BMBM = 7 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
|
|
28
|
+
BMBM_T = 8 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)^T (last two dimensions)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _transposeB(action):
|
|
32
|
+
if action == _EmitAction.DOT:
|
|
33
|
+
return _EmitAction.DOT
|
|
34
|
+
if action == _EmitAction.VM:
|
|
35
|
+
return _EmitAction.VM_T
|
|
36
|
+
if action == _EmitAction.VM_T:
|
|
37
|
+
return _EmitAction.VM
|
|
38
|
+
if action == _EmitAction.BMM:
|
|
39
|
+
return _EmitAction.BMM_T
|
|
40
|
+
if action == _EmitAction.BMM_T:
|
|
41
|
+
return _EmitAction.BMM
|
|
42
|
+
if action == _EmitAction.BMBM:
|
|
43
|
+
return _EmitAction.BMBM_T
|
|
44
|
+
if action == _EmitAction.BMBM_T:
|
|
45
|
+
return _EmitAction.BMBM
|
|
46
|
+
raise ValueError(f"Unexpected transposition of {action}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _find_range(litems, expr1, expr2):
|
|
50
|
+
for rl, (k, v) in enumerate(litems):
|
|
51
|
+
if v == LevelFormat.RANGE and k in (expr1, expr2):
|
|
52
|
+
return rl, k
|
|
53
|
+
raise ValueError(f"Cannot find {expr1} or {expr2} in levels")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _emit_lvl2dim(tensor, indent, stream):
|
|
57
|
+
"""Private method to translate levels to dimensions."""
|
|
58
|
+
litems = tensor.tensor_format.levels.items()
|
|
59
|
+
for lvl, (k, fmt) in enumerate(litems):
|
|
60
|
+
if isinstance(fmt, tuple):
|
|
61
|
+
fmt, _ = fmt
|
|
62
|
+
if isinstance(k, Dimension):
|
|
63
|
+
di = tensor.tensor_format.dimensions.index(k)
|
|
64
|
+
print(f"{indent}d{di} = l{lvl};", file=stream)
|
|
65
|
+
elif isinstance(k.operator, Add):
|
|
66
|
+
rl, re = _find_range(litems, k.expression1, k.expression2)
|
|
67
|
+
if re == k.expression2:
|
|
68
|
+
i = tensor.tensor_format.dimensions.index(k.expression1)
|
|
69
|
+
print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
|
|
70
|
+
else:
|
|
71
|
+
assert re == k.expression1
|
|
72
|
+
i = tensor.tensor_format.dimensions.index(k.expression2)
|
|
73
|
+
print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
|
|
74
|
+
elif isinstance(k.operator, Subtract):
|
|
75
|
+
rl, re = _find_range(litems, k.expression1, k.expression2)
|
|
76
|
+
if re == k.expression2:
|
|
77
|
+
i = tensor.tensor_format.dimensions.index(k.expression1)
|
|
78
|
+
print(f"{indent}d{i} = l{rl} + l{lvl};", file=stream)
|
|
79
|
+
else:
|
|
80
|
+
assert re == k.expression1
|
|
81
|
+
i = tensor.tensor_format.dimensions.index(k.expression2)
|
|
82
|
+
print(f"{indent}d{i} = l{rl} - l{lvl};", file=stream)
|
|
83
|
+
elif isinstance(k.operator, Divide):
|
|
84
|
+
di = tensor.tensor_format.dimensions.index(k.expression1)
|
|
85
|
+
print(f"{indent}d{di} = l{lvl} * {k.expression2};", file=stream)
|
|
86
|
+
elif isinstance(k.operator, Modulo):
|
|
87
|
+
di = tensor.tensor_format.dimensions.index(k.expression1)
|
|
88
|
+
print(f"{indent}d{di} += l{lvl};", file=stream) # seen second
|
|
89
|
+
else:
|
|
90
|
+
raise AssertionError(f"Unsupported: {k}")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _emit_types(tensor, ctp, stream):
|
|
94
|
+
"""Private method to emit type macros."""
|
|
95
|
+
vtp = type_str(tensor.dtype)
|
|
96
|
+
itp = type_str(tensor.index_type)
|
|
97
|
+
atp = vtp
|
|
98
|
+
|
|
99
|
+
if tensor.dtype in ["float8_e4m3fn", "float8_e5m2"]:
|
|
100
|
+
print("#include <cuda_fp8.h>\n", file=stream)
|
|
101
|
+
atp = ctp # TODO: remove, but to make it compile atomic
|
|
102
|
+
elif tensor.dtype == "float16":
|
|
103
|
+
print("#include <cuda_fp16.h>\n", file=stream)
|
|
104
|
+
elif tensor.dtype == "bfloat16":
|
|
105
|
+
print("#include <cuda_bf16.h>\n", file=stream)
|
|
106
|
+
elif tensor.dtype in ["complex64", "complex128"]:
|
|
107
|
+
print("#include <cuda/std/complex>\n", file=stream)
|
|
108
|
+
atp = f"{COMPLEX_PRECISION[tensor.dtype]}"
|
|
109
|
+
|
|
110
|
+
print(f"using VAL = {vtp};", file=stream)
|
|
111
|
+
print(f"using POS = {itp};", file=stream)
|
|
112
|
+
print(f"using CRD = {itp};", file=stream)
|
|
113
|
+
if ctp is not None:
|
|
114
|
+
print(f"using ATP = {atp};", file=stream)
|
|
115
|
+
print(f"using CTP = {ctp};", file=stream)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _emit_parameters(tensor, A, kind, stream):
|
|
119
|
+
"""Private method to emit parameters."""
|
|
120
|
+
for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
|
|
121
|
+
if isinstance(fmt, tuple):
|
|
122
|
+
fmt, _ = fmt
|
|
123
|
+
# Handle level format.
|
|
124
|
+
if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
|
|
125
|
+
pass
|
|
126
|
+
elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
|
|
127
|
+
print(f" const POS* __restrict__ {A}pos{lvl},", file=stream)
|
|
128
|
+
print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
|
|
129
|
+
elif fmt == LevelFormat.SINGLETON:
|
|
130
|
+
print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
|
|
131
|
+
else:
|
|
132
|
+
raise AssertionError(f"Unsupported: {fmt}")
|
|
133
|
+
print(f" VAL* __restrict__ {A}values", file=stream, end="\n" if kind == 0 else ",\n")
|
|
134
|
+
|
|
135
|
+
# Optionally append dimension or level sizes.
|
|
136
|
+
if kind == 1:
|
|
137
|
+
print(" ", ", ".join([f"unsigned long {A}d{i}" for i in range(tensor.num_dimensions)]), end=",\n", file=stream)
|
|
138
|
+
print(" ", ", ".join([f"unsigned long {A}l{i}" for i in range(tensor.num_levels)]), end=",\n", file=stream)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _emit_header(stream):
|
|
142
|
+
"""Private method to emit header with thread/block logic."""
|
|
143
|
+
print(") {", file=stream)
|
|
144
|
+
print(" const unsigned long tidx = threadIdx.x;", file=stream)
|
|
145
|
+
print(" const unsigned long bidx = blockIdx.x;", file=stream)
|
|
146
|
+
print(" const unsigned long tid = bidx * blockDim.x + tidx;", file=stream)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _emit_decls(tensor, stream):
|
|
150
|
+
if not tensor.tensor_format.is_identity:
|
|
151
|
+
dims = ", ".join(f"d{d}" for d in range(tensor.num_dimensions))
|
|
152
|
+
print(f" CRD {dims};", file=stream)
|
|
153
|
+
lvls = ", ".join(f"l{level}" for level in range(tensor.num_levels))
|
|
154
|
+
print(f" CRD {lvls};", file=stream)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _emit_load_a(aidx, stream, end=", "):
|
|
158
|
+
print(f"prolog_a(static_cast<CTP>(Avalues[{aidx}]))", end=end, file=stream)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _emit_load_b(bidx, stream, end=");\n"):
|
|
162
|
+
print(f"prolog_b(static_cast<CTP>(Bvalues[{bidx}]))", end=end, file=stream)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _emit_load_c(cidx, indent, stream):
|
|
166
|
+
print(f"{indent}CTP acc = prolog_c(static_cast<CTP>(Cvalues[{cidx}]));", file=stream)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _emit_store_c(cidx, indent, stream):
|
|
170
|
+
print(f"{indent}Cvalues[{cidx}] = static_cast<VAL>(epilog(acc));", file=stream)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _emit_atomic(dtype, indent, cidx, stream):
|
|
174
|
+
if "complex" in dtype:
|
|
175
|
+
print(f"{indent} VAL* offset = Cvalues + {cidx};", file=stream)
|
|
176
|
+
print(f"{indent} ATP* address = reinterpret_cast<ATP *>(offset);", file=stream)
|
|
177
|
+
print(f"{indent} atomic_add(address + 0, acc.real());", file=stream)
|
|
178
|
+
print(f"{indent} atomic_add(address + 1, acc.imag());", file=stream)
|
|
179
|
+
else:
|
|
180
|
+
# ATP == VAL
|
|
181
|
+
print(f"{indent} atomic_add(Cvalues + {cidx}, static_cast<VAL>(acc));", file=stream)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _emit_traversal(tensor, action, transpose_A, stream):
|
|
185
|
+
# Open the traversal.
|
|
186
|
+
P = None
|
|
187
|
+
lasta = None
|
|
188
|
+
batch = 0
|
|
189
|
+
no_atomic = False
|
|
190
|
+
for lvl, (k, fmt) in enumerate(tensor.tensor_format.levels.items()):
|
|
191
|
+
if isinstance(fmt, tuple):
|
|
192
|
+
fmt, _ = fmt
|
|
193
|
+
lvlsz = tensor.levels[lvl] if action == _EmitAction.APPLY else f"Al{lvl}"
|
|
194
|
+
indent = " " * (lvl + 1)
|
|
195
|
+
if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH:
|
|
196
|
+
if lvl == 0:
|
|
197
|
+
# Dense outermost driver loop.
|
|
198
|
+
print(f"{indent}const CRD p0 = tid;", file=stream)
|
|
199
|
+
print(f"{indent}if (p0 >= {lvlsz})", file=stream)
|
|
200
|
+
print(f"{indent} return;", file=stream)
|
|
201
|
+
print(f"{indent}l0 = p0;", file=stream)
|
|
202
|
+
if not transpose_A and action == _EmitAction.MV and tensor.tensor_format.is_identity:
|
|
203
|
+
_emit_load_c("l0", indent, stream)
|
|
204
|
+
no_atomic = True
|
|
205
|
+
print(f"{indent}{{", file=stream)
|
|
206
|
+
else:
|
|
207
|
+
# Dense inner traversal loop.
|
|
208
|
+
print(f"{indent}POS p{lvl} = p{P} * {lvlsz};", file=stream)
|
|
209
|
+
print(
|
|
210
|
+
f"{indent}for (CRD i{lvl} = 0; i{lvl} < {lvlsz}; i{lvl}++, p{lvl}++) {{",
|
|
211
|
+
file=stream,
|
|
212
|
+
)
|
|
213
|
+
print(f"{indent} l{lvl} = i{lvl};", file=stream)
|
|
214
|
+
P = lvl
|
|
215
|
+
if fmt == LevelFormat.BATCH:
|
|
216
|
+
batch += 1
|
|
217
|
+
elif fmt == LevelFormat.COMPRESSED:
|
|
218
|
+
if lvl == 0:
|
|
219
|
+
# Compressed outermost driver loop.
|
|
220
|
+
print(f"{indent}const POS p0 = tid;", file=stream)
|
|
221
|
+
print(f"{indent}if (p0 >= Apos0[1])", file=stream)
|
|
222
|
+
print(f"{indent} return;", file=stream)
|
|
223
|
+
print(f"{indent}l0 = Acrd0[p0];", file=stream)
|
|
224
|
+
print(f"{indent}{{", file=stream)
|
|
225
|
+
else:
|
|
226
|
+
# Compressed inner traversal loop.
|
|
227
|
+
if batch > 0:
|
|
228
|
+
# This only happens for prior BATCH. Correct the higher-dimensions in
|
|
229
|
+
# both pos and crd buffers and adjust position by #nnz per batch.
|
|
230
|
+
cidx = f"p{batch - 1} * (Al{batch} + 1) + l{P}"
|
|
231
|
+
hidx = f"p{batch - 1} * (Al{batch} + 1) + Al{batch}"
|
|
232
|
+
print(f"{indent}const POS lo{lvl} = Apos{lvl}[{cidx}];", file=stream)
|
|
233
|
+
print(f"{indent}const POS hi{lvl} = Apos{lvl}[{cidx} + 1];", file=stream)
|
|
234
|
+
print(f"{indent}const POS no{lvl} = Apos{lvl}[{hidx}];", file=stream)
|
|
235
|
+
print(
|
|
236
|
+
f"{indent}for (POS i{lvl} = lo{lvl}, p{lvl} = p{lvl - 2} * no{lvl} "
|
|
237
|
+
f"+ i{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
|
|
238
|
+
file=stream,
|
|
239
|
+
)
|
|
240
|
+
print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
|
|
241
|
+
batch = 0 # consumed
|
|
242
|
+
else:
|
|
243
|
+
print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
|
|
244
|
+
print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
|
|
245
|
+
print(f"{indent}for (POS p{lvl} = lo{lvl}; p{lvl} < hi{lvl}; p{lvl}++) {{", file=stream)
|
|
246
|
+
print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
|
|
247
|
+
P = lvl
|
|
248
|
+
if isinstance(k, LevelExpr) and isinstance(k.operator, (Add, Subtract)):
|
|
249
|
+
assert lasta is None # no add/sub nesting
|
|
250
|
+
lasta = lvl, k # record last add/sub
|
|
251
|
+
elif fmt == LevelFormat.SINGLETON:
|
|
252
|
+
assert lvl > 0 # no driver loop
|
|
253
|
+
print(f"{indent}l{lvl} = Acrd{lvl}[p{P}];", file=stream)
|
|
254
|
+
print(f"{indent}{{", file=stream)
|
|
255
|
+
elif fmt == LevelFormat.RANGE:
|
|
256
|
+
assert lvl > 0 # no driver loop
|
|
257
|
+
assert lasta is not None
|
|
258
|
+
la, add = lasta
|
|
259
|
+
isI = k == add.expression2
|
|
260
|
+
di = tensor.tensor_format.dimensions.index(k)
|
|
261
|
+
dj = tensor.tensor_format.dimensions.index(add.expression1 if isI else add.expression2)
|
|
262
|
+
szi = tensor.extents[di] if action == _EmitAction.APPLY else f"Ad{di}"
|
|
263
|
+
szj = tensor.extents[dj] if action == _EmitAction.APPLY else f"Ad{dj}"
|
|
264
|
+
if isinstance(add.operator, Add):
|
|
265
|
+
print(f"{indent}const CRD of{lvl} = l{la};", file=stream)
|
|
266
|
+
print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl} - {szj} + 1);", file=stream)
|
|
267
|
+
print(f"{indent}const CRD hi{lvl} = llmin({szi}, of{lvl} + 1);", file=stream)
|
|
268
|
+
else:
|
|
269
|
+
sign = "-" if isI else ""
|
|
270
|
+
print(f"{indent}const CRD of{lvl} = {sign}l{la};", file=stream)
|
|
271
|
+
print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl});", file=stream)
|
|
272
|
+
print(f"{indent}const CRD hi{lvl} = llmin({szi}, {szj} + of{lvl});", file=stream)
|
|
273
|
+
print(
|
|
274
|
+
f"{indent}POS p{lvl} = p{P} * {szi} + lo{lvl};",
|
|
275
|
+
file=stream,
|
|
276
|
+
)
|
|
277
|
+
print(
|
|
278
|
+
f"{indent}for (CRD i{lvl} = lo{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
|
|
279
|
+
file=stream,
|
|
280
|
+
)
|
|
281
|
+
print(f"{indent} l{lvl} = i{lvl};", file=stream)
|
|
282
|
+
P = lvl
|
|
283
|
+
elif fmt == LevelFormat.DELTA:
|
|
284
|
+
assert lvl > 0 # no driver loop
|
|
285
|
+
# Delta compressed inner traversal loop.
|
|
286
|
+
print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
|
|
287
|
+
print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
|
|
288
|
+
print(
|
|
289
|
+
f"{indent}for (POS p{lvl} = lo{lvl}, at{lvl} = 0; p{lvl} < hi{lvl}; p{lvl}++, at{lvl}++) {{",
|
|
290
|
+
file=stream,
|
|
291
|
+
)
|
|
292
|
+
print(f"{indent} at{lvl} += Acrd{lvl}[p{lvl}];", file=stream)
|
|
293
|
+
print(f"{indent} l{lvl} = at{lvl};", file=stream)
|
|
294
|
+
P = lvl
|
|
295
|
+
else:
|
|
296
|
+
raise AssertionError(f"Unsupported: {fmt}")
|
|
297
|
+
lvl += 1
|
|
298
|
+
# Translation prior to traversal.
|
|
299
|
+
indent = " " * (tensor.num_levels + 1)
|
|
300
|
+
if tensor.tensor_format.is_identity:
|
|
301
|
+
dvars = [f"l{level}" for level in range(tensor.num_levels)]
|
|
302
|
+
else:
|
|
303
|
+
_emit_lvl2dim(tensor, indent, stream)
|
|
304
|
+
dvars = [f"d{d}" for d in range(tensor.num_dimensions)]
|
|
305
|
+
# Transposition of A (last two dimensions).
|
|
306
|
+
if transpose_A:
|
|
307
|
+
dvars[-2], dvars[-1] = dvars[-1], dvars[-2]
|
|
308
|
+
# Perform the traversal.
|
|
309
|
+
if action == _EmitAction.APPLY: # apply
|
|
310
|
+
idxs = ", ".join(d for d in dvars)
|
|
311
|
+
print(f"{indent}Avalues[p{P}] = apply(Avalues[p{P}], {idxs});", file=stream)
|
|
312
|
+
elif action == _EmitAction.DOT: # c = A(i) b(i)
|
|
313
|
+
print(f"{indent}{{", file=stream)
|
|
314
|
+
print(f"{indent} const CTP acc = mul(", end="", file=stream)
|
|
315
|
+
_emit_load_a(f"p{P}", stream)
|
|
316
|
+
_emit_load_b(f"{dvars[0]}", stream)
|
|
317
|
+
_emit_atomic(tensor.dtype, indent, "0", stream)
|
|
318
|
+
print(f"{indent}}}", file=stream)
|
|
319
|
+
elif action == _EmitAction.VM or action == _EmitAction.VM_T: # c(k) = A(j) B(j,k)
|
|
320
|
+
print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
|
|
321
|
+
print(f"{indent} const CTP acc = mul(", end="", file=stream)
|
|
322
|
+
_emit_load_a(f"p{P}", stream)
|
|
323
|
+
bidx = f"{dvars[0]} * Bd1 + k" if action == _EmitAction.VM else f"{dvars[0]} + Bd0 * k"
|
|
324
|
+
_emit_load_b(f"{bidx}", stream)
|
|
325
|
+
_emit_atomic(tensor.dtype, indent, "k", stream)
|
|
326
|
+
print(f"{indent}}}", file=stream)
|
|
327
|
+
elif action == _EmitAction.MV: # c(i) = A(i,j) b(j)
|
|
328
|
+
print(f"{indent}{{", file=stream)
|
|
329
|
+
if no_atomic:
|
|
330
|
+
print(f"{indent} acc = add(acc, mul(", end="", file=stream)
|
|
331
|
+
_emit_load_a(f"p{P}", stream)
|
|
332
|
+
_emit_load_b(f"{dvars[1]}", stream, end="));\n")
|
|
333
|
+
else:
|
|
334
|
+
print(f"{indent} const CTP acc = mul(", end="", file=stream)
|
|
335
|
+
_emit_load_a(f"p{P}", stream)
|
|
336
|
+
_emit_load_b(f"{dvars[1]}", stream)
|
|
337
|
+
_emit_atomic(tensor.dtype, indent, f"{dvars[0]}", stream)
|
|
338
|
+
print(f"{indent}}}", file=stream)
|
|
339
|
+
elif action == _EmitAction.BMM or action == _EmitAction.BMM_T: # C(b0.., i,k) = A(b0.., i,j) B(j,k)
|
|
340
|
+
b = tensor.num_dimensions - 1
|
|
341
|
+
print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
|
|
342
|
+
print(f"{indent} const CTP acc = mul(", end="", file=stream)
|
|
343
|
+
_emit_load_a(f"p{P}", stream)
|
|
344
|
+
bidx = f"{dvars[b]} * Bd1 + k" if action == _EmitAction.BMM else f"{dvars[b]} + Bd0 * k"
|
|
345
|
+
_emit_load_b(f"{bidx}", stream)
|
|
346
|
+
cidx = f"{dvars[0]}"
|
|
347
|
+
for d in range(1, b):
|
|
348
|
+
cidx = f"({cidx} * Ad{d} + {dvars[d]})"
|
|
349
|
+
_emit_atomic(tensor.dtype, indent, f"{cidx} * Bd1 + k", stream)
|
|
350
|
+
print(f"{indent}}}", file=stream)
|
|
351
|
+
elif action == _EmitAction.BMBM or action == _EmitAction.BMBM_T: # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
|
|
352
|
+
b = tensor.num_dimensions - 1
|
|
353
|
+
print(f"{indent}for (CRD k = 0; k < Bd{b}; k++) {{", file=stream)
|
|
354
|
+
print(f"{indent} const CTP acc = mul(", end="", file=stream)
|
|
355
|
+
_emit_load_a(f"p{P}", stream)
|
|
356
|
+
bidx = f"{dvars[0]}"
|
|
357
|
+
for d in range(1, b - 1):
|
|
358
|
+
bidx = f"({bidx} * Ad{d} + {dvars[d]})"
|
|
359
|
+
bidx = (
|
|
360
|
+
f"(({bidx} * Bd{b - 1}) + {dvars[b]}) * Bd{b} + k"
|
|
361
|
+
if action == _EmitAction.BMBM
|
|
362
|
+
else f"(({bidx} * Bd{b - 1}) + k) * Bd{b} + {dvars[b]}"
|
|
363
|
+
)
|
|
364
|
+
_emit_load_b(f"{bidx}", stream)
|
|
365
|
+
cidx = f"{dvars[0]}"
|
|
366
|
+
for d in range(1, b):
|
|
367
|
+
cidx = f"({cidx} * Ad{d} + {dvars[d]})"
|
|
368
|
+
_emit_atomic(tensor.dtype, indent, f"{cidx} * Bd{b} + k", stream)
|
|
369
|
+
print(f"{indent}}}", file=stream)
|
|
370
|
+
else:
|
|
371
|
+
raise TypeError(f"Unsupported: {action}")
|
|
372
|
+
# Close the traversal.
|
|
373
|
+
for level in range(tensor.num_levels, 0, -1):
|
|
374
|
+
indent = " " * level
|
|
375
|
+
print(f"{indent}}}", file=stream)
|
|
376
|
+
if no_atomic:
|
|
377
|
+
_emit_store_c("l0", indent, stream)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def emit_apply(tensor, with_indices):
|
|
381
|
+
"""
|
|
382
|
+
Emits CUDA code for an apply() operation. Note that since the kernel
|
|
383
|
+
is very specific to one UST instance, the kernel can freely specialize
|
|
384
|
+
on metadata like dimension or level sizes.
|
|
385
|
+
"""
|
|
386
|
+
stream = StringIO()
|
|
387
|
+
_emit_types(tensor, None, stream)
|
|
388
|
+
dim = tensor.num_dimensions if with_indices else 0
|
|
389
|
+
print(f'\nextern "C" __device__ VAL apply(VAL{", CRD" * dim});\n', file=stream)
|
|
390
|
+
print('extern "C" __global__ void apply_kernel(', file=stream)
|
|
391
|
+
if with_indices:
|
|
392
|
+
_emit_parameters(tensor, "A", 0, stream)
|
|
393
|
+
_emit_header(stream)
|
|
394
|
+
_emit_decls(tensor, stream)
|
|
395
|
+
_emit_traversal(tensor, _EmitAction.APPLY, False, stream)
|
|
396
|
+
else:
|
|
397
|
+
# Fast path for values only.
|
|
398
|
+
print(" VAL* __restrict__ Avalues,", file=stream)
|
|
399
|
+
print(" POS Anse", file=stream)
|
|
400
|
+
_emit_header(stream)
|
|
401
|
+
print(" if (tid >= Anse)", file=stream)
|
|
402
|
+
print(" return;", file=stream)
|
|
403
|
+
print(" Avalues[tid] = apply(Avalues[tid]);", file=stream)
|
|
404
|
+
print("}", file=stream)
|
|
405
|
+
return stream.getvalue()
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
# TODO: proof-of-concept sparse emitter that should be generalized; currently
|
|
409
|
+
# it only accepts very simple forms where only operand A is sparse;
|
|
410
|
+
# also, currently it drops the prolog_c/epilog when atomic updates are needed
|
|
411
|
+
def _actions(tensor_A, tensor_B, tensor_C):
|
|
412
|
+
"""Returns (akind, bkind, action) encoding for supported matmul combinations."""
|
|
413
|
+
|
|
414
|
+
if tensor_B.tensor_format.name not in [
|
|
415
|
+
"DenseVector",
|
|
416
|
+
"DensedRight",
|
|
417
|
+
"DensedLeft",
|
|
418
|
+
"Dense3D-0-1-2",
|
|
419
|
+
"Dense4D-0-1-2-3",
|
|
420
|
+
] or tensor_C.tensor_format.name not in ["Scalar", "DenseVector", "DensedRight", "Dense3D-0-1-2", "Dense4D-0-1-2-3"]:
|
|
421
|
+
raise NotImplementedError(
|
|
422
|
+
f"The code generator doesn't currently support the \
|
|
423
|
+
{tensor_B.tensor_format.name} or {tensor_C.tensor_format.name} formats."
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
if tensor_A.num_dimensions == 1:
|
|
427
|
+
# A is a vector.
|
|
428
|
+
if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 0:
|
|
429
|
+
return 1, 1, _EmitAction.DOT # c = A(i) b(i)
|
|
430
|
+
if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 1:
|
|
431
|
+
if tensor_B.tensor_format.name != "DensedLeft":
|
|
432
|
+
return 1, 1, _EmitAction.VM # c(j) = A(i) B(i,j)
|
|
433
|
+
else:
|
|
434
|
+
return 1, 1, _EmitAction.VM_T # c(j) = A(i) B(i,j)^T
|
|
435
|
+
elif tensor_A.num_dimensions == 2:
|
|
436
|
+
# A is a matrix.
|
|
437
|
+
if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 1:
|
|
438
|
+
return 1, -1, _EmitAction.MV # c(i) = A(i,j) b(j)
|
|
439
|
+
elif tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 2:
|
|
440
|
+
if tensor_B.tensor_format.name != "DensedLeft":
|
|
441
|
+
return 1, 1, _EmitAction.BMM # C(i,k) = A(i,j) B(j,k)
|
|
442
|
+
else:
|
|
443
|
+
return 1, 1, _EmitAction.BMM_T # C(i,k) = A(i,j) B(j,k)^T
|
|
444
|
+
elif tensor_A.num_dimensions > 2:
|
|
445
|
+
# A is a tensor.
|
|
446
|
+
if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == tensor_A.num_dimensions:
|
|
447
|
+
if tensor_B.tensor_format.name != "DensedLeft":
|
|
448
|
+
return 1, 1, _EmitAction.BMM # C(b0.., i,k) = A(b0.., i,j) B(j,k)
|
|
449
|
+
else:
|
|
450
|
+
return 1, 1, _EmitAction.BMM_T # C(b0.., i,k) = A(b0.., i,j) B(j,k)^T
|
|
451
|
+
elif tensor_B.num_dimensions == tensor_A.num_dimensions and tensor_C.num_dimensions == tensor_A.num_dimensions:
|
|
452
|
+
return 1, 1, _EmitAction.BMBM # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
|
|
453
|
+
raise TypeError("Unsupported matmul() in sparse emitter")
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def emit_matmul(tensor_A, tensor_B, tensor_C, ctp, transpose_A=False, transpose_B=False):
|
|
457
|
+
"""
|
|
458
|
+
Emits CUDA code for a matmul(A, B, C) operation. Note that since the kernel
|
|
459
|
+
is cached at a generic UST and type level only, the kernel should not specialize
|
|
460
|
+
on metadata like dimension or level sizes, but use parameter values instead.
|
|
461
|
+
"""
|
|
462
|
+
akind, bkind, action = _actions(tensor_A, tensor_B, tensor_C)
|
|
463
|
+
stream = StringIO()
|
|
464
|
+
_emit_types(tensor_A, ctp, stream)
|
|
465
|
+
print(f"{semiring_ops_decl}{prolog_epilog_decl}", file=stream)
|
|
466
|
+
print('extern "C" __global__ void matmul(', file=stream)
|
|
467
|
+
_emit_parameters(tensor_A, "A", akind, stream)
|
|
468
|
+
_emit_parameters(tensor_B, "B", bkind, stream)
|
|
469
|
+
_emit_parameters(tensor_C, "C", 0, stream)
|
|
470
|
+
_emit_header(stream)
|
|
471
|
+
_emit_decls(tensor_A, stream)
|
|
472
|
+
if transpose_B:
|
|
473
|
+
action = _transposeB(action)
|
|
474
|
+
_emit_traversal(tensor_A, action, transpose_A, stream)
|
|
475
|
+
print("}", file=stream)
|
|
476
|
+
return stream.getvalue()
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _populate_sizes(params, tensor):
|
|
480
|
+
for i in range(tensor.num_dimensions):
|
|
481
|
+
params.append(tensor.extents[i])
|
|
482
|
+
for i in range(tensor.num_levels):
|
|
483
|
+
params.append(tensor.levels[i])
|
|
484
|
+
return params
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
# TODO: improve the parallelization scheme dramatically
|
|
488
|
+
def _populate_parameter(params, tensor, kind):
|
|
489
|
+
"""Private method to populate parameters for a single UST tensor."""
|
|
490
|
+
size = None
|
|
491
|
+
for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
|
|
492
|
+
if isinstance(fmt, tuple):
|
|
493
|
+
fmt, _ = fmt
|
|
494
|
+
# Handle level format.
|
|
495
|
+
if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
|
|
496
|
+
if lvl == 0:
|
|
497
|
+
size = tensor.levels[0]
|
|
498
|
+
else:
|
|
499
|
+
size = tensor.extents[0] if size < tensor.extents[0] else size
|
|
500
|
+
elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
|
|
501
|
+
params.append(tensor.pos(lvl).data_ptr)
|
|
502
|
+
params.append(tensor.crd(lvl).data_ptr)
|
|
503
|
+
if lvl == 0:
|
|
504
|
+
size = tensor.crd(0).size
|
|
505
|
+
elif fmt == LevelFormat.SINGLETON:
|
|
506
|
+
params.append(tensor.crd(lvl).data_ptr)
|
|
507
|
+
else:
|
|
508
|
+
raise TypeError(f"Unsupported: {fmt}")
|
|
509
|
+
params.append(tensor.val.data_ptr)
|
|
510
|
+
|
|
511
|
+
# Optionally append dimension and level sizes.
|
|
512
|
+
if kind == 1:
|
|
513
|
+
params = _populate_sizes(params, tensor)
|
|
514
|
+
|
|
515
|
+
return (params, size)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def populate_apply_parameters(tensor, with_indices=True):
|
|
519
|
+
"""
|
|
520
|
+
Populates the parameters for an apply() operation (with our without indices).
|
|
521
|
+
The API follows the UST parameter passing conventions for the tensor when
|
|
522
|
+
indices are needed. Otherwise it directly passes the values buffer.
|
|
523
|
+
|
|
524
|
+
Returns (parameter list, kernel launch size)
|
|
525
|
+
"""
|
|
526
|
+
if with_indices:
|
|
527
|
+
return _populate_parameter([], tensor, 0)
|
|
528
|
+
return ([tensor.val.data_ptr, tensor.nse], tensor.nse)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def populate_matmul_parameters(tensor_A, tensor_B, tensor_C, dense_bc=False):
|
|
532
|
+
"""
|
|
533
|
+
Populates the parameters for a matmul(A, B, C) operation.
|
|
534
|
+
|
|
535
|
+
The API follows the UST parameter passing conventions for A, B, C,
|
|
536
|
+
each possibly followed by the dimension and level sizes.
|
|
537
|
+
|
|
538
|
+
Returns (parameter list, kernel launch size)
|
|
539
|
+
"""
|
|
540
|
+
akind, bkind, _ = _actions(tensor_A, tensor_B, tensor_C)
|
|
541
|
+
params = []
|
|
542
|
+
params, n = _populate_parameter(params, tensor_A, akind)
|
|
543
|
+
if dense_bc:
|
|
544
|
+
# Fast path for dense B and C.
|
|
545
|
+
params.append(tensor_B._val.data_ptr)
|
|
546
|
+
if bkind == 1:
|
|
547
|
+
params = _populate_sizes(params, tensor_B)
|
|
548
|
+
params.append(tensor_C._val.data_ptr)
|
|
549
|
+
else:
|
|
550
|
+
params, _ = _populate_parameter(params, tensor_B, bkind)
|
|
551
|
+
params, _ = _populate_parameter(params, tensor_C, 0)
|
|
552
|
+
assert n is not None
|
|
553
|
+
return (params, n)
|