diff --git a/.buildkite/test-amd.yaml b/.buildkite/test-amd.yaml
index c7ef61b719..1bfe200ade 100644
--- a/.buildkite/test-amd.yaml
+++ b/.buildkite/test-amd.yaml
@@ -416,7 +416,7 @@ steps:
- tests/kernels/helion/
- vllm/platforms/rocm.py
commands:
- - pip install helion==1.0.0
+ - pip install helion==1.4.0
- pytest -v -s kernels/helion/
- label: Kernels Mamba Test # TBD
diff --git a/.buildkite/test_areas/kernels.yaml b/.buildkite/test_areas/kernels.yaml
index 68e6a5762e..0259847d99 100644
--- a/.buildkite/test_areas/kernels.yaml
+++ b/.buildkite/test_areas/kernels.yaml
@@ -223,7 +223,7 @@ steps:
- vllm/utils/import_utils.py
- tests/kernels/helion/
commands:
- - pip install helion==1.0.0
+ - pip install helion==1.4.0
- pytest -v -s kernels/helion/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index bd92ec9854..39de56e352 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,7 +4,7 @@ default_install_hook_types:
default_stages:
- pre-commit # Run locally
- manual # Run in CI
-exclude: '(vllm/third_party/.*|flash_qla/.*)'
+exclude: '(vllm/third_party/.*|flash_qla/.*|csrc/sm70_turbomind/lmdeploy/.*)'
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.0
@@ -35,6 +35,11 @@ repos:
rev: v1.7.7
hooks:
- id: actionlint
+- repo: https://github.com/shellcheck-py/shellcheck-py
+ rev: 745eface02aef23e168a8afb6b5737818efbea95 # v0.11.0.1
+ hooks:
+ - id: shellcheck
+ args: ["-s", "bash", "--format=gcc", "--severity=error"]
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.11.1
hooks:
@@ -177,11 +182,6 @@ repos:
entry: python tools/pre_commit/mypy.py 1 "3.13"
<<: *mypy_common
stages: [manual] # Only run in CI
- - id: shellcheck
- name: Lint shell scripts
- entry: tools/pre_commit/shellcheck.sh
- language: script
- types: [shell]
- id: png-lint
name: Lint PNG exports from excalidraw
entry: tools/pre_commit/png-lint.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 21dc88d62a..c1fdaa5ea4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -397,6 +397,7 @@ if(VLLM_GPU_LANG STREQUAL "CUDA")
"${VLLM_SM70_TURBOMIND_LMDEPLOY_ROOT}/src/turbomind/kernels/gemm/kernel/sm70_884_16.cu"
"${VLLM_SM70_TURBOMIND_ROOT}/ops/tm_registry_sm70.cu"
"${VLLM_SM70_TURBOMIND_ROOT}/ops/fp8_qpn8_sm70.cu"
+ "${VLLM_SM70_TURBOMIND_ROOT}/ops/mxfp4_qpn_m1_sm70.cu"
"${VLLM_SM70_TURBOMIND_ROOT}/ops/nvfp4_qpn4_sm70.cu"
"${VLLM_SM70_TURBOMIND_ROOT}/ops/qwen38_prefill_cutlass.cu"
"${VLLM_SM70_TURBOMIND_ROOT}/ops/nvfp4_qpn2_sm70.cu"
@@ -729,6 +730,7 @@ if(VLLM_GPU_LANG STREQUAL "CUDA" AND SM70_TURBOMIND_ARCHS)
SOURCES ${VLLM_SM70_SAMPLER_FRAGMENT_SRCS}
COMPILE_FLAGS ${VLLM_GPU_FLAGS}
ARCHITECTURES ${VLLM_GPU_ARCHES}
+ USE_SABI 3
WITH_SOABI)
set_target_properties(_sm70_sampler_C PROPERTIES
CXX_STANDARD 17
diff --git a/README.md b/README.md
index f305d6e580..af2aba0f4d 100644
--- a/README.md
+++ b/README.md
@@ -349,9 +349,9 @@ python -m pip install -e . --no-build-isolation
请使用微信扫描下方二维码加入群组:
-
+
-> 提示:微信群二维码通常 7 天内有效。若扫描失败或提示过期,请重新打开本页查看最新图片,或关注仓库更新。
+> 提示:微信群二维码通常 7 天内有效。若扫描失败或提示过期,请微信搜索微信号添加:YM_isi。
## Repository Notes
diff --git a/benchmarks/benchmark_dspark_api.py b/benchmarks/benchmark_dspark_api.py
index 0279e4e896..a4cfa62140 100644
--- a/benchmarks/benchmark_dspark_api.py
+++ b/benchmarks/benchmark_dspark_api.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Issue one reproducible OpenAI chat request for DSpark validation."""
diff --git a/benchmarks/benchmark_dspark_stream.py b/benchmarks/benchmark_dspark_stream.py
index 16e7de9ae8..d40f1f237f 100644
--- a/benchmarks/benchmark_dspark_stream.py
+++ b/benchmarks/benchmark_dspark_stream.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Measure one streamed completions request with separate TTFT and TPOT."""
diff --git a/benchmarks/benchmark_sm70_decode.py b/benchmarks/benchmark_sm70_decode.py
index 19f27d6dea..93f4596100 100644
--- a/benchmarks/benchmark_sm70_decode.py
+++ b/benchmarks/benchmark_sm70_decode.py
@@ -52,20 +52,42 @@ def _sm70_fa2_d256_prefill_status(torch: Any) -> dict[str, Any]:
"sm70_d256_splitd_n32_paged_fwd",
)
optional_ops = ("sm70_d256_splitd_n32_dense_splitkv3_fwd",)
- try:
- importlib.import_module("vllm.vllm_flash_attn.flash_attn_interface")
- except (AttributeError, ImportError, RuntimeError) as exc:
- return {
- "available": False,
- "error": f"{type(exc).__name__}: {exc}",
- "extension_file": None,
- "extension_realpath": None,
- "required_ops": {name: False for name in required_ops},
- "optional_ops": {name: False for name in optional_ops},
- }
-
extension_file = _module_file("vllm.vllm_flash_attn._vllm_fa2_C")
namespace = getattr(torch.ops, "_vllm_fa2_C", None)
+ import_error: Exception | None = None
+ if namespace is None or not all(hasattr(namespace, name) for name in required_ops):
+ try:
+ importlib.import_module("vllm.vllm_flash_attn.flash_attn_interface")
+ except (AttributeError, ImportError, RuntimeError) as exc:
+ import_error = exc
+ namespace = getattr(torch.ops, "_vllm_fa2_C", None)
+ if namespace is None or not all(hasattr(namespace, name) for name in required_ops):
+ library_path = os.getenv("VLLM_SM70_FA2_D256_LIBRARY")
+ if library_path is not None:
+ try:
+ torch.ops.load_library(library_path)
+ except (OSError, RuntimeError) as load_exc:
+ return {
+ "available": False,
+ "error": f"{type(load_exc).__name__}: {load_exc}",
+ "extension_file": library_path,
+ "extension_realpath": str(Path(library_path).resolve()),
+ "required_ops": {name: False for name in required_ops},
+ "optional_ops": {name: False for name in optional_ops},
+ }
+ extension_file = library_path
+ elif import_error is not None:
+ return {
+ "available": False,
+ "error": f"{type(import_error).__name__}: {import_error}",
+ "extension_file": None,
+ "extension_realpath": None,
+ "required_ops": {name: False for name in required_ops},
+ "optional_ops": {name: False for name in optional_ops},
+ }
+ namespace = getattr(torch.ops, "_vllm_fa2_C", None)
+ if extension_file is None:
+ extension_file = os.getenv("VLLM_SM70_FA2_D256_LIBRARY")
required_status = {
name: namespace is not None and hasattr(namespace, name)
for name in required_ops
@@ -169,6 +191,7 @@ def _tracked_env() -> dict[str, str]:
"VLLM_FLASH_",
"FLASH_ATTN",
"FLA_",
+ "PREFIX_",
"CUDA_MODULE_LOADING",
"TORCH_CUDA_ARCH_LIST",
"TORCHINDUCTOR_",
@@ -1172,6 +1195,8 @@ def _sm70_gdn_fla_policy() -> dict[str, Any]:
def _sm70_moe_policy() -> dict[str, Any]:
add_allreduce = _env_bool("VLLM_SM70_MOE_ADD_ALLREDUCE", False)
+ qwen38_router_topk = _env_bool("VLLM_SM70_QWEN38_ROUTER_TOPK", True)
+ qwen38_nvfp4_qpn_m1 = _env_bool("VLLM_SM70_NVFP4_QWEN38_MOE_QPN_M1_DECODE", True)
single_token_fastpath = _env_bool("VLLM_SM70_MOE_SINGLE_TOKEN_FASTPATH", False)
single_token_permute = _env_bool(
"VLLM_SM70_MOE_SINGLE_TOKEN_PERMUTE_FASTPATH", False
@@ -1203,6 +1228,12 @@ def _sm70_moe_policy() -> dict[str, Any]:
return {
"VLLM_SM70_MOE_ADD_ALLREDUCE": os.environ.get("VLLM_SM70_MOE_ADD_ALLREDUCE"),
"moe_add_allreduce_effective": add_allreduce,
+ "VLLM_SM70_QWEN38_ROUTER_TOPK": os.environ.get("VLLM_SM70_QWEN38_ROUTER_TOPK"),
+ "qwen38_router_topk_effective": qwen38_router_topk,
+ "VLLM_SM70_NVFP4_QWEN38_MOE_QPN_M1_DECODE": os.environ.get(
+ "VLLM_SM70_NVFP4_QWEN38_MOE_QPN_M1_DECODE"
+ ),
+ "qwen38_nvfp4_qpn_m1_effective": qwen38_nvfp4_qpn_m1,
"VLLM_SM70_MOE_SINGLE_TOKEN_FASTPATH": os.environ.get(
"VLLM_SM70_MOE_SINGLE_TOKEN_FASTPATH"
),
@@ -1249,8 +1280,16 @@ def _sm70_moe_policy() -> dict[str, Any]:
),
"profile_trace_effective": profile_trace,
"expected_default": False,
+ "qwen38_router_topk_expected_default": True,
+ "qwen38_nvfp4_qpn_m1_expected_default": True,
"single_token_unpermute_expected_default": True,
"route_hit_oracle": (
+ "The exact Qwen3.8 E512/K10 lane requires "
+ "qwen38_router_topk_effective=true and the "
+ "`SM70 Qwen3.8 E512/K10 router top-k path enabled` marker. "
+ "The accepted routed-expert lane additionally requires "
+ "qwen38_nvfp4_qpn_m1_effective=true and the `SM70 Qwen3.8 "
+ "NVFP4 direct QPN-M1 expert path enabled` marker. "
"For CUDA-graph fast-path acceptance, require the C++ trace "
"`SM70 custom all_reduce_sum2 op reached ... capture=active`; "
"the Python MoERunner candidate log alone is not a custom-op hit. "
@@ -1267,6 +1306,7 @@ def _sm70_moe_policy() -> dict[str, Any]:
def _sm70_sampling_policy() -> dict[str, Any]:
+ use_v2_model_runner = _env_bool("VLLM_USE_V2_MODEL_RUNNER", False)
flash_0dot3_compile = _env_bool(
"VLLM_SM70_FLASH_V100_0DOT3_COMPILE_GRAPH",
False,
@@ -1279,6 +1319,8 @@ def _sm70_sampling_policy() -> dict[str, Any]:
full_lm_head = _env_bool("VLLM_SM70_ENABLE_LM_HEAD_FASTPATH", False)
dense_f16 = _env_bool("VLLM_SM70_ENABLE_DENSE_F16_FASTPATH", False)
return {
+ "VLLM_USE_V2_MODEL_RUNNER": os.environ.get("VLLM_USE_V2_MODEL_RUNNER"),
+ "use_v2_model_runner_effective": use_v2_model_runner,
"VLLM_SM70_GREEDY_TOKEN_FASTPATH": os.environ.get(
"VLLM_SM70_GREEDY_TOKEN_FASTPATH"
),
@@ -1319,6 +1361,14 @@ def _sm70_sampling_policy() -> dict[str, Any]:
and not full_lm_head
and not custom_top1_ar
),
+ "v2_greedy_tp_local_pair_policy": (
+ use_v2_model_runner
+ and greedy_fastpath
+ and not lm_head_top1
+ and not lm_head_top1_tc
+ and not full_lm_head
+ and not custom_top1_ar
+ ),
"route_hit_oracle": (
"Accepted default greedy decode requires "
"`SM70 LM head top1 layout prepared` plus "
@@ -1326,7 +1376,10 @@ def _sm70_sampling_policy() -> dict[str, Any]:
"The SM70 Flash-V100 compile-graph quality lane instead requires "
"VLLM_SM70_LM_HEAD_TOP1=0 and "
"compile_graph_local_logits_top1_policy=true, preserving greedy "
- "pair-gather while avoiding the fused top1 epilogue. "
+ "pair-gather while avoiding the fused top1 epilogue. The MRv2 "
+ "single-token lane additionally requires "
+ "v2_greedy_tp_local_pair_policy=true and the "
+ "`SM70 MRv2 greedy TP-local pair path enabled` log marker. "
"`SM70 dense fp16 fast path enabled for LM head` is expected only "
"when the explicit full LM-head fast path gate is enabled. "
"The 0.0.3 LM-head baseline lane requires full LM-head fast path "
diff --git a/benchmarks/benchmark_sm70_dflash2_gsm8k.py b/benchmarks/benchmark_sm70_dflash2_gsm8k.py
index ac92519225..47f96a1847 100644
--- a/benchmarks/benchmark_sm70_dflash2_gsm8k.py
+++ b/benchmarks/benchmark_sm70_dflash2_gsm8k.py
@@ -66,6 +66,12 @@ def _parse_args() -> argparse.Namespace:
parser.add_argument("--max-num-batched-tokens", type=int, default=512)
parser.add_argument("--max-num-seqs", type=int, default=4)
parser.add_argument("--sequential", action="store_true")
+ parser.add_argument("--enable-prefix-caching", action="store_true")
+ parser.add_argument(
+ "--mamba-cache-mode",
+ choices=("all", "align", "none"),
+ help="Override the engine Mamba cache mode for practical-contract runs.",
+ )
parser.add_argument("--gpu-memory-utilization", type=float, default=0.8)
parser.add_argument(
"--target-kv-cache-dtype",
@@ -85,12 +91,26 @@ def _parse_args() -> argparse.Namespace:
help="Draft-only attention backend; the target remains on FLASH_ATTN_V100.",
)
parser.add_argument("--seed", type=int, default=0)
- parser.add_argument(
+ seed_group = parser.add_mutually_exclusive_group()
+ seed_group.add_argument(
"--request-seed",
type=int,
default=0,
help="Sampling seed for every request; use -1 for server-style random seeds.",
)
+ seed_group.add_argument(
+ "--request-seeds",
+ help=(
+ "Comma-separated non-negative sampling seeds. Each seed replays the "
+ "selected prompt set without reloading the model."
+ ),
+ )
+ parser.add_argument(
+ "--request-seed-mode",
+ choices=("fixed", "index"),
+ default="fixed",
+ help="Use each seed as-is or add the original dataset index per request.",
+ )
parser.add_argument(
"--cuda-profiler-capture",
action="store_true",
@@ -107,6 +127,23 @@ def _sha256_file(path: Path) -> str:
return digest.hexdigest()
+def _request_seeds(args: argparse.Namespace) -> list[int | None]:
+ if args.request_seeds is None:
+ if args.request_seed < -1:
+ raise ValueError("--request-seed must be -1 or a non-negative integer")
+ return [None if args.request_seed == -1 else args.request_seed]
+
+ try:
+ seeds = [int(value.strip()) for value in args.request_seeds.split(",")]
+ except ValueError as exc:
+ raise ValueError("--request-seeds must be comma-separated integers") from exc
+ if not seeds or any(seed < 0 for seed in seeds):
+ raise ValueError("--request-seeds must contain non-negative integers")
+ if len(set(seeds)) != len(seeds):
+ raise ValueError("--request-seeds must not contain duplicates")
+ return seeds
+
+
def _model_weight_files(model: Path) -> dict[str, str]:
index = model / "model.safetensors.index.json"
if not index.is_file():
@@ -219,10 +256,11 @@ def main() -> int:
args = _parse_args()
if args.num_questions <= 0:
raise ValueError("--num-questions must be positive")
- if args.request_seed < -1:
- raise ValueError("--request-seed must be -1 or a non-negative integer")
if args.mode == "dflash" and args.draft_model is None:
raise ValueError("--draft-model is required for --mode dflash")
+ if args.request_seed_mode == "index" and not args.sequential:
+ raise ValueError("--request-seed-mode index requires --sequential")
+ request_seeds = _request_seeds(args)
import torch
import vllm._C as vllm_c
@@ -275,12 +313,14 @@ def main() -> int:
"max_num_batched_tokens": args.max_num_batched_tokens,
"max_num_seqs": args.max_num_seqs,
"gpu_memory_utilization": args.gpu_memory_utilization,
- "enable_prefix_caching": False,
+ "enable_prefix_caching": args.enable_prefix_caching,
"disable_log_stats": False,
"enforce_eager": args.enforce_eager,
"seed": args.seed,
"speculative_config": speculative_config,
}
+ if args.mamba_cache_mode is not None:
+ engine_kwargs["mamba_cache_mode"] = args.mamba_cache_mode
if args.cuda_profiler_capture:
engine_kwargs["profiler_config"] = {"profiler": "cuda"}
@@ -288,42 +328,84 @@ def main() -> int:
llm = LLM(**engine_kwargs)
load_seconds = time.perf_counter() - load_started
- request_seed = None if args.request_seed == -1 else args.request_seed
+ warmup_seed = request_seeds[0]
+ if warmup_seed is not None and args.request_seed_mode == "index":
+ warmup_seed += rows[0][0]
warmup_sampling = SamplingParams(
temperature=args.temperature,
top_p=0.95,
top_k=20,
max_tokens=args.warmup_tokens,
- seed=request_seed,
+ seed=warmup_seed,
skip_special_tokens=False,
)
llm.generate([prompts[0]], warmup_sampling, use_tqdm=False)
- sampling = SamplingParams(
- temperature=args.temperature,
- top_p=0.95,
- top_k=20,
- max_tokens=args.max_tokens,
- seed=request_seed,
- skip_special_tokens=False,
- )
spec_before = _spec_metrics_snapshot(llm)
if args.cuda_profiler_capture:
llm.start_profile()
started = time.perf_counter()
- if args.sequential:
- outputs = []
- request_spec_metrics = []
- for prompt in prompts:
- request_spec_before = _spec_metrics_snapshot(llm)
- outputs.append(llm.generate([prompt], sampling, use_tqdm=False)[0])
- request_spec_after = _spec_metrics_snapshot(llm)
- request_spec_metrics.append(
- _diff_spec_metrics(request_spec_before, request_spec_after)
+ outputs = []
+ request_spec_metrics = []
+ case_inputs = []
+ for seed_base in request_seeds:
+ if args.sequential:
+ seed_outputs = []
+ seed_spec_metrics = []
+ actual_seeds = []
+ for (dataset_index, _row), prompt in zip(rows, prompts, strict=True):
+ request_seed = seed_base
+ if request_seed is not None and args.request_seed_mode == "index":
+ request_seed += dataset_index
+ sampling = SamplingParams(
+ temperature=args.temperature,
+ top_p=0.95,
+ top_k=20,
+ max_tokens=args.max_tokens,
+ seed=request_seed,
+ skip_special_tokens=False,
+ )
+ request_spec_before = _spec_metrics_snapshot(llm)
+ seed_outputs.append(llm.generate([prompt], sampling, use_tqdm=False)[0])
+ request_spec_after = _spec_metrics_snapshot(llm)
+ seed_spec_metrics.append(
+ _diff_spec_metrics(request_spec_before, request_spec_after)
+ )
+ actual_seeds.append(request_seed)
+ else:
+ sampling = SamplingParams(
+ temperature=args.temperature,
+ top_p=0.95,
+ top_k=20,
+ max_tokens=args.max_tokens,
+ seed=seed_base,
+ skip_special_tokens=False,
+ )
+ seed_outputs = llm.generate(prompts, sampling, use_tqdm=False)
+ seed_spec_metrics = [None] * len(seed_outputs)
+ actual_seeds = [seed_base] * len(seed_outputs)
+ outputs.extend(seed_outputs)
+ request_spec_metrics.extend(seed_spec_metrics)
+ case_inputs.extend(
+ (
+ seed_base,
+ request_seed,
+ dataset_index,
+ row,
+ prompt_content,
+ prompt_tokens,
+ )
+ for request_seed, (
+ dataset_index,
+ row,
+ ), prompt_content, prompt_tokens in zip(
+ actual_seeds,
+ rows,
+ prompt_contents,
+ prompt_token_counts,
+ strict=True,
)
- else:
- outputs = llm.generate(prompts, sampling, use_tqdm=False)
- request_spec_metrics = [None] * len(outputs)
+ )
elapsed_seconds = time.perf_counter() - started
if args.cuda_profiler_capture:
llm.stop_profile()
@@ -331,10 +413,17 @@ def main() -> int:
cases = []
for (
+ request_seed_base,
+ request_seed,
dataset_index,
row,
- ), prompt_content, prompt_tokens, output, request_spec in zip(
- rows, prompt_contents, prompt_token_counts, outputs, request_spec_metrics
+ prompt_content,
+ prompt_tokens,
+ ), output, request_spec in zip(
+ case_inputs,
+ outputs,
+ request_spec_metrics,
+ strict=True,
):
result = output.outputs[0]
token_ids = list(result.token_ids)
@@ -348,7 +437,11 @@ def main() -> int:
correct = None
cases.append(
{
+ "request_seed_base": request_seed_base,
+ "request_seed": request_seed,
"dataset_index": dataset_index,
+ "suite": row.get("_suite"),
+ "suite_index": row.get("_suite_index"),
"question": row.get("question"),
"prompt_content": prompt_content,
"expected_answer": expected,
@@ -400,6 +493,7 @@ def main() -> int:
"dataset_format": args.dataset_format,
"start_index": args.start_index,
"num_questions": args.num_questions,
+ "num_samples": len(cases),
"dataset_order": args.dataset_order,
"model": str(args.model),
"model_config_sha256": _sha256_file(args.model / "config.json"),
@@ -418,7 +512,14 @@ def main() -> int:
"top_p": 0.95,
"top_k": 20,
"max_tokens": args.max_tokens,
- "seed": request_seed,
+ "seed": (
+ request_seeds[0]
+ if len(request_seeds) == 1 and args.request_seed_mode == "fixed"
+ else None
+ ),
+ "seeds": (request_seeds if args.request_seed_mode == "fixed" else None),
+ "seed_bases": request_seeds,
+ "seed_mode": args.request_seed_mode,
"ignore_eos": False,
"thinking": True,
"reasoning_effort": "xhigh",
diff --git a/benchmarks/benchmark_sm70_flashinfer_fixed_entry.py b/benchmarks/benchmark_sm70_flashinfer_fixed_entry.py
index 2482003308..4eb48de306 100644
--- a/benchmarks/benchmark_sm70_flashinfer_fixed_entry.py
+++ b/benchmarks/benchmark_sm70_flashinfer_fixed_entry.py
@@ -263,9 +263,7 @@ def _active_ctas_per_sm(
threads_per_cta: int,
shared_bytes_per_cta: int,
) -> int:
- register_limited = SM70_REGISTERS_PER_SM // (
- registers_per_thread * threads_per_cta
- )
+ register_limited = SM70_REGISTERS_PER_SM // (registers_per_thread * threads_per_cta)
shared_limited = SM70_SHARED_BYTES_PER_SM // shared_bytes_per_cta
thread_limited = SM70_THREADS_PER_SM // threads_per_cta
return min(register_limited, shared_limited, thread_limited, SM70_MAX_CTA_PER_SM)
@@ -350,9 +348,7 @@ def _paged_resource_gate(kernel: Mapping[str, Any]) -> dict[str, Any]:
f"requires <= {PAGED_MAX_SHARED_BYTES}"
)
if kernel["active_ctas_per_sm"] != 2:
- reasons.append(
- f"active_ctas_per_sm={kernel['active_ctas_per_sm']}, requires 2"
- )
+ reasons.append(f"active_ctas_per_sm={kernel['active_ctas_per_sm']}, requires 2")
instructions = kernel["instructions"]
if instructions["hmma"] == 0:
reasons.append("paged target has no HMMA")
@@ -617,15 +613,9 @@ def _pairwise_stats(
return {
"right_minus_left_mean_ms": float(statistics.mean(deltas)),
"right_minus_left_p50_ms": float(statistics.median(deltas)),
- "right_faster_wins": sum(
- right_ms < left_ms for left_ms, right_ms in paired
- ),
- "left_faster_wins": sum(
- left_ms < right_ms for left_ms, right_ms in paired
- ),
- "ties": sum(
- left_ms == right_ms for left_ms, right_ms in paired
- ),
+ "right_faster_wins": sum(right_ms < left_ms for left_ms, right_ms in paired),
+ "left_faster_wins": sum(left_ms < right_ms for left_ms, right_ms in paired),
+ "ties": sum(left_ms == right_ms for left_ms, right_ms in paired),
"right_vs_left_mean_pct": (
(right_stats["mean_ms"] / left_stats["mean_ms"] - 1.0) * 100.0
),
diff --git a/benchmarks/benchmark_sm70_flashqla_indexed_state_cache.py b/benchmarks/benchmark_sm70_flashqla_indexed_state_cache.py
index f83336bfbc..e94a7f9ace 100644
--- a/benchmarks/benchmark_sm70_flashqla_indexed_state_cache.py
+++ b/benchmarks/benchmark_sm70_flashqla_indexed_state_cache.py
@@ -72,27 +72,38 @@ def main() -> None:
dtype = torch.float16
scale = args.dim**-0.5
- q = (torch.randn(1, args.tokens, args.q_heads, args.dim,
- device=device, dtype=dtype) * 0.05).contiguous()
+ q = (
+ torch.randn(1, args.tokens, args.q_heads, args.dim, device=device, dtype=dtype)
+ * 0.05
+ ).contiguous()
k = (torch.randn_like(q) * 0.05).contiguous()
- v = (torch.randn(1, args.tokens, args.v_heads, args.dim,
- device=device, dtype=dtype) * 0.1).contiguous()
- g = (torch.randn(1, args.tokens, args.v_heads,
- device=device, dtype=torch.float32) * 0.02 - 0.04).contiguous()
- beta = torch.rand(1, args.tokens, args.v_heads,
- device=device, dtype=torch.float32).contiguous()
+ v = (
+ torch.randn(1, args.tokens, args.v_heads, args.dim, device=device, dtype=dtype)
+ * 0.1
+ ).contiguous()
+ g = (
+ torch.randn(1, args.tokens, args.v_heads, device=device, dtype=torch.float32)
+ * 0.02
+ - 0.04
+ ).contiguous()
+ beta = torch.rand(
+ 1, args.tokens, args.v_heads, device=device, dtype=torch.float32
+ ).contiguous()
cu_seqlens = torch.tensor([0, args.tokens], device=device, dtype=torch.int32)
state_indices = torch.tensor([args.state_index], device=device, dtype=torch.long)
has_initial_state = torch.ones(1, device=device, dtype=torch.bool)
- base_state_cache = (torch.randn(
- args.state_slots,
- args.v_heads,
- args.dim,
- args.dim,
- device=device,
- dtype=torch.float32,
- ) * 0.01).contiguous()
+ base_state_cache = (
+ torch.randn(
+ args.state_slots,
+ args.v_heads,
+ args.dim,
+ args.dim,
+ device=device,
+ dtype=torch.float32,
+ )
+ * 0.01
+ ).contiguous()
gather_cache = base_state_cache.clone()
indexed_cache = base_state_cache.clone()
gather_out = torch.empty_like(v)
@@ -151,8 +162,9 @@ def indexed_call():
correctness = {
"out": _diff(gather_result, indexed_result),
- "state_slot": _diff(gather_cache[args.state_index],
- indexed_cache[args.state_index]),
+ "state_slot": _diff(
+ gather_cache[args.state_index], indexed_cache[args.state_index]
+ ),
}
if args.state_slots > 1:
untouched_index = 0 if args.state_index != 0 else args.state_slots - 1
diff --git a/benchmarks/benchmark_sm70_fp8_fixed_vs_dynamic.py b/benchmarks/benchmark_sm70_fp8_fixed_vs_dynamic.py
index 7d21e6def3..fd9e069e54 100644
--- a/benchmarks/benchmark_sm70_fp8_fixed_vs_dynamic.py
+++ b/benchmarks/benchmark_sm70_fp8_fixed_vs_dynamic.py
@@ -65,8 +65,9 @@ def _candidate_layers(model_path: Path) -> tuple[dict[str, str], list[str]]:
return weight_map, layers
-def _select_layers(layers: list[str], layer_ids: set[int],
- max_layers: int) -> list[str]:
+def _select_layers(
+ layers: list[str], layer_ids: set[int], max_layers: int
+) -> list[str]:
selected: list[str] = []
seen_kind: set[str] = set()
for prefix in layers:
@@ -100,8 +101,7 @@ def _run_case(
"skip": "shape_not_multiple_128",
}
- tm_weight, tm_scales, meta = sm70_ops.fp8_sm70_prepare(
- qweight, scales, group_size)
+ tm_weight, tm_scales, meta = sm70_ops.fp8_sm70_prepare(qweight, scales, group_size)
x = torch.randn((m, k), device=qweight.device, dtype=torch.float16)
fixed = torch.empty((m, n), device=qweight.device, dtype=torch.float16)
@@ -120,8 +120,7 @@ def _run_case(
os.environ["VLLM_SM70_FP8_TUNE_SMALL_SHAPES"] = "0"
fixed_after = torch.empty((m, n), device=qweight.device, dtype=torch.float16)
- sm70_ops.fp8_gemm_sm70_out_meta(
- fixed_after, x, tm_weight, tm_scales, meta)
+ sm70_ops.fp8_gemm_sm70_out_meta(fixed_after, x, tm_weight, tm_scales, meta)
torch.accelerator.synchronize(qweight.device)
diff_dynamic = (fixed.float() - dynamic.float()).abs()
@@ -178,8 +177,7 @@ def main() -> int:
results: list[dict[str, Any]] = []
try:
for prefix in selected:
- qweight, scales = _load_fp8_layer(
- args.model, weight_map, prefix, device)
+ qweight, scales = _load_fp8_layer(args.model, weight_map, prefix, device)
for m in args.m:
results.append(_run_case(prefix, qweight, scales, m))
finally:
@@ -189,7 +187,8 @@ def main() -> int:
os.environ["VLLM_SM70_FP8_TUNE_SMALL_SHAPES"] = original_env
failures = [
- item for item in results
+ item
+ for item in results
if item.get("fixed_vs_dynamic_max_diff", 0.0) != 0.0
or not item.get("fixed_vs_dynamic_equal", True)
]
diff --git a/benchmarks/benchmark_sm70_hmma_c2a_mincomm.py b/benchmarks/benchmark_sm70_hmma_c2a_mincomm.py
index 8eed68503a..1e9baafc70 100644
--- a/benchmarks/benchmark_sm70_hmma_c2a_mincomm.py
+++ b/benchmarks/benchmark_sm70_hmma_c2a_mincomm.py
@@ -7,13 +7,14 @@
import argparse
import json
import os
-import re
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Any
+import regex as re
+
SYMBOLS = {
"reference": "sm70_hmma_c2a_reference",
"candidate": "sm70_hmma_c2a_mincomm",
diff --git a/benchmarks/benchmark_sm70_instruction_latency.py b/benchmarks/benchmark_sm70_instruction_latency.py
index 05ec0612f7..d75ddb1397 100644
--- a/benchmarks/benchmark_sm70_instruction_latency.py
+++ b/benchmarks/benchmark_sm70_instruction_latency.py
@@ -7,13 +7,14 @@
import argparse
import json
import os
-import re
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Any
+import regex as re
+
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
diff --git a/benchmarks/benchmark_sm70_lm_head_top1.py b/benchmarks/benchmark_sm70_lm_head_top1.py
index a34e3e0fc1..4e846e1c50 100644
--- a/benchmarks/benchmark_sm70_lm_head_top1.py
+++ b/benchmarks/benchmark_sm70_lm_head_top1.py
@@ -111,9 +111,7 @@ def main() -> int:
x = torch.randn((args.m, args.k), device=device, dtype=torch.float16)
weight = torch.randn((args.n, args.k), device=device, dtype=torch.float16)
- torch_logits_out = torch.empty(
- (args.m, args.n), device=device, dtype=torch.float16
- )
+ torch_logits_out = torch.empty((args.m, args.n), device=device, dtype=torch.float16)
prepared = sm70_ops.sm70_f16_prepare(weight)
tm_weight = prepared[0]
k_ld = int(prepared[1][0].item())
@@ -121,7 +119,7 @@ def main() -> int:
def torch_mm_max() -> tuple[torch.Tensor, torch.Tensor]:
logits = torch.mm(x, weight.t())
if args.pad:
- logits[:, -args.pad:] = -float("inf")
+ logits[:, -args.pad :] = -float("inf")
values, indices = logits.max(dim=-1)
return values, indices.to(torch.int64) + args.vocab_start
@@ -189,15 +187,21 @@ def tensor_core_top1() -> None:
def sm70_gemm_max() -> tuple[torch.Tensor, torch.Tensor]:
sm70_ops.sm70_f16_gemm_out(logits_out, x, tm_weight, k_ld, False)
if args.pad:
- logits_out[:, -args.pad:] = -float("inf")
+ logits_out[:, -args.pad :] = -float("inf")
values, indices = logits_out.max(dim=-1)
return values, indices.to(torch.int64) + args.vocab_start
sm70_values, sm70_indices = sm70_gemm_max()
sm70_ms = _bench_cuda_ms(lambda: sm70_gemm_max(), args.warmup, args.iters)
results.append(
- _stats("sm70_gemm_then_max", sm70_values, sm70_indices, ref_values,
- ref_indices, sm70_ms)
+ _stats(
+ "sm70_gemm_then_max",
+ sm70_values,
+ sm70_indices,
+ ref_values,
+ ref_indices,
+ sm70_ms,
+ )
)
torch_mm_ms = _bench_cuda_ms(lambda: torch_mm_max(), args.warmup, args.iters)
diff --git a/benchmarks/benchmark_sm70_long_quality_suffix.py b/benchmarks/benchmark_sm70_long_quality_suffix.py
index 0a9c06a273..f57a802ce3 100644
--- a/benchmarks/benchmark_sm70_long_quality_suffix.py
+++ b/benchmarks/benchmark_sm70_long_quality_suffix.py
@@ -220,9 +220,9 @@ def main() -> None:
"im_end_count": result["im_end_count"],
"unique_tokens": result["unique_tokens"],
"top_token_count_id": result["top_token_count_id"],
- "steady_decode_tps": (
- result["request_metrics"] or {}
- ).get("steady_decode_tps"),
+ "steady_decode_tps": (result["request_metrics"] or {}).get(
+ "steady_decode_tps"
+ ),
"prefix": text[:160],
},
ensure_ascii=False,
diff --git a/benchmarks/benchmark_sm70_model_tokens.py b/benchmarks/benchmark_sm70_model_tokens.py
index 2f0d580bcf..75112d51fd 100644
--- a/benchmarks/benchmark_sm70_model_tokens.py
+++ b/benchmarks/benchmark_sm70_model_tokens.py
@@ -240,6 +240,66 @@ def _spec_decoding_summary(
}
+def _spec_decoding_delta(
+ before: list[dict[str, Any]],
+ after: list[dict[str, Any]],
+) -> dict[str, Any] | None:
+ """Return speculative-decoding counters added between two snapshots."""
+
+ before_summary = _spec_decoding_summary(before)
+ after_summary = _spec_decoding_summary(after)
+ if after_summary is None:
+ return None
+
+ before_drafts = int(before_summary["num_drafts"]) if before_summary else 0
+ before_draft_tokens = (
+ int(before_summary["num_draft_tokens"]) if before_summary else 0
+ )
+ before_accepted = (
+ int(before_summary["num_accepted_tokens"]) if before_summary else 0
+ )
+ after_drafts = int(after_summary["num_drafts"])
+ after_draft_tokens = int(after_summary["num_draft_tokens"])
+ after_accepted = int(after_summary["num_accepted_tokens"])
+
+ num_drafts = after_drafts - before_drafts
+ num_draft_tokens = after_draft_tokens - before_draft_tokens
+ num_accepted_tokens = after_accepted - before_accepted
+ if num_drafts <= 0:
+ return None
+ if num_draft_tokens < 0 or num_accepted_tokens < 0:
+ raise RuntimeError("Speculative-decoding counters moved backwards")
+
+ before_per_pos = (
+ list(before_summary["accepted_tokens_per_pos"]) if before_summary else []
+ )
+ after_per_pos = list(after_summary["accepted_tokens_per_pos"])
+ width = max(len(before_per_pos), len(after_per_pos))
+ before_per_pos.extend([0] * (width - len(before_per_pos)))
+ after_per_pos.extend([0] * (width - len(after_per_pos)))
+ accepted_tokens_per_pos = [
+ end - start for start, end in zip(before_per_pos, after_per_pos, strict=True)
+ ]
+ if any(value < 0 for value in accepted_tokens_per_pos):
+ raise RuntimeError("Per-position speculative counters moved backwards")
+
+ avg_accepted_tokens = num_accepted_tokens / num_drafts
+ return {
+ "num_drafts": num_drafts,
+ "num_draft_tokens": num_draft_tokens,
+ "num_accepted_tokens": num_accepted_tokens,
+ "avg_accepted_tokens_no_bonus": avg_accepted_tokens,
+ "mean_acceptance_length": 1 + avg_accepted_tokens,
+ "draft_acceptance_rate": (
+ num_accepted_tokens / num_draft_tokens if num_draft_tokens else None
+ ),
+ "accepted_tokens_per_pos": accepted_tokens_per_pos,
+ "per_position_acceptance_rate": [
+ value / num_drafts for value in accepted_tokens_per_pos
+ ],
+ }
+
+
def _load_prompts(args: argparse.Namespace) -> list[Any]:
if args.input_lens is not None:
if args.input_len is not None or args.prompt or args.prompts_json is not None:
@@ -1713,6 +1773,7 @@ def _dump(args: argparse.Namespace) -> int:
torch.accelerator.synchronize()
torch.cuda.cudart().cudaProfilerStart()
generate_seconds_by_repeat: list[float] = []
+ sequential_prompt_metrics: list[dict[str, Any]] = []
outputs = []
try:
for repeat_index in range(args.repeat_count):
@@ -1724,8 +1785,24 @@ def _dump(args: argparse.Namespace) -> int:
raise RuntimeError("Failed to reset the idle prefix cache")
generate_start = time.perf_counter()
if args.sequential_prompts:
- for prompt in prompts:
+ metrics_before_prompt = _metric_snapshot(llm)
+ for prompt_index, prompt in enumerate(prompts):
+ prompt_start = time.perf_counter()
outputs.extend(llm.generate([prompt], sampling_params))
+ prompt_seconds = time.perf_counter() - prompt_start
+ metrics_after_prompt = _metric_snapshot(llm)
+ sequential_prompt_metrics.append(
+ {
+ "repeat_index": repeat_index,
+ "prompt_index": prompt_index,
+ "generate_seconds": prompt_seconds,
+ "spec_decoding_metrics": _spec_decoding_delta(
+ metrics_before_prompt,
+ metrics_after_prompt,
+ ),
+ }
+ )
+ metrics_before_prompt = metrics_after_prompt
else:
outputs.extend(llm.generate(prompts, sampling_params))
generate_seconds_by_repeat.append(time.perf_counter() - generate_start)
@@ -1831,6 +1908,7 @@ def _dump(args: argparse.Namespace) -> int:
"eos_token_ids": eos_token_ids,
"metrics_snapshot": metrics_snapshot,
"spec_decoding_metrics": _spec_decoding_summary(metrics_snapshot),
+ "sequential_prompt_metrics": sequential_prompt_metrics,
"sampling_params": {
"max_tokens": args.max_tokens,
"temperature": args.temperature,
diff --git a/benchmarks/benchmark_sm70_native_bm32_allp_crossblock_micro.py b/benchmarks/benchmark_sm70_native_bm32_allp_crossblock_micro.py
index 10771b3a8b..6069cf2926 100644
--- a/benchmarks/benchmark_sm70_native_bm32_allp_crossblock_micro.py
+++ b/benchmarks/benchmark_sm70_native_bm32_allp_crossblock_micro.py
@@ -103,8 +103,7 @@ def _require_environment(args: argparse.Namespace) -> None:
raise ValueError(f"formal runs require exactly {K_DEFAULT_ROUNDS} rounds.")
if args.launches_per_sample != K_DEFAULT_LAUNCHES:
raise ValueError(
- "formal runs require exactly "
- f"{K_DEFAULT_LAUNCHES} launches per sample."
+ f"formal runs require exactly {K_DEFAULT_LAUNCHES} launches per sample."
)
@@ -261,12 +260,8 @@ def _inspect_sass(binary: Path) -> dict[str, Any]:
"kernels": kernels,
"static_instruction_delta": {
mnemonic: (
- kernels.get("candidate", {})
- .get("instructions", {})
- .get(mnemonic, 0)
- - kernels.get("baseline", {})
- .get("instructions", {})
- .get(mnemonic, 0)
+ kernels.get("candidate", {}).get("instructions", {}).get(mnemonic, 0)
+ - kernels.get("baseline", {}).get("instructions", {}).get(mnemonic, 0)
)
for mnemonic in ("hmma", "ldg", "lds", "sts", "ldl", "stl", "bar")
},
@@ -302,13 +297,11 @@ def _resource_gate(
)
if resource.get("registers_per_thread", 65) > 64:
reasons.append(
- f"{path} REG={resource.get('registers_per_thread')}, "
- "requires <=64"
+ f"{path} REG={resource.get('registers_per_thread')}, requires <=64"
)
if resource.get("local_bytes_per_thread") != 0:
reasons.append(
- f"{path} LOCAL={resource.get('local_bytes_per_thread')}, "
- "requires 0"
+ f"{path} LOCAL={resource.get('local_bytes_per_thread')}, requires 0"
)
if resource.get("static_shared_bytes") != K_ALLP_SHARED_BYTES:
reasons.append(
@@ -333,8 +326,7 @@ def _resource_gate(
continue
if ptxas["registers_per_thread"] > 64:
reasons.append(
- f"PTXAS {path} REG={ptxas['registers_per_thread']}, "
- "requires <=64"
+ f"PTXAS {path} REG={ptxas['registers_per_thread']}, requires <=64"
)
for key in ("stack_frame_bytes", "spill_store_bytes", "spill_load_bytes"):
if ptxas[key] != 0:
@@ -356,9 +348,7 @@ def _resource_gate(
instructions = path_sass.get("instructions", {})
for mnemonic in ("hmma", "ldg", "lds", "sts"):
if instructions.get(mnemonic, 0) == 0:
- reasons.append(
- f"{path} SASS has no {mnemonic.upper()} instruction"
- )
+ reasons.append(f"{path} SASS has no {mnemonic.upper()} instruction")
if instructions.get("ldl", 0) or instructions.get("stl", 0):
reasons.append(
f"{path} SASS has local instructions "
@@ -397,40 +387,31 @@ def _resource_gate(
return not reasons, reasons
-def _correctness_gate(
- payload: dict[str, Any], groups: int
-) -> tuple[bool, list[str]]:
+def _correctness_gate(payload: dict[str, Any], groups: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
exactness = payload.get("exactness") or {}
expected_words = groups * K_M * K_D // 2
if exactness.get("word_dtype") != "uint32 packed fp16":
reasons.append(
- "word_dtype="
- f"{exactness.get('word_dtype')}, requires uint32 packed fp16"
+ f"word_dtype={exactness.get('word_dtype')}, requires uint32 packed fp16"
)
if exactness.get("word_count") != expected_words:
reasons.append(
- "word_count="
- f"{exactness.get('word_count')}, requires {expected_words}"
+ f"word_count={exactness.get('word_count')}, requires {expected_words}"
)
if exactness.get("full_output") is not True:
reasons.append("C++ probe did not compare the full output")
if exactness.get("bitwise_equal") is not True:
reasons.append("candidate output is not bitwise equal to baseline")
if exactness.get("mismatch_words") != 0:
- reasons.append(
- "mismatch_words="
- f"{exactness.get('mismatch_words')}, requires 0"
- )
+ reasons.append(f"mismatch_words={exactness.get('mismatch_words')}, requires 0")
xor = exactness.get("xor", {})
if xor.get("max_word") != 0 or xor.get("reduction") != 0:
reasons.append("packed uint32 XOR result is nonzero")
return not reasons, reasons
-def _performance_gate(
- payload: dict[str, Any], rounds: int
-) -> tuple[bool, list[str]]:
+def _performance_gate(payload: dict[str, Any], rounds: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
pairs = payload.get("pairs") or {}
if pairs.get("count") != rounds:
@@ -441,13 +422,10 @@ def _performance_gate(
f"candidate_faster={pairs.get('candidate_faster')}, "
f"requires >= {required_wins}/{rounds}"
)
- speedup_pct = (payload.get("timing") or {}).get(
- "candidate_speedup_vs_baseline_pct"
- )
+ speedup_pct = (payload.get("timing") or {}).get("candidate_speedup_vs_baseline_pct")
if speedup_pct is None or speedup_pct < K_REQUIRED_SPEEDUP_PCT:
reasons.append(
- f"median speedup={speedup_pct}, requires "
- f">= {K_REQUIRED_SPEEDUP_PCT}%"
+ f"median speedup={speedup_pct}, requires >= {K_REQUIRED_SPEEDUP_PCT}%"
)
return not reasons, reasons
@@ -666,14 +644,11 @@ def _run_ncu_kernel(
"mio_throttle_per_warp_active": metrics.get(
"smsp__warp_issue_stalled_mio_throttle_per_warp_active"
),
- "tensor_instructions": metrics.get(
- "smsp__inst_executed_pipe_tensor.sum"
- ),
+ "tensor_instructions": metrics.get("smsp__inst_executed_pipe_tensor.sum"),
},
"stdout_tail": completed.stdout[-3000:],
"stderr_tail": completed.stderr[-3000:],
- "permission_error": "ERR_NVGPUCTRPERM"
- in (completed.stdout + completed.stderr),
+ "permission_error": "ERR_NVGPUCTRPERM" in (completed.stdout + completed.stderr),
}
@@ -830,8 +805,7 @@ def _main() -> int:
"benchmark": "sm70_native_bm32_allp_crossblock_micro",
"target": "sm_70",
"matrix": [
- {"pattern": pattern, "nblocks": nblocks}
- for pattern, nblocks in K_CASES
+ {"pattern": pattern, "nblocks": nblocks} for pattern, nblocks in K_CASES
],
"configuration": {
"groups": args.groups,
diff --git a/benchmarks/benchmark_sm70_native_bm32_allp_scratch_micro.py b/benchmarks/benchmark_sm70_native_bm32_allp_scratch_micro.py
index 4679eff592..177a128420 100644
--- a/benchmarks/benchmark_sm70_native_bm32_allp_scratch_micro.py
+++ b/benchmarks/benchmark_sm70_native_bm32_allp_scratch_micro.py
@@ -94,10 +94,7 @@ def _require_environment(args: argparse.Namespace) -> None:
if args.rounds < K_DEFAULT_ROUNDS:
raise ValueError(f"rounds must be at least {K_DEFAULT_ROUNDS}.")
if args.launches_per_sample < K_DEFAULT_LAUNCHES:
- raise ValueError(
- "launches-per-sample must be at least "
- f"{K_DEFAULT_LAUNCHES}."
- )
+ raise ValueError(f"launches-per-sample must be at least {K_DEFAULT_LAUNCHES}.")
def _graphics_clock_mhz(physical_gpu: int) -> int:
@@ -248,8 +245,7 @@ def _inspect_sass(binary: Path) -> dict[str, Any]:
"ctas_per_group": ctas_per_group,
"instructions": instructions,
"instructions_per_group": {
- name: count * ctas_per_group
- for name, count in instructions.items()
+ name: count * ctas_per_group for name, count in instructions.items()
},
}
baseline_instructions = kernels.get("baseline", {}).get("instructions", {})
@@ -293,13 +289,11 @@ def _resource_gate(
)
if resource.get("registers_per_thread", 65) > 64:
reasons.append(
- f"{path} REG={resource.get('registers_per_thread')}, "
- "requires <=64"
+ f"{path} REG={resource.get('registers_per_thread')}, requires <=64"
)
if resource.get("local_bytes_per_thread") != 0:
reasons.append(
- f"{path} LOCAL={resource.get('local_bytes_per_thread')}, "
- "requires 0"
+ f"{path} LOCAL={resource.get('local_bytes_per_thread')}, requires 0"
)
if resource.get("static_shared_bytes") != K_ALLP_SHARED_BYTES:
reasons.append(
@@ -326,8 +320,7 @@ def _resource_gate(
continue
if ptxas["registers_per_thread"] > 64:
reasons.append(
- f"PTXAS {path} REG={ptxas['registers_per_thread']}, "
- "requires <=64"
+ f"PTXAS {path} REG={ptxas['registers_per_thread']}, requires <=64"
)
for key in ("stack_frame_bytes", "spill_store_bytes", "spill_load_bytes"):
if ptxas[key] != 0:
@@ -348,9 +341,7 @@ def _resource_gate(
instructions = path_sass.get("instructions", {})
for mnemonic in ("hmma", "ldg", "lds"):
if instructions.get(mnemonic, 0) == 0:
- reasons.append(
- f"{path} SASS has no {mnemonic.upper()} instruction"
- )
+ reasons.append(f"{path} SASS has no {mnemonic.upper()} instruction")
if instructions.get("ldl", 0) or instructions.get("stl", 0):
reasons.append(
f"{path} SASS has local instructions "
@@ -380,46 +371,35 @@ def _resource_gate(
}
for key, expected in expected_scratch.items():
if scratch.get(key) != expected:
- reasons.append(
- f"scratch {key}={scratch.get(key)}, requires {expected}"
- )
+ reasons.append(f"scratch {key}={scratch.get(key)}, requires {expected}")
return not reasons, reasons
-def _correctness_gate(
- payload: dict[str, Any], groups: int
-) -> tuple[bool, list[str]]:
+def _correctness_gate(payload: dict[str, Any], groups: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
exactness = payload.get("exactness", {})
expected_words = groups * K_M * K_D // 2
if exactness.get("word_dtype") != "uint32 packed fp16":
reasons.append(
- "word_dtype="
- f"{exactness.get('word_dtype')}, requires uint32 packed fp16"
+ f"word_dtype={exactness.get('word_dtype')}, requires uint32 packed fp16"
)
if exactness.get("word_count") != expected_words:
reasons.append(
- "word_count="
- f"{exactness.get('word_count')}, requires {expected_words}"
+ f"word_count={exactness.get('word_count')}, requires {expected_words}"
)
if exactness.get("full_output") is not True:
reasons.append("C++ probe did not compare the full output")
if exactness.get("bitwise_equal") is not True:
reasons.append("candidate output is not bitwise equal to baseline")
if exactness.get("mismatch_words") != 0:
- reasons.append(
- "mismatch_words="
- f"{exactness.get('mismatch_words')}, requires 0"
- )
+ reasons.append(f"mismatch_words={exactness.get('mismatch_words')}, requires 0")
xor = exactness.get("xor", {})
if xor.get("max_word") != 0 or xor.get("reduction") != 0:
reasons.append("packed uint32 XOR result is nonzero")
return not reasons, reasons
-def _performance_gate(
- payload: dict[str, Any], rounds: int
-) -> tuple[bool, list[str]]:
+def _performance_gate(payload: dict[str, Any], rounds: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
pairs = payload.get("pairs", {})
if pairs.get("count") != rounds:
@@ -430,13 +410,10 @@ def _performance_gate(
f"candidate_faster={pairs.get('candidate_faster')}, "
f"requires >= {required_wins}/{rounds}"
)
- speedup_pct = payload.get("timing", {}).get(
- "candidate_speedup_vs_baseline_pct"
- )
+ speedup_pct = payload.get("timing", {}).get("candidate_speedup_vs_baseline_pct")
if speedup_pct is None or speedup_pct < K_REQUIRED_SPEEDUP_PCT:
reasons.append(
- f"median speedup={speedup_pct}, requires "
- f">= {K_REQUIRED_SPEEDUP_PCT}%"
+ f"median speedup={speedup_pct}, requires >= {K_REQUIRED_SPEEDUP_PCT}%"
)
return not reasons, reasons
@@ -502,9 +479,7 @@ def _run_case(
resource_passed, resource_reasons = _resource_gate(
payload, sass, ptxas_baseline, ptxas_candidate, build_command
)
- performance_passed, performance_reasons = _performance_gate(
- payload, args.rounds
- )
+ performance_passed, performance_reasons = _performance_gate(payload, args.rounds)
reasons = [
*([] if completed.returncode == 0 else ["C++ benchmark returned nonzero"]),
*correctness_reasons,
@@ -625,14 +600,11 @@ def _run_ncu_kernel(
"l1tex__data_bank_conflicts_pipe_lsu_mem_shared.sum"
),
"duration_ns": metrics.get("gpu__time_duration.sum"),
- "tensor_instructions": metrics.get(
- "smsp__inst_executed_pipe_tensor.sum"
- ),
+ "tensor_instructions": metrics.get("smsp__inst_executed_pipe_tensor.sum"),
},
"stdout_tail": completed.stdout[-3000:],
"stderr_tail": completed.stderr[-3000:],
- "permission_error": "ERR_NVGPUCTRPERM"
- in (completed.stdout + completed.stderr),
+ "permission_error": "ERR_NVGPUCTRPERM" in (completed.stdout + completed.stderr),
}
@@ -659,17 +631,13 @@ def _ncu_payload(
def _aggregate_gates(cases: list[dict[str, Any]]) -> dict[str, Any]:
- correctness_all_cases = all(
- case["gates"]["correctness_passed"] for case in cases
- )
+ correctness_all_cases = all(case["gates"]["correctness_passed"] for case in cases)
resource_all_cases = all(case["gates"]["resource_passed"] for case in cases)
all_case_performance_passed = all(
case["gates"]["performance_passed"] for case in cases
)
aggregate_passed = (
- correctness_all_cases
- and resource_all_cases
- and all_case_performance_passed
+ correctness_all_cases and resource_all_cases and all_case_performance_passed
)
reasons: list[str] = []
if not correctness_all_cases:
@@ -735,8 +703,7 @@ def main() -> int:
"benchmark": "sm70_native_bm32_allp_scratch_micro",
"target": "sm_70",
"matrix": [
- {"pattern": pattern, "nblocks": nblocks}
- for pattern, nblocks in K_CASES
+ {"pattern": pattern, "nblocks": nblocks} for pattern, nblocks in K_CASES
],
"configuration": {
"groups": args.groups,
diff --git a/benchmarks/benchmark_sm70_native_bm32_full_phase_allp_micro.py b/benchmarks/benchmark_sm70_native_bm32_full_phase_allp_micro.py
index 0a222682e1..cbbe4b867d 100644
--- a/benchmarks/benchmark_sm70_native_bm32_full_phase_allp_micro.py
+++ b/benchmarks/benchmark_sm70_native_bm32_full_phase_allp_micro.py
@@ -87,10 +87,7 @@ def _require_environment(args: argparse.Namespace) -> None:
if args.rounds < K_DEFAULT_ROUNDS:
raise ValueError(f"rounds must be at least {K_DEFAULT_ROUNDS}.")
if args.launches_per_sample < K_DEFAULT_LAUNCHES:
- raise ValueError(
- "launches-per-sample must be at least "
- f"{K_DEFAULT_LAUNCHES}."
- )
+ raise ValueError(f"launches-per-sample must be at least {K_DEFAULT_LAUNCHES}.")
def _graphics_clock_mhz(physical_gpu: int) -> int:
@@ -239,8 +236,7 @@ def _inspect_sass(binary: Path) -> dict[str, Any]:
"ctas_per_group": ctas_per_group,
"instructions": instructions,
"instructions_per_group": {
- name: count * ctas_per_group
- for name, count in instructions.items()
+ name: count * ctas_per_group for name, count in instructions.items()
},
}
return {"available": True, "binary": str(binary), "kernels": kernels}
@@ -266,8 +262,7 @@ def _resource_gate(
reasons.append("C++ runtime resource gate did not pass")
if baseline.get("threads_per_cta") != 512:
reasons.append(
- "baseline threads_per_cta="
- f"{baseline.get('threads_per_cta')}, requires 512"
+ f"baseline threads_per_cta={baseline.get('threads_per_cta')}, requires 512"
)
if baseline.get("active_ctas_per_sm", 0) < 2:
reasons.append(
@@ -281,18 +276,15 @@ def _resource_gate(
)
if candidate.get("registers_per_thread", 65) > 64:
reasons.append(
- "candidate REG="
- f"{candidate.get('registers_per_thread')}, requires <=64"
+ f"candidate REG={candidate.get('registers_per_thread')}, requires <=64"
)
if candidate.get("local_bytes_per_thread") != 0:
reasons.append(
- "candidate LOCAL="
- f"{candidate.get('local_bytes_per_thread')}, requires 0"
+ f"candidate LOCAL={candidate.get('local_bytes_per_thread')}, requires 0"
)
if candidate.get("static_shared_bytes", 48 * 1024 + 1) > 48 * 1024:
reasons.append(
- "candidate shared="
- f"{candidate.get('static_shared_bytes')}, requires <=49152"
+ f"candidate shared={candidate.get('static_shared_bytes')}, requires <=49152"
)
if candidate.get("active_ctas_per_sm", 0) < 2:
reasons.append(
@@ -348,40 +340,31 @@ def _resource_gate(
return not reasons, reasons
-def _correctness_gate(
- payload: dict[str, Any], groups: int
-) -> tuple[bool, list[str]]:
+def _correctness_gate(payload: dict[str, Any], groups: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
exactness = payload.get("exactness", {})
expected_words = groups * K_M * K_D // 2
if exactness.get("word_dtype") != "uint32 packed fp16":
reasons.append(
- "word_dtype="
- f"{exactness.get('word_dtype')}, requires uint32 packed fp16"
+ f"word_dtype={exactness.get('word_dtype')}, requires uint32 packed fp16"
)
if exactness.get("word_count") != expected_words:
reasons.append(
- "word_count="
- f"{exactness.get('word_count')}, requires {expected_words}"
+ f"word_count={exactness.get('word_count')}, requires {expected_words}"
)
if exactness.get("full_output") is not True:
reasons.append("C++ probe did not compare the full output")
if exactness.get("bitwise_equal") is not True:
reasons.append("candidate output is not bitwise equal to baseline")
if exactness.get("mismatch_words") != 0:
- reasons.append(
- "mismatch_words="
- f"{exactness.get('mismatch_words')}, requires 0"
- )
+ reasons.append(f"mismatch_words={exactness.get('mismatch_words')}, requires 0")
xor = exactness.get("xor", {})
if xor.get("max_word") != 0 or xor.get("reduction") != 0:
reasons.append("packed uint32 XOR result is nonzero")
return not reasons, reasons
-def _performance_gate(
- payload: dict[str, Any], rounds: int
-) -> tuple[bool, list[str]]:
+def _performance_gate(payload: dict[str, Any], rounds: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
timing = payload.get("timing", {})
pairs = payload.get("pairs", {})
@@ -390,8 +373,7 @@ def _performance_gate(
reasons.append("candidate speedup was not reported")
elif speedup < K_REQUIRED_SPEEDUP_PCT:
reasons.append(
- f"candidate speedup {speedup:.3f}% is below "
- f"{K_REQUIRED_SPEEDUP_PCT:.3f}%"
+ f"candidate speedup {speedup:.3f}% is below {K_REQUIRED_SPEEDUP_PCT:.3f}%"
)
if pairs.get("count") != rounds:
reasons.append(f"pair count={pairs.get('count')}, requires {rounds}")
@@ -468,9 +450,7 @@ def _run_case(
resource_passed, resource_reasons = _resource_gate(
payload, sass, ptxas_candidate, build_command
)
- performance_passed, performance_reasons = _performance_gate(
- payload, args.rounds
- )
+ performance_passed, performance_reasons = _performance_gate(payload, args.rounds)
reasons = [
*([] if completed.returncode == 0 else ["C++ benchmark returned nonzero"]),
*correctness_reasons,
@@ -584,14 +564,11 @@ def _run_ncu_kernel(
"long_scoreboard_per_warp_active": metrics.get(
"smsp__warp_issue_stalled_long_scoreboard_per_warp_active"
),
- "tensor_instructions": metrics.get(
- "smsp__inst_executed_pipe_tensor.sum"
- ),
+ "tensor_instructions": metrics.get("smsp__inst_executed_pipe_tensor.sum"),
},
"stdout_tail": completed.stdout[-3000:],
"stderr_tail": completed.stderr[-3000:],
- "permission_error": "ERR_NVGPUCTRPERM"
- in (completed.stdout + completed.stderr),
+ "permission_error": "ERR_NVGPUCTRPERM" in (completed.stdout + completed.stderr),
}
@@ -620,9 +597,7 @@ def _ncu_payload(
def _aggregate_gates(cases: list[dict[str, Any]]) -> dict[str, Any]:
primary_cases = [case for case in cases if case["nblocks"] == 4]
short_cases = [case for case in cases if case["nblocks"] != 4]
- correctness_all_cases = all(
- case["gates"]["correctness_passed"] for case in cases
- )
+ correctness_all_cases = all(case["gates"]["correctness_passed"] for case in cases)
resource_all_cases = all(case["gates"]["resource_passed"] for case in cases)
primary_performance_passed = all(
case["gates"]["performance_passed"] for case in primary_cases
@@ -631,9 +606,7 @@ def _aggregate_gates(cases: list[dict[str, Any]]) -> dict[str, Any]:
case["gates"]["performance_passed"] for case in cases
)
short_case_performance_failures = [
- case["name"]
- for case in short_cases
- if not case["gates"]["performance_passed"]
+ case["name"] for case in short_cases if not case["gates"]["performance_passed"]
]
aggregate_passed = (
correctness_all_cases and resource_all_cases and primary_performance_passed
@@ -702,8 +675,7 @@ def main() -> int:
"benchmark": "sm70_native_bm32_full_phase_allp_micro",
"target": "sm_70",
"matrix": [
- {"pattern": pattern, "nblocks": nblocks}
- for pattern, nblocks in K_CASES
+ {"pattern": pattern, "nblocks": nblocks} for pattern, nblocks in K_CASES
],
"configuration": {
"groups": args.groups,
diff --git a/benchmarks/benchmark_sm70_native_bm32_full_phase_micro.py b/benchmarks/benchmark_sm70_native_bm32_full_phase_micro.py
index fa97a71a36..d856e33db1 100644
--- a/benchmarks/benchmark_sm70_native_bm32_full_phase_micro.py
+++ b/benchmarks/benchmark_sm70_native_bm32_full_phase_micro.py
@@ -87,10 +87,7 @@ def _require_environment(args: argparse.Namespace) -> None:
if args.rounds < K_DEFAULT_ROUNDS:
raise ValueError(f"rounds must be at least {K_DEFAULT_ROUNDS}.")
if args.launches_per_sample < K_DEFAULT_LAUNCHES:
- raise ValueError(
- "launches-per-sample must be at least "
- f"{K_DEFAULT_LAUNCHES}."
- )
+ raise ValueError(f"launches-per-sample must be at least {K_DEFAULT_LAUNCHES}.")
def _graphics_clock_mhz(physical_gpu: int) -> int:
@@ -239,8 +236,7 @@ def _inspect_sass(binary: Path) -> dict[str, Any]:
"ctas_per_group": ctas_per_group,
"instructions": instructions,
"instructions_per_group": {
- name: count * ctas_per_group
- for name, count in instructions.items()
+ name: count * ctas_per_group for name, count in instructions.items()
},
}
return {"available": True, "binary": str(binary), "kernels": kernels}
@@ -266,8 +262,7 @@ def _resource_gate(
reasons.append("C++ runtime resource gate did not pass")
if baseline.get("threads_per_cta") != 512:
reasons.append(
- "baseline threads_per_cta="
- f"{baseline.get('threads_per_cta')}, requires 512"
+ f"baseline threads_per_cta={baseline.get('threads_per_cta')}, requires 512"
)
if baseline.get("active_ctas_per_sm", 0) < 2:
reasons.append(
@@ -281,18 +276,15 @@ def _resource_gate(
)
if candidate.get("registers_per_thread", 65) > 64:
reasons.append(
- "candidate REG="
- f"{candidate.get('registers_per_thread')}, requires <=64"
+ f"candidate REG={candidate.get('registers_per_thread')}, requires <=64"
)
if candidate.get("local_bytes_per_thread") != 0:
reasons.append(
- "candidate LOCAL="
- f"{candidate.get('local_bytes_per_thread')}, requires 0"
+ f"candidate LOCAL={candidate.get('local_bytes_per_thread')}, requires 0"
)
if candidate.get("static_shared_bytes", 48 * 1024 + 1) > 48 * 1024:
reasons.append(
- "candidate shared="
- f"{candidate.get('static_shared_bytes')}, requires <=49152"
+ f"candidate shared={candidate.get('static_shared_bytes')}, requires <=49152"
)
if candidate.get("active_ctas_per_sm", 0) < 2:
reasons.append(
@@ -348,40 +340,31 @@ def _resource_gate(
return not reasons, reasons
-def _correctness_gate(
- payload: dict[str, Any], groups: int
-) -> tuple[bool, list[str]]:
+def _correctness_gate(payload: dict[str, Any], groups: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
exactness = payload.get("exactness", {})
expected_words = groups * K_M * K_D // 2
if exactness.get("word_dtype") != "uint32 packed fp16":
reasons.append(
- "word_dtype="
- f"{exactness.get('word_dtype')}, requires uint32 packed fp16"
+ f"word_dtype={exactness.get('word_dtype')}, requires uint32 packed fp16"
)
if exactness.get("word_count") != expected_words:
reasons.append(
- "word_count="
- f"{exactness.get('word_count')}, requires {expected_words}"
+ f"word_count={exactness.get('word_count')}, requires {expected_words}"
)
if exactness.get("full_output") is not True:
reasons.append("C++ probe did not compare the full output")
if exactness.get("bitwise_equal") is not True:
reasons.append("candidate output is not bitwise equal to baseline")
if exactness.get("mismatch_words") != 0:
- reasons.append(
- "mismatch_words="
- f"{exactness.get('mismatch_words')}, requires 0"
- )
+ reasons.append(f"mismatch_words={exactness.get('mismatch_words')}, requires 0")
xor = exactness.get("xor", {})
if xor.get("max_word") != 0 or xor.get("reduction") != 0:
reasons.append("packed uint32 XOR result is nonzero")
return not reasons, reasons
-def _performance_gate(
- payload: dict[str, Any], rounds: int
-) -> tuple[bool, list[str]]:
+def _performance_gate(payload: dict[str, Any], rounds: int) -> tuple[bool, list[str]]:
reasons: list[str] = []
timing = payload.get("timing", {})
pairs = payload.get("pairs", {})
@@ -390,8 +373,7 @@ def _performance_gate(
reasons.append("candidate speedup was not reported")
elif speedup < K_REQUIRED_SPEEDUP_PCT:
reasons.append(
- f"candidate speedup {speedup:.3f}% is below "
- f"{K_REQUIRED_SPEEDUP_PCT:.3f}%"
+ f"candidate speedup {speedup:.3f}% is below {K_REQUIRED_SPEEDUP_PCT:.3f}%"
)
if pairs.get("count") != rounds:
reasons.append(f"pair count={pairs.get('count')}, requires {rounds}")
@@ -468,9 +450,7 @@ def _run_case(
resource_passed, resource_reasons = _resource_gate(
payload, sass, ptxas_candidate, build_command
)
- performance_passed, performance_reasons = _performance_gate(
- payload, args.rounds
- )
+ performance_passed, performance_reasons = _performance_gate(payload, args.rounds)
reasons = [
*([] if completed.returncode == 0 else ["C++ benchmark returned nonzero"]),
*correctness_reasons,
@@ -584,14 +564,11 @@ def _run_ncu_kernel(
"long_scoreboard_per_warp_active": metrics.get(
"smsp__warp_issue_stalled_long_scoreboard_per_warp_active"
),
- "tensor_instructions": metrics.get(
- "smsp__inst_executed_pipe_tensor.sum"
- ),
+ "tensor_instructions": metrics.get("smsp__inst_executed_pipe_tensor.sum"),
},
"stdout_tail": completed.stdout[-3000:],
"stderr_tail": completed.stderr[-3000:],
- "permission_error": "ERR_NVGPUCTRPERM"
- in (completed.stdout + completed.stderr),
+ "permission_error": "ERR_NVGPUCTRPERM" in (completed.stdout + completed.stderr),
}
@@ -620,9 +597,7 @@ def _ncu_payload(
def _aggregate_gates(cases: list[dict[str, Any]]) -> dict[str, Any]:
primary_cases = [case for case in cases if case["nblocks"] == 4]
short_cases = [case for case in cases if case["nblocks"] != 4]
- correctness_all_cases = all(
- case["gates"]["correctness_passed"] for case in cases
- )
+ correctness_all_cases = all(case["gates"]["correctness_passed"] for case in cases)
resource_all_cases = all(case["gates"]["resource_passed"] for case in cases)
primary_performance_passed = all(
case["gates"]["performance_passed"] for case in primary_cases
@@ -631,9 +606,7 @@ def _aggregate_gates(cases: list[dict[str, Any]]) -> dict[str, Any]:
case["gates"]["performance_passed"] for case in cases
)
short_case_performance_failures = [
- case["name"]
- for case in short_cases
- if not case["gates"]["performance_passed"]
+ case["name"] for case in short_cases if not case["gates"]["performance_passed"]
]
aggregate_passed = (
correctness_all_cases and resource_all_cases and primary_performance_passed
@@ -702,8 +675,7 @@ def main() -> int:
"benchmark": "sm70_native_bm32_full_phase_micro",
"target": "sm_70",
"matrix": [
- {"pattern": pattern, "nblocks": nblocks}
- for pattern, nblocks in K_CASES
+ {"pattern": pattern, "nblocks": nblocks} for pattern, nblocks in K_CASES
],
"configuration": {
"groups": args.groups,
diff --git a/benchmarks/benchmark_sm70_native_bm32_pv_panel_micro.py b/benchmarks/benchmark_sm70_native_bm32_pv_panel_micro.py
index 3394ea1fd6..0391ec6b96 100644
--- a/benchmarks/benchmark_sm70_native_bm32_pv_panel_micro.py
+++ b/benchmarks/benchmark_sm70_native_bm32_pv_panel_micro.py
@@ -108,9 +108,7 @@ def _build_binary(verbose: bool) -> tuple[Path, list[str], str]:
if nvcc is None:
raise RuntimeError("nvcc is required to build the SM70 BM32 PV microbenchmark.")
source = (
- Path(__file__).resolve().parent
- / "csrc"
- / "sm70_native_bm32_pv_panel_micro.cu"
+ Path(__file__).resolve().parent / "csrc" / "sm70_native_bm32_pv_panel_micro.cu"
)
build_dir = (
Path(tempfile.gettempdir())
@@ -228,8 +226,7 @@ def _resource_gate(
)
if baseline.get("threads_per_cta") != 512:
reasons.append(
- "baseline threads_per_cta="
- f"{baseline.get('threads_per_cta')}, requires 512"
+ f"baseline threads_per_cta={baseline.get('threads_per_cta')}, requires 512"
)
if baseline.get("resident_active_warps") != 32:
reasons.append(
@@ -258,13 +255,11 @@ def _resource_gate(
)
if candidate.get("registers_per_thread", 65) > 64:
reasons.append(
- "candidate REG="
- f"{candidate.get('registers_per_thread')}, requires <=64"
+ f"candidate REG={candidate.get('registers_per_thread')}, requires <=64"
)
if candidate.get("local_bytes_per_thread") != 0:
reasons.append(
- "candidate LOCAL="
- f"{candidate.get('local_bytes_per_thread')}, requires 0"
+ f"candidate LOCAL={candidate.get('local_bytes_per_thread')}, requires 0"
)
if candidate_topology.get("ctas_per_group") != 1:
reasons.append(
@@ -388,9 +383,7 @@ def _run_ncu_kernel(
"long_scoreboard_per_warp_active": metrics.get(
"smsp__warp_issue_stalled_long_scoreboard_per_warp_active"
),
- "tensor_instructions": metrics.get(
- "smsp__inst_executed_pipe_tensor.sum"
- ),
+ "tensor_instructions": metrics.get("smsp__inst_executed_pipe_tensor.sum"),
},
"stdout_tail": result.stdout[-3000:],
"stderr_tail": result.stderr[-3000:],
diff --git a/benchmarks/benchmark_sm70_nvfp4_gemm_micro.py b/benchmarks/benchmark_sm70_nvfp4_gemm_micro.py
index e3751f9ee6..253ba1d1f9 100644
--- a/benchmarks/benchmark_sm70_nvfp4_gemm_micro.py
+++ b/benchmarks/benchmark_sm70_nvfp4_gemm_micro.py
@@ -1,11 +1,13 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
-"""Microbenchmark SM70 TurboMind NVFP4 dense GEMMs for 27B decode.
+"""Microbenchmark SM70 TurboMind and QPN4 NVFP4 dense GEMMs.
The default case set models one Qwen3.5-27B-NVFP4 decode token on one TP rank
with tensor_parallel_size=2. It times only nvfp4_gemm_sm70_out after synthetic
weights have been prepared and dispatch has been warmed, so the weighted total
-is comparable to the Nsight "TurboMind NVFP4 GEMM" critical-path bucket.
+is comparable to the Nsight "TurboMind NVFP4 GEMM" critical-path bucket. The
+``qpn4-prefill`` mode measures the existing bounded-workspace large-M route,
+including weight dequantization on every call.
"""
from __future__ import annotations
@@ -160,23 +162,30 @@ def _run_case(
use_cuda_graph: bool,
mode: str,
gemv_split_k: int,
+ gated_silu: bool,
) -> dict[str, Any]:
if case.k % group_size != 0:
raise ValueError(f"{case.label}: K={case.k} not divisible by {group_size}.")
qweight = _make_qweight(case.k, case.n, device)
scales = _make_scales(case.k, case.n, group_size, device)
x = _make_input(case.m, case.k, device)
- out = torch.empty((case.m, case.n), dtype=torch.float16, device=device)
+ if gated_silu and case.n % 2 != 0:
+ raise ValueError(f"{case.label}: gated-SiLU requires even N, got {case.n}.")
+ output_size = case.n // 2 if gated_silu else case.n
+ out = torch.empty((case.m, output_size), dtype=torch.float16, device=device)
k_ld = 0
q_ld = 0
tm_weight = None
tm_scales = None
+ qpn4_codes = None
+ qpn4_scales = None
+ dense_weight = None
qweight_packed = None
partials = None
if mode == "gemm":
tm_weight, tm_scales, meta = ops.nvfp4_sm70_prepare(
- qweight, scales, group_size, False
+ qweight, scales, group_size, gated_silu
)
k_ld = int(meta[0].item())
q_ld = int(meta[1].item())
@@ -190,7 +199,21 @@ def _run_case(
group_size,
k_ld,
q_ld,
+ gated_silu,
+ )
+ elif mode == "qpn4-prefill":
+ qpn4_codes, qpn4_scales = ops.nvfp4_qpn4_prepare_sm70(qweight, scales)
+ dense_weight = torch.empty((case.k, case.n), dtype=torch.float16, device=device)
+ run = partial(
+ ops.nvfp4_qpn4_dispatch_sm70_out,
+ out,
+ dense_weight.data_ptr(),
+ x,
+ qpn4_codes,
+ qpn4_scales,
+ 0.0,
False,
+ gated_silu,
)
elif mode in ("raw-gemv", "raw-gemv-warp", "raw-gemv-h2"):
if case.m != 1:
@@ -254,6 +277,7 @@ def _run_case(
"n": case.n,
"k": case.k,
"group_size": group_size,
+ "gated_silu": gated_silu,
"gemv_split_k": gemv_split_k if mode in ("raw-gemv", "raw-gemv-h2") else 0,
"k_ld": k_ld,
"q_ld": q_ld,
@@ -266,15 +290,31 @@ def _run_case(
else (
f"raw_gemv_h2_split{gemv_split_k}_{case.m}x{case.n}x{case.k}"
if mode == "raw-gemv-h2"
- else f"sm70_f16_nvfp4k{group_size}_f16_tnt_fff_"
- f"{case.m}x{case.n}x{case.k}_1"
+ else (
+ f"qpn4_prefill_{case.m}x{case.n}x{case.k}"
+ if mode == "qpn4-prefill"
+ else f"sm70_f16_nvfp4k{group_size}_f16_tnt_fff_"
+ f"{case.m}x{case.n}x{case.k}_1"
+ )
)
)
),
**timing,
"weighted_mean_ms": weighted_mean_ms,
}
- del qweight, scales, tm_weight, tm_scales, qweight_packed, partials, x, out
+ del (
+ qweight,
+ scales,
+ tm_weight,
+ tm_scales,
+ qpn4_codes,
+ qpn4_scales,
+ dense_weight,
+ qweight_packed,
+ partials,
+ x,
+ out,
+ )
torch.accelerator.empty_cache()
return row
@@ -289,6 +329,7 @@ def _write_csv(path: Path, rows: list[dict[str, Any]]) -> None:
"n",
"k",
"group_size",
+ "gated_silu",
"gemv_split_k",
"k_ld",
"q_ld",
@@ -321,10 +362,21 @@ def _parse_args() -> argparse.Namespace:
)
parser.add_argument(
"--mode",
- choices=("gemm", "raw-gemv", "raw-gemv-warp", "raw-gemv-h2"),
+ choices=(
+ "gemm",
+ "qpn4-prefill",
+ "raw-gemv",
+ "raw-gemv-warp",
+ "raw-gemv-h2",
+ ),
default="gemm",
help="Operator implementation to benchmark.",
)
+ parser.add_argument(
+ "--gated-silu",
+ action="store_true",
+ help="Fuse gate/up SiLU and emit N/2 output columns.",
+ )
parser.add_argument(
"--gemv-split-k",
type=int,
@@ -351,6 +403,16 @@ def main() -> int:
raise RuntimeError("Missing _C::nvfp4_sm70_prepare.")
if not hasattr(torch.ops._C, "nvfp4_gemm_sm70_out"):
raise RuntimeError("Missing _C::nvfp4_gemm_sm70_out.")
+ if args.mode == "qpn4-prefill":
+ required_qpn4_ops = (
+ "nvfp4_qpn4_prepare_sm70",
+ "nvfp4_qpn4_dispatch_sm70_out",
+ )
+ missing_qpn4_ops = [
+ name for name in required_qpn4_ops if not hasattr(torch.ops._C, name)
+ ]
+ if missing_qpn4_ops:
+ raise RuntimeError(f"Missing QPN4 operators: {missing_qpn4_ops}.")
if args.mode == "raw-gemv" and not hasattr(torch.ops._C, "nvfp4_gemv_sm70_raw_out"):
raise RuntimeError("Missing _C::nvfp4_gemv_sm70_raw_out.")
if args.mode == "raw-gemv-warp" and not hasattr(
@@ -378,6 +440,7 @@ def main() -> int:
use_cuda_graph=args.cuda_graph,
mode=args.mode,
gemv_split_k=args.gemv_split_k,
+ gated_silu=args.gated_silu,
)
for case in cases
]
@@ -392,6 +455,7 @@ def main() -> int:
"cuda_version": torch.version.cuda,
"group_size": args.group_size,
"mode": args.mode,
+ "gated_silu": args.gated_silu,
"gemv_split_k": (
args.gemv_split_k if args.mode in ("raw-gemv", "raw-gemv-h2") else 0
),
diff --git a/benchmarks/benchmark_sm70_raw_hmma_probe.py b/benchmarks/benchmark_sm70_raw_hmma_probe.py
index a1928d4436..aec857c44d 100644
--- a/benchmarks/benchmark_sm70_raw_hmma_probe.py
+++ b/benchmarks/benchmark_sm70_raw_hmma_probe.py
@@ -32,10 +32,7 @@ def _build_binary(source: Path, verbose: bool) -> tuple[Path, list[str]]:
if nvcc is None:
raise RuntimeError("nvcc is required to build the SM70 raw HMMA probe.")
- build_dir = (
- Path(tempfile.gettempdir())
- / f"vllm-sm70-raw-hmma-probe-{os.getuid()}"
- )
+ build_dir = Path(tempfile.gettempdir()) / f"vllm-sm70-raw-hmma-probe-{os.getuid()}"
build_dir.mkdir(parents=True, exist_ok=True)
binary = build_dir / "sm70_raw_hmma_probe_sm70"
command = [
diff --git a/benchmarks/benchmark_sm70_rejection_sampler_micro.py b/benchmarks/benchmark_sm70_rejection_sampler_micro.py
index 037b70653a..ec680a82dc 100644
--- a/benchmarks/benchmark_sm70_rejection_sampler_micro.py
+++ b/benchmarks/benchmark_sm70_rejection_sampler_micro.py
@@ -174,9 +174,7 @@ def _sparse_target_topk_topp_rejection_prototype(
target_logits = sampled_logits[:num_tokens].float()
bonus_logits = sampled_logits[num_tokens:].float()
- target_topk_values, target_topk_ids = torch.topk(
- target_logits, k=top_k, dim=-1
- )
+ target_topk_values, target_topk_ids = torch.topk(target_logits, k=top_k, dim=-1)
target_topk_probs = target_topk_values.softmax(dim=-1, dtype=torch.float32)
target_remove_mask = target_topk_probs.cumsum(dim=-1) > top_p
target_remove_mask[:, 1:] = target_remove_mask[:, :-1].clone()
@@ -191,9 +189,7 @@ def _sparse_target_topk_topp_rejection_prototype(
bonus_remove_mask = bonus_topk_probs.cumsum(dim=-1) > top_p
bonus_remove_mask[:, 1:] = bonus_remove_mask[:, :-1].clone()
bonus_remove_mask[:, 0] = False
- bonus_topk_values = bonus_topk_values.masked_fill(
- bonus_remove_mask, -float("inf")
- )
+ bonus_topk_values = bonus_topk_values.masked_fill(bonus_remove_mask, -float("inf"))
bonus_topk_probs = bonus_topk_values.softmax(dim=-1, dtype=torch.float32)
draft_ids_i64 = draft_token_ids.to(torch.int64).view(-1, 1)
@@ -210,9 +206,9 @@ def _sparse_target_topk_topp_rejection_prototype(
).clamp_max(1.0)
accepted_prefix = (torch.rand_like(accept_ratio) <= accept_ratio).cumprod(0)
- residual = (
- target_topk_probs - draft_probs.gather(1, target_topk_ids)
- ).clamp_min_(0.0)
+ residual = (target_topk_probs - draft_probs.gather(1, target_topk_ids)).clamp_min_(
+ 0.0
+ )
residual_q = torch.empty_like(residual).exponential_()
recovered_offsets = (residual / residual_q).argmax(dim=-1, keepdim=True)
recovered_token_ids = target_topk_ids.gather(1, recovered_offsets).view(-1)
@@ -247,9 +243,9 @@ def _full_vocab_topk_topp_probability_reference(
k=min(top_k, probs.shape[-1]),
dim=-1,
)
- residual = (
- target_top_probs - draft_probs.gather(1, target_top_ids)
- ).clamp_min_(0.0)
+ residual = (target_top_probs - draft_probs.gather(1, target_top_ids)).clamp_min_(
+ 0.0
+ )
return target_draft_probs, target_top_ids, residual
@@ -292,9 +288,7 @@ def _compact_tp2_topk_topp_probability_prototype(
target_probs,
torch.zeros_like(target_probs),
).sum(dim=-1)
- residual = (
- target_probs - draft_probs.gather(1, target_ids)
- ).clamp_min_(0.0)
+ residual = (target_probs - draft_probs.gather(1, target_ids)).clamp_min_(0.0)
return target_draft_probs, target_ids, residual
@@ -394,9 +388,7 @@ def main() -> None:
bonus_logits_indices=torch.tensor(
[num_tokens], dtype=torch.int32, device=device
),
- logits_indices=torch.arange(
- num_tokens + 1, dtype=torch.int32, device=device
- ),
+ logits_indices=torch.arange(num_tokens + 1, dtype=torch.int32, device=device),
)
target_logits_constrained = apply_sampling_constraints(
@@ -495,9 +487,9 @@ def _set_combined_bonus(enabled: bool) -> None:
args.iters,
),
"target_prepare_with_clone": _time_cuda(
- lambda: target_prepare_base[target_prepare_indices].to(
- torch.float32
- ).clone(),
+ lambda: target_prepare_base[target_prepare_indices]
+ .to(torch.float32)
+ .clone(),
args.warmup,
args.iters,
),
diff --git a/benchmarks/benchmark_sm70_source_inventory.py b/benchmarks/benchmark_sm70_source_inventory.py
index f8b13b47fa..87c7e5f151 100644
--- a/benchmarks/benchmark_sm70_source_inventory.py
+++ b/benchmarks/benchmark_sm70_source_inventory.py
@@ -502,19 +502,14 @@ def _scan_tree(root: Path) -> dict[str, Any]:
"file_count": file_count,
"scanned_bytes": scanned_bytes,
"env_vars": {
- name: sorted(files)
- for name, files in sorted(env_to_files.items())
+ name: sorted(files) for name, files in sorted(env_to_files.items())
},
"runtime_env_vars": {
- name: sorted(files)
- for name, files in sorted(runtime_env_to_files.items())
+ name: sorted(files) for name, files in sorted(runtime_env_to_files.items())
},
"env_file_counts": dict(sorted(env_counts.items())),
"keyword_files": dict(sorted(keyword_files.items())),
- "torch_ops": {
- name: sorted(files)
- for name, files in sorted(torch_ops.items())
- },
+ "torch_ops": {name: sorted(files) for name, files in sorted(torch_ops.items())},
}
@@ -597,11 +592,11 @@ def _compact_diff(old: dict[str, Any], latest: dict[str, Any]) -> dict[str, Any]
diff["old_only_torch_op_classification"] = _classify_old_only_torch_ops(
diff["torch_ops"]["old_only"]
)
- diff["old_only_runtime_env_classification"] = (
- _classify_old_only_runtime_envs(diff["runtime_env_vars"]["old_only"])
+ diff["old_only_runtime_env_classification"] = _classify_old_only_runtime_envs(
+ diff["runtime_env_vars"]["old_only"]
)
- diff["old_only_keyword_file_classification"] = (
- _classify_old_only_keyword_files(diff["keyword_files"]["old_only"])
+ diff["old_only_keyword_file_classification"] = _classify_old_only_keyword_files(
+ diff["keyword_files"]["old_only"]
)
return diff
@@ -617,15 +612,9 @@ def _classification_counts(section: dict[str, Any]) -> dict[str, Any]:
def _inventory_gate(diff: dict[str, Any]) -> dict[str, Any]:
- runtime_env = _classification_counts(
- diff["old_only_runtime_env_classification"]
- )
- keyword_files = _classification_counts(
- diff["old_only_keyword_file_classification"]
- )
- torch_ops = _classification_counts(
- diff["old_only_torch_op_classification"]
- )
+ runtime_env = _classification_counts(diff["old_only_runtime_env_classification"])
+ keyword_files = _classification_counts(diff["old_only_keyword_file_classification"])
+ torch_ops = _classification_counts(diff["old_only_torch_op_classification"])
old_only_env_vars = diff["env_vars"]["old_only"]
complete = (
not old_only_env_vars
@@ -675,32 +664,37 @@ def main() -> int:
json.dumps(payload, indent=args.indent, sort_keys=True) + "\n",
encoding="utf-8",
)
- print(json.dumps({
- "out": str(args.out),
- "old_files": payload["old"]["file_count"],
- "latest_files": payload["latest"]["file_count"],
- "old_env_vars": len(payload["old"]["env_vars"]),
- "latest_env_vars": len(payload["latest"]["env_vars"]),
- "old_runtime_env_vars": len(payload["old"]["runtime_env_vars"]),
- "latest_runtime_env_vars": len(payload["latest"]["runtime_env_vars"]),
- "old_keyword_files": len(payload["old"]["keyword_files"]),
- "latest_keyword_files": len(payload["latest"]["keyword_files"]),
- "old_torch_ops": len(payload["old"]["torch_ops"]),
- "latest_torch_ops": len(payload["latest"]["torch_ops"]),
- "inventory_complete": payload["inventory_gate"]["complete"],
- "old_only_env_vars": payload["inventory_gate"][
- "old_only_env_vars_count"
- ],
- "old_only_runtime_env_unclassified": payload["inventory_gate"][
- "old_only_runtime_env"
- ]["unclassified_count"],
- "old_only_keyword_files_unclassified": payload["inventory_gate"][
- "old_only_keyword_files"
- ]["unclassified_count"],
- "old_only_torch_ops_unclassified": payload["inventory_gate"][
- "old_only_torch_ops"
- ]["unclassified_count"],
- }, sort_keys=True))
+ print(
+ json.dumps(
+ {
+ "out": str(args.out),
+ "old_files": payload["old"]["file_count"],
+ "latest_files": payload["latest"]["file_count"],
+ "old_env_vars": len(payload["old"]["env_vars"]),
+ "latest_env_vars": len(payload["latest"]["env_vars"]),
+ "old_runtime_env_vars": len(payload["old"]["runtime_env_vars"]),
+ "latest_runtime_env_vars": len(payload["latest"]["runtime_env_vars"]),
+ "old_keyword_files": len(payload["old"]["keyword_files"]),
+ "latest_keyword_files": len(payload["latest"]["keyword_files"]),
+ "old_torch_ops": len(payload["old"]["torch_ops"]),
+ "latest_torch_ops": len(payload["latest"]["torch_ops"]),
+ "inventory_complete": payload["inventory_gate"]["complete"],
+ "old_only_env_vars": payload["inventory_gate"][
+ "old_only_env_vars_count"
+ ],
+ "old_only_runtime_env_unclassified": payload["inventory_gate"][
+ "old_only_runtime_env"
+ ]["unclassified_count"],
+ "old_only_keyword_files_unclassified": payload["inventory_gate"][
+ "old_only_keyword_files"
+ ]["unclassified_count"],
+ "old_only_torch_ops_unclassified": payload["inventory_gate"][
+ "old_only_torch_ops"
+ ]["unclassified_count"],
+ },
+ sort_keys=True,
+ )
+ )
return 0
diff --git a/benchmarks/benchmark_sm70_tool_datasets.py b/benchmarks/benchmark_sm70_tool_datasets.py
new file mode 100644
index 0000000000..b85077ba97
--- /dev/null
+++ b/benchmarks/benchmark_sm70_tool_datasets.py
@@ -0,0 +1,546 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Run fixed ToolACE and NexusRaven function-calling samples via an API.
+
+These are deterministic dataset subsets for matched route comparisons, not
+full official leaderboard submissions. ToolACE function names are sanitized
+to the OpenAI-compatible namespace while retaining their original names in
+the descriptions and ground truth.
+"""
+
+from __future__ import annotations
+
+import argparse
+import ast
+import hashlib
+import json
+import time
+from pathlib import Path
+from typing import Any
+
+import pandas as pd
+import regex as re
+import requests
+
+TOOLACE_MARKER = "Here is a list of functions in JSON format that you can invoke:"
+SAFE_TOOL_NAME = re.compile(r"[^A-Za-z0-9_]")
+
+
+def _sha256(path: Path) -> str:
+ digest = hashlib.sha256()
+ with path.open("rb") as file:
+ for chunk in iter(lambda: file.read(1024 * 1024), b""):
+ digest.update(chunk)
+ return digest.hexdigest()
+
+
+def _post_chat(base_url: str, payload: dict[str, Any]) -> dict[str, Any]:
+ started = time.perf_counter()
+ response = requests.post(
+ f"{base_url.rstrip('/')}/v1/chat/completions",
+ json=payload,
+ timeout=600,
+ )
+ if response.status_code != 200:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+ try:
+ body = response.json()
+ except requests.JSONDecodeError as exc:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "error": str(exc),
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+ choice = body.get("choices", [{}])[0]
+ message = choice.get("message") or {}
+ return {
+ "ok": True,
+ "status_code": response.status_code,
+ "elapsed_seconds": time.perf_counter() - started,
+ "finish_reason": choice.get("finish_reason"),
+ "content": message.get("content") or "",
+ "reasoning_content": message.get("reasoning_content") or "",
+ "prompt_token_ids": body.get("prompt_token_ids") or [],
+ "output_token_ids": choice.get("token_ids") or [],
+ "tool_calls": message.get("tool_calls") or [],
+ "raw_response": body,
+ }
+
+
+def _canonical_calls(result: dict[str, Any]) -> tuple[list[dict[str, Any]], list[str]]:
+ calls: list[dict[str, Any]] = []
+ errors: list[str] = []
+ for call in result.get("tool_calls") or []:
+ function = call.get("function") or {}
+ try:
+ arguments = json.loads(function.get("arguments") or "")
+ except (TypeError, json.JSONDecodeError) as exc:
+ errors.append(f"invalid arguments JSON: {exc}")
+ continue
+ calls.append({"name": function.get("name") or "", "arguments": arguments})
+ return calls, errors
+
+
+def _normalize_schema(value: Any) -> Any:
+ if isinstance(value, list):
+ return [_normalize_schema(item) for item in value]
+ if not isinstance(value, dict):
+ return value
+ normalized = {key: _normalize_schema(item) for key, item in value.items()}
+ type_map = {
+ "dict": "object",
+ "float": "number",
+ "tuple": "array",
+ "any": None,
+ "None": None,
+ }
+ schema_type = normalized.get("type")
+ if isinstance(schema_type, str) and schema_type in type_map:
+ mapped = type_map[schema_type]
+ if mapped is None:
+ normalized.pop("type")
+ else:
+ normalized["type"] = mapped
+ return normalized
+
+
+def _stratified(items: list[Any], count: int, *, key) -> list[Any]:
+ items = sorted(items, key=key)
+ if len(items) <= count:
+ return items
+ if count == 1:
+ return [items[len(items) // 2]]
+ return [
+ items[round(index * (len(items) - 1) / (count - 1))] for index in range(count)
+ ]
+
+
+def _split_top_level(text: str) -> list[str]:
+ pieces: list[str] = []
+ start = 0
+ depth = 0
+ quote: str | None = None
+ escaped = False
+ for index, character in enumerate(text):
+ if quote is not None:
+ if escaped:
+ escaped = False
+ elif character == "\\":
+ escaped = True
+ elif character == quote:
+ quote = None
+ elif character in {'"', "'"}:
+ quote = character
+ elif character in "([{":
+ depth += 1
+ elif character in ")]}" and depth:
+ depth -= 1
+ elif character == "," and depth == 0:
+ pieces.append(text[start:index].strip())
+ start = index + 1
+ pieces.append(text[start:].strip())
+ return [piece for piece in pieces if piece]
+
+
+def _toolace_functions(record: dict[str, Any]) -> list[dict[str, Any]] | None:
+ system = record.get("system") or ""
+ marker = system.find(TOOLACE_MARKER)
+ if marker == -1:
+ return None
+ start = system.find("[", marker + len(TOOLACE_MARKER))
+ if start == -1:
+ return None
+ try:
+ functions = json.JSONDecoder().raw_decode(system[start:])[0]
+ except (TypeError, json.JSONDecodeError):
+ return None
+ if not isinstance(functions, list) or not all(
+ isinstance(function, dict)
+ and isinstance(function.get("name"), str)
+ and isinstance(function.get("parameters"), dict)
+ for function in functions
+ ):
+ return None
+ return functions
+
+
+def _parse_toolace_calls(
+ answer: str, function_names: list[str]
+) -> list[dict[str, Any]] | None:
+ answer = answer.strip()
+ if not answer.startswith("[") or not answer.endswith("]"):
+ return None
+ body = answer[1:-1].strip()
+ if not body:
+ return []
+ calls: list[dict[str, Any]] = []
+ for piece in _split_top_level(body):
+ names = [
+ name
+ for name in function_names
+ if piece.startswith(f"{name}(") and piece.endswith(")")
+ ]
+ if not names:
+ return None
+ name = max(names, key=len)
+ argument_text = piece[len(name) + 1 : -1]
+ try:
+ call = ast.parse(f"f({argument_text})", mode="eval").body
+ if not isinstance(call, ast.Call) or call.args:
+ return None
+ arguments = {
+ keyword.arg: ast.literal_eval(keyword.value)
+ for keyword in call.keywords
+ if keyword.arg is not None
+ }
+ except (SyntaxError, ValueError):
+ return None
+ calls.append({"name": name, "arguments": arguments})
+ return calls
+
+
+def _clear_no_tool_answer(answer: str, functions: list[dict[str, Any]]) -> bool:
+ if not functions:
+ return True
+ lowered = answer.lower()
+ signatures = (
+ "no available function",
+ "no available functions",
+ "lacks the required",
+ "lacks the parameter",
+ "please provide",
+ "provide further",
+ "additional information",
+ "not enough information",
+ )
+ return any(signature in lowered for signature in signatures)
+
+
+def _safe_tool_names(
+ functions: list[dict[str, Any]],
+) -> tuple[list[dict[str, Any]], dict[str, str]]:
+ tools: list[dict[str, Any]] = []
+ name_map: dict[str, str] = {}
+ used: set[str] = set()
+ for index, function in enumerate(functions):
+ slug = SAFE_TOOL_NAME.sub("_", function["name"]).strip("_") or "function"
+ safe_name = f"tool_{index}_{slug}"[:64]
+ while safe_name in used:
+ safe_name = f"tool_{index}_{slug}_{len(used)}"[:64]
+ used.add(safe_name)
+ name_map[function["name"]] = safe_name
+ tools.append(
+ {
+ "type": "function",
+ "function": {
+ "name": safe_name,
+ "description": (
+ f"Original tool name: {function['name']}. "
+ f"{function.get('description') or ''}"
+ ),
+ "parameters": _normalize_schema(function["parameters"]),
+ },
+ }
+ )
+ return tools, name_map
+
+
+def _run_toolace(
+ base_url: str,
+ model: str,
+ seed: int,
+ path: Path,
+ per_bucket: int,
+) -> dict[str, Any]:
+ records = json.loads(path.read_text())
+ buckets: dict[str, list[dict[str, Any]]] = {
+ "single": [],
+ "parallel": [],
+ "no_tool": [],
+ }
+ for index, record in enumerate(records):
+ conversations = record.get("conversations") or []
+ if len(conversations) != 2 or conversations[0].get("from") != "user":
+ continue
+ functions = _toolace_functions(record)
+ if functions is None:
+ continue
+ answer = conversations[1].get("value") or ""
+ calls = _parse_toolace_calls(answer, [item["name"] for item in functions])
+ if calls is not None and calls:
+ bucket = "parallel" if len(calls) > 1 else "single"
+ elif _clear_no_tool_answer(answer, functions):
+ bucket = "no_tool"
+ calls = []
+ else:
+ continue
+ buckets[bucket].append(
+ {
+ "index": index,
+ "prompt": conversations[0]["value"],
+ "functions": functions,
+ "expected": calls,
+ "system_length": len(record.get("system") or ""),
+ }
+ )
+
+ results_by_bucket: dict[str, Any] = {}
+ for bucket, candidates in buckets.items():
+ selected = _stratified(
+ candidates,
+ per_bucket,
+ key=lambda item: (item["system_length"], item["index"]),
+ )
+ results: list[dict[str, Any]] = []
+ for case in selected:
+ tools, name_map = _safe_tool_names(case["functions"])
+ expected = [
+ {"name": name_map[call["name"]], "arguments": call["arguments"]}
+ for call in case["expected"]
+ ]
+ payload = {
+ "model": model,
+ "messages": [{"role": "user", "content": case["prompt"]}],
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 1024,
+ "return_token_ids": True,
+ "chat_template_kwargs": {"enable_thinking": False},
+ }
+ if tools:
+ payload.update(
+ {
+ "tools": tools,
+ "tool_choice": "auto",
+ "parallel_tool_calls": True,
+ }
+ )
+ result = _post_chat(base_url, payload)
+ actual, errors = _canonical_calls(result)
+ if result.get("ok") and actual != expected:
+ errors.append(f"calls {actual!r} != {expected!r}")
+ elif not result.get("ok"):
+ errors.append("request failed")
+ result.update(
+ {
+ "index": case["index"],
+ "expected": expected,
+ "actual": actual,
+ "errors": errors,
+ }
+ )
+ results.append(result)
+ results_by_bucket[bucket] = {
+ "score": sum(not result["errors"] for result in results),
+ "total": len(results),
+ "cases": results,
+ }
+ score = sum(item["score"] for item in results_by_bucket.values())
+ total = sum(item["total"] for item in results_by_bucket.values())
+ return {
+ "score": score,
+ "total": total,
+ "protocol_passed": all(
+ case.get("ok")
+ for bucket in results_by_bucket.values()
+ for case in bucket["cases"]
+ ),
+ "per_bucket": results_by_bucket,
+ "note": "Fixed ToolACE subset with OpenAI-safe function-name mapping.",
+ }
+
+
+def _nexus_tool(function: dict[str, Any]) -> dict[str, Any]:
+ json_types = {
+ "str": "string",
+ "int": "integer",
+ "list": "array",
+ "dict": "object",
+ }
+ properties: dict[str, Any] = {}
+ required: list[str] = []
+ for argument in function["args_dicts"]:
+ properties[argument["name"]] = {
+ "description": argument.get("description") or ""
+ }
+ if json_type := json_types.get(str(argument.get("type"))):
+ properties[argument["name"]]["type"] = json_type
+ if argument.get("required"):
+ required.append(argument["name"])
+ return {
+ "type": "function",
+ "function": {
+ "name": function["name"],
+ "description": function.get("description") or "",
+ "parameters": {
+ "type": "object",
+ "properties": properties,
+ "required": required,
+ "additionalProperties": False,
+ },
+ },
+ }
+
+
+def _run_nexus(
+ base_url: str,
+ model: str,
+ seed: int,
+ queries_path: Path,
+ api_path: Path,
+ per_domain: int,
+) -> dict[str, Any]:
+ queries = pd.read_parquet(queries_path)
+ functions = pd.read_parquet(api_path)
+ function_map = {
+ (row["dataset"], row["name"]): row for row in functions.to_dict("records")
+ }
+ domain_results: dict[str, Any] = {}
+ for domain in sorted(queries["dataset"].unique()):
+ records = queries[queries["dataset"] == domain].to_dict("records")
+ selected = _stratified(
+ list(enumerate(records)),
+ per_domain,
+ key=lambda item: (len(item[1]["prompt"]), item[0]),
+ )
+ results: list[dict[str, Any]] = []
+ for dataset_index, record in selected:
+ tools = [
+ _nexus_tool(function_map[(domain, name)])
+ for name in record["context_functions"]
+ ]
+ expected = [
+ {
+ "name": record["python_function_name"],
+ "arguments": json.loads(record["python_args_dict"]),
+ }
+ ]
+ result = _post_chat(
+ base_url,
+ {
+ "model": model,
+ "messages": [{"role": "user", "content": record["prompt"]}],
+ "tools": tools,
+ "tool_choice": "auto",
+ "parallel_tool_calls": False,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 1024,
+ "return_token_ids": True,
+ "chat_template_kwargs": {"enable_thinking": False},
+ },
+ )
+ actual, errors = _canonical_calls(result)
+ if result.get("ok") and actual != expected:
+ errors.append(f"calls {actual!r} != {expected!r}")
+ elif not result.get("ok"):
+ errors.append("request failed")
+ result.update(
+ {
+ "dataset_index": dataset_index,
+ "prompt": record["prompt"],
+ "expected": expected,
+ "actual": actual,
+ "errors": errors,
+ }
+ )
+ results.append(result)
+ domain_results[domain] = {
+ "score": sum(not result["errors"] for result in results),
+ "total": len(results),
+ "cases": results,
+ }
+ score = sum(item["score"] for item in domain_results.values())
+ total = sum(item["total"] for item in domain_results.values())
+ return {
+ "score": score,
+ "total": total,
+ "protocol_passed": all(
+ case.get("ok")
+ for domain in domain_results.values()
+ for case in domain["cases"]
+ ),
+ "per_domain": domain_results,
+ "note": "Fixed NexusRaven API evaluation subset; exact call/argument match.",
+ }
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--base-url", required=True)
+ parser.add_argument("--model", default="quality-audit-dflash2")
+ parser.add_argument("--seed", type=int, default=20260827)
+ parser.add_argument("--out", type=Path, required=True)
+ parser.add_argument("--toolace-data", type=Path, required=True)
+ parser.add_argument("--toolace-per-bucket", type=int, default=4)
+ parser.add_argument("--nexus-queries", type=Path, required=True)
+ parser.add_argument("--nexus-api-list", type=Path, required=True)
+ parser.add_argument("--nexus-per-domain", type=int, default=4)
+ args = parser.parse_args()
+
+ artifact = {
+ "base_url": args.base_url,
+ "model": args.model,
+ "seed": args.seed,
+ "sources": {
+ "toolace": {
+ "path": str(args.toolace_data),
+ "sha256": _sha256(args.toolace_data),
+ },
+ "nexus_queries": {
+ "path": str(args.nexus_queries),
+ "sha256": _sha256(args.nexus_queries),
+ },
+ "nexus_api_list": {
+ "path": str(args.nexus_api_list),
+ "sha256": _sha256(args.nexus_api_list),
+ },
+ },
+ "toolace": _run_toolace(
+ args.base_url,
+ args.model,
+ args.seed,
+ args.toolace_data,
+ args.toolace_per_bucket,
+ ),
+ "nexus_raven": _run_nexus(
+ args.base_url,
+ args.model,
+ args.seed,
+ args.nexus_queries,
+ args.nexus_api_list,
+ args.nexus_per_domain,
+ ),
+ }
+ artifact["protocol_passed"] = bool(
+ artifact["toolace"]["protocol_passed"]
+ and artifact["nexus_raven"]["protocol_passed"]
+ )
+ args.out.parent.mkdir(parents=True, exist_ok=True)
+ args.out.write_text(json.dumps(artifact, ensure_ascii=False, indent=2) + "\n")
+ print(
+ json.dumps(
+ {
+ "protocol_passed": artifact["protocol_passed"],
+ "toolace": [artifact["toolace"]["score"], artifact["toolace"]["total"]],
+ "nexus_raven": [
+ artifact["nexus_raven"]["score"],
+ artifact["nexus_raven"]["total"],
+ ],
+ "out": str(args.out),
+ }
+ )
+ )
+ if not artifact["protocol_passed"]:
+ raise SystemExit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/benchmark_sm70_tool_protocol.py b/benchmarks/benchmark_sm70_tool_protocol.py
new file mode 100644
index 0000000000..b7cccb1425
--- /dev/null
+++ b/benchmarks/benchmark_sm70_tool_protocol.py
@@ -0,0 +1,1291 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Exercise long, streamed tool calls and structured output through an API.
+
+This is a deterministic protocol gate, not a substitute for BFCL task scores.
+It catches malformed streamed arguments, invalid tool names, history replay
+failures, and JSON-schema violations while retaining the raw SSE events needed
+to localize a first divergence between two server configurations.
+"""
+
+from __future__ import annotations
+
+import argparse
+import copy
+import json
+import time
+from pathlib import Path
+from typing import Any
+
+import jsonschema
+import regex as re
+import requests
+
+TOOLS: list[dict[str, Any]] = [
+ {
+ "type": "function",
+ "function": {
+ "name": "Read",
+ "description": "Read a UTF-8 file.",
+ "parameters": {
+ "type": "object",
+ "properties": {"file_path": {"type": "string"}},
+ "required": ["file_path"],
+ "additionalProperties": False,
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "Grep",
+ "description": "Search files for a literal pattern.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "pattern": {"type": "string"},
+ "path": {"type": "string"},
+ "output_mode": {
+ "type": "string",
+ "enum": ["content", "files_with_matches", "count"],
+ },
+ },
+ "required": ["pattern", "path", "output_mode"],
+ "additionalProperties": False,
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "Glob",
+ "description": "Find files matching a glob pattern.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "pattern": {"type": "string"},
+ "path": {"type": "string"},
+ },
+ "required": ["pattern", "path"],
+ "additionalProperties": False,
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "Bash",
+ "description": "Run one shell command.",
+ "parameters": {
+ "type": "object",
+ "properties": {"command": {"type": "string"}},
+ "required": ["command"],
+ "additionalProperties": False,
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "Edit",
+ "description": "Replace an exact string in a file.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "file_path": {"type": "string"},
+ "old_string": {"type": "string"},
+ "new_string": {"type": "string"},
+ "replace_all": {"type": "boolean"},
+ },
+ "required": [
+ "file_path",
+ "old_string",
+ "new_string",
+ "replace_all",
+ ],
+ "additionalProperties": False,
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "Write",
+ "description": "Write complete UTF-8 content to a file.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "file_path": {"type": "string"},
+ "content": {"type": "string"},
+ },
+ "required": ["file_path", "content"],
+ "additionalProperties": False,
+ },
+ },
+ },
+]
+
+
+STEPS: list[dict[str, Any]] = [
+ {
+ "name": "Read",
+ "prompt": "Call Read for /tmp/project/src/app.py. Do not call another tool.",
+ "arguments": {"file_path": "/tmp/project/src/app.py"},
+ "result": "def run():\n return 1\n",
+ },
+ {
+ "name": "Grep",
+ "prompt": (
+ "Call Grep for literal pattern run in /tmp/project/src with "
+ "output_mode=count. Do not call another tool."
+ ),
+ "arguments": {
+ "pattern": "run",
+ "path": "/tmp/project/src",
+ "output_mode": "count",
+ },
+ "result": "/tmp/project/src/app.py:1",
+ },
+ {
+ "name": "Glob",
+ "prompt": (
+ "Call Glob with pattern **/*.py under /tmp/project. "
+ "Do not call another tool."
+ ),
+ "arguments": {"pattern": "**/*.py", "path": "/tmp/project"},
+ "result": "/tmp/project/src/app.py",
+ },
+ {
+ "name": "Bash",
+ "prompt": (
+ "Call Bash with exactly: python -m pytest -q. Do not call another tool."
+ ),
+ "arguments": {"command": "python -m pytest -q"},
+ "result": "8 passed in 1.20s",
+ },
+ {
+ "name": "Edit",
+ "prompt": (
+ "Call Edit on /tmp/project/src/app.py. Replace exactly the string "
+ "` return 1\\n` with ` return 2\\n`, and set replace_all=false. "
+ "Preserve all indentation and newlines."
+ ),
+ "arguments": {
+ "file_path": "/tmp/project/src/app.py",
+ "old_string": " return 1\n",
+ "new_string": " return 2\n",
+ "replace_all": False,
+ },
+ "result": "updated /tmp/project/src/app.py",
+ },
+ {
+ "name": "Write",
+ "prompt": (
+ "Call Write for /tmp/project/result.json with exactly this content: "
+ '{"ok":true,"lines":["a\\nb","literal"]}.'
+ ),
+ "arguments": {
+ "file_path": "/tmp/project/result.json",
+ "content": '{"ok":true,"lines":["a\\nb","literal"]}',
+ },
+ "result": "wrote 55 bytes",
+ },
+]
+
+
+STRUCTURED_CASES: list[dict[str, Any]] = [
+ {
+ "name": "nested",
+ "prompt": (
+ "Return the build record for project alpha, successful, with stages "
+ "compile=12 and test=8."
+ ),
+ "schema": {
+ "type": "object",
+ "properties": {
+ "project": {"type": "string", "const": "alpha"},
+ "success": {"type": "boolean", "const": True},
+ "stages": {
+ "type": "array",
+ "prefixItems": [
+ {
+ "type": "object",
+ "properties": {
+ "name": {"const": "compile"},
+ "seconds": {"type": "integer", "const": 12},
+ },
+ "required": ["name", "seconds"],
+ "additionalProperties": False,
+ },
+ {
+ "type": "object",
+ "properties": {
+ "name": {"const": "test"},
+ "seconds": {"type": "integer", "const": 8},
+ },
+ "required": ["name", "seconds"],
+ "additionalProperties": False,
+ },
+ ],
+ "minItems": 2,
+ "maxItems": 2,
+ },
+ },
+ "required": ["project", "success", "stages"],
+ "additionalProperties": False,
+ },
+ },
+ {
+ "name": "escaped_text",
+ "prompt": "Return path /tmp/a, the two-line text `a\\nb`, and count 2.",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "path": {"type": "string", "const": "/tmp/a"},
+ "text": {"type": "string", "const": "a\nb"},
+ "count": {"type": "integer", "const": 2},
+ },
+ "required": ["path", "text", "count"],
+ "additionalProperties": False,
+ },
+ },
+]
+
+
+STREAM_PARITY_CASES: list[dict[str, str]] = [
+ {
+ "name": "quoted_ascii",
+ "expected": 'The "implied" volatility is a "forward-looking" measure.',
+ },
+ {
+ "name": "json_utf8",
+ "expected": '{"path":"/tmp/中.txt","text":"a\\nb","emoji":"🌶️"}',
+ },
+]
+
+
+def _schema_by_tool_name() -> dict[str, dict[str, Any]]:
+ return {item["function"]["name"]: item["function"]["parameters"] for item in TOOLS}
+
+
+def _stream_chat(base_url: str, payload: dict[str, Any]) -> dict[str, Any]:
+ started = time.perf_counter()
+ response = requests.post(
+ f"{base_url.rstrip('/')}/v1/chat/completions",
+ json=payload,
+ stream=True,
+ timeout=600,
+ )
+ if response.status_code != 200:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+
+ raw_events: list[dict[str, Any]] = []
+ prompt_token_ids: list[int] = []
+ output_token_ids: list[int] = []
+ output_token_chunks: list[list[int]] = []
+ content = ""
+ reasoning = ""
+ finish_reason = None
+ calls: dict[int, dict[str, Any]] = {}
+ malformed_sse: list[str] = []
+ for raw_line in response.iter_lines(decode_unicode=True):
+ if not raw_line or not raw_line.startswith("data:"):
+ continue
+ data = raw_line[5:].strip()
+ if data == "[DONE]":
+ break
+ try:
+ event = json.loads(data)
+ except json.JSONDecodeError:
+ malformed_sse.append(data)
+ continue
+ raw_events.append(event)
+ choice = event.get("choices", [{}])[0]
+ if event.get("prompt_token_ids"):
+ prompt_token_ids.extend(event["prompt_token_ids"])
+ token_ids = choice.get("token_ids") or []
+ if token_ids:
+ output_token_chunks.append(token_ids)
+ output_token_ids.extend(token_ids)
+ finish_reason = choice.get("finish_reason") or finish_reason
+ delta = choice.get("delta") or {}
+ content += delta.get("content") or ""
+ reasoning += delta.get("reasoning_content") or ""
+ for call_delta in delta.get("tool_calls") or []:
+ index = int(call_delta.get("index", 0))
+ call = calls.setdefault(
+ index,
+ {
+ "id": "",
+ "type": "function",
+ "function": {"name": "", "arguments": ""},
+ },
+ )
+ call["id"] += call_delta.get("id") or ""
+ function = call_delta.get("function") or {}
+ call["function"]["name"] += function.get("name") or ""
+ call["function"]["arguments"] += function.get("arguments") or ""
+
+ return {
+ "ok": not malformed_sse,
+ "status_code": response.status_code,
+ "elapsed_seconds": time.perf_counter() - started,
+ "finish_reason": finish_reason,
+ "content": content,
+ "reasoning_content": reasoning,
+ "prompt_token_ids": prompt_token_ids,
+ "output_token_ids": output_token_ids,
+ "output_token_chunks": output_token_chunks,
+ "tool_calls": [calls[index] for index in sorted(calls)],
+ "malformed_sse": malformed_sse,
+ "raw_events": raw_events,
+ }
+
+
+def _nonstream_chat(base_url: str, payload: dict[str, Any]) -> dict[str, Any]:
+ started = time.perf_counter()
+ response = requests.post(
+ f"{base_url.rstrip('/')}/v1/chat/completions",
+ json=payload,
+ timeout=600,
+ )
+ if response.status_code != 200:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+ try:
+ body = response.json()
+ except requests.JSONDecodeError as exc:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "error": str(exc),
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+ choice = body.get("choices", [{}])[0]
+ message = choice.get("message") or {}
+ return {
+ "ok": True,
+ "status_code": response.status_code,
+ "elapsed_seconds": time.perf_counter() - started,
+ "finish_reason": choice.get("finish_reason"),
+ "content": message.get("content") or "",
+ "reasoning_content": message.get("reasoning_content") or "",
+ "prompt_token_ids": body.get("prompt_token_ids") or [],
+ "output_token_ids": choice.get("token_ids") or [],
+ "tool_calls": message.get("tool_calls") or [],
+ "raw_response": body,
+ }
+
+
+def _responses_tools() -> list[dict[str, Any]]:
+ tools: list[dict[str, Any]] = []
+ for tool in TOOLS:
+ function = tool["function"]
+ tools.append(
+ {
+ "type": "function",
+ "name": function["name"],
+ "description": function["description"],
+ "parameters": function["parameters"],
+ "strict": True,
+ }
+ )
+ return tools
+
+
+def _stream_responses(base_url: str, payload: dict[str, Any]) -> dict[str, Any]:
+ """Collect Responses SSE without relying on a particular SDK version."""
+ started = time.perf_counter()
+ response = requests.post(
+ f"{base_url.rstrip('/')}/v1/responses",
+ json=payload,
+ stream=True,
+ timeout=600,
+ )
+ if response.status_code != 200:
+ return {
+ "ok": False,
+ "status_code": response.status_code,
+ "body": response.text,
+ "elapsed_seconds": time.perf_counter() - started,
+ }
+
+ raw_events: list[dict[str, Any]] = []
+ malformed_sse: list[str] = []
+ response_id = ""
+ response_status = ""
+ output_text_chunks: list[str] = []
+ protocol_errors: list[str] = []
+ calls: dict[int, dict[str, Any]] = {}
+
+ for raw_line in response.iter_lines(decode_unicode=True):
+ if not raw_line or not raw_line.startswith("data:"):
+ continue
+ data = raw_line[5:].strip()
+ if data == "[DONE]":
+ break
+ try:
+ event = json.loads(data)
+ except json.JSONDecodeError:
+ malformed_sse.append(data)
+ continue
+ raw_events.append(event)
+ event_type = event.get("type") or ""
+ event_response = event.get("response") or {}
+ response_id = event_response.get("id") or response_id
+ response_status = event_response.get("status") or response_status
+
+ if event_type == "response.output_text.delta":
+ output_text_chunks.append(event.get("delta") or "")
+ elif event_type == "response.output_item.added":
+ item = event.get("item") or {}
+ if item.get("type") == "function_call":
+ output_index = int(event.get("output_index", 0))
+ calls[output_index] = {
+ "output_index": output_index,
+ "added_item": item,
+ "argument_chunks": [],
+ "done_arguments": None,
+ "done_item": None,
+ }
+ elif event_type == "response.function_call_arguments.delta":
+ output_index = int(event.get("output_index", 0))
+ call = calls.get(output_index)
+ if call is None:
+ protocol_errors.append(
+ f"arguments delta before item at output {output_index}"
+ )
+ else:
+ call["argument_chunks"].append(event.get("delta") or "")
+ elif event_type == "response.function_call_arguments.done":
+ output_index = int(event.get("output_index", 0))
+ call = calls.get(output_index)
+ if call is None:
+ protocol_errors.append(
+ f"arguments done before item at output {output_index}"
+ )
+ else:
+ call["done_arguments"] = event.get("arguments") or ""
+ elif event_type == "response.output_item.done":
+ item = event.get("item") or {}
+ if item.get("type") == "function_call":
+ output_index = int(event.get("output_index", 0))
+ call = calls.get(output_index)
+ if call is None:
+ protocol_errors.append(
+ f"item done before item added at output {output_index}"
+ )
+ else:
+ call["done_item"] = item
+ elif event_type in {"response.failed", "error"}:
+ protocol_errors.append(json.dumps(event, ensure_ascii=False))
+
+ function_calls: list[dict[str, Any]] = []
+ for output_index in sorted(calls):
+ record = calls[output_index]
+ added = record["added_item"]
+ done = record["done_item"] or {}
+ delta_arguments = "".join(record["argument_chunks"])
+ done_arguments = record["done_arguments"]
+ final_arguments = done.get("arguments")
+ if final_arguments is None:
+ final_arguments = done_arguments
+ if final_arguments is None:
+ final_arguments = delta_arguments or added.get("arguments") or ""
+
+ if done_arguments is not None and done_arguments != delta_arguments:
+ protocol_errors.append(
+ f"arguments delta/done mismatch at output {output_index}"
+ )
+ if done and done.get("arguments") != final_arguments:
+ protocol_errors.append(
+ f"arguments done/item mismatch at output {output_index}"
+ )
+ if done and done.get("name") != added.get("name"):
+ protocol_errors.append(f"tool name changed at output {output_index}")
+
+ function_calls.append(
+ {
+ "output_index": output_index,
+ "id": done.get("id") or added.get("id") or "",
+ "call_id": done.get("call_id") or added.get("call_id") or "",
+ "name": done.get("name") or added.get("name") or "",
+ "arguments": final_arguments,
+ "argument_chunks": record["argument_chunks"],
+ "done_arguments": done_arguments,
+ "added_item": added,
+ "done_item": record["done_item"],
+ }
+ )
+
+ completed = any(event.get("type") == "response.completed" for event in raw_events)
+ if not completed:
+ protocol_errors.append("response.completed event missing")
+ return {
+ "ok": not malformed_sse and not protocol_errors,
+ "status_code": response.status_code,
+ "elapsed_seconds": time.perf_counter() - started,
+ "response_id": response_id,
+ "response_status": response_status,
+ "output_text": "".join(output_text_chunks),
+ "function_calls": function_calls,
+ "malformed_sse": malformed_sse,
+ "protocol_errors": protocol_errors,
+ "raw_events": raw_events,
+ }
+
+
+def _validate_responses_tool_step(
+ result: dict[str, Any], expected: dict[str, Any]
+) -> list[str]:
+ if not result.get("ok"):
+ return ["request failed"]
+ calls = result.get("function_calls") or []
+ if len(calls) != 1:
+ return [f"expected one function call, got {len(calls)}"]
+ call = calls[0]
+ errors: list[str] = []
+ if call["name"] != expected["name"]:
+ errors.append(f"tool name {call['name']!r} != {expected['name']!r}")
+ if not call.get("call_id"):
+ errors.append("call_id missing")
+ try:
+ arguments = json.loads(call["arguments"])
+ except json.JSONDecodeError as exc:
+ return errors + [f"invalid arguments JSON: {exc}"]
+ schema = _schema_by_tool_name().get(call["name"])
+ if schema is None:
+ errors.append(f"unknown tool {call['name']!r}")
+ else:
+ try:
+ jsonschema.validate(arguments, schema)
+ except jsonschema.ValidationError as exc:
+ errors.append(f"schema violation: {exc.message}")
+ if arguments != expected["arguments"]:
+ errors.append(f"arguments {arguments!r} != {expected['arguments']!r}")
+ return errors
+
+
+def _responses_payload(
+ model: str,
+ seed: int,
+ input_items: str | list[dict[str, Any]],
+ tool_name: str,
+ *,
+ previous_response_id: str | None = None,
+) -> dict[str, Any]:
+ payload: dict[str, Any] = {
+ "model": model,
+ "input": input_items,
+ "instructions": (
+ "Follow the user literally, call exactly the requested listed tool, "
+ "and preserve every string byte including whitespace and XML-like text."
+ ),
+ "tools": _responses_tools(),
+ "tool_choice": {"type": "function", "name": tool_name},
+ "parallel_tool_calls": False,
+ "stream": True,
+ "store": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_output_tokens": 2048,
+ "chat_template_kwargs": {"enable_thinking": False},
+ }
+ if previous_response_id is not None:
+ payload["previous_response_id"] = previous_response_id
+ return payload
+
+
+def _run_responses_chain(base_url: str, model: str, seed: int) -> dict[str, Any]:
+ """Cover stateful and explicit-history Responses tool protocols."""
+ stateful_steps = [*STEPS, STEPS[0]]
+ stateful_results: list[dict[str, Any]] = []
+ previous_response_id: str | None = None
+ previous_call_id = ""
+ previous_result = ""
+ for step_index, step in enumerate(stateful_steps):
+ if previous_response_id is None:
+ input_items: str | list[dict[str, Any]] = step["prompt"]
+ else:
+ input_items = [
+ {
+ "type": "function_call_output",
+ "call_id": previous_call_id,
+ "output": previous_result,
+ },
+ {"role": "user", "content": step["prompt"]},
+ ]
+ payload = _responses_payload(
+ model,
+ seed,
+ input_items,
+ step["name"],
+ previous_response_id=previous_response_id,
+ )
+ result = _stream_responses(base_url, payload)
+ errors = _validate_responses_tool_step(result, step)
+ result["step"] = step_index
+ result["expected_name"] = step["name"]
+ result["errors"] = errors
+ stateful_results.append(result)
+ if errors:
+ break
+ previous_response_id = result["response_id"]
+ previous_call_id = result["function_calls"][0]["call_id"]
+ previous_result = step["result"]
+
+ explicit_input: list[dict[str, Any]] = []
+ for step_index, step in enumerate(STEPS):
+ call_id = f"call_explicit_history_{step_index}"
+ explicit_input.extend(
+ [
+ {"role": "user", "content": step["prompt"]},
+ {
+ "type": "function_call",
+ "call_id": call_id,
+ "name": step["name"],
+ "arguments": json.dumps(
+ step["arguments"], ensure_ascii=False, separators=(",", ":")
+ ),
+ },
+ {
+ "type": "function_call_output",
+ "call_id": call_id,
+ "output": step["result"],
+ },
+ ]
+ )
+ replay_step = STEPS[0]
+ explicit_input.append({"role": "user", "content": replay_step["prompt"]})
+ explicit_result = _stream_responses(
+ base_url,
+ _responses_payload(
+ model,
+ seed,
+ explicit_input,
+ replay_step["name"],
+ ),
+ )
+ explicit_errors = _validate_responses_tool_step(explicit_result, replay_step)
+ explicit_result["errors"] = explicit_errors
+
+ return {
+ "passed": (
+ len(stateful_results) == len(stateful_steps)
+ and all(not item["errors"] for item in stateful_results)
+ and not explicit_errors
+ ),
+ "stateful_steps": stateful_results,
+ "explicit_history_replay": explicit_result,
+ }
+
+
+def _read_jsonl(path: Path) -> list[dict[str, Any]]:
+ return [json.loads(line) for line in path.read_text().splitlines() if line]
+
+
+def _normalize_bfcl_schema(value: Any) -> Any:
+ if isinstance(value, list):
+ return [_normalize_bfcl_schema(item) for item in value]
+ if not isinstance(value, dict):
+ return value
+ normalized = {key: _normalize_bfcl_schema(item) for key, item in value.items()}
+ type_map = {"dict": "object", "float": "number", "tuple": "array"}
+ if isinstance(normalized.get("type"), str):
+ normalized["type"] = type_map.get(normalized["type"], normalized["type"])
+ return normalized
+
+
+def _bfcl_tools(functions: list[dict[str, Any]]) -> list[dict[str, Any]]:
+ return [
+ {
+ "type": "function",
+ "function": {
+ "name": function["name"],
+ "description": function.get("description") or "",
+ "parameters": _normalize_bfcl_schema(function["parameters"]),
+ },
+ }
+ for function in functions
+ ]
+
+
+def _bfcl_normalized_value(value: Any) -> Any:
+ if isinstance(value, str):
+ return re.sub(r"[ ,./\-_*^]", "", value).lower().replace("'", '"')
+ if isinstance(value, list):
+ return [_bfcl_normalized_value(item) for item in value]
+ if isinstance(value, dict):
+ return {
+ key: _bfcl_normalized_value(item) for key, item in sorted(value.items())
+ }
+ return value
+
+
+def _bfcl_call_matches(
+ actual: dict[str, Any],
+ expected: dict[str, Any],
+ functions: dict[str, dict[str, Any]],
+) -> tuple[bool, str]:
+ expected_name, expected_arguments = next(iter(expected.items()))
+ if actual.get("name") != expected_name:
+ return False, f"tool name {actual.get('name')!r} != {expected_name!r}"
+ arguments = actual.get("arguments")
+ if not isinstance(arguments, dict):
+ return False, "arguments are not a JSON object"
+ function = functions.get(expected_name)
+ if function is None:
+ return False, f"function description missing for {expected_name!r}"
+ properties = function["parameters"].get("properties") or {}
+ required = function["parameters"].get("required") or []
+ for name in required:
+ if name not in arguments:
+ return False, f"required argument {name!r} missing"
+ for name, value in arguments.items():
+ if name not in properties or name not in expected_arguments:
+ return False, f"unexpected argument {name!r}"
+ allowed = expected_arguments[name]
+ if not any(
+ _bfcl_normalized_value(value) == _bfcl_normalized_value(candidate)
+ for candidate in allowed
+ ):
+ return False, f"argument {name!r} value {value!r} not in {allowed!r}"
+ for name, allowed in expected_arguments.items():
+ if name not in arguments and "" not in allowed:
+ return False, f"expected argument {name!r} missing"
+ return True, ""
+
+
+def _validate_bfcl_calls(
+ result: dict[str, Any],
+ entry: dict[str, Any],
+ ground_truth: list[dict[str, Any]] | None,
+ *,
+ irrelevance: bool,
+) -> list[str]:
+ if not result.get("ok"):
+ return ["request failed"]
+ canonical = _canonical_tool_calls(result.get("tool_calls") or [])
+ if irrelevance:
+ return [] if not canonical else [f"irrelevant request called {canonical!r}"]
+ assert ground_truth is not None
+ if len(canonical) != len(ground_truth):
+ return [
+ f"wrong number of calls: got {len(canonical)}, expected {len(ground_truth)}"
+ ]
+ functions = {function["name"]: function for function in entry["function"]}
+ unmatched = set(range(len(canonical)))
+ errors: list[str] = []
+ for expected in ground_truth:
+ candidate_errors: list[str] = []
+ for index in list(unmatched):
+ matched, error = _bfcl_call_matches(canonical[index], expected, functions)
+ if matched:
+ unmatched.remove(index)
+ break
+ candidate_errors.append(error)
+ else:
+ errors.append(f"no call matched {expected!r}: {candidate_errors!r}")
+ return errors
+
+
+def _run_bfcl_sample(
+ base_url: str,
+ model: str,
+ seed: int,
+ data_dir: Path,
+ per_category: int,
+) -> dict[str, Any]:
+ categories = {
+ "simple_python": False,
+ "parallel": False,
+ "multiple": False,
+ "irrelevance": True,
+ }
+ category_results: dict[str, Any] = {}
+ for category, irrelevance in categories.items():
+ filename = f"BFCL_v4_{category}.json"
+ entries = _read_jsonl(data_dir / filename)[:per_category]
+ ground_truth_by_id: dict[str, list[dict[str, Any]]] = {}
+ if not irrelevance:
+ ground_truth_by_id = {
+ item["id"]: item["ground_truth"]
+ for item in _read_jsonl(data_dir / "possible_answer" / filename)
+ }
+ results: list[dict[str, Any]] = []
+ for entry in entries:
+ payload = {
+ "model": model,
+ "messages": entry["question"][0],
+ "tools": _bfcl_tools(entry["function"]),
+ "tool_choice": "auto",
+ "parallel_tool_calls": True,
+ "stream": True,
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 1024,
+ "chat_template_kwargs": {"enable_thinking": False},
+ }
+ result = _stream_chat(base_url, payload)
+ errors = _validate_bfcl_calls(
+ result,
+ entry,
+ ground_truth_by_id.get(entry["id"]),
+ irrelevance=irrelevance,
+ )
+ result["id"] = entry["id"]
+ result["errors"] = errors
+ results.append(result)
+ category_results[category] = {
+ "passed": sum(not item["errors"] for item in results),
+ "total": len(results),
+ "cases": results,
+ }
+ passed = sum(item["passed"] for item in category_results.values())
+ total = sum(item["total"] for item in category_results.values())
+ return {
+ "passed": passed == total,
+ "score": passed,
+ "total": total,
+ "per_category": category_results,
+ "note": "Fixed BFCL v4 subset; not a full leaderboard submission.",
+ }
+
+
+def _adapt_openai_json_schema(schema: dict[str, Any]) -> dict[str, Any]:
+ adapted = copy.deepcopy(schema)
+ if "type" not in adapted:
+ adapted["type"] = "object"
+
+ def visit(value: Any) -> None:
+ if isinstance(value, list):
+ for item in value:
+ visit(item)
+ return
+ if not isinstance(value, dict):
+ return
+ properties = value.get("properties")
+ if isinstance(properties, dict):
+ if value.get("additionalProperties", True):
+ value["additionalProperties"] = False
+ value["required"] = list(properties)
+ for item in value.values():
+ visit(item)
+
+ visit(adapted)
+ return adapted
+
+
+def _run_json_schema_bench_sample(
+ base_url: str,
+ model: str,
+ seed: int,
+ schema_dir: Path,
+ limit: int,
+ max_schema_bytes: int,
+) -> dict[str, Any]:
+ results: list[dict[str, Any]] = []
+ candidates = sorted(
+ (
+ path
+ for path in schema_dir.glob("*.json")
+ if path.stat().st_size <= max_schema_bytes
+ ),
+ key=lambda path: (path.stat().st_size, path.name),
+ )
+ if len(candidates) > limit:
+ if limit == 1:
+ candidates = [candidates[len(candidates) // 2]]
+ else:
+ candidates = [
+ candidates[round(index * (len(candidates) - 1) / (limit - 1))]
+ for index in range(limit)
+ ]
+ for path in candidates:
+ schema = _adapt_openai_json_schema(json.loads(path.read_text()))
+ payload = {
+ "model": model,
+ "messages": [
+ {
+ "role": "system",
+ "content": (
+ "You need to generate a JSON object that matches the "
+ "schema below."
+ ),
+ },
+ {
+ "role": "user",
+ "content": json.dumps(schema, ensure_ascii=False),
+ },
+ ],
+ "stream": True,
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 2048,
+ "response_format": {
+ "type": "json_schema",
+ "json_schema": {
+ "name": path.stem,
+ "strict": True,
+ "schema": schema,
+ },
+ },
+ }
+ result = _stream_chat(base_url, payload)
+ errors: list[str] = []
+ if not result.get("ok"):
+ errors.append("request failed")
+ else:
+ try:
+ value = json.loads(result["content"])
+ jsonschema.validate(value, schema)
+ except (json.JSONDecodeError, jsonschema.ValidationError) as exc:
+ errors.append(str(exc))
+ result["schema"] = path.name
+ result["errors"] = errors
+ results.append(result)
+ passed = sum(not item["errors"] for item in results)
+ return {
+ "passed": passed == len(results),
+ "score": passed,
+ "total": len(results),
+ "cases": results,
+ "note": (
+ "Deterministic zero-shot WashingtonPost JSONSchemaBench subset; "
+ f"schemas are size-stratified up to {max_schema_bytes} bytes; not a "
+ "full benchmark score."
+ ),
+ }
+
+
+def _canonical_tool_calls(calls: list[dict[str, Any]]) -> list[dict[str, Any]]:
+ canonical: list[dict[str, Any]] = []
+ for call in calls:
+ function = call.get("function") or {}
+ arguments = function.get("arguments") or ""
+ try:
+ parsed_arguments: Any = json.loads(arguments)
+ except (TypeError, json.JSONDecodeError):
+ parsed_arguments = arguments
+ canonical.append(
+ {
+ "name": function.get("name") or "",
+ "arguments": parsed_arguments,
+ }
+ )
+ return canonical
+
+
+def _compare_stream_pair(
+ nonstream: dict[str, Any],
+ stream: dict[str, Any],
+ *,
+ compare_content: bool,
+ compare_tools: bool,
+) -> list[str]:
+ errors: list[str] = []
+ if not nonstream.get("ok") or not stream.get("ok"):
+ return ["stream or non-stream request failed"]
+ if compare_content and nonstream["content"] != stream["content"]:
+ errors.append("stream/non-stream content mismatch")
+ if nonstream["reasoning_content"] != stream["reasoning_content"]:
+ errors.append("stream/non-stream reasoning mismatch")
+ if compare_tools and _canonical_tool_calls(
+ nonstream["tool_calls"]
+ ) != _canonical_tool_calls(stream["tool_calls"]):
+ errors.append("stream/non-stream tool-call mismatch")
+ nonstream_ids = nonstream.get("output_token_ids") or []
+ stream_ids = stream.get("output_token_ids") or []
+ if not nonstream_ids or not stream_ids:
+ errors.append("output token IDs unavailable for parity check")
+ elif nonstream_ids != stream_ids:
+ errors.append("stream/non-stream output token IDs differ")
+ return errors
+
+
+def _run_stream_parity(base_url: str, model: str, seed: int) -> dict[str, Any]:
+ results: list[dict[str, Any]] = []
+ for case in STREAM_PARITY_CASES:
+ expected = case["expected"]
+ payload = {
+ "model": model,
+ "messages": [
+ {
+ "role": "user",
+ "content": (
+ "Reply with exactly the text after TEXT, without quotes, "
+ f"commentary, or a code fence.\nTEXT: {expected}"
+ ),
+ }
+ ],
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 256,
+ "chat_template_kwargs": {"enable_thinking": False},
+ }
+ nonstream = _nonstream_chat(base_url, {**payload, "stream": False})
+ stream = _stream_chat(base_url, {**payload, "stream": True})
+ errors = _compare_stream_pair(
+ nonstream,
+ stream,
+ compare_content=True,
+ compare_tools=False,
+ )
+ if nonstream.get("ok") and nonstream["content"] != expected:
+ errors.append("non-stream exact-copy output mismatch")
+ if stream.get("ok") and stream["content"] != expected:
+ errors.append("stream exact-copy output mismatch")
+ results.append(
+ {
+ "case": case["name"],
+ "expected": expected,
+ "nonstream": nonstream,
+ "stream": stream,
+ "errors": errors,
+ }
+ )
+
+ step = STEPS[0]
+ tool_payload = {
+ "model": model,
+ "messages": [{"role": "user", "content": step["prompt"]}],
+ "tools": TOOLS,
+ "tool_choice": "auto",
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 512,
+ "chat_template_kwargs": {"enable_thinking": False},
+ }
+ nonstream = _nonstream_chat(base_url, {**tool_payload, "stream": False})
+ stream = _stream_chat(base_url, {**tool_payload, "stream": True})
+ errors = _compare_stream_pair(
+ nonstream,
+ stream,
+ compare_content=True,
+ compare_tools=True,
+ )
+ if nonstream.get("ok"):
+ errors.extend(_validate_tool_step(nonstream, step))
+ if stream.get("ok"):
+ errors.extend(_validate_tool_step(stream, step))
+ results.append(
+ {
+ "case": "tool_read",
+ "nonstream": nonstream,
+ "stream": stream,
+ "errors": errors,
+ }
+ )
+ return {"passed": all(not item["errors"] for item in results), "cases": results}
+
+
+def _validate_tool_step(result: dict[str, Any], expected: dict[str, Any]) -> list[str]:
+ errors: list[str] = []
+ calls = result.get("tool_calls") or []
+ if len(calls) != 1:
+ return [f"expected one tool call, got {len(calls)}"]
+ call = calls[0]
+ name = call["function"]["name"]
+ if name != expected["name"]:
+ errors.append(f"tool name {name!r} != {expected['name']!r}")
+ try:
+ arguments = json.loads(call["function"]["arguments"])
+ except json.JSONDecodeError as exc:
+ return errors + [f"invalid arguments JSON: {exc}"]
+ schema = _schema_by_tool_name().get(name)
+ if schema is None:
+ errors.append(f"unknown tool {name!r}")
+ else:
+ try:
+ jsonschema.validate(arguments, schema)
+ except jsonschema.ValidationError as exc:
+ errors.append(f"schema violation: {exc.message}")
+ if arguments != expected["arguments"]:
+ errors.append(f"arguments {arguments!r} != {expected['arguments']!r}")
+ return errors
+
+
+def _run_tool_chain(base_url: str, model: str, seed: int) -> dict[str, Any]:
+ messages: list[dict[str, Any]] = [
+ {
+ "role": "system",
+ "content": (
+ "You are a tool protocol validation agent. Follow each user request "
+ "literally, call only a listed tool, and preserve string whitespace."
+ ),
+ }
+ ]
+ results: list[dict[str, Any]] = []
+ for step_index, step in enumerate(STEPS):
+ messages.append({"role": "user", "content": step["prompt"]})
+ payload = {
+ "model": model,
+ "messages": messages,
+ "tools": TOOLS,
+ "tool_choice": "auto",
+ "stream": True,
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 2048,
+ }
+ result = _stream_chat(base_url, payload)
+ errors = (
+ _validate_tool_step(result, step)
+ if result.get("ok")
+ else ["request failed"]
+ )
+ result["step"] = step_index
+ result["expected_name"] = step["name"]
+ result["errors"] = errors
+ results.append(result)
+ if errors:
+ break
+
+ tool_call = result["tool_calls"][0]
+ history_tool_call = copy.deepcopy(tool_call)
+ history_tool_call["id"] = f"call_protocol_step_{step_index}"
+ messages.append(
+ {
+ "role": "assistant",
+ "content": result.get("content") or None,
+ "tool_calls": [history_tool_call],
+ }
+ )
+ messages.append(
+ {
+ "role": "tool",
+ "tool_call_id": history_tool_call["id"],
+ "content": step["result"],
+ }
+ )
+ return {
+ "passed": len(results) == len(STEPS)
+ and all(not item["errors"] for item in results),
+ "steps": results,
+ }
+
+
+def _run_structured(base_url: str, model: str, seed: int) -> dict[str, Any]:
+ results: list[dict[str, Any]] = []
+ for case in STRUCTURED_CASES:
+ payload = {
+ "model": model,
+ "messages": [{"role": "user", "content": case["prompt"]}],
+ "stream": True,
+ "return_token_ids": True,
+ "temperature": 0.0,
+ "seed": seed,
+ "max_tokens": 512,
+ "response_format": {
+ "type": "json_schema",
+ "json_schema": {
+ "name": case["name"],
+ "strict": True,
+ "schema": case["schema"],
+ },
+ },
+ }
+ result = _stream_chat(base_url, payload)
+ errors: list[str] = []
+ if not result.get("ok"):
+ errors.append("request failed")
+ else:
+ try:
+ value = json.loads(result["content"])
+ jsonschema.validate(value, case["schema"])
+ except (json.JSONDecodeError, jsonschema.ValidationError) as exc:
+ errors.append(str(exc))
+ result["case"] = case["name"]
+ result["errors"] = errors
+ results.append(result)
+ return {"passed": all(not item["errors"] for item in results), "cases": results}
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--base-url", required=True)
+ parser.add_argument("--model", default="quality-audit-dflash2")
+ parser.add_argument("--out", type=Path, required=True)
+ parser.add_argument("--seed", type=int, default=20260827)
+ parser.add_argument("--bfcl-data-dir", type=Path)
+ parser.add_argument("--bfcl-per-category", type=int, default=0)
+ parser.add_argument("--json-schema-dir", type=Path)
+ parser.add_argument("--json-schema-limit", type=int, default=0)
+ parser.add_argument("--json-schema-max-bytes", type=int, default=16384)
+ parser.add_argument(
+ "--only-datasets",
+ action="store_true",
+ help="Skip synthetic protocol and Responses gates for matched dataset arms.",
+ )
+ args = parser.parse_args()
+
+ artifact: dict[str, Any] = {
+ "base_url": args.base_url,
+ "model": args.model,
+ "seed": args.seed,
+ "only_datasets": args.only_datasets,
+ }
+ if not args.only_datasets:
+ artifact.update(
+ {
+ "tool_chain": _run_tool_chain(args.base_url, args.model, args.seed),
+ "structured": _run_structured(args.base_url, args.model, args.seed),
+ "stream_parity": _run_stream_parity(
+ args.base_url, args.model, args.seed
+ ),
+ "responses": _run_responses_chain(args.base_url, args.model, args.seed),
+ }
+ )
+ if args.bfcl_data_dir is not None and args.bfcl_per_category > 0:
+ artifact["bfcl_fixed_sample"] = _run_bfcl_sample(
+ args.base_url,
+ args.model,
+ args.seed,
+ args.bfcl_data_dir,
+ args.bfcl_per_category,
+ )
+ if args.json_schema_dir is not None and args.json_schema_limit > 0:
+ artifact["json_schema_bench_fixed_sample"] = _run_json_schema_bench_sample(
+ args.base_url,
+ args.model,
+ args.seed,
+ args.json_schema_dir,
+ args.json_schema_limit,
+ args.json_schema_max_bytes,
+ )
+ result_keys = {
+ "tool_chain",
+ "structured",
+ "stream_parity",
+ "responses",
+ "bfcl_fixed_sample",
+ "json_schema_bench_fixed_sample",
+ }
+ required_results = [value for key, value in artifact.items() if key in result_keys]
+ artifact["passed"] = bool(
+ required_results and all(value["passed"] for value in required_results)
+ )
+ args.out.parent.mkdir(parents=True, exist_ok=True)
+ args.out.write_text(json.dumps(artifact, ensure_ascii=False, indent=2) + "\n")
+ print(json.dumps({"passed": artifact["passed"], "out": str(args.out)}))
+ if not artifact["passed"]:
+ raise SystemExit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/benchmark_sm70_turbomind_parity.py b/benchmarks/benchmark_sm70_turbomind_parity.py
index ed1f27739f..bbc2cd7c75 100644
--- a/benchmarks/benchmark_sm70_turbomind_parity.py
+++ b/benchmarks/benchmark_sm70_turbomind_parity.py
@@ -94,8 +94,9 @@ def _load_awq(
device: torch.device,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
weight_map = _weight_map(model_path)
- with safe_open(model_path / weight_map[f"{layer}.qweight"],
- framework="pt", device="cpu") as f:
+ with safe_open(
+ model_path / weight_map[f"{layer}.qweight"], framework="pt", device="cpu"
+ ) as f:
qweight = f.get_tensor(f"{layer}.qweight").to(device).contiguous()
scales = f.get_tensor(f"{layer}.scales").to(device).contiguous()
qzeros = f.get_tensor(f"{layer}.qzeros").to(device).contiguous()
@@ -108,8 +109,9 @@ def _load_fp8(
device: torch.device,
) -> tuple[torch.Tensor, torch.Tensor]:
weight_map = _weight_map(model_path)
- with safe_open(model_path / weight_map[f"{layer}.weight"],
- framework="pt", device="cpu") as f:
+ with safe_open(
+ model_path / weight_map[f"{layer}.weight"], framework="pt", device="cpu"
+ ) as f:
weight = f.get_tensor(f"{layer}.weight").to(device).contiguous()
scales = (
f.get_tensor(f"{layer}.weight_scale_inv")
@@ -158,9 +160,7 @@ def _dump_fp8(
ops = _import_sm70_ops()
weight, scales = _load_fp8(args.model, args.layer, device)
x = _make_input(args.m, weight.shape[1], device)
- tm_weight, tm_scales, meta = ops.fp8_sm70_prepare(
- weight, scales, args.group_size
- )
+ tm_weight, tm_scales, meta = ops.fp8_sm70_prepare(weight, scales, args.group_size)
out = torch.empty((args.m, weight.shape[0]), device=device, dtype=torch.float16)
ops.fp8_gemm_sm70_out_meta(out, x, tm_weight, tm_scales, meta)
details = {
@@ -205,8 +205,13 @@ def _dump(args: argparse.Namespace) -> int:
"output": out.detach().cpu(),
}
torch.save(payload, args.out)
- print(json.dumps({k: v for k, v in payload.items() if k != "output"},
- indent=2, sort_keys=True))
+ print(
+ json.dumps(
+ {k: v for k, v in payload.items() if k != "output"},
+ indent=2,
+ sort_keys=True,
+ )
+ )
return 0
@@ -270,9 +275,9 @@ def _bench_awq(
tm_weight, tm_scales, meta = ops.awq_sm70_prepare(
qweight, scales, qzeros, args.group_size
)
- out = torch.empty((args.m, qweight.shape[1] * 8),
- device=device,
- dtype=torch.float16)
+ out = torch.empty(
+ (args.m, qweight.shape[1] * 8), device=device, dtype=torch.float16
+ )
k_ld = int(meta[0].item())
q_ld = int(meta[1].item())
@@ -300,9 +305,7 @@ def _bench_fp8(
ops = _import_sm70_ops()
weight, scales = _load_fp8(args.model, args.layer, device)
x = _make_input(args.m, weight.shape[1], device)
- tm_weight, tm_scales, meta = ops.fp8_sm70_prepare(
- weight, scales, args.group_size
- )
+ tm_weight, tm_scales, meta = ops.fp8_sm70_prepare(weight, scales, args.group_size)
out = torch.empty((args.m, weight.shape[0]), device=device, dtype=torch.float16)
def run() -> None:
diff --git a/benchmarks/benchmark_sm70_wmma_fragment_probe.py b/benchmarks/benchmark_sm70_wmma_fragment_probe.py
index 26e7c4435d..301d49ef27 100644
--- a/benchmarks/benchmark_sm70_wmma_fragment_probe.py
+++ b/benchmarks/benchmark_sm70_wmma_fragment_probe.py
@@ -15,11 +15,7 @@
def _load_extension() -> object:
- source = (
- Path(__file__).resolve().parent
- / "csrc"
- / "sm70_wmma_fragment_probe.cu"
- )
+ source = Path(__file__).resolve().parent / "csrc" / "sm70_wmma_fragment_probe.cu"
os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "7.0")
return load(
name="sm70_wmma_fragment_probe_v3",
@@ -41,17 +37,16 @@ def _parse_args() -> argparse.Namespace:
def main() -> int:
args = _parse_args()
device = torch.device(args.device)
- if not torch.cuda.is_available() or torch.cuda.get_device_capability(
- device
- ) != (7, 0):
+ if not torch.cuda.is_available() or torch.cuda.get_device_capability(device) != (
+ 7,
+ 0,
+ ):
raise RuntimeError("This probe requires an SM70 CUDA device.")
extension = _load_extension()
tile = torch.arange(256, device=device, dtype=torch.float16).reshape(16, 16)
words = extension.dump_matrix_a_fragment(tile, args.stride)
- reference_words, swizzled_words = (
- extension.compare_swizzled_matrix_a_fragment(tile)
- )
+ reference_words, swizzled_words = extension.compare_swizzled_matrix_a_fragment(tile)
matrix_b_row_words = extension.dump_matrix_b_fragment(tile, False)
matrix_b_col_storage = tile.t().contiguous()
matrix_b_col_words = extension.dump_matrix_b_fragment(
@@ -59,9 +54,7 @@ def main() -> int:
True,
)
matrix_b_reference_words, matrix_b_compact_words = (
- extension.compare_compact_matrix_b_col_fragment(
- matrix_b_col_storage
- )
+ extension.compare_compact_matrix_b_col_fragment(matrix_b_col_storage)
)
torch.accelerator.synchronize(device)
elements = words.cpu().view(torch.float16).to(torch.int32).reshape(32, 16)
@@ -69,15 +62,10 @@ def main() -> int:
counts = Counter(value for lane in mapping for value in lane)
multiplicities = Counter(counts.values())
matrix_b_elements = (
- matrix_b_col_words.cpu()
- .view(torch.float16)
- .to(torch.int32)
- .reshape(32, 16)
+ matrix_b_col_words.cpu().view(torch.float16).to(torch.int32).reshape(32, 16)
)
matrix_b_mapping = matrix_b_elements.tolist()
- matrix_b_counts = Counter(
- value for lane in matrix_b_mapping for value in lane
- )
+ matrix_b_counts = Counter(value for lane in matrix_b_mapping for value in lane)
matrix_b_multiplicities = Counter(matrix_b_counts.values())
payload = {
"device": str(device),
@@ -94,10 +82,7 @@ def main() -> int:
torch.equal(reference_words, swizzled_words)
),
"swizzled_fragment_max_word_xor": int(
- torch.bitwise_xor(reference_words, swizzled_words)
- .abs()
- .max()
- .item()
+ torch.bitwise_xor(reference_words, swizzled_words).abs().max().item()
),
"matrix_b": {
"lane_elements": matrix_b_mapping,
@@ -106,8 +91,7 @@ def main() -> int:
str(key): value
for key, value in sorted(matrix_b_multiplicities.items())
},
- "all_elements_covered": sorted(matrix_b_counts)
- == list(range(256)),
+ "all_elements_covered": sorted(matrix_b_counts) == list(range(256)),
"row_col_fragment_words_equal": bool(
torch.equal(matrix_b_row_words, matrix_b_col_words)
),
diff --git a/benchmarks/compare_sm70_dflash2_quality_matrix.py b/benchmarks/compare_sm70_dflash2_quality_matrix.py
new file mode 100644
index 0000000000..68af86055c
--- /dev/null
+++ b/benchmarks/compare_sm70_dflash2_quality_matrix.py
@@ -0,0 +1,280 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Compare paired multi-seed rows from the bounded DFlash2 quality matrix."""
+
+from __future__ import annotations
+
+import argparse
+import itertools
+import json
+import math
+import random
+from collections import Counter, defaultdict
+from pathlib import Path
+from typing import Any
+
+import regex as re
+
+
+def _parse_args() -> argparse.Namespace:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--scores", type=Path, required=True)
+ parser.add_argument("--out", type=Path, required=True)
+ parser.add_argument("--bootstrap-samples", type=int, default=20_000)
+ parser.add_argument("--bootstrap-seed", type=int, default=20260826)
+ return parser.parse_args()
+
+
+def _arm_name(path: Path) -> str:
+ match = re.search(r"-(t0|d[0-9]+)$", path.stem)
+ if match is None:
+ raise ValueError(f"cannot infer matrix arm from {path}")
+ return match.group(1)
+
+
+def _ordered_arm_names(arms: dict[str, Any]) -> list[str]:
+ """Order the target control before progressively accelerated DFlash arms."""
+
+ def key(name: str) -> tuple[int, int]:
+ if name == "t0":
+ return (0, 0)
+ return (1, int(name[1:]))
+
+ return sorted(arms, key=key)
+
+
+def _percentile(values: list[float], quantile: float) -> float | None:
+ if not values:
+ return None
+ ordered = sorted(values)
+ position = (len(ordered) - 1) * quantile
+ lower = math.floor(position)
+ upper = math.ceil(position)
+ if lower == upper:
+ return ordered[lower]
+ weight = position - lower
+ return ordered[lower] + (ordered[upper] - ordered[lower]) * weight
+
+
+def _paired_bootstrap_delta(
+ pairs: list[tuple[float, float]],
+ *,
+ samples: int,
+ seed: int,
+) -> dict[str, float | int | None]:
+ if not pairs:
+ return {"count": 0, "mean_delta": None, "ci95": None}
+ deltas = [right - left for left, right in pairs]
+ rng = random.Random(seed)
+ means = []
+ for _ in range(samples):
+ means.append(sum(rng.choice(deltas) for _ in deltas) / len(deltas))
+ return {
+ "count": len(deltas),
+ "mean_delta": sum(deltas) / len(deltas),
+ "ci95": [_percentile(means, 0.025), _percentile(means, 0.975)],
+ }
+
+
+def _mcnemar_exact(left: list[bool], right: list[bool]) -> dict[str, float | int]:
+ left_only = sum(a and not b for a, b in zip(left, right, strict=True))
+ right_only = sum(b and not a for a, b in zip(left, right, strict=True))
+ discordant = left_only + right_only
+ if discordant == 0:
+ p_value = 1.0
+ else:
+ tail = sum(
+ math.comb(discordant, index)
+ for index in range(min(left_only, right_only) + 1)
+ ) / (2**discordant)
+ p_value = min(1.0, 2.0 * tail)
+ return {
+ "left_only": left_only,
+ "right_only": right_only,
+ "discordant": discordant,
+ "p_value": p_value,
+ }
+
+
+def _summarize(records: list[dict[str, Any]]) -> dict[str, Any]:
+ passed = sum(record["passed"] for record in records)
+ acceptance = [
+ float(record["acceptance_length"])
+ for record in records
+ if record["acceptance_length"] is not None
+ ]
+ steady_decode = [
+ float(record["steady_decode_tps"])
+ for record in records
+ if record["steady_decode_tps"] is not None
+ ]
+ return {
+ "num_cases": len(records),
+ "passed": passed,
+ "score": passed / len(records) if records else None,
+ "finish_reasons": dict(Counter(record["finish_reason"] for record in records)),
+ "failure_reasons": dict(
+ Counter(record["reason"] for record in records if not record["passed"])
+ ),
+ "mean_acceptance_length": (
+ sum(acceptance) / len(acceptance) if acceptance else None
+ ),
+ "mean_steady_decode_tps": (
+ sum(steady_decode) / len(steady_decode) if steady_decode else None
+ ),
+ }
+
+
+def _load_arms(scores_path: Path) -> dict[str, dict[str, Any]]:
+ scores = json.loads(scores_path.read_text(encoding="utf-8"))
+ arms = {}
+ for scored_run in scores["runs"]:
+ raw_path = Path(scored_run["result"])
+ raw = json.loads(raw_path.read_text(encoding="utf-8"))
+ if len(raw["cases"]) != len(scored_run["cases"]):
+ raise ValueError(f"raw/scored case count differs for {raw_path}")
+
+ records = []
+ for raw_case, scored_case in zip(
+ raw["cases"], scored_run["cases"], strict=True
+ ):
+ if raw_case["dataset_index"] != scored_case["dataset_index"]:
+ raise ValueError(f"raw/scored case order differs for {raw_path}")
+ request_metrics = raw_case.get("request_metrics") or {}
+ spec_metrics = raw_case.get("spec_decode_metrics") or {}
+ records.append(
+ {
+ "key": [raw_case.get("request_seed"), raw_case["dataset_index"]],
+ "request_seed": raw_case.get("request_seed"),
+ "dataset_index": raw_case["dataset_index"],
+ "suite": scored_case["suite"],
+ "suite_index": scored_case["suite_index"],
+ "passed": bool(scored_case["passed"]),
+ "reason": scored_case["reason"],
+ "finish_reason": raw_case["finish_reason"],
+ "token_hash": raw_case["token_hash"],
+ "output_tokens": raw_case["output_tokens"],
+ "acceptance_length": spec_metrics.get("acceptance_length"),
+ "steady_decode_tps": request_metrics.get("steady_decode_tps"),
+ }
+ )
+ arm = _arm_name(raw_path)
+ if arm in arms:
+ raise ValueError(f"duplicate matrix arm {arm}")
+ arms[arm] = {
+ "result": str(raw_path),
+ "contract": raw["contract"],
+ "runtime": raw["runtime"],
+ "records": records,
+ }
+ return arms
+
+
+def _record_map(arm: dict[str, Any]) -> dict[tuple[int | None, int], dict[str, Any]]:
+ result = {}
+ for record in arm["records"]:
+ key = tuple(record["key"])
+ if key in result:
+ raise ValueError(f"duplicate paired key {key}")
+ result[key] = record
+ return result
+
+
+def _compare(
+ left_name: str,
+ left_arm: dict[str, Any],
+ right_name: str,
+ right_arm: dict[str, Any],
+ *,
+ bootstrap_samples: int,
+ bootstrap_seed: int,
+) -> dict[str, Any]:
+ left = _record_map(left_arm)
+ right = _record_map(right_arm)
+ if set(left) != set(right):
+ raise ValueError(f"paired keys differ for {left_name}/{right_name}")
+ keys = sorted(left)
+ left_pass = [left[key]["passed"] for key in keys]
+ right_pass = [right[key]["passed"] for key in keys]
+ score_pairs = [(float(a), float(b)) for a, b in zip(left_pass, right_pass)]
+ acceptance_pairs = [
+ (float(left[key]["acceptance_length"]), float(right[key]["acceptance_length"]))
+ for key in keys
+ if left[key]["acceptance_length"] is not None
+ and right[key]["acceptance_length"] is not None
+ ]
+ return {
+ "left": left_name,
+ "right": right_name,
+ "num_cases": len(keys),
+ "token_hash_equal_cases": sum(
+ left[key]["token_hash"] == right[key]["token_hash"] for key in keys
+ ),
+ "score": _paired_bootstrap_delta(
+ score_pairs,
+ samples=bootstrap_samples,
+ seed=bootstrap_seed,
+ ),
+ "acceptance_length": _paired_bootstrap_delta(
+ acceptance_pairs,
+ samples=bootstrap_samples,
+ seed=bootstrap_seed + 1,
+ ),
+ "mcnemar_exact": _mcnemar_exact(left_pass, right_pass),
+ }
+
+
+def main() -> int:
+ args = _parse_args()
+ if args.bootstrap_samples <= 0:
+ raise ValueError("--bootstrap-samples must be positive")
+ arms = _load_arms(args.scores)
+
+ summaries = {}
+ for arm_name, arm in sorted(arms.items()):
+ by_suite: dict[str, list[dict[str, Any]]] = defaultdict(list)
+ by_seed: dict[str, list[dict[str, Any]]] = defaultdict(list)
+ for record in arm["records"]:
+ by_suite[record["suite"]].append(record)
+ by_seed[str(record["request_seed"])].append(record)
+ summaries[arm_name] = {
+ "result": arm["result"],
+ "aggregate": _summarize(arm["records"]),
+ "by_suite": {
+ name: _summarize(records) for name, records in sorted(by_suite.items())
+ },
+ "by_seed": {
+ name: _summarize(records) for name, records in sorted(by_seed.items())
+ },
+ }
+
+ comparisons = [
+ _compare(
+ left,
+ arms[left],
+ right,
+ arms[right],
+ bootstrap_samples=args.bootstrap_samples,
+ bootstrap_seed=args.bootstrap_seed,
+ )
+ for left, right in itertools.combinations(_ordered_arm_names(arms), 2)
+ ]
+
+ payload = {
+ "format": "sm70_dflash2_quality_matrix_v1",
+ "scores": str(args.scores),
+ "bootstrap": {
+ "samples": args.bootstrap_samples,
+ "seed": args.bootstrap_seed,
+ },
+ "arms": summaries,
+ "comparisons": comparisons,
+ }
+ args.out.parent.mkdir(parents=True, exist_ok=True)
+ args.out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
+ print(json.dumps(payload, indent=2, sort_keys=True))
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/benchmarks/compare_sm70_tensor_dumps.py b/benchmarks/compare_sm70_tensor_dumps.py
index 9e3de08e8a..649bf9b7c8 100644
--- a/benchmarks/compare_sm70_tensor_dumps.py
+++ b/benchmarks/compare_sm70_tensor_dumps.py
@@ -79,11 +79,13 @@ def _load_records(root: Path) -> dict[tuple[Any, ...], list[dict[str, Any]]]:
source = payload.get("source", payload.get("layer_type", "unknown"))
shape = tuple(payload.get("shape", tuple(tensor.shape)))
key = (step, layer_idx, source, label, shape)
- records.setdefault(key, []).append({
- "path": str(path),
- "pid": payload.get("pid"),
- "tensor": tensor,
- })
+ records.setdefault(key, []).append(
+ {
+ "path": str(path),
+ "pid": payload.get("pid"),
+ "tensor": tensor,
+ }
+ )
return records
@@ -134,33 +136,37 @@ def compare_dirs(left: Path, right: Path, top: int) -> dict[str, Any]:
right_items = right_records.get(key, [])
step, layer_idx, source, label, shape = key
if not left_items or not right_items:
- missing.append({
- "step": step,
- "layer_idx": layer_idx,
- "source": source,
- "label": label,
- "shape": shape,
- "left_count": len(left_items),
- "right_count": len(right_items),
- })
+ missing.append(
+ {
+ "step": step,
+ "layer_idx": layer_idx,
+ "source": source,
+ "label": label,
+ "shape": shape,
+ "left_count": len(left_items),
+ "right_count": len(right_items),
+ }
+ )
continue
_, pairs = _best_pairing(left_items, right_items)
for left_idx, right_idx, stats in pairs:
left_tensor = left_items[left_idx]["tensor"]
right_tensor = right_items[right_idx]["tensor"]
- summaries.append({
- "step": step,
- "layer_idx": layer_idx,
- "source": source,
- "label": label,
- "shape": shape,
- "left_pid": left_items[left_idx]["pid"],
- "right_pid": right_items[right_idx]["pid"],
- "left_path": left_items[left_idx]["path"],
- "right_path": right_items[right_idx]["path"],
- **stats,
- "rows": _row_stats(left_tensor, right_tensor),
- })
+ summaries.append(
+ {
+ "step": step,
+ "layer_idx": layer_idx,
+ "source": source,
+ "label": label,
+ "shape": shape,
+ "left_pid": left_items[left_idx]["pid"],
+ "right_pid": right_items[right_idx]["pid"],
+ "left_path": left_items[left_idx]["path"],
+ "right_path": right_items[right_idx]["path"],
+ **stats,
+ "rows": _row_stats(left_tensor, right_tensor),
+ }
+ )
by_worst = sorted(
summaries,
@@ -262,10 +268,12 @@ def _numeric_gate(
if missing and not allow_missing:
for item in missing[:20]:
- violations.append({
- "reason": "missing_tensor_dump",
- **item,
- })
+ violations.append(
+ {
+ "reason": "missing_tensor_dump",
+ **item,
+ }
+ )
for item in compared:
max_abs = float(item.get("max_abs", math.inf))
@@ -280,21 +288,25 @@ def _numeric_gate(
)
if item.get("shape_mismatch"):
- violations.append({
- "reason": "shape_mismatch",
- **_record_ref(item),
- "left_shape": item.get("left_shape"),
- "right_shape": item.get("right_shape"),
- })
+ violations.append(
+ {
+ "reason": "shape_mismatch",
+ **_record_ref(item),
+ "left_shape": item.get("left_shape"),
+ "right_shape": item.get("right_shape"),
+ }
+ )
continue
if not math.isfinite(max_abs) or not math.isfinite(mean_abs):
- violations.append({
- "reason": "non_finite_diff",
- **_record_ref(item),
- "max_abs": item.get("max_abs"),
- "mean_abs": item.get("mean_abs"),
- })
+ violations.append(
+ {
+ "reason": "non_finite_diff",
+ **_record_ref(item),
+ "max_abs": item.get("max_abs"),
+ "mean_abs": item.get("mean_abs"),
+ }
+ )
continue
item_max_abs_bound, max_abs_rule = _bound_for_item(
@@ -304,21 +316,25 @@ def _numeric_gate(
)
if item_max_abs_bound is None:
if max_abs != 0.0:
- pending.append({
- "reason": "nonzero_max_abs_without_bound",
- **_record_ref(item),
- "max_abs": max_abs,
- })
+ pending.append(
+ {
+ "reason": "nonzero_max_abs_without_bound",
+ **_record_ref(item),
+ "max_abs": max_abs,
+ }
+ )
else:
checked_max_abs += 1
if max_abs > item_max_abs_bound:
- violations.append({
- "reason": "max_abs_exceeds_bound",
- **_record_ref(item),
- "max_abs": max_abs,
- "bound": item_max_abs_bound,
- "bound_rule": max_abs_rule,
- })
+ violations.append(
+ {
+ "reason": "max_abs_exceeds_bound",
+ **_record_ref(item),
+ "max_abs": max_abs,
+ "bound": item_max_abs_bound,
+ "bound_rule": max_abs_rule,
+ }
+ )
item_mean_abs_bound, mean_abs_rule = _bound_for_item(
item,
@@ -328,23 +344,27 @@ def _numeric_gate(
if item_mean_abs_bound is not None:
checked_mean_abs += 1
if mean_abs > item_mean_abs_bound:
- violations.append({
- "reason": "mean_abs_exceeds_bound",
- **_record_ref(item),
- "mean_abs": mean_abs,
- "bound": item_mean_abs_bound,
- "bound_rule": mean_abs_rule,
- })
+ violations.append(
+ {
+ "reason": "mean_abs_exceeds_bound",
+ **_record_ref(item),
+ "mean_abs": mean_abs,
+ "bound": item_mean_abs_bound,
+ "bound_rule": mean_abs_rule,
+ }
+ )
if min_cosine is not None and cosine is not None:
checked_cosine += 1
if cosine < min_cosine:
- violations.append({
- "reason": "cosine_below_bound",
- **_record_ref(item),
- "cosine": cosine,
- "bound": min_cosine,
- })
+ violations.append(
+ {
+ "reason": "cosine_below_bound",
+ **_record_ref(item),
+ "cosine": cosine,
+ "bound": min_cosine,
+ }
+ )
if checked_max_abs == 0 and (max_abs_bound is not None or max_abs_rules):
pending.append("no tensors matched any max_abs bound")
diff --git a/benchmarks/kernels/benchmark_dflash2_lookup.py b/benchmarks/kernels/benchmark_dflash2_lookup.py
new file mode 100644
index 0000000000..65c8300ad0
--- /dev/null
+++ b/benchmarks/kernels/benchmark_dflash2_lookup.py
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Microbenchmark DFlash2 lookup drafting against the production UVA history."""
+
+import argparse
+import json
+from collections.abc import Callable
+
+import torch
+
+from vllm.v1.worker.gpu.buffer_utils import UvaBuffer
+from vllm.v1.worker.gpu.spec_decode.dflash2.lookup import fuse_draft, suffix_lookup
+
+
+def _time_ms(fn: Callable[[], None], repeats: int, warmup: int) -> float:
+ for _ in range(warmup):
+ fn()
+ torch.accelerator.synchronize()
+ start = torch.cuda.Event(enable_timing=True)
+ end = torch.cuda.Event(enable_timing=True)
+ start.record()
+ for _ in range(repeats):
+ fn()
+ end.record()
+ end.synchronize()
+ return start.elapsed_time(end) / repeats
+
+
+def _make_history(batch_size: int, context_len: int) -> UvaBuffer:
+ history = UvaBuffer((batch_size, context_len + 32), torch.int32)
+ history.cpu.random_(1000, 200000)
+ suffix = torch.arange(700001, 700013, dtype=torch.int32)
+ continuation = torch.arange(800001, 800016, dtype=torch.int32)
+ match_start = max(0, context_len // 2 - suffix.numel())
+ for row in range(batch_size):
+ history.cpu[row, match_start : match_start + suffix.numel()].copy_(suffix)
+ history.cpu[
+ row,
+ match_start + suffix.numel() : match_start
+ + suffix.numel()
+ + continuation.numel(),
+ ].copy_(continuation)
+ history.cpu[row, context_len - suffix.numel() : context_len].copy_(suffix)
+ return history
+
+
+def _benchmark_case(
+ batch_size: int,
+ context_len: int,
+ repeats: int,
+ warmup: int,
+) -> dict[str, float | int]:
+ device = torch.device("cuda")
+ k, draft_block = 15, 7
+ history = _make_history(batch_size, context_len)
+ total_len = torch.full((batch_size,), context_len, dtype=torch.int32, device=device)
+ idx_mapping = torch.arange(
+ batch_size, dtype=torch.int32, device=device
+ ).repeat_interleave(
+ draft_block,
+ )
+ eligible = torch.ones(batch_size, dtype=torch.int32, device=device)
+ lookup_tokens = torch.zeros((batch_size, k), dtype=torch.int32, device=device)
+ match_len = torch.zeros(batch_size, dtype=torch.int32, device=device)
+ valid = torch.zeros_like(match_len)
+ drafted = torch.zeros((batch_size, k), dtype=torch.int64, device=device)
+ use = torch.zeros((batch_size, k), dtype=torch.int32, device=device)
+ hits = torch.zeros((), dtype=torch.int64, device=device)
+ take_flags = torch.zeros(batch_size, dtype=torch.int32, device=device)
+
+ def lookup_only() -> None:
+ suffix_lookup(
+ history.uva,
+ total_len,
+ idx_mapping,
+ eligible,
+ batch_size,
+ k,
+ idx_mapping_stride=draft_block,
+ nmin=6,
+ nmax=12,
+ out_tokens=lookup_tokens,
+ out_len=match_len,
+ out_valid=valid,
+ )
+
+ def lookup_and_fuse() -> None:
+ lookup_only()
+ fuse_draft(
+ drafted,
+ lookup_tokens,
+ match_len,
+ valid,
+ use,
+ idx_mapping,
+ hits,
+ batch_size,
+ k,
+ draft_block=draft_block,
+ idx_mapping_stride=draft_block,
+ nmin=6,
+ nstrong=6,
+ agree_min=0,
+ nmin_tail=4,
+ long_min=6,
+ take_flags=take_flags,
+ )
+
+ eager_ms = _time_ms(lookup_and_fuse, repeats, warmup)
+ graph = torch.cuda.CUDAGraph()
+ capture_stream = torch.cuda.Stream()
+ capture_stream.wait_stream(torch.cuda.current_stream())
+ with torch.cuda.stream(capture_stream):
+ for _ in range(3):
+ lookup_and_fuse()
+ torch.cuda.current_stream().wait_stream(capture_stream)
+ torch.accelerator.synchronize()
+ with torch.cuda.graph(graph):
+ lookup_and_fuse()
+ graph_ms = _time_ms(graph.replay, repeats, warmup)
+
+ assert torch.all(match_len == 12)
+ assert torch.all(valid == k)
+ assert torch.all(take_flags == 1)
+ return {
+ "batch_size": batch_size,
+ "context_len": context_len,
+ "uva_lookup_fuse_eager_ms": eager_ms,
+ "uva_lookup_fuse_graph_ms": graph_ms,
+ }
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--contexts", default="1024,32768,65536,131072")
+ parser.add_argument("--batches", default="1,2,4,8")
+ parser.add_argument("--repeats", type=int, default=100)
+ parser.add_argument("--warmup", type=int, default=10)
+ parser.add_argument("--output", default="")
+ args = parser.parse_args()
+
+ results = [
+ _benchmark_case(batch, context, args.repeats, args.warmup)
+ for context in (int(value) for value in args.contexts.split(","))
+ for batch in (int(value) for value in args.batches.split(","))
+ ]
+ payload = {
+ "device": torch.cuda.get_device_name(),
+ "results": results,
+ }
+ rendered = json.dumps(payload, indent=2)
+ print(rendered)
+ if args.output:
+ with open(args.output, "w") as output_file:
+ output_file.write(rendered + "\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/kernels/benchmark_dspark_markov.py b/benchmarks/kernels/benchmark_dspark_markov.py
index df2185b35d..23e3202761 100644
--- a/benchmarks/kernels/benchmark_dspark_markov.py
+++ b/benchmarks/kernels/benchmark_dspark_markov.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Microbenchmark DSpark's sequential Markov sampling chain."""
diff --git a/benchmarks/kernels/benchmark_dspark_metadata.py b/benchmarks/kernels/benchmark_dspark_metadata.py
index 850231e984..40604d9a08 100644
--- a/benchmarks/kernels/benchmark_dspark_metadata.py
+++ b/benchmarks/kernels/benchmark_dspark_metadata.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Validate DSpark query expansion and non-causal SWA metadata."""
diff --git a/benchmarks/kernels/benchmark_dspark_sm70_attention.py b/benchmarks/kernels/benchmark_dspark_sm70_attention.py
index 70db0a7892..a9764bddc7 100644
--- a/benchmarks/kernels/benchmark_dspark_sm70_attention.py
+++ b/benchmarks/kernels/benchmark_dspark_sm70_attention.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Replay a real DSpark packed-FP8 attention dump at N=7."""
diff --git a/benchmarks/kernels/benchmark_flash_v100_dflash2_swa.py b/benchmarks/kernels/benchmark_flash_v100_dflash2_swa.py
new file mode 100644
index 0000000000..ddea51045e
--- /dev/null
+++ b/benchmarks/kernels/benchmark_flash_v100_dflash2_swa.py
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+
+"""Benchmark the DFlash2 draft sliding-window paged-attention shape."""
+
+from __future__ import annotations
+
+import argparse
+import json
+import statistics
+from pathlib import Path
+
+import torch
+from flash_attn_v100 import flash_attn_prefill_paged
+
+
+def _time_ms(fn, *, warmup: int, reps: int) -> list[float]:
+ for _ in range(warmup):
+ fn()
+ torch.cuda.synchronize()
+
+ samples = []
+ for _ in range(reps):
+ start = torch.cuda.Event(enable_timing=True)
+ end = torch.cuda.Event(enable_timing=True)
+ start.record()
+ fn()
+ end.record()
+ end.synchronize()
+ samples.append(start.elapsed_time(end))
+ return samples
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--seq-lens",
+ type=int,
+ nargs="+",
+ default=[1024, 32768, 131072, 261888],
+ )
+ parser.add_argument("--q-len", type=int, default=8)
+ parser.add_argument("--num-query-heads", type=int, default=8)
+ parser.add_argument("--num-kv-heads", type=int, default=2)
+ parser.add_argument("--head-dim", type=int, default=128)
+ parser.add_argument("--block-size", type=int, default=16)
+ parser.add_argument("--window-left", type=int, default=2048)
+ parser.add_argument("--window-right", type=int, default=2048)
+ parser.add_argument("--warmup", type=int, default=20)
+ parser.add_argument("--reps", type=int, default=100)
+ parser.add_argument("--output", type=Path)
+ parser.add_argument("--tensor-output", type=Path)
+ args = parser.parse_args()
+
+ if not torch.cuda.is_available():
+ raise RuntimeError("CUDA is required")
+ if torch.cuda.get_device_capability() != (7, 0):
+ raise RuntimeError("This benchmark targets SM70")
+
+ torch.manual_seed(0)
+ device = torch.device("cuda")
+ dtype = torch.float16
+ max_seq_len = max(args.seq_lens)
+ num_blocks = (max_seq_len + args.block_size - 1) // args.block_size
+ query = torch.randn(
+ 1,
+ args.q_len,
+ args.num_query_heads,
+ args.head_dim,
+ device=device,
+ dtype=dtype,
+ )
+ key_cache = torch.randn(
+ num_blocks,
+ args.block_size,
+ args.num_kv_heads,
+ args.head_dim,
+ device=device,
+ dtype=dtype,
+ )
+ value_cache = torch.randn_like(key_cache)
+ full_block_table = torch.arange(
+ num_blocks, device=device, dtype=torch.int32
+ ).unsqueeze(0)
+ output = torch.empty_like(query)
+ tensor_outputs: dict[int, torch.Tensor] = {}
+ results = []
+
+ for seq_len in args.seq_lens:
+ active_blocks = (seq_len + args.block_size - 1) // args.block_size
+ block_table = full_block_table[:, :active_blocks]
+ seq_lens = torch.tensor([seq_len], device=device, dtype=torch.int32)
+
+ def run(
+ block_table: torch.Tensor = block_table,
+ seq_lens: torch.Tensor = seq_lens,
+ ) -> None:
+ flash_attn_prefill_paged(
+ query,
+ key_cache,
+ value_cache,
+ block_table,
+ seq_lens,
+ out=output,
+ causal=False,
+ window_size=(args.window_left, args.window_right),
+ )
+
+ samples = _time_ms(run, warmup=args.warmup, reps=args.reps)
+ run()
+ torch.cuda.synchronize()
+ tensor_outputs[seq_len] = output.detach().cpu().clone()
+ results.append(
+ {
+ "seq_len": seq_len,
+ "median_ms": statistics.median(samples),
+ "mean_ms": statistics.mean(samples),
+ "min_ms": min(samples),
+ "max_ms": max(samples),
+ "five_draft_layers_median_ms": 5 * statistics.median(samples),
+ }
+ )
+
+ report = {
+ "device": torch.cuda.get_device_name(),
+ "torch": torch.__version__,
+ "shape": {
+ "q_len": args.q_len,
+ "num_query_heads": args.num_query_heads,
+ "num_kv_heads": args.num_kv_heads,
+ "head_dim": args.head_dim,
+ "block_size": args.block_size,
+ "causal": False,
+ "window_size": [args.window_left, args.window_right],
+ },
+ "warmup": args.warmup,
+ "reps": args.reps,
+ "results": results,
+ }
+ rendered = json.dumps(report, indent=2)
+ print(rendered)
+ if args.output is not None:
+ args.output.parent.mkdir(parents=True, exist_ok=True)
+ args.output.write_text(rendered + "\n", encoding="utf-8")
+ if args.tensor_output is not None:
+ args.tensor_output.parent.mkdir(parents=True, exist_ok=True)
+ torch.save(tensor_outputs, args.tensor_output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/kernels/benchmark_sm70_dflash2_grouped_verify.py b/benchmarks/kernels/benchmark_sm70_dflash2_grouped_verify.py
new file mode 100644
index 0000000000..1545c512e0
--- /dev/null
+++ b/benchmarks/kernels/benchmark_sm70_dflash2_grouped_verify.py
@@ -0,0 +1,163 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Microbenchmark the SM70 q8/q16 grouped DFlash2 verifier."""
+
+from __future__ import annotations
+
+import argparse
+import json
+import math
+from collections.abc import Callable
+from functools import partial
+
+import torch
+
+
+def _make_case(
+ query_len: int, prefix_len: int, page_size: int
+) -> tuple[torch.Tensor, ...]:
+ total_len = prefix_len + query_len
+ logical_pages = math.ceil(total_len / page_size)
+ physical_pages = logical_pages + 3
+ source = torch.randn(
+ (physical_pages, 2, page_size, 1, 256),
+ dtype=torch.float16,
+ device="cuda",
+ ).mul_(0.25)
+ cache = source.to(torch.float8_e5m2).view(torch.uint8)
+ key_cache, value_cache = cache.unbind(1)
+ block_table = torch.randperm(physical_pages, dtype=torch.int32, device="cuda")[
+ :logical_pages
+ ].view(1, -1)
+ query = torch.randn((query_len, 6, 256), dtype=torch.float16, device="cuda").mul_(
+ 0.25
+ )
+ seq_lens = torch.tensor([total_len], dtype=torch.int32, device="cuda")
+ return query, key_cache, value_cache, block_table, seq_lens
+
+
+def _time_cuda(fn: Callable[[], object], warmup: int, repeats: int) -> float:
+ for _ in range(warmup):
+ fn()
+ torch.accelerator.synchronize()
+ start = torch.cuda.Event(enable_timing=True)
+ end = torch.cuda.Event(enable_timing=True)
+ start.record()
+ for _ in range(repeats):
+ fn()
+ end.record()
+ end.synchronize()
+ return start.elapsed_time(end) / repeats
+
+
+def _capture(fn: Callable[[], object]) -> torch.cuda.CUDAGraph:
+ fn()
+ torch.accelerator.synchronize()
+ graph = torch.cuda.CUDAGraph()
+ with torch.cuda.graph(graph):
+ fn()
+ return graph
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--query-lens", type=int, nargs="+", default=[8, 16])
+ parser.add_argument(
+ "--prefix-lens", type=int, nargs="+", default=[1024, 32768, 128000]
+ )
+ parser.add_argument("--page-size", type=int, default=3296)
+ parser.add_argument("--warmup", type=int, default=10)
+ parser.add_argument("--repeats", type=int, default=100)
+ args = parser.parse_args()
+
+ if not torch.cuda.is_available():
+ raise RuntimeError("CUDA is required")
+ if torch.cuda.get_device_capability() != (7, 0):
+ raise RuntimeError("This benchmark requires an SM70 GPU")
+
+ import flash_attn_v100
+
+ torch.manual_seed(20260827)
+ results = []
+ for query_len in args.query_lens:
+ for prefix_len in args.prefix_lens:
+ query, key_cache, value_cache, block_table, seq_lens = _make_case(
+ query_len, prefix_len, args.page_size
+ )
+ grouped_out = torch.empty_like(query)
+ independent_out = torch.empty_like(query)
+ decode_block_table = block_table.repeat(query_len, 1).contiguous()
+ decode_seq_lens = torch.arange(
+ prefix_len + 1,
+ prefix_len + query_len + 1,
+ dtype=torch.int32,
+ device=query.device,
+ )
+
+ grouped = partial(
+ flash_attn_v100.flash_attn_grouped_verify_paged,
+ query,
+ key_cache,
+ value_cache,
+ block_table,
+ seq_lens,
+ out=grouped_out,
+ one_pass=True,
+ )
+ independent = partial(
+ flash_attn_v100.flash_attn_decode_paged_xqa,
+ query,
+ key_cache,
+ value_cache,
+ decode_block_table,
+ decode_seq_lens,
+ out=independent_out,
+ kv_cache_dtype="fp8_e5m2",
+ max_seq_len_hint=prefix_len + query_len,
+ workspace_seq_capacity_hint=prefix_len + query_len,
+ )
+
+ grouped()
+ independent()
+ torch.accelerator.synchronize()
+ difference = grouped_out.float().sub(independent_out.float()).abs()
+ grouped_eager_ms = _time_cuda(grouped, args.warmup, args.repeats)
+ independent_eager_ms = _time_cuda(independent, args.warmup, args.repeats)
+ grouped_graph = _capture(grouped)
+ independent_graph = _capture(independent)
+ grouped_graph_ms = _time_cuda(
+ grouped_graph.replay, args.warmup, args.repeats
+ )
+ independent_graph_ms = _time_cuda(
+ independent_graph.replay, args.warmup, args.repeats
+ )
+ results.append(
+ {
+ "query_len": query_len,
+ "prefix_len": prefix_len,
+ "page_size": args.page_size,
+ "grouped_eager_ms": grouped_eager_ms,
+ "independent_eager_ms": independent_eager_ms,
+ "eager_speedup": independent_eager_ms / grouped_eager_ms,
+ "grouped_graph_ms": grouped_graph_ms,
+ "independent_graph_ms": independent_graph_ms,
+ "graph_speedup": independent_graph_ms / grouped_graph_ms,
+ "max_abs_vs_independent": difference.max().item(),
+ "mean_abs_vs_independent": difference.mean().item(),
+ }
+ )
+
+ print(
+ json.dumps(
+ {
+ "gpu": torch.cuda.get_device_name(),
+ "torch": torch.__version__,
+ "results": results,
+ },
+ indent=2,
+ )
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/kernels/benchmark_sm70_fp8_graph_capture.py b/benchmarks/kernels/benchmark_sm70_fp8_graph_capture.py
index ba73f21797..d31121dd36 100644
--- a/benchmarks/kernels/benchmark_sm70_fp8_graph_capture.py
+++ b/benchmarks/kernels/benchmark_sm70_fp8_graph_capture.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Validate an uncached SM70 FP8 GEMM shape under CUDA Graph capture."""
diff --git a/benchmarks/verify_sm70_artifact.py b/benchmarks/verify_sm70_artifact.py
index dfca12798f..81dde92497 100644
--- a/benchmarks/verify_sm70_artifact.py
+++ b/benchmarks/verify_sm70_artifact.py
@@ -75,18 +75,14 @@
("sm70_turbomind_policy.awq_turbomind_effective", True),
)
-AWQ_TURBOMIND_DENSE_REQUIRED_LOGS = (
- "SM70 AWQ TurboMind dense path enabled",
-)
+AWQ_TURBOMIND_DENSE_REQUIRED_LOGS = ("SM70 AWQ TurboMind dense path enabled",)
FP8_TURBOMIND_DENSE_JSON_EXPECTATIONS = (
("sm70_turbomind_policy.fp8_turbomind_effective", True),
("sm70_turbomind_policy.fp8_dequant_fallback_effective", True),
)
-FP8_TURBOMIND_DENSE_REQUIRED_LOGS = (
- "SM70 FP8 TurboMind W8A16 dense path enabled",
-)
+FP8_TURBOMIND_DENSE_REQUIRED_LOGS = ("SM70 FP8 TurboMind W8A16 dense path enabled",)
FP8_0DOT3_DENSE_DEQUANT_JSON_EXPECTATIONS = (
("sm70_turbomind_policy.fp8_turbomind_effective", False),
@@ -105,8 +101,7 @@
("sm70_turbomind_policy.accepted_awq_moe_default_policy", True),
("sm70_turbomind_policy.awq_moe_disable_effective", False),
("sm70_turbomind_policy.awq_moe_batched_gemm_effective", False),
- ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective",
- False),
+ ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective", False),
("sm70_moe_policy.single_token_unpermute_fastpath_effective", True),
)
@@ -121,8 +116,7 @@
("sm70_turbomind_policy.accepted_awq_moe_default_policy", True),
("sm70_turbomind_policy.awq_moe_disable_effective", False),
("sm70_turbomind_policy.awq_moe_batched_gemm_effective", True),
- ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective",
- False),
+ ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective", False),
)
AWQ_MOE_BATCHED_SAFE_ROUTE_REQUIRED_LOGS = (
@@ -138,8 +132,7 @@
("sm70_turbomind_policy.awq_moe_0dot3_baseline_policy", True),
("sm70_turbomind_policy.awq_moe_disable_effective", False),
("sm70_turbomind_policy.awq_moe_batched_gemm_effective", True),
- ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective",
- True),
+ ("sm70_turbomind_policy.awq_moe_legacy_single_token_compact_effective", True),
)
AWQ_MOE_0DOT3_BASELINE_ROUTE_REQUIRED_LOGS = (
@@ -153,9 +146,7 @@
("sm70_turbomind_policy.fp8_moe_batched_gemm_effective", True),
)
-FP8_MOE_SAFE_ROUTE_REQUIRED_LOGS = (
- "SM70 FP8 MoE TurboMind batched path enabled",
-)
+FP8_MOE_SAFE_ROUTE_REQUIRED_LOGS = ("SM70 FP8 MoE TurboMind batched path enabled",)
FP8_MOE_0DOT3_FALLBACK_ROUTE_JSON_EXPECTATIONS = (
("sm70_turbomind_policy.fp8_moe_0dot3_dequant_fallback_policy", True),
@@ -281,9 +272,7 @@ def _get_json_path(payload: Any, path: str) -> Any:
def _parse_expectation(raw: str) -> tuple[str, Any]:
if "=" not in raw:
- raise ValueError(
- f"Expected PATH=VALUE for --expect-json, got {raw!r}"
- )
+ raise ValueError(f"Expected PATH=VALUE for --expect-json, got {raw!r}")
path, expected = raw.split("=", 1)
if not path:
raise ValueError(f"Expected non-empty PATH in {raw!r}")
@@ -339,17 +328,13 @@ def _awq_moe_safe_tune_gate_for_meta(meta: Any) -> dict[str, Any]:
}
raw = tune_policy.get("VLLM_SM70_AWQ_TUNE_SMALL_SHAPES")
- tune_safe_default = tune_policy.get(
- "awq_moe_safe_default_selector_effective"
- )
+ tune_safe_default = tune_policy.get("awq_moe_safe_default_selector_effective")
turbomind_safe_default = turbomind_policy.get(
"awq_moe_safe_default_selector_effective"
)
pinned = raw == "0"
source_safe_unset = (
- raw is None
- and tune_safe_default is True
- and turbomind_safe_default is True
+ raw is None and tune_safe_default is True and turbomind_safe_default is True
)
return {
"passed": pinned or source_safe_unset,
@@ -409,10 +394,12 @@ def _awq_moe_safe_tune_gate(payload: Any) -> dict[str, Any]:
return {
"passed": False,
"location": None,
- "checks": [{
- "passed": False,
- "reason": "no top-level or compare metadata policies found",
- }],
+ "checks": [
+ {
+ "passed": False,
+ "reason": "no top-level or compare metadata policies found",
+ }
+ ],
}
@@ -529,8 +516,7 @@ def _model_quality_failures(payload: Any) -> list[str]:
failures = []
if gate.get("label") != "model-pass":
failures.append(
- "model_quality_gate.label is not model-pass "
- f"({gate.get('label')!r})"
+ f"model_quality_gate.label is not model-pass ({gate.get('label')!r})"
)
if gate.get("default_acceptance") != "model-level gate passed":
failures.append(
@@ -586,8 +572,7 @@ def _inventory_complete_failures(payload: Any) -> list[str]:
failures = []
if gate.get("label") != "inventory-complete":
failures.append(
- "inventory_gate.label is not inventory-complete "
- f"({gate.get('label')!r})"
+ f"inventory_gate.label is not inventory-complete ({gate.get('label')!r})"
)
if gate.get("complete") is not True:
failures.append("inventory_gate.complete is not true")
@@ -595,8 +580,7 @@ def _inventory_complete_failures(payload: Any) -> list[str]:
old_only_env_vars = gate.get("old_only_env_vars")
if old_only_env_vars:
failures.append(
- "inventory_gate.old_only_env_vars is not empty: "
- f"{old_only_env_vars!r}"
+ f"inventory_gate.old_only_env_vars is not empty: {old_only_env_vars!r}"
)
if gate.get("old_only_env_vars_count") != 0:
failures.append(
@@ -647,11 +631,13 @@ def _verify(
present = location is not None
if not present:
missing_policies.append(policy)
- policy_results.append({
- "policy": policy,
- "present": present,
- "location": location,
- })
+ policy_results.append(
+ {
+ "policy": policy,
+ "present": present,
+ "location": location,
+ }
+ )
json_results = []
failed_json_expectations = []
@@ -678,10 +664,12 @@ def _verify(
present = text in logs
if not present:
missing_log_texts.append(text)
- log_results.append({
- "text": text,
- "present": present,
- })
+ log_results.append(
+ {
+ "text": text,
+ "present": present,
+ }
+ )
log_regex_results = []
missing_log_regexes = []
@@ -689,10 +677,12 @@ def _verify(
present = re.search(pattern, logs) is not None
if not present:
missing_log_regexes.append(pattern)
- log_regex_results.append({
- "pattern": pattern,
- "present": present,
- })
+ log_regex_results.append(
+ {
+ "pattern": pattern,
+ "present": present,
+ }
+ )
rejected_log_results = []
rejected_log_texts = []
@@ -700,10 +690,12 @@ def _verify(
present = text in logs
if present:
rejected_log_texts.append(text)
- rejected_log_results.append({
- "text": text,
- "present": present,
- })
+ rejected_log_results.append(
+ {
+ "text": text,
+ "present": present,
+ }
+ )
rejected_log_regex_results = []
rejected_log_regexes = []
@@ -711,10 +703,12 @@ def _verify(
present = re.search(pattern, logs) is not None
if present:
rejected_log_regexes.append(pattern)
- rejected_log_regex_results.append({
- "pattern": pattern,
- "present": present,
- })
+ rejected_log_regex_results.append(
+ {
+ "pattern": pattern,
+ "present": present,
+ }
+ )
decode_timing_failures = (
_decode_timing_failures(payload) if require_decode_timing else []
@@ -723,8 +717,7 @@ def _verify(
_model_quality_failures(payload) if require_model_quality_pass else []
)
inventory_complete_failures = (
- _inventory_complete_failures(payload)
- if require_inventory_complete else []
+ _inventory_complete_failures(payload) if require_inventory_complete else []
)
passed = not (
@@ -888,9 +881,7 @@ def _build_parser() -> argparse.ArgumentParser:
parser.add_argument(
"--require-awq-turbomind-dense",
action="store_true",
- help=(
- "Require SM70 AWQ TurboMind dense policy and its runtime route log."
- ),
+ help=("Require SM70 AWQ TurboMind dense policy and its runtime route log."),
)
parser.add_argument(
"--require-fp8-turbomind-dense",
@@ -1017,9 +1008,7 @@ def main() -> int:
try:
payload = _read_json(args.json)
- expectations = [
- _parse_expectation(raw) for raw in args.expect_json
- ]
+ expectations = [_parse_expectation(raw) for raw in args.expect_json]
log_expectations = list(args.expect_log)
log_regex_expectations = list(args.expect_log_regex)
rejected_log_expectations = list(args.reject_log)
@@ -1034,9 +1023,7 @@ def main() -> int:
log_expectations.extend(FULL_FLASH_V100_REQUIRED_LOGS)
log_expectations.extend(SM70_FP8_KV_CACHE_ROUTE_REQUIRED_LOGS)
rejected_log_expectations.extend(FULL_FLASH_V100_REJECTED_LOGS)
- rejected_log_expectations.extend(
- SM70_FP8_KV_CACHE_ROUTE_REJECTED_LOGS
- )
+ rejected_log_expectations.extend(SM70_FP8_KV_CACHE_ROUTE_REJECTED_LOGS)
if args.require_turbomind_default_policy:
expectations.extend(TURBOMIND_DEFAULT_JSON_EXPECTATIONS)
if args.require_awq_turbomind_dense:
@@ -1057,27 +1044,17 @@ def main() -> int:
if args.require_awq_moe_batched_safe_route:
expectations.extend(AWQ_MOE_BATCHED_SAFE_ROUTE_JSON_EXPECTATIONS)
log_expectations.extend(AWQ_MOE_BATCHED_SAFE_ROUTE_REQUIRED_LOGS)
- rejected_log_expectations.extend(
- AWQ_MOE_BATCHED_SAFE_ROUTE_REJECTED_LOGS
- )
+ rejected_log_expectations.extend(AWQ_MOE_BATCHED_SAFE_ROUTE_REJECTED_LOGS)
if args.require_awq_moe_0dot3_baseline_route:
expectations.extend(AWQ_MOE_0DOT3_BASELINE_ROUTE_JSON_EXPECTATIONS)
- log_expectations.extend(
- AWQ_MOE_0DOT3_BASELINE_ROUTE_REQUIRED_LOGS
- )
+ log_expectations.extend(AWQ_MOE_0DOT3_BASELINE_ROUTE_REQUIRED_LOGS)
if args.require_fp8_moe_safe_route:
expectations.extend(FP8_MOE_SAFE_ROUTE_JSON_EXPECTATIONS)
log_expectations.extend(FP8_MOE_SAFE_ROUTE_REQUIRED_LOGS)
if args.require_fp8_moe_0dot3_fallback_route:
- expectations.extend(
- FP8_MOE_0DOT3_FALLBACK_ROUTE_JSON_EXPECTATIONS
- )
- log_expectations.extend(
- FP8_MOE_0DOT3_FALLBACK_ROUTE_REQUIRED_LOGS
- )
- rejected_log_expectations.extend(
- FP8_MOE_0DOT3_FALLBACK_ROUTE_REJECTED_LOGS
- )
+ expectations.extend(FP8_MOE_0DOT3_FALLBACK_ROUTE_JSON_EXPECTATIONS)
+ log_expectations.extend(FP8_MOE_0DOT3_FALLBACK_ROUTE_REQUIRED_LOGS)
+ rejected_log_expectations.extend(FP8_MOE_0DOT3_FALLBACK_ROUTE_REJECTED_LOGS)
extra_required_policies = list(args.require_policy)
if args.require_sm70_breakable_graph_route:
extra_required_policies.append("sm70_graph_policy")
@@ -1085,12 +1062,8 @@ def main() -> int:
log_expectations.extend(SM70_BREAKABLE_GRAPH_ROUTE_REQUIRED_LOGS)
if args.require_sm70_flash_v100_0dot3_compile_graph:
extra_required_policies.append("sm70_graph_policy")
- expectations.extend(
- SM70_FLASH_V100_0DOT3_COMPILE_GRAPH_JSON_EXPECTATIONS
- )
- log_expectations.extend(
- SM70_FLASH_V100_0DOT3_COMPILE_GRAPH_REQUIRED_LOGS
- )
+ expectations.extend(SM70_FLASH_V100_0DOT3_COMPILE_GRAPH_JSON_EXPECTATIONS)
+ log_expectations.extend(SM70_FLASH_V100_0DOT3_COMPILE_GRAPH_REQUIRED_LOGS)
rejected_log_expectations.extend(
SM70_FLASH_V100_0DOT3_COMPILE_GRAPH_REJECTED_LOGS
)
@@ -1098,19 +1071,17 @@ def main() -> int:
extra_required_policies.append("sm70_comm_policy")
expectations.extend(SM70_CUSTOM_ALLREDUCE_ROUTE_JSON_EXPECTATIONS)
log_expectations.extend(SM70_CUSTOM_ALLREDUCE_ROUTE_REQUIRED_LOGS)
- rejected_log_expectations.extend(
- SM70_CUSTOM_ALLREDUCE_ROUTE_REJECTED_LOGS
- )
+ rejected_log_expectations.extend(SM70_CUSTOM_ALLREDUCE_ROUTE_REJECTED_LOGS)
if args.require_sm70_all_reduce_sum2_route:
extra_required_policies.append("sm70_comm_policy")
expectations.extend(SM70_ALL_REDUCE_SUM2_ROUTE_JSON_EXPECTATIONS)
log_expectations.extend(SM70_ALL_REDUCE_SUM2_ROUTE_REQUIRED_LOGS)
- log_regex_expectations.extend(
- SM70_ALL_REDUCE_SUM2_ROUTE_REQUIRED_REGEXES
- )
- required_policies = [] if args.require_inventory_complete else list(
- dict.fromkeys(
- list(DEFAULT_REQUIRED_POLICIES) + extra_required_policies
+ log_regex_expectations.extend(SM70_ALL_REDUCE_SUM2_ROUTE_REQUIRED_REGEXES)
+ required_policies = (
+ []
+ if args.require_inventory_complete
+ else list(
+ dict.fromkeys(list(DEFAULT_REQUIRED_POLICIES) + extra_required_policies)
)
)
result = _verify(
@@ -1127,10 +1098,7 @@ def main() -> int:
require_model_quality_pass=args.require_model_quality_pass,
require_inventory_complete=args.require_inventory_complete,
)
- if (
- args.require_awq_moe_safe_route
- or args.require_awq_moe_batched_safe_route
- ):
+ if args.require_awq_moe_safe_route or args.require_awq_moe_batched_safe_route:
awq_moe_safe_tune_gate = _awq_moe_safe_tune_gate(payload)
result["awq_moe_safe_tune_gate"] = awq_moe_safe_tune_gate
if not awq_moe_safe_tune_gate["passed"]:
diff --git a/cmake/patches/sm70_flash_attn_d256_gqa_arch.patch b/cmake/patches/sm70_flash_attn_d256_gqa_arch.patch
index d6d65439a5..8809667dc1 100644
--- a/cmake/patches/sm70_flash_attn_d256_gqa_arch.patch
+++ b/cmake/patches/sm70_flash_attn_d256_gqa_arch.patch
@@ -1211,8 +1211,8 @@ index 0000000..197453f
+ constexpr int kHeadsQ = 6;
+ constexpr int kHeadsKV = 1;
+ constexpr int kTail = 8000;
-+ constexpr int kMinTotalKV = 40000;
-+ constexpr int kMaxTotalKV = 128000;
++ constexpr int kMinTotalKV = 16000;
++ constexpr int kMaxTotalKV = 256000;
+ constexpr int kTotalKVStep = 8000;
+ constexpr int kBlockN = 8192;
+
@@ -1232,7 +1232,7 @@ index 0000000..197453f
+ const int total_kv = static_cast(k.size(1));
+ TORCH_CHECK(total_kv >= kMinTotalKV && total_kv <= kMaxTotalKV
+ && total_kv % kTotalKVStep == 0,
-+ "SM70 GQA architecture requires KV in [40000, 128000] "
++ "SM70 GQA architecture requires KV in [16000, 256000] "
+ "with an 8000-token step, got ",
+ total_kv);
+ const int prefix = total_kv - kTail;
diff --git a/csrc/custom_all_reduce.cuh b/csrc/custom_all_reduce.cuh
index f98aef77f5..a19ffe9e94 100644
--- a/csrc/custom_all_reduce.cuh
+++ b/csrc/custom_all_reduce.cuh
@@ -70,6 +70,7 @@ constexpr int kSm70Tp4PushAllreduceSentinelByte = 0x7f;
constexpr size_t kSm70Tp4PushAllreduceBytes =
8 * kSm70GemmaRmsNormHiddenSize * sizeof(half);
constexpr size_t kSm70Tp4PushAllreduce8KiBBytes = 4096 * sizeof(half);
+constexpr size_t kSm70Tp4PushAllreduceQwen4ExpBytes = 2560 * sizeof(half);
constexpr size_t kSm70Tp4PushAllreduceSignalBytes =
((kSm70Tp4PushAllreduceBlocks * sizeof(uint32_t) + 127) / 128) * 128;
constexpr size_t kSm70Tp4PushAllreduceBufferBytes =
@@ -81,7 +82,10 @@ inline int sm70_tp4_push_allreduce_blocks(size_t bytes) {
if (bytes == kSm70Tp4PushAllreduceBytes) {
return kSm70Tp4PushAllreduceBlocks;
}
- return bytes == kSm70Tp4PushAllreduce8KiBBytes ? 4 : 0;
+ if (bytes == kSm70Tp4PushAllreduce8KiBBytes) {
+ return 4;
+ }
+ return bytes == kSm70Tp4PushAllreduceQwen4ExpBytes ? 3 : 0;
}
inline int sm70_gemma_rms_norm_threads() {
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_fp8_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_fp8_gemm.cu
index 1329091679..290e531181 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_fp8_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_fp8_gemm.cu
@@ -35,22 +35,25 @@ class Sm70MoeFp8IteratorB {
static int const kPackedMacroN = PackedMacroN_;
static constexpr bool kUseMetadataVectorWords = UseMetadataVectorWords_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE FP8 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE FP8 IteratorB expects one contiguous iteration per "
- "64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE FP8 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE FP8 IteratorB expects one contiguous iteration per "
+ "64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE FP8 IteratorB expects 64-column deltas.");
- static_assert(ThreadMap::kElementsPerAccess == kFp8ValuesPerAccess,
- "SM70 Marlin MoE FP8 IteratorB expects two packed FP8 words per "
- "access.");
- static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U8-family IteratorB expects one or more strided "
- "iterations.");
+ static_assert(
+ ThreadMap::kElementsPerAccess == kFp8ValuesPerAccess,
+ "SM70 Marlin MoE FP8 IteratorB expects two packed FP8 words per "
+ "access.");
+ static_assert(
+ ThreadMap::Iterations::kStrided >= 1,
+ "SM70 Marlin MoE U8-family IteratorB expects one or more strided "
+ "iterations.");
static constexpr int kQweightWordStrideWords = kPackedMacroN / kQuantTileN;
struct Params {
@@ -83,12 +86,11 @@ class Sm70MoeFp8IteratorB {
public:
CUTLASS_DEVICE
Sm70MoeFp8IteratorB(Params const& params, uint32_t const* qweight,
- half const* scales, half const*, int thread_id,
- int expert, int k_offset, int n_offset)
+ half const* scales, half const*, int thread_id,
+ int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -130,9 +132,7 @@ class Sm70MoeFp8IteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
@@ -155,8 +155,8 @@ class Sm70MoeFp8IteratorB {
CUTLASS_DEVICE
void cache_metadata_lane_vectors(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- half2 const* scale_vec = reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ half2 const* scale_vec =
+ reinterpret_cast(scales_expert_base_ + metadata_offset);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
scale_cache[1] = scale_vec[1];
@@ -167,8 +167,8 @@ class Sm70MoeFp8IteratorB {
CUTLASS_DEVICE
void cache_metadata_vector_words(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- uint4 const scale_words = *reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ uint4 const scale_words =
+ *reinterpret_cast(scales_expert_base_ + metadata_offset);
half2 const* scale_vec = reinterpret_cast(&scale_words);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
@@ -181,9 +181,8 @@ class Sm70MoeFp8IteratorB {
void cache_current_group_metadata(int group) const {
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
if constexpr (kUseMetadataVectorWords) {
cache_metadata_vector_words(c, group, cache_n);
} else {
@@ -244,8 +243,9 @@ class Sm70MoeFp8IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE FP8 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE FP8 contiguous iteration count.");
uint32_t const qword0 =
load_qword_vector<1>(qweight_ + qweight_base_offset_);
uint32_t const qword1 = load_qword_vector<1>(
@@ -267,9 +267,8 @@ class Sm70MoeFp8IteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
if constexpr (kGroupSize != -1) {
cache_current_group_metadata(scale_group(logical_k_s));
}
@@ -277,10 +276,9 @@ class Sm70MoeFp8IteratorB {
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- uint4 const qwords0 =
- load_qword_vector<4>(qweight_ + qweight_base_s);
- uint4 const qwords1 = load_qword_vector<4>(
- qweight_ + qweight_base_s + kQweightWordStrideWords);
+ uint4 const qwords0 = load_qword_vector<4>(qweight_ + qweight_base_s);
+ uint4 const qwords1 = load_qword_vector<4>(qweight_ + qweight_base_s +
+ kQweightWordStrideWords);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -294,22 +292,17 @@ class Sm70MoeFp8IteratorB {
half2* frag_vec = reinterpret_cast(frag.data() + frag_base);
marlin::dequant(
static_cast(qword0), deq);
- frag_vec[0] =
- __hmul2(deq[0], scale_vec[0]);
- frag_vec[1] =
- __hmul2(deq[1], scale_vec[1]);
+ frag_vec[0] = __hmul2(deq[0], scale_vec[0]);
+ frag_vec[1] = __hmul2(deq[1], scale_vec[1]);
marlin::dequant(
static_cast(qword1), deq);
- frag_vec[2] =
- __hmul2(deq[0], scale_vec[2]);
- frag_vec[3] =
- __hmul2(deq[1], scale_vec[3]);
+ frag_vec[2] = __hmul2(deq[0], scale_vec[2]);
+ frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else if constexpr (ThreadMap::Iterations::kContiguous == 2) {
- uint2 const qwords0 =
- load_qword_vector<2>(qweight_ + qweight_base_s);
- uint2 const qwords1 = load_qword_vector<2>(
- qweight_ + qweight_base_s + kQweightWordStrideWords);
+ uint2 const qwords0 = load_qword_vector<2>(qweight_ + qweight_base_s);
+ uint2 const qwords1 = load_qword_vector<2>(qweight_ + qweight_base_s +
+ kQweightWordStrideWords);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -323,20 +316,17 @@ class Sm70MoeFp8IteratorB {
half2* frag_vec = reinterpret_cast(frag.data() + frag_base);
marlin::dequant(
static_cast(qword0), deq);
- frag_vec[0] =
- __hmul2(deq[0], scale_vec[0]);
- frag_vec[1] =
- __hmul2(deq[1], scale_vec[1]);
+ frag_vec[0] = __hmul2(deq[0], scale_vec[0]);
+ frag_vec[1] = __hmul2(deq[1], scale_vec[1]);
marlin::dequant(
static_cast(qword1), deq);
- frag_vec[2] =
- __hmul2(deq[0], scale_vec[2]);
- frag_vec[3] =
- __hmul2(deq[1], scale_vec[3]);
+ frag_vec[2] = __hmul2(deq[0], scale_vec[2]);
+ frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE FP8 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE FP8 contiguous iteration count.");
uint32_t const qword0 =
load_qword_vector<1>(qweight_ + qweight_base_s);
uint32_t const qword1 = load_qword_vector<1>(
@@ -366,8 +356,7 @@ class Sm70MoeFp8IteratorB {
return;
}
- if constexpr (kGroupSize != -1 &&
- ThreadMap::Iterations::kStrided == 1) {
+ if constexpr (kGroupSize != -1 && ThreadMap::Iterations::kStrided == 1) {
int const first_logical_k = k_offset_ + thread_offset_.strided();
cache_current_group_metadata(scale_group(first_logical_k));
}
@@ -386,18 +375,17 @@ struct Sm70MoeFp8GemmSpec {
using IteratorA = Sm70MoeGatherIteratorA;
template
- using IteratorB =
- Sm70MoeFp8IteratorB;
+ using IteratorB = Sm70MoeFp8IteratorB;
};
-template
using Sm70MoeFp8GemmTraits =
- Sm70MarlinMoeGemmTraits<
- Sm70MoeFp8GemmSpec, CtaM, CtaN, CtaK,
- Warps, WarpM, WarpN, WarpK, GroupSize, PackedMacroN>;
+ Sm70MarlinMoeGemmTraits, CtaM,
+ CtaN, CtaK, Warps, WarpM, WarpN, WarpK, GroupSize,
+ PackedMacroN>;
template
struct Sm70MoeFp8Launcher {
@@ -419,16 +407,16 @@ struct Sm70MoeFp8Launcher {
int64_t size_k;
int requested_split_k;
- template
+ template
torch::Tensor operator()() const {
- using Traits = Sm70MoeFp8GemmTraits;
+ using Traits =
+ Sm70MoeFp8GemmTraits;
return launch_sm70_marlin_moe_gemm(
a, c, b_q_weight, b_scales, b_zeros, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size,
- top_k, mul_topk_weights, size_m, size_n, size_k, requested_split_k);
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ mul_topk_weights, size_m, size_n, size_k, requested_split_k);
}
};
@@ -446,9 +434,10 @@ torch::Tensor sm70_marlin_fp8_gemm(
auto const params = sm70_marlin_moe_auto_stage_params(
"fp8_e4m3", group_size, moe_block_size, top_k, size_m, size_n, size_k);
Sm70CtaGeometry const geometry = params.geometry;
- validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE fp8_e4m3", geometry);
- validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE fp8_e4m3", geometry,
- size_n);
+ validate_sm70_marlin_moe_stage_cta_geometry_supported(
+ "SM70 Marlin MoE fp8_e4m3", geometry);
+ validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE fp8_e4m3",
+ geometry, size_n);
TORCH_CHECK(size_k % geometry.cta_k == 0,
"SM70 Marlin MoE fp8_e4m3 requires K divisible by CTA_K=",
geometry.cta_k, ". Got K=", size_k, ".");
@@ -457,17 +446,45 @@ torch::Tensor sm70_marlin_fp8_gemm(
auto empty_float = torch::empty(
{0}, torch::TensorOptions().dtype(at::kFloat).device(a.device()));
if (params.use_metadata_vector_words) {
- Sm70MoeFp8Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
- return dispatch_sm70_marlin_moe_fp8_geometry(launcher, geometry, params.packed_macro_n, group_size);
+ Sm70MoeFp8Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
+ return dispatch_sm70_marlin_moe_fp8_geometry(
+ launcher, geometry, params.packed_macro_n, group_size);
}
- Sm70MoeFp8Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
- return dispatch_sm70_marlin_moe_fp8_geometry(launcher, geometry, params.packed_macro_n, group_size);
+ Sm70MoeFp8Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
+ return dispatch_sm70_marlin_moe_fp8_geometry(
+ launcher, geometry, params.packed_macro_n, group_size);
}
} // namespace marlin_moe_wna16
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_gemm.cuh b/csrc/moe/marlin_moe_wna16/sm70_marlin_gemm.cuh
index fdc516a3a6..2cd0b71f90 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_gemm.cuh
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_gemm.cuh
@@ -27,22 +27,22 @@
namespace marlin_moe_wna16 {
-using marlin::sm70::Sm70CtaGeometry;
-using marlin::sm70::Sm70MarlinAutoParams;
-using marlin::sm70::Sm70MarlinMoeAutoParamsContext;
-using marlin::sm70::Sm70SplitKPartition;
-using marlin::sm70::Sm70MarlinMmaPipelined;
-using marlin::sm70::Sm70WarpShape;
using marlin::sm70::configure_sm70_dynamic_smem;
using marlin::sm70::kQuantTileK;
using marlin::sm70::kQuantTileN;
+using marlin::sm70::sm70_active_split_k;
using marlin::sm70::sm70_marlin_any_auto_env_is_set;
using marlin::sm70::sm70_marlin_auto_packed_macro_n;
using marlin::sm70::sm70_marlin_auto_params_from_env;
using marlin::sm70::sm70_marlin_cta_geometry_is_supported;
using marlin::sm70::sm70_marlin_default_auto_params;
-using marlin::sm70::sm70_active_split_k;
using marlin::sm70::sm70_splitk_partition;
+using marlin::sm70::Sm70CtaGeometry;
+using marlin::sm70::Sm70MarlinAutoParams;
+using marlin::sm70::Sm70MarlinMmaPipelined;
+using marlin::sm70::Sm70MarlinMoeAutoParamsContext;
+using marlin::sm70::Sm70SplitKPartition;
+using marlin::sm70::Sm70WarpShape;
using marlin::sm70::validate_sm70_marlin_auto_params;
inline constexpr char const* kSupportedSm70MarlinMoeCtaGeometries =
@@ -55,9 +55,9 @@ inline constexpr char const* kSupportedSm70MarlinMoeCtaGeometries =
"geometries are dense-only.";
inline bool sm70_marlin_moe_auto_env_is_set() {
- return sm70_marlin_any_auto_env_is_set(
- "SM70_MARLIN_MOE_CTA_GEOMETRY", "SM70_MARLIN_MOE_SPLIT_K",
- "SM70_MARLIN_MOE_METADATA_CACHE");
+ return sm70_marlin_any_auto_env_is_set("SM70_MARLIN_MOE_CTA_GEOMETRY",
+ "SM70_MARLIN_MOE_SPLIT_K",
+ "SM70_MARLIN_MOE_METADATA_CACHE");
}
inline Sm70MarlinAutoParams sm70_marlin_moe_auto_params_from_env(
@@ -68,16 +68,14 @@ inline Sm70MarlinAutoParams sm70_marlin_moe_auto_params_from_env(
}
inline bool sm70_marlin_moe_try_select_quanttrio_qwen3_6_35b_a3b_awq_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4") != 0 ||
- ctx.group_size != 128 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4") != 0 || ctx.group_size != 128 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -152,8 +150,7 @@ inline bool sm70_marlin_moe_try_select_quanttrio_qwen3_6_35b_a3b_awq_params(
}
return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
- if (ctx.moe_block_size == 64 &&
- (ctx.size_n == 256 || ctx.size_n == 1024)) {
+ if (ctx.moe_block_size == 64 && (ctx.size_n == 256 || ctx.size_n == 1024)) {
return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
@@ -162,16 +159,14 @@ inline bool sm70_marlin_moe_try_select_quanttrio_qwen3_6_35b_a3b_awq_params(
}
inline bool sm70_marlin_moe_try_select_quanttrio_qwen3_5_122b_a10b_awq_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4") != 0 ||
- ctx.group_size != 128 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4") != 0 || ctx.group_size != 128 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -278,16 +273,14 @@ inline bool sm70_marlin_moe_try_select_quanttrio_qwen3_5_122b_a10b_awq_params(
}
inline bool sm70_marlin_moe_try_select_quanttrio_minimax_m2_7_awq_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4") != 0 ||
- ctx.group_size != 128 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4") != 0 || ctx.group_size != 128 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -378,17 +371,16 @@ inline bool sm70_marlin_moe_try_select_quanttrio_minimax_m2_7_awq_params(
return false;
}
-inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+inline bool
+sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_params(
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint8b128") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint8b128") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -400,57 +392,57 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_param
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 256) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1024) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,128,64,8,32,32,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 64, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 512) {
- if (ctx.size_m <= 1) {
- return set_params({32,256,32,4,32,64,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 2048) {
- if (ctx.size_m <= 1) {
- return set_params({32,256,32,4,32,64,32}, 2, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 2, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -460,13 +452,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_param
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1024) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 2048) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -476,13 +468,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_param
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1024) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 2048) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -492,33 +484,33 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_param
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 512) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 2048) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -527,16 +519,14 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_5_122b_a10b_awq_8bit_param
}
inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -548,63 +538,63 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 8) {
- return set_params({32,64,32,4,32,32,16}, 1, false);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 1, false);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 8) {
- return set_params({32,64,32,4,32,32,16}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,64,16}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, false);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,64,16}, 2, false);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, false);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 64, 16}, 2, false);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, false);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,256,32,4,32,64,32}, 4, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 4, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -614,16 +604,16 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 32) {
- return set_params({32,256,64,8,32,64,32}, 1, false);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, false);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -633,13 +623,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
}
@@ -649,36 +639,36 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 2048) {
- return set_params({64,128,32,4,64,64,16}, 1, false);
- }
- return set_params({64,128,32,8,32,32,32}, 1, true);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 128, 32, 4, 64, 64, 16}, 1, false);
+ }
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -686,17 +676,16 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_4bit_params(
return false;
}
-inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+inline bool
+sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params(
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "nvfp4") != 0 ||
- ctx.group_size != 16 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "nvfp4") != 0 || ctx.group_size != 16 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -708,63 +697,63 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,64,4,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 64, 4, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, false);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, false);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,64,4,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 64, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,64,32,4,32,32,16}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,32,32}, 4, true);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 32, 32}, 4, true);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 4, false);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, false);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -774,16 +763,16 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,128,32,4,32,32,32}, 1, false);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 32) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -793,13 +782,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,256,64,8,32,64,32}, 1, false);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, false);
}
}
}
@@ -809,45 +798,45 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 16384) {
- return set_params({64,64,32,4,32,32,32}, 1, true);
- }
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 64, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 2048) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({64,128,32,8,32,32,32}, 1, true);
+ if (ctx.size_m <= 2048) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 2048) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
- }
- return set_params({64,256,64,8,64,64,32}, 1, false);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
+ }
+ return set_params({64, 256, 64, 8, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
}
@@ -855,17 +844,16 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_6_35b_a3b_awq_nvfp4_params
return false;
}
-inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+inline bool
+sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params(
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4b8") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4b8") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -877,63 +865,63 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 10) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 10) {
- return set_params({32,128,64,4,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 128, 64, 4, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,64,32,4,32,32,16}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,64,16}, 2, true);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 64, 16}, 2, true);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,256,32,4,32,64,32}, 4, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 4, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -943,13 +931,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -959,23 +947,23 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,8,32,32,32}, 1, false);
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -985,33 +973,33 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,4,32,64,32}, 1, true);
+ return set_params({64, 128, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -1019,17 +1007,16 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_4bit_params
return false;
}
-inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+inline bool
+sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params(
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint8b128") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint8b128") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1041,63 +1028,63 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 10) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 10) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,64,32,4,32,32,16}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,64,16}, 2, true);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 64, 16}, 2, true);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,256,32,4,32,64,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -1107,13 +1094,13 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
}
@@ -1123,23 +1110,23 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,8,32,32,32}, 1, false);
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -1149,33 +1136,33 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,8,32,32,32}, 1, false);
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -1184,16 +1171,14 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_qwen3_coder_next_awq_8bit_params
}
inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "nvfp4") != 0 ||
- ctx.group_size != 16 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "nvfp4") != 0 || ctx.group_size != 16 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1205,63 +1190,63 @@ inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 192) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, false);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, false);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 384) {
- if (ctx.size_m <= 8) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 1536) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, false);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 384) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,32,4,32,64,16}, 2, true);
- }
- return set_params({32,128,32,4,32,64,16}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 2, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 768) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,64,16}, 4, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,32,4,32,64,16}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 4, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 4, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 3072) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- return set_params({32,128,32,4,32,32,32}, 2, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 2, true);
}
}
}
@@ -1271,19 +1256,19 @@ inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 1536) {
- if (ctx.size_m <= 256) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 3072) {
- if (ctx.size_m <= 32) {
- return set_params({32,128,32,4,32,32,32}, 4, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
}
@@ -1293,13 +1278,13 @@ inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 1536) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 3072) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
}
@@ -1309,42 +1294,42 @@ inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 192) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
- }
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 384) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 5120) {
if (ctx.size_k == 1536) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 384) {
- if (ctx.size_m <= 2048) {
- return set_params({64,128,32,8,32,32,32}, 1, false);
- }
- return set_params({64,128,32,8,32,32,32}, 1, true);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
+ }
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 768) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 5120) {
if (ctx.size_n == 3072) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
}
@@ -1353,16 +1338,14 @@ inline bool sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
}
inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "nvfp4") != 0 ||
- ctx.group_size != 16 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "nvfp4") != 0 || ctx.group_size != 16 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1374,63 +1357,63 @@ inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 192) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 384) {
- if (ctx.size_m <= 8) {
- return set_params({32,256,32,4,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,256,32,4,32,64,32}, 1, false);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, false);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1536) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,32,4,32,64,16}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 384) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, false);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,32,4,32,64,16}, 2, true);
- }
- return set_params({32,128,32,4,32,64,16}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, false);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 2, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 768) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 4, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,32,4,32,64,16}, 1, true);
- }
- return set_params({32,128,32,4,32,64,16}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 64, 16}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 3072) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 4, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
}
@@ -1440,19 +1423,19 @@ inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1536) {
- if (ctx.size_m <= 256) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 256) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 3072) {
- if (ctx.size_m <= 32) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -1462,13 +1445,13 @@ inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1536) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 3072) {
- return set_params({32,256,64,8,32,64,32}, 1, false);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, false);
}
}
}
@@ -1478,45 +1461,45 @@ inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 192) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
- }
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 384) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 3072) {
if (ctx.size_k == 1536) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
- }
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 384) {
- if (ctx.size_m <= 2048) {
- return set_params({64,128,32,8,32,32,32}, 1, true);
- }
- return set_params({64,128,32,8,32,32,32}, 1, false);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
+ }
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 768) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 3072) {
if (ctx.size_n == 3072) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
}
@@ -1525,16 +1508,14 @@ inline bool sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
}
inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "nvfp4") != 0 ||
- ctx.group_size != 16 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "nvfp4") != 0 || ctx.group_size != 16 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1546,63 +1527,63 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 8) {
- return set_params({32,64,64,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 64, 64, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 8) {
- return set_params({32,64,64,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 256) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 64, 64, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 256) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 8) {
- return set_params({32,128,64,4,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 8) {
+ return set_params({32, 128, 64, 4, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,64,32,4,32,32,16}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,32,32}, 4, true);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 32, 32}, 4, true);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 4, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 4, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -1612,16 +1593,16 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 32) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -1631,13 +1612,13 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
}
@@ -1647,48 +1628,48 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 16384) {
- return set_params({64,64,32,4,32,32,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 64, 32, 4, 32, 32, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 16384) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 16384) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
// top_k=8
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 2048) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({64,128,32,8,32,32,32}, 1, true);
+ if (ctx.size_m <= 2048) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 2048) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
- }
- return set_params({64,256,64,8,64,64,32}, 1, false);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
+ }
+ return set_params({64, 256, 64, 8, 64, 64, 32}, 1, false);
}
}
if (ctx.top_k == 8 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 2048) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 2048) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
}
@@ -1696,17 +1677,16 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
return false;
}
-inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+inline bool
+sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_params(
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "nvfp4") != 0 ||
- ctx.group_size != 16 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "nvfp4") != 0 || ctx.group_size != 16 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1718,69 +1698,69 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- if (ctx.size_m <= 10) {
- return set_params({32,128,32,4,32,32,32}, 1, false);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- if (ctx.size_m <= 10) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,256,32,4,32,64,32}, 1, true);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 10) {
- return set_params({32,256,64,8,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 320) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
- }
- return set_params({32,128,32,4,32,32,32}, 1, false);
+ if (ctx.size_m <= 10) {
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 320) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, false);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- if (ctx.size_m <= 1) {
- return set_params({32,64,32,4,32,32,16}, 8, false);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,64,8,32,64,16}, 2, true);
- }
- return set_params({32,128,128,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 64, 32, 4, 32, 32, 16}, 8, false);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 64, 8, 32, 64, 16}, 2, true);
+ }
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,32,4,32,32,32}, 8, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- return set_params({32,256,64,8,32,64,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 8, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ return set_params({32, 256, 64, 8, 32, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- if (ctx.size_m <= 1) {
- return set_params({32,128,128,8,32,64,32}, 1, true);
- }
- if (ctx.size_m <= 32) {
- return set_params({32,256,32,4,32,64,32}, 1, false);
- }
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ if (ctx.size_m <= 1) {
+ return set_params({32, 128, 128, 8, 32, 64, 32}, 1, true);
+ }
+ if (ctx.size_m <= 32) {
+ return set_params({32, 256, 32, 4, 32, 64, 32}, 1, false);
+ }
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -1790,13 +1770,13 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({32,128,32,4,32,32,32}, 1, true);
+ return set_params({32, 128, 32, 4, 32, 32, 32}, 1, true);
}
}
}
@@ -1806,23 +1786,23 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,8,32,32,32}, 1, false);
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, false);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
}
}
}
@@ -1832,36 +1812,36 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_
// top_k=1
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 64) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 128) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 1 && ctx.size_n == 2048) {
if (ctx.size_k == 512) {
- if (ctx.size_m <= 20480) {
- return set_params({64,256,32,4,64,64,32}, 1, false);
- }
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ if (ctx.size_m <= 20480) {
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, false);
+ }
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
// top_k=10
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 128) {
- return set_params({64,128,32,8,32,32,32}, 1, true);
+ return set_params({64, 128, 32, 8, 32, 32, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 256) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
if (ctx.top_k == 10 && ctx.size_k == 2048) {
if (ctx.size_n == 1024) {
- return set_params({64,256,32,4,64,64,32}, 1, true);
+ return set_params({64, 256, 32, 4, 64, 64, 32}, 1, true);
}
}
}
@@ -1870,16 +1850,14 @@ inline bool sm70_marlin_moe_try_select_nvidia_qwen3_next_80b_a3b_thinking_nvfp4_
}
inline bool sm70_marlin_moe_try_select_cyankiwi_minimax_m2_7_awq_4bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4b8") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4b8") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -1995,16 +1973,14 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_minimax_m2_7_awq_4bit_params(
}
inline bool sm70_marlin_moe_try_select_cyankiwi_glm_4_7_awq_4bit_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4b8") != 0 ||
- ctx.group_size != 32 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4b8") != 0 || ctx.group_size != 32 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -2108,16 +2084,14 @@ inline bool sm70_marlin_moe_try_select_cyankiwi_glm_4_7_awq_4bit_params(
}
inline bool sm70_marlin_moe_try_select_quanttrio_glm_4_7_awq_params(
- Sm70MarlinMoeAutoParamsContext const& ctx,
- Sm70MarlinAutoParams& params) {
+ Sm70MarlinMoeAutoParamsContext const& ctx, Sm70MarlinAutoParams& params) {
if (ctx.quant_format == nullptr ||
- std::strcmp(ctx.quant_format, "uint4") != 0 ||
- ctx.group_size != 128 || ctx.size_m <= 0) {
+ std::strcmp(ctx.quant_format, "uint4") != 0 || ctx.group_size != 128 ||
+ ctx.size_m <= 0) {
return false;
}
- auto const set_params = [&](Sm70CtaGeometry geometry,
- int requested_split_k,
+ auto const set_params = [&](Sm70CtaGeometry geometry, int requested_split_k,
bool use_metadata_vector_words) {
params = {geometry, requested_split_k, use_metadata_vector_words,
ctx.packed_macro_n};
@@ -2206,20 +2180,21 @@ inline bool sm70_marlin_moe_try_select_quanttrio_glm_4_7_awq_params(
}
inline Sm70MarlinAutoParams sm70_marlin_moe_auto_stage_params(
- char const* quant_format, int64_t group_size,
- int64_t moe_block_size, int64_t top_k, int64_t size_m,
- int64_t size_n, int64_t size_k) {
+ char const* quant_format, int64_t group_size, int64_t moe_block_size,
+ int64_t top_k, int64_t size_m, int64_t size_n, int64_t size_k) {
Sm70MarlinMoeAutoParamsContext const ctx{
- quant_format, group_size, moe_block_size, top_k, size_m, size_n, size_k,
- sm70_marlin_auto_packed_macro_n(size_n)};
+ quant_format, group_size,
+ moe_block_size, top_k,
+ size_m, size_n,
+ size_k, sm70_marlin_auto_packed_macro_n(size_n)};
if (sm70_marlin_moe_auto_env_is_set()) {
return sm70_marlin_moe_auto_params_from_env(ctx);
}
Sm70MarlinAutoParams params{};
- if (sm70_marlin_moe_try_select_quanttrio_qwen3_6_35b_a3b_awq_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_quanttrio_qwen3_6_35b_a3b_awq_params(ctx,
+ params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
@@ -2228,8 +2203,8 @@ inline Sm70MarlinAutoParams sm70_marlin_moe_auto_stage_params(
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_quanttrio_minimax_m2_7_awq_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_quanttrio_minimax_m2_7_awq_params(ctx,
+ params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
@@ -2258,18 +2233,17 @@ inline Sm70MarlinAutoParams sm70_marlin_moe_auto_stage_params(
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_nvidia_glm_4_7_nvfp4_params(ctx, params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_nvidia_minimax_m2_7_nvfp4_params(ctx,
+ params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_nvidia_qwen3_6_35b_a3b_nvfp4_params(ctx,
+ params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
@@ -2283,13 +2257,12 @@ inline Sm70MarlinAutoParams sm70_marlin_moe_auto_stage_params(
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_cyankiwi_glm_4_7_awq_4bit_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_cyankiwi_glm_4_7_awq_4bit_params(ctx,
+ params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
- if (sm70_marlin_moe_try_select_quanttrio_glm_4_7_awq_params(
- ctx, params)) {
+ if (sm70_marlin_moe_try_select_quanttrio_glm_4_7_awq_params(ctx, params)) {
validate_sm70_marlin_auto_params("MoE", params);
return params;
}
@@ -2303,46 +2276,44 @@ inline bool sm70_marlin_moe_cta_geometry_is_supported(
sm70_marlin_cta_geometry_is_supported(geometry);
}
-inline void validate_sm70_marlin_moe_stage_cta_geometry_supported(char const* op_name,
- Sm70CtaGeometry geometry) {
+inline void validate_sm70_marlin_moe_stage_cta_geometry_supported(
+ char const* op_name, Sm70CtaGeometry geometry) {
TORCH_CHECK(sm70_marlin_moe_cta_geometry_is_supported(geometry),
"Unsupported SM70 Marlin MoE CTA geometry for ", op_name, ": ",
- geometry.cta_m, "x", geometry.cta_n, "x", geometry.cta_k,
- "x", geometry.warps, "x", geometry.warp_m, "x",
- geometry.warp_n, "x", geometry.warp_k,
- ". Supported geometries are ",
+ geometry.cta_m, "x", geometry.cta_n, "x", geometry.cta_k, "x",
+ geometry.warps, "x", geometry.warp_m, "x", geometry.warp_n, "x",
+ geometry.warp_k, ". Supported geometries are ",
kSupportedSm70MarlinMoeCtaGeometries, ".");
}
-inline void validate_sm70_marlin_moe_stage_cta_n_alignment(char const* op_name,
- Sm70CtaGeometry geometry,
- int64_t size_n) {
+inline void validate_sm70_marlin_moe_stage_cta_n_alignment(
+ char const* op_name, Sm70CtaGeometry geometry, int64_t size_n) {
TORCH_CHECK(
size_n % geometry.cta_n == 0 && size_n % kQuantTileN == 0,
"SM70 Marlin MoE requires size_n divisible by both CTA_N and 64 for ",
- op_name, " with CTA geometry ", geometry.cta_m, "x", geometry.cta_n,
- "x", geometry.cta_k, "x", geometry.warps, "x", geometry.warp_m,
- "x", geometry.warp_n, "x", geometry.warp_k, ". Got size_n = ",
- size_n, ".");
+ op_name, " with CTA geometry ", geometry.cta_m, "x", geometry.cta_n, "x",
+ geometry.cta_k, "x", geometry.warps, "x", geometry.warp_m, "x",
+ geometry.warp_n, "x", geometry.warp_k, ". Got size_n = ", size_n, ".");
}
template
-torch::Tensor dispatch_sm70_marlin_moe_group_size(
- Launcher const& launcher, int64_t group_size, char const* quant_name) {
+torch::Tensor dispatch_sm70_marlin_moe_group_size(Launcher const& launcher,
+ int64_t group_size,
+ char const* quant_name) {
switch (group_size) {
case -1:
- return launcher.template operator()();
+ return launcher.template operator()();
case 32:
- return launcher.template operator()();
+ return launcher.template operator()();
case 64:
- return launcher.template operator()();
+ return launcher.template operator()();
case 128:
- return launcher.template operator()();
+ return launcher.template operator()();
default:
TORCH_CHECK(false, "SM70 Marlin MoE ", quant_name,
" supports only group_size -1, 32, 64, or 128. Got ",
@@ -2357,17 +2328,17 @@ torch::Tensor dispatch_sm70_marlin_moe_group_size_with_group32(
Launcher const& launcher, int64_t group_size, char const* quant_name) {
switch (group_size) {
case -1:
- return launcher.template operator()();
+ return launcher.template operator()();
case 32:
- return launcher.template operator()();
+ return launcher.template operator()();
case 64:
- return launcher.template operator()();
+ return launcher.template operator()();
case 128:
- return launcher.template operator()();
+ return launcher.template operator()();
default:
TORCH_CHECK(false, "SM70 Marlin MoE ", quant_name,
" supports only group_size -1, 32, 64, or 128. Got ",
@@ -2378,15 +2349,15 @@ torch::Tensor dispatch_sm70_marlin_moe_group_size_with_group32(
template
-torch::Tensor dispatch_sm70_marlin_moe_fp8_group_size(
- Launcher const& launcher, int64_t group_size) {
+torch::Tensor dispatch_sm70_marlin_moe_fp8_group_size(Launcher const& launcher,
+ int64_t group_size) {
switch (group_size) {
case -1:
- return launcher.template operator()();
+ return launcher.template operator()();
case 128:
- return launcher.template operator()();
+ return launcher.template operator()();
default:
TORCH_CHECK(false,
"SM70 Marlin MoE fp8_e4m3 supports only group_size -1 "
@@ -2448,10 +2419,9 @@ struct Sm70MarlinMoeFp8GroupSizeDispatchLauncher {
template
torch::Tensor operator()() const {
- return dispatch_sm70_marlin_moe_fp8_group_size(
- inner, group_size);
+ return dispatch_sm70_marlin_moe_fp8_group_size<
+ CtaM, CtaN, CtaK, Warps, WarpM, WarpN, WarpK, PackedMacroN>(inner,
+ group_size);
}
};
@@ -2465,59 +2435,59 @@ struct Sm70MarlinMoeFixedGroupSizeDispatchLauncher {
int WarpK, int PackedMacroN>
torch::Tensor operator()() const {
return dispatch_sm70_marlin_moe_fixed_group_size<
- CtaM, CtaN, CtaK, Warps, WarpM, WarpN, WarpK, GroupSize,
- PackedMacroN>(inner, group_size, quant_name);
+ CtaM, CtaN, CtaK, Warps, WarpM, WarpN, WarpK, GroupSize, PackedMacroN>(
+ inner, group_size, quant_name);
}
};
template
-torch::Tensor dispatch_sm70_marlin_moe_cta_geometry(
- Launcher const& launcher, Sm70CtaGeometry geometry, int packed_macro_n,
- char const* quant_name) {
-#define DISPATCH_SM70_MOE_PACKED_MACRO_N(CM, CN, CK, W, WM, WN, WK, PMN) \
+torch::Tensor dispatch_sm70_marlin_moe_cta_geometry(Launcher const& launcher,
+ Sm70CtaGeometry geometry,
+ int packed_macro_n,
+ char const* quant_name) {
+#define DISPATCH_SM70_MOE_PACKED_MACRO_N(CM, CN, CK, W, WM, WN, WK, PMN) \
if (packed_macro_n == PMN) { \
return launcher.template operator()(); \
}
-#define DISPATCH_SM70_MOE_GEOMETRY(CM, CN, CK, W, WM, WN, WK, PMN) \
- if (geometry.cta_m == CM && geometry.cta_n == CN && \
- geometry.cta_k == CK && geometry.warps == W && \
- geometry.warp_m == WM && geometry.warp_n == WN && \
- geometry.warp_k == WK) { \
- DISPATCH_SM70_MOE_PACKED_MACRO_N(CM, CN, CK, W, WM, WN, WK, PMN) \
- }
-
-#define FOR_EACH_SM70_MOE_GEOMETRY(M) \
- M(32, 64, 32, 4, 32, 32, 16, 128) \
- M(32, 64, 32, 4, 32, 32, 16, 256) \
- M(32, 64, 64, 4, 32, 32, 32, 128) \
- M(32, 64, 64, 4, 32, 32, 32, 256) \
- M(32, 128, 32, 4, 32, 32, 32, 128) \
- M(32, 128, 32, 4, 32, 32, 32, 256) \
- M(32, 128, 32, 4, 32, 64, 16, 128) \
- M(32, 128, 32, 4, 32, 64, 16, 256) \
- M(32, 128, 64, 4, 32, 64, 32, 128) \
- M(32, 128, 64, 4, 32, 64, 32, 256) \
- M(32, 128, 64, 8, 32, 32, 32, 128) \
- M(32, 128, 64, 8, 32, 32, 32, 256) \
- M(32, 128, 64, 8, 32, 64, 16, 128) \
- M(32, 128, 64, 8, 32, 64, 16, 256) \
- M(32, 128, 128, 8, 32, 64, 32, 128) \
- M(32, 128, 128, 8, 32, 64, 32, 256) \
- M(32, 256, 32, 4, 32, 64, 32, 256) \
- M(32, 256, 64, 8, 32, 64, 32, 256) \
- M(64, 64, 32, 4, 32, 32, 32, 64) \
- M(64, 64, 32, 4, 32, 32, 32, 128) \
- M(64, 64, 32, 4, 32, 32, 32, 256) \
- M(64, 128, 32, 4, 32, 64, 32, 128) \
- M(64, 128, 32, 4, 32, 64, 32, 256) \
- M(64, 128, 32, 4, 64, 64, 16, 128) \
- M(64, 128, 32, 4, 64, 64, 16, 256) \
- M(64, 128, 32, 8, 32, 32, 32, 128) \
- M(64, 128, 32, 8, 32, 32, 32, 256) \
- M(64, 128, 64, 4, 64, 64, 32, 128) \
- M(64, 128, 64, 4, 64, 64, 32, 256) \
- M(64, 256, 32, 4, 64, 64, 32, 256) \
+#define DISPATCH_SM70_MOE_GEOMETRY(CM, CN, CK, W, WM, WN, WK, PMN) \
+ if (geometry.cta_m == CM && geometry.cta_n == CN && geometry.cta_k == CK && \
+ geometry.warps == W && geometry.warp_m == WM && geometry.warp_n == WN && \
+ geometry.warp_k == WK) { \
+ DISPATCH_SM70_MOE_PACKED_MACRO_N(CM, CN, CK, W, WM, WN, WK, PMN) \
+ }
+
+#define FOR_EACH_SM70_MOE_GEOMETRY(M) \
+ M(32, 64, 32, 4, 32, 32, 16, 128) \
+ M(32, 64, 32, 4, 32, 32, 16, 256) \
+ M(32, 64, 64, 4, 32, 32, 32, 128) \
+ M(32, 64, 64, 4, 32, 32, 32, 256) \
+ M(32, 128, 32, 4, 32, 32, 32, 128) \
+ M(32, 128, 32, 4, 32, 32, 32, 256) \
+ M(32, 128, 32, 4, 32, 64, 16, 128) \
+ M(32, 128, 32, 4, 32, 64, 16, 256) \
+ M(32, 128, 64, 4, 32, 64, 32, 128) \
+ M(32, 128, 64, 4, 32, 64, 32, 256) \
+ M(32, 128, 64, 8, 32, 32, 32, 128) \
+ M(32, 128, 64, 8, 32, 32, 32, 256) \
+ M(32, 128, 64, 8, 32, 64, 16, 128) \
+ M(32, 128, 64, 8, 32, 64, 16, 256) \
+ M(32, 128, 128, 8, 32, 64, 32, 128) \
+ M(32, 128, 128, 8, 32, 64, 32, 256) \
+ M(32, 256, 32, 4, 32, 64, 32, 256) \
+ M(32, 256, 64, 8, 32, 64, 32, 256) \
+ M(64, 64, 32, 4, 32, 32, 32, 64) \
+ M(64, 64, 32, 4, 32, 32, 32, 128) \
+ M(64, 64, 32, 4, 32, 32, 32, 256) \
+ M(64, 128, 32, 4, 32, 64, 32, 128) \
+ M(64, 128, 32, 4, 32, 64, 32, 256) \
+ M(64, 128, 32, 4, 64, 64, 16, 128) \
+ M(64, 128, 32, 4, 64, 64, 16, 256) \
+ M(64, 128, 32, 8, 32, 32, 32, 128) \
+ M(64, 128, 32, 8, 32, 32, 32, 256) \
+ M(64, 128, 64, 4, 64, 64, 32, 128) \
+ M(64, 128, 64, 4, 64, 64, 32, 256) \
+ M(64, 256, 32, 4, 64, 64, 32, 256) \
M(64, 256, 64, 8, 64, 64, 32, 256)
FOR_EACH_SM70_MOE_GEOMETRY(DISPATCH_SM70_MOE_GEOMETRY)
@@ -2537,8 +2507,8 @@ torch::Tensor dispatch_sm70_marlin_moe_geometry(Launcher const& launcher,
int64_t group_size,
char const* quant_name) {
return dispatch_sm70_marlin_moe_cta_geometry(
- Sm70MarlinMoeGroupSizeDispatchLauncher{
- launcher, group_size, quant_name},
+ Sm70MarlinMoeGroupSizeDispatchLauncher{launcher, group_size,
+ quant_name},
geometry, packed_macro_n, quant_name);
}
@@ -2547,18 +2517,18 @@ torch::Tensor dispatch_sm70_marlin_moe_geometry_with_group32(
Launcher const& launcher, Sm70CtaGeometry geometry, int packed_macro_n,
int64_t group_size, char const* quant_name) {
return dispatch_sm70_marlin_moe_cta_geometry(
- Sm70MarlinMoeGroupSize32DispatchLauncher{
- launcher, group_size, quant_name},
+ Sm70MarlinMoeGroupSize32DispatchLauncher{launcher, group_size,
+ quant_name},
geometry, packed_macro_n, quant_name);
}
template
-torch::Tensor dispatch_sm70_marlin_moe_fp8_geometry(
- Launcher const& launcher, Sm70CtaGeometry geometry, int packed_macro_n,
- int64_t group_size) {
+torch::Tensor dispatch_sm70_marlin_moe_fp8_geometry(Launcher const& launcher,
+ Sm70CtaGeometry geometry,
+ int packed_macro_n,
+ int64_t group_size) {
return dispatch_sm70_marlin_moe_cta_geometry(
- Sm70MarlinMoeFp8GroupSizeDispatchLauncher{launcher,
- group_size},
+ Sm70MarlinMoeFp8GroupSizeDispatchLauncher{launcher, group_size},
geometry, packed_macro_n, "fp8_e4m3");
}
@@ -2603,8 +2573,8 @@ class Sm70MoeGatherIteratorA {
using Element = cutlass::half_t;
using Layout = cutlass::layout::RowMajor;
using TensorCoord = cutlass::MatrixCoord;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
+ using Fragment = cutlass::Array;
struct Params {
int lda;
int moe_block_size;
@@ -2689,9 +2659,8 @@ class Sm70MoeGatherIteratorA {
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const local_row =
- local_m_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const local_row = local_m_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
int const route_row = moe_block_ * params_.moe_block_size + local_row;
int sorted_id = -1;
@@ -2699,20 +2668,17 @@ class Sm70MoeGatherIteratorA {
route_row < params_.padded_tokens;
if (valid_row) {
sorted_id = sorted_token_ids_[route_row];
- valid_row =
- sorted_id >= 0 && sorted_id < params_.expanded_token_count;
+ valid_row = sorted_id >= 0 && sorted_id < params_.expanded_token_count;
}
int const token_row = valid_row ? (sorted_id / params_.top_k) : 0;
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const logical_k =
- k_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
- int const frag_base =
- (c + s * ThreadMap::Iterations::kContiguous) *
- ThreadMap::kElementsPerAccess;
+ int const logical_k = k_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
+ int const frag_base = (c + s * ThreadMap::Iterations::kContiguous) *
+ ThreadMap::kElementsPerAccess;
bool const valid = valid_row && logical_k < params_.lda;
CUTLASS_PRAGMA_UNROLL
@@ -2754,8 +2720,8 @@ struct Sm70MarlinMoeGemmTraits {
using LayoutB = cutlass::layout::RowMajor;
using LayoutC = cutlass::layout::RowMajor;
using ThreadblockShape = cutlass::gemm::GemmShape;
- using WarpShape =
- typename Sm70WarpShape::Type;
+ using WarpShape = typename Sm70WarpShape::Type;
static_assert(WarpShape::kM <= 64 && WarpShape::kN <= 64,
"SM70 Marlin MoE keeps per-warp M/N no larger than 64.");
using InstructionShape = cutlass::gemm::GemmShape<8, 8, 4>;
@@ -2763,13 +2729,16 @@ struct Sm70MarlinMoeGemmTraits {
ThreadblockShape, WarpShape, InstructionShape, ElementA, LayoutA,
ElementB, LayoutB, ElementAccumulator, LayoutC,
cutlass::arch::OpClassTensorOp, 2, cutlass::arch::OpMultiplyAdd>;
- static_assert(MmaCore::kThreads == Warps * 32,
- "SM70 Marlin MoE launch threads must match CUTLASS warp count.");
- using IteratorA = typename Spec::template IteratorA<
- ThreadblockShape, typename MmaCore::IteratorThreadMapA>;
- using IteratorB = typename Spec::template IteratorB<
- ThreadblockShape, typename MmaCore::IteratorThreadMapB, GroupSize,
- PackedMacroN>;
+ static_assert(
+ MmaCore::kThreads == Warps * 32,
+ "SM70 Marlin MoE launch threads must match CUTLASS warp count.");
+ using IteratorA =
+ typename Spec::template IteratorA;
+ using IteratorB =
+ typename Spec::template IteratorB;
using Mma = Sm70MarlinMmaPipelined<
ThreadblockShape, IteratorA, typename MmaCore::SmemIteratorA, IteratorB,
typename MmaCore::SmemIteratorB, ElementAccumulator, LayoutC,
@@ -2818,11 +2787,11 @@ class Sm70MoeScatterEpilogue {
typename SharedLoadIterator::Fragment const& frag,
int32_t const* __restrict__ sorted_token_ids,
float const* __restrict__ topk_weights,
- cutlass::half_t* __restrict__ c,
- int n, int moe_block, int local_m_offset,
- int moe_block_size, int expanded_token_count,
- int padded_tokens, bool mul_topk_weights,
- bool atomic_store, float output_scale) const {
+ cutlass::half_t* __restrict__ c, int n, int moe_block,
+ int local_m_offset, int moe_block_size,
+ int expanded_token_count, int padded_tokens,
+ bool mul_topk_weights, bool atomic_store,
+ float output_scale) const {
float const* frag_ptr = reinterpret_cast(&frag);
half* c_half = reinterpret_cast(c);
int const thread_start_row = destination_iterator.thread_start_row();
@@ -2838,20 +2807,17 @@ class Sm70MoeScatterEpilogue {
int const frag_row_idx =
row + ThreadMap::Iterations::kRow *
(group + ThreadMap::Iterations::kGroup * cluster);
- int const row_offset =
- row * ThreadMap::Delta::kRow +
- group * ThreadMap::Delta::kGroup +
- cluster * ThreadMap::Delta::kCluster;
- int const local_row =
- local_m_offset + thread_start_row + row_offset;
+ int const row_offset = row * ThreadMap::Delta::kRow +
+ group * ThreadMap::Delta::kGroup +
+ cluster * ThreadMap::Delta::kCluster;
+ int const local_row = local_m_offset + thread_start_row + row_offset;
int const route_row = moe_block * moe_block_size + local_row;
bool valid_row =
local_row < moe_block_size && route_row < padded_tokens;
int sorted_id = -1;
if (valid_row) {
sorted_id = sorted_token_ids[route_row];
- valid_row =
- sorted_id >= 0 && sorted_id < expanded_token_count;
+ valid_row = sorted_id >= 0 && sorted_id < expanded_token_count;
}
float const route_scale =
(valid_row && mul_topk_weights) ? topk_weights[sorted_id] : 1.0f;
@@ -2896,8 +2862,7 @@ class Sm70MoeScatterEpilogue {
int const warp_mn = warp_idx % (WarpCount::kM * WarpCount::kN);
int const warp_m = warp_mn % WarpCount::kM;
int const warp_n = warp_mn / WarpCount::kM;
- cutlass::MatrixCoord warp_offset{warp_k * WarpCount::kM + warp_m,
- warp_n};
+ cutlass::MatrixCoord warp_offset{warp_k * WarpCount::kM + warp_m, warp_n};
warp_tile_iterator_.add_tile_offset(warp_offset);
}
@@ -2906,11 +2871,11 @@ class Sm70MoeScatterEpilogue {
AccumulatorTile const& accumulators,
int32_t const* __restrict__ sorted_token_ids,
float const* __restrict__ topk_weights,
- cutlass::half_t* __restrict__ c,
- int n, int moe_block, int local_m_offset,
- int moe_block_size, int expanded_token_count,
- int padded_tokens, bool mul_topk_weights,
- bool atomic_store, float output_scale = 1.0f) {
+ cutlass::half_t* __restrict__ c, int n, int moe_block,
+ int local_m_offset, int moe_block_size,
+ int expanded_token_count, int padded_tokens,
+ bool mul_topk_weights, bool atomic_store,
+ float output_scale = 1.0f) {
AccumulatorFragmentIterator accum_fragment_iterator(accumulators);
CUTLASS_PRAGMA_UNROLL
@@ -2956,19 +2921,19 @@ class Sm70MoeScatterEpilogue {
};
template
-__global__ __launch_bounds__(Traits::MmaCore::kThreads, 1)
-void sm70_marlin_moe_gemm_kernel(
+__global__
+__launch_bounds__(Traits::MmaCore::kThreads, 1) void sm70_marlin_moe_gemm_kernel(
cutlass::half_t const* __restrict__ a,
uint32_t const* __restrict__ b_q_weight,
typename Traits::GemmSpec::ScaleElement const* __restrict__ b_scales,
typename Traits::GemmSpec::ZeroElement const* __restrict__ b_zeros,
- float const* __restrict__ global_scale,
- cutlass::half_t* __restrict__ c,
+ float const* __restrict__ global_scale, cutlass::half_t* __restrict__ c,
int32_t const* __restrict__ sorted_token_ids,
int32_t const* __restrict__ expert_ids,
int32_t const* __restrict__ num_tokens_past_padded,
float const* __restrict__ topk_weights, int moe_block_size, int top_k,
- bool mul_topk_weights, int m, int n, int k, int lda, int requested_split_k) {
+ bool mul_topk_weights, int m, int n, int k, int lda,
+ int requested_split_k) {
using Mma = typename Traits::Mma;
using Epilogue = Sm70MoeScatterEpilogue;
constexpr int CtaM = Traits::ThreadblockShape::kM;
@@ -3002,8 +2967,8 @@ void sm70_marlin_moe_gemm_kernel(
int partition_k = k;
if constexpr (SplitK) {
Sm70SplitKPartition const partition =
- sm70_splitk_partition(
- k, requested_split_k, int(blockIdx.z));
+ sm70_splitk_partition(k, requested_split_k,
+ int(blockIdx.z));
if (partition.partition_k == 0) {
return;
}
@@ -3014,8 +2979,8 @@ void sm70_marlin_moe_gemm_kernel(
int const n_offset = int(blockIdx.y) * CtaN;
typename Mma::IteratorA iterator_A(
- typename Mma::IteratorA::Params(lda, moe_block_size, top_k, m,
- m * top_k, padded_tokens),
+ typename Mma::IteratorA::Params(lda, moe_block_size, top_k, m, m * top_k,
+ padded_tokens),
a, sorted_token_ids, thread_idx, moe_block, local_m_offset, k_begin);
typename Mma::IteratorB iterator_B(
typename Mma::IteratorB::Params(k, n),
@@ -3042,8 +3007,8 @@ void sm70_marlin_moe_gemm_kernel(
}
Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx);
epilogue(iterator_D, accumulators, sorted_token_ids, topk_weights, c, n,
- moe_block, local_m_offset, moe_block_size, m * top_k,
- padded_tokens, mul_topk_weights, SplitK, output_scale);
+ moe_block, local_m_offset, moe_block_size, m * top_k, padded_tokens,
+ mul_topk_weights, SplitK, output_scale);
}
template
@@ -3103,9 +3068,9 @@ torch::Tensor launch_sm70_marlin_moe_gemm(
smem_bytes = configure_sm70_dynamic_smem(split_kernel);
int64_t const numel = size_m * top_k * size_n;
- C10_CUDA_CHECK(cudaMemsetAsync(
- c.data_ptr(), 0,
- static_cast(numel) * sizeof(at::Half), stream));
+ C10_CUDA_CHECK(cudaMemsetAsync(c.data_ptr(), 0,
+ static_cast(numel) * sizeof(at::Half),
+ stream));
int const active_split_k =
sm70_active_split_k(static_cast(size_k), requested_split_k, CtaK);
@@ -3115,11 +3080,11 @@ torch::Tensor launch_sm70_marlin_moe_gemm(
reinterpret_cast(b_q_weight.data_ptr()),
b_scales_ptr, b_zeros_ptr, global_scale_ptr,
reinterpret_cast(c.data_ptr()),
- sorted_token_ids.data_ptr(),
- expert_ids.data_ptr(), num_tokens_past_padded.data_ptr(),
+ sorted_token_ids.data_ptr(), expert_ids.data_ptr(),
+ num_tokens_past_padded.data_ptr(),
topk_weights.data_ptr(), int(moe_block_size), int(top_k),
- mul_topk_weights, int(size_m), int(size_n), int(size_k),
- int(a.stride(0)), requested_split_k);
+ mul_topk_weights, int(size_m), int(size_n), int(size_k), int(a.stride(0)),
+ requested_split_k);
C10_CUDA_KERNEL_LAUNCH_CHECK();
return c;
}
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_moe_dispatch.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_moe_dispatch.cu
index 733d9a4959..ec11d6d72e 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_moe_dispatch.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_moe_dispatch.cu
@@ -43,15 +43,13 @@ __device__ __forceinline__ int sm70_inverse_zp_interleave(int idx,
return inv[idx];
}
-__device__ __forceinline__ int sm70_inverse_scale_perm(int idx,
- int perm_len) {
+__device__ __forceinline__ int sm70_inverse_scale_perm(int idx, int perm_len) {
if (perm_len == 64) {
return (idx % 8) * 8 + idx / 8;
}
- constexpr int inv[32] = {0, 1, 8, 9, 16, 17, 24, 25,
- 2, 3, 10, 11, 18, 19, 26, 27,
- 4, 5, 12, 13, 20, 21, 28, 29,
- 6, 7, 14, 15, 22, 23, 30, 31};
+ constexpr int inv[32] = {0, 1, 8, 9, 16, 17, 24, 25, 2, 3, 10,
+ 11, 18, 19, 26, 27, 4, 5, 12, 13, 20, 21,
+ 28, 29, 6, 7, 14, 15, 22, 23, 30, 31};
return inv[idx];
}
@@ -66,10 +64,9 @@ __global__ void sm70_unpermute_half_metadata_kernel(
}
__global__ void sm70_unpack_moe_zp_to_half_kernel(
- const int32_t* __restrict__ packed_zp,
- const half* __restrict__ scales, half* __restrict__ out,
- int64_t total, int64_t num_groups, int64_t size_n, int64_t packed_n,
- int num_bits, bool is_a_8bit) {
+ const int32_t* __restrict__ packed_zp, const half* __restrict__ scales,
+ half* __restrict__ out, int64_t total, int64_t num_groups, int64_t size_n,
+ int64_t packed_n, int num_bits, bool is_a_8bit) {
const int64_t idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx >= total) return;
@@ -83,15 +80,14 @@ __global__ void sm70_unpack_moe_zp_to_half_kernel(
if (!is_a_8bit) {
packed_col_in_block =
(packed_col_in_block / pack_factor) * pack_factor +
- sm70_inverse_zp_interleave(packed_col_in_block % pack_factor,
- num_bits);
+ sm70_inverse_zp_interleave(packed_col_in_block % pack_factor, num_bits);
}
const int64_t packed_col = block64 * 64 + packed_col_in_block;
- const uint32_t word = reinterpret_cast(packed_zp)
- [(expert * num_groups + group) * packed_n + packed_col / pack_factor];
- const uint32_t zp =
- (word >> ((packed_col % pack_factor) * num_bits)) &
- ((1u << num_bits) - 1u);
+ const uint32_t word = reinterpret_cast(
+ packed_zp)[(expert * num_groups + group) * packed_n +
+ packed_col / pack_factor];
+ const uint32_t zp = (word >> ((packed_col % pack_factor) * num_bits)) &
+ ((1u << num_bits) - 1u);
out[idx] = __float2half(static_cast(zp) * __half2float(scales[idx]));
}
@@ -111,8 +107,8 @@ torch::Tensor sm70_moe_scales_as_logical(torch::Tensor const& b_scales,
const int64_t total = out.numel();
constexpr int threads = 256;
const int blocks = static_cast((total + threads - 1) / threads);
- sm70_unpermute_half_metadata_kernel<<<
- blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(
+ sm70_unpermute_half_metadata_kernel<<>>(
reinterpret_cast(b_scales.data_ptr()),
reinterpret_cast(out.data_ptr()), total, perm_len);
C10_CUDA_KERNEL_LAUNCH_CHECK();
@@ -120,9 +116,8 @@ torch::Tensor sm70_moe_scales_as_logical(torch::Tensor const& b_scales,
}
torch::Tensor sm70_moe_zp_as_half(torch::Tensor const& b_zeros,
- torch::Tensor const& b_scales,
- int64_t size_n, int num_bits,
- bool is_a_8bit) {
+ torch::Tensor const& b_scales, int64_t size_n,
+ int num_bits, bool is_a_8bit) {
if (b_zeros.scalar_type() == at::ScalarType::Half) {
return b_zeros;
}
@@ -143,14 +138,13 @@ torch::Tensor sm70_moe_zp_as_half(torch::Tensor const& b_zeros,
TORCH_CHECK(b_scales.scalar_type() == at::ScalarType::Half,
"SM70 Marlin MoE packed zero-point adapter expects fp16 scales.");
- auto out =
- torch::empty({b_scales.size(0), b_scales.size(1), size_n},
- b_scales.options());
+ auto out = torch::empty({b_scales.size(0), b_scales.size(1), size_n},
+ b_scales.options());
const int64_t total = out.numel();
constexpr int threads = 256;
const int blocks = static_cast((total + threads - 1) / threads);
- sm70_unpack_moe_zp_to_half_kernel<<<
- blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(
+ sm70_unpack_moe_zp_to_half_kernel<<>>(
b_zeros.data_ptr(),
reinterpret_cast(b_scales.data_ptr()),
reinterpret_cast(out.data_ptr()), total,
@@ -229,8 +223,7 @@ torch::Tensor moe_wna16_marlin_gemm(
std::optional const& global_scale_or_none,
std::optional const& b_zeros_or_none,
std::optional const& g_idx_or_none,
- std::optional const& perm_or_none,
- torch::Tensor& workspace,
+ std::optional const& perm_or_none, torch::Tensor& workspace,
torch::Tensor& sorted_token_ids, torch::Tensor& expert_ids,
torch::Tensor& num_tokens_past_padded, torch::Tensor& topk_weights,
int64_t moe_block_size, int64_t top_k, bool mul_topk_weights,
@@ -308,8 +301,7 @@ torch::Tensor moe_wna16_marlin_gemm(
"SM70 Marlin MoE supports only float16 outputs.");
TORCH_CHECK(s_type == vllm::kFloat16 ||
(b_type == vllm::kFE2M1f &&
- (s_type == vllm::kFE4M3fn ||
- s_type == vllm::kFE8M0fnu)),
+ (s_type == vllm::kFE4M3fn || s_type == vllm::kFE8M0fnu)),
"SM70 Marlin MoE supports only float16 scales, "
"except FP4 uses float8_e4m3fn scales for NVFP4 or "
"float8_e8m0fnu scales for MXFP4.");
@@ -364,10 +356,8 @@ torch::Tensor moe_wna16_marlin_gemm(
TORCH_CHECK(b_scales.is_contiguous(), "b_scales is not contiguous");
TORCH_CHECK(b_scales.scalar_type() == at::ScalarType::Half ||
(b_type == vllm::kFE2M1f &&
- (b_scales.scalar_type() ==
- at::ScalarType::Float8_e4m3fn ||
- b_scales.scalar_type() ==
- at::ScalarType::Float8_e8m0fnu)),
+ (b_scales.scalar_type() == at::ScalarType::Float8_e4m3fn ||
+ b_scales.scalar_type() == at::ScalarType::Float8_e8m0fnu)),
"SM70 Marlin MoE supports float16 scales, except FP4 uses "
"float8_e4m3fn scales for NVFP4 or float8_e8m0fnu scales for "
"MXFP4.");
@@ -457,17 +447,15 @@ torch::Tensor moe_wna16_marlin_gemm(
torch::Tensor b_scales_kernel = b_scales;
if (b_scales.scalar_type() == at::ScalarType::Half) {
- b_scales_kernel =
- sm70_moe_scales_as_logical(b_scales, size_k, group_size,
- a_type.size_bits() == 8);
+ b_scales_kernel = sm70_moe_scales_as_logical(b_scales, size_k, group_size,
+ a_type.size_bits() == 8);
}
torch::Tensor global_scale;
if (global_scale_or_none.has_value()) {
global_scale = global_scale_or_none.value();
- TORCH_CHECK(
- b_type == vllm::kFE2M1f && s_type == vllm::kFE4M3fn,
- "SM70 Marlin MoE supports global_scale only for nvfp4 format.");
+ TORCH_CHECK(b_type == vllm::kFE2M1f && s_type == vllm::kFE4M3fn,
+ "SM70 Marlin MoE supports global_scale only for nvfp4 format.");
TORCH_CHECK(global_scale.device().is_cuda(), "global_scale is not on GPU");
TORCH_CHECK(global_scale.is_contiguous(), "global_scale is not contiguous");
TORCH_CHECK(global_scale.scalar_type() == at::ScalarType::Float,
@@ -510,9 +498,9 @@ torch::Tensor moe_wna16_marlin_gemm(
"weights when zero-points are enabled. Got = ",
b_type.str());
if (!is_zp_float && b_zeros.scalar_type() == at::ScalarType::Int) {
- b_zeros = sm70_moe_zp_as_half(
- b_zeros, b_scales_kernel, size_n, b_type == vllm::kU4 ? 4 : 8,
- a_type.size_bits() == 8);
+ b_zeros = sm70_moe_zp_as_half(b_zeros, b_scales_kernel, size_n,
+ b_type == vllm::kU4 ? 4 : 8,
+ a_type.size_bits() == 8);
zp_is_float = true;
}
} else {
@@ -535,8 +523,7 @@ torch::Tensor moe_wna16_marlin_gemm(
TORCH_CHECK(num_groups == b_zeros.size(1),
"b_zeros dim 1 = ", b_zeros.size(1),
" is not num_groups = ", num_groups);
- TORCH_CHECK(b_zeros.size(2) == size_n,
- "b_zeros dim 2 = ", b_zeros.size(2),
+ TORCH_CHECK(b_zeros.size(2) == size_n, "b_zeros dim 2 = ", b_zeros.size(2),
" is not size_n = ", size_n);
} else {
TORCH_CHECK(!zp_is_float,
@@ -559,20 +546,18 @@ torch::Tensor moe_wna16_marlin_gemm(
TORCH_CHECK(!has_act_order,
"act_order is not supported for the SM70 Marlin MoE path.");
- TORCH_CHECK(!has_bias,
- "SM70 Marlin MoE does not support bias.");
+ TORCH_CHECK(!has_bias, "SM70 Marlin MoE does not support bias.");
TORCH_CHECK(!use_atomic_add,
"SM70 Marlin MoE does not support atomic-add "
"output.");
- TORCH_CHECK(is_k_full,
- "SM70 Marlin MoE requires full-K inputs.");
+ TORCH_CHECK(is_k_full, "SM70 Marlin MoE requires full-K inputs.");
if (b_type == vllm::kU4) {
TORCH_CHECK(has_zp && zp_is_float,
"SM70 Marlin MoE uint4 path requires fp16 zero points.");
return MARLIN_NAMESPACE_NAME::sm70_marlin_u4_gemm(
- a, c, b_q_weight, b_scales_kernel, b_zeros, sorted_token_ids, expert_ids,
- num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ a, c, b_q_weight, b_scales_kernel, b_zeros, sorted_token_ids,
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
mul_topk_weights, size_m, size_n, size_k, group_size);
}
@@ -580,8 +565,8 @@ torch::Tensor moe_wna16_marlin_gemm(
TORCH_CHECK(has_zp && zp_is_float,
"SM70 Marlin MoE uint8 path requires fp16 zero points.");
return MARLIN_NAMESPACE_NAME::sm70_marlin_u8_gemm(
- a, c, b_q_weight, b_scales_kernel, b_zeros, sorted_token_ids, expert_ids,
- num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ a, c, b_q_weight, b_scales_kernel, b_zeros, sorted_token_ids,
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
mul_topk_weights, size_m, size_n, size_k, group_size);
}
@@ -622,8 +607,9 @@ torch::Tensor moe_wna16_marlin_gemm(
TORCH_CHECK(!has_zp && !is_zp_float,
"SM70 Marlin MoE fp4 does not support zero-point metadata.");
if (s_type == vllm::kFE4M3fn) {
- TORCH_CHECK(global_scale.numel() == num_experts,
- "the global_scale parameter must be passed for nvfp4 format.");
+ TORCH_CHECK(
+ global_scale.numel() == num_experts,
+ "the global_scale parameter must be passed for nvfp4 format.");
TORCH_CHECK(group_size == 16,
"SM70 Marlin MoE NVFP4 supports only group_size 16. "
"Got ",
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_mxfp4_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_mxfp4_gemm.cu
index 76443f12b8..9755b3edbf 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_mxfp4_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_mxfp4_gemm.cu
@@ -51,7 +51,8 @@ void dequant_e8m0_scales_to_half2(int q, half2* scale_cache) {
*reinterpret_cast(scale_cache) = vec_res;
}
-template
+template
class Sm70MoeMxfp4IteratorB {
public:
using Shape = Shape_;
@@ -59,22 +60,25 @@ class Sm70MoeMxfp4IteratorB {
static int const kGroupSize = GroupSize_;
static int const kPackedMacroN = PackedMacroN_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE MXFP4 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE MXFP4 IteratorB expects one contiguous iteration "
- "per 64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE MXFP4 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE MXFP4 IteratorB expects one contiguous iteration "
+ "per 64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE MXFP4 IteratorB expects 64-column deltas.");
- static_assert(ThreadMap::kElementsPerAccess == kMxfp4ValuesPerWord,
- "SM70 Marlin MoE MXFP4 IteratorB expects one packed FP4 word per "
- "access.");
- static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
- "iterations.");
+ static_assert(
+ ThreadMap::kElementsPerAccess == kMxfp4ValuesPerWord,
+ "SM70 Marlin MoE MXFP4 IteratorB expects one packed FP4 word per "
+ "access.");
+ static_assert(
+ ThreadMap::Iterations::kStrided >= 1,
+ "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
+ "iterations.");
struct Params {
int size_k;
int size_n;
@@ -85,9 +89,7 @@ class Sm70MoeMxfp4IteratorB {
CUTLASS_HOST_DEVICE
Params(int size_k_, int size_n_)
- : size_k(size_k_),
- size_n(size_n_),
- num_groups(size_k_ / GroupSize_) {}
+ : size_k(size_k_), size_n(size_n_), num_groups(size_k_ / GroupSize_) {}
};
private:
@@ -108,9 +110,8 @@ class Sm70MoeMxfp4IteratorB {
uint8_t const* scales, half const*, int thread_id,
int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -149,9 +150,7 @@ class Sm70MoeMxfp4IteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
@@ -184,14 +183,12 @@ class Sm70MoeMxfp4IteratorB {
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
int const logical_k =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ k_offset_ + thread_offset_.strided() + s * ThreadMap::Delta::kStrided;
int const group = scale_group(logical_k);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
int const cache_index = c + s * ThreadMap::Iterations::kContiguous;
cache_metadata_e8m0_scales(cache_index, group, cache_n);
}
@@ -244,8 +241,9 @@ class Sm70MoeMxfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE MXFP4 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE MXFP4 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_offset_);
half2 const* scale_vec = cached_scales_;
@@ -265,15 +263,13 @@ class Sm70MoeMxfp4IteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
int const qweight_base_s =
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- auto const qwords =
- load_qword_vector<4>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<4>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -296,8 +292,7 @@ class Sm70MoeMxfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else if constexpr (ThreadMap::Iterations::kContiguous == 2) {
- auto const qwords =
- load_qword_vector<2>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<2>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -320,8 +315,9 @@ class Sm70MoeMxfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE MXFP4 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE MXFP4 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_s);
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -364,15 +360,15 @@ struct Sm70MoeMxfp4GemmSpec {
using IteratorA = Sm70MoeGatherIteratorA;
template
- using IteratorB = Sm70MoeMxfp4IteratorB;
+ using IteratorB =
+ Sm70MoeMxfp4IteratorB;
};
-template
+template
using Sm70MoeMxfp4GemmTraits =
- Sm70MarlinMoeGemmTraits;
+ Sm70MarlinMoeGemmTraits;
struct Sm70MoeMxfp4Launcher {
torch::Tensor& a;
@@ -393,15 +389,15 @@ struct Sm70MoeMxfp4Launcher {
int64_t size_k;
int requested_split_k;
- template
+ template
torch::Tensor operator()() const {
- using Traits = Sm70MoeMxfp4GemmTraits;
+ using Traits = Sm70MoeMxfp4GemmTraits;
return launch_sm70_marlin_moe_gemm(
a, c, b_q_weight, b_scales, b_zeros, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size,
- top_k, mul_topk_weights, size_m, size_n, size_k, requested_split_k);
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ mul_topk_weights, size_m, size_n, size_k, requested_split_k);
}
};
@@ -419,9 +415,10 @@ torch::Tensor sm70_marlin_mxfp4_gemm(
auto const params = sm70_marlin_moe_auto_stage_params(
"mxfp4", group_size, moe_block_size, top_k, size_m, size_n, size_k);
Sm70CtaGeometry const geometry = params.geometry;
- validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE mxfp4", geometry);
- validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE mxfp4", geometry,
- size_n);
+ validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE mxfp4",
+ geometry);
+ validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE mxfp4",
+ geometry, size_n);
TORCH_CHECK(size_k % geometry.cta_k == 0,
"SM70 Marlin MoE mxfp4 requires K divisible by CTA_K=",
geometry.cta_k, ". Got K=", size_k, ".");
@@ -429,10 +426,23 @@ torch::Tensor sm70_marlin_mxfp4_gemm(
auto empty_half = torch::empty({0}, b_scales.options().dtype(at::kHalf));
auto empty_float = torch::empty(
{0}, torch::TensorOptions().dtype(at::kFloat).device(a.device()));
- Sm70MoeMxfp4Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
+ Sm70MoeMxfp4Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
return dispatch_sm70_marlin_moe_fixed_group_geometry<32>(
launcher, geometry, params.packed_macro_n, group_size, "mxfp4");
}
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_nvfp4_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_nvfp4_gemm.cu
index a1ea955d34..b2cc86aa91 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_nvfp4_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_nvfp4_gemm.cu
@@ -26,7 +26,8 @@ namespace {
constexpr int kNvfp4ValuesPerWord = 8;
-template
+template
class Sm70MoeNvfp4IteratorB {
public:
using Shape = Shape_;
@@ -34,22 +35,25 @@ class Sm70MoeNvfp4IteratorB {
static int const kGroupSize = GroupSize_;
static int const kPackedMacroN = PackedMacroN_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE NVFP4 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE NVFP4 IteratorB expects one contiguous iteration "
- "per 64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE NVFP4 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE NVFP4 IteratorB expects one contiguous iteration "
+ "per 64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE NVFP4 IteratorB expects 64-column deltas.");
- static_assert(ThreadMap::kElementsPerAccess == kNvfp4ValuesPerWord,
- "SM70 Marlin MoE NVFP4 IteratorB expects one packed FP4 word per "
- "access.");
- static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
- "iterations.");
+ static_assert(
+ ThreadMap::kElementsPerAccess == kNvfp4ValuesPerWord,
+ "SM70 Marlin MoE NVFP4 IteratorB expects one packed FP4 word per "
+ "access.");
+ static_assert(
+ ThreadMap::Iterations::kStrided >= 1,
+ "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
+ "iterations.");
struct Params {
int size_k;
int size_n;
@@ -60,9 +64,7 @@ class Sm70MoeNvfp4IteratorB {
CUTLASS_HOST_DEVICE
Params(int size_k_, int size_n_)
- : size_k(size_k_),
- size_n(size_n_),
- num_groups(size_k_ / GroupSize_) {}
+ : size_k(size_k_), size_n(size_n_), num_groups(size_k_ / GroupSize_) {}
};
private:
@@ -83,9 +85,8 @@ class Sm70MoeNvfp4IteratorB {
uint8_t const* scales, half const*, int thread_id,
int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -124,9 +125,7 @@ class Sm70MoeNvfp4IteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
@@ -159,14 +158,12 @@ class Sm70MoeNvfp4IteratorB {
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
int const logical_k =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ k_offset_ + thread_offset_.strided() + s * ThreadMap::Delta::kStrided;
int const group = scale_group(logical_k);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
int const cache_index = c + s * ThreadMap::Iterations::kContiguous;
cache_metadata_fp8_scales(cache_index, group, cache_n);
}
@@ -219,8 +216,9 @@ class Sm70MoeNvfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE NVFP4 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE NVFP4 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_offset_);
half2 const* scale_vec = cached_scales_;
@@ -240,15 +238,13 @@ class Sm70MoeNvfp4IteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
int const qweight_base_s =
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- auto const qwords =
- load_qword_vector<4>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<4>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -271,8 +267,7 @@ class Sm70MoeNvfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else if constexpr (ThreadMap::Iterations::kContiguous == 2) {
- auto const qwords =
- load_qword_vector<2>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<2>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -295,8 +290,9 @@ class Sm70MoeNvfp4IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE NVFP4 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE NVFP4 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_s);
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -339,15 +335,15 @@ struct Sm70MoeNvfp4GemmSpec {
using IteratorA = Sm70MoeGatherIteratorA;
template
- using IteratorB = Sm70MoeNvfp4IteratorB;
+ using IteratorB =
+ Sm70MoeNvfp4IteratorB;
};
-template
+template
using Sm70MoeNvfp4GemmTraits =
- Sm70MarlinMoeGemmTraits;
+ Sm70MarlinMoeGemmTraits;
struct Sm70MoeNvfp4Launcher {
torch::Tensor& a;
@@ -368,15 +364,15 @@ struct Sm70MoeNvfp4Launcher {
int64_t size_k;
int requested_split_k;
- template
+ template
torch::Tensor operator()() const {
- using Traits = Sm70MoeNvfp4GemmTraits;
+ using Traits = Sm70MoeNvfp4GemmTraits;
return launch_sm70_marlin_moe_gemm(
a, c, b_q_weight, b_scales, b_zeros, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size,
- top_k, mul_topk_weights, size_m, size_n, size_k, requested_split_k);
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ mul_topk_weights, size_m, size_n, size_k, requested_split_k);
}
};
@@ -394,18 +390,32 @@ torch::Tensor sm70_marlin_nvfp4_gemm(
auto const params = sm70_marlin_moe_auto_stage_params(
"nvfp4", group_size, moe_block_size, top_k, size_m, size_n, size_k);
Sm70CtaGeometry const geometry = params.geometry;
- validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE nvfp4", geometry);
- validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE nvfp4", geometry,
- size_n);
+ validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE nvfp4",
+ geometry);
+ validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE nvfp4",
+ geometry, size_n);
TORCH_CHECK(size_k % geometry.cta_k == 0,
"SM70 Marlin MoE nvfp4 requires K divisible by CTA_K=",
geometry.cta_k, ". Got K=", size_k, ".");
auto empty_half = torch::empty({0}, b_scales.options().dtype(at::kHalf));
- Sm70MoeNvfp4Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
+ Sm70MoeNvfp4Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ global_scale,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
return dispatch_sm70_marlin_moe_fixed_group_geometry<16>(
launcher, geometry, params.packed_macro_n, group_size, "nvfp4");
}
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_u4_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_u4_gemm.cu
index cf412f4d0f..bce2bfb899 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_u4_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_u4_gemm.cu
@@ -35,21 +35,23 @@ class Sm70MoeU4ZpIteratorB {
static int const kPackedMacroN = PackedMacroN_;
static constexpr bool kUseMetadataVectorWords = UseMetadataVectorWords_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE U4 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE U4 IteratorB expects one contiguous iteration per "
- "64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE U4 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE U4 IteratorB expects one contiguous iteration per "
+ "64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE U4 IteratorB expects 64-column deltas.");
static_assert(ThreadMap::kElementsPerAccess == kU4ValuesPerWord,
"SM70 Marlin MoE U4 IteratorB expects one packed int4 word per "
"access.");
static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U4-family IteratorB expects one or more strided iterations.");
+ "SM70 Marlin MoE U4-family IteratorB expects one or more "
+ "strided iterations.");
struct Params {
int size_k;
int size_n;
@@ -85,11 +87,10 @@ class Sm70MoeU4ZpIteratorB {
half const* scales, half const* zp, int thread_id,
int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
- zp_expert_base_(zp + (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
+ zp_expert_base_(zp + (expert >= 0 ? expert : 0) * params.num_groups *
+ params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -131,17 +132,14 @@ class Sm70MoeU4ZpIteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
if constexpr (kGroupSize == -1) {
return 0;
} else {
- static_assert(kGroupSize == 32 || kGroupSize == 64 ||
- kGroupSize == 128,
+ static_assert(kGroupSize == 32 || kGroupSize == 64 || kGroupSize == 128,
"SM70 Marlin MoE U4 supports only group sizes -1, 32, 64, "
"and 128.");
return logical_k / kGroupSize;
@@ -158,16 +156,16 @@ class Sm70MoeU4ZpIteratorB {
CUTLASS_DEVICE
void cache_metadata_lane_vectors(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- half2 const* scale_vec = reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ half2 const* scale_vec =
+ reinterpret_cast(scales_expert_base_ + metadata_offset);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
scale_cache[1] = scale_vec[1];
scale_cache[2] = scale_vec[2];
scale_cache[3] = scale_vec[3];
- half2 const* zp_vec = reinterpret_cast(
- zp_expert_base_ + metadata_offset);
+ half2 const* zp_vec =
+ reinterpret_cast(zp_expert_base_ + metadata_offset);
half2* zp_cache = cached_zp_ + c * 4;
zp_cache[0] = zp_vec[0];
zp_cache[1] = zp_vec[1];
@@ -178,8 +176,8 @@ class Sm70MoeU4ZpIteratorB {
CUTLASS_DEVICE
void cache_metadata_vector_words(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- uint4 const scale_words = *reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ uint4 const scale_words =
+ *reinterpret_cast(scales_expert_base_ + metadata_offset);
half2 const* scale_vec = reinterpret_cast(&scale_words);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
@@ -187,8 +185,8 @@ class Sm70MoeU4ZpIteratorB {
scale_cache[2] = scale_vec[2];
scale_cache[3] = scale_vec[3];
- uint4 const zp_words = *reinterpret_cast(
- zp_expert_base_ + metadata_offset);
+ uint4 const zp_words =
+ *reinterpret_cast(zp_expert_base_ + metadata_offset);
half2 const* zp_vec = reinterpret_cast(&zp_words);
half2* zp_cache = cached_zp_ + c * 4;
zp_cache[0] = zp_vec[0];
@@ -201,9 +199,8 @@ class Sm70MoeU4ZpIteratorB {
void cache_current_group_metadata(int group) const {
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
if constexpr (kUseMetadataVectorWords) {
cache_metadata_vector_words(c, group, cache_n);
} else {
@@ -228,8 +225,8 @@ class Sm70MoeU4ZpIteratorB {
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data() + frag_base);
- marlin::dequant(
- static_cast(qword), deq);
+ marlin::dequant(static_cast(qword),
+ deq);
frag_vec[0] = __hfma2(deq[0], scale_vec[0], __hneg2(zp_vec[0]));
frag_vec[1] = __hfma2(deq[1], scale_vec[1], __hneg2(zp_vec[1]));
marlin::dequant(
@@ -250,8 +247,8 @@ class Sm70MoeU4ZpIteratorB {
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data() + frag_base);
- marlin::dequant(
- static_cast(qword), deq);
+ marlin::dequant(static_cast(qword),
+ deq);
frag_vec[0] = __hfma2(deq[0], scale_vec[0], __hneg2(zp_vec[0]));
frag_vec[1] = __hfma2(deq[1], scale_vec[1], __hneg2(zp_vec[1]));
marlin::dequant(
@@ -260,16 +257,18 @@ class Sm70MoeU4ZpIteratorB {
frag_vec[3] = __hfma2(deq[1], scale_vec[3], __hneg2(zp_vec[3]));
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE U4 contiguous iteration count.");
- uint32_t const qword = load_qword_vector<1>(qweight_ + qweight_base_offset_);
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE U4 contiguous iteration count.");
+ uint32_t const qword =
+ load_qword_vector<1>(qweight_ + qweight_base_offset_);
half2 const* scale_vec = cached_scales_;
half2 const* zp_vec = cached_zp_;
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data());
- marlin::dequant(
- static_cast(qword), deq);
+ marlin::dequant(static_cast(qword),
+ deq);
frag_vec[0] = __hfma2(deq[0], scale_vec[0], __hneg2(zp_vec[0]));
frag_vec[1] = __hfma2(deq[1], scale_vec[1], __hneg2(zp_vec[1]));
marlin::dequant(
@@ -281,9 +280,8 @@ class Sm70MoeU4ZpIteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
if constexpr (kGroupSize != -1) {
cache_current_group_metadata(scale_group(logical_k_s));
}
@@ -291,8 +289,7 @@ class Sm70MoeU4ZpIteratorB {
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- auto const qwords =
- load_qword_vector<4>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<4>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -314,8 +311,7 @@ class Sm70MoeU4ZpIteratorB {
frag_vec[3] = __hfma2(deq[1], scale_vec[3], __hneg2(zp_vec[3]));
}
} else if constexpr (ThreadMap::Iterations::kContiguous == 2) {
- auto const qwords =
- load_qword_vector<2>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<2>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -337,9 +333,11 @@ class Sm70MoeU4ZpIteratorB {
frag_vec[3] = __hfma2(deq[1], scale_vec[3], __hneg2(zp_vec[3]));
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE U4 contiguous iteration count.");
- uint32_t const qword = load_qword_vector<1>(qweight_ + qweight_base_s);
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE U4 contiguous iteration count.");
+ uint32_t const qword =
+ load_qword_vector<1>(qweight_ + qweight_base_s);
constexpr int kAccess = ThreadMap::kElementsPerAccess;
int const frag_base = s * kAccess;
half2 const* scale_vec = cached_scales_;
@@ -347,8 +345,8 @@ class Sm70MoeU4ZpIteratorB {
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data() + frag_base);
- marlin::dequant(
- static_cast(qword), deq);
+ marlin::dequant(static_cast(qword),
+ deq);
frag_vec[0] = __hfma2(deq[0], scale_vec[0], __hneg2(zp_vec[0]));
frag_vec[1] = __hfma2(deq[1], scale_vec[1], __hneg2(zp_vec[1]));
marlin::dequant(
@@ -366,8 +364,7 @@ class Sm70MoeU4ZpIteratorB {
return;
}
- if constexpr (kGroupSize != -1 &&
- ThreadMap::Iterations::kStrided == 1) {
+ if constexpr (kGroupSize != -1 && ThreadMap::Iterations::kStrided == 1) {
int const first_logical_k = k_offset_ + thread_offset_.strided();
cache_current_group_metadata(scale_group(first_logical_k));
}
@@ -386,18 +383,17 @@ struct Sm70MoeU4ZpGemmSpec {
using IteratorA = Sm70MoeGatherIteratorA;
template
- using IteratorB =
- Sm70MoeU4ZpIteratorB;
+ using IteratorB = Sm70MoeU4ZpIteratorB;
};
-template
using Sm70MoeU4ZpGemmTraits =
- Sm70MarlinMoeGemmTraits<
- Sm70MoeU4ZpGemmSpec, CtaM, CtaN, CtaK,
- Warps, WarpM, WarpN, WarpK, GroupSize, PackedMacroN>;
+ Sm70MarlinMoeGemmTraits, CtaM,
+ CtaN, CtaK, Warps, WarpM, WarpN, WarpK, GroupSize,
+ PackedMacroN>;
template
struct Sm70MoeU4Launcher {
@@ -419,16 +415,16 @@ struct Sm70MoeU4Launcher {
int64_t size_k;
int requested_split_k;
- template
+ template
torch::Tensor operator()() const {
- using Traits = Sm70MoeU4ZpGemmTraits;
+ using Traits =
+ Sm70MoeU4ZpGemmTraits;
return launch_sm70_marlin_moe_gemm(
a, c, b_q_weight, b_scales, b_zeros, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size,
- top_k, mul_topk_weights, size_m, size_n, size_k, requested_split_k);
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ mul_topk_weights, size_m, size_n, size_k, requested_split_k);
}
};
@@ -446,9 +442,10 @@ torch::Tensor sm70_marlin_u4_gemm(
auto const params = sm70_marlin_moe_auto_stage_params(
"uint4", group_size, moe_block_size, top_k, size_m, size_n, size_k);
Sm70CtaGeometry const geometry = params.geometry;
- validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE uint4", geometry);
- validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE uint4", geometry,
- size_n);
+ validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE uint4",
+ geometry);
+ validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE uint4",
+ geometry, size_n);
TORCH_CHECK(size_k % geometry.cta_k == 0,
"SM70 Marlin MoE uint4 requires K divisible by CTA_K=",
geometry.cta_k, ". Got K=", size_k, ".");
@@ -456,19 +453,45 @@ torch::Tensor sm70_marlin_u4_gemm(
auto empty_float = torch::empty(
{0}, torch::TensorOptions().dtype(at::kFloat).device(a.device()));
if (params.use_metadata_vector_words) {
- Sm70MoeU4Launcher const launcher{
- a, c, b_q_weight, b_scales, b_zeros, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
- return dispatch_sm70_marlin_moe_geometry(launcher, geometry, params.packed_macro_n, group_size,
- "uint4");
+ Sm70MoeU4Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ b_zeros,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
+ return dispatch_sm70_marlin_moe_geometry(
+ launcher, geometry, params.packed_macro_n, group_size, "uint4");
}
- Sm70MoeU4Launcher const launcher{
- a, c, b_q_weight, b_scales, b_zeros, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
- return dispatch_sm70_marlin_moe_geometry(launcher, geometry, params.packed_macro_n, group_size,
- "uint4");
+ Sm70MoeU4Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ b_zeros,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
+ return dispatch_sm70_marlin_moe_geometry(
+ launcher, geometry, params.packed_macro_n, group_size, "uint4");
}
} // namespace marlin_moe_wna16
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_u4b8_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_u4b8_gemm.cu
index 56f4206460..c5e03f0ece 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_u4b8_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_u4b8_gemm.cu
@@ -35,22 +35,25 @@ class Sm70MoeU4B8IteratorB {
static int const kPackedMacroN = PackedMacroN_;
static constexpr bool kUseMetadataVectorWords = UseMetadataVectorWords_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE U4B8 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE U4B8 IteratorB expects one contiguous iteration per "
- "64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE U4B8 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE U4B8 IteratorB expects one contiguous iteration per "
+ "64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE U4B8 IteratorB expects 64-column deltas.");
- static_assert(ThreadMap::kElementsPerAccess == kU4ValuesPerWord,
- "SM70 Marlin MoE U4B8 IteratorB expects one packed int4 word per "
- "access.");
- static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
- "iterations.");
+ static_assert(
+ ThreadMap::kElementsPerAccess == kU4ValuesPerWord,
+ "SM70 Marlin MoE U4B8 IteratorB expects one packed int4 word per "
+ "access.");
+ static_assert(
+ ThreadMap::Iterations::kStrided >= 1,
+ "SM70 Marlin MoE U4-family IteratorB expects one or more strided "
+ "iterations.");
struct Params {
int size_k;
int size_n;
@@ -84,9 +87,8 @@ class Sm70MoeU4B8IteratorB {
half const* scales, half const*, int thread_id,
int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -128,19 +130,17 @@ class Sm70MoeU4B8IteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
if constexpr (kGroupSize == -1) {
return 0;
} else {
- static_assert(kGroupSize == 32 || kGroupSize == 64 ||
- kGroupSize == 128,
- "SM70 Marlin MoE U4B8 supports only group sizes -1, 32, 64, "
- "and 128.");
+ static_assert(
+ kGroupSize == 32 || kGroupSize == 64 || kGroupSize == 128,
+ "SM70 Marlin MoE U4B8 supports only group sizes -1, 32, 64, "
+ "and 128.");
return logical_k / kGroupSize;
}
}
@@ -155,8 +155,8 @@ class Sm70MoeU4B8IteratorB {
CUTLASS_DEVICE
void cache_metadata_lane_vectors(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- half2 const* scale_vec = reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ half2 const* scale_vec =
+ reinterpret_cast(scales_expert_base_ + metadata_offset);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
scale_cache[1] = scale_vec[1];
@@ -167,8 +167,8 @@ class Sm70MoeU4B8IteratorB {
CUTLASS_DEVICE
void cache_metadata_vector_words(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- uint4 const scale_words = *reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ uint4 const scale_words =
+ *reinterpret_cast(scales_expert_base_ + metadata_offset);
half2 const* scale_vec = reinterpret_cast(&scale_words);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
@@ -181,9 +181,8 @@ class Sm70MoeU4B8IteratorB {
void cache_current_group_metadata(int group) const {
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
if constexpr (kUseMetadataVectorWords) {
cache_metadata_vector_words(c, group, cache_n);
} else {
@@ -238,16 +237,17 @@ class Sm70MoeU4B8IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE U4B8 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE U4B8 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_offset_);
half2 const* scale_vec = cached_scales_;
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data());
- marlin::dequant(
- static_cast(qword), deq);
+ marlin::dequant(static_cast(qword),
+ deq);
frag_vec[0] = __hmul2(deq[0], scale_vec[0]);
frag_vec[1] = __hmul2(deq[1], scale_vec[1]);
marlin::dequant(
@@ -259,9 +259,8 @@ class Sm70MoeU4B8IteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
if constexpr (kGroupSize != -1) {
cache_current_group_metadata(scale_group(logical_k_s));
}
@@ -269,8 +268,7 @@ class Sm70MoeU4B8IteratorB {
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- auto const qwords =
- load_qword_vector<4>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<4>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -291,8 +289,7 @@ class Sm70MoeU4B8IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else if constexpr (ThreadMap::Iterations::kContiguous == 2) {
- auto const qwords =
- load_qword_vector<2>(qweight_ + qweight_base_s);
+ auto const qwords = load_qword_vector<2>(qweight_ + qweight_base_s);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -313,8 +310,9 @@ class Sm70MoeU4B8IteratorB {
frag_vec[3] = __hmul2(deq[1], scale_vec[3]);
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE U4B8 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE U4B8 contiguous iteration count.");
uint32_t const qword =
load_qword_vector<1>(qweight_ + qweight_base_s);
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -342,8 +340,7 @@ class Sm70MoeU4B8IteratorB {
return;
}
- if constexpr (kGroupSize != -1 &&
- ThreadMap::Iterations::kStrided == 1) {
+ if constexpr (kGroupSize != -1 && ThreadMap::Iterations::kStrided == 1) {
int const first_logical_k = k_offset_ + thread_offset_.strided();
cache_current_group_metadata(scale_group(first_logical_k));
}
@@ -362,18 +359,17 @@ struct Sm70MoeU4B8GemmSpec {
using IteratorA = Sm70MoeGatherIteratorA;
template
- using IteratorB =
- Sm70MoeU4B8IteratorB;
+ using IteratorB = Sm70MoeU4B8IteratorB;
};
-template
using Sm70MoeU4B8GemmTraits =
- Sm70MarlinMoeGemmTraits<
- Sm70MoeU4B8GemmSpec, CtaM, CtaN, CtaK,
- Warps, WarpM, WarpN, WarpK, GroupSize, PackedMacroN>;
+ Sm70MarlinMoeGemmTraits, CtaM,
+ CtaN, CtaK, Warps, WarpM, WarpN, WarpK, GroupSize,
+ PackedMacroN>;
template
struct Sm70MoeU4B8Launcher {
@@ -395,16 +391,16 @@ struct Sm70MoeU4B8Launcher {
int64_t size_k;
int requested_split_k;
- template
+ template
torch::Tensor operator()() const {
- using Traits = Sm70MoeU4B8GemmTraits;
+ using Traits =
+ Sm70MoeU4B8GemmTraits;
return launch_sm70_marlin_moe_gemm(
a, c, b_q_weight, b_scales, b_zeros, global_scale, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size,
- top_k, mul_topk_weights, size_m, size_n, size_k, requested_split_k);
+ expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
+ mul_topk_weights, size_m, size_n, size_k, requested_split_k);
}
};
@@ -422,9 +418,10 @@ torch::Tensor sm70_marlin_u4b8_gemm(
auto const params = sm70_marlin_moe_auto_stage_params(
"uint4b8", group_size, moe_block_size, top_k, size_m, size_n, size_k);
Sm70CtaGeometry const geometry = params.geometry;
- validate_sm70_marlin_moe_stage_cta_geometry_supported("SM70 Marlin MoE uint4b8", geometry);
- validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE uint4b8", geometry,
- size_n);
+ validate_sm70_marlin_moe_stage_cta_geometry_supported(
+ "SM70 Marlin MoE uint4b8", geometry);
+ validate_sm70_marlin_moe_stage_cta_n_alignment("SM70 Marlin MoE uint4b8",
+ geometry, size_n);
TORCH_CHECK(size_k % geometry.cta_k == 0,
"SM70 Marlin MoE uint4b8 requires K divisible by CTA_K=",
geometry.cta_k, ". Got K=", size_k, ".");
@@ -433,17 +430,43 @@ torch::Tensor sm70_marlin_u4b8_gemm(
auto empty_float = torch::empty(
{0}, torch::TensorOptions().dtype(at::kFloat).device(a.device()));
if (params.use_metadata_vector_words) {
- Sm70MoeU4B8Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
+ Sm70MoeU4B8Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
return dispatch_sm70_marlin_moe_geometry(
launcher, geometry, params.packed_macro_n, group_size, "uint4b8");
}
- Sm70MoeU4B8Launcher const launcher{
- a, c, b_q_weight, b_scales, empty_half, empty_float, sorted_token_ids,
- expert_ids, num_tokens_past_padded, topk_weights, moe_block_size, top_k,
- mul_topk_weights, size_m, size_n, size_k, params.requested_split_k};
+ Sm70MoeU4B8Launcher const launcher{a,
+ c,
+ b_q_weight,
+ b_scales,
+ empty_half,
+ empty_float,
+ sorted_token_ids,
+ expert_ids,
+ num_tokens_past_padded,
+ topk_weights,
+ moe_block_size,
+ top_k,
+ mul_topk_weights,
+ size_m,
+ size_n,
+ size_k,
+ params.requested_split_k};
return dispatch_sm70_marlin_moe_geometry(
launcher, geometry, params.packed_macro_n, group_size, "uint4b8");
}
diff --git a/csrc/moe/marlin_moe_wna16/sm70_marlin_u8_gemm.cu b/csrc/moe/marlin_moe_wna16/sm70_marlin_u8_gemm.cu
index c620f30112..25c86f4f2a 100644
--- a/csrc/moe/marlin_moe_wna16/sm70_marlin_u8_gemm.cu
+++ b/csrc/moe/marlin_moe_wna16/sm70_marlin_u8_gemm.cu
@@ -35,22 +35,24 @@ class Sm70MoeU8ZpIteratorB {
static int const kPackedMacroN = PackedMacroN_;
static constexpr bool kUseMetadataVectorWords = UseMetadataVectorWords_;
using Element = cutlass::half_t;
- using Fragment = cutlass::Array<
- Element, ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>;
- static_assert(Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
- "SM70 Marlin MoE U8 IteratorB expects CTA_N in {64, 128, 256}.");
- static_assert(ThreadMap::Iterations::kContiguous ==
- Shape::kN / kQuantTileN,
- "SM70 Marlin MoE U8 IteratorB expects one contiguous iteration per "
- "64-column quant tile.");
+ using Fragment = cutlass::Array;
+ static_assert(
+ Shape::kN == 64 || Shape::kN == 128 || Shape::kN == 256,
+ "SM70 Marlin MoE U8 IteratorB expects CTA_N in {64, 128, 256}.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == Shape::kN / kQuantTileN,
+ "SM70 Marlin MoE U8 IteratorB expects one contiguous iteration per "
+ "64-column quant tile.");
static_assert(ThreadMap::Delta::kContiguous == kQuantTileN,
"SM70 Marlin MoE U8 IteratorB expects 64-column deltas.");
static_assert(ThreadMap::kElementsPerAccess == kU8ValuesPerAccess,
"SM70 Marlin MoE U8 IteratorB expects two packed U8 words per "
"access.");
- static_assert(ThreadMap::Iterations::kStrided >= 1,
- "SM70 Marlin MoE U8-family IteratorB expects one or more strided "
- "iterations.");
+ static_assert(
+ ThreadMap::Iterations::kStrided >= 1,
+ "SM70 Marlin MoE U8-family IteratorB expects one or more strided "
+ "iterations.");
static constexpr int kQweightWordStrideWords = kPackedMacroN / kQuantTileN;
struct Params {
@@ -88,11 +90,10 @@ class Sm70MoeU8ZpIteratorB {
half const* scales, half const* zp, int thread_id,
int expert, int k_offset, int n_offset)
: qweight_(qweight),
- scales_expert_base_(scales +
- (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
- zp_expert_base_(zp + (expert >= 0 ? expert : 0) *
- params.num_groups * params.size_n),
+ scales_expert_base_(scales + (expert >= 0 ? expert : 0) *
+ params.num_groups * params.size_n),
+ zp_expert_base_(zp + (expert >= 0 ? expert : 0) * params.num_groups *
+ params.size_n),
params_(params),
thread_offset_(ThreadMap::initial_offset(thread_id)),
expert_(expert),
@@ -134,17 +135,14 @@ class Sm70MoeU8ZpIteratorB {
}
CUTLASS_DEVICE
- int metadata_group_offset(int group) const {
- return group * params_.size_n;
- }
+ int metadata_group_offset(int group) const { return group * params_.size_n; }
CUTLASS_DEVICE
int scale_group(int logical_k) const {
if constexpr (kGroupSize == -1) {
return 0;
} else {
- static_assert(kGroupSize == 32 || kGroupSize == 64 ||
- kGroupSize == 128,
+ static_assert(kGroupSize == 32 || kGroupSize == 64 || kGroupSize == 128,
"SM70 Marlin MoE U8 supports only group sizes -1, 32, 64, "
"and 128.");
return logical_k / kGroupSize;
@@ -161,16 +159,16 @@ class Sm70MoeU8ZpIteratorB {
CUTLASS_DEVICE
void cache_metadata_lane_vectors(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- half2 const* scale_vec = reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ half2 const* scale_vec =
+ reinterpret_cast(scales_expert_base_ + metadata_offset);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
scale_cache[1] = scale_vec[1];
scale_cache[2] = scale_vec[2];
scale_cache[3] = scale_vec[3];
- half2 const* zp_vec = reinterpret_cast(
- zp_expert_base_ + metadata_offset);
+ half2 const* zp_vec =
+ reinterpret_cast(zp_expert_base_ + metadata_offset);
half2* zp_cache = cached_zp_ + c * 4;
zp_cache[0] = zp_vec[0];
zp_cache[1] = zp_vec[1];
@@ -181,8 +179,8 @@ class Sm70MoeU8ZpIteratorB {
CUTLASS_DEVICE
void cache_metadata_vector_words(int c, int group, int cache_n) const {
int const metadata_offset = metadata_group_offset(group) + cache_n;
- uint4 const scale_words = *reinterpret_cast(
- scales_expert_base_ + metadata_offset);
+ uint4 const scale_words =
+ *reinterpret_cast(scales_expert_base_ + metadata_offset);
half2 const* scale_vec = reinterpret_cast(&scale_words);
half2* scale_cache = cached_scales_ + c * 4;
scale_cache[0] = scale_vec[0];
@@ -190,8 +188,8 @@ class Sm70MoeU8ZpIteratorB {
scale_cache[2] = scale_vec[2];
scale_cache[3] = scale_vec[3];
- uint4 const zp_words = *reinterpret_cast(
- zp_expert_base_ + metadata_offset);
+ uint4 const zp_words =
+ *reinterpret_cast(zp_expert_base_ + metadata_offset);
half2 const* zp_vec = reinterpret_cast(&zp_words);
half2* zp_cache = cached_zp_ + c * 4;
zp_cache[0] = zp_vec[0];
@@ -204,9 +202,8 @@ class Sm70MoeU8ZpIteratorB {
void cache_current_group_metadata(int group) const {
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
- int const cache_n =
- n_offset_ + thread_offset_.contiguous() +
- c * ThreadMap::Delta::kContiguous;
+ int const cache_n = n_offset_ + thread_offset_.contiguous() +
+ c * ThreadMap::Delta::kContiguous;
if constexpr (kUseMetadataVectorWords) {
cache_metadata_vector_words(c, group, cache_n);
} else {
@@ -269,8 +266,9 @@ class Sm70MoeU8ZpIteratorB {
frag_vec[3] = __hfma2(deq[1], scale_vec[3], __hneg2(zp_vec[3]));
}
} else {
- static_assert(ThreadMap::Iterations::kContiguous == 1,
- "Unsupported SM70 Marlin MoE U8 contiguous iteration count.");
+ static_assert(
+ ThreadMap::Iterations::kContiguous == 1,
+ "Unsupported SM70 Marlin MoE U8 contiguous iteration count.");
uint32_t const qword0 =
load_qword_vector<1>(qweight_ + qweight_base_offset_);
uint32_t const qword1 = load_qword_vector<1>(
@@ -280,12 +278,12 @@ class Sm70MoeU8ZpIteratorB {
half2 deq[2];
half2* frag_vec = reinterpret_cast(frag.data());
- marlin::dequant(
- static_cast(qword0), deq);
+ marlin::dequant(static_cast(qword0),
+ deq);
frag_vec[0] = __hfma2(deq[0], scale_vec[0], __hneg2(zp_vec[0]));
frag_vec[1] = __hfma2(deq[1], scale_vec[1], __hneg2(zp_vec[1]));
- marlin::dequant(
- static_cast(qword1), deq);
+ marlin::dequant(static_cast(qword1),
+ deq);
frag_vec[2] = __hfma2(deq[0], scale_vec[2], __hneg2(zp_vec[2]));
frag_vec[3] = __hfma2(deq[1], scale_vec[3], __hneg2(zp_vec[3]));
}
@@ -293,9 +291,8 @@ class Sm70MoeU8ZpIteratorB {
int const logical_n_base = n_offset_ + thread_offset_.contiguous();
CUTLASS_PRAGMA_UNROLL
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
- int const logical_k_s =
- k_offset_ + thread_offset_.strided() +
- s * ThreadMap::Delta::kStrided;
+ int const logical_k_s = k_offset_ + thread_offset_.strided() +
+ s * ThreadMap::Delta::kStrided;
if constexpr (kGroupSize != -1) {
cache_current_group_metadata(scale_group(logical_k_s));
}
@@ -303,10 +300,9 @@ class Sm70MoeU8ZpIteratorB {
expert_qweight_base_offset() +
qweight_offset_from_logical(params_, logical_k_s, logical_n_base);
if constexpr (ThreadMap::Iterations::kContiguous == 4) {
- uint4 const qwords0 =
- load_qword_vector<4>(qweight_ + qweight_base_s);
- uint4 const qwords1 = load_qword_vector<4>(
- qweight_ + qweight_base_s + kQweightWordStrideWords);
+ uint4 const qwords0 = load_qword_vector<4>(qweight_ + qweight_base_s);
+ uint4 const qwords1 = load_qword_vector<4>(qweight_ + qweight_base_s +
+ kQweightWordStrideWords);
CUTLASS_PRAGMA_UNROLL
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
constexpr int kAccess = ThreadMap::kElementsPerAccess;
@@ -321,22 +317,17 @@ class Sm70MoeU8ZpIteratorB {
half2* frag_vec = reinterpret_cast