-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
[WIP] Implement Basic LRU Cache for merkledag nodes. #2890
Conversation
@whyrusleeping this is a very basic implementation. I could use some guidance in what you are looking for. (1) Currently only Get's are cached, I am thinking we should also populate the cache when adding nodes. (2) I am thinking that maybe the 2Q or ARC cache from the golang-lru package (https://godoc.org/github.com/hashicorp/golang-lru) would be a better fit, to protect against large reads (or adds) flushing the cahce. (3) I am not sure the best place in the pipeline to put this. |
CC @Kubuxu |
cache *lru.Cache | ||
} | ||
|
||
func CloneNode(nd * Node) *Node { |
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.
you can just use nd.Copy()
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.
That is an overkill. A shallow copy is all that is needed. I don't think any sort of copying should be necessary as it is in general bad practice to modify an object returned from the cache.
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 disagree. We cannot guarantee that callers will not choose to modify nodes they get back from the DAGService. This happens very frequently, see the object patch commands, the dagmodifier, the pinset commands, mfs, and a few other places. If a deep copy becomes a perf issue, we can address it then.
general bad practice to modify an object returned from the cache.
This might be true, but the caller has no idea if the object they are getting was returned from a cache
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.
Okay will use nd.Copy()
.
@kevina i have a small benchmark here: https://github.com/whyrusleeping/ipfs-whatever That tests the performance of object operations. This PR should help with that. Mind running some numbers? |
@whyrusleeping sure, what do you want me to do? |
If i could just see some before and after numbers that would be nice. Just start a daemon, run the program a few times and record the outputs. |
@whyrusleeping right now there is no improvement, I take it only the patch operations should see any real improvements? I will look into the reason, it would be helpful if you could add some additional benchmarks for workflows you expect to be improved from this cache. |
@kevina will do |
Maybe try caching on puts too |
@whyrusleeping yeah caching on puts is something I will try. I will assume that is is only the patch operations should see an improvement and will disable to add from the benchmark for now. |
After caching puts I get a near 100% hit rate and am still not seeing any improvements. I notice a lot of disk/io so maybe it is the writing of the new patched node that is slowing everything down. |
@kevina i pushed another benchmark to that set that creates directories with a few hundred child nodes. That should show some different numbers. |
Okay, now we are seeing improvements. Preliminary results: DirAddOpsPerSec before = 47.5 after = 200. |
I spoke too soon. It made the mistake of not running the initial test more than once. It seams like the OS-level disk cache is having more effect than the DAG cache. |
@kevina i'm seeing some respectable perf improvement here.
I particularly like the reduction in the standard deviation of add times. That basically tells me the cache is working nicely as the deviation most likely comes from disk contention |
@kevina could you rebase this on master? |
I'm not sure I would agree that these are respectable improvements. I did not measure the Add10MB as I didn't see how my cache would improve that. |
License: MIT Signed-off-by: Kevin Atkinson <k@kevina.org>
@whyrusleeping I just rebased on master. At this point I am not convinced that caching Merkledag nodes globally is necessary a good idea. I am particular worried about the extra copies being made. Especially for 256kb leaf nodes. It might make sense to only cache nodes that contains at least one link. Otherwise the functionally will overlap with the OS cache as possible the block cache. I did not report such small improvements because I did not see them as statically significant. For me a cache should improve performance by 50% or more to be worth the overhead. But then again I don't have a lot of experience in this area. |
@kevina I agree that we probably dont want to cache leaf nodes, but i've run the tests again on master and i'm seeing much nicer patch ops per second improvement (20-30%) If you still feel its not worth the overhead, thats fair. But i'd say a 10% improvement is a huge deal in any case (getting 10% improvement in IOPS at my previous company got you a raise). I've updated ipfs-whatever to be able to generate nicer output between runs:
|
I also just realized that the first numbers i posted an hour ago were run on an in memory tmpfs, not my SSD. (and not my spinning rusty disks either) |
License: MIT Signed-off-by: Kevin Atkinson <k@kevina.org>
@whyrusleeping, I just pushed a commit to only cache non-leaf nodes (i.e. nodes with at least one link). I didn't bother to report results before because there was so much variance between runs that any improvements where lost in the noise. |
@whyrusleeping, I am not getting consistent results:
Here is the script I used:
The repo is on a ssd drive with Datastore.NoSync enabled. I would agree that a 10% improvement would be significant, but only if it was reproducible. At this point I maintain the view that caching dag nodes may not be worthwhile. However, I will be happy to work on this anyway however I would have a hard time tuning it until we can find a workload where the cache makes a significant and reproducible improvement. |
In my opinion testing those optimizations on our nice SSD enabled dev machines misses the aim of the optimizations. While doing those optimizations we should think about loaded down, HDD servers. |
Two runs:
and
and this is on very steady |
@Kubuxu thanks, I propose we hold off on this until we get a better understanding of where the bottlenecks and also also how much CPU time is used to retrieve the block and decode the protobuf. Otherwise there may not be much benefit over the OS level disk cache. |
Ok, bumping it off the 0.4.3 |
@whyrusleeping (like #2942) I am marking this as blocked. I think we need better metrics to determine where exactly caching will be the most beneficial. If you disagree fell free to remove and readjust the labels. |
@kevina good call |
@kevina I'm gonna close this for now. If we decide that this will improve performance later on we can pull the branch from the archive and revive the PR |
That's fine my me. |
Closes #2849.
This is still a work in progress.