-
Notifications
You must be signed in to change notification settings - Fork 702
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
Accelerate hash table iterator with value prefetching #1568
Conversation
1da6b36
to
35f6b6e
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## unstable #1568 +/- ##
============================================
+ Coverage 70.80% 71.00% +0.19%
============================================
Files 121 121
Lines 65132 65139 +7
============================================
+ Hits 46118 46249 +131
+ Misses 19014 18890 -124
|
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.
Interesting idea. I just skimmed though, not a full review.
To summarize, this is a second level of pre-fetching. Theoretically, we could do even more levels, right? It could even be generalized to any number of levels. We could use an array of prefetch callbacks.... (not saying we should)
We should probably also consider the bigger picture where this kind of callbacks can be used not only for the iterator, but also for the hashtableIncrementalFind that's already used with IO threads, and with other operations like Scan.
A hypothetical use case: Imagine we have a sorted set where we want to find the 10 members sorted by score, ZRANGE. We could find the starting element and also prefetch in up to 10 steps the next elements.
Have you been thinking about more prefetching ideas? Can you share your ideas? It's useful to understand the bigger picture better before we add many small optimizations for specific scenarios.
@zuiderkwast Thank you for your thoughtful feedback and for taking the time to review my PR. I apologize for not sharing my broader ideas earlier. Let me address these and share my current thoughts on the matter:
Current Ideas and Roadmap:
|
@NadavGigi No need to apologize! I didn't ask before. :D
Yes, intriguing, that was the intention of my comment. 😄 We should base the decisions on actual use cases and facts. The ZRANGE idea I had isn't even in the hashtable code. It is the skiplist code. We could definitely do some prefetching in that kind of code. And in the quicklist implementation for lists we could do it.
This is interesting! Should we add this callback information in the commands' JSON files? Feel free to open an issue to explain it, or a PR if you already have some code.
Cool! It seems to me that we should prioritize SCAN next, don't you think? If users find out that KEYS is faster than SCAN, maybe they switch to using KEYS. 🙀 And we use scan for expiration and other internal jobs too. It seems easy to add prefetching to scan. We can just prefetch the next bucket. Maybe it doesn't speed up |
c9d2294
to
1e4823f
Compare
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.
I like it! Just some nits.
1e4823f
to
4da9437
Compare
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.
Haha, I guess I was being a bit too formal there!
Great Idea! it can be added to the prefetching tasks list. When working on sunionDiffGenericCommand i will try to make a general batch prefetching function that will might be good for all.
Sounds great! |
4da9437
to
618ba26
Compare
I'd like to have another look. Should be quick. |
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.
Just minor comments about wording.
618ba26
to
0096df0
Compare
Signed-off-by: NadavGigi <[email protected]>
0096df0
to
57a387a
Compare
@NadavGigi Another remind to not force push, just keep pushing little commits, we can squash them at the end. |
This PR builds upon the previous entry prefetching optimization to further enhance performance by implementing value prefetching for hashtable iterators.
Implementation
Modified
hashtableInitIterator
to accept a new flags parameter, allowing control over iterator behavior.Implemented conditional value prefetching within
hashtableNext
based on the newHASHTABLE_ITER_PREFETCH_VALUES
flag.When the flag is set, hashtableNext now calls
prefetchBucketValues
at the start of each new bucket, preemptively loading the values of filled entries into the CPU cache.The actual prefetching of values is performed using type-specific callback functions implemented in
server.c
:robj
thehashtableObjectPrefetchValue
callback is used to prefetch the value if not embeded.This implementation is specifically focused on main database iterations at this stage. Applying it to hashtables that hold other object types should not be problematic, but its performance benefits for those cases will need to be proven through testing and benchmarking.
Performance
Setup:
Action
Results
The results regarding the duration of “save” command was taken from “info all” command.
The results largely align with our expectations, showing significant improvements for larger values (100 bytes and 40 bytes) that are stored outside the robj. For smaller values (20 bytes and 10 bytes) that are embedded within the robj, we see almost no improvement, which is as expected.
However, the small improvement observed even for these embedded values is somewhat surprising. Given that we are not actively prefetching these embedded values, this minor performance gain was not anticipated.
perf record on save command without value prefetching:
perf record on save command with value prefetching:
Conclusions:
The prefetching strategy appears to be working as intended, shifting the performance bottleneck from data access to I/O operations.
The significant reduction in rdbSaveStringObject time suggests that string objects(which are the values) are being accessed more efficiently.