nvmath-python 1.0.0__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +45 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/attribute_ifc_factory.py +330 -0
  5. nvmath/_internal/layout.py +70 -0
  6. nvmath/_internal/templates.py +130 -0
  7. nvmath/_internal/threadsafe.py +106 -0
  8. nvmath/_internal/utils.py +43 -0
  9. nvmath/_internal/workspace.py +490 -0
  10. nvmath/_utils.py +147 -0
  11. nvmath/bindings/__init__.py +60 -0
  12. nvmath/bindings/_internal/__init__.pxd +0 -0
  13. nvmath/bindings/_internal/__init__.py +0 -0
  14. nvmath/bindings/_internal/common_types.pxd +31 -0
  15. nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
  16. nvmath/bindings/_internal/cublas.pxd +530 -0
  17. nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
  18. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  19. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  20. nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
  21. nvmath/bindings/_internal/cudss.pxd +54 -0
  22. nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
  23. nvmath/bindings/_internal/cufft.pxd +70 -0
  24. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  25. nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/curand.pxd +42 -0
  27. nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusolver.pxd +15 -0
  29. nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  31. nvmath/bindings/_internal/cusolverMp.pxd +71 -0
  32. nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
  33. nvmath/bindings/_internal/cusolverSp.pxd +75 -0
  34. nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
  35. nvmath/bindings/_internal/cusparse.pxd +471 -0
  36. nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  38. nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
  39. nvmath/bindings/_internal/cutensor.pxd +58 -0
  40. nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
  41. nvmath/bindings/_internal/mathdx.pxd +116 -0
  42. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  43. nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
  44. nvmath/bindings/_internal/utils.pxd +174 -0
  45. nvmath/bindings/_internal/utils.pyi +10 -0
  46. nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
  47. nvmath/bindings/cublas.pxd +558 -0
  48. nvmath/bindings/cublas.pyi +812 -0
  49. nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
  50. nvmath/bindings/cublasLt.pxd +109 -0
  51. nvmath/bindings/cublasLt.pyi +1461 -0
  52. nvmath/bindings/cublasMp.pxd +85 -0
  53. nvmath/bindings/cublasMp.pyi +267 -0
  54. nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
  55. nvmath/bindings/cudss.pxd +98 -0
  56. nvmath/bindings/cudss.pyi +443 -0
  57. nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
  58. nvmath/bindings/cufft.pxd +118 -0
  59. nvmath/bindings/cufft.pyi +301 -0
  60. nvmath/bindings/cufftMp.pxd +124 -0
  61. nvmath/bindings/cufftMp.pyi +326 -0
  62. nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
  63. nvmath/bindings/curand.pxd +71 -0
  64. nvmath/bindings/curand.pyi +189 -0
  65. nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
  66. nvmath/bindings/cusolver.pxd +62 -0
  67. nvmath/bindings/cusolver.pyi +320 -0
  68. nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
  69. nvmath/bindings/cusolverDn.pxd +430 -0
  70. nvmath/bindings/cusolverDn.pyi +422 -0
  71. nvmath/bindings/cusolverMp.pxd +98 -0
  72. nvmath/bindings/cusolverMp.pyi +114 -0
  73. nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
  74. nvmath/bindings/cusolverSp.pxd +95 -0
  75. nvmath/bindings/cusolverSp.pyi +70 -0
  76. nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
  77. nvmath/bindings/cusparse.pxd +546 -0
  78. nvmath/bindings/cusparse.pyi +1017 -0
  79. nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
  80. nvmath/bindings/cusparseLt.pxd +99 -0
  81. nvmath/bindings/cusparseLt.pyi +252 -0
  82. nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
  83. nvmath/bindings/cutensor.pxd +98 -0
  84. nvmath/bindings/cutensor.pyi +324 -0
  85. nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycublas.pxd +664 -0
  87. nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycublasLt.pxd +1045 -0
  89. nvmath/bindings/cycublasMp.pxd +171 -0
  90. nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
  91. nvmath/bindings/cycudss.pxd +277 -0
  92. nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
  93. nvmath/bindings/cycufft.pxd +333 -0
  94. nvmath/bindings/cycufftMp.pxd +342 -0
  95. nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
  96. nvmath/bindings/cycurand.pxd +141 -0
  97. nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
  98. nvmath/bindings/cycusolver.pxd +137 -0
  99. nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
  100. nvmath/bindings/cycusolverDn.pxd +443 -0
  101. nvmath/bindings/cycusolverMp.pxd +107 -0
  102. nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
  103. nvmath/bindings/cycusolverSp.pxd +93 -0
  104. nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
  105. nvmath/bindings/cycusparse.pxd +679 -0
  106. nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
  107. nvmath/bindings/cycusparseLt.pxd +135 -0
  108. nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
  109. nvmath/bindings/cycutensor.pxd +189 -0
  110. nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
  111. nvmath/bindings/cymathdx.pxd +552 -0
  112. nvmath/bindings/cynvshmem.pxd +118 -0
  113. nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
  114. nvmath/bindings/mathdx.pxd +182 -0
  115. nvmath/bindings/mathdx.pyi +1562 -0
  116. nvmath/bindings/nvpl/__init__.pxd +0 -0
  117. nvmath/bindings/nvpl/__init__.py +13 -0
  118. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  119. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  120. nvmath/bindings/nvpl/_internal/blas.cp314t-win_amd64.pyd +0 -0
  121. nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
  122. nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
  123. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  124. nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
  125. nvmath/bindings/nvpl/blas.pxd +131 -0
  126. nvmath/bindings/nvpl/blas.pyi +168 -0
  127. nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
  128. nvmath/bindings/nvpl/cyblas.pxd +280 -0
  129. nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
  130. nvmath/bindings/nvpl/cyfft.pxd +93 -0
  131. nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
  132. nvmath/bindings/nvpl/fft.pxd +100 -0
  133. nvmath/bindings/nvpl/fft.pyi +168 -0
  134. nvmath/bindings/nvshmem.pxd +54 -0
  135. nvmath/bindings/nvshmem.pyi +191 -0
  136. nvmath/device/__init__.py +38 -0
  137. nvmath/device/_deprecated.py +33 -0
  138. nvmath/device/common.py +315 -0
  139. nvmath/device/common_backend.py +131 -0
  140. nvmath/device/common_cuda.py +201 -0
  141. nvmath/device/common_numba.py +300 -0
  142. nvmath/device/common_numba_cuda_mlir.py +202 -0
  143. nvmath/device/common_opaque_tensor.py +201 -0
  144. nvmath/device/cublasdx.py +1606 -0
  145. nvmath/device/cublasdx_backend.py +860 -0
  146. nvmath/device/cublasdx_numba.py +1534 -0
  147. nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
  148. nvmath/device/cufftdx.py +373 -0
  149. nvmath/device/cufftdx_backend.py +220 -0
  150. nvmath/device/cufftdx_numba.py +140 -0
  151. nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
  152. nvmath/device/curand_kernel.py +9147 -0
  153. nvmath/device/cusolverdx.py +2708 -0
  154. nvmath/device/cusolverdx_backend.py +440 -0
  155. nvmath/device/cusolverdx_numba.py +567 -0
  156. nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
  157. nvmath/device/cusolverdx_overload_backend.py +1029 -0
  158. nvmath/device/llvm_array.py +29 -0
  159. nvmath/device/random.py +441 -0
  160. nvmath/device/random_helpers.py +23 -0
  161. nvmath/device/random_states.py +187 -0
  162. nvmath/device/types.py +138 -0
  163. nvmath/device/vector_types_numba.py +259 -0
  164. nvmath/distributed/__init__.py +200 -0
  165. nvmath/distributed/_internal/__init__.py +0 -0
  166. nvmath/distributed/_internal/nccl.py +86 -0
  167. nvmath/distributed/_internal/nvshmem.py +307 -0
  168. nvmath/distributed/_internal/symmetric_memory.py +35 -0
  169. nvmath/distributed/_internal/tensor_ifc.py +70 -0
  170. nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
  171. nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
  172. nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
  173. nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
  174. nvmath/distributed/_internal/tensor_wrapper.py +81 -0
  175. nvmath/distributed/_utils.py +167 -0
  176. nvmath/distributed/distribution/__init__.py +30 -0
  177. nvmath/distributed/distribution/_configuration.py +39 -0
  178. nvmath/distributed/distribution/distributions.py +1024 -0
  179. nvmath/distributed/distribution/redistribute.py +1284 -0
  180. nvmath/distributed/fft/__init__.py +7 -0
  181. nvmath/distributed/fft/_configuration.py +82 -0
  182. nvmath/distributed/fft/fft.py +2742 -0
  183. nvmath/distributed/linalg/__init__.py +22 -0
  184. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  185. nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -0
  186. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  187. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  188. nvmath/distributed/linalg/advanced/_configuration.py +171 -0
  189. nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
  190. nvmath/distributed/linalg/generic/__init__.py +8 -0
  191. nvmath/distributed/linalg/generic/_caching.py +66 -0
  192. nvmath/distributed/linalg/generic/_configuration.py +61 -0
  193. nvmath/distributed/linalg/generic/_factorization.py +172 -0
  194. nvmath/distributed/linalg/generic/_initialization.py +966 -0
  195. nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
  196. nvmath/distributed/linalg/generic/solvermod.py +1368 -0
  197. nvmath/distributed/process_group.py +408 -0
  198. nvmath/fft/__init__.py +7 -0
  199. nvmath/fft/_configuration.py +189 -0
  200. nvmath/fft/_exec_utils.py +82 -0
  201. nvmath/fft/_helpers.py +237 -0
  202. nvmath/fft/fft.py +3122 -0
  203. nvmath/internal/__init__.pxd +3 -0
  204. nvmath/internal/__init__.py +10 -0
  205. nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
  206. nvmath/internal/_bindings.pxd +18 -0
  207. nvmath/internal/_device_utils.py +45 -0
  208. nvmath/internal/_layout/__init__.pxd +3 -0
  209. nvmath/internal/_layout/__init__.py +7 -0
  210. nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
  211. nvmath/internal/_layout/_layout.pxd +1303 -0
  212. nvmath/internal/_layout/_layout.pyi +1145 -0
  213. nvmath/internal/enum_utils.py +142 -0
  214. nvmath/internal/formatters.py +87 -0
  215. nvmath/internal/mem_limit.py +51 -0
  216. nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
  217. nvmath/internal/memory.pxd +13 -0
  218. nvmath/internal/memory.pyi +50 -0
  219. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  220. nvmath/internal/ndbuffer/__init__.py +9 -0
  221. nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
  222. nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
  223. nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
  224. nvmath/internal/ndbuffer/_jit.pxd +7 -0
  225. nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
  226. nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
  227. nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -0
  228. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  229. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  230. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  231. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  232. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +242 -0
  233. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  234. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  235. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  236. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  237. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  238. nvmath/internal/package_ifc.py +168 -0
  239. nvmath/internal/package_ifc_cuda.py +57 -0
  240. nvmath/internal/package_ifc_cupy.py +67 -0
  241. nvmath/internal/package_ifc_torch.py +69 -0
  242. nvmath/internal/package_wrapper.py +14 -0
  243. nvmath/internal/tensor_ifc.py +179 -0
  244. nvmath/internal/tensor_ifc_cupy.py +234 -0
  245. nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
  246. nvmath/internal/tensor_ifc_numpy.py +184 -0
  247. nvmath/internal/tensor_ifc_torch.py +178 -0
  248. nvmath/internal/tensor_wrapper.py +160 -0
  249. nvmath/internal/typemaps.py +113 -0
  250. nvmath/internal/utils.py +805 -0
  251. nvmath/linalg/__init__.py +56 -0
  252. nvmath/linalg/_internal/__init__.py +3 -0
  253. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  254. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  255. nvmath/linalg/_internal/batch.py +234 -0
  256. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  257. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  258. nvmath/linalg/_internal/layout.py +624 -0
  259. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  260. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  261. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  262. nvmath/linalg/_internal/solver_utils.py +432 -0
  263. nvmath/linalg/_internal/typemaps.py +144 -0
  264. nvmath/linalg/_internal/utils.py +157 -0
  265. nvmath/linalg/advanced/__init__.py +8 -0
  266. nvmath/linalg/advanced/_algorithmmod.py +170 -0
  267. nvmath/linalg/advanced/_configuration.py +351 -0
  268. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  269. nvmath/linalg/advanced/helpers/matmul.py +1316 -0
  270. nvmath/linalg/advanced/matmulmod.py +3734 -0
  271. nvmath/linalg/generic/__init__.py +53 -0
  272. nvmath/linalg/generic/_configuration/__init__.py +39 -0
  273. nvmath/linalg/generic/_configuration/layout.py +263 -0
  274. nvmath/linalg/generic/_configuration/match.py +734 -0
  275. nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
  276. nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
  277. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  278. nvmath/linalg/generic/_dtype.py +15 -0
  279. nvmath/linalg/generic/matmulmod.py +2094 -0
  280. nvmath/linalg/generic/solvermod.py +1301 -0
  281. nvmath/memory.py +279 -0
  282. nvmath/sparse/__init__.py +38 -0
  283. nvmath/sparse/_internal/__init__.py +21 -0
  284. nvmath/sparse/_internal/common_utils.py +147 -0
  285. nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
  286. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  287. nvmath/sparse/_internal/cudss_utils.py +506 -0
  288. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  289. nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
  290. nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
  291. nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
  292. nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
  293. nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
  294. nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
  295. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  296. nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
  297. nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
  298. nvmath/sparse/_internal/utils.py +56 -0
  299. nvmath/sparse/advanced/__init__.py +7 -0
  300. nvmath/sparse/advanced/_configuration.py +227 -0
  301. nvmath/sparse/advanced/direct_solver.py +2069 -0
  302. nvmath/sparse/generic/__init__.py +7 -0
  303. nvmath/sparse/generic/_configuration.py +129 -0
  304. nvmath/sparse/generic/_helpers.py +137 -0
  305. nvmath/sparse/generic/_thunks.py +21 -0
  306. nvmath/sparse/generic/matmulmod.py +2353 -0
  307. nvmath/sparse/ust/__init__.py +7 -0
  308. nvmath/sparse/ust/_converters.py +422 -0
  309. nvmath/sparse/ust/_cpp.py +28 -0
  310. nvmath/sparse/ust/_drawer.py +565 -0
  311. nvmath/sparse/ust/_emitter.py +1033 -0
  312. nvmath/sparse/ust/_jit.py +188 -0
  313. nvmath/sparse/ust/_kernel.py +282 -0
  314. nvmath/sparse/ust/_utils.py +149 -0
  315. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  316. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  317. nvmath/sparse/ust/tensor.py +1016 -0
  318. nvmath/sparse/ust/tensor_format.py +957 -0
  319. nvmath/tensor/__init__.py +6 -0
  320. nvmath/tensor/_configuration.py +120 -0
  321. nvmath/tensor/_internal/__init__.py +3 -0
  322. nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
  323. nvmath/tensor/_internal/cutensor_utils.py +230 -0
  324. nvmath/tensor/_internal/data.py +43 -0
  325. nvmath/tensor/_internal/einsum_parser.py +444 -0
  326. nvmath/tensor/_internal/typemaps.py +96 -0
  327. nvmath/tensor/contract.py +1900 -0
  328. nvmath_python-1.0.0.dist-info/METADATA +134 -0
  329. nvmath_python-1.0.0.dist-info/RECORD +332 -0
  330. nvmath_python-1.0.0.dist-info/WHEEL +5 -0
  331. nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
  332. nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
