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,141 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use distributed Torch tensor objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations # allows typehint of class methods to return the self class
|
|
10
|
+
|
|
11
|
+
__all__ = ["TorchDistributedTensor"]
|
|
12
|
+
|
|
13
|
+
import math
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import torch
|
|
17
|
+
except ImportError:
|
|
18
|
+
torch = None # type: ignore
|
|
19
|
+
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
|
|
22
|
+
import nvmath.distributed
|
|
23
|
+
from nvmath.distributed._internal.nvshmem import nvshmem_empty_dlpack
|
|
24
|
+
from nvmath.internal.package_ifc import StreamHolder
|
|
25
|
+
from nvmath.internal.tensor_ifc_torch import TorchTensor
|
|
26
|
+
from nvmath.internal.utils import device_ctx
|
|
27
|
+
|
|
28
|
+
from .tensor_ifc import DistributedTensor
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Most methods aren't redefined, because they simply act on the local array
|
|
32
|
+
class TorchDistributedTensor(TorchTensor, DistributedTensor):
|
|
33
|
+
"""
|
|
34
|
+
TensorHolder for distributed torch tensors.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, tensor):
|
|
38
|
+
super().__init__(tensor)
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def empty(
|
|
42
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
43
|
+
) -> TorchDistributedTensor:
|
|
44
|
+
"""
|
|
45
|
+
Create an empty tensor of the specified shape and data type on the specified device
|
|
46
|
+
(None, 'cpu', or device id).
|
|
47
|
+
|
|
48
|
+
Note, that the strides, if specified, should correspond to a dense
|
|
49
|
+
(possibly permuted) tensor and MUST NOT overlap.
|
|
50
|
+
Otherwise, the behaviour is not defined.
|
|
51
|
+
"""
|
|
52
|
+
symmetric_memory = context.pop("symmetric_memory", False)
|
|
53
|
+
make_symmetric = context.pop("make_symmetric", False)
|
|
54
|
+
skip_symmetric_check = context.pop("skip_symmetric_check", False)
|
|
55
|
+
|
|
56
|
+
if device_id == "cpu":
|
|
57
|
+
if symmetric_memory or make_symmetric or skip_symmetric_check:
|
|
58
|
+
raise ValueError("symmetric memory options cannot be used when allocating tensor on CPU")
|
|
59
|
+
return super().empty(shape, device_id, dtype=dtype, strides=strides, **context)
|
|
60
|
+
|
|
61
|
+
ctx = nvmath.distributed.get_context()
|
|
62
|
+
assert ctx is not None, "nvmath.distributed has not been initialized"
|
|
63
|
+
|
|
64
|
+
logger = context.get("logger")
|
|
65
|
+
|
|
66
|
+
if not symmetric_memory:
|
|
67
|
+
if make_symmetric or skip_symmetric_check:
|
|
68
|
+
raise ValueError("Use of symmetric memory option with symmetric_memory=False")
|
|
69
|
+
return super().empty(
|
|
70
|
+
shape, device_id=device_id, dtype=dtype, strides=strides, stream_holder=stream_holder, **context
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
dtype = TorchTensor.name_to_dtype[dtype]
|
|
74
|
+
|
|
75
|
+
with device_ctx(device_id):
|
|
76
|
+
size = math.prod(shape, start=dtype.itemsize)
|
|
77
|
+
# TODO: ideally strides should be set in DLPack, but cuda.core doesn't support
|
|
78
|
+
# ndarray yet and instead returns a flat buffer.
|
|
79
|
+
dlpack_buf = nvshmem_empty_dlpack(
|
|
80
|
+
size,
|
|
81
|
+
device_id,
|
|
82
|
+
ctx.process_group,
|
|
83
|
+
make_symmetric=make_symmetric,
|
|
84
|
+
skip_symmetric_check=skip_symmetric_check,
|
|
85
|
+
logger=logger,
|
|
86
|
+
)
|
|
87
|
+
tensor = torch.from_dlpack(dlpack_buf)
|
|
88
|
+
# Buffer may be padded if make_symmetric=True.
|
|
89
|
+
tensor = tensor[:size]
|
|
90
|
+
if strides is None:
|
|
91
|
+
tensor = tensor.view(dtype).view(shape)
|
|
92
|
+
else:
|
|
93
|
+
tensor = torch.as_strided(tensor.view(dtype), shape, strides)
|
|
94
|
+
|
|
95
|
+
return cls(tensor)
|
|
96
|
+
|
|
97
|
+
def to(self, device_id, stream_holder, symmetric_memory: bool = False) -> TorchDistributedTensor:
|
|
98
|
+
"""
|
|
99
|
+
In addition to the base class semantics:
|
|
100
|
+
- Source or target device must be the one used to initialize NVSHMEM on this
|
|
101
|
+
process. This implies that copy from one CUDA device to another is not allowed.
|
|
102
|
+
- Memory layout is preserved.
|
|
103
|
+
- Strides must be non-overlapping.
|
|
104
|
+
"""
|
|
105
|
+
if not (device_id == "cpu" or isinstance(device_id, int)):
|
|
106
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
107
|
+
|
|
108
|
+
blocking = (device_id == "cpu") or (self.device_id == "cpu")
|
|
109
|
+
|
|
110
|
+
# To CPU or same device
|
|
111
|
+
if device_id == "cpu" or self.device_id == device_id:
|
|
112
|
+
with stream_holder.ctx:
|
|
113
|
+
tensor = self.tensor.to(device=device_id, non_blocking=not blocking)
|
|
114
|
+
result = TorchDistributedTensor(tensor)
|
|
115
|
+
assert result.is_symmetric_memory == symmetric_memory
|
|
116
|
+
return result
|
|
117
|
+
|
|
118
|
+
# Currently we don't allow copy from one device to another for distributed
|
|
119
|
+
# tensors (see comment in CupyDistributedTensor.to()).
|
|
120
|
+
if self.device_id != "cpu" and self.device_id != device_id:
|
|
121
|
+
raise ValueError("Cannot copy distributed tensor to a different CUDA device")
|
|
122
|
+
|
|
123
|
+
# CPU to GPU
|
|
124
|
+
with stream_holder.ctx:
|
|
125
|
+
tensor_device = TorchDistributedTensor.empty(
|
|
126
|
+
self.shape,
|
|
127
|
+
device_id=device_id,
|
|
128
|
+
dtype=self.dtype,
|
|
129
|
+
strides=self.strides,
|
|
130
|
+
stream_holder=stream_holder,
|
|
131
|
+
make_symmetric=symmetric_memory,
|
|
132
|
+
symmetric_memory=symmetric_memory,
|
|
133
|
+
)
|
|
134
|
+
tensor_device.tensor.copy_(self.tensor, non_blocking=not blocking)
|
|
135
|
+
assert tensor_device.is_symmetric_memory == symmetric_memory
|
|
136
|
+
return tensor_device
|
|
137
|
+
|
|
138
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None) -> TorchDistributedTensor:
|
|
139
|
+
if copy and self.device_id != "cpu":
|
|
140
|
+
raise NotImplementedError("reshape with copy=True is not supported for TorchDistributedTensor on GPU")
|
|
141
|
+
return super().reshape(shape, copy=copy)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Entry point to using tensors from different libraries seamlessly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["wrap_operand", "copy_"]
|
|
10
|
+
|
|
11
|
+
import warnings
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
from nvmath.internal.tensor_ifc import Tensor, TensorHolder
|
|
15
|
+
from nvmath.internal.tensor_wrapper import (
|
|
16
|
+
infer_tensor_package as base_infer_tensor_package,
|
|
17
|
+
)
|
|
18
|
+
from nvmath.internal.tensor_wrapper import (
|
|
19
|
+
maybe_register_package as base_maybe_register_package,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from .tensor_ifc import DistributedTensor
|
|
23
|
+
from .tensor_ifc_numpy import CudaDistributedTensor, NumpyDistributedTensor
|
|
24
|
+
|
|
25
|
+
_TENSOR_TYPES: dict[str, type[DistributedTensor]] = {"numpy": NumpyDistributedTensor, "cuda": CudaDistributedTensor}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def infer_tensor_package(tensor):
|
|
29
|
+
"""
|
|
30
|
+
Infer the package that defines this tensor.
|
|
31
|
+
"""
|
|
32
|
+
package = base_infer_tensor_package(tensor)
|
|
33
|
+
# Use call_base=False because base_infer_tensor_package already
|
|
34
|
+
# called base_maybe_register_package
|
|
35
|
+
maybe_register_package(package, call_base=False)
|
|
36
|
+
return package
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def maybe_register_package(package, call_base=True):
|
|
40
|
+
if call_base:
|
|
41
|
+
base_maybe_register_package(package)
|
|
42
|
+
if package == "torch":
|
|
43
|
+
from .tensor_ifc_torch import TorchDistributedTensor
|
|
44
|
+
|
|
45
|
+
_TENSOR_TYPES[package] = TorchDistributedTensor
|
|
46
|
+
elif package == "cupy":
|
|
47
|
+
from .tensor_ifc_cupy import CupyDistributedTensor, HostDistributedTensor
|
|
48
|
+
|
|
49
|
+
_TENSOR_TYPES["cupy"] = CupyDistributedTensor
|
|
50
|
+
_TENSOR_TYPES["cupy_host"] = HostDistributedTensor
|
|
51
|
+
elif package != "numpy":
|
|
52
|
+
raise AssertionError(f"Internal error: unrecognized package {package}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def wrap_operand(native_operand: Tensor) -> DistributedTensor[Tensor]:
|
|
56
|
+
"""
|
|
57
|
+
Wrap one "native" operand so that package-agnostic API can be used.
|
|
58
|
+
"""
|
|
59
|
+
if isinstance(native_operand, TensorHolder):
|
|
60
|
+
msg = (
|
|
61
|
+
"wrap_operand() is being called unnecessarily because the input is already a TensorHolder. "
|
|
62
|
+
"Only public facing APIs should call wrap_operand(). "
|
|
63
|
+
"Internal APIs should assume the operands are TensorHolder already."
|
|
64
|
+
"Trying to wrap a TensorHolder will become an error in the future."
|
|
65
|
+
)
|
|
66
|
+
warnings.warn(msg, DeprecationWarning)
|
|
67
|
+
assert isinstance(native_operand, DistributedTensor)
|
|
68
|
+
return native_operand
|
|
69
|
+
wrapped_operand = _TENSOR_TYPES[infer_tensor_package(native_operand)](native_operand)
|
|
70
|
+
return wrapped_operand
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def copy_(src: Sequence[TensorHolder], dest: Sequence[TensorHolder], stream_holder):
|
|
74
|
+
"""
|
|
75
|
+
Copy the wrapped operands in dest to the corresponding wrapped operands in src.
|
|
76
|
+
"""
|
|
77
|
+
for s, d in zip(src, dest, strict=True):
|
|
78
|
+
d.copy_(s, stream_holder=stream_holder)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
__all__ = ["allocate_symmetric_memory", "free_symmetric_memory"]
|
|
8
|
+
|
|
9
|
+
from collections.abc import Iterable, Sequence
|
|
10
|
+
from logging import Logger
|
|
11
|
+
from types import ModuleType
|
|
12
|
+
from typing import TYPE_CHECKING, Literal
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
import torch
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from numpy.typing import DTypeLike
|
|
19
|
+
|
|
20
|
+
import nvmath.distributed
|
|
21
|
+
from nvmath.distributed._internal import tensor_wrapper
|
|
22
|
+
from nvmath.internal.utils import device_ctx
|
|
23
|
+
|
|
24
|
+
# Supported packages for tensors backed by symmetric memory.
|
|
25
|
+
_SUPPORTED_PACKAGES = ("cupy", "torch")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# TODO: do a general refactor of this function in nvmath
|
|
29
|
+
def calculate_strides(shape: Sequence[int], axis_order: Iterable[int]):
|
|
30
|
+
"""
|
|
31
|
+
Calculate the strides for the provided shape and axis order.
|
|
32
|
+
"""
|
|
33
|
+
strides = [0] * len(shape)
|
|
34
|
+
|
|
35
|
+
stride = 1
|
|
36
|
+
for axis in axis_order:
|
|
37
|
+
strides[axis] = stride
|
|
38
|
+
stride *= shape[axis]
|
|
39
|
+
|
|
40
|
+
return strides
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def allocate_symmetric_memory(
|
|
44
|
+
shape: int | Sequence[int],
|
|
45
|
+
package: ModuleType,
|
|
46
|
+
*,
|
|
47
|
+
dtype: DTypeLike | torch.dtype | None = None,
|
|
48
|
+
axis_order: Literal["C", "F"] | Sequence[int] = "C",
|
|
49
|
+
make_symmetric: bool = False,
|
|
50
|
+
skip_symmetric_check: bool = False,
|
|
51
|
+
logger: Logger | None = None,
|
|
52
|
+
):
|
|
53
|
+
"""Return uninitialized tensor of given shape and type, allocated from the NVSHMEM
|
|
54
|
+
symmetric heap, on the device on which nvmath.distributed was initialized. The
|
|
55
|
+
tensor type is determined by the provided package (e.g. cupy, torch).
|
|
56
|
+
**This is a collective operation and must be called by all processes**.
|
|
57
|
+
Note that the buffer size must be the same on all processes, or you can
|
|
58
|
+
use ``make_symmetric=True`` to pad all buffers to the same max size.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
shape: Shape of the tensor to allocate.
|
|
62
|
+
|
|
63
|
+
package: Python package determining the tensor type (e.g. cupy, torch).
|
|
64
|
+
|
|
65
|
+
dtype: Tensor dtype in a form recognized by the package. If None, will use the
|
|
66
|
+
package's default dtype.
|
|
67
|
+
|
|
68
|
+
axis_order: Axis order. The default is 'C' (row-major ordering).
|
|
69
|
+
|
|
70
|
+
make_symmetric: If buffer sizes do not match across processes, will allocate
|
|
71
|
+
the maximum size on every process to ensure the allocation is symmetric.
|
|
72
|
+
The default is False.
|
|
73
|
+
|
|
74
|
+
skip_symmetric_check: Skip checking that the allocation is symmetric (which
|
|
75
|
+
requires inter-process communication). The default is False.
|
|
76
|
+
|
|
77
|
+
logger (logging.Logger): Python Logger object. The root logger will be used if a
|
|
78
|
+
logger object is not provided.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
if package.__name__ not in _SUPPORTED_PACKAGES:
|
|
82
|
+
raise ValueError(f"The package must be one of {_SUPPORTED_PACKAGES}. Got {package}.")
|
|
83
|
+
|
|
84
|
+
distributed_ctx = nvmath.distributed.get_context()
|
|
85
|
+
if distributed_ctx is None:
|
|
86
|
+
raise RuntimeError(
|
|
87
|
+
"nvmath.distributed has not been initialized. Refer to "
|
|
88
|
+
"https://docs.nvidia.com/cuda/nvmath-python/latest/distributed-apis/runtime.html"
|
|
89
|
+
" for more information."
|
|
90
|
+
)
|
|
91
|
+
if not distributed_ctx.nvshmem_available:
|
|
92
|
+
raise RuntimeError("nvmath.distributed wasn't initialized with NVSHMEM backend")
|
|
93
|
+
|
|
94
|
+
device_id = distributed_ctx.device_id
|
|
95
|
+
|
|
96
|
+
if isinstance(shape, int):
|
|
97
|
+
shape = (shape,)
|
|
98
|
+
|
|
99
|
+
strides = None
|
|
100
|
+
if axis_order is not None:
|
|
101
|
+
if axis_order == "C":
|
|
102
|
+
strides = calculate_strides(shape, reversed(range(len(shape))))
|
|
103
|
+
elif axis_order == "F":
|
|
104
|
+
strides = calculate_strides(shape, range(len(shape)))
|
|
105
|
+
else:
|
|
106
|
+
strides = calculate_strides(shape, axis_order)
|
|
107
|
+
|
|
108
|
+
if package.__name__ == "cupy":
|
|
109
|
+
from ._internal.tensor_ifc_cupy import CupyDistributedTensor
|
|
110
|
+
|
|
111
|
+
if dtype is None:
|
|
112
|
+
# This mimics numpy and cupy
|
|
113
|
+
dtype = np.float64
|
|
114
|
+
|
|
115
|
+
dtype = np.dtype(dtype).name # type: ignore
|
|
116
|
+
return CupyDistributedTensor.empty(
|
|
117
|
+
shape,
|
|
118
|
+
dtype=dtype,
|
|
119
|
+
device_id=device_id,
|
|
120
|
+
strides=strides,
|
|
121
|
+
symmetric_memory=True,
|
|
122
|
+
make_symmetric=make_symmetric,
|
|
123
|
+
skip_symmetric_check=skip_symmetric_check,
|
|
124
|
+
logger=logger,
|
|
125
|
+
).tensor
|
|
126
|
+
elif package.__name__ == "torch":
|
|
127
|
+
from ._internal.tensor_ifc_torch import TorchDistributedTensor
|
|
128
|
+
|
|
129
|
+
if dtype is None:
|
|
130
|
+
import torch
|
|
131
|
+
|
|
132
|
+
dtype = torch.get_default_dtype()
|
|
133
|
+
|
|
134
|
+
dtype = str(dtype).split(".")[1]
|
|
135
|
+
return TorchDistributedTensor.empty(
|
|
136
|
+
shape,
|
|
137
|
+
dtype=dtype,
|
|
138
|
+
device_id=device_id,
|
|
139
|
+
strides=strides,
|
|
140
|
+
symmetric_memory=True,
|
|
141
|
+
make_symmetric=make_symmetric,
|
|
142
|
+
skip_symmetric_check=skip_symmetric_check,
|
|
143
|
+
logger=logger,
|
|
144
|
+
).tensor
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def free_symmetric_memory(*tensors) -> None:
|
|
148
|
+
"""Frees tensors' data buffer where the buffer was allocated on the NVSHMEM
|
|
149
|
+
symmetric heap. Note that this is only meant to be called on tensors returned
|
|
150
|
+
by ``allocate_symmetric_memory()``.
|
|
151
|
+
|
|
152
|
+
**This is a collective operation and must be called by all processes, with tensors
|
|
153
|
+
in the same order**."""
|
|
154
|
+
|
|
155
|
+
device_id = tensor_wrapper.wrap_operand(tensors[0]).device_id
|
|
156
|
+
if device_id == "cpu":
|
|
157
|
+
raise TypeError("free_symmetric_memory called on CPU array/tensor")
|
|
158
|
+
|
|
159
|
+
with device_ctx(device_id):
|
|
160
|
+
for tensor in tensors:
|
|
161
|
+
wrapped_tensor = tensor_wrapper.wrap_operand(tensor)
|
|
162
|
+
if wrapped_tensor.device_id == "cpu":
|
|
163
|
+
raise TypeError("free_symmetric_memory called on CPU array/tensor")
|
|
164
|
+
|
|
165
|
+
assert wrapped_tensor.device_id == device_id, "Internal error: symmetric memory tensors are not on the same device"
|
|
166
|
+
|
|
167
|
+
wrapped_tensor.free_symmetric()
|