Add neutral KV-cache core: registry and bookkeeping#21383
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21383
Note: Links to docs will display an error until the docs builds have been completed. ❌ 5 New Failures, 4 Pending, 2 Unrelated Failures, 1 Unclassified FailureAs of commit 94744ea with merge base 1fb8b57 ( NEW FAILURES - The following jobs have failed:
UNCLASSIFIED FAILURE - DrCI could not classify the following job because the workflow did not run on the merge base. The failure may be pre-existing on trunk or introduced by this PR:
FLAKY - The following jobs failed but were likely due to flakiness present on trunk:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
e16a69c to
116bf40
Compare
This PR needs a
|
116bf40 to
94744ea
Compare
| int n_layers; | ||
| std::vector<int> n_kv_heads; | ||
| std::vector<int> head_dim; | ||
| int min_chunk = 512; |
| // Integer-only handoff from bookkeeping to the backend byte layer: where to | ||
| // write this step and how much history to read. | ||
| struct StepPlan { | ||
| bool contiguous; |
|
|
||
| def define_common_targets(): | ||
| pass | ||
| """Defines targets that should be shared between fbcode and xplat. |
There was a problem hiding this comment.
Either stick with CMake only (we can buckify later), or if doing buck, let's import to internal to make sure it works
| // Contiguous single-sequence bookkeeping: history is a length counter; writes | ||
| // append at the current position and reads cover [0, length). Backends inherit | ||
| // this for the runner-facing methods and the per-step plan. | ||
| class ContiguousBookkeeping : public Cache { |
There was a problem hiding this comment.
Two things about this I'm hesitant about:
- I don't like the name Contiguous b/c it implies something about memory
- The interface here has two audiences that want separate APIs: 1) the backends which want "plan", and 2) the application/user which wants "can_extend" / "clear" / "rewind".
What do you think of splitting the "Bookkeeping" class to serve these two audiences. Something like "Control" class for application, and "Planner" for backend. A cache inherits both "FlatCache : public SequenceControl, public SequencePlanner"
class CacheBase { // registry ownership / erasure anchor
public: virtual ~CacheBase() = default;
};
class SequenceControl : public virtual CacheBase { // application face
public:
virtual bool can_extend(int n = 1) const = 0;
virtual void rewind(int new_len) = 0;
virtual void clear() = 0;
};
class SequencePlanner : public virtual CacheBase { // backend face
public:
virtual SeqStepPlan plan(int position, int T) = 0;
};
// ---- Flat: non-wrapping, full history [0,length) --------------------------
class FlatCache : public SequenceControl, public SequencePlanner
// ---- Ring: sliding window, wraps, evicts ---------------------------------
class RingCache : public SequenceControl, public SequencePlanner
The planner and step plan are tied. SequencePlanner (single sequence) returns a step plan like this:
struct Run { int start = 0; int len = 0; }; // contiguous slot range in the pool
struct SeqStepPlan {
bool contiguous = true; // hint: single write run AND single read run (no wrap)
int valid_len = 0; // # valid context rows (= sum of read lens)
Run write[2]; // where the T new rows land (1 run, or 2 on ring wrap)
Run read[2]; // pool rows holding valid context, logical order
int read_base_pos = 0; // logical pos of read[0].start (RoPE/mask). Flat: 0.
};
A TreePlanner/ BatchedPaged one would return a different kind of step plan.
Thoughts?
|
@claude review this code |
|
Claude finished @metascroy's task in 2m 43s —— View job Code Review
Nicely scoped, well-commented, and the tests cover the bookkeeping/registry/session paths cleanly. A few substantive points below. 1. Exceptions vs. ExecuTorch error handling (most important)
Consider mirroring the rest of the runtime: return 2. On @metascroy's audience-split proposal (cache.h:46)I agree with the direction. Today If you go this way, the registry's value type stays 3.
|
Summary
Adds a shared, backend-agnostic core for the off-graph KV cache: a set of C++ pieces that manage cache length/limits and let a runtime look up the right cache by a key. It has no backend or tensor code.
Files
Testing
Added C++ unit tests (test/cache_test.cpp) covering the bookkeeping (plan/can_extend/rewind/clear), the registry (install/get/erase, unique keys), the builder registry (build + missing-kind error), and the session's install-on-create / remove-on-destroy. Built and ran through the standard cmake/ctest flow, all pass:
cmake -B cmake-out -DEXECUTORCH_BUILD_EXTENSION_LLM=ON -DEXECUTORCH_BUILD_TESTS=ON
cmake --build cmake-out --target extension_llm_cache_test -j
ctest --test-dir cmake-out -R extension_llm_cache --output-on-failure