liangsu9988 commited on
Commit
dfd0c7d
·
verified ·
1 Parent(s): 10a85ab

Uploaded using `kernel-builder`.

Browse files
benchmarks/benchmark.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ import torch
4
+
5
+ import int4_blackwell
6
+
7
+
8
+ def main() -> None:
9
+ parser = argparse.ArgumentParser()
10
+ parser.add_argument("--iterations", type=int, default=8192)
11
+ parser.add_argument("--repeats", type=int, default=10)
12
+ parser.add_argument("--launches", type=int, default=20)
13
+ args = parser.parse_args()
14
+
15
+ props = torch.cuda.get_device_properties(0)
16
+ blocks = props.multi_processor_count * 4
17
+ warps = blocks * 8
18
+ flops = warps * 4 * args.iterations * 2 * 16 * 8 * 64
19
+ out = torch.empty((blocks, 256), device="cuda", dtype=torch.float32)
20
+ for mode in ("e2m1", "a", "b", "ab"):
21
+ int4_blackwell.mma_probe(
22
+ mode, iterations=args.iterations, blocks=blocks, out=out
23
+ )
24
+ torch.cuda.synchronize()
25
+ start = torch.cuda.Event(enable_timing=True)
26
+ end = torch.cuda.Event(enable_timing=True)
27
+ best_ms = float("inf")
28
+ for _ in range(args.repeats):
29
+ start.record()
30
+ int4_blackwell.mma_probe(
31
+ mode,
32
+ iterations=args.iterations,
33
+ blocks=blocks,
34
+ launches=args.launches,
35
+ out=out,
36
+ )
37
+ end.record()
38
+ end.synchronize()
39
+ best_ms = min(best_ms, start.elapsed_time(end))
40
+ per_launch_ms = best_ms / args.launches
41
+ tflops = flops / (per_launch_ms * 1e-3) / 1e12
42
+ print(f"{mode:5s} {per_launch_ms * 1e3:9.3f} us {tflops:8.1f} TFLOPS")
43
+
44
+
45
+ if __name__ == "__main__":
46
+ main()
build/torch211-cxx11-cu128-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Experimental native E0M3/INT4 tensor-core primitives for Blackwell."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.resources import files
6
+ from typing import Literal
7
+
8
+ import torch
9
+
10
+ from ._ops import ops
11
+
12
+ OperandMode = Literal["e2m1", "a", "b", "ab"]
13
+
14
+ _CUBIN_NAMES = {
15
+ "e2m1": "probe.cubin",
16
+ "a": "probe_int4a.cubin",
17
+ "b": "probe_int4b.cubin",
18
+ "ab": "probe_int4.cubin",
19
+ }
20
+ _SUPPORTED_ARCHES = {(12, 0): "sm120", (12, 1): "sm121"}
21
+ _CACHE: dict[tuple[str, str], torch.Tensor] = {}
22
+
23
+
24
+ def _architecture(device: int) -> str:
25
+ capability = torch.cuda.get_device_capability(device)
26
+ try:
27
+ return _SUPPORTED_ARCHES[capability]
28
+ except KeyError as error:
29
+ supported = ", ".join(name.upper() for name in _SUPPORTED_ARCHES.values())
30
+ raise RuntimeError(
31
+ f"int4-blackwell supports {supported}; got SM{capability[0]}{capability[1]}"
32
+ ) from error
33
+
34
+
35
+ def _capability(device: int) -> tuple[int, int]:
36
+ return tuple(torch.cuda.get_device_capability(device))
37
+
38
+
39
+ def _is_tcgen05(device: int) -> bool:
40
+ return _capability(device) in {(10, 0), (10, 3), (11, 0)}
41
+
42
+
43
+ def _cubin(mode: OperandMode, device: int) -> torch.Tensor:
44
+ if mode not in _CUBIN_NAMES:
45
+ raise ValueError(
46
+ f"mode must be one of {tuple(_CUBIN_NAMES)}, got {mode!r}"
47
+ )
48
+ architecture = _architecture(device)
49
+ key = (architecture, mode)
50
+ if key not in _CACHE:
51
+ data = (
52
+ files(__package__)
53
+ .joinpath("cubin", architecture, _CUBIN_NAMES[mode])
54
+ .read_bytes()
55
+ )
56
+ _CACHE[key] = torch.frombuffer(bytearray(data), dtype=torch.uint8)
57
+ return _CACHE[key]
58
+
59
+
60
+ def _device_index(device: int | torch.device | None) -> int:
61
+ if device is None:
62
+ return torch.cuda.current_device()
63
+ if isinstance(device, int):
64
+ return device
65
+ parsed = torch.device(device)
66
+ if parsed.type != "cuda":
67
+ raise ValueError(f"device must be CUDA, got {parsed}")
68
+ return torch.cuda.current_device() if parsed.index is None else parsed.index
69
+
70
+
71
+ def codebook_probe(
72
+ mode: OperandMode = "ab", *, device: int | torch.device | None = None
73
+ ) -> torch.Tensor:
74
+ """Return the 16-value A-operand decode table measured by native MMA.
75
+
76
+ ``mode`` selects standard E2M1 or the patched INT4 format independently
77
+ for the A and B operands. The result is synchronized and returned on CPU.
78
+ """
79
+ dev = _device_index(device)
80
+ if _is_tcgen05(dev):
81
+ if mode != "ab":
82
+ raise ValueError(
83
+ "the tcgen05 backend currently exposes the native INT4 x INT4 "
84
+ "descriptor; use mode='ab'"
85
+ )
86
+ m = n = k = 128
87
+ b_packed = torch.full(
88
+ (n, k // 2), 0x11, device=f"cuda:{dev}", dtype=torch.uint8
89
+ )
90
+ # Constant-one UE4M3 storage is layout-invariant. Deliberately
91
+ # overallocate the physical CUTLASS scale-factor tensors for this
92
+ # instruction canary so no private layout helper leaks into the API.
93
+ sfa = torch.full((m * k,), 0x38, device=f"cuda:{dev}", dtype=torch.uint8)
94
+ sfb = torch.full((n * k,), 0x38, device=f"cuda:{dev}", dtype=torch.uint8)
95
+ values = []
96
+ for value in range(16):
97
+ packed = value | (value << 4)
98
+ a_packed = torch.full(
99
+ (m, k // 2), packed, device=f"cuda:{dev}", dtype=torch.uint8
100
+ )
101
+ tile = ops.tcgen05_int4_gemm_bf16(a_packed, sfa, b_packed, sfb)
102
+ first = tile[0, 0]
103
+ if not torch.equal(tile, first.expand_as(tile)):
104
+ raise RuntimeError("tcgen05 INT4 codebook output is not uniform")
105
+ values.append(first.float() / k)
106
+ return torch.stack(values).cpu()
107
+ tile = ops.run_codebook_probe(_cubin(mode, dev), dev)
108
+ torch.cuda.synchronize(dev)
109
+ if not torch.equal(tile, tile[:, :1].expand_as(tile)):
110
+ raise RuntimeError("native MMA output tile is not uniform")
111
+ return (tile[:, 0] / 64.0).cpu()
112
+
113
+
114
+ def mma_probe(
115
+ mode: OperandMode = "ab",
116
+ *,
117
+ iterations: int = 8192,
118
+ blocks: int | None = None,
119
+ launches: int = 1,
120
+ device: int | torch.device | None = None,
121
+ out: torch.Tensor | None = None,
122
+ ) -> torch.Tensor:
123
+ """Launch the register-resident MMA throughput probe asynchronously."""
124
+ dev = _device_index(device)
125
+ if _is_tcgen05(dev):
126
+ raise RuntimeError(
127
+ "mma_probe is the SM120/SM121 register-resident OMMA probe; "
128
+ "benchmark tcgen05_int4_gemm_bf16 on SM100/SM103/SM110"
129
+ )
130
+ if blocks is None:
131
+ blocks = torch.cuda.get_device_properties(dev).multi_processor_count * 4
132
+ if out is None:
133
+ out = torch.empty((blocks, 256), device=f"cuda:{dev}", dtype=torch.float32)
134
+ ops.run_mma_probe(_cubin(mode, dev), out, iterations, blocks, launches, dev)
135
+ return out
136
+
137
+
138
+ def tcgen05_int4_gemm_bf16(
139
+ a_packed: torch.Tensor,
140
+ sfa_physical: torch.Tensor,
141
+ b_packed: torch.Tensor,
142
+ sfb_physical: torch.Tensor,
143
+ ) -> torch.Tensor:
144
+ """Run native E0M3 x E0M3 block-scaled GEMM on SM100/SM103/SM110.
145
+
146
+ ``a_packed`` and ``b_packed`` contain two sign-magnitude INT4 values per
147
+ byte. Scale tensors are the physical CUTLASS UE4M3 block-16 layouts.
148
+ """
149
+ return ops.tcgen05_int4_gemm_bf16(
150
+ a_packed, sfa_physical, b_packed, sfb_physical
151
+ )
152
+
153
+
154
+ __all__ = ["codebook_probe", "mma_probe", "tcgen05_int4_gemm_bf16"]
build/torch211-cxx11-cu128-x86_64-linux/_int4_blackwell_cuda_7293754.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c12086e2af3de089fc891e46c61cecbbd35347166ad58366d19daf47871a608
3
+ size 131624
build/torch211-cxx11-cu128-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _int4_blackwell_cuda_7293754
3
+ ops = torch.ops._int4_blackwell_cuda_7293754
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_int4_blackwell_cuda_7293754::{op_name}"
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm120/probe.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm120/probe_int4.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm120/probe_int4a.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm120/probe_int4b.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm121/probe.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm121/probe_int4.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm121/probe_int4a.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/cubin/sm121/probe_int4b.cubin ADDED
Binary file (18.2 kB). View file
 
build/torch211-cxx11-cu128-x86_64-linux/int4_blackwell/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch211-cxx11-cu128-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "int4-blackwell",
3
+ "id": "_int4_blackwell_cuda_7293754",
4
+ "version": 2,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "12.0a"
11
+ ]
12
+ },
13
+ "digest": {
14
+ "algorithm": "sha256",
15
+ "files": {
16
+ "__init__.py": "ZXxr7dTBPug6WkGl6AIQHXvBFx51IvL03xSBxzBlFPw=",
17
+ "_int4_blackwell_cuda_7293754.abi3.so": "bBIIbirz3gifyJHkbGHOy701NHFmrVg2bRna9Hhxpgg=",
18
+ "_ops.py": "foZsaPY0s4R51rR73LdBoOgtyau46OPCUG7Pv4UVyu8=",
19
+ "cubin/sm120/probe.cubin": "NI7vTEvUQQv2rWK04n+aAn/WcVx6SeuGLwifH9cOtsw=",
20
+ "cubin/sm120/probe_int4.cubin": "pQquaOOezAuM53Z7WqvGac4/sU1D4OtNsiRJ46q9L2E=",
21
+ "cubin/sm120/probe_int4a.cubin": "UtRYoYXq2v2xKjv0tRejI8fk5cOwf9Pole8nr/wq74s=",
22
+ "cubin/sm120/probe_int4b.cubin": "MsXapGaqimIsNiaxoNYtbPlPq+0dd28nhxWj9tGebJg=",
23
+ "cubin/sm121/probe.cubin": "0J8zHuXX+WaIrucvSvA4n+CcvaPlhMUnEQrTwPAm0yg=",
24
+ "cubin/sm121/probe_int4.cubin": "RJ8EHWdGcqVdHVD0pMnmXUHBvSUT5Vx7Okn0KTVjxn8=",
25
+ "cubin/sm121/probe_int4a.cubin": "3WcJv9FranOf2UX6/JpqqivR8hG7GXSlSfFqpM8+7vs=",
26
+ "cubin/sm121/probe_int4b.cubin": "EiaR1+5SEYoKO6S+WJPgIvsJYut2j2aMarowlCfRJ6U=",
27
+ "int4_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
28
+ }
29
+ },
30
+ "provenance": {
31
+ "kernel-builder": {
32
+ "version": "0.17.0-dev0",
33
+ "sha": "da73ab4c34bde4916c8efe88854722ed00c036bd",
34
+ "dirty": false
35
+ },
36
+ "kernel": {
37
+ "sha": "729375469a56c44de15a9a84689a7eba2dae35e6",
38
+ "dirty": false
39
+ }
40
+ }
41
+ }