liangsu9988 commited on
Commit
bd9c69a
·
verified ·
1 Parent(s): 871279e

Promote latest kernel artifacts to main

Browse files
.gitattributes CHANGED
@@ -1,35 +1,3 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.so filter=lfs diff=lfs merge=lfs -text
2
+ *.pyd filter=lfs diff=lfs merge=lfs -text
3
+ *.dylib filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md DELETED
@@ -1,9 +0,0 @@
1
- # flashrt/fp8-kv-attention
2
-
3
- This repository is a compatibility mirror for older `kernels` clients
4
- that resolve repositories through the default Hugging Face model repo API.
5
-
6
- Canonical Kernel Hub repo: https://huggingface.co/kernels/flashrt/fp8-kv-attention
7
-
8
- Do not edit this mirror by hand. It is generated from the Kernel Hub
9
- `vN` branches and contains the same `build/**` artifacts.
 
 
 
 
 
 
 
 
 
 
benchmarks/benchmark.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Benchmark fp8-kv-attention against a PyTorch FP8-dequant reference."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import time
9
+ from pathlib import Path
10
+
11
+ import torch
12
+
13
+ import sys
14
+
15
+ TESTS = Path(__file__).resolve().parents[1] / "tests"
16
+ sys.path.insert(0, str(TESTS))
17
+ from test_fp8_kv_attention import SHAPES, SourceOps, load_installed_ops, load_source_ops, make_inputs, reference # noqa: E402
18
+
19
+
20
+ MODES = {
21
+ "smoke": ["decode_128"],
22
+ "headline": ["decode_1024", "verify4_1024", "verify8_4096"],
23
+ "full": ["decode_128", "decode_1024", "verify4_1024", "verify8_4096"],
24
+ }
25
+
26
+
27
+ def time_cuda(fn, warmup: int, iters: int) -> float:
28
+ for _ in range(warmup):
29
+ fn()
30
+ torch.cuda.synchronize()
31
+ start = torch.cuda.Event(enable_timing=True)
32
+ end = torch.cuda.Event(enable_timing=True)
33
+ start.record()
34
+ for _ in range(iters):
35
+ fn()
36
+ end.record()
37
+ torch.cuda.synchronize()
38
+ return float(start.elapsed_time(end) * 1000.0 / iters)
39
+
40
+
41
+ def main() -> int:
42
+ parser = argparse.ArgumentParser()
43
+ parser.add_argument("--backend", choices=["source", "installed"], default="source")
44
+ parser.add_argument("--artifact", default=None)
45
+ parser.add_argument("--mode", choices=sorted(MODES), default="smoke")
46
+ parser.add_argument("--warmup", type=int, default=20)
47
+ parser.add_argument("--iters", type=int, default=100)
48
+ parser.add_argument("--json-out", default=None)
49
+ args = parser.parse_args()
50
+
51
+ ops = load_source_ops() if args.backend == "source" else load_installed_ops(args.artifact)
52
+ rows = []
53
+ for name in MODES[args.mode]:
54
+ q_seq, kv_seq = SHAPES[name]
55
+ q, k, v = make_inputs(q_seq, kv_seq, seed=3000 + q_seq * 17 + kv_seq)
56
+ if isinstance(ops, SourceOps):
57
+ def kernel_call():
58
+ return ops.xqa_bf16_fp8kv(q, k, v, kv_seq)
59
+ else:
60
+ pages = k.shape[0]
61
+ page_table = ops.default_page_table(pages, device=q.device)
62
+ seq_lens = torch.tensor([[kv_seq]], device=q.device, dtype=torch.int32)
63
+ mask = ops.causal_spec_mask(q_seq, device=q.device)
64
+ sem, scratch = ops.allocate_workspace(q_seq=q_seq, device=q.device)
65
+ out = torch.empty_like(q)
66
+
67
+ def kernel_call():
68
+ return ops.xqa_bf16_fp8kv(
69
+ q, k, v, page_table, seq_lens, mask,
70
+ out=out, semaphores=sem, scratch=scratch,
71
+ max_seq_len=pages * 128,
72
+ )
73
+
74
+ def ref_call():
75
+ return reference(q, k, v, kv_seq)
76
+
77
+ kernel_us = time_cuda(kernel_call, args.warmup, args.iters)
78
+ ref_us = time_cuda(ref_call, max(2, args.warmup // 5), max(5, args.iters // 10))
79
+ rows.append(
80
+ {
81
+ "shape": name,
82
+ "q_seq": q_seq,
83
+ "kv_seq": kv_seq,
84
+ "kernel_us": kernel_us,
85
+ "torch_reference_us": ref_us,
86
+ "speedup": ref_us / kernel_us,
87
+ }
88
+ )
89
+ print(f"{name}: kernel={kernel_us:.3f}us ref={ref_us:.3f}us speedup={ref_us / kernel_us:.2f}x")
90
+ if args.json_out:
91
+ Path(args.json_out).parent.mkdir(parents=True, exist_ok=True)
92
+ Path(args.json_out).write_text(json.dumps(rows, indent=2) + "\n")
93
+ return 0
94
+
95
+
96
+ if __name__ == "__main__":
97
+ raise SystemExit(main())
build/torch211-cxx11-cu128-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT BF16-Q + FP8-KV XQA attention kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+
9
+ from ._ops import add_op_namespace_prefix, ops
10
+
11
+
12
+ PAGE_SIZE = 128
13
+ NUM_Q_HEADS = 24
14
+ NUM_KV_HEADS = 4
15
+ HEAD_DIM = 256
16
+
17
+
18
+ @torch.library.register_fake(add_op_namespace_prefix("xqa_bf16_fp8kv"))
19
+ def _xqa_bf16_fp8kv_fake(
20
+ q: torch.Tensor,
21
+ k_cache: torch.Tensor,
22
+ v_cache: torch.Tensor,
23
+ page_table: torch.Tensor,
24
+ seq_lens: torch.Tensor,
25
+ mask: torch.Tensor,
26
+ out: torch.Tensor,
27
+ semaphores: torch.Tensor,
28
+ scratch: torch.Tensor,
29
+ max_seq_len: int = 0,
30
+ q_scale: float = 1.0,
31
+ kv_scale: float = 1.0,
32
+ enable_pdl: bool = True,
33
+ sm_count: int = 0,
34
+ k_stride_page: int = 0,
35
+ k_stride_token: int = 0,
36
+ k_stride_head: int = 0,
37
+ ) -> None:
38
+ if q.dim() == 3:
39
+ q_seq = q.shape[0]
40
+ ok = q.shape[1:] == (NUM_Q_HEADS, HEAD_DIM)
41
+ elif q.dim() == 5:
42
+ q_seq = q.shape[2]
43
+ ok = q.shape[:2] == (1, 1) and q.shape[3:] == (NUM_Q_HEADS, HEAD_DIM)
44
+ else:
45
+ raise RuntimeError("q must have rank 3 or 5")
46
+ if not ok or out.shape != q.shape:
47
+ raise RuntimeError("q/out shape mismatch for v1 XQA contract")
48
+ if k_cache.dim() != 4 or k_cache.shape[1:] != (PAGE_SIZE, NUM_KV_HEADS, HEAD_DIM):
49
+ raise RuntimeError("k_cache must have shape (pages,128,4,256)")
50
+ if v_cache.shape != k_cache.shape:
51
+ raise RuntimeError("v_cache shape mismatch")
52
+ if mask.numel() < q_seq * ((q_seq + 31) // 32):
53
+ raise RuntimeError("mask is too small")
54
+ return None
55
+
56
+
57
+ def causal_spec_mask(q_seq: int, *, device: torch.device | str = "cuda", dtype: torch.dtype = torch.int32) -> torch.Tensor:
58
+ """Return the packed lower-triangular mask expected by the v1 XQA kernel."""
59
+
60
+ q_seq = int(q_seq)
61
+ words = (q_seq + 31) // 32
62
+ rows = torch.zeros((q_seq, words), dtype=torch.int32)
63
+ for i in range(q_seq):
64
+ upto = i + 1
65
+ full = upto // 32
66
+ rem = upto % 32
67
+ if full:
68
+ rows[i, :full] = -1
69
+ if rem:
70
+ rows[i, full] = (1 << rem) - 1
71
+ return rows.to(device=device, dtype=dtype)
72
+
73
+
74
+ def default_page_table(num_pages: int, *, device: torch.device | str = "cuda") -> torch.Tensor:
75
+ """Contiguous one-batch page table for `(pages,128,4,256)` K/V caches."""
76
+
77
+ return torch.arange(int(num_pages), device=device, dtype=torch.int32).view(1, int(num_pages))
78
+
79
+
80
+ def allocate_workspace(
81
+ *,
82
+ q_seq: int,
83
+ device: torch.device | str = "cuda",
84
+ scratch_mb: int = 256,
85
+ ) -> tuple[torch.Tensor, torch.Tensor]:
86
+ """Allocate semaphores and scratch tensors for static-buffer runtimes."""
87
+
88
+ sem_count = NUM_KV_HEADS * (((int(q_seq) * (NUM_Q_HEADS // NUM_KV_HEADS)) + 31) // 32)
89
+ semaphores = torch.zeros(max(256, sem_count), device=device, dtype=torch.int32)
90
+ scratch = torch.empty(max(1, int(scratch_mb)) << 20, device=device, dtype=torch.uint8)
91
+ return semaphores, scratch
92
+
93
+
94
+ def xqa_bf16_fp8kv(
95
+ q: torch.Tensor,
96
+ k_cache: torch.Tensor,
97
+ v_cache: torch.Tensor,
98
+ page_table: Optional[torch.Tensor] = None,
99
+ seq_lens: Optional[torch.Tensor] = None,
100
+ mask: Optional[torch.Tensor] = None,
101
+ *,
102
+ out: Optional[torch.Tensor] = None,
103
+ semaphores: Optional[torch.Tensor] = None,
104
+ scratch: Optional[torch.Tensor] = None,
105
+ max_seq_len: int = 0,
106
+ q_scale: float = 1.0,
107
+ kv_scale: float = 1.0,
108
+ enable_pdl: bool = True,
109
+ sm_count: int = 0,
110
+ k_stride_page: int = 0,
111
+ k_stride_token: int = 0,
112
+ k_stride_head: int = 0,
113
+ ) -> torch.Tensor:
114
+ """Run BF16-query / FP8-KV XQA attention for the v1 fixed public shape.
115
+
116
+ v1 shape contract:
117
+ `q`: `(q_seq, 24, 256)` or `(1, 1, q_seq, 24, 256)` BF16.
118
+ `k_cache`, `v_cache`: `(pages, 128, 4, 256)` FP8 E4M3.
119
+ """
120
+
121
+ if out is None:
122
+ out = torch.empty_like(q)
123
+ if page_table is None:
124
+ page_table = default_page_table(k_cache.shape[0], device=q.device)
125
+ if seq_lens is None:
126
+ seq_lens = torch.tensor([[k_cache.shape[0] * PAGE_SIZE]], device=q.device, dtype=torch.int32)
127
+ if mask is None:
128
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
129
+ mask = causal_spec_mask(int(q_seq), device=q.device, dtype=torch.int32)
130
+ if semaphores is None or scratch is None:
131
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
132
+ semaphores_new, scratch_new = allocate_workspace(q_seq=int(q_seq), device=q.device)
133
+ if semaphores is None:
134
+ semaphores = semaphores_new
135
+ if scratch is None:
136
+ scratch = scratch_new
137
+ ops.xqa_bf16_fp8kv(
138
+ q,
139
+ k_cache,
140
+ v_cache,
141
+ page_table,
142
+ seq_lens,
143
+ mask,
144
+ out,
145
+ semaphores,
146
+ scratch,
147
+ int(max_seq_len),
148
+ float(q_scale),
149
+ float(kv_scale),
150
+ bool(enable_pdl),
151
+ int(sm_count),
152
+ int(k_stride_page),
153
+ int(k_stride_token),
154
+ int(k_stride_head),
155
+ )
156
+ return out
157
+
158
+
159
+ __all__ = [
160
+ "HEAD_DIM",
161
+ "NUM_KV_HEADS",
162
+ "NUM_Q_HEADS",
163
+ "PAGE_SIZE",
164
+ "allocate_workspace",
165
+ "causal_spec_mask",
166
+ "default_page_table",
167
+ "xqa_bf16_fp8kv",
168
+ ]
build/torch211-cxx11-cu128-x86_64-linux/_fp8_kv_attention_cuda_1798e7f.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cf401a2268d87ffe836d824c39fb3286fa12828eba64a5e3c27e61845556fcd3
3
+ size 288176
build/torch211-cxx11-cu128-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp8_kv_attention_cuda_1798e7f
3
+ ops = torch.ops._fp8_kv_attention_cuda_1798e7f
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp8_kv_attention_cuda_1798e7f::{op_name}"
build/torch211-cxx11-cu128-x86_64-linux/fp8_kv_attention/__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,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp8-kv-attention",
3
+ "id": "_fp8_kv_attention_cuda_1798e7f",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "12.0"
11
+ ]
12
+ },
13
+ "digest": {
14
+ "algorithm": "sha256",
15
+ "files": {
16
+ "__init__.py": "AipNkYPvsd/zyT+YU7bggBObENJYocXbAV7/Yr5A+6c=",
17
+ "_fp8_kv_attention_cuda_1798e7f.abi3.so": "z0AaImjYf/6DbYJMOfsyhvoSgo66ZKXjwn5hhFVW/NM=",
18
+ "_ops.py": "u1tuL5lFum0BIgl8+j1z86OkjJn3e4Mnmc/29zQSfHA=",
19
+ "fp8_kv_attention/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
+ }
21
+ }
22
+ }
build/torch211-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT BF16-Q + FP8-KV XQA attention kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+
9
+ from ._ops import add_op_namespace_prefix, ops
10
+
11
+
12
+ PAGE_SIZE = 128
13
+ NUM_Q_HEADS = 24
14
+ NUM_KV_HEADS = 4
15
+ HEAD_DIM = 256
16
+
17
+
18
+ @torch.library.register_fake(add_op_namespace_prefix("xqa_bf16_fp8kv"))
19
+ def _xqa_bf16_fp8kv_fake(
20
+ q: torch.Tensor,
21
+ k_cache: torch.Tensor,
22
+ v_cache: torch.Tensor,
23
+ page_table: torch.Tensor,
24
+ seq_lens: torch.Tensor,
25
+ mask: torch.Tensor,
26
+ out: torch.Tensor,
27
+ semaphores: torch.Tensor,
28
+ scratch: torch.Tensor,
29
+ max_seq_len: int = 0,
30
+ q_scale: float = 1.0,
31
+ kv_scale: float = 1.0,
32
+ enable_pdl: bool = True,
33
+ sm_count: int = 0,
34
+ k_stride_page: int = 0,
35
+ k_stride_token: int = 0,
36
+ k_stride_head: int = 0,
37
+ ) -> None:
38
+ if q.dim() == 3:
39
+ q_seq = q.shape[0]
40
+ ok = q.shape[1:] == (NUM_Q_HEADS, HEAD_DIM)
41
+ elif q.dim() == 5:
42
+ q_seq = q.shape[2]
43
+ ok = q.shape[:2] == (1, 1) and q.shape[3:] == (NUM_Q_HEADS, HEAD_DIM)
44
+ else:
45
+ raise RuntimeError("q must have rank 3 or 5")
46
+ if not ok or out.shape != q.shape:
47
+ raise RuntimeError("q/out shape mismatch for v1 XQA contract")
48
+ if k_cache.dim() != 4 or k_cache.shape[1:] != (PAGE_SIZE, NUM_KV_HEADS, HEAD_DIM):
49
+ raise RuntimeError("k_cache must have shape (pages,128,4,256)")
50
+ if v_cache.shape != k_cache.shape:
51
+ raise RuntimeError("v_cache shape mismatch")
52
+ if mask.numel() < q_seq * ((q_seq + 31) // 32):
53
+ raise RuntimeError("mask is too small")
54
+ return None
55
+
56
+
57
+ def causal_spec_mask(q_seq: int, *, device: torch.device | str = "cuda", dtype: torch.dtype = torch.int32) -> torch.Tensor:
58
+ """Return the packed lower-triangular mask expected by the v1 XQA kernel."""
59
+
60
+ q_seq = int(q_seq)
61
+ words = (q_seq + 31) // 32
62
+ rows = torch.zeros((q_seq, words), dtype=torch.int32)
63
+ for i in range(q_seq):
64
+ upto = i + 1
65
+ full = upto // 32
66
+ rem = upto % 32
67
+ if full:
68
+ rows[i, :full] = -1
69
+ if rem:
70
+ rows[i, full] = (1 << rem) - 1
71
+ return rows.to(device=device, dtype=dtype)
72
+
73
+
74
+ def default_page_table(num_pages: int, *, device: torch.device | str = "cuda") -> torch.Tensor:
75
+ """Contiguous one-batch page table for `(pages,128,4,256)` K/V caches."""
76
+
77
+ return torch.arange(int(num_pages), device=device, dtype=torch.int32).view(1, int(num_pages))
78
+
79
+
80
+ def allocate_workspace(
81
+ *,
82
+ q_seq: int,
83
+ device: torch.device | str = "cuda",
84
+ scratch_mb: int = 256,
85
+ ) -> tuple[torch.Tensor, torch.Tensor]:
86
+ """Allocate semaphores and scratch tensors for static-buffer runtimes."""
87
+
88
+ sem_count = NUM_KV_HEADS * (((int(q_seq) * (NUM_Q_HEADS // NUM_KV_HEADS)) + 31) // 32)
89
+ semaphores = torch.zeros(max(256, sem_count), device=device, dtype=torch.int32)
90
+ scratch = torch.empty(max(1, int(scratch_mb)) << 20, device=device, dtype=torch.uint8)
91
+ return semaphores, scratch
92
+
93
+
94
+ def xqa_bf16_fp8kv(
95
+ q: torch.Tensor,
96
+ k_cache: torch.Tensor,
97
+ v_cache: torch.Tensor,
98
+ page_table: Optional[torch.Tensor] = None,
99
+ seq_lens: Optional[torch.Tensor] = None,
100
+ mask: Optional[torch.Tensor] = None,
101
+ *,
102
+ out: Optional[torch.Tensor] = None,
103
+ semaphores: Optional[torch.Tensor] = None,
104
+ scratch: Optional[torch.Tensor] = None,
105
+ max_seq_len: int = 0,
106
+ q_scale: float = 1.0,
107
+ kv_scale: float = 1.0,
108
+ enable_pdl: bool = True,
109
+ sm_count: int = 0,
110
+ k_stride_page: int = 0,
111
+ k_stride_token: int = 0,
112
+ k_stride_head: int = 0,
113
+ ) -> torch.Tensor:
114
+ """Run BF16-query / FP8-KV XQA attention for the v1 fixed public shape.
115
+
116
+ v1 shape contract:
117
+ `q`: `(q_seq, 24, 256)` or `(1, 1, q_seq, 24, 256)` BF16.
118
+ `k_cache`, `v_cache`: `(pages, 128, 4, 256)` FP8 E4M3.
119
+ """
120
+
121
+ if out is None:
122
+ out = torch.empty_like(q)
123
+ if page_table is None:
124
+ page_table = default_page_table(k_cache.shape[0], device=q.device)
125
+ if seq_lens is None:
126
+ seq_lens = torch.tensor([[k_cache.shape[0] * PAGE_SIZE]], device=q.device, dtype=torch.int32)
127
+ if mask is None:
128
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
129
+ mask = causal_spec_mask(int(q_seq), device=q.device, dtype=torch.int32)
130
+ if semaphores is None or scratch is None:
131
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
132
+ semaphores_new, scratch_new = allocate_workspace(q_seq=int(q_seq), device=q.device)
133
+ if semaphores is None:
134
+ semaphores = semaphores_new
135
+ if scratch is None:
136
+ scratch = scratch_new
137
+ ops.xqa_bf16_fp8kv(
138
+ q,
139
+ k_cache,
140
+ v_cache,
141
+ page_table,
142
+ seq_lens,
143
+ mask,
144
+ out,
145
+ semaphores,
146
+ scratch,
147
+ int(max_seq_len),
148
+ float(q_scale),
149
+ float(kv_scale),
150
+ bool(enable_pdl),
151
+ int(sm_count),
152
+ int(k_stride_page),
153
+ int(k_stride_token),
154
+ int(k_stride_head),
155
+ )
156
+ return out
157
+
158
+
159
+ __all__ = [
160
+ "HEAD_DIM",
161
+ "NUM_KV_HEADS",
162
+ "NUM_Q_HEADS",
163
+ "PAGE_SIZE",
164
+ "allocate_workspace",
165
+ "causal_spec_mask",
166
+ "default_page_table",
167
+ "xqa_bf16_fp8kv",
168
+ ]
build/torch211-cxx11-cu130-x86_64-linux/_fp8_kv_attention_cuda_1798e7f.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ee536f2f46f5118d095c14a22ebbf275811a39c3aba56b774a1c6797c234044a
3
+ size 289032
build/torch211-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp8_kv_attention_cuda_1798e7f
3
+ ops = torch.ops._fp8_kv_attention_cuda_1798e7f
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp8_kv_attention_cuda_1798e7f::{op_name}"
build/torch211-cxx11-cu130-x86_64-linux/fp8_kv_attention/__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-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp8-kv-attention",
3
+ "id": "_fp8_kv_attention_cuda_1798e7f",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "12.0"
11
+ ]
12
+ },
13
+ "digest": {
14
+ "algorithm": "sha256",
15
+ "files": {
16
+ "__init__.py": "AipNkYPvsd/zyT+YU7bggBObENJYocXbAV7/Yr5A+6c=",
17
+ "_fp8_kv_attention_cuda_1798e7f.abi3.so": "7lNvL0b1EY0JXBSiLrvydYEaOcOrpWt3Shxnl8I0BEo=",
18
+ "_ops.py": "u1tuL5lFum0BIgl8+j1z86OkjJn3e4Mnmc/29zQSfHA=",
19
+ "fp8_kv_attention/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
+ }
21
+ }
22
+ }
build/torch212-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT BF16-Q + FP8-KV XQA attention kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+
9
+ from ._ops import add_op_namespace_prefix, ops
10
+
11
+
12
+ PAGE_SIZE = 128
13
+ NUM_Q_HEADS = 24
14
+ NUM_KV_HEADS = 4
15
+ HEAD_DIM = 256
16
+
17
+
18
+ @torch.library.register_fake(add_op_namespace_prefix("xqa_bf16_fp8kv"))
19
+ def _xqa_bf16_fp8kv_fake(
20
+ q: torch.Tensor,
21
+ k_cache: torch.Tensor,
22
+ v_cache: torch.Tensor,
23
+ page_table: torch.Tensor,
24
+ seq_lens: torch.Tensor,
25
+ mask: torch.Tensor,
26
+ out: torch.Tensor,
27
+ semaphores: torch.Tensor,
28
+ scratch: torch.Tensor,
29
+ max_seq_len: int = 0,
30
+ q_scale: float = 1.0,
31
+ kv_scale: float = 1.0,
32
+ enable_pdl: bool = True,
33
+ sm_count: int = 0,
34
+ k_stride_page: int = 0,
35
+ k_stride_token: int = 0,
36
+ k_stride_head: int = 0,
37
+ ) -> None:
38
+ if q.dim() == 3:
39
+ q_seq = q.shape[0]
40
+ ok = q.shape[1:] == (NUM_Q_HEADS, HEAD_DIM)
41
+ elif q.dim() == 5:
42
+ q_seq = q.shape[2]
43
+ ok = q.shape[:2] == (1, 1) and q.shape[3:] == (NUM_Q_HEADS, HEAD_DIM)
44
+ else:
45
+ raise RuntimeError("q must have rank 3 or 5")
46
+ if not ok or out.shape != q.shape:
47
+ raise RuntimeError("q/out shape mismatch for v1 XQA contract")
48
+ if k_cache.dim() != 4 or k_cache.shape[1:] != (PAGE_SIZE, NUM_KV_HEADS, HEAD_DIM):
49
+ raise RuntimeError("k_cache must have shape (pages,128,4,256)")
50
+ if v_cache.shape != k_cache.shape:
51
+ raise RuntimeError("v_cache shape mismatch")
52
+ if mask.numel() < q_seq * ((q_seq + 31) // 32):
53
+ raise RuntimeError("mask is too small")
54
+ return None
55
+
56
+
57
+ def causal_spec_mask(q_seq: int, *, device: torch.device | str = "cuda", dtype: torch.dtype = torch.int32) -> torch.Tensor:
58
+ """Return the packed lower-triangular mask expected by the v1 XQA kernel."""
59
+
60
+ q_seq = int(q_seq)
61
+ words = (q_seq + 31) // 32
62
+ rows = torch.zeros((q_seq, words), dtype=torch.int32)
63
+ for i in range(q_seq):
64
+ upto = i + 1
65
+ full = upto // 32
66
+ rem = upto % 32
67
+ if full:
68
+ rows[i, :full] = -1
69
+ if rem:
70
+ rows[i, full] = (1 << rem) - 1
71
+ return rows.to(device=device, dtype=dtype)
72
+
73
+
74
+ def default_page_table(num_pages: int, *, device: torch.device | str = "cuda") -> torch.Tensor:
75
+ """Contiguous one-batch page table for `(pages,128,4,256)` K/V caches."""
76
+
77
+ return torch.arange(int(num_pages), device=device, dtype=torch.int32).view(1, int(num_pages))
78
+
79
+
80
+ def allocate_workspace(
81
+ *,
82
+ q_seq: int,
83
+ device: torch.device | str = "cuda",
84
+ scratch_mb: int = 256,
85
+ ) -> tuple[torch.Tensor, torch.Tensor]:
86
+ """Allocate semaphores and scratch tensors for static-buffer runtimes."""
87
+
88
+ sem_count = NUM_KV_HEADS * (((int(q_seq) * (NUM_Q_HEADS // NUM_KV_HEADS)) + 31) // 32)
89
+ semaphores = torch.zeros(max(256, sem_count), device=device, dtype=torch.int32)
90
+ scratch = torch.empty(max(1, int(scratch_mb)) << 20, device=device, dtype=torch.uint8)
91
+ return semaphores, scratch
92
+
93
+
94
+ def xqa_bf16_fp8kv(
95
+ q: torch.Tensor,
96
+ k_cache: torch.Tensor,
97
+ v_cache: torch.Tensor,
98
+ page_table: Optional[torch.Tensor] = None,
99
+ seq_lens: Optional[torch.Tensor] = None,
100
+ mask: Optional[torch.Tensor] = None,
101
+ *,
102
+ out: Optional[torch.Tensor] = None,
103
+ semaphores: Optional[torch.Tensor] = None,
104
+ scratch: Optional[torch.Tensor] = None,
105
+ max_seq_len: int = 0,
106
+ q_scale: float = 1.0,
107
+ kv_scale: float = 1.0,
108
+ enable_pdl: bool = True,
109
+ sm_count: int = 0,
110
+ k_stride_page: int = 0,
111
+ k_stride_token: int = 0,
112
+ k_stride_head: int = 0,
113
+ ) -> torch.Tensor:
114
+ """Run BF16-query / FP8-KV XQA attention for the v1 fixed public shape.
115
+
116
+ v1 shape contract:
117
+ `q`: `(q_seq, 24, 256)` or `(1, 1, q_seq, 24, 256)` BF16.
118
+ `k_cache`, `v_cache`: `(pages, 128, 4, 256)` FP8 E4M3.
119
+ """
120
+
121
+ if out is None:
122
+ out = torch.empty_like(q)
123
+ if page_table is None:
124
+ page_table = default_page_table(k_cache.shape[0], device=q.device)
125
+ if seq_lens is None:
126
+ seq_lens = torch.tensor([[k_cache.shape[0] * PAGE_SIZE]], device=q.device, dtype=torch.int32)
127
+ if mask is None:
128
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
129
+ mask = causal_spec_mask(int(q_seq), device=q.device, dtype=torch.int32)
130
+ if semaphores is None or scratch is None:
131
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
132
+ semaphores_new, scratch_new = allocate_workspace(q_seq=int(q_seq), device=q.device)
133
+ if semaphores is None:
134
+ semaphores = semaphores_new
135
+ if scratch is None:
136
+ scratch = scratch_new
137
+ ops.xqa_bf16_fp8kv(
138
+ q,
139
+ k_cache,
140
+ v_cache,
141
+ page_table,
142
+ seq_lens,
143
+ mask,
144
+ out,
145
+ semaphores,
146
+ scratch,
147
+ int(max_seq_len),
148
+ float(q_scale),
149
+ float(kv_scale),
150
+ bool(enable_pdl),
151
+ int(sm_count),
152
+ int(k_stride_page),
153
+ int(k_stride_token),
154
+ int(k_stride_head),
155
+ )
156
+ return out
157
+
158
+
159
+ __all__ = [
160
+ "HEAD_DIM",
161
+ "NUM_KV_HEADS",
162
+ "NUM_Q_HEADS",
163
+ "PAGE_SIZE",
164
+ "allocate_workspace",
165
+ "causal_spec_mask",
166
+ "default_page_table",
167
+ "xqa_bf16_fp8kv",
168
+ ]
build/torch212-cxx11-cu130-x86_64-linux/_fp8_kv_attention_cuda_1798e7f.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7f3555f239dbbc144b463c9a90f991f82abdb31838e360236697c859b45e1cc0
3
+ size 304040
build/torch212-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp8_kv_attention_cuda_1798e7f
3
+ ops = torch.ops._fp8_kv_attention_cuda_1798e7f
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp8_kv_attention_cuda_1798e7f::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/fp8_kv_attention/__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/torch212-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp8-kv-attention",
3
+ "id": "_fp8_kv_attention_cuda_1798e7f",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "12.0"
11
+ ]
12
+ },
13
+ "digest": {
14
+ "algorithm": "sha256",
15
+ "files": {
16
+ "__init__.py": "AipNkYPvsd/zyT+YU7bggBObENJYocXbAV7/Yr5A+6c=",
17
+ "_fp8_kv_attention_cuda_1798e7f.abi3.so": "fzVV8jnbvBRLRjyakPmR+Cq9sxg442AjZpfIWbReHMA=",
18
+ "_ops.py": "u1tuL5lFum0BIgl8+j1z86OkjJn3e4Mnmc/29zQSfHA=",
19
+ "fp8_kv_attention/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
+ }
21
+ }
22
+ }
build/torch212-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FlashRT BF16-Q + FP8-KV XQA attention kernels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+
9
+ from ._ops import add_op_namespace_prefix, ops
10
+
11
+
12
+ PAGE_SIZE = 128
13
+ NUM_Q_HEADS = 24
14
+ NUM_KV_HEADS = 4
15
+ HEAD_DIM = 256
16
+
17
+
18
+ @torch.library.register_fake(add_op_namespace_prefix("xqa_bf16_fp8kv"))
19
+ def _xqa_bf16_fp8kv_fake(
20
+ q: torch.Tensor,
21
+ k_cache: torch.Tensor,
22
+ v_cache: torch.Tensor,
23
+ page_table: torch.Tensor,
24
+ seq_lens: torch.Tensor,
25
+ mask: torch.Tensor,
26
+ out: torch.Tensor,
27
+ semaphores: torch.Tensor,
28
+ scratch: torch.Tensor,
29
+ max_seq_len: int = 0,
30
+ q_scale: float = 1.0,
31
+ kv_scale: float = 1.0,
32
+ enable_pdl: bool = True,
33
+ sm_count: int = 0,
34
+ k_stride_page: int = 0,
35
+ k_stride_token: int = 0,
36
+ k_stride_head: int = 0,
37
+ ) -> None:
38
+ if q.dim() == 3:
39
+ q_seq = q.shape[0]
40
+ ok = q.shape[1:] == (NUM_Q_HEADS, HEAD_DIM)
41
+ elif q.dim() == 5:
42
+ q_seq = q.shape[2]
43
+ ok = q.shape[:2] == (1, 1) and q.shape[3:] == (NUM_Q_HEADS, HEAD_DIM)
44
+ else:
45
+ raise RuntimeError("q must have rank 3 or 5")
46
+ if not ok or out.shape != q.shape:
47
+ raise RuntimeError("q/out shape mismatch for v1 XQA contract")
48
+ if k_cache.dim() != 4 or k_cache.shape[1:] != (PAGE_SIZE, NUM_KV_HEADS, HEAD_DIM):
49
+ raise RuntimeError("k_cache must have shape (pages,128,4,256)")
50
+ if v_cache.shape != k_cache.shape:
51
+ raise RuntimeError("v_cache shape mismatch")
52
+ if mask.numel() < q_seq * ((q_seq + 31) // 32):
53
+ raise RuntimeError("mask is too small")
54
+ return None
55
+
56
+
57
+ def causal_spec_mask(q_seq: int, *, device: torch.device | str = "cuda", dtype: torch.dtype = torch.int32) -> torch.Tensor:
58
+ """Return the packed lower-triangular mask expected by the v1 XQA kernel."""
59
+
60
+ q_seq = int(q_seq)
61
+ words = (q_seq + 31) // 32
62
+ rows = torch.zeros((q_seq, words), dtype=torch.int32)
63
+ for i in range(q_seq):
64
+ upto = i + 1
65
+ full = upto // 32
66
+ rem = upto % 32
67
+ if full:
68
+ rows[i, :full] = -1
69
+ if rem:
70
+ rows[i, full] = (1 << rem) - 1
71
+ return rows.to(device=device, dtype=dtype)
72
+
73
+
74
+ def default_page_table(num_pages: int, *, device: torch.device | str = "cuda") -> torch.Tensor:
75
+ """Contiguous one-batch page table for `(pages,128,4,256)` K/V caches."""
76
+
77
+ return torch.arange(int(num_pages), device=device, dtype=torch.int32).view(1, int(num_pages))
78
+
79
+
80
+ def allocate_workspace(
81
+ *,
82
+ q_seq: int,
83
+ device: torch.device | str = "cuda",
84
+ scratch_mb: int = 256,
85
+ ) -> tuple[torch.Tensor, torch.Tensor]:
86
+ """Allocate semaphores and scratch tensors for static-buffer runtimes."""
87
+
88
+ sem_count = NUM_KV_HEADS * (((int(q_seq) * (NUM_Q_HEADS // NUM_KV_HEADS)) + 31) // 32)
89
+ semaphores = torch.zeros(max(256, sem_count), device=device, dtype=torch.int32)
90
+ scratch = torch.empty(max(1, int(scratch_mb)) << 20, device=device, dtype=torch.uint8)
91
+ return semaphores, scratch
92
+
93
+
94
+ def xqa_bf16_fp8kv(
95
+ q: torch.Tensor,
96
+ k_cache: torch.Tensor,
97
+ v_cache: torch.Tensor,
98
+ page_table: Optional[torch.Tensor] = None,
99
+ seq_lens: Optional[torch.Tensor] = None,
100
+ mask: Optional[torch.Tensor] = None,
101
+ *,
102
+ out: Optional[torch.Tensor] = None,
103
+ semaphores: Optional[torch.Tensor] = None,
104
+ scratch: Optional[torch.Tensor] = None,
105
+ max_seq_len: int = 0,
106
+ q_scale: float = 1.0,
107
+ kv_scale: float = 1.0,
108
+ enable_pdl: bool = True,
109
+ sm_count: int = 0,
110
+ k_stride_page: int = 0,
111
+ k_stride_token: int = 0,
112
+ k_stride_head: int = 0,
113
+ ) -> torch.Tensor:
114
+ """Run BF16-query / FP8-KV XQA attention for the v1 fixed public shape.
115
+
116
+ v1 shape contract:
117
+ `q`: `(q_seq, 24, 256)` or `(1, 1, q_seq, 24, 256)` BF16.
118
+ `k_cache`, `v_cache`: `(pages, 128, 4, 256)` FP8 E4M3.
119
+ """
120
+
121
+ if out is None:
122
+ out = torch.empty_like(q)
123
+ if page_table is None:
124
+ page_table = default_page_table(k_cache.shape[0], device=q.device)
125
+ if seq_lens is None:
126
+ seq_lens = torch.tensor([[k_cache.shape[0] * PAGE_SIZE]], device=q.device, dtype=torch.int32)
127
+ if mask is None:
128
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
129
+ mask = causal_spec_mask(int(q_seq), device=q.device, dtype=torch.int32)
130
+ if semaphores is None or scratch is None:
131
+ q_seq = q.shape[0] if q.dim() == 3 else q.shape[2]
132
+ semaphores_new, scratch_new = allocate_workspace(q_seq=int(q_seq), device=q.device)
133
+ if semaphores is None:
134
+ semaphores = semaphores_new
135
+ if scratch is None:
136
+ scratch = scratch_new
137
+ ops.xqa_bf16_fp8kv(
138
+ q,
139
+ k_cache,
140
+ v_cache,
141
+ page_table,
142
+ seq_lens,
143
+ mask,
144
+ out,
145
+ semaphores,
146
+ scratch,
147
+ int(max_seq_len),
148
+ float(q_scale),
149
+ float(kv_scale),
150
+ bool(enable_pdl),
151
+ int(sm_count),
152
+ int(k_stride_page),
153
+ int(k_stride_token),
154
+ int(k_stride_head),
155
+ )
156
+ return out
157
+
158
+
159
+ __all__ = [
160
+ "HEAD_DIM",
161
+ "NUM_KV_HEADS",
162
+ "NUM_Q_HEADS",
163
+ "PAGE_SIZE",
164
+ "allocate_workspace",
165
+ "causal_spec_mask",
166
+ "default_page_table",
167
+ "xqa_bf16_fp8kv",
168
+ ]
build/torch212-cxx11-cu132-x86_64-linux/_fp8_kv_attention_cuda_1798e7f.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c7e4715f54563584e19ef3c507f7ddd7d0ed3297e28b7dba2fd1f9bcacb68051
3
+ size 304040
build/torch212-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _fp8_kv_attention_cuda_1798e7f
3
+ ops = torch.ops._fp8_kv_attention_cuda_1798e7f
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_fp8_kv_attention_cuda_1798e7f::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/fp8_kv_attention/__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/torch212-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "fp8-kv-attention",
3
+ "id": "_fp8_kv_attention_cuda_1798e7f",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "12.0"
11
+ ]
12
+ },
13
+ "digest": {
14
+ "algorithm": "sha256",
15
+ "files": {
16
+ "__init__.py": "AipNkYPvsd/zyT+YU7bggBObENJYocXbAV7/Yr5A+6c=",
17
+ "_fp8_kv_attention_cuda_1798e7f.abi3.so": "x+RxX1RWNYThnvPFB/fd19DtMpfii326L9H5vKy2gFE=",
18
+ "_ops.py": "u1tuL5lFum0BIgl8+j1z86OkjJn3e4Mnmc/29zQSfHA=",
19
+ "fp8_kv_attention/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
20
+ }
21
+ }
22
+ }