Files
vLLM-4x-RTX-3090/patches/0090-envs-the-MERLIN_-kernel-toggles-default-to-the-shipp.patch
MOVZX 777e910dd0 Initial commit
Signed-off-by: MOVZX <movzx@yahoo.com>
2026-10-15 01:01:52 +07:00

202 lines
9.5 KiB
Diff

From 5e39153dbfb58d752f93ce708c230db0f3987772 Mon Sep 17 00:00:00 2001
From: halt95 <halt95@users.noreply.github.com>
Date: Sun, 4 Oct 2026 09:23:24 -0400
Subject: [PATCH 090/103] envs: the MERLIN_* kernel toggles default to the
shipped value when unset
MERLIN_FULL_K, MERLIN_QSA_SORT, MERLIN_TIE_DET, MERLIN_TIE_RECENT and MERLIN_TOPK_SORTED_EMIT defaulted to off in
code while every shipped launcher set them to 1, so a launch without them ran a different kernel configuration.
vllm/env_override.py now sets each to 1 when unset; 0 still turns one off. tests/test_merlin_toggle_defaults.py
covers it.
---
.../moe/marlin_moe_wna16/ops.cu | 2 +-
csrc/libtorch_stable/persistent_topk.cuh | 4 +-
csrc/libtorch_stable/topk.cu | 8 ++--
tests/test_merlin_toggle_defaults.py | 48 +++++++++++++++++++
vllm/env_override.py | 16 +++++++
vllm/envs.py | 2 +-
.../qwen4_exp/nvidia/ops/qsa_indexer.py | 4 +-
7 files changed, 74 insertions(+), 10 deletions(-)
create mode 100644 tests/test_merlin_toggle_defaults.py
diff --git a/csrc/libtorch_stable/moe/marlin_moe_wna16/ops.cu b/csrc/libtorch_stable/moe/marlin_moe_wna16/ops.cu
index 0a6f5de..12a6a2c 100644
--- a/csrc/libtorch_stable/moe/marlin_moe_wna16/ops.cu
+++ b/csrc/libtorch_stable/moe/marlin_moe_wna16/ops.cu
@@ -49,7 +49,7 @@ namespace {
// Resolved ONCE per process, not per launch, so it is a launch constant in
// exactly the sense topk.cu's exact_medium_enabled() is: a cudagraph bakes in
// the value that was live at capture time and every replay agrees with it.
-// Default OFF -- enabling it by default is a separate release decision.
+// Code default off; vllm/env_override.py sets 1 (the shipped value) when unset.
//
// This std::getenv is the SINGLE source of truth. vllm/envs.py carries a raw
// passthrough entry for validate_environ and the compile-factor hash only;
diff --git a/csrc/libtorch_stable/persistent_topk.cuh b/csrc/libtorch_stable/persistent_topk.cuh
index 0b1b8b5..c86e63d 100644
--- a/csrc/libtorch_stable/persistent_topk.cuh
+++ b/csrc/libtorch_stable/persistent_topk.cuh
@@ -58,7 +58,7 @@ __device__ __forceinline__ auto convert_to_uint32_v2(float x) -> uint32_t {
// both the host (to report it) and the device (to obey it), so the reported
// policy and the executed policy cannot drift.
//
-// `MERLIN_TIE_DET=0` is the shipped default and leaves the buffered paths on
+// `MERLIN_TIE_DET=0` (the code default; launchers ship 1) leaves the buffered paths on
// their original racy atomicAdd rule, which has no direction; the medium-path exact
// restart is deterministic whatever happens, so it keeps the most-recent-wins
// direction the medium-path restart shipped and was measured with.
@@ -209,7 +209,7 @@ struct PersistentTopKParams {
// large tail) re-emit their OWN selected set through sorted_emit_row().
// Selection is never re-derived, so the selected set cannot change.
// Resolved once per process on the host, so it is a launch constant a
- // cudagraph bakes in. Default OFF.
+ // cudagraph bakes in. Code default off; vllm/env_override.py sets 1 (the shipped value) when unset.
bool sorted_emit;
};
diff --git a/csrc/libtorch_stable/topk.cu b/csrc/libtorch_stable/topk.cu
index 060f7a6..3200966 100644
--- a/csrc/libtorch_stable/topk.cu
+++ b/csrc/libtorch_stable/topk.cu
@@ -38,7 +38,7 @@ namespace {
//
// Our own toggle rather than upstream's VLLM_BATCH_INVARIANT, which aborts
// engine startup on GDN models (upstream #42960) and so can never reach this
-// kernel on Flash-Next. Default OFF -- promotion is a release decision.
+// kernel on Flash-Next. Code default off; vllm/env_override.py sets 1 (the shipped value) when unset.
//
// This std::getenv is the SINGLE source of truth; vllm/envs.py carries a raw
// passthrough for validate_environ and the compile-factor hash only.
@@ -72,7 +72,7 @@ bool publish_cached(std::atomic<int>& mirror, bool value) {
// most-recent-wins is +1.5 %. Both deterministic. Also the direction
// medium_exact_restart() already implements, so setting this alongside
// MERLIN_TIE_DET makes the medium path agree with itself on overflowing
-// rows. Only read when MERLIN_TIE_DET is set. Default OFF.
+// rows. Only read when MERLIN_TIE_DET is set; code default OFF; vllm/env_override.py sets 1 (the shipped value) when unset.
bool tie_recent_enabled() {
static const bool enabled = [] {
const char* raw = std::getenv("MERLIN_TIE_RECENT");
@@ -148,8 +148,8 @@ bool exact_decode_enabled() {
// (ascending index, padding last as -1), so qsa_indexer.py can drop that sort.
// See sorted_emit_row() in persistent_topk.cuh for the contract; the selected
// SET is never touched. Resolved once per process like every switch here, so
-// it is a launch constant a cudagraph bakes in. Default OFF: the maintainer
-// promotes after reference-host qualification.
+// it is a launch constant a cudagraph bakes in. Code default OFF; vllm/env_override.py
+// sets 1 (the shipped value) when unset.
//
// This std::getenv is the single source of truth. Python does not parse the
// variable to decide anything: qsa_indexer.py asks THIS cache, through
diff --git a/tests/test_merlin_toggle_defaults.py b/tests/test_merlin_toggle_defaults.py
new file mode 100644
index 0000000..bb17582
--- /dev/null
+++ b/tests/test_merlin_toggle_defaults.py
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
+"""Fork (v2.5): the MERLIN_* kernel toggles default to the shipped value (1) when
+unset, and an explicit "0" is left alone. Each case runs `import vllm` in a
+fresh interpreter, since env_override applies the defaults at import time."""
+
+import json
+import os
+import subprocess
+import sys
+
+import pytest
+
+NAMES = (
+ "MERLIN_FULL_K",
+ "MERLIN_QSA_SORT",
+ "MERLIN_TIE_DET",
+ "MERLIN_TIE_RECENT",
+ "MERLIN_TOPK_SORTED_EMIT",
+)
+
+
+def _env_after_import(overrides: dict) -> dict:
+ env = {k: v for k, v in os.environ.items() if k not in NAMES}
+ env.update(overrides)
+ code = (
+ "import json, os, vllm, vllm.envs as e;"
+ f"print(json.dumps({{n: os.environ.get(n) for n in {NAMES!r}}}"
+ " | {'QSA_SORT_ENVS': e.MERLIN_QSA_SORT}))"
+ )
+ out = subprocess.run(
+ [sys.executable, "-c", code], env=env, capture_output=True, text=True, check=True
+ )
+ return json.loads(out.stdout.strip().splitlines()[-1])
+
+
+def test_unset_toggles_default_to_the_shipped_value():
+ got = _env_after_import({})
+ assert {n: got[n] for n in NAMES} == dict.fromkeys(NAMES, "1")
+ assert got["QSA_SORT_ENVS"] is True
+
+
+@pytest.mark.parametrize("name", NAMES)
+def test_explicit_zero_is_kept(name):
+ got = _env_after_import({name: "0"})
+ assert got[name] == "0"
+ others = [n for n in NAMES if n != name]
+ assert all(got[n] == "1" for n in others)
diff --git a/vllm/env_override.py b/vllm/env_override.py
index a6b3c37..fc15a40 100644
--- a/vllm/env_override.py
+++ b/vllm/env_override.py
@@ -182,6 +182,22 @@ os.environ.setdefault("TRITON_CACHE_AUTOTUNING", "1")
# debug layout (see https://github.com/vllm-project/vllm/issues/41410).
os.environ.setdefault("TILELANG_CLEANUP_TEMP_FILES", "1")
+# Fork (v2.5, knob-absent boot): the MERLIN_* kernel toggles are read by
+# getenv in C++ (FULL_K, TIE_DET, TIE_RECENT, TOPK_SORTED_EMIT) and by
+# vllm.envs (QSA_SORT) with OFF as the code default, while every shipped
+# launcher sets them to 1. Unset now means the shipped value; an explicit "0"
+# still turns a toggle off. Set here because this module runs on `import vllm`,
+# before any reader, and worker processes inherit the environment.
+_SHIPPED_KERNEL_TOGGLE_DEFAULTS = (
+ "MERLIN_FULL_K",
+ "MERLIN_QSA_SORT",
+ "MERLIN_TIE_DET",
+ "MERLIN_TIE_RECENT",
+ "MERLIN_TOPK_SORTED_EMIT",
+)
+for _name in _SHIPPED_KERNEL_TOGGLE_DEFAULTS:
+ os.environ.setdefault(_name, "1")
+
# ===================================================
# torch 2.9 Inductor PythonWrapperCodegen monkeypatch
# ===================================================
diff --git a/vllm/envs.py b/vllm/envs.py
index 9fe769a..7b55618 100755
--- a/vllm/envs.py
+++ b/vllm/envs.py
@@ -515,7 +515,7 @@ if TYPE_CHECKING:
# --- determinism toggles -----------------------------------------
# The three nondeterminism mechanisms (FULL_K, QSA_SORT, TIE_DET/TIE_RECENT).
# Every one of them is
- # OFF by default: promotion is the maintainer's decision.
+ # OFF by default in this file; vllm/env_override.py sets each to 1 (the shipped value) when unset.
#
# Why these are registered at all: validate_environ() only inspects names
# beginning with VLLM_, so a MERLIN_ name never trips the unknown-variable
diff --git a/vllm/models/qwen4_exp/nvidia/ops/qsa_indexer.py b/vllm/models/qwen4_exp/nvidia/ops/qsa_indexer.py
index b9e88b0..45ace70 100644
--- a/vllm/models/qwen4_exp/nvidia/ops/qsa_indexer.py
+++ b/vllm/models/qwen4_exp/nvidia/ops/qsa_indexer.py
@@ -45,8 +45,8 @@ _DECODE_BLOCK_N = 64
# on the reference host and is why this version has no Python-visible branch on data.
#
# Resolved once at import so it is a launch constant: a cudagraph captures the
-# op sequence that was live at capture time. Default OFF -- promotion is a release
-# decision, which is the maintainer's.
+# op sequence that was live at capture time. Code default OFF; vllm/env_override.py
+# sets 1 (the shipped value) when unset.
# ---------------------------------------------------------------------------
_QSA_SORT = envs.MERLIN_QSA_SORT
--
2.43.0