perf(agent): store embeddings once, not twice
MemoryCache held every embedding in two places: a `Vec<Vec<f32>>` and a flattened copy for the batched kernels, kept in lock-step on every push, update and compaction. A store loaded from disk therefore carried the corpus twice, plus one heap allocation per entry. A new `cache::Embeddings` owns just the flat `[N x dim]` buffer and indexes into it, so `embeddings[i]` still reads as a `&[f32]` row. The batch kernels take a `VectorSet` (implemented for both `Embeddings` and `Vec<Vec<f32>>`) instead of `&[Vec<f32>]`, so their callers and tests are unchanged. Loading no longer unflattens what it just read. 100k 384-dim entries, reopened from disk: 505 -> 357 MiB, 3.44x -> 2.43x the raw vectors. Recall (1.0000 at ef=64) and query latency are unchanged. Rows are now always exactly `dim` long, shorter ones zero-padded. The old representation allowed ragged rows, which silently misaligned the flattened copy — every row after a wrong-length embedding — and `update` carried a comment about falling back to a rebuild to avoid exactly that. It is now unrepresentable. A record saved without an embedding holds a zero row and is told apart by its norm, which is what `total_embeddings` now counts. Measured with a counting allocator rather than RSS: freeing a structure returns its pages to the allocator's pool, not the OS, so an RSS reading from inside the process showed the two representations as identical. Breaking: MemoryCache::embeddings changes type, embeddings_flat is replaced by flat_embeddings(), rebuild_flat() is a deprecated no-op. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
@@ -2,6 +2,24 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Memory
|
||||
- `clawhdf5-agent`: **a loaded store holds ~30% less memory** (100k 384-dim
|
||||
entries: 505 -> 357 MiB, 3.44x -> 2.43x the raw vectors). The cache kept
|
||||
every embedding twice — a `Vec<Vec<f32>>` and a flattened copy for the
|
||||
batched kernels, maintained in lock-step — so it now stores only the flat
|
||||
buffer and indexes into it. Recall and query latency are unchanged.
|
||||
**Breaking:** `MemoryCache::embeddings` is a `cache::Embeddings` rather than
|
||||
a `Vec<Vec<f32>>` (indexing still yields a `&[f32]` row); `embeddings_flat`
|
||||
is gone, replaced by `flat_embeddings()`; `rebuild_flat()` is a deprecated
|
||||
no-op. Rows are now always exactly `dim` long — shorter ones are
|
||||
zero-padded — which makes the ragged-row case that used to silently
|
||||
misalign the flattened copy unrepresentable.
|
||||
- `clawhdf5-bench`: `search_harness --footprint` reports live heap use per
|
||||
stage, measured with a counting allocator (RSS cannot see a structure freed
|
||||
into the allocator's own pool).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Retrieval quality
|
||||
- `clawhdf5-agent`: **re-ranking discarded the retrieval score.**
|
||||
`reranker::rerank` built its combined score from temporal decay, source
|
||||
|
||||
Reference in New Issue
Block a user