From: Liam R. Howlett Date: Fri, 2 May 2025 15:18:20 +0000 (-0400) Subject: add state_setup() function X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8a93e0941c46fa6ac3bfeff05068ec75480afcde;p=users%2Fjedix%2Flinux-maple.git add state_setup() function Signed-off-by: Liam R. Howlett --- diff --git a/lib/maple_tree.c b/lib/maple_tree.c index 9297606e8442..574f95590ca8 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -3113,7 +3113,7 @@ struct ma_node_part { unsigned long pivots[3]; void *slots[3]; unsigned long gaps[2]; - bool unfinished; + //bool unfinished; unsigned char skip; bool leaf; }; @@ -3174,7 +3174,7 @@ void mns_node_part_leaf_init(struct ma_node_part *part, part->size++; } - part->unfinished = false; + //part->unfinished = false; part->dst_max_off = 255; part->skip = wr_mas->offset_end - wr_mas->mas->offset + 1; part->leaf = true; @@ -3198,12 +3198,13 @@ void mni_node_part_init(struct ma_node_part *part, } part->pos = 0; - part->unfinished = false; + //part->unfinished = false; part->dst_max_off = 255; part->skip = 1; part->leaf = false; } +#if 0 static __always_inline void mni_insert_part(struct ma_node_part *part, struct ma_node_info *dst) @@ -3240,6 +3241,7 @@ void mni_insert_part(struct ma_node_part *part, //WARN_ON_ONCE(1); part->unfinished = true; } +#endif static inline void _mni_node_init(struct ma_node_info *mni, struct maple_node *node, @@ -3571,142 +3573,6 @@ void mas_wr_ascend_init(struct ma_state *mas, struct ma_node_info *ni) ni->insert_off = mas->offset; } -#if 0 -static void mas_wr_rebalance_nodes( - struct ma_node_info *l_src, - struct ma_node_info *r_src, - struct ma_node_info *left, - struct ma_node_info *right, - bool left_store, - unsigned char split, - struct ma_node_part *part, - unsigned char mas_off, - unsigned char new_end - ) -{ - unsigned char l_end, r_end; - - /* - * l_src, part, and r_src will be split between the new left and - * right nodes. Depending on where the split and the store offset - * (mas_off) falls within the data will determine where the new data - * will end up in the new nodes (left and right). - * - * This is further complicated by the insert potentially spanning the - * nodes and the left node ending on a NULL. If left does end in null, - * then the data is shifted forward one (if possible), or back one. - * Shifting back means copying the data to the right node. Shifting - * forward is complicated by a potential insert splitting the nodes, - * which means the new data going to the left will have to come from the - * part. This is all taken care of in mas_wr_split_no_null(). - */ - - l_end = l_src->end; - r_end = r_src->end; - if (left_store) { /* Store is targeting l_src */ - printk("%s %d\n", __func__, __LINE__); - if (mas_off <= split) { /* Store will end up in left */ - printk("%s %d\n", __func__, __LINE__); - if (mas_off) - mni_cp(l_src, left, mas_off); - - part->dst_max_off = split; - mni_insert_part(part, left); - l_src->offset+= part->skip; - printk("%d\n", __LINE__); - - printk("\tright min %lu left max %lu\n", right->min, left->max); - if (left->offset <= split) - mni_cp(l_src, left, split - left->offset + 1); - - printk("\tright min %lu left max %lu\n", right->min, left->max); - mas_wr_split_no_null(l_src, left, right, - r_end + new_end + 1, part); - right->min = left->max + 1; - printk("\tright min %lu left max %lu\n", right->min, left->max); - if (part->unfinished) - mni_insert_part(part, right); - - if (l_end >= l_src->offset) - mni_cp(l_src, right, l_end - l_src->offset + 1); - - } else { /* Store will end up in right */ - printk("%s %d\n", __func__, __LINE__); - mni_cp(l_src, left, split + 1); - mas_wr_split_no_null(l_src, left, right, - r_end + new_end + 1, part); - right->min = left->max + 1; - mni_cp(l_src, right, mas_off - l_src->offset); - mni_insert_part(part, right); - //printk("%d\n", __LINE__); - l_src->offset+= part->skip; - if (l_end >= l_src->offset) - mni_cp(l_src, right, l_end - l_src->offset + 1); - } - - mni_cp(r_src, right, r_end + 1); - } else { /* Store is targeting r_src */ - printk("%s %d\n", __func__, __LINE__); - if (split <= l_end) { /* Store will end up in right */ - printk("%s %d\n", __func__, __LINE__); - mni_cp(l_src, left, split + 1); - mas_wr_split_no_null(l_src, left, right, - l_end + new_end + 1, part); - - mni_cp(l_src, right, l_end - l_src->offset + 1); - right->min = left->max + 1; - mni_cp(r_src, right, mas_off); - mni_insert_part(part, right); - //printk("%d\n", __LINE__); - r_src->offset+= part->skip; - if (r_src->offset <= r_end) - mni_cp(r_src, right, r_end - r_src->offset + 1); - - } else { /* Store will end up in left */ - unsigned char r_split; - - printk("%s %d\n", __func__, __LINE__); - r_split = split - l_end - 1; - mni_cp(l_src, left, l_end + 1); - if (mas_off <= r_split) { - if (mas_off) - mni_cp(r_src, left, mas_off); - part->dst_max_off = split; - mni_insert_part(part, left); - //printk("%d\n", __LINE__); - r_src->offset+= part->skip; - if (r_src->offset < r_split) - mni_cp(r_src, left, - r_split - r_src->offset); - - mas_wr_split_no_null(r_src, left, right, - l_end + new_end + 1, - part); - - if (part->unfinished) - mni_insert_part(part, right); - - right->min = left->max + 1; - } else { - mni_cp(r_src, left, r_split + 1); - mas_wr_split_no_null(r_src, left, right, - l_end + new_end + 1, - part); - right->min = left->max + 1; - if (mas_off > r_src->offset) - mni_cp(r_src, right, - mas_off - r_src->offset); - mni_insert_part(part, right); - //printk("%d\n", __LINE__); - r_src->offset+= part->skip; - } - - if (r_src->offset <= r_end) - mni_cp(r_src, right, r_end - r_src->offset + 1); - } - } -} -#endif /* * Assemble all the states into the dst within those states @@ -3800,6 +3666,7 @@ struct split_data { unsigned char space; /* The space left in the current destination node */ unsigned char split; /* Proposed split of data */ unsigned char insert; /* Insert location of destination */ + unsigned char insert_end;/* Insert end location of destination */ unsigned char new_end; /* Total data */ unsigned char src_ins_end; /* Offset into source data where the write ends */ unsigned char len; /* Number of ma_node_states in the states array */ @@ -3842,6 +3709,45 @@ static inline void mas_wr_converged(struct ma_node_info *src, mni_finalise(dst); } +static int state_setup(struct ma_node_state *state, struct ma_node_info *src, + struct ma_node_info *dst, struct ma_node_part *part, + struct split_data *sd, int node_off) +{ + unsigned char copied; + unsigned char inc_off; + + /* Configure one state */ + state = &sd->states[sd->len]; + if (sd->offset >= sd->insert && sd->offset <= sd->insert_end) { + copied = min(part->size - part->pos, sd->space); + state->part = part; + printk("insert part at %u first entry is %p\n", sd->offset, part->slots[0]); + mns_mni_init(state, dst, part->pos , copied); + state->use_part = true; + part->pos += copied; + inc_off = sd->src_ins_end + 1; + } else { + state->info = src; + if (sd->offset < sd->insert_end) { + /* + * First part of node, may split across node + * boundaries though + */ + copied = min(sd->space, sd->insert - sd->offset); + } else { + copied = min(sd->space, (src->end - node_off + 1)); + } + BUG_ON(copied == 0); + mns_mni_init(state, dst, node_off, copied); + inc_off = copied; + } + + sd->offset += copied; + sd->space -= copied; + printk("offset %u split %u\n", sd->offset, sd->split); + return inc_off; +} + /* * mt_wr_split_data() - Split the combined data into ma_node_state parts. * @@ -3874,47 +3780,25 @@ static void mt_wr_split_data(struct ma_node_info *src, struct ma_node_part *part, struct split_data *sd) { unsigned char insert_end; - unsigned char node_off, part_off; + unsigned char node_off; struct ma_node_info *to; struct ma_node_state *state; printk("%s\n", __func__); /* Offset into the destination data where the insert ends */ - insert_end = sd->insert + part->size - 1; + sd->insert_end = sd->insert + part->size - 1; to = left; node_off = 0; /* src */ - part_off = 0; do { - unsigned char copied = 0; - + /* Configure one state */ state = &sd->states[sd->len]; - if (sd->offset >= sd->insert && sd->offset <= insert_end) { - copied = min(part->size - part_off, sd->space); - state->part = part; - printk("insert part at %u first entry is %p\n", sd->offset, part->slots[0]); - mns_mni_init(state, to, part_off, copied); - state->use_part = true; - part_off += copied; - node_off = sd->src_ins_end + 1; - } else { - state->info = src; - if (sd->offset < insert_end) { - /* - * First part of node, may split across node - * boundaries though - */ - copied = min(sd->space, sd->insert - sd->offset); - } else { - copied = min(sd->space, (src->end - node_off + 1)); - } - BUG_ON(copied == 0); - mns_mni_init(state, to, node_off, copied); - node_off += copied; - } + node_off += state_setup(state, src, to, part, sd, node_off); - sd->offset += copied; - sd->space -= copied; + /* + * Potentially remove one entry from the state if it's NULL and + * the destination is switching + */ if ((to == left) && (sd->offset >= sd->split)) { if (ma_is_leaf(src->type) && mns_ends_in_null(state)) { @@ -3930,7 +3814,7 @@ static void mt_wr_split_data(struct ma_node_info *src, sd->offset--; sd->space++; if (state->use_part) { - part_off--; + part->pos--; } else { node_off--; } @@ -4080,8 +3964,10 @@ bool mas_wr_try_rebalance(struct ma_state *mas, struct ma_node_info *src, return true; } -#if 1 - +/* + * mas_wr_rebalance_two() - rebalance data into two nodes, expects data to + * be decreasing (vs splitting pushing data to a neighbour). + */ static void mas_wr_rebalance_two(struct ma_wr_state *wr_mas, struct ma_node_info *left, struct ma_node_info *right, @@ -4092,15 +3978,28 @@ static void mas_wr_rebalance_two(struct ma_wr_state *wr_mas, bool left_store) { if (!left_store) { - printk("store right->n"); + char len; + + /* + * Store to the right implies left is going to donate data to + * the right node + */ + printk("store right\n"); left->min = src2->min; right->max = src->max; sd->offset = src2->end + 1; - sd->space = sd->split - src2->end; + sd->split++; sd->states[sd->len].info = src2; /* The first state to copy is the left node */ - mns_mni_init(&sd->states[sd->len], left, 0, src2->end + 1); + printk("cp to left %u-%u\n", 0, src2->end + 1); + mns_mni_init(&sd->states[sd->len], left, 0, sd->split); sd->len++; + /* Copy the remainder of the left to the start of the right */ + len = src2->end + 1 - sd->split; + sd->states[sd->len].info = src2; + mns_mni_init(&sd->states[sd->len], right, sd->split, len); + sd->space = mt_slots[right->type]; + sd->split = 255; } else { printk("store left\n"); sd->space = sd->split; @@ -4147,7 +4046,7 @@ static void mas_wr_rebalance_reduce(struct ma_wr_state *wr_mas, left->min = src2->min; left->max = src->max; sd->offset = src2->end + 1; - sd->space = sd->split - src2->end; + sd->space = sd->new_end + 1; sd->states[sd->len].info = src2; /* The first state to copy is the left node */ mns_mni_init(&sd->states[sd->len], left, 0, src2->end + 1); @@ -4259,6 +4158,7 @@ static void mas_wr_rebalance(struct ma_wr_state *wr_mas) } printk("REDUCE %p %p\n", src.node, src2.node); + sd.split = 255; mas_wr_rebalance_reduce(wr_mas, &left, &src, &src2, &part, &sd, left_store); /* Must go again */ @@ -4280,6 +4180,8 @@ static void mas_wr_rebalance(struct ma_wr_state *wr_mas) left.node->parent = mas_mn(mas)->parent; mas->node = left.enode; mas->depth = mas_mt_height(mas) - 1; + if (mas->depth == 1) + mas_set_height(mas); goto new_root; } @@ -4305,329 +4207,7 @@ new_root: mtree_range_walk(mas); mt_dump(mas->tree, mt_dump_dec); mt_validate(mas->tree); - return; - - /* - * allocate left - * set alloc in left - * figure out src2 - * rebalance leaves { - * allocate right, if needed - * set right alloc to left value - * set up split data - * split the data - * set up part - * } - * - * while ( parent is insufficient including overwrite, extra part) { - * allocate left - * figure out src2 - * rebalance src and src 2 { - * allocate right, if needed - * set right alloc to left value - * set up split data - * split the data and insert part - * set up next part - * } - * - * allocate new parent - * converge - * copy to insert - * insert part - * skip entry (or 2) - * copy to end - * put in tree - * - */ - - while (height--) { - printk("height %d\n", height); - mas_wr_ascend_init(&tmp_mas, &parent); - max = mt_slots[src.type] - 1; - if (ma_is_leaf(src.type)) - max--; - - src.end = mas->end; - if (parent.insert_off != mas->end) { - /* Right sibling exists, rebalance against right */ - tmp_mas.offset = parent.insert_off + 1; - mas_descend(&tmp_mas); - mni_mas_init(&src2, &tmp_mas); - mni_set_end(&src2); - left_store = true; - sd.insert = mas->offset; - } else { - /* Rebalance against left sibling */ - tmp_mas.offset--; - mas_descend(&tmp_mas); - mni_mas_init(&src2, &tmp_mas); - mni_node_init(&right, mas_pop_node(mas), wr_mas->type); - parent.insert_off--; - sd.insert = mas->offset + src2.end + 1; - } - - sd.new_end += src2.end + 1; - mni_node_init(&left, mas_pop_node(mas), wr_mas->type); - if (sd.new_end > 2 * mt_min_slots[src.type]) { - printk("Rebalance\n"); - mni_node_init(&right, mas_pop_node(mas), wr_mas->type); - sd.split = mas_wr_rebalance_calc(sd.new_end, - src2.type); - /* - * Rebalance between nodes is possible, so the - * operation stops early. - */ - - /* Taken from mas_wr_try_rebalance */ - if (left_store) { - /* Left pushes data right. */ - sd.insert = mas->offset; - sd.space = sd.split; - sd.offset = 0; - } else { - /* Right pushes data left */ - sd.insert = mas->offset + src2.end + 1; - sd.offset = src2.end + 1; - sd.space = sd.split - src2.end; - sd.states[sd.len].info = &src2; - mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1); - sd.len++; - } - - /* - * There are two splits of src, at insert and insert_end. - * There can also be a split between nodes that may happen at these - * boundaries, or elsewhere. - */ - mt_wr_split_data(&src, &left, &right, &part, &sd); - if (left_store) { - sd.states[sd.len].info = &src2; - mns_mni_init(&sd.states[sd.len], &right, 0, src2.end + 1); - sd.len++; - } - - mns_assemble(sd.states, sd.len); - mni_finalise(&left); - mni_finalise(&right); - mni_node_part_init(&part, &left, &right); - part.skip = 2; - mas_ascend(mas); - mas->end = parent.end; - mas->offset = parent.insert_off; - mas_wr_converged(&parent, &new_parent, &part, mas, &sd); - src.enode = parent.enode; - mas->node = new_parent.enode; - /* FIXME: make another function */ - /* We can stop rebalancing here */ - goto replace_node; - } else { - /* - * Absorb all the data from two nodes, which may need - * more rebalancing - */ - printk("Absorb src %p src2 %p\n", src.node, src2.node); - sd.split = sd.new_end + 2; /* No split */ - - if (!left_store) { - sd.states[sd.len].info = &src2; - mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1); - sd.len++; - } - mt_wr_split_data(&src, &left, NULL, &part, &sd); - - if (left_store) { - sd.states[sd.len].info = &src2; - mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1); - sd.len++; - } - - mns_assemble(sd.states, sd.len); - mni_finalise(&left); - if (ma_is_root(parent.node) && parent.end == 1) { - /* New root */ - } - if (parent.end > mt_min_slots[parent.type]) { - mni_node_part_init(&part, &left, NULL); - break; - } - } - } - - mas_ascend(mas); - mas->end = parent.end - 1; - mas->offset = parent.insert_off; - mas_wr_converged(&parent, &new_parent, &part, mas, &sd); - src.enode = parent.enode; - mas->node = new_parent.enode; -replace_node: - mas_wmb_replace(mas, src.enode); - mtree_range_walk(mas); - mt_dump(mas->tree, mt_dump_dec); - mt_validate(mas->tree); -} -#endif - -#if 0 -/* - * There is insufficient data in the node after a store. - * This rebalance will succeed, not like the split variant that will attempt - * to rebalance. - * - * Rebalance leaves - * Continue upwards until parent is sufficient, or root is reached. If root - * has a single child, replace root with new root. - */ -static void mas_wr_rebalance(struct ma_wr_state *wr_mas) -{ - struct ma_state *mas = wr_mas->mas; - struct ma_node_state src, parent, l_src, r_src; - struct ma_node_info src_info; - struct ma_node_state left, right; - struct ma_node_part part; - unsigned char total, split, height; - unsigned char insert; - - trace_ma_op(__func__, mas); - mt_dump(mas->tree, mt_dump_dec); - height = mas_mt_height(mas); - mns_mas_init(&src, &src_info, mas); - mns_node_part_leaf_init(&part, wr_mas, &src); - /* Total will lack sibling data until the sibling is known */ - printk("end %p %u\n", mas->node, mas->end); - total = mas->end + part.size - part.skip - 1; - printk("%p will have %u in the end\n", mas->node, total); - printk("Skip %u\n", part.skip); - // Skipping is causing a copy beyond the end of the src. - - printk("Rebalance %p %lu-%lu", mas->node, mas->index, mas->last); - - insert = mas->offset; - printk("Write to node at %u\n", insert); - while (mas->depth) { - bool l_store; - - mas_wr_ascend_init(mas, &parent); - printk("Ascend to parent %p\n", parent.node); - printk("offset of child is %u\n", mas->offset); - mas->depth--; - parent.insert = mas->offset; - printk("parent insert is %u\n", parent.insert); - - if (parent.insert < parent.end) { - /* Pull data from r_src */ - printk("Pull from right\n"); - mns_pmns_init(&r_src, &parent, mas->offset + 1, mas->tree); - mns_set_end(&r_src); - printk("right is %p %lu-%lu\n", r_src.node, r_src.min, r_src.max); - l_src = src; - l_src.insert = insert; - total += r_src.end; - l_store = true; - } else { - /* Pull data from l_src */ - printk("Pull from left\n"); - mns_pmns_init(&l_src, &parent, mas->offset - 1, mas->tree); - printk("left is %p\n", l_src.node); - r_src = src; - r_src.insert = insert; - mns_set_end(&l_src); - total += l_src.end; - l_store = false; - parent.insert--; - } - - printk("\tNew total will be %u\n", total); - mni_node_init(&left, mas_pop_node(mas), l_src.type); - /* - * Two possibilities: - * 1. keep two nodes if possible and limit ripple - * 2. make one node if possible and limit memory use - * - * Case 1: - * Left takes data from right. - * Fill left up to split from l_src and part - Func_1 - * Fill left up from l_src remainder - Func_2 - * Fill left up to split from right. - Func_2 - * fill right with remainder of right. - Func_2 - * - * Right takes data from left - * Copy left to new left up to split - Func_2 - * Fill right with remainder of left - Func_2 - * Fill right from old right or part - Func_1 - */ - if ((total > 2 * mt_min_slots[l_src.type] ) || - ma_is_root(parent.node)) { - struct ma_node_state new_parent; - - printk("Rebalance\n"); - /* - * Rebalance between nodes is possible, so the - * operation stops early. - */ - - mni_node_init(&right, mas_pop_node(mas), r_src.type); - printk("new right will be %p\n", right.node); - split = mas_wr_rebalance_calc(total, l_src.type); - printk("split is %u\n", split); - left.min = l_src.min; - mas_wr_rebalance_nodes(&l_src, &r_src, &left, &right, - l_store, split, &part, - insert, total); - - mni_finalise(&left); - mni_finalise(&right); - mni_node_part_init(&part, &left, &right); - part.skip = 2; - mas_wr_converged(&parent, &new_parent, &part, mas); - src.enode = parent.enode; - mas->node = new_parent.enode; - mas->depth = height; - printk("Height is %u\n", mas->depth); - break; - } - - printk("consume\n"); - /* Reduce two nodes into one */ - if (l_store) { - if (l_src.insert) - mni_cp(&l_src, &left, l_src.insert); - mni_insert_part(&part, &left); - l_src.offset += part.skip; - if (l_src.offset <= l_src.end) - mni_cp(&l_src, &left, - l_src.end - l_src.offset + 1); - mni_cp(&r_src, &left, r_src.end); - - } else { - mni_cp(&l_src, &left, l_src.end); - if (r_src.insert) - mni_cp(&r_src, &left, r_src.insert); - mni_insert_part(&part, &left); - r_src.offset += part.skip; - if (r_src.offset <= r_src.end) - mni_cp(&r_src, &left, - r_src.end - r_src.offset + 1); - } - left.node->parent = l_src.node->parent; - mni_finalise(&left); - if (mte_is_root(parent.enode)) { - /* Height reduction */ - if (mas->depth) - mas->depth = --height; - else - mas->depth = height; - - mas_set_height(mas); - break; - } - } - - - mas_wmb_replace(mas, parent.enode); - mtree_range_walk(mas); - mt_dump(mas->tree, mt_dump_dec); } -#endif /* * There is not enough room to contain the store in one node. diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index 10212d27ea57..ed88f7da937e 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -36367,6 +36367,7 @@ void farmer_tests(void) struct maple_node *node; DEFINE_MTREE(tree); + goto skip; mt_dump(&tree, mt_dump_dec); mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | MT_FLAGS_USE_RCU); @@ -36423,6 +36424,7 @@ void farmer_tests(void) check_mtree_dup(&tree); mtree_destroy(&tree); +skip: /* RCU testing */ mt_init_flags(&tree, 0); check_erase_testset(&tree); @@ -36540,10 +36542,10 @@ static void regression_tests(void) void maple_tree_tests(void) { - maple_tree_seed(); - maple_tree_harvest(); +// maple_tree_seed(); +// maple_tree_harvest(); #if !defined(BENCH) - regression_tests(); + //regression_tests(); farmer_tests(); #endif }