btree: Resurrected btree leaf caching
This is an indulgence to simplify the upcoming auxiliary btree work.
Brings back the previously-reverted per-btree leaf caches, where each
lfs3_btree_t keeps track of two rbyds: The root and the most recently
accessed leaf.
At the surface level, this optimizes repeated access to the same btree
leaf. A common pattern for a number of littlefs's operations that has
proven tricky to manually optimize:
- Btree iteration
- Pokes for our crystalization heuristic
- Checksum collision resolution for dids and (FUTURE) ddkeys
- Related rattrs attached to a single bid
But the real motivation is to drop lfs3_btree_*lookupleaf and simplify
the internal APIs. If repeated lfs3_btree_lookup*s are already
efficient, there's no reason for extra leaf-level APIs, and in theory
any logic that interacts with btrees will be simpler.
---
This comes at a cost (humorously about the same amount as the
tag-returning refactor, if you ignore the extra 28 bytes of ctx).
Unsurprisingly, increasing the size of lfs3_btree_t has the biggest
impact on stack and ctx:
code stack ctx
before: 36084 2336 656
after: 36784 (+1.9%) 2400 (+2.7%) 684 (+4.3%)
Also note from the previous commit messages: Btree leaf caching has
resulted in surprisingly little performance improvement for our current
benchmarks + implementation. It turns out if you're dominated by write
cost, optimizing btree lookups -- which already skip rbyd fetches, has
barely noticeable impact.
---
A note on reverting!
Eventually (after the auxiliary btree work) it will probably make sense
to revert this -- or at least provide a non-leaf-caching build for
code/RAM sensitive users.
I don't think this should be reverted as-is. Instead, I think we should
allow the option to just disable the leaf cache, while keeping the
simpler internal API. This would give us the best of all three worlds:
- A small code/RAM option
- Optimal btree iteration/nearby-lookup performance
- Simpler internal APIs
The only reason this isn't already implemented is because I want to
avoid fragmenting the codebase further while we're still in development
mode.
This commit is contained in:
@@ -681,8 +681,19 @@ typedef struct lfs3_rbyd {
|
||||
uint32_t cksum;
|
||||
} lfs3_rbyd_t;
|
||||
|
||||
// a btree is represented by the root rbyd
|
||||
typedef lfs3_rbyd_t lfs3_btree_t;
|
||||
// littlefs's btree representation
|
||||
//
|
||||
// technically all we need for btrees is the root rbyd, but tracking the
|
||||
// most recent leaf helps speed up iteration/subattrs/etc without
|
||||
// local rbyd allocations -- less code and stack for the same
|
||||
// performance
|
||||
typedef struct lfs3_btree {
|
||||
lfs3_rbyd_t r;
|
||||
struct {
|
||||
lfs3_bid_t bid;
|
||||
lfs3_rbyd_t rbyd;
|
||||
} leaf;
|
||||
} lfs3_btree_t;
|
||||
|
||||
// littlefs's atomic metadata log type
|
||||
typedef struct lfs3_mdir {
|
||||
@@ -712,7 +723,7 @@ typedef struct lfs3_bshrub {
|
||||
// trunk=0 => no bshrub/btree
|
||||
// sign(trunk)=1 => bshrub
|
||||
// sign(trunk)=0 => btree
|
||||
lfs3_shrub_t shrub;
|
||||
lfs3_btree_t shrub;
|
||||
#ifndef LFS3_RDONLY
|
||||
lfs3_shrub_t shrub_;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user