vramsuite 0.5.0__py3-none-any.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.
- vramsuite/__init__.py +18 -0
- vramsuite/__main__.py +59 -0
- vramsuite/backends/__init__.py +0 -0
- vramsuite/backends/cublas.py +281 -0
- vramsuite/backends/cublaslt/__init__.py +44 -0
- vramsuite/backends/cublaslt/descriptors.py +243 -0
- vramsuite/backends/cublaslt/enums.py +52 -0
- vramsuite/backends/cublaslt/errors.py +29 -0
- vramsuite/backends/cublaslt/heuristics.py +139 -0
- vramsuite/backends/cublaslt/layouts.py +159 -0
- vramsuite/backends/cublaslt/matmul.py +69 -0
- vramsuite/backends/cublaslt/runtime.py +296 -0
- vramsuite/backends/cublaslt/workspace.py +41 -0
- vramsuite/backends/cuda.py +511 -0
- vramsuite/backends/cuda_driver.py +267 -0
- vramsuite/backends/native_loader.py +153 -0
- vramsuite/backends/nvml.py +504 -0
- vramsuite/backends/windows_gpu.py +206 -0
- vramsuite/cli/__init__.py +0 -0
- vramsuite/cli/main.py +591 -0
- vramsuite/compute/__init__.py +0 -0
- vramsuite/compute/compute_math.py +142 -0
- vramsuite/compute/cublaslt_math.py +327 -0
- vramsuite/compute/minifloat.py +115 -0
- vramsuite/compute/validation.py +13 -0
- vramsuite/core/__init__.py +0 -0
- vramsuite/core/advise.py +160 -0
- vramsuite/core/bundle.py +103 -0
- vramsuite/core/comfy.py +79 -0
- vramsuite/core/compare.py +162 -0
- vramsuite/core/doctor.py +140 -0
- vramsuite/core/estimate.py +176 -0
- vramsuite/core/fingerprint.py +95 -0
- vramsuite/core/model_inspect.py +135 -0
- vramsuite/core/probe.py +180 -0
- vramsuite/core/processes.py +190 -0
- vramsuite/core/profile.py +197 -0
- vramsuite/core/reports.py +618 -0
- vramsuite/core/risk.py +127 -0
- vramsuite/core/runtime.py +102 -0
- vramsuite/core/transfer.py +160 -0
- vramsuite/core/validate.py +141 -0
- vramsuite/core/vramcard.py +282 -0
- vramsuite/core/workflow.py +298 -0
- vramsuite-0.5.0.dist-info/METADATA +273 -0
- vramsuite-0.5.0.dist-info/RECORD +49 -0
- vramsuite-0.5.0.dist-info/WHEEL +4 -0
- vramsuite-0.5.0.dist-info/entry_points.txt +2 -0
- vramsuite-0.5.0.dist-info/licenses/LICENSE +21 -0
vramsuite/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
|
|
5
|
+
from vramsuite.core.doctor import run_doctor
|
|
6
|
+
from vramsuite.core.fingerprint import collect_fingerprint
|
|
7
|
+
from vramsuite.core.vramcard import create_vramcard, load_vramcard, save_vramcard
|
|
8
|
+
|
|
9
|
+
__version__ = importlib.metadata.version("vramsuite")
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"__version__",
|
|
13
|
+
"run_doctor",
|
|
14
|
+
"collect_fingerprint",
|
|
15
|
+
"create_vramcard",
|
|
16
|
+
"save_vramcard",
|
|
17
|
+
"load_vramcard",
|
|
18
|
+
]
|
vramsuite/__main__.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`python -m vramsuite` and the entry point of the Windows exe.
|
|
3
|
+
|
|
4
|
+
Double-clicking the exe opens a console that closes as soon as the program
|
|
5
|
+
exits. In that case the exe runs `doctor` and waits for Enter instead of
|
|
6
|
+
printing the help and vanishing.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import platform
|
|
13
|
+
import sys
|
|
14
|
+
import traceback
|
|
15
|
+
|
|
16
|
+
from vramsuite.cli.main import app
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _started_by_double_click() -> bool:
|
|
20
|
+
"""
|
|
21
|
+
True when no other program shares this console: Explorer created it for us.
|
|
22
|
+
|
|
23
|
+
From a terminal, the shell is attached too. The one-file exe runs as two
|
|
24
|
+
processes (the PyInstaller bootloader and its Python child, this one),
|
|
25
|
+
both attached to the console, so the bootloader parent does not count.
|
|
26
|
+
"""
|
|
27
|
+
if platform.system() != "Windows":
|
|
28
|
+
return False
|
|
29
|
+
import ctypes
|
|
30
|
+
|
|
31
|
+
kernel32 = ctypes.windll.kernel32
|
|
32
|
+
kernel32.GetConsoleProcessList.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint32]
|
|
33
|
+
kernel32.GetConsoleProcessList.restype = ctypes.c_uint32
|
|
34
|
+
processes = (ctypes.c_uint32 * 16)()
|
|
35
|
+
count = kernel32.GetConsoleProcessList(processes, 16)
|
|
36
|
+
|
|
37
|
+
ours = {os.getpid()}
|
|
38
|
+
if getattr(sys, "frozen", False):
|
|
39
|
+
ours.add(os.getppid())
|
|
40
|
+
return 0 < count <= 16 and not set(processes[:count]) - ours
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main() -> None:
|
|
44
|
+
if len(sys.argv) == 1 and _started_by_double_click():
|
|
45
|
+
sys.argv += ["doctor", "--no-write-card"]
|
|
46
|
+
try:
|
|
47
|
+
app()
|
|
48
|
+
except SystemExit:
|
|
49
|
+
pass
|
|
50
|
+
except Exception:
|
|
51
|
+
# Show the error instead of a window that closes before it can be read.
|
|
52
|
+
traceback.print_exc()
|
|
53
|
+
input("\nPress Enter to close...")
|
|
54
|
+
return
|
|
55
|
+
app()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import platform
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from vramsuite.backends.cublaslt.errors import decode_cublas_status
|
|
10
|
+
from vramsuite.backends.native_loader import load_native_library
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
CUBLAS_STATUS_SUCCESS = 0
|
|
14
|
+
|
|
15
|
+
CUBLAS_OP_N = 0
|
|
16
|
+
CUBLAS_OP_T = 1
|
|
17
|
+
CUBLAS_OP_C = 2
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class CublasInfo:
|
|
21
|
+
available: bool
|
|
22
|
+
error: str | None
|
|
23
|
+
library_path: str | None
|
|
24
|
+
handle_created: bool
|
|
25
|
+
version: int | None
|
|
26
|
+
version_text: str | None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _candidate_library_names() -> list[str]:
|
|
30
|
+
system = platform.system()
|
|
31
|
+
|
|
32
|
+
if system == "Windows":
|
|
33
|
+
return [
|
|
34
|
+
"cublas64_13.dll",
|
|
35
|
+
"cublas64_12.dll",
|
|
36
|
+
"cublas64_11.dll",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
if system == "Linux":
|
|
40
|
+
return [
|
|
41
|
+
"libcublas.so",
|
|
42
|
+
"libcublas.so.13",
|
|
43
|
+
"libcublas.so.12",
|
|
44
|
+
"libcublas.so.11",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
return ["libcublas.so"]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _check(status: int, operation: str) -> str | None:
|
|
51
|
+
if status == CUBLAS_STATUS_SUCCESS:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
return f"{operation} failed: {decode_cublas_status(status)}"
|
|
55
|
+
|
|
56
|
+
def _format_cublas_version(version: int | None) -> str | None:
|
|
57
|
+
if version is None:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
major = version // 10000
|
|
61
|
+
minor = (version % 10000) // 100
|
|
62
|
+
patch = version % 100
|
|
63
|
+
|
|
64
|
+
return f"{major}.{minor}.{patch}"
|
|
65
|
+
|
|
66
|
+
def _configure_signatures(cublas: ctypes.CDLL) -> None:
|
|
67
|
+
cublas.cublasCreate_v2.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
|
|
68
|
+
cublas.cublasCreate_v2.restype = ctypes.c_int
|
|
69
|
+
|
|
70
|
+
cublas.cublasDestroy_v2.argtypes = [ctypes.c_void_p]
|
|
71
|
+
cublas.cublasDestroy_v2.restype = ctypes.c_int
|
|
72
|
+
|
|
73
|
+
cublas.cublasGetVersion_v2.argtypes = [
|
|
74
|
+
ctypes.c_void_p,
|
|
75
|
+
ctypes.POINTER(ctypes.c_int),
|
|
76
|
+
]
|
|
77
|
+
cublas.cublasGetVersion_v2.restype = ctypes.c_int
|
|
78
|
+
|
|
79
|
+
cublas.cublasSgemm_v2.argtypes = [
|
|
80
|
+
ctypes.c_void_p, # handle
|
|
81
|
+
ctypes.c_int, # transa
|
|
82
|
+
ctypes.c_int, # transb
|
|
83
|
+
ctypes.c_int, # m
|
|
84
|
+
ctypes.c_int, # n
|
|
85
|
+
ctypes.c_int, # k
|
|
86
|
+
ctypes.POINTER(ctypes.c_float), # alpha
|
|
87
|
+
ctypes.c_void_p, # A
|
|
88
|
+
ctypes.c_int, # lda
|
|
89
|
+
ctypes.c_void_p, # B
|
|
90
|
+
ctypes.c_int, # ldb
|
|
91
|
+
ctypes.POINTER(ctypes.c_float), # beta
|
|
92
|
+
ctypes.c_void_p, # c
|
|
93
|
+
ctypes.c_int, # ldc
|
|
94
|
+
]
|
|
95
|
+
cublas.cublasSgemm_v2.restype = ctypes.c_int
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class CublasRuntime:
|
|
99
|
+
def __init__(self) -> None:
|
|
100
|
+
self._native_library = None
|
|
101
|
+
self.cublas: ctypes.CDLL | None = None
|
|
102
|
+
self.library_path: str | None = None
|
|
103
|
+
self.handle: ctypes.c_void_p | None = None
|
|
104
|
+
|
|
105
|
+
def __enter__(self) -> "CublasRuntime":
|
|
106
|
+
venv_patterns = (
|
|
107
|
+
["cublas*.dll"]
|
|
108
|
+
if platform.system() == "Windows"
|
|
109
|
+
else ["libcublas.so*"]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
self._native_library = load_native_library(
|
|
113
|
+
logical_name="cublas",
|
|
114
|
+
candidates=_candidate_library_names(),
|
|
115
|
+
venv_patterns=venv_patterns,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
loaded = self._native_library.__enter__()
|
|
120
|
+
|
|
121
|
+
self.cublas = loaded.require_library()
|
|
122
|
+
self.library_path = loaded.library_path
|
|
123
|
+
|
|
124
|
+
_configure_signatures(self.cublas)
|
|
125
|
+
|
|
126
|
+
self.handle = self._create_handle()
|
|
127
|
+
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
except Exception:
|
|
131
|
+
if self._native_library is not None:
|
|
132
|
+
self._native_library.__exit__(None, None, None)
|
|
133
|
+
|
|
134
|
+
self._native_library = None
|
|
135
|
+
self.cublas = None
|
|
136
|
+
self.library_path = None
|
|
137
|
+
self.handle = None
|
|
138
|
+
|
|
139
|
+
raise
|
|
140
|
+
|
|
141
|
+
def __exit__(
|
|
142
|
+
self,
|
|
143
|
+
exc_type: type[BaseException] | None,
|
|
144
|
+
exc: BaseException | None,
|
|
145
|
+
traceback: TracebackType | None,
|
|
146
|
+
) -> None:
|
|
147
|
+
if self.handle is not None:
|
|
148
|
+
try:
|
|
149
|
+
self._destroy_handle(self.handle)
|
|
150
|
+
finally:
|
|
151
|
+
self.handle = None
|
|
152
|
+
|
|
153
|
+
self.cublas = None
|
|
154
|
+
self.library_path = None
|
|
155
|
+
|
|
156
|
+
if self._native_library is not None:
|
|
157
|
+
self._native_library.__exit__(exc_type, exc, traceback)
|
|
158
|
+
|
|
159
|
+
self._native_library = None
|
|
160
|
+
|
|
161
|
+
def _require_cublas(self) -> ctypes.CDLL:
|
|
162
|
+
if self.cublas is None:
|
|
163
|
+
raise RuntimeError("cuBLAS runtime is not loaded")
|
|
164
|
+
|
|
165
|
+
return self.cublas
|
|
166
|
+
|
|
167
|
+
def _require_handle(self) -> ctypes.c_void_p:
|
|
168
|
+
if self.handle is None:
|
|
169
|
+
raise RuntimeError("cuBLAS handle is not created")
|
|
170
|
+
|
|
171
|
+
return self.handle
|
|
172
|
+
|
|
173
|
+
def _check_status(self, status: int, operation: str) -> None:
|
|
174
|
+
error = _check(status, operation)
|
|
175
|
+
if error is not None:
|
|
176
|
+
raise RuntimeError(error)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _create_handle(self) -> ctypes.c_void_p:
|
|
180
|
+
cublas = self._require_cublas()
|
|
181
|
+
|
|
182
|
+
handle = ctypes.c_void_p()
|
|
183
|
+
status = cublas.cublasCreate_v2(ctypes.byref(handle))
|
|
184
|
+
self._check_status(status, "cublasCreate_v2")
|
|
185
|
+
|
|
186
|
+
if handle.value is None:
|
|
187
|
+
raise RuntimeError("cublasCreate_v2 returned NULL handle")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
return handle
|
|
191
|
+
|
|
192
|
+
def _destroy_handle(self, handle: ctypes.c_void_p) -> None:
|
|
193
|
+
cublas = self._require_cublas()
|
|
194
|
+
|
|
195
|
+
status = cublas.cublasDestroy_v2(handle)
|
|
196
|
+
self._check_status(status, "cublasDestroy_v2")
|
|
197
|
+
|
|
198
|
+
def get_version(self) -> int:
|
|
199
|
+
cublas = self._require_cublas()
|
|
200
|
+
handle = self._require_handle()
|
|
201
|
+
|
|
202
|
+
version = ctypes.c_int()
|
|
203
|
+
status = cublas.cublasGetVersion_v2(handle, ctypes.byref(version))
|
|
204
|
+
self._check_status(status, "cublasGetVersion_v2")
|
|
205
|
+
|
|
206
|
+
return int(version.value)
|
|
207
|
+
|
|
208
|
+
def sgemm(
|
|
209
|
+
self,
|
|
210
|
+
*,
|
|
211
|
+
m: int,
|
|
212
|
+
n: int,
|
|
213
|
+
k: int,
|
|
214
|
+
alpha: float,
|
|
215
|
+
a_ptr: ctypes.c_void_p,
|
|
216
|
+
lda: int,
|
|
217
|
+
b_ptr: ctypes.c_void_p,
|
|
218
|
+
ldb: int,
|
|
219
|
+
beta: float,
|
|
220
|
+
c_ptr: ctypes.c_void_p,
|
|
221
|
+
ldc: int,
|
|
222
|
+
transa: int = CUBLAS_OP_N,
|
|
223
|
+
transb: int = CUBLAS_OP_N,
|
|
224
|
+
) -> None:
|
|
225
|
+
cublas = self._require_cublas()
|
|
226
|
+
handle = self._require_handle()
|
|
227
|
+
|
|
228
|
+
alpha_value = ctypes.c_float(alpha)
|
|
229
|
+
beta_value = ctypes.c_float(beta)
|
|
230
|
+
|
|
231
|
+
status = cublas.cublasSgemm_v2(
|
|
232
|
+
handle,
|
|
233
|
+
transa,
|
|
234
|
+
transb,
|
|
235
|
+
m,
|
|
236
|
+
n,
|
|
237
|
+
k,
|
|
238
|
+
ctypes.byref(alpha_value),
|
|
239
|
+
a_ptr,
|
|
240
|
+
lda,
|
|
241
|
+
b_ptr,
|
|
242
|
+
ldb,
|
|
243
|
+
ctypes.byref(beta_value),
|
|
244
|
+
c_ptr,
|
|
245
|
+
ldc,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
self._check_status(status, "cublasSgemm_v2")
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def collect_info(self) -> CublasInfo:
|
|
252
|
+
version = self.get_version()
|
|
253
|
+
|
|
254
|
+
return CublasInfo(
|
|
255
|
+
available=True,
|
|
256
|
+
error=None,
|
|
257
|
+
library_path=self.library_path,
|
|
258
|
+
handle_created=self.handle is not None and self.handle.value is not None,
|
|
259
|
+
version=version,
|
|
260
|
+
version_text=_format_cublas_version(version),
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def collect_cublas_info() -> CublasInfo:
|
|
266
|
+
try:
|
|
267
|
+
with CublasRuntime() as runtime:
|
|
268
|
+
return runtime.collect_info()
|
|
269
|
+
|
|
270
|
+
except Exception as exc:
|
|
271
|
+
return CublasInfo(
|
|
272
|
+
available=False,
|
|
273
|
+
error=f"Unexpected cuBLAS runtime backend error: {exc}",
|
|
274
|
+
library_path=None,
|
|
275
|
+
handle_created=False,
|
|
276
|
+
version=None,
|
|
277
|
+
version_text=None
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
def collect_cublas_info_dict() -> dict[str, Any]:
|
|
281
|
+
return asdict(collect_cublas_info())
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from vramsuite.backends.cublaslt.descriptors import (
|
|
4
|
+
MatmulDesc,
|
|
5
|
+
MatrixLayout,
|
|
6
|
+
MatmulPreference,
|
|
7
|
+
)
|
|
8
|
+
from vramsuite.backends.cublaslt.runtime import (
|
|
9
|
+
CublasLtInfo,
|
|
10
|
+
CublasLtRuntime,
|
|
11
|
+
collect_cublaslt_info,
|
|
12
|
+
collect_cublaslt_info_dict,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from vramsuite.backends.cublaslt.layouts import (
|
|
16
|
+
GemmShape,
|
|
17
|
+
MatrixLayoutSpec,
|
|
18
|
+
MatmulLayoutSpec,
|
|
19
|
+
)
|
|
20
|
+
from vramsuite.backends.cublaslt.workspace import DeviceWorkspace
|
|
21
|
+
|
|
22
|
+
from vramsuite.backends.cublaslt.heuristics import (
|
|
23
|
+
RawMatmulHeuristic,
|
|
24
|
+
select_matmul_algorithm,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from vramsuite.backends.cublaslt.matmul import run_cublaslt_matmul
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"CublasLtInfo",
|
|
31
|
+
"CublasLtRuntime",
|
|
32
|
+
"collect_cublaslt_info",
|
|
33
|
+
"collect_cublaslt_info_dict",
|
|
34
|
+
"MatmulDesc",
|
|
35
|
+
"MatrixLayout",
|
|
36
|
+
"MatmulPreference",
|
|
37
|
+
"GemmShape",
|
|
38
|
+
"MatrixLayoutSpec",
|
|
39
|
+
"MatmulLayoutSpec",
|
|
40
|
+
"DeviceWorkspace",
|
|
41
|
+
"RawMatmulHeuristic",
|
|
42
|
+
"select_matmul_algorithm",
|
|
43
|
+
"run_cublaslt_matmul",
|
|
44
|
+
]
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
from types import TracebackType
|
|
5
|
+
|
|
6
|
+
from vramsuite.backends.cublaslt.enums import (
|
|
7
|
+
CUBLAS_COMPUTE_32F,
|
|
8
|
+
CUBLAS_OP_N,
|
|
9
|
+
CUBLASLT_MATMUL_DESC_TRANSA,
|
|
10
|
+
CUBLASLT_MATMUL_DESC_TRANSB,
|
|
11
|
+
CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
|
|
12
|
+
CUDA_R_32F,
|
|
13
|
+
)
|
|
14
|
+
from vramsuite.backends.cublaslt.errors import check_cublas_status
|
|
15
|
+
from vramsuite.backends.cublaslt.runtime import CublasLtRuntime
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CublasLtDescriptor:
|
|
20
|
+
def __init__(self, runtime: CublasLtRuntime) -> None:
|
|
21
|
+
self.runtime = runtime
|
|
22
|
+
self.ptr: ctypes.c_void_p | None = None
|
|
23
|
+
|
|
24
|
+
def _require_cublaslt(self) -> ctypes.CDLL:
|
|
25
|
+
if self.runtime.cublaslt is None:
|
|
26
|
+
raise RuntimeError("cuBLASLt runtime is not loaded")
|
|
27
|
+
|
|
28
|
+
return self.runtime.cublaslt
|
|
29
|
+
|
|
30
|
+
def _require_ptr(self) -> ctypes.c_void_p:
|
|
31
|
+
if self.ptr is None or self.ptr.value is None:
|
|
32
|
+
raise RuntimeError(f"{self.__class__.__name__} is not created")
|
|
33
|
+
|
|
34
|
+
return self.ptr
|
|
35
|
+
|
|
36
|
+
def __enter__(self):
|
|
37
|
+
self.create()
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
def __exit__(
|
|
41
|
+
self,
|
|
42
|
+
exc_type: type[BaseException] | None,
|
|
43
|
+
exc: BaseException | None,
|
|
44
|
+
traceback: TracebackType | None,
|
|
45
|
+
) -> None:
|
|
46
|
+
self.destroy()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MatmulDesc(CublasLtDescriptor):
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
runtime: CublasLtRuntime,
|
|
53
|
+
*,
|
|
54
|
+
compute_type: int = CUBLAS_COMPUTE_32F,
|
|
55
|
+
scale_type: int = CUDA_R_32F,
|
|
56
|
+
transa: int = CUBLAS_OP_N,
|
|
57
|
+
transb: int = CUBLAS_OP_N,
|
|
58
|
+
) -> None:
|
|
59
|
+
super().__init__(runtime)
|
|
60
|
+
self.compute_type = compute_type
|
|
61
|
+
self.scale_type = scale_type
|
|
62
|
+
self.transa = transa
|
|
63
|
+
self.transb = transb
|
|
64
|
+
|
|
65
|
+
def create(self) -> None:
|
|
66
|
+
if self.ptr is not None:
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
cublaslt = self._require_cublaslt()
|
|
70
|
+
|
|
71
|
+
desc = ctypes.c_void_p()
|
|
72
|
+
status = cublaslt.cublasLtMatmulDescCreate(
|
|
73
|
+
ctypes.byref(desc),
|
|
74
|
+
self.compute_type,
|
|
75
|
+
self.scale_type,
|
|
76
|
+
)
|
|
77
|
+
check_cublas_status(status, "cublasLtMatmulDescCreate")
|
|
78
|
+
|
|
79
|
+
if desc.value is None:
|
|
80
|
+
raise RuntimeError("cublasLtMatmulDescCreate returned NULL descriptor")
|
|
81
|
+
|
|
82
|
+
self.ptr = desc
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
self.set_int32_attribute(CUBLASLT_MATMUL_DESC_TRANSA, self.transa)
|
|
86
|
+
self.set_int32_attribute(CUBLASLT_MATMUL_DESC_TRANSB, self.transb)
|
|
87
|
+
except Exception:
|
|
88
|
+
# __exit__ is not called when __enter__ raises, so destroy here.
|
|
89
|
+
self.destroy()
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
def set_int32_attribute(self, attr: int, value: int) -> None:
|
|
93
|
+
cublaslt = self._require_cublaslt()
|
|
94
|
+
desc = self._require_ptr()
|
|
95
|
+
|
|
96
|
+
raw = ctypes.c_int32(value)
|
|
97
|
+
status = cublaslt.cublasLtMatmulDescSetAttribute(
|
|
98
|
+
desc,
|
|
99
|
+
attr,
|
|
100
|
+
ctypes.cast(ctypes.byref(raw), ctypes.c_void_p),
|
|
101
|
+
ctypes.sizeof(raw),
|
|
102
|
+
)
|
|
103
|
+
check_cublas_status(status, "cublasLtMatmulDescSetAttribute")
|
|
104
|
+
|
|
105
|
+
def destroy(self) -> None:
|
|
106
|
+
if self.ptr is None:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
cublaslt = self._require_cublaslt()
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
status = cublaslt.cublasLtMatmulDescDestroy(self.ptr)
|
|
113
|
+
check_cublas_status(status, "cublasLtMatmulDescDestroy")
|
|
114
|
+
finally:
|
|
115
|
+
self.ptr = None
|
|
116
|
+
|
|
117
|
+
class MatrixLayout(CublasLtDescriptor):
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
runtime: CublasLtRuntime,
|
|
121
|
+
*,
|
|
122
|
+
data_type: int = CUDA_R_32F,
|
|
123
|
+
rows: int,
|
|
124
|
+
cols: int,
|
|
125
|
+
ld: int,
|
|
126
|
+
) -> None:
|
|
127
|
+
super().__init__(runtime)
|
|
128
|
+
self.data_type = data_type
|
|
129
|
+
self.rows = rows
|
|
130
|
+
self.cols = cols
|
|
131
|
+
self.ld = ld
|
|
132
|
+
|
|
133
|
+
def create(self) -> None:
|
|
134
|
+
if self.ptr is not None:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if self.rows <= 0:
|
|
138
|
+
raise ValueError("rows must be positive")
|
|
139
|
+
if self.cols <= 0:
|
|
140
|
+
raise ValueError("cols must be positive")
|
|
141
|
+
if self.ld <= 0:
|
|
142
|
+
raise ValueError("ld must be positive")
|
|
143
|
+
if self.ld < self.rows:
|
|
144
|
+
raise ValueError("ld must be >= rows for column-major layout")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
cublaslt = self._require_cublaslt()
|
|
148
|
+
|
|
149
|
+
layout = ctypes.c_void_p()
|
|
150
|
+
status = cublaslt.cublasLtMatrixLayoutCreate(
|
|
151
|
+
ctypes.byref(layout),
|
|
152
|
+
self.data_type,
|
|
153
|
+
self.rows,
|
|
154
|
+
self.cols,
|
|
155
|
+
self.ld,
|
|
156
|
+
)
|
|
157
|
+
check_cublas_status(status, "cublasLtMatrixLayoutCreate")
|
|
158
|
+
|
|
159
|
+
if layout.value is None:
|
|
160
|
+
raise RuntimeError("cublasLtMatrixLayoutCreate returned NULL descriptor")
|
|
161
|
+
|
|
162
|
+
self.ptr = layout
|
|
163
|
+
|
|
164
|
+
def destroy(self) -> None:
|
|
165
|
+
if self.ptr is None:
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
cublaslt = self._require_cublaslt()
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
status = cublaslt.cublasLtMatrixLayoutDestroy(self.ptr)
|
|
172
|
+
check_cublas_status(status, "cublasLtMatrixLayoutDestroy")
|
|
173
|
+
finally:
|
|
174
|
+
self.ptr = None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class MatmulPreference(CublasLtDescriptor):
|
|
178
|
+
def __init__(
|
|
179
|
+
self,
|
|
180
|
+
runtime: CublasLtRuntime,
|
|
181
|
+
*,
|
|
182
|
+
max_workspace_bytes: int = 0,
|
|
183
|
+
) -> None:
|
|
184
|
+
super().__init__(runtime)
|
|
185
|
+
self.max_workspace_bytes = max_workspace_bytes
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def create(self) -> None:
|
|
189
|
+
if self.ptr is not None:
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
if self.max_workspace_bytes < 0:
|
|
193
|
+
raise ValueError("max_workspace_bytes must be >= 0")
|
|
194
|
+
|
|
195
|
+
cublaslt = self._require_cublaslt()
|
|
196
|
+
|
|
197
|
+
pref = ctypes.c_void_p()
|
|
198
|
+
status = cublaslt.cublasLtMatmulPreferenceCreate(ctypes.byref(pref))
|
|
199
|
+
check_cublas_status(status, "cublasLtMatmulPreferenceCreate")
|
|
200
|
+
|
|
201
|
+
if pref.value is None:
|
|
202
|
+
raise RuntimeError("cublasLtMatmulPreferenceCreate returned NULL descriptor")
|
|
203
|
+
|
|
204
|
+
self.ptr = pref
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
self.set_max_workspace_bytes(self.max_workspace_bytes)
|
|
208
|
+
except Exception:
|
|
209
|
+
# __exit__ is not called when __enter__ raises, so destroy here.
|
|
210
|
+
self.destroy()
|
|
211
|
+
raise
|
|
212
|
+
|
|
213
|
+
def destroy(self) -> None:
|
|
214
|
+
if self.ptr is None:
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
cublaslt = self._require_cublaslt()
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
status = cublaslt.cublasLtMatmulPreferenceDestroy(self.ptr)
|
|
221
|
+
check_cublas_status(status, "cublasLtMatmulPreferenceDestroy")
|
|
222
|
+
finally:
|
|
223
|
+
self.ptr = None
|
|
224
|
+
|
|
225
|
+
def set_max_workspace_bytes(self, value: int) -> None:
|
|
226
|
+
if value < 0:
|
|
227
|
+
raise ValueError("max workspace bytes must be >= 0")
|
|
228
|
+
|
|
229
|
+
cublaslt = self._require_cublaslt()
|
|
230
|
+
pref = self._require_ptr()
|
|
231
|
+
|
|
232
|
+
workspace_value = ctypes.c_uint64(value)
|
|
233
|
+
workspace_ptr = ctypes.cast(ctypes.byref(workspace_value), ctypes.c_void_p)
|
|
234
|
+
|
|
235
|
+
status = cublaslt.cublasLtMatmulPreferenceSetAttribute(
|
|
236
|
+
pref,
|
|
237
|
+
CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
|
|
238
|
+
workspace_ptr,
|
|
239
|
+
ctypes.sizeof(workspace_value),
|
|
240
|
+
)
|
|
241
|
+
check_cublas_status(status, "cublasLtMatmulPreferenceSetAttribute")
|
|
242
|
+
|
|
243
|
+
self.max_workspace_bytes = value
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# cudaDataType_t
|
|
8
|
+
CUDA_R_32F = 0
|
|
9
|
+
CUDA_R_64F = 1
|
|
10
|
+
CUDA_R_16F = 2
|
|
11
|
+
CUDA_R_8I = 3
|
|
12
|
+
CUDA_C_32F = 4
|
|
13
|
+
CUDA_C_64F = 5
|
|
14
|
+
CUDA_C_16F = 6
|
|
15
|
+
CUDA_R_8U = 8
|
|
16
|
+
CUDA_R_32I = 10
|
|
17
|
+
CUDA_R_32U = 11
|
|
18
|
+
CUDA_R_16BF = 14
|
|
19
|
+
CUDA_R_8F_E4M3 = 28
|
|
20
|
+
CUDA_R_8F_E5M2 = 29
|
|
21
|
+
CUDA_R_8F_UE8M0 = 30
|
|
22
|
+
CUDA_R_4F_E2M1 = 33
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# cublasComputeType_t
|
|
26
|
+
CUBLAS_COMPUTE_16F = 64
|
|
27
|
+
CUBLAS_COMPUTE_16F_PEDANTIC = 65
|
|
28
|
+
CUBLAS_COMPUTE_32F = 68
|
|
29
|
+
CUBLAS_COMPUTE_32F_PEDANTIC = 69
|
|
30
|
+
CUBLAS_COMPUTE_64F = 70
|
|
31
|
+
CUBLAS_COMPUTE_64F_PEDANTIC = 71
|
|
32
|
+
CUBLAS_COMPUTE_32I = 72
|
|
33
|
+
CUBLAS_COMPUTE_32I_PEDANTIC = 73
|
|
34
|
+
CUBLAS_COMPUTE_32F_FAST_16F = 74
|
|
35
|
+
CUBLAS_COMPUTE_32F_FAST_16BF = 75
|
|
36
|
+
CUBLAS_COMPUTE_32F_FAST_TF32 = 77
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# cublasOperation_t
|
|
40
|
+
CUBLAS_OP_N = 0
|
|
41
|
+
CUBLAS_OP_T = 1
|
|
42
|
+
CUBLAS_OP_C = 2
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# cublasLtMatmulDescAttributes_t
|
|
46
|
+
CUBLASLT_MATMUL_DESC_TRANSA = 3
|
|
47
|
+
CUBLASLT_MATMUL_DESC_TRANSB = 4
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# cublasLtMatmulPreferenceAttributes_t
|
|
51
|
+
CUBLASLT_MATMUL_PREF_SEARCH_MODE = 0
|
|
52
|
+
CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES = 1
|