Pull requests / #2630

#2630 kv: --kv-evict clock|lrfu, the streamed page pool's victim pick (#2415)

open · @MrKop-git · 0 comentarios · En GitHub

BenchmarksMulti-GPUAMD / HIPModels & quantsSecurity

Descripción

## Summary

The measurement half of #2415 asked whether the streamed page pool should evict by something other than the resolve kernel's clock sweep. This is the other half: the option itself.

When the pool is full the kernel evicts one block per miss. `--kv-evict clock` (the default, the engine's own) sweeps slots from a hand and takes the first that is unreferenced. `--kv-evict lrfu` keeps a per-block score that **survives eviction**, decays a little every call (the policy bench's lambda = 0.5 per 64 calls), gains on a hit, and evicts the lowest-scoring block - with ties going to the least recently used slot. That tie rule matters: a just-loaded block scores 0 and would otherwise be the first victim, where the clock sweep's reference bit gives it the same second chance.

## What it changes and what it leaves alone

The pool is a cache over an authoritative RAM copy, so **the output cannot change** - the flag only decides which blocks are re-read from RAM. Without `--kv-evict` nothing is allocated, no score is kept and the kernel takes the clock sweep exactly as before.

## How it was checked

- **`kv_stream_parity` PASS** in both modes, all four KV formats - the invariant (streamed == resident, bitwise) holds, and the two modes show the different miss counts the two picks produce on the same selections (int8: 69,581 clock vs 101,744 lrfu over 306 batches).
- **Live counters on this box's GTX 1080 Ti** (IQ3_S, `--kv int8 --kv-resident 32768`, 64K-token prompt + 128 decode tokens, ABBA):

| arm | hit rate | MiB read from RAM | tok/s |
|---|---|---|---|
| clock | 87.89 / 87.23 % | 489.9 / 472.5 | 27.86 / 31.63 |
| lrfu | **88.14 / 88.68 %** | 476.8 / 485.9 | 24.62 / 19.52 |

LRFU reads no more from RAM and its hit rate is a little higher, which is the direction the offline bench predicts: on real selection traces (a 4K-token prompt and a 64K-token one) `tools/replay_kv_stream_policy.py` has LRFU re-reading **2.6-6.0% fewer blocks** than clock at pool sizes between one call's width and the working set, while on the `kv_stream_parity` synthetic pattern (a sliding recent window mixed with uniform draws) clock wins and lrfu matches its own offline model.

## What it does not claim

**No speed claim.** The wall clock did not separate (27.86/31.63 vs 24.62/19.52 tok/s) and could not here: the runs' work differs (918K-1.07M lookups, drafts 74-90 accepted) and this box's run-to-run spread is ±40%. The default stays `clock` per the repo's rule that a default changes only where it was measured faster - the flag is opt-in so the two can be compared on a quieter machine and on the workloads that matter.

## Not tested

HIP (no toolchain here) and SYCL (a separate engine tree with its own `kv_stream` sources); `--batch` and the layer-split paths; long multi-request sessions where the scores accumulate across requests.

⚠️ One build note for reviewers: this branch needs a **normal** `cmake --build`. The `make <target>/fast` shortcuts skip header-dependency checks, so after `kv_stream.hpp`'s `KvStreamMap` grew they left stale objects with the old layout and the engine faulted with an illegal memory access at prefill. Nothing in the PR depends on that; it cost an evening to bisect.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

En el sitio

Enlaces a install, modelos, releases.