Repository navigation
Conversation
findMany(keys, handles) resolves each key with the semantics of find() (expiry, access promotion, TTA, NVM lookup on a DRAM miss), but walks the batch in groups of 8 keys: the bucket slots of the next group are prefetched while the chain heads of the current one are prefetched and looked up, so the cache misses of different keys overlap. Groups of 4 to 8 keys measured fastest; 16 and 32 were slower. Lookup stats and the clock are updated once per batch. The NVM lookups of DRAM misses are issued without waiting on each other. The chain head is read from the slot without the bucket lock, only for 4-byte compressed pointers, and the read is annotated for TSAN. As it may be stale, it goes to a new PtrCompressor::prefetch(), which, unlike unCompress(), does not validate the pointer and skips offsets outside the slab. The handles that findMany() overwrites are released after the bucket lock is dropped, as releasing them may run item callbacks. Tests: FindManyTest, NvmCacheTest.FindMany. Benchmark: FindManyBench.
Contributor
|
@AlnisM has imported this pull request. If you are a Meta employee, you can view this in D131231523. |
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary:
We are moving a production profile cache with batched reads (about 32 keys per request) to CacheLib. Calling
find()per key makes each lookup wait on its own DRAM misses: the bucket slot, the chain head and the item.findMany(keys, handles)gives the same handles, stats and promotion as callingfind()per key, but overlaps the cache misses of different keys. It walks the batch in groups of 8: the bucket slots of the next group are prefetched while the chain heads of the current group are prefetched and looked up. Stats and the clock are updated once per batch. DRAM misses go to NVM as infind(); those lookups are issued without waiting on each other. The keys must stay valid during the call.The chain head is read from the slot without the bucket lock (4-byte compressed pointers only, annotated for TSAN), so it may be stale. It goes to a new
PtrCompressor::prefetch(), which, unlikeunCompress(), does not validate the pointer and skips offsets outside the slab. The handles thatfindMany()overwrites are released after the bucket lock is dropped, since releasing them can run item callbacks.Happy to change the API or split this into smaller PRs.
Test Plan:
FindManyTest: handles, refcounts, expiry and stats matchfind(); lookups race with inserts and removes; a remove callback uses the cache whilefindMany()overwrites the last handle to a removed item (this deadlocks if the old handle is released under the bucket lock).NvmCacheTest.FindMany: a DRAM hit, an NVM hit and a miss in one batch.MemoryAllocatorTest.PrefetchStale:prefetch()of pointers into an uncarved slab and past the end of a slab;unCompress()rejects these in debug builds.FindManyTestandMemoryAllocatorTestalso pass in a Debug build.cachelib/benchmarks/FindManyBench.cpp, 40M items × 500 B, Zipf 0.99, batches of 32, 16 threads on AMD EPYC 7713:findMany()uses about 34% less CPU per key thanfind()(558 vs 846 ns/key, faster in 3/3 blocks). Groups of 4 to 8 keys are a plateau; 16, 32 and a per-key pipeline are 2–10% slower (1M and 40M items, 1 and 16 threads).