Repository navigation
Conversation
Port della PR Niko1221#1437 di agorevski, head d006768; conserva la tabella upstream e adatta i callsite locali. Registra parità numerica e screening B-only L01/L02, con cache SSD native private. I token forzati non certificano qualità FREE e manca un controllo A prestazionale. Co-Authored-By: OpenAI Codex <noreply@openai.com>
|
Tested on RTX 2080 Ti (sm_75), which may be useful since the table was tuned only on a Quadro RTX 8000. Short version: it helps here too. Whole-model decode is +4.4% on average (up to +7%), and parity is bitwise. Setup
Note: this is a port, not the PR head. The PR conflicts with current
I did not port the parity-harness changes or Parity0.1.42's Kernel timingFrom 0.1.42's
The cells the table leaves out are small or lose on this card too, so the table's exclusions also hold here. For example, Q6_K 2560×512 at T=2 went 6.4 → 7.8 / 8.5 / 17.0 µs at rows 1/2/4. Whole-model decodeDecode tok/s through the server, temperature 0. Each cell is the median of 4 runs: two passes in opposite order (base before IL, then IL before base), server restarted per variant, 2 alternating rounds each. Runs were 400 tokens for en/ja/code and 300 tokens after a long prompt.
Caveats:
Port onto 61b3fb5 (0.1.42)diff --git a/include/strata/kernels/native_mmvq.hpp b/include/strata/kernels/native_mmvq.hpp
index fef71027..f7ff5b67 100644
--- a/include/strata/kernels/native_mmvq.hpp
+++ b/include/strata/kernels/native_mmvq.hpp
@@ -143,7 +143,8 @@ std::size_t native_q8_1_il_bytes(int n_in, int ncols);
// to x_il (native_q8_1_il_bytes): the same values in the same bytes.
void native_q8_1_interleave(const void* x_q8_1, void* x_il, int n_in, int ncols, void* stream);
// True when native_mmvq_il runs its own kernel for this call (IQ4_XS, Q4_K, Q5_K, Q6_K, 2-4 columns, the exact layout).
-bool native_mmvq_il_supported(int ggml_type, int ncols, int n_out);
+// n_in: the reduction width (sm_75's table is by exact shape; 0 = any)
+bool native_mmvq_il_supported(int ggml_type, int ncols, int n_out, int n_in = 0);
// native_mmvq for 2..4 columns whose copy native_q8_1_interleave wrote, bitwise native_mmvq's output: kernels in which a
// warp takes 1, 2 or 4 rows and reads the columns from the interleaved copy; native_mmvq (x_q8_1) when not supported.
void native_mmvq_il(int ggml_type, const void* weights, const void* x_q8_1, const void* x_il, float* y, int n_in,
diff --git a/src/core/verify.cpp b/src/core/verify.cpp
index 3e9ec069..f2a9896d 100644
--- a/src/core/verify.cpp
+++ b/src/core/verify.cpp
@@ -1009,7 +1009,7 @@ bool Verifier::record_window(int T, cudaStream_t cs, std::string& err) {
float* xm = mixed_ + tb * N;
bool il_ready = false; // xil_ holds xq_'s interleaved copy (reset whenever xq_ is rewritten)
auto mm = [&](const WeightRef* w, float* out, int n_in, int n_out) {
- if (g_mmvq_il() && strata::kernels::native_mmvq_il_supported(w->native_type, n, n_out)) {
+ if (g_mmvq_il() && strata::kernels::native_mmvq_il_supported(w->native_type, n, n_out, n_in)) {
if (!il_ready) {
strata::kernels::native_q8_1_interleave(xq_, xil_, n_in, n, cs);
il_ready = true;
@@ -1666,7 +1666,7 @@ bool Verifier::record_window(int T, cudaStream_t cs, std::string& err) {
if (head_ != nullptr && head_->loaded()) {
try {
native_quantize_q8_1(head_mixed_, xq_, (int) N, T, cs);
- if (g_mmvq_il() && strata::kernels::native_mmvq_il_supported(head_->type(), (int) T, (int) n_vocab_)) {
+ if (g_mmvq_il() && strata::kernels::native_mmvq_il_supported(head_->type(), (int) T, (int) n_vocab_, (int) N)) {
strata::kernels::native_q8_1_interleave(xq_, xil_, (int) N, (int) T, cs);
strata::kernels::native_mmvq_il(head_->type(), head_->weights(), xq_, xil_, head_logits_, (int) N,
(int) n_vocab_, (int) T, cs);
diff --git a/src/kernels/cuda/native_mmvq.cu b/src/kernels/cuda/native_mmvq.cu
index 6a47e6fa..45e940ce 100644
--- a/src/kernels/cuda/native_mmvq.cu
+++ b/src/kernels/cuda/native_mmvq.cu
@@ -2595,6 +2595,41 @@ namespace {
// native_mmvq's kernels unchanged
// Volta (PR 1401): opt-in with STRATA_SM70_TABLE=1 until the author confirms on a V100 with the final code
bool sm70_opt_in() { const char* v = std::getenv("STRATA_SM70_TABLE"); return v != nullptr && std::atoi(v) != 0; }
+// PR #1437 (ported to 0.1.42): Turing opt-in with exactly STRATA_MMVQ_IL=1. Quadro RTX 8000, mmvq_il_parity
+// --sm75-bench: two sweeps of seven alternating A/B pairs, cold-weight rotation, T=2/3/4; only cells where every
+// pair in both sweeps saves >=3% (charging the interleave launch). Exact GGUF dense shapes only.
+struct IlShapeRows { int type, n_in, n_out; uint8_t r[3]; };
+constexpr IlShapeRows kIlRowsSm75[] = {
+ {23, 2560, 640, {0, 0, 2}},
+ {23, 2560, 6144, {2, 4, 2}},
+ {23, 2560, 10240, {2, 2, 2}},
+ {23, 2560, 12288, {2, 4, 2}},
+ {12, 2560, 6144, {2, 2, 2}},
+ {12, 2560, 10240, {2, 2, 2}},
+ {12, 2560, 12288, {4, 2, 2}},
+ {12, 6144, 2560, {4, 2, 2}},
+ {13, 2560, 6144, {2, 2, 2}},
+ {13, 2560, 10240, {2, 4, 4}},
+ {13, 2560, 12288, {4, 2, 4}},
+ {13, 6144, 2560, {0, 4, 4}},
+ {14, 2560, 6144, {0, 2, 4}},
+ {14, 2560, 10240, {2, 2, 4}},
+ {14, 2560, 12288, {2, 4, 4}},
+ {14, 6144, 2560, {0, 2, 2}},
+ {14, 2560, 248320, {2, 4, 2}},
+};
+bool sm75_opt_in() {
+ static const int on = [] { const char* v = std::getenv("STRATA_MMVQ_IL"); return v != nullptr && std::strcmp(v, "1") == 0; }();
+ return on != 0;
+}
+int il_rows_sm75(int type, int ncols, int n_out, int n_in) {
+ for (const IlShapeRows& e : kIlRowsSm75)
+ if (e.type == type && e.n_out == n_out && (n_in == 0 || e.n_in == n_in))
+ return e.r[ncols - 2];
+ return 0;
+}
+// rows a warp for this call on this card (0: native_mmvq)
+int il_dispatch_rows(int type, int ncols, int n_out, int n_in);
bool il_arch_ok() {
static int ok[16] = {}; // 0 unknown, 1 yes, -1 no, by device ordinal
int dev = 0;
@@ -2604,25 +2639,34 @@ bool il_arch_ok() {
int minor = 0;
cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, dev);
ok[dev] = (cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, dev) == cudaSuccess &&
- (major >= 8 || (major == 7 && minor == 0 && sm70_opt_in()))) ? 1 : -1;
+ (major >= 8 || (major == 7 && minor == 0 && sm70_opt_in()) ||
+ (major == 7 && minor == 5))) ? 1 : -1;
}
return ok[dev] > 0;
}
} // namespace
-bool native_mmvq_il_supported(int ggml_type, int ncols, int n_out) {
- if (ncols < 2 || ncols > 4 || !g_multi_exact || !il_arch_ok()) return false;
- return (g_tune_rows ? g_tune_rows : il_rows(ggml_type, ncols, n_out)) != 0 &&
- (ggml_type == 23 || ggml_type == 12 || ggml_type == 13 || ggml_type == 14);
+namespace {
+int il_dispatch_rows(int type, int ncols, int n_out, int n_in) {
+ if (ncols < 2 || ncols > 4 || !g_multi_exact || !il_arch_ok() ||
+ (type != 23 && type != 12 && type != 13 && type != 14)) return 0;
+ if (g_tune_rows) return g_tune_rows;
+ if (il_cc() == 75) return sm75_opt_in() ? il_rows_sm75(type, ncols, n_out, n_in) : 0;
+ return il_rows(type, ncols, n_out);
+}
+} // namespace
+
+bool native_mmvq_il_supported(int ggml_type, int ncols, int n_out, int n_in) {
+ return il_dispatch_rows(ggml_type, ncols, n_out, n_in) != 0;
}
void native_mmvq_il(int ggml_type, const void* weights, const void* x_q8_1, const void* x_il, float* y, int n_in,
int n_out, int ncols, void* stream) {
- if (!native_mmvq_il_supported(ggml_type, ncols, n_out)) {
+ const int r = il_dispatch_rows(ggml_type, ncols, n_out, n_in);
+ if (!r) {
native_mmvq(ggml_type, weights, x_q8_1, y, n_in, n_out, ncols, stream);
return;
}
- const int r = g_tune_rows ? g_tune_rows : il_rows(ggml_type, ncols, n_out);
validate_shape(n_in, ncols, QK);
validate_pointer(weights);
validate_pointer(x_il);
@@ -2643,7 +2687,7 @@ std::size_t native_q8_1_il_bytes(int n_in, int ncols) { return native_q8_1_bytes
void native_q8_1_interleave(const void*, void*, int, int, void*) {
throw std::invalid_argument("native_q8_1_interleave is CUDA only");
}
-bool native_mmvq_il_supported(int, int, int) { return false; }
+bool native_mmvq_il_supported(int, int, int, int) { return false; }
int native_mmvq_il_rows_for(int, int, int, int) { return 0; }
void native_mmvq_il(int ggml_type, const void* weights, const void* x_q8_1, const void*, float* y, int n_in, int n_out,
int ncols, void* stream) { |
…o e --sm75-bench (PR Niko1221#1437) Casi con code di righe e riduzione, forme dense del GGUF IQ3_S, verifica che 1/2/4 forzati e la tabella lancino davvero il kernel atteso, opt-in rigoroso su Turing, tabella sm_75 controllata senza scheda, banco a coppie A/B. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…solo l'input su rami del grafo (PR Niko1221#1889) Diff del PR applicato com'è, più due adattamenti: le due chiamate a native_mmvq_il_supported del ramo =2 passano n_in (API del Niko1221#1437), e con STRATA_SIDE_MIXER acceso STRATA_DF_BRANCH (acceso di default su Windows) si spegne già in init senza creare i suoi stream; se era chiesto esplicitamente lo dice una volta su stderr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…75 (PR Niko1221#1437) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Another Turing data point, in case it helps this land. I measured a table on a third sm_75 card before I saw this PR, and have closed my duplicate (#2089). Card: NVIDIA CMP 50HX, a TU102 at RTX 2080 Ti clocks (2100 MHz, 56 SMs). Driver 610.43.03, CUDA 13.3, GCC 14, Linux. Parity: Kernel times,
Table from Decode A/B in the engine:
So this is a third Turing card, alongside the Quadro RTX 8000 and the RTX 2080 Ti above, with a gain in the same direction. On the same card, |
Select exact dense shapes for Turing only with STRATA_MMVQ_IL=1. Observe actual dispatch, expand bitwise parity and paired tuning, and document RTX 8000 measurements without generalizing them to other sm75 cards. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7c2bcbb-4264-4eb2-879d-c71a90285b0b
Register CPU-only architecture and exact-shape isolation checks, retain Q3_K and one-column benchmark emission, and document the upstream integration and separately attributed community measurements. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7c2bcbb-4264-4eb2-879d-c71a90285b0b
Keep class-table emission kernel-only, but normalize each row choice against its paired reference instead of reusing the last row choice baseline. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7c2bcbb-4264-4eb2-879d-c71a90285b0b
d006768 to
43c2c36
Compare
|
Thanks, ioridev and xrip. Rebased onto CUDA 12.4/GCC 13 build: passed. CPU policy checks: 3/3 passed. Physical GPU 3, exclusively locked: four full parity policies passed bitwise, 720 forced launches each; opt-in selected 86 IL/154 fallback, other policies 0/240. Both benchmark-interface smoke checks passed. CUDA worked despite the reported NVML mismatch; no drivers/power settings changed. Docs attribute the RTX 2080 Ti port (+4.4%) separately from the CMP 50HX different table (+7%); EXP_MODE remains out of scope. No new whole-model measurements. Updated head |
|
Thanks for the rebase, and for crediting the RTX 2080 Ti numbers separately in the docs! |
Title
Opt in to measured sm_75 interleaved dense verify projections
Issue: No closing reference. Related context: #1349, #2007, #1842; this PR does not establish a fix for those reports.
Summary
Allow Turing (sm_75) to reuse interleaved Q8_1 activations for measured IQ4_XS/Q4_K/Q5_K/Q6_K dense projections in 2–4-token verify windows. Require exactly
STRATA_MMVQ_IL=1and exact input/output dimensions; unset,0,true, unspecified reduction width and unlisted shapes retain the native fallback.The branch has been rebased onto fetched
origin/mainata0116b2782a5b82622358c04a06496485d12b2d6, notmaster. Original headd0067686ac537ec0f12617e7ce6458d95b913ad1is preserved bybackup/pr1437-d0067686-rebase-20261012-1152. Rebased implementation:680b7f6846de07255ee5a20a0e852ba080b38bf6; follow-up tests/documentation:556f82d2e639f2a4292e752bc21dfd8a95b8552b; final paired-emission correction/head:43c2c361c0f965931380b6467f49602af7e952c3.What changed
kIlArchandnative_mmvq_il_rows_for, extending the lookup with reduction width. Preserve upstream Pascal/Volta/Ampere/shared tables, Q3_K kernels, one-column handling andSTRATA_MMVQ_IL_ROWSon the other eligible architectures. Class overrides cannot broaden sm_75's measured exact-shape policy. The sm_75 table entries are unchanged from the original PR.n_inat both dense-projection and output-head eligibility call sites inverify.cpp. Keep upstream'sn >= 2/T >= 2guards so one-column calls do not interleave.MMVQ_IL_ONLY,--bench --emit-table, output-row-class table emission and its one-column entries; retain--sm75-benchfor the original 2–4-column paired sweep including pack cost.docs/OLDER_GPUS.mdanddocs/MMVQ_IL_TABLE.mdwith architecture selection, the override boundary, CPU checks and clearly attributed community reports.No old conflicted file was restored wholesale. No upstream architecture tables, one-column or Q3_K support were removed. No community class table or
STRATA_EXP_MODEchange is adopted.Extra Notes
Comment follow-up and independent reports
main, retaining its new APIs/features rather than reverting them. Their measurements were a port of the unchanged table onto 0.1.42 (61b3fb5d), with the strict opt-in and actual input widths, not the exact PR head. They did not port this PR's extended harness or last-launch observer. On two RTX 2080 Ti cards (22 GB main / 11 GB peer, 250 W, i9-9820X, CUDA 12.4/GCC 15.2), IQ3_S + MTP, spec 4, INT8 KV, BF16_TC and SELECT_SIMT enabled, they reported bitwise parity using 0.1.42's harness and mean decode 68.3 → 71.3 tok/s (+4.4%, five workloads, four-run medians with reversed arm order). Their ~8K measurements were noisy; baseline greedy replies already varied, so text equality was not their correctness evidence. These are their results, not our new tests or measurements of the rebased head.STRATA_EXP_MODE=8expert-layout results are outside this PR.The PR discussion comments and reviews, plus
GET repos/Niko1221/Strata/pulls/1437/comments, were read. There were no formal reviews or inline review comments returned; the two discussion reports above are addressed in the code/docs and follow-up reply.Historical author measurements, not a rebased whole-model retest
Original Quadro RTX 8000 tuning retained 46/69 measured shape/window cells: every paired trial in both seven-pair sweeps saved at least 3%, charging the full interleave launch. The retained entries remain unchanged.
Previously recorded controlled whole-model decode medians (three runs per prompt, 128 outputs):
STRATA_MMVQ_IL=1(tok/s)Quadro RTX 8000, 260 W, Xeon W-2295, CUDA 12.4/GCC 13, IQ3_S + MTP, spec 4, fixed 19,000 expert slots, automatic prefill 8,192, INT8 KV, maximum context 262,144 / resident 32,768, PCIe fraction 0.20. Prompt caching and adaptation were disabled; BF16_TC was already enabled in both arms, with BF16 cache, SIMT scorer and CPU prefill sharing off. These are historical results, not fresh server runs after this rebase.
Fresh local build and exact validation outcomes
All commands ran in the independent worktree:
/home/algore/.copilot/session-state/a7c2bcbb-4264-4eb2-879d-c71a90285b0b/files/pr-worktrees/sm75-verify.The original dirty checkout was not modified; only its requested llama.cpp vendor source was shared read-only.
Results: fresh configure passed, exit 0; both targets built, exit 0, with CUDA 12.4.131 and system GCC/G++ 13.3.0. Final-source rebuild also passed, exit 0. Compiler warnings were emitted, but no build/tool incompatibility was encountered. Focused CPU tests passed 3/3, exit 0.
The host was reported to have an NVML driver/library mismatch (
nvidia-smi, NVML 580.178). We did not reboot, replace drivers/libraries or change the user environment. The actual CUDA runtime worked: the first bounded attempt below passed, and only then were full parity and bounded benchmark-interface checks run. This does not assert NVML was repaired.flock -x /home/algore/.copilot/session-state/a7c2bcbb-4264-4eb2-879d-c71a90285b0b/files/pr-gpu3.lock \ env -u STRATA_MMVQ_IL_ROWS -u STRATA_MMVQ_IL_T1 -u STRATA_MMVQ_IL_Q3K \ CUDA_DEVICE_ORDER=PCI_BUS_ID CUDA_VISIBLE_DEVICES=3 STRATA_MMVQ_IL=1 \ MMVQ_IL_ONLY='IQ4_XS 2560x6144' ./build-rebase1437-sm75/mmvq_il_parityResult: passed, exit 0, Quadro RTX 8000 logical 0 / physical 3, bitwise T=1–4; 24 forced interleaved, 6 automatic interleaved / 2 fallback launches.
Final-source full validation command (the exclusive lock covers the entire loop and both smoke commands):
Results:
=1: passed, exit 0, bitwise T=1–4; 720 forced interleaved, 86 automatic interleaved / 154 fallback launches.=0,=true, unset: each passed, exit 0, bitwise T=1–4; each 720 forced interleaved, 0 automatic interleaved / 240 fallback launches. Strict opt-in and exact-shape assertions passed.--bench --emit-table, filtered Q3_K shape: passed, exit 0, including actual forced Q3_K one-column launches and class/one-column emission; 12 forced interleaved, 0 automatic / 4 fallback.--sm75-bench, filtered IQ4_XS shape: passed, exit 0, T=2–4, seven alternating pairs per forced-row choice with pack cost; 9 forced interleaved, 3 automatic / 0 fallback. These bounded smoke checks are not a new full tuning sweep or grounds for replacing the measured table.Logs remain in the worktree as
build-rebase1437-*.log(untracked build artifacts are ignored). No servers, power-limit changes or other GPUs were used. Other architectures were host-table-tested, not hardware-tested or compiled for their architectures. No new whole-model measurements were taken.Related issues found through repository issue search
No
Resolves/Fixesclaim is made.