From 64046d495ef80eaf6858661e622463682a68157c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 8 Apr 2024 01:54:45 -0500 Subject: [PATCH] rbyd-rr: Cleaned up new 2-trunk range-removal algorithm Removed a bunch of outdated code, printfs, old diverging state machine, updated comments, etc. Also tried to simplify the diverging alt logic as much as possible, but the logic is quite stubborn. We can at least make some interesting assumptions about alt ordering on the upper-diverged path, since we know the lower-diverged path will flip and collapse 2-3 nodes. --- Now that the dust has settled (again), we can compare our new 2-trunk algorithm to our previous attempts: code stack rr-div-naive: 33968 2864 rr-div-altn: 34304 (+1.0%) 2864 (+0.0%) rr-2trunk-altn: 34656 (+2.0%) 2864 (+0.0%) Focusing on lfsr_rbyd_appendattr, which lets us compare further back in history: code frame stack appendattr rr-stitching: 1940 184 536 appendattr rr-div-naive: 2028 (+4.5%) 200 (+8.7%) 552 (+3.0%) appendattr rr-div-altn: 2198 (+13.3%) 216 (+17.4%) 568 (+6.0%) appendattr rr-2trunk-altn: 2464 (+27.0%) 224 (+21.7%) 576 (+7.5%) And comparing the resulting tree color-balance: 2-tree 2-3-4-tree rr-stitching: +~2x +~2x rr-div-naive: +0 +~2x rr-div-altn: +0 +~1 on red rr-2trunk-altn: +0 +~1 on yellow It's again an annoyingly expensive algorithm change, but necessary to maintain the correct balance of our rbyds as much as possible. Keep in mind range operations are used _everywhere_ in the high-level operations in our filesystem. It's just too useful a tool. The "+~1 on yellow" vs "+~1 on red" may not seem like that much of an improvement, but keep in mind yellow alts are much less common, and temporary. Decaying into black alts on the next append. At rest, most alts are either black or red. It's also worth mentioning that, in theory, the rr-2trunk-altn approach _could_ be extended to be perfectly balancing, but this would likely require duplicating the entire yellow-split logic, which is probably not worth it in this implemention... --- lfs.c | 536 +++++++++------------------------------------------------- 1 file changed, 76 insertions(+), 460 deletions(-) diff --git a/lfs.c b/lfs.c index 90461f23..3d3c28b2 100644 --- a/lfs.c +++ b/lfs.c @@ -2765,32 +2765,6 @@ static void lfsr_rbyd_p_recolor( } } -// diverged state machine for range appends -enum { - LFSR_D_NOTDIVERGING = 0, - LFSR_D_DIVERGINGLOWER = 1, - LFSR_D_DIVERGINGUPPER = 2, - LFSR_D_DIVERGEDLOWER = 3, - LFSR_D_DIVERGEDUPPER = 4, -}; - -//enum { -// LFSR_D_NOTDIVERGEDLOWER = 0, -// LFSR_D_NOTDIVERGEDUPPER = 1, -// LFSR_D_DIVERGEDLOWER = 2, -// LFSR_D_DIVERGEDUPPER = 3, -//}; - -static inline bool lfsr_d_isdiverged(uint8_t d_state) { - return d_state >= LFSR_D_DIVERGEDLOWER; -} - -static inline uint8_t lfsr_d_diverge(uint8_t d_state) { - LFS_ASSERT(d_state != LFSR_D_NOTDIVERGING); - LFS_ASSERT(!lfsr_d_isdiverged(d_state)); - return d_state + (LFSR_D_DIVERGEDLOWER - LFSR_D_DIVERGINGLOWER); -} - // core rbyd algorithm static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, lfsr_srid_t rid, lfsr_tag_t tag, lfsr_srid_t delta, lfsr_data_t data) { @@ -2809,10 +2783,6 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, return 0; } - printf("%04x->%04x: --- appendattr ---\n", - lfsr_rbyd_trunk(rbyd), - rbyd->eoff); - // begin appending int err = lfsr_rbyd_prepareappend(lfs, rbyd); if (err) { @@ -2880,23 +2850,14 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, // we may need to write two trunks // // to pull this off, we make two passes: - // 1. to write the diverged-lower trunk - // 2. to write the non-diverging trunk and diverged-upper trunk, - // stitching in the diverged-lower trunk where the trunks diverged + // 1. to write the common trunk + diverged-lower trunk + // 2. to write the common trunk + diverged-upper trunk, stitching the + // two diverged trunks together where they diverged // - // we may also end up not diverging, in which case we fallback to a - // normal append - // -// uint8_t d_state = (a_rid != b_rid || a_tag != b_tag) -// ? LFSR_D_DIVERGINGLOWER -// : LFSR_D_NOTDIVERGING; -// uint8_t diverged = LFSR_D_NOTDIVERGED; bool diverged = false; - bool d_will_diverge = false; bool d_upper = false; lfsr_srid_t d_rid = 0; lfsr_tag_t d_tag = 0; -// lfs_size_t d_branch = rbyd->eoff; again:; // the new trunk starts here @@ -2946,14 +2907,6 @@ again:; return d; } - printf("%04x->%04x: tag 0x%x w%d (%d %d)\n", - branch, - rbyd->eoff, - alt, - weight, - lower_rid, - upper_rid); - // found an alt? if (lfsr_tag_isalt(alt)) { // make jump absolute @@ -2962,63 +2915,31 @@ again:; // do bounds want to take different paths? begin diverging if (!diverged - // try to wait for black alt to avoid red alt corner cases - && (lfsr_tag_isblack(alt) - // give up if we find a yellow alt - || lfsr_tag_isred(p_alts[0])) - // diverged red? - && ((lfsr_tag_isred(p_alts[0]) - && lfsr_tag_follow( + // diverging black? + && (((lfsr_tag_isblack(alt) + // give up if we find a yellow alt + || lfsr_tag_isred(p_alts[0])) + && lfsr_tag_follow2( + alt, weight, p_alts[0], p_weights[0], lower_rid, upper_rid, a_rid, a_tag) - ^ lfsr_tag_follow( + ^ lfsr_tag_follow2( + alt, weight, p_alts[0], p_weights[0], lower_rid, upper_rid, b_rid, b_tag)) - // diverged black? - || lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - b_rid, b_tag))) { -// // both diverging? collapse -// if (lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag) -// && lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag)) { -// printf("%04x->%04x: dcollapse 0x%x w%d 0x%x w%d\n", -// branch, -// rbyd->eoff, -// alt, -// weight, -// p_alts[0], -// p_weights[0]); -// alt = p_alts[0] & ~LFSR_TAG_R; -// weight = p_weights[0]; -// jump = p_jumps[0]; -// lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); -// branch_ = branch; -// } + // diverging red? + || (lfsr_tag_isred(p_alts[0]) + && lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag) + ^ lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + b_rid, b_tag)))) { + diverged = true; // diverged red? flip if (lfsr_tag_isred(p_alts[0]) @@ -3030,14 +2951,6 @@ again:; p_alts[0], p_weights[0], lower_rid, upper_rid, b_rid, b_tag))) { - printf("%04x->%04x: dflip 0x%x w%d 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0]); - if (lfsr_tag_isparallel(alt, p_alts[0])) { lfsr_tag_flip2(&alt, &weight, p_alts[0], p_weights[0], @@ -3051,11 +2964,6 @@ again:; p_alts[0] |= LFSR_TAG_R; alt &= ~LFSR_TAG_R; - lfsr_tag_flip2(&alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfs_swap32(&jump, &branch_); - // both diverging? collapse if (lfsr_tag_follow( p_alts[0], p_weights[0], @@ -3065,150 +2973,22 @@ again:; p_alts[0], p_weights[0], lower_rid, upper_rid, b_rid, b_tag)) { - printf("%04x->%04x: dcollapse 0x%x w%d 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0]); -// if (!lfsr_tag_isparallel(alt, p_alts[0])) { -// lfsr_tag_flip2(&alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } + LFS_ASSERT(!lfsr_tag_isparallel(alt, p_alts[0])); + lfsr_tag_flip2(&alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); -// if (lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag)) { -// if (lfsr_tag_isparallel(alt, p_alts[0])) { -// lfsr_tag_flip2(&alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } -// -// lfs_swap16(&p_alts[0], &alt); -// lfs_swap32(&p_weights[0], &weight); -// lfs_swap32(&p_jumps[0], &jump); -// p_alts[0] |= LFSR_TAG_R; -// alt &= ~LFSR_TAG_R; -// -// lfsr_tag_flip2(&alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } - - LFS_ASSERT(lfsr_tag_isparallel(alt, p_alts[0])); - - alt = alt & ~LFSR_TAG_R; //p_alts[0] & ~LFSR_TAG_R; weight += p_weights[0]; jump = p_jumps[0]; lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); - - printf("%04x->%04x: -> 0x%x w%d 0x%x w%d (%x %x)\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0], - jump, - branch_); } } -// -// -// // flip red -// if (lfsr_tag_isred(p_alts[0]) -// && lfsr_tag_follow2( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag -// ^ lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag))) { -// -// -// -// // diverging red? flip -// if (lfsr_tag_isred(p_alts[0]) -// && (lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag))) { -// printf("%04x->%04x: dflip 0x%x w%d 0x%x w%d\n", -// branch, -// rbyd->eoff, -// alt, -// weight, -// p_alts[0], -// p_weights[0]); -// if (lfsr_tag_isparallel(alt, p_alts[0])) { -// lfsr_tag_flip2(&alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } -// -// lfs_swap16(&p_alts[0], &alt); -// lfs_swap32(&p_weights[0], &weight); -// lfs_swap32(&p_jumps[0], &jump); -// p_alts[0] |= LFSR_TAG_R; -// alt &= ~LFSR_TAG_R; -// -// lfsr_tag_flip2(&alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// -// } -// -// // diverging black? -// if (lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag)) { - printf("%04x->%04x: diverge 0x%x w%d 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0]); + + // diverged upper? stitch together both trunks if (d_upper) { - alt &= ~LFSR_TAG_R; - diverged = true; - -// alt = LFSR_TAG_ALT( -// alt & LFSR_TAG_GT, -// alt & LFSR_TAG_R, -// d_tag); -// if (lfsr_tag_isle(alt)) { -// weight = d_rid - lower_rid + weight; -// } else { -// weight = (upper_rid - lower_rid) - weight; -// } - - if (lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag)) { + // flip + if (lfsr_tag_isgt(alt)) { lfsr_tag_flip2( &alt, &weight, p_alts[0], p_weights[0], @@ -3216,96 +2996,37 @@ again:; lfs_swap32(&jump, &branch_); } - if (lfsr_tag_isle(alt)) { - printf("%04x->%04x: dle 0x%x %d w%d (%d %d)\n", - branch, - rbyd->eoff, - d_tag, - d_rid, - weight, - lower_rid, - upper_rid); - alt = LFSR_TAG_ALT( - LFSR_TAG_LE, - alt & LFSR_TAG_R, - d_tag); - lfsr_rid_t weight_ = d_rid - lower_rid; - if (lfsr_tag_isred(p_alts[0]) - && lfsr_tag_isle(p_alts[0])) { - weight_ -= p_weights[0]; - } - lower_rid += weight - weight_; -// a_rid += weight - weight_; -// b_rid += weight - weight_; - weight = weight_; -// lower_rid += weight; -// weight = d_rid - lower_rid + weight; -// if (lfsr_tag_isred(p_alts[0]) -// && lfsr_tag_isle(p_alts[0])) { -// weight -= p_weights[0]; -// } -// lower_rid -= weight; -// jump = d_branch; - } else { - LFS_UNREACHABLE(); -// printf("%04x->%04x: dgt 0x%x %d w%d (%d %d)\n", -// branch, -// rbyd->eoff, -// d_tag, -// d_rid, -// weight, -// lower_rid, -// upper_rid); -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// alt = LFSR_TAG_ALT( -// LFSR_TAG_LE, -// alt & LFSR_TAG_R, -// d_tag); -// lower_rid += weight; -// weight = d_rid - lower_rid + weight; -// if (lfsr_tag_isred(p_alts[0]) -// && lfsr_tag_isle(p_alts[0])) { -// weight -= p_weights[0]; -// } -// lower_rid -= weight; -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -//// branch_ = d_branch; + // trim + lfsr_tag_trim2( + alt, weight, + p_alts[0], p_weights[0], + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + + // stitch together both trunks + err = lfsr_rbyd_p_push(lfs, rbyd, + p_alts, p_weights, p_jumps, + LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag), + d_rid - (lower_rid - weight), + jump); + if (err) { + return err; } - printf("%04x->%04x: dtag 0x%x w%d (%d %d)\n", - branch, - rbyd->eoff, - alt, - weight, - lower_rid, - upper_rid); - - goto push; - - } else { - //alt &= ~LFSR_TAG_R; - //d_will_diverge = true; - diverged = true; + // continue to next alt + branch = branch_; + continue; } - goto dont_trim_me; - } - // trim unreachable diverged alts so they end up pruned - if (diverged - && (d_upper - ^ lfsr_tag_isgt(alt) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag))) { + } else if (diverged + && (d_upper + ^ lfsr_tag_isgt(alt) + ^ lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag))) { if (lfsr_tag_follow2( alt, weight, p_alts[0], p_weights[0], @@ -3317,11 +3038,7 @@ again:; lower_rid, upper_rid); lfs_swap32(&jump, &branch_); } - printf("%04x->%04x: dtrim 0x%x w%d -> w0\n", - branch, - rbyd->eoff, - alt, - weight); + lfsr_tag_trim( alt, weight, &lower_rid, &upper_rid, @@ -3329,7 +3046,6 @@ again:; weight = 0; } - dont_trim_me:; // prune? // b // .-'| .-'| @@ -3350,8 +3066,7 @@ again:; p_alts[0], p_weights[0], lower_rid, upper_rid, lower_tag, upper_tag)) { - // note, yellow pruning always follows, it's only diverged - // pruning that needs all these special cases + // note if only yellow pruning this could be much simpler if (lfsr_tag_unavoidable2( alt, weight, p_alts[0], p_weights[0], @@ -3362,11 +3077,6 @@ again:; // prune unreachable red-black alts if (lfsr_tag_isred(p_alts[0])) { - printf("%04x->%04x: rbprune 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight); alt = p_alts[0] & ~LFSR_TAG_R; weight = p_weights[0]; jump = p_jumps[0]; @@ -3374,22 +3084,12 @@ again:; // prune unreachable root alts and red alts } else if (!p_alts[0] || lfsr_tag_isred(alt)) { - printf("%04x->%04x: rprune 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight); branch = branch_; continue; // convert unreachable non-root black alts into alt-nevers, // if we prune these it would break the coloring of our tree } else { - printf("%04x->%04x: bprune 0x%x w%d\n", - branch, - rbyd->eoff, - alt, - weight); alt = LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, 0); weight = 0; jump = 0; @@ -3414,16 +3114,6 @@ again:; p_alts[0], p_weights[0], lower_rid, upper_rid, a_rid, a_tag)) { - printf("%04x->%04x: ysplit1 0x%x w%d 0x%x w%d (%x %x %x)\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0], - p_jumps[0], - jump, - branch_); lfsr_tag_flip2(&alt, &weight, p_alts[0], p_weights[0], lower_rid, upper_rid); @@ -3452,17 +3142,6 @@ again:; // | | .-'| | | .----'| // 1 2 3 4 1 2 3 4 4 } else { - printf("%04x->%04x: ysplit2 0x%x w%d 0x%x w%d (%x %x %x %x)\n", - branch, - rbyd->eoff, - alt, - weight, - p_alts[0], - p_weights[0], - p_jumps[0], - jump, - branch_, - y_branch); LFS_ASSERT(y_branch != 0); p_alts[0] = alt; p_weights[0] += weight; @@ -3496,42 +3175,34 @@ again:; lfs_swap32(&jump, &branch_); } - // TODO flatten this if statement - if (lfsr_tag_isred(p_alts[0])) { - // should've taken red alt? needs a flip - // r - // .----'| .-'| - // | | >b - // | .-'| .--|-'| - // 1 2 3 1 2 3 1 - if (lfsr_tag_follow(p_alts[0], p_weights[0], + // should've taken red alt? needs a flip + // r + // .----'| .-'| + // | | >b + // | .-'| .--|-'| + // 1 2 3 1 2 3 1 + if (lfsr_tag_isred(p_alts[0]) + && lfsr_tag_follow(p_alts[0], p_weights[0], lower_rid, upper_rid, a_rid, a_tag)) { - lfs_swap16(&p_alts[0], &alt); - lfs_swap32(&p_weights[0], &weight); - lfs_swap32(&p_jumps[0], &jump); - p_alts[0] |= LFSR_TAG_R; - alt &= ~LFSR_TAG_R; + lfs_swap16(&p_alts[0], &alt); + lfs_swap32(&p_weights[0], &weight); + lfs_swap32(&p_jumps[0], &jump); + p_alts[0] |= LFSR_TAG_R; + alt &= ~LFSR_TAG_R; - lfsr_tag_flip2(&alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfs_swap32(&jump, &branch_); - } + lfsr_tag_flip2(&alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); } - push:; // trim alts from our current bounds lfsr_tag_trim2( alt, weight, p_alts[0], p_weights[0], &lower_rid, &upper_rid, &lower_tag, &upper_tag); - - if (d_will_diverge) { - diverged = true; - d_will_diverge = false; - } } // push alt onto our queue @@ -3559,12 +3230,6 @@ again:; // diverged lower trunk? move on to upper trunk if (diverged && !d_upper) { - printf("%04x->%04x: diverging again %d 0x%x\n", - branch, - rbyd->eoff, - lower_rid, - lower_tag); - diverged = false; d_upper = true; // keep track of the lower diverged bound @@ -3600,55 +3265,6 @@ again:; lower_rid = d_rid; lower_tag = d_tag; } - -// // no divergence? guess we only need one trunk then, actually write -// // it out this time -// if (d_state == LFSR_D_DIVERGINGLOWER) { -// printf("%04x->%04x: not diverging\n", -// branch, -// rbyd->eoff); -// d_state = LFSR_D_NOTDIVERGING; -// goto again; -// -// // diverged lower trunk? we need an upper trunk too -// } else if (d_state == LFSR_D_DIVERGEDLOWER) { -// printf("%04x->%04x: diverging again\n", -// branch, -// rbyd->eoff); -// // keep track of last alt on diverged trunk to stitch the trunks -// // together with -// d_state = LFSR_D_DIVERGINGUPPER; -// d_rid = lower_rid; -// d_tag = lower_tag; -// -// // flush any pending alts -// err = lfsr_rbyd_p_flush(lfs, rbyd, -// p_alts, p_weights, p_jumps, 3); -// if (err) { -// return err; -// } -// -// // terminate diverged trunk with an unreachable tag -// err = lfsr_rbyd_appendattr_(lfs, rbyd, -// (lfsr_rbyd_isshrub(rbyd) ? LFSR_TAG_SHRUB : 0) -// | LFSR_TAG_NULL, -// 0, -// LFSR_DATA_NULL()); -// if (err) { -// return err; -// } -// -// // swap tag/rid and write out the upper trunk -// lfs_swap16(&a_tag, &b_tag); -// lfs_sswap32(&a_rid, &b_rid); -// goto again; -// -// // diverged upper trunk? done diverging -// } else if (d_state == LFSR_D_DIVERGEDUPPER) { -// // use the lower diverged bound for leaf weight calculation -// lower_rid = d_rid; -// lower_tag = d_tag; -// } // split leaf nodes? //