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