-
Notifications
You must be signed in to change notification settings - Fork 249
feat(kvflash): snapshot ledger + QK-pool restore-seed + consume-restored-KV #446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
6f7e792
perf(qwen35moe): pool-sized KV reservation keeps experts hot at high …
dusterbloom b5a1808
feat(kvflash): pager serialize/deserialize + critical-chunk pinning
dusterbloom 7c7d618
feat(qwen35moe): pooled chunked prefill + pooled snapshot/restore ove…
dusterbloom 1a78f7f
refactor(qwen35moe): dedup chunked-prefill loops + inline for_each_se…
dusterbloom 7047300
fix(kvflash): save pooled prefix snapshot at chunk boundary so ≥128K …
dusterbloom b1d748f
feat(kvflash): snapshot ledger + QK-pool restore-seed (lib + tests) f…
dusterbloom b7a1e91
feat(kvflash): consume restored KV on pooled restore instead of re-pr…
dusterbloom 3366fda
fix(kvflash): reconstruct restored-prefix drafter-history from ledger…
dusterbloom d61cfa5
test(server): cold_prefix_boundary returns 4000 after layout_known_ g…
dusterbloom 17e97d9
fix(cubic): address production P1/P2 review findings (bounded loop, O…
dusterbloom 6d7eb3e
fix(kvflash): reconstruct pooled-K from ledger on QK warm-restore
dusterbloom File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| #!/usr/bin/env python3 | ||
| """Phase 3 intra-process gate: greedy bit-identity at the restore seam. | ||
|
|
||
| Methodology: ONE server launch. Build snapshot in turns 1+2. Then send | ||
| the SAME turn-3 request TWICE back-to-back (same snapshot slot, same temp=0). | ||
|
|
||
| Then restart with KVFLASH_RESTORE_CONSUME=1 and repeat the same sequence. | ||
|
|
||
| Compare: | ||
| consume=0 run1 vs consume=0 run2 → measures re-prefill reproducibility | ||
| consume=0 run1 vs consume=1 run1 → the real Phase 3 gate | ||
|
|
||
| If (C0_r1 == C0_r2) AND (C0_r1 != C1_r1): Phase 3 has a real seam bug. | ||
| If (C0_r1 != C0_r2): re-prefill itself is non-deterministic (GPU FP variance); | ||
| Phase 3 cannot be gated by text comparison. | ||
| If (C0_r1 == C0_r2 == C1_r1): Phase 3 PASSES. | ||
|
|
||
| Port 18081 only. Never 18099. temp=0. flock /tmp/lucebox_gpu.lock. | ||
| """ | ||
| from __future__ import annotations | ||
| import fcntl, json, os, re, subprocess, sys, time, urllib.request | ||
| from pathlib import Path | ||
|
|
||
| HOST = "127.0.0.1" | ||
| PORT = 18081 | ||
| SERVER_BIN = Path("/home/peppi/Dev/lucebox-hub/server/build/dflash_server") | ||
| MODEL_TGT = Path("/home/peppi/models/qwen3.6-35b-a3b/Qwen3.6-35B-A3B-UD-Q3_K_XL.gguf") | ||
| MODEL_DRAFT = Path("/home/peppi/models/qwen3.6-35b-a3b-dflash-new/qwen3.6-35b-a3b-dflash-new-bf16-reconv.gguf") | ||
| TMPL = Path("/home/peppi/models/qwen3-coder-chat-template.jinja") | ||
| PROMPT_FILE = Path("/home/peppi/Dev/lucebox-hub/bench/qwen35moe_dflash/ctxsweep/ctx_032768.json") | ||
| BENCH_DIR = Path(__file__).parent | ||
| MAX_CTX, KV_POOL, MAX_GEN = 131072, 8192, 64 | ||
| SYSTEM_MSG = "You are a helpful coding assistant. Analyze the provided source code carefully and answer questions accurately." | ||
| FOLLOW_UP_2 = "Please summarize what you found in one sentence." | ||
| FOLLOW_UP_3 = "What is the computational complexity of the main loop?" | ||
|
|
||
| def wait_server(timeout=360): | ||
| dl = time.time() + timeout | ||
| while time.time() < dl: | ||
| try: | ||
| with urllib.request.urlopen(f"http://{HOST}:{PORT}/health", timeout=3) as r: | ||
| if r.status == 200: return True | ||
| except: pass | ||
| time.sleep(2) | ||
| return False | ||
|
|
||
| def launch_server(consume: bool, log_path: Path, *, with_draft: bool = False): | ||
| env = dict(os.environ) | ||
| env.update({"GGML_CUDA_NO_VMM":"1","DFLASH_FEAT_RING_CAP":"65536", | ||
| "DFLASH_SPEC_GATE":"1","DFLASH_DRAFT_CTX_MAX":"2048", | ||
| "DFLASH_DRAFT_BLOCK_SIZE":"16", | ||
| "KVFLASH_RESTORE_CONSUME":"1" if consume else "0"}) | ||
| cmd = [str(SERVER_BIN), str(MODEL_TGT), | ||
| "--host",HOST,"--port",str(PORT), | ||
| "--max-ctx",str(MAX_CTX), | ||
| "--cache-type-k","f16","--cache-type-v","f16", | ||
| "--chat-template-file",str(TMPL), | ||
| "--model-name","luce-dflash", | ||
| "--kvflash",str(KV_POOL)] | ||
| if with_draft: | ||
| cmd += ["--draft",str(MODEL_DRAFT),"--draft-swa","2048"] | ||
| print(f" [launch] consume={'1' if consume else '0'} log={log_path.name}") | ||
| lf = log_path.open("w") | ||
| return subprocess.Popen(cmd,env=env,stdout=lf,stderr=lf), lf | ||
|
|
||
| def kill_server(proc, lf): | ||
| if proc and proc.poll() is None: | ||
| proc.terminate() | ||
| try: proc.wait(15) | ||
| except subprocess.TimeoutExpired: proc.kill(); proc.wait(5) | ||
| if lf: lf.close() | ||
|
|
||
| def api(msgs, max_tok=MAX_GEN, system=SYSTEM_MSG): | ||
| body = json.dumps({"model":"luce-dflash","max_tokens":max_tok, | ||
| "temperature":0.0,"system":system,"messages":msgs}, | ||
| ensure_ascii=False).encode() | ||
| req = urllib.request.Request(f"http://{HOST}:{PORT}/v1/messages", | ||
| data=body,headers={"Content-Type":"application/json"},method="POST") | ||
| with urllib.request.urlopen(req,timeout=600) as r: | ||
| return json.loads(r.read()) | ||
|
|
||
| def text(body): | ||
| c = body.get("content",[]) | ||
| if isinstance(c,str): return c | ||
| return "".join(b.get("text","") for b in c if isinstance(b,dict) and b.get("type")=="text") | ||
|
|
||
| DONE_RE = re.compile(r'\[server\] chat DONE\s+\S+\s+ok=\w+\s+in=\d+\s+effective_in=\d+\s+out=\d+\s+[\d.]+s\s+[\d.]+\s+tok/s\s+finish=\S+\s+restore=(\w+)\s+slot=(-?\d+)\s+prefix_len=(\d+)\s+prefill=([\d.]+)s') | ||
|
|
||
| def parse_done(log, idx): | ||
| ms = DONE_RE.findall(log) | ||
| if len(ms) <= idx: return {} | ||
| m = ms[idx] | ||
| return {"restore":m[0]=="true","slot":int(m[1]),"prefix":int(m[2]),"prefill_s":float(m[3])} | ||
|
|
||
| def run_in_server(consume: bool, with_draft: bool = False) -> dict: | ||
| ts = time.strftime("%Y%m%d_%H%M%S") | ||
| label = f"c{'1' if consume else '0'}_{'spec' if with_draft else 'ar'}" | ||
| log_path = BENCH_DIR / f"phase3_intraproc_{ts}_{label}.log" | ||
| proc, lf = launch_server(consume, log_path, with_draft=with_draft) | ||
| try: | ||
| print(f" waiting...", end=" ", flush=True) | ||
| if not wait_server(): raise RuntimeError("timeout") | ||
| print("ready") | ||
|
|
||
| req_data = json.loads(PROMPT_FILE.read_text()) | ||
| user_msg = req_data["messages"][0]["content"] | ||
|
|
||
| # Turn 1 | ||
| print(" turn1...", end=" ", flush=True) | ||
| t1 = text(api([{"role":"user","content":user_msg}])) | ||
| time.sleep(1) | ||
| log = log_path.read_text() | ||
| d1 = parse_done(log, 0) | ||
| print(f"prefill={d1.get('prefill_s',0):.1f}s chars={len(t1)}") | ||
|
|
||
| # Turn 2 (grows conv, saves snapshot) | ||
| msgs2 = [{"role":"user","content":user_msg}, | ||
| {"role":"assistant","content":t1.strip()}, | ||
| {"role":"user","content":FOLLOW_UP_2}] | ||
| print(" turn2...", end=" ", flush=True) | ||
| t2 = text(api(msgs2)) | ||
| time.sleep(1) | ||
| log = log_path.read_text() | ||
| d2 = parse_done(log, 1) | ||
| snap_committed = "[pc] inline-snap committed" in log | ||
| print(f"prefill={d2.get('prefill_s',0):.1f}s snap={'OK' if snap_committed else 'MISSING'}") | ||
| if not snap_committed: | ||
| raise RuntimeError("no snapshot committed after turn 2") | ||
|
|
||
| # Turn 3 — send TWICE from the same snapshot | ||
| msgs3 = [{"role":"user","content":user_msg}, | ||
| {"role":"assistant","content":t1.strip()}, | ||
| {"role":"user","content":FOLLOW_UP_2}, | ||
| {"role":"assistant","content":t2.strip()}, | ||
| {"role":"user","content":FOLLOW_UP_3}] | ||
|
|
||
| print(" turn3 (req A)...", end=" ", flush=True) | ||
| t3a = text(api(msgs3)) | ||
| time.sleep(1) | ||
| log = log_path.read_text() | ||
| d3a = parse_done(log, 2) | ||
| print(f"restore={d3a.get('restore')} prefix={d3a.get('prefix')} " | ||
| f"prefill={d3a.get('prefill_s',0):.3f}s") | ||
| print(f" {repr(t3a[:120])}") | ||
|
|
||
| print(" turn3 (req B, same snapshot)...", end=" ", flush=True) | ||
| t3b = text(api(msgs3)) | ||
| time.sleep(1) | ||
| log = log_path.read_text() | ||
| d3b = parse_done(log, 3) | ||
| print(f"restore={d3b.get('restore')} prefix={d3b.get('prefix')} " | ||
| f"prefill={d3b.get('prefill_s',0):.3f}s") | ||
| print(f" {repr(t3b[:120])}") | ||
|
|
||
| return {"t3a":t3a,"t3b":t3b,"d3a":d3a,"d3b":d3b,"log":str(log_path)} | ||
| finally: | ||
| kill_server(proc, lf) | ||
| time.sleep(3) | ||
|
|
||
| def cmp(label_a, a, label_b, b): | ||
| if a == b: print(f" {label_a} vs {label_b}: IDENTICAL ({len(a)} chars)"); return True | ||
| min_l = min(len(a),len(b)) | ||
| fd = next((i for i in range(min_l) if a[i]!=b[i]), min_l) | ||
| print(f" {label_a} vs {label_b}: DIVERGE @ char {fd}") | ||
| print(f" {label_a}: {repr(a[max(0,fd-10):fd+30])}") | ||
| print(f" {label_b}: {repr(b[max(0,fd-10):fd+30])}") | ||
| return False | ||
|
|
||
| def main(): | ||
| print(f"Phase 3 intra-process gate") | ||
| md5 = subprocess.check_output(["md5sum",str(SERVER_BIN)],text=True).strip() | ||
| print(f" binary: {md5}") | ||
| print() | ||
|
|
||
| # Acquire GPU lock | ||
| gpu_lock_fd = open("/tmp/lucebox_gpu.lock","w") | ||
| fcntl.flock(gpu_lock_fd, fcntl.LOCK_EX) | ||
|
|
||
| try: | ||
| # AR-only gate (no draft = no spec decode = feature-mirror-independent) | ||
| print("=== ARM A: consume=0, AR-only ===") | ||
| r0 = run_in_server(consume=False, with_draft=False) | ||
| print() | ||
| print("=== ARM B: consume=1, AR-only ===") | ||
| r1 = run_in_server(consume=True, with_draft=False) | ||
| finally: | ||
| fcntl.flock(gpu_lock_fd, fcntl.LOCK_UN) | ||
| gpu_lock_fd.close() | ||
|
|
||
| print() | ||
| print("=" * 60) | ||
| print("RESULTS") | ||
| print("=" * 60) | ||
| c0_self = cmp("C0.A", r0["t3a"], "C0.B", r0["t3b"]) | ||
| c1_self = cmp("C1.A", r1["t3a"], "C1.B", r1["t3b"]) | ||
| c0_c1 = cmp("C0.A", r0["t3a"], "C1.A", r1["t3a"]) | ||
| print() | ||
|
|
||
| p0 = r0["d3a"].get("prefill_s",0) | ||
| p1 = r1["d3a"].get("prefill_s",0) | ||
| speedup = p0/p1 if p1>0.001 else float("inf") | ||
|
|
||
| print(f" C0.A prefill={p0:.3f}s C1.A prefill={p1:.3f}s speedup={speedup:.1f}x") | ||
| print() | ||
| print("NOTE: Both arms run WITHOUT draft model (AR-only decode).") | ||
| print("This eliminates spec-decode as a divergence source (feature-mirror FP variance)") | ||
| print("and isolates the Phase 3 KV+SSM seam correctness.") | ||
| print() | ||
|
|
||
| if not c0_self: | ||
| print("INFRASTRUCTURE: C0 not self-consistent in AR mode.") | ||
| print("AR decode must be deterministic (temp=0 greedy, same model, same KV).") | ||
| print("Unexpected hardware or driver issue. Phase 3 inconclusive.") | ||
| sys.exit(2) | ||
| if c0_self and not c0_c1: | ||
| print("GATE: FAIL — AR C0 is self-consistent but AR C1 diverges.") | ||
| print("Phase 3 KV+SSM seam bug confirmed. Target attention diverges.") | ||
| print("The feature mirror is NOT the cause (both arms use AR without draft).") | ||
| sys.exit(1) | ||
| if c0_self and c0_c1: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Gate result can falsely pass when consume=1 is internally non-deterministic because c1_self is not included in pass/fail conditions. Prompt for AI agents |
||
| print(f"GATE: PASS (AR mode) — C0 self-consistent AND C1 identical to C0.") | ||
| print(f"Phase 3 KV+SSM seam is correct. Warm-prefill speedup: {p0:.3f}s -> {p1:.3f}s ({speedup:.1f}x)") | ||
| print() | ||
| print("DIAGNOSIS: The previous spec-decode test diverged due to feature-mirror FP") | ||
| print("variance across turn boundaries (turn-2 GPU output != turn-3 recompute).") | ||
| print("This is NOT a Phase 3 KV+SSM correctness bug.") | ||
| print(f"\nLogs:\n {r0['log']}\n {r1['log']}") | ||
| sys.exit(0) | ||
|
|
||
| if __name__=="__main__": | ||
| main() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Prefill metric extraction conflates absent prefill_s with 0.0, producing misleading speedup/output when parse_done fails.
Prompt for AI agents