mxflashattn 1.4.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.
@@ -0,0 +1,139 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+
5
+ import torch
6
+
7
+
8
+ def attention_single(
9
+ q: torch.Tensor,
10
+ k: torch.Tensor,
11
+ v: torch.Tensor,
12
+ *,
13
+ softmax_scale: float | None = None,
14
+ causal: bool = False,
15
+ ) -> torch.Tensor:
16
+ """Readable PyTorch reference for [seq, heads, dim] inputs."""
17
+ if q.shape[0] == 0:
18
+ return q.clone()
19
+ query_len, query_heads, head_dim = q.shape
20
+ key_len, kv_heads, _ = k.shape
21
+ if key_len == 0:
22
+ raise ValueError("attention requires at least one key/value token")
23
+
24
+ scale = softmax_scale if softmax_scale is not None else 1.0 / math.sqrt(head_dim)
25
+ groups = query_heads // kv_heads
26
+ qf = q.float().transpose(0, 1)
27
+ kf = k.float().repeat_interleave(groups, dim=1).transpose(0, 1)
28
+ vf = v.float().repeat_interleave(groups, dim=1).transpose(0, 1)
29
+ scores = torch.matmul(qf, kf.transpose(-2, -1)) * scale
30
+
31
+ if causal:
32
+ q_positions = torch.arange(query_len, device=q.device) + (key_len - query_len)
33
+ k_positions = torch.arange(key_len, device=q.device)
34
+ blocked = k_positions.unsqueeze(0) > q_positions.unsqueeze(1)
35
+ scores = scores.masked_fill(blocked.unsqueeze(0), float("-inf"))
36
+
37
+ probabilities = torch.softmax(scores, dim=-1)
38
+ probabilities = torch.nan_to_num(probabilities, nan=0.0, posinf=0.0, neginf=0.0)
39
+ output = torch.matmul(probabilities, vf).transpose(0, 1)
40
+ return output.to(dtype=q.dtype)
41
+
42
+
43
+ def attention_batched(
44
+ q: torch.Tensor,
45
+ k: torch.Tensor,
46
+ v: torch.Tensor,
47
+ *,
48
+ softmax_scale: float | None = None,
49
+ causal: bool = False,
50
+ ) -> torch.Tensor:
51
+ outputs = [
52
+ attention_single(q[index], k[index], v[index], softmax_scale=softmax_scale, causal=causal)
53
+ for index in range(q.shape[0])
54
+ ]
55
+ if not outputs:
56
+ return q.clone()
57
+ return torch.stack(outputs, dim=0)
58
+
59
+
60
+ def attention_varlen(
61
+ q: torch.Tensor,
62
+ k: torch.Tensor,
63
+ v: torch.Tensor,
64
+ cu_seqlens_q: list[int],
65
+ cu_seqlens_k: list[int],
66
+ *,
67
+ softmax_scale: float | None = None,
68
+ causal: bool = False,
69
+ ) -> torch.Tensor:
70
+ outputs = []
71
+ for index in range(len(cu_seqlens_q) - 1):
72
+ q_start, q_end = cu_seqlens_q[index : index + 2]
73
+ k_start, k_end = cu_seqlens_k[index : index + 2]
74
+ outputs.append(
75
+ attention_single(
76
+ q[q_start:q_end],
77
+ k[k_start:k_end],
78
+ v[k_start:k_end],
79
+ softmax_scale=softmax_scale,
80
+ causal=causal,
81
+ )
82
+ )
83
+ if not outputs:
84
+ return q[:0].clone()
85
+ return torch.cat(outputs, dim=0)
86
+
87
+
88
+ def attention_kvcache(
89
+ q: torch.Tensor,
90
+ k_cache: torch.Tensor,
91
+ v_cache: torch.Tensor,
92
+ *,
93
+ cache_seqlens: torch.Tensor,
94
+ block_table: torch.Tensor | None,
95
+ k: torch.Tensor | None = None,
96
+ v: torch.Tensor | None = None,
97
+ softmax_scale: float | None = None,
98
+ causal: bool = False,
99
+ ) -> torch.Tensor:
100
+ lengths = [int(length) for length in cache_seqlens.detach().cpu().tolist()]
101
+ batch = q.shape[0]
102
+ outputs = []
103
+
104
+ for batch_index in range(batch):
105
+ old_len = lengths[batch_index]
106
+ append_len = 0 if k is None else k.shape[1]
107
+ total_len = old_len + append_len
108
+ if block_table is None:
109
+ if append_len:
110
+ k_cache[batch_index, old_len:total_len] = k[batch_index]
111
+ v_cache[batch_index, old_len:total_len] = v[batch_index]
112
+ current_k = k_cache[batch_index, :total_len]
113
+ current_v = v_cache[batch_index, :total_len]
114
+ else:
115
+ page_size = k_cache.shape[1]
116
+ row = [int(block) for block in block_table[batch_index].detach().cpu().tolist()]
117
+ for token_index in range(append_len):
118
+ logical = old_len + token_index
119
+ page_index, page_offset = divmod(logical, page_size)
120
+ physical_page = row[page_index]
121
+ k_cache[physical_page, page_offset] = k[batch_index, token_index]
122
+ v_cache[physical_page, page_offset] = v[batch_index, token_index]
123
+ page_count = (total_len + page_size - 1) // page_size
124
+ pages = row[:page_count]
125
+ current_k = torch.cat([k_cache[page] for page in pages], dim=0)[:total_len]
126
+ current_v = torch.cat([v_cache[page] for page in pages], dim=0)[:total_len]
127
+ outputs.append(
128
+ attention_single(
129
+ q[batch_index],
130
+ current_k,
131
+ current_v,
132
+ softmax_scale=softmax_scale,
133
+ causal=causal,
134
+ )
135
+ )
136
+
137
+ if k is not None:
138
+ cache_seqlens.add_(k.shape[1])
139
+ return torch.stack(outputs, dim=0) if outputs else q.clone()
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from collections.abc import Sequence
5
+
6
+ import torch
7
+
8
+
9
+ SUPPORTED_HEAD_DIMS = (64, 128)
10
+ REFERENCE_DTYPES = (torch.float16, torch.bfloat16, torch.float32)
11
+ NATIVE_DTYPES = (torch.float16, torch.bfloat16)
12
+
13
+
14
+ def validate_softmax_scale(softmax_scale: float | None) -> None:
15
+ if softmax_scale is None:
16
+ return
17
+ try:
18
+ scale = float(softmax_scale)
19
+ except (TypeError, ValueError) as error:
20
+ raise TypeError("softmax_scale must be a finite number or None") from error
21
+ if not math.isfinite(scale):
22
+ raise ValueError("softmax_scale must be finite")
23
+
24
+
25
+ def validate_qkv(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> None:
26
+ tensors = {"q": q, "k": k, "v": v}
27
+ for name, tensor in tensors.items():
28
+ if not isinstance(tensor, torch.Tensor):
29
+ raise TypeError(f"{name} must be a torch.Tensor")
30
+ if tensor.ndim != 4:
31
+ raise ValueError(f"{name} must have rank 4 with layout [batch, seq, heads, dim]")
32
+
33
+ if q.device != k.device or q.device != v.device:
34
+ raise ValueError("q, k, and v must be on the same device")
35
+ if q.dtype != k.dtype or q.dtype != v.dtype:
36
+ raise ValueError("q, k, and v must have the same dtype")
37
+ if q.dtype not in REFERENCE_DTYPES:
38
+ raise TypeError("supported dtypes are float16, bfloat16, and float32 for reference execution")
39
+
40
+ batch, q_len, q_heads, head_dim = q.shape
41
+ kv_batch, kv_len, kv_heads, kv_dim = k.shape
42
+ if v.shape != k.shape:
43
+ raise ValueError("k and v must have identical shapes")
44
+ if batch != kv_batch:
45
+ raise ValueError("q, k, and v batch dimensions must match")
46
+ if q_heads <= 0 or kv_heads <= 0:
47
+ raise ValueError("q and kv head counts must be positive")
48
+ if q_heads % kv_heads:
49
+ raise ValueError("the number of q heads must be divisible by the number of kv heads")
50
+ if head_dim != kv_dim or head_dim not in SUPPORTED_HEAD_DIMS:
51
+ raise ValueError(f"head dimension must be one of {SUPPORTED_HEAD_DIMS} and match across q, k, and v")
52
+ if q_len < 0 or kv_len <= 0:
53
+ raise ValueError("q must have a non-negative sequence length and k/v must be non-empty")
54
+
55
+
56
+ def validate_options(
57
+ *,
58
+ dropout_p: float,
59
+ window_size: Sequence[int],
60
+ softcap: float,
61
+ alibi_slopes: torch.Tensor | None,
62
+ return_attn_probs: bool,
63
+ deterministic: bool,
64
+ ) -> None:
65
+ if dropout_p != 0:
66
+ raise NotImplementedError("dropout is not supported in the forward-only implementation")
67
+ if tuple(window_size) != (-1, -1):
68
+ raise NotImplementedError("local window attention is not supported")
69
+ if softcap != 0:
70
+ raise NotImplementedError("soft-capping is not supported")
71
+ if alibi_slopes is not None:
72
+ raise NotImplementedError("alibi_slopes are not supported")
73
+ if return_attn_probs:
74
+ raise NotImplementedError("return_attn_probs is not supported")
75
+ if deterministic:
76
+ raise NotImplementedError("deterministic mode is not currently supported")
77
+
78
+
79
+ def validate_cumulative_lengths(
80
+ cu_seqlens: torch.Tensor,
81
+ *,
82
+ total_tokens: int,
83
+ max_seqlen: int,
84
+ name: str,
85
+ require_non_empty: bool = False,
86
+ ) -> list[int]:
87
+ if not isinstance(cu_seqlens, torch.Tensor) or cu_seqlens.ndim != 1:
88
+ raise TypeError(f"{name} must be a one-dimensional torch.Tensor")
89
+ if cu_seqlens.dtype not in (torch.int32, torch.int64):
90
+ raise TypeError(f"{name} must use int32 or int64")
91
+ values = [int(value) for value in cu_seqlens.detach().cpu().tolist()]
92
+ if len(values) < 2 or values[0] != 0 or values[-1] != total_tokens:
93
+ raise ValueError(f"{name} must start at zero and cover all tokens")
94
+ if any(right < left for left, right in zip(values, values[1:])):
95
+ raise ValueError(f"{name} must be monotonically non-decreasing")
96
+ if require_non_empty and any(right == left for left, right in zip(values, values[1:])):
97
+ raise ValueError("key/value sequences must be non-empty")
98
+ if max_seqlen < 0 or max(values[i + 1] - values[i] for i in range(len(values) - 1)) > max_seqlen:
99
+ raise ValueError(f"{name} contains a sequence longer than max_seqlen")
100
+ return values
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: mxflashattn
3
+ Version: 1.4.0
4
+ Summary: FlashAttention-compatible forward APIs and MXMACA bring-up backend
5
+ License-Expression: Apache-2.0
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: torch>=2.4
13
+ Requires-Dist: PyYAML<7,>=6.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest<10,>=8; extra == "dev"
16
+ Requires-Dist: ruff<1,>=0.6; extra == "dev"
17
+ Provides-Extra: vllm
18
+ Requires-Dist: vllm==0.17.0; extra == "vllm"
19
+ Provides-Extra: reports
20
+ Requires-Dist: matplotlib<4,>=3.8; extra == "reports"
21
+ Dynamic: license-file
22
+
23
+ # MXFlashAttn
24
+
25
+ > **状态(2026-10-17):v1.4.0 C500 发布候选版本。**
26
+ > 已完成 C500 上的算子、真实 vLLM 0.17.0 生成、dispatch、回退和近 16K 长上下文回归;
27
+ > 生产加速范围仍限定为 M1 Split-KV Decode,不宣称 Prefill 生产加速。
28
+ >
29
+ > **项目边界:**这是面向 MXMACA/MetaX C500 的专项适配与 decode 优化工程,
30
+ > 不是跨硬件 FlashAttention 替代品,也不是 MXAttention(MXFP4)复现。
31
+
32
+ 中文说明 · **[English](README.en.md)**
33
+
34
+ MXFlashAttn 是面向 **MXMACA / MetaX C500** 的 FlashAttention 兼容前向算子与推理适配项目。
35
+ v1.3.0 起包含**自研 device kernel**(`csrc_native/m1_kernel.cpp`,split-KV paged decode)。
36
+ v1.4.0 在 v1.3.0 基础上完成了 C500 验证和长上下文回归。2026-10-17 的复测中,
37
+ Qwen3-4B 在 batch=32、max_tokens=1024 的长上下文 decode 场景相对本项目 v7 路径达到约
38
+ **3.66×** 吞吐;Qwen3-8B 在 batch=16、max_tokens=256 时约 **1.37×**。跨模型结果表明收益依赖模型、
39
+ batch 和 KV 长度,短序列或低并发不保证加速。
40
+
41
+ [![CI](https://github.com/leo1852098393-blip/MXFlashAttn/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/leo1852098393-blip/MXFlashAttn/actions/workflows/ci.yml)
42
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
43
+ [![Python](https://img.shields.io/badge/python-3.10%2B-3776AB.svg)](pyproject.toml)
44
+
45
+ ## 2026-10-13 C500 复测结果(申报主口径/历史对照)
46
+
47
+ 环境:MetaX C500 64G、MACA 3.5.3.20、驱动 3.8.30、PyTorch
48
+ `2.8.0+metax3.5.3.9`、vLLM 0.17.0。所有 M1 结果均由 dispatch 日志确认进入
49
+ `m1_split_decode`。
50
+
51
+ | 模型与场景 | v7 | M1-UM2 | 相对 v7 |
52
+ | --- | ---: | ---: | ---: |
53
+ | Qwen3-4B,batch=128,256 token | 1375.59 tok/s | 4554.69 tok/s | **3.31×** |
54
+ | Qwen3-4B,batch=32,1024 token | 359.82 tok/s | 1293.48 tok/s | **3.59×** |
55
+ | Qwen3-8B,batch=16,256 token | 500.79 tok/s | 703.06 tok/s | **1.40×** |
56
+ | PaddleOCR-VL,batch=16,64 token | 281.73 tok/s | 334.71 tok/s | **1.19×** |
57
+
58
+ 本轮最新复测为 Qwen3-4B `v7=357.76`、`M1-UM2=1309.15 tok/s`(约 **3.66×**),
59
+ Qwen3-8B `v7=508.48`、`M1-UM2=695.45 tok/s`(约 **1.37×**)。
60
+ 这些数字只描述表中 C500 配置,不外推为所有模型或所有请求形态的固定倍率。
61
+ 另已完成 Qwen3-4B 真实 15,000 token prompt、`max_model_len=16384` 的
62
+ vendor prefill + M1 decode 回归,生成 32 token 成功且 M1 dispatch 命中。
63
+ 流式 TTFT/P95 采集链路已验证,但 candidate 记录没有 M1 dispatch 事件,
64
+ 因此不把它写成 M1 TTFT 性能提升。
65
+
66
+ 2026-10-13 的复测表仍作为申报主口径和历史对照保留在
67
+ [`docs/results/c500-2026-10-13.md`](docs/results/c500-2026-10-13.md)。
68
+
69
+ 2026-10-07 Gate 4 的更大场景矩阵(包括 3.67×、6.48× 等数字)保留在历史报告中,
70
+ 用于说明研发过程与形状覆盖,不与本轮复测混成同一组结果:
71
+ [`docs/gate4/Gate4_收官报告.md`](docs/gate4/Gate4_收官报告.md)。
72
+
73
+ 支持形状 `{GQ in {2,4,8} x HD in {64,128}}` 的**全部6 个格子均有真实模型 E2E 证据**;
74
+ M1 不支持的形状不得直接调用 binding。vLLM official-split 路径会把这些形状交还原始
75
+ MetaX/vendor KV-cache 实现。2026-10-13 已用 Qwen3.5-9B(head_dim=256)验证:
76
+ 真实生成成功、M1 dispatch=0、M1-UM/M1-UM2 均为 4/4 文本匹配。
77
+
78
+ 新一轮原始证据和报告位于申报工作空间的本地目录 `02_evidence/c500_20261013/`;
79
+ 公开仓库内的历史 Gate 4 证据见
80
+ [`docs/gate4/E2E_大模型与守卫验证.md`](docs/gate4/E2E_大模型与守卫验证.md)。
81
+
82
+ ## 快速复现(需要 C500)
83
+
84
+ ```bash
85
+ export MACA_PATH=/opt/maca # 缺这一行 triton import 会报NoneType
86
+ bash csrc_native/build_m1.sh # mxcc 编译 M1,产出 csrc_native/mxmmain.so
87
+ python csrc_native/patch_plugin.py # 把 M1 接线打进 vLLM 插件(幂等)
88
+ python csrc_native/test_m1.py # 稳健性矩阵:s1~s8192 / GQA 2,4,8 / bf16 / ovf
89
+ ```
90
+
91
+ 端到端基准(注意四个环境变量,缺任一项会静默全走 vendor 直连,三路对比退化为同一路径跑三遍):
92
+
93
+ ```bash
94
+ export MXFLASHATTN_GRAPH_OFFICIAL_SPLIT=1 MXFA_NATIVE_DECODE=1
95
+ export VLLM_ENABLE_V1_MULTIPROCESSING=0 # EngineCore 是子进程,否则 env 热切换无效
96
+ python csrc_native/bench_e2e.py --model /path/to/Qwen3-4B --batches 128 64 --max-tokens 256 --output artifacts/bench-q4b.json
97
+ ```
98
+
99
+ **判据:先查 `dispatch.jsonl` 里 `m1_split_decode` 的事件计数,再信吞吐数字。**
100
+ 计数为 0 说明内核根本没被派发,数据无意义。
101
+
102
+ ## 能力矩阵
103
+
104
+ | 能力 | 状态 |
105
+ | --- | --- |
106
+ | FP16 / BF16 forward | C500 已验证 |
107
+ | Head dimension 64 / 128 | C500 已验证 |
108
+ | GQA 比率 2 / 4 / 8 | C500 已验证 |
109
+ | M1 不支持的 GQA 比率(历史验证 GQ=5/7) | 不进入 M1;由上层回退,未验证比率不作支持承诺 |
110
+ | vLLM 中 head_dim > 128 | 不进入 M1;official split 回退原始 MetaX/vendor 路径 |
111
+ | 直接调用 MXFlashAttn 公共 API 的 head_dim > 128 | 显式 `ValueError`,不静默计算 |
112
+ | 自研 split-KV decode kernel(M1) | C500 已验证,vLLM 0.17.0 接线 |
113
+ | dense / varlen / paged KV cache | API 已实现;paged KV append 已在 C500 验证 |
114
+ | dispatch 后端 | `m1_split_decode`(M1)→ `native_decode`(v7)→ `vendor_direct` → `reference` |
115
+ | PyTorch reference fallback | 需显式设置 `MXFLASHATTN_ALLOW_FALLBACK=1`,不会静默切换 |
116
+ | TTFT / P95 | 流式采集链路已验证;candidate 未命中 M1,不作为 M1 性能证据 |
117
+ | backward、FP8、多卡 | 首期不支持 |
118
+ | SGLang | 未安装验证 |
119
+
120
+ 详细边界见 [`docs/support-matrix.md`](docs/support-matrix.md)。
121
+
122
+ ## 项目结构
123
+
124
+ ```text
125
+ mxflashattn/ Python API、校验、reference 与 dispatch
126
+ csrc/mxmac/ C++/ATen bring-up 扩展(朴素 O(n^2) 实现,正确性对照路径)
127
+ csrc_native/ 自研 M1 split-KV decode 内核 + v7 内核 + 基准/测试/构建脚本
128
+ integrations/vllm/ vLLM 0.17.0 适配桥接、decoder adapter 与 preflight
129
+ benchmarks/ 固定配置、公平矩阵运行器和报告工具
130
+ scripts/ C500 实例运维与 E2E 复现脚本(模型暂存、形状扫描、各模型 E2E 编排)
131
+ docs/gate4/ Gate 4 技术报告(原始实例日志保留在本地工作空间)
132
+ docs/results/ C500 原始结果、报告和图表
133
+ tests/ CPU/reference 与 C500 条件测试
134
+ ```
135
+
136
+ `csrc/mxmac/` 是 **PyTorch ATen bring-up / 正确性对照路径**,由 `at::matmul` + `softmax`
137
+ 组装的朴素实现,不是融合 kernel。自研 device kernel 在 `csrc_native/`。
138
+
139
+ Gate 4 各档E2E 的实例侧复现脚本在 `scripts/`(对应文档各节):
140
+ `run_e2e_q4b.sh` / `run_e2e_q8b.sh`(GQ=4 主场景)、
141
+ `run_e2e_gq7.sh`(GQ=7 守卫拒绝)、`run_e2e_gq8.sh`(GQ=8 PaddleOCR-VL)、
142
+ `run_e2e_hd256.sh`(HD=256 回退验证)、`run_queue.sh`(单卡串行编排)、
143
+ `scan_shapes.sh`(共享模型库形状扫描)和 `probe_paddle_vllm.sh`(架构探测)。
144
+ 这些公开脚本面向有 C500 的实例;模型下载与数据盘暂存脚本属于本地申报工作区,
145
+ 不随公开仓库发布。项目根目录支持通过 `MXFLASHATTN_ROOT` 覆盖,模型路径由各脚本中的
146
+ `MODEL` 变量或命令行 `--model` 提供。
147
+
148
+ ## 前向算子 API
149
+
150
+ 公开接口:
151
+
152
+ - `flash_attn_func`
153
+ - `flash_attn_varlen_func`
154
+ - `flash_attn_with_kvcache`
155
+
156
+ ```python
157
+ import torch
158
+ from mxflashattn import flash_attn_func, get_last_dispatch_info
159
+
160
+ q = torch.randn(1, 32, 8, 64, dtype=torch.float16, device="cuda")
161
+ k = torch.randn(1, 128, 2, 64, dtype=q.dtype, device=q.device)
162
+ v = torch.randn_like(k)
163
+ out = flash_attn_func(q, k, v, causal=True)
164
+ print(get_last_dispatch_info())
165
+ ```
166
+
167
+ 在没有 MetaX provider 或编译扩展时,调用默认报错。只有主动设置
168
+ `MXFLASHATTN_ALLOW_FALLBACK=1` 才启用 PyTorch reference fallback(会发`RuntimeWarning`)。
169
+ dropout、局部窗口、AliBi、soft-capping、rotary embeddings、backward 和 softmax-LSE
170
+ 返回会明确报错,不会静默产生错误结果。
171
+
172
+ ## 历史基准(v0.9公平矩阵)
173
+
174
+ v0.9 用固定 seed 覆盖 36 组 batch/seq/head_dim/GQA 比例/layout/dtype/causal 组合,
175
+ 在 C500 上做reference、Torch SDPA、MetaX vendor、MXFlashAttn API 四路公平对比:
176
+
177
+ | 指标 | 结果 |
178
+ | --- | --- |
179
+ | 公平矩阵完成度 | C500 36/36 组 |
180
+ | MXFlashAttn vs PyTorch reference | 中位延迟下降 60.52% |
181
+ | MXFlashAttn vs MetaX vendor 直调 | 中位延迟**上升 32.74%** |
182
+ | 最大绝对误差 | 0.00390625 |
183
+
184
+ 必须同时说清的口径:算子级基线是**同输入同设备的四路公平矩阵**,不是拿自写 reference
185
+ 单独对比得出的加速比;模型级 vendor 与 candidate **分栏列示**,不混入算子级 median。
186
+ 仓库早期那组 384 用例 benchmark基线是本项目 PyTorch reference,已被 v0.9 公平矩阵取代,
187
+ 仅作历史数据保留在 `docs/results/`。
188
+
189
+ 公开仓库提供脱敏结果摘要:[`docs/results/c500-2026-10-05.md`](docs/results/c500-2026-10-05.md)
190
+ 和 [`docs/results/c500-2026-10-13.md`](docs/results/c500-2026-10-13.md)。完整原始 JSON、
191
+ dispatch 流和实例环境记录保留在本地申报工作空间,不随公开仓库发布。下面命令的
192
+ `--output` 是**重新生成**时的本地输出目标。
193
+
194
+ ```bash
195
+ # 评测输出默认写入被忽略的 artifacts/,只作为本地复现缓存。
196
+ python -m benchmarks.fair_matrix --device cuda --count 36 --repeats 5 \
197
+ --output artifacts/fair-matrix-c500.json
198
+ python benchmarks/fair_report.py artifacts/fair-matrix-c500.json \
199
+ --vendor-model artifacts/vllm-vendor-36.json \
200
+ --candidate-model artifacts/vllm-candidate-36.json \
201
+ --output artifacts/fair-matrix-c500.md
202
+ ```
203
+
204
+ ![C500 benchmark summary](docs/results/c500-speedup-summary.png)
205
+
206
+ ## vLLM 集成
207
+
208
+ `integrations/vllm/vllm_plugin.py` 注册 MXFlashAttn backend。v1.3.0 起该插件在
209
+ `MXFA_M1_DECODE=1` 时把 paged decode 派发给 M1 内核,不支持的形状自动落回 v7,
210
+ 再不支持则落回 MetaX vendor 直连。接线细节见
211
+ [`docs/gate4/M3_VLLM_WIRING.md`](docs/gate4/M3_VLLM_WIRING.md)。
212
+
213
+ ```bash
214
+ python integrations/vllm/smoke_generate.py --model /mnt/moark-models/Qwen3-0.6B \
215
+ --prompt-count 36 --max-tokens 16 --baseline-only \
216
+ --output artifacts/vllm-vendor-36.json
217
+ ```
218
+
219
+ ## 已知限制
220
+
221
+ - **v7 路径上下文上限 4096**(>4096 启动失败)。
222
+ - **M1 相对硬件上限仍有差距**:IR 分析显示 v7 走硬件融合`llvm.mxc.expadd.f32.i32`
223
+ 做 softmax 重缩放,而 M1 走软件 shuffle 归约 + `exp2` 模拟。替换为硬件 intrinsic
224
+ 是下一步方向,尚未实施。
225
+ - **text_match 不可在连续批处理下作正确性判据**:batch 组成随调度漂移。文本一致性
226
+ 必须在固定 batch 下单独验证(见 `csrc_native/diag_guard_text_match.py`)。
227
+ - **dispatch 事件统计必须按 `(path, operation, fallback)` 三元组**,只按 path取 top-N
228
+ 会在 M1 从未成功时误判为"没派发"。
229
+
230
+ ## 路线图
231
+
232
+ 后续优化与风险收敛路线见 [`docs/V1.5_OPTIMIZATION_PLAN.md`](docs/V1.5_OPTIMIZATION_PLAN.md)。
233
+ 其中包括 M1 硬件 intrinsic 评估、C500 Prefill kernel、可复现 TTFT 口径、
234
+ 自适应调度、vLLM 新版本兼容性以及 FP8/多卡/SGLang 评估;这些不属于
235
+ v1.4.0 已完成能力。
236
+
237
+ ## 许可证
238
+
239
+ 本项目采用 [Apache License 2.0](LICENSE)。MXMACA runtime、vendor PyTorch、MetaX wheel、
240
+ vLLM、模型权重和数据集分别遵循各自许可证。
241
+
242
+ 欢迎通过 [`CONTRIBUTING.md`](CONTRIBUTING.md) 提交问题和改进。
@@ -0,0 +1,35 @@
1
+ benchmarks/__init__.py,sha256=OGcbfyPIQ9ysnubA1iPIiH5v8e-QTVG1vGYN6wLaE3U,48
2
+ benchmarks/compare.py,sha256=5AZZRXZzBS2Wb4xL_YNsrQutkVCEczosmJuduoINgeQ,3655
3
+ benchmarks/fair_matrix.py,sha256=8Zg_KiLTQ4Y7YCFHD-1fYUn27tj5yLofTlkqvYQ5Y6U,8342
4
+ benchmarks/fair_report.py,sha256=8Lry2NRImH7eizEAnvO8rbv_mhcnKMNHZgYGCQv-j5A,5218
5
+ benchmarks/model_fair_report.py,sha256=OhJZhsbF1wnLjG7SbANU0vsYGEg8Xgxldee3SN-450k,3427
6
+ benchmarks/plot_summary.py,sha256=H76cdfWcNSR3_XqKMf5ZCwSX47WWcbAbv6Amc8deWEo,4722
7
+ benchmarks/report.py,sha256=SLwLAxyxQD9Ku2t_uUHi9RFNFTtCOXb2lpP6V3jUMwE,6351
8
+ benchmarks/run.py,sha256=ImTFVLYTgvAeJfShjCn3f_WaXZSb8DoqBC3rXBtFHPg,12092
9
+ benchmarks/configs/c500.yaml,sha256=J6EvQlJ9Hu7lOmpKsxkHF2u_K4MyZIwqJg-m_EjT4yg,210
10
+ integrations/__init__.py,sha256=3Ogvoli1FHmsLI_2vHgTmZVqgcs7zdHKy0LjG8_X4NU,44
11
+ integrations/vllm/README.md,sha256=WUX5w8dIYcImIm6Hx3-TTHdkEzJgi2UIEXlDYzclWTg,1307
12
+ integrations/vllm/__init__.py,sha256=VIaMdbLixoulqRTR1W_ha0K6hxXyjOk4pBrtPKL3_5M,45
13
+ integrations/vllm/backend.py,sha256=ITIrb2lu8WQGi9XUjdpsO8RSyaEOi-6fuSxd27beq8U,6473
14
+ integrations/vllm/compat.py,sha256=yF1FhPku64eYbVeKlBsizqTI_WlRFpD5UKGiFr-TNqI,1368
15
+ integrations/vllm/config.py,sha256=KCeFToCCu75A8BTpdn2kqoNSu_3Va2TFZnDbg8oYGog,414
16
+ integrations/vllm/decoder_adapter.py,sha256=uKVgwwKUrNB4bSeqNvI7JJEeakKOOykblalzPHBflS0,14836
17
+ integrations/vllm/probe_compat.py,sha256=fGmicONVmcritXiEm-Q9W_Ik5wA_0EAYd-RaiLGZWxU,722
18
+ integrations/vllm/probe_decoder_layout.py,sha256=D9e-OfXJObICxBJ-ON92eFBeD0eqKEJYPKu5XYeASlw,4013
19
+ integrations/vllm/probe_registration.py,sha256=0DxyCL-GezyuIqAPNK3OCbYE73PZiYlx7ZU4CSzHJpQ,752
20
+ integrations/vllm/probe_v017.py,sha256=U9l6ZkKorKop56a3L6BUsCdUpyJVg6mYghzCzJQjHVE,2365
21
+ integrations/vllm/smoke_generate.py,sha256=V20kOp-FhRU-r2_6Olrlw__mQgMFXaWTBWNiW7vYOQ8,9756
22
+ integrations/vllm/vllm_plugin.py,sha256=nG8plmhupQYDmNOS0rAO3uYvxemU8OUlK4Iyq8FbB4U,23145
23
+ mxflashattn/__init__.py,sha256=eefPpHIpLJHuGjr0fRcx16J0_72Vl3f5lU9tVlRMWhA,947
24
+ mxflashattn/accuracy.py,sha256=4BPB7peSM7ad-MAPw06pOURJsd2lurkEBSjXDvYXmLg,1963
25
+ mxflashattn/api.py,sha256=0ANjh3hM8aZsMVlDBLlMOPA3wRT9YgPLousmrhmqORE,12494
26
+ mxflashattn/dispatch.py,sha256=mBQjkBpI4QOX-dMlmatRlqSCXYCDtPC72nYtRre8XGs,6399
27
+ mxflashattn/policy.py,sha256=X9w5C-zJ5dzJLHy9gzJldWdO3UT2fToNRppxy53yJac,3628
28
+ mxflashattn/prefill.py,sha256=bkC7IdxGQrsmK_jsvwbwpN-WhS4lwDvPdFssLIDki2A,4031
29
+ mxflashattn/reference.py,sha256=Nde4e_mTSbRLFJllfuXL52JS22Ie2pTQAiSla97KKB0,4866
30
+ mxflashattn/validation.py,sha256=vE-rkeuyTI2kmKqSnrk9UOCyx8j8e7z3bUyfABf9U6E,4313
31
+ mxflashattn-1.4.0.dist-info/licenses/LICENSE,sha256=W8keWZ0wz2Gmlbibj3pKjX8mmMSIFbBVzRAFiquPYdk,11357
32
+ mxflashattn-1.4.0.dist-info/METADATA,sha256=6Uwd9e2JPy5ibioSW6rOg6SR3wBzn6NTk7tmUtjsgGk,12669
33
+ mxflashattn-1.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
34
+ mxflashattn-1.4.0.dist-info/top_level.txt,sha256=CavV-_vqFF4S5_ZLeY0f220-9-GHqW4hDjsYQQSMCM0,36
35
+ mxflashattn-1.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+