nvmath/device/types.py ADDED
@@ -0,0 +1,138 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ __all__ = [
6
+ "Complex",
7
+ "Vector",
8
+ "complex32",
9
+ "complex64",
10
+ "complex128",
11
+ "half2",
12
+ "half4",
13
+ "np_float16x2",
14
+ "np_float16x4",
15
+ "REAL_NP_TYPES",
16
+ "INT_NP_TYPES",
17
+ ]
18
+
19
+ import warnings
20
+
21
+ import numpy as np
22
+
23
+ np_float16x2 = np.dtype([("x", np.float16), ("y", np.float16)], align=True)
24
+ np_float16x4 = np.dtype([("x", np.float16), ("y", np.float16), ("z", np.float16), ("w", np.float16)], align=True)
25
+
26
+ REAL_NP_TYPES: list = [np.float16, np.float32, np.float64]
27
+ INT_NP_TYPES: list = [np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64]
28
+
29
+ _alignment_warning_msg = (
30
+ "You are using the host counterpart of a dtype that is under-aligned "
31
+ "compared to what the device function expects. In most cases this will "
32
+ "work, since device memory is typically allocated with at least 256-byte "
33
+ "alignment. For details on device memory access and built-in type "
34
+ "alignment requirements, see "
35
+ "https://docs.nvidia.com/cuda/cuda-c-programming-guide/#device-memory-accesses "
36
+ "and "
37
+ "https://docs.nvidia.com/cuda/cuda-programming-guide/05-appendices/cpp-language-extensions.html#built-in-types"
38
+ )
39
+
40
+
41
+ class Complex:
42
+ """
43
+ Complex type that can be used to represent complex numbers both
44
+ on host and device side. Numpy does not provide a built-in complex type with
45
+ 16-bit real and imaginary parts, so we define our own dtype for that case.
46
+ For 32-bit and 64-bit complex numbers, we can use the built-in numpy dtypes.
47
+ However on device side we expect those types to be aligned to the full size
48
+ of the complex type, so the array defined on host and device side will have
49
+ different type and alignment. :py:const:`np_float16x2`,
50
+ ``numpy.dtype(numpy.complex64)`` and
51
+ ``numpy.dtype(numpy.complex128)`` are the host side dtypes and
52
+ :py:const:`float16x2_type`, :py:const:`float32x2_type` and
53
+ :py:const:`float64x2_type` are the device side types.
54
+ """
55
+
56
+ def __init__(self, real_dtype):
57
+ self._real_dtype = real_dtype
58
+
59
+ @property
60
+ def real_dtype(self):
61
+ return self._real_dtype
62
+
63
+ @property
64
+ def dtype(self):
65
+ warnings.warn(_alignment_warning_msg, UserWarning, stacklevel=2)
66
+ if self._real_dtype == np.float16:
67
+ return np_float16x2
68
+ elif self._real_dtype == np.float32:
69
+ return np.dtype(np.complex64)
70
+ assert self._real_dtype == np.float64
71
+ return np.dtype(np.complex128)
72
+
73
+ @property
74
+ def _numba_type(self):
75
+ from .vector_types_numba import float16x2_type, float32x2_type, float64x2_type
76
+
77
+ if self.real_dtype == np.float16:
78
+ return float16x2_type
79
+ if self.real_dtype == np.float32:
80
+ return float32x2_type
81
+ assert self.real_dtype == np.float64
82
+ return float64x2_type
83
+
84
+
85
+ complex32 = Complex(np.float16)
86
+ complex64 = Complex(np.float32)
87
+ complex128 = Complex(np.float64)
88
+
89
+
90
+ class Vector:
91
+ """
92
+ Vector type that can be used to represent vector values both
93
+ on host and device side. Host side representation uses numpy structured
94
+ dtypes to represent the vector components, while device side representation
95
+ uses custom numba types. This difference is necessary because device
96
+ functions expect alignment of the vector types to be the same as the size of
97
+ the vector, which is not the case for numpy structured dtypes.
98
+ :py:const:`np_float16x2` and :py:const:`np_float16x4` are the host side
99
+ dtypes and :py:const:`float16x2_type` and :py:const:`float16x4_type` are the
100
+ device side types.
101
+ """
102
+
103
+ def __init__(self, real_dtype, size):
104
+ if size not in (2, 4):
105
+ raise ValueError(f"Unsupported vector size {size}, only 2 and 4 are supported")
106
+ if real_dtype != np.float16:
107
+ raise ValueError(f"Unsupported vector real dtype {real_dtype}, only float16 is supported")
108
+ self._real_dtype = real_dtype
109
+ self._size = size
110
+
111
+ @property
112
+ def real_dtype(self):
113
+ return self._real_dtype
114
+
115
+ @property
116
+ def size(self):
117
+ return self._size
118
+
119
+ @property
120
+ def dtype(self):
121
+ warnings.warn(_alignment_warning_msg, UserWarning, stacklevel=2)
122
+ if self._size == 2:
123
+ return np_float16x2
124
+ assert self._size == 4
125
+ return np_float16x4
126
+
127
+ @property
128
+ def _numba_type(self):
129
+ from .vector_types_numba import float16x2_type, float16x4_type
130
+
131
+ if self._size == 2:
132
+ return float16x2_type
133
+ assert self._size == 4
134
+ return float16x4_type
135
+
136
+
137
+ half2 = Vector(np.float16, 2)
138
+ half4 = Vector(np.float16, 4)
@@ -0,0 +1,259 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ __all__ = [
6
+ "float16x2",
7
+ "float16x4",
8
+ "float32x2",
9
+ "float32x4",
10
+ "float64x2",
11
+ "float64x4",
12
+ "uint32x4",
13
+ "float16x2_type",
14
+ "float16x4_type",
15
+ "float32x2_type",
16
+ "float32x4_type",
17
+ "float64x2_type",
18
+ "float64x4_type",
19
+ "uint32x4_type",
20
+ ]
21
+
22
+ import typing
23
+
24
+ from llvmlite import ir
25
+ from numba.core import types
26
+ from numba.core.typeconv import Conversion
27
+ from numba.core.typing.templates import AttributeTemplate
28
+ from numba.cuda.cudadecl import registry as cuda_registry
29
+ from numba.cuda.cudaimpl import lower_attr as cuda_lower_attr
30
+ from numba.cuda.extending import as_numba_type, lower_builtin, lower_cast, overload, register_model, type_callable
31
+ from numba.extending import models
32
+
33
+
34
+ def make_vector(
35
+ scalar_type: types.Number,
36
+ llvm_scalar_type,
37
+ vector_length: typing.Literal[2, 4],
38
+ ):
39
+ assert vector_length == 2 or vector_length == 4
40
+ assert isinstance(scalar_type, (types.Float, types.Integer))
41
+ vector_name = f"{scalar_type.name}x{vector_length}"
42
+ vector_bitwidth = vector_length * scalar_type.bitwidth
43
+ if isinstance(scalar_type, types.Float):
44
+ scalar_class = types.Float
45
+ else:
46
+ scalar_class = types.Integer
47
+
48
+ # User visible types and functions
49
+ class vector:
50
+ def __init__(self, *args):
51
+ pass
52
+
53
+ def create(input):
54
+ pass
55
+
56
+ # FE types
57
+ class vectorType(types.Number):
58
+ def __init__(self):
59
+ super().__init__(name=f"vector({scalar_type.name}x{vector_length})")
60
+ self.dtype = scalar_type
61
+ self.count = vector_length
62
+ self.bitwidth = vector_bitwidth
63
+ self.make = vector
64
+
65
+ def can_convert_from(self, typingctx, other):
66
+ if scalar_class is types.Float and vector_length == 2 and isinstance(other, types.Complex):
67
+ if other.bitwidth == vector_bitwidth:
68
+ return Conversion.exact
69
+ elif other.bitwidth < vector_bitwidth:
70
+ return Conversion.safe
71
+ elif other.bitwidth > vector_bitwidth:
72
+ return Conversion.unsafe
73
+
74
+ def can_convert_to(self, typingctx, other):
75
+ if scalar_class is types.Float and vector_length == 2 and isinstance(other, types.Complex):
76
+ if other.bitwidth == vector_bitwidth:
77
+ return Conversion.exact
78
+ elif other.bitwidth < vector_bitwidth:
79
+ return Conversion.unsafe
80
+ elif other.bitwidth > vector_bitwidth:
81
+ return Conversion.safe
82
+
83
+ def __name__(self):
84
+ return f"vector({scalar_type.name}x{vector_length})"
85
+
86
+ vector_type = vectorType()
87
+
88
+ types.number_domain = types.number_domain | frozenset([vector_type])
89
+
90
+ # Type inference (Python --> FE type)
91
+ as_numba_type.register(vector, vector_type)
92
+
93
+ # How to build a vectorType from individual elements
94
+ @type_callable(vector)
95
+ def type(context):
96
+ def typer(x, y=None, z=None, w=None):
97
+ if (
98
+ (
99
+ scalar_class is types.Float
100
+ and vector_length == 2
101
+ and isinstance(x, types.Complex)
102
+ and y is None
103
+ and z is None
104
+ and w is None
105
+ )
106
+ or (vector_length == 2 and all(isinstance(v, scalar_class) for v in [x, y]) and z is None and w is None)
107
+ or (vector_length == 4 and all(isinstance(v, scalar_class) for v in [x, y, z, w]))
108
+ ):
109
+ return vector_type
110
+
111
+ return typer
112
+
113
+ # How to represent vectorType in Memory?
114
+ @register_model(vectorType)
115
+ class vectorTypeModel(models.PrimitiveModel):
116
+ def __init__(self, dmm, fe_type):
117
+ be_type = ir.IntType(vector_bitwidth)
118
+ super().__init__(dmm, fe_type, be_type)
119
+
120
+ # How to build a vectorType from individual float values?
121
+ @lower_builtin(vector, *(vector_length * [scalar_class])) # FIXME
122
+ def vector_ctor(context, builder, sig, args):
123
+ typ = sig.return_type
124
+ args = list(args)
125
+ assert len(args) == vector_length
126
+ for i in range(vector_length):
127
+ args[i] = context.cast(builder, args[i], sig.args[i], scalar_type)
128
+
129
+ vt = ir.VectorType(llvm_scalar_type, vector_length)
130
+ val = ir.Constant(vt, ir.Undefined)
131
+
132
+ for i in range(vector_length):
133
+ val = builder.insert_element(val, args[i], context.get_constant(types.int32, i))
134
+
135
+ return builder.bitcast(val, context.get_value_type(typ))
136
+
137
+ # How to access .x, .y, .z, .w
138
+ @cuda_registry.register_attr
139
+ class complex_attrs(AttributeTemplate):
140
+ key = vectorType
141
+
142
+ def resolve_x(self, mod):
143
+ return scalar_type
144
+
145
+ def resolve_y(self, mod):
146
+ return scalar_type
147
+
148
+ def resolve_z(self, mod):
149
+ return scalar_type
150
+
151
+ def resolve_w(self, mod):
152
+ return scalar_type
153
+
154
+ def complex_get(context, builder, typ, val, i):
155
+ vt = ir.VectorType(llvm_scalar_type, vector_length)
156
+ vec = builder.bitcast(val, vt)
157
+ index = context.get_constant(types.int32, i)
158
+ return builder.extract_element(vec, index)
159
+
160
+ # This cannot be done with a loop
161
+ @cuda_lower_attr(vectorType, "x")
162
+ def complex_get_x(context, builder, typ, val):
163
+ return complex_get(context, builder, typ, val, 0)
164
+
165
+ @cuda_lower_attr(vectorType, "y")
166
+ def complex_get_y(context, builder, typ, val):
167
+ return complex_get(context, builder, typ, val, 1)
168
+
169
+ if vector_length == 4:
170
+
171
+ @cuda_lower_attr(vectorType, "z")
172
+ def complex_get_z(context, builder, typ, val):
173
+ return complex_get(context, builder, typ, val, 2)
174
+
175
+ @cuda_lower_attr(vectorType, "w")
176
+ def complex_get_w(context, builder, typ, val):
177
+ return complex_get(context, builder, typ, val, 3)
178
+
179
+ # Conversions from types.Complex
180
+ if scalar_class is types.Float and vector_length == 2:
181
+
182
+ @overload(create)
183
+ def make_complex(cplx):
184
+ if isinstance(cplx, types.Complex):
185
+
186
+ def impl(cplx):
187
+ return vector(cplx.real, cplx.imag)
188
+
189
+ return impl
190
+
191
+ @lower_cast(types.Complex, vector_type)
192
+ def np_complex_to_complex(context, builder, fromty, toty, val):
193
+ src = context.make_complex(builder, fromty, value=val)
194
+ src_float_ty = fromty.underlying_float
195
+ ctor_sig = toty(src_float_ty, src_float_ty)
196
+ ctor_args = (src.real, src.imag)
197
+ return vector_ctor(context, builder, ctor_sig, ctor_args)
198
+
199
+ @lower_cast(vector_type, types.Complex)
200
+ def complex_to_np_complex(context, builder, fromty, toty, val):
201
+ dst_float_ty = toty.underlying_float
202
+ x = complex_get(context, builder, fromty, val, 0)
203
+ y = complex_get(context, builder, fromty, val, 1)
204
+ x = context.cast(builder, x, scalar_type, dst_float_ty)
205
+ y = context.cast(builder, y, scalar_type, dst_float_ty)
206
+ vt = context.get_value_type(toty)
207
+ val = ir.Constant(vt, ir.Undefined)
208
+ val = builder.insert_value(val, x, [0])
209
+ val = builder.insert_value(val, y, [1])
210
+ return val
211
+
212
+ vector.__name__ = vector_name
213
+ attrs = "``x`` and ``y``" if vector_length == 2 else "``x``, ``y``, ``z``, and ``w``"
214
+ vector.__doc__ = f"""
215
+ {vector_name}({"x, y" if vector_length == 2 else "x, y, z, w"})
216
+
217
+ A Numba-compliant vector object for {scalar_type.name} with vector length {vector_length}.
218
+ Elements can be accessed with the {attrs} attributes.
219
+ """
220
+ return vector, vector_type
221
+
222
+
223
+ class VectorTypeClass(types.NumberClass):
224
+ """
225
+ NumberClass for the vector FE types.
226
+ Reuses NumberClass for the DTypeSpec behavior but routes cls(x, y, ...)
227
+ to the vector constructor instead of NumberClass's single-value scalar cast.
228
+ """
229
+
230
+ def get_impl_key(self, sig):
231
+ return self.instance_type.make
232
+
233
+
234
+ register_model(VectorTypeClass)(models.OpaqueModel)
235
+
236
+
237
+ @cuda_registry.register_attr
238
+ class _VectorTypeClassCallAttribute(AttributeTemplate):
239
+ """
240
+ Overrides NumberClass's scalar-cast __call__.
241
+ Resolves cls(x, y, ...) to the vector constructor,
242
+ so calls build a vector instead of attempting a single-value cast.
243
+ """
244
+
245
+ key = VectorTypeClass
246
+
247
+ def resolve___call__(self, classty):
248
+ return self.context.resolve_value_type(classty.instance_type.make)
249
+
250
+
251
+ # IMPORTANT: take care to update symbol list in docs/sphinx/device-apis/utils.rst
252
+ # and docstring processing in docs/sphinx/conf.py if names are changed or types are added
253
+ float16x2, float16x2_type = make_vector(types.float16, ir.IntType(16), 2)
254
+ float16x4, float16x4_type = make_vector(types.float16, ir.IntType(16), 4)
255
+ float32x2, float32x2_type = make_vector(types.float32, ir.FloatType(), 2)
256
+ float32x4, float32x4_type = make_vector(types.float32, ir.FloatType(), 4)
257
+ float64x2, float64x2_type = make_vector(types.float64, ir.DoubleType(), 2)
258
+ float64x4, float64x4_type = make_vector(types.float64, ir.DoubleType(), 4)
259
+ uint32x4, uint32x4_type = make_vector(types.uint32, ir.IntType(32), 4)
@@ -0,0 +1,200 @@
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
+ import sys
8
+
9
+ if sys.platform != "linux":
10
+ raise ImportError("nvmath.distributed is only supported on Linux.")
11
+
12
+ import atexit
13
+ from collections.abc import Sequence
14
+ from dataclasses import dataclass
15
+ from threading import Lock
16
+ from typing import TYPE_CHECKING, Any, Literal
17
+
18
+ import numpy as np
19
+ from cuda.core import Device
20
+
21
+ if TYPE_CHECKING:
22
+ import mpi4py
23
+
24
+ from nvmath.internal.utils import device_ctx
25
+
26
+ from . import distribution, fft, linalg
27
+ from ._internal import nvshmem
28
+ from ._utils import allocate_symmetric_memory, free_symmetric_memory
29
+ from .process_group import MPIProcessGroup, ProcessGroup, TorchProcessGroup
30
+
31
+ __all__ = [
32
+ "initialize",
33
+ "finalize",
34
+ "get_context",
35
+ "ProcessGroup",
36
+ "MPIProcessGroup",
37
+ "TorchProcessGroup",
38
+ "allocate_symmetric_memory",
39
+ "free_symmetric_memory",
40
+ "distribution",
41
+ "fft",
42
+ "linalg",
43
+ ]
44
+
45
+ _initialize_mutex = Lock()
46
+ _atexit_registered = False
47
+ _ctx = None
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class DistributedContext:
52
+ """
53
+ Context of initialized ``nvmath.distributed`` runtime.
54
+
55
+ Attributes:
56
+ device_id: CUDA device ID associated with the distributed runtime
57
+ on this process.
58
+
59
+ process_group: ``nvmath.distributed`` participating processes.
60
+
61
+ nvshmem_available: True if NVSHMEM backend was selected at initialization.
62
+
63
+ nccl_comm: nccl4py communicator if NCCL backend was selected at
64
+ initialization, None otherwise.
65
+ """
66
+
67
+ device_id: int
68
+ process_group: ProcessGroup
69
+ nvshmem_available: bool
70
+ nccl_comm: Any | None
71
+
72
+
73
+ def initialize(
74
+ device_id: int,
75
+ process_group: ProcessGroup | mpi4py.MPI.Comm,
76
+ backends: Sequence[Literal["nvshmem", "nccl"]],
77
+ ) -> None:
78
+ """Initialize ``nvmath.distributed`` runtime. This is required before any distributed
79
+ operations can be performed. **Note that this is a collective operation and must be
80
+ called by all processes.**
81
+
82
+ If the runtime is already initialized this function will raise an error. If you need
83
+ to reinitialize the runtime (for example with different backends) you have to finalize
84
+ it first.
85
+
86
+ Note: NCCL doesn't allow assigning more than one process to the same GPU.
87
+
88
+ Args:
89
+ device_id: CUDA device ID to associate with the ``nvmath.distributed`` runtime
90
+ on this process.
91
+
92
+ process_group: ProcessGroup (or mpi4py communicator) specifying the participating
93
+ processes. This is used for setup and not for communication during compute.
94
+
95
+ backends: Communication backends to use in distributed computations. Valid values
96
+ are "nvshmem" and "nccl". Note that specific libraries (cuFFTMp, cuBLASMp, ...)
97
+ have specific required backends.
98
+ """
99
+ if not isinstance(device_id, int):
100
+ raise TypeError(
101
+ "The device ID used to initialize the nvmath.distributed module "
102
+ f"must be an integer. The provided device ID is {device_id}."
103
+ )
104
+
105
+ valid_backends = ("nvshmem", "nccl")
106
+ for backend in backends:
107
+ if backend not in valid_backends:
108
+ raise ValueError(f"backend must be one of {valid_backends}, got {backend}")
109
+
110
+ if len(backends) == 0:
111
+ raise ValueError(f"Need to specify at least one of {valid_backends} communication backends")
112
+
113
+ if process_group is None:
114
+ raise ValueError("process_group cannot be None")
115
+
116
+ with _initialize_mutex:
117
+ global _atexit_registered, _ctx
118
+
119
+ if _ctx is not None:
120
+ raise RuntimeError("nvmath.distributed has already been initialized")
121
+
122
+ if not _atexit_registered:
123
+ atexit.register(finalize)
124
+ _atexit_registered = True
125
+
126
+ if not isinstance(process_group, ProcessGroup):
127
+ valid_process_group = False
128
+ if "mpi4py" in sys.modules:
129
+ import mpi4py.MPI
130
+
131
+ if isinstance(process_group, mpi4py.MPI.Comm):
132
+ process_group = MPIProcessGroup(process_group)
133
+ valid_process_group = True
134
+ if not valid_process_group:
135
+ raise TypeError(
136
+ f"Unrecognized process group type ({process_group}). "
137
+ "Need nvmath.distributed.ProcessGroup or mpi4py communicator."
138
+ )
139
+
140
+ assert isinstance(process_group, ProcessGroup) # for type-checker
141
+ rank = process_group.rank
142
+ nranks = process_group.nranks
143
+
144
+ # Set the device for NVSHMEM and NCCL initialization, but also need to make sure
145
+ # that a CUDA context has been created. We can't rely on `device_ctx` to do it
146
+ # since it's not guaranteed to make a runtime API call.
147
+ old_device = Device()
148
+ device = Device(device_id)
149
+ device.set_current()
150
+
151
+ try:
152
+ nvshmem_available = False
153
+ if "nvshmem" in backends:
154
+ nvshmem.initialize(device_id, process_group)
155
+ nvshmem_available = True
156
+
157
+ nccl_comm = None
158
+ if "nccl" in backends:
159
+ # Don't want to import this at the global scope yet because
160
+ # `import nccl.core` imports cupy and torch (with nccl4py 0.1.1)
161
+ import nccl.core as nccl # type: ignore
162
+
163
+ # Create NCCL communicator.
164
+ unique_id = nccl.get_unique_id()
165
+ process_group.broadcast_buffer(unique_id.as_ndarray.view(np.int8), root=0)
166
+ nccl_comm = nccl.Communicator.init(nranks=nranks, rank=rank, unique_id=unique_id)
167
+
168
+ _ctx = DistributedContext(
169
+ device_id=device_id, process_group=process_group, nvshmem_available=nvshmem_available, nccl_comm=nccl_comm
170
+ )
171
+ finally:
172
+ old_device.set_current()
173
+
174
+
175
+ def finalize() -> None:
176
+ """Finalize ``nvmath.distributed`` runtime (this is called automatically at exit
177
+ if the runtime is initialized). **Note that this is a collective operation and
178
+ must be called by all processes.**"""
179
+ global _ctx
180
+ with _initialize_mutex:
181
+ if _ctx is None:
182
+ return
183
+
184
+ linalg.advanced.matmulmod._grid_cache.clear()
185
+ linalg.generic._caching.clear_handles()
186
+
187
+ if _ctx.nccl_comm is not None:
188
+ with device_ctx(_ctx.device_id):
189
+ _ctx.nccl_comm.finalize()
190
+ _ctx.nccl_comm.destroy()
191
+
192
+ if _ctx.nvshmem_available:
193
+ nvshmem.finalize(_ctx.device_id)
194
+
195
+ _ctx = None
196
+
197
+
198
+ def get_context() -> DistributedContext | None:
199
+ """Return the distributed runtime's context or None if not initialized."""
200
+ return _ctx
File without changes
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from __future__ import annotations
6
+
7
+ __all__ = [
8
+ "nccl_empty_dlpack",
9
+ "NcclNDBufferAllocator",
10
+ ]
11
+
12
+ import logging
13
+ from typing import TYPE_CHECKING
14
+
15
+ from .symmetric_memory import calculate_symmetric_size
16
+
17
+ if TYPE_CHECKING:
18
+ from cuda.core import Buffer, Stream
19
+
20
+ from nvmath.distributed import DistributedContext
21
+ from nvmath.distributed.process_group import ProcessGroup
22
+
23
+
24
+ def nccl_empty_dlpack(
25
+ size: int,
26
+ device_id: int,
27
+ process_group: ProcessGroup,
28
+ make_symmetric: bool = False,
29
+ skip_symmetric_check: bool = False,
30
+ logger: logging.Logger | None = None,
31
+ ) -> Buffer:
32
+ """
33
+ Allocates a buffer with nccl4py. This function can be used to prepare a buffer
34
+ for symmetric memory registration, but **doesn't register the buffer as symmetric
35
+ memory** (because buffer registrations in NCCL are not global but on a
36
+ per-communicator basis, so for registration the buffer typically has to be passed
37
+ to the library that owns the communicator).
38
+
39
+ This is a collective call when ``make_symmetric=True`` or
40
+ ``skip_symmetric_check=False``.
41
+
42
+ Args:
43
+ size: Number of bytes to allocate.
44
+
45
+ device_id: Device on which to allocate.
46
+
47
+ process_group: nvmath.distributed process group.
48
+
49
+ make_symmetric: If the buffer is going to be registered with NCCL symmetric memory,
50
+ use ``make_symmetric=True`` to allocate the same size on every process (padding
51
+ the buffer to the maximum size given by all processes).
52
+
53
+ skip_symmetric_check: True if buffer is not needed for NCCL symmetric memory or
54
+ already known to be of the same size on every process.
55
+ """
56
+
57
+ logger = logger if logger is not None else logging.getLogger()
58
+
59
+ size = calculate_symmetric_size(size, process_group, make_symmetric, skip_symmetric_check, logger)
60
+
61
+ import nccl.core as nccl # type: ignore
62
+
63
+ mem_buffer = nccl.buffer.mem_alloc(size, device_id)
64
+ return mem_buffer
65
+
66
+
67
+ class NcclNDBufferAllocator:
68
+ __slots__ = ("ctx", "make_symmetric", "skip_symmetric_check")
69
+
70
+ def __init__(self, device_id: int, ctx: DistributedContext, make_symmetric: bool, skip_symmetric_check: bool):
71
+ assert ctx.device_id == device_id, (
72
+ "Internal error: attempting to allocate symmetric memory on a device not used by NCCL on this process"
73
+ )
74
+ self.ctx = ctx
75
+ self.make_symmetric = make_symmetric
76
+ self.skip_symmetric_check = skip_symmetric_check
77
+
78
+ def allocate(self, size: int, stream: Stream, logger: logging.Logger | None = None) -> Buffer:
79
+ return nccl_empty_dlpack(
80
+ size,
81
+ self.ctx.device_id,
82
+ self.ctx.process_group,
83
+ make_symmetric=self.make_symmetric,
84
+ skip_symmetric_check=self.skip_symmetric_check,
85
+ logger=logger,
86
+ )