From: Andre Noll Date: Fri, 30 Dec 2022 13:09:51 +0000 (+0100) Subject: btr: Merge buffers on insertion. X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=f64cbcc034844628b7e7817e27205cc6b48e9a18;p=paraslash.git btr: Merge buffers on insertion. Currently add_btrb_to_children() simply adds the given buffer reference to the input queue of all children of the given node even if the newly added buffer reference points memory adjacent to the previously added buffer. Since several helpers iterate over all buffer references, performance suffers, given enough buffer references. So merge buffers when possible. User time: 147s -> 83s, speedup: 44%. --- diff --git a/buffer_tree.c b/buffer_tree.c index 5d97f86f..36a7e6e1 100644 --- a/buffer_tree.c +++ b/buffer_tree.c @@ -330,6 +330,14 @@ static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn) struct btr_buffer_reference, node); } +static struct btr_buffer_reference *get_last_input_br(struct btr_node *btrn) +{ + if (list_empty(&btrn->input_queue)) + return NULL; + return list_last_entry(&btrn->input_queue, + struct btr_buffer_reference, node); +} + /* * Deallocate the reference, release the resources if refcount drops to zero. */ @@ -346,6 +354,20 @@ static void btr_drop_buffer_reference(struct btr_buffer_reference *br) } } +static bool may_merge_btrb(const struct btr_buffer *btrb, + const struct btr_buffer_reference *br) +{ + if (!br) + return false; + if (br->consumed > 0) + return false; + if (br->btrb->buf + br->btrb->size != btrb->buf) + return false; + if (!br->btrb->pool) + return true; + return br->btrb->size + btrb->size < btr_pool_size(br->btrb->pool) / 3; +} + static void add_btrb_to_children(struct btr_buffer *btrb, struct btr_node *btrn, size_t consumed) { @@ -354,11 +376,17 @@ static void add_btrb_to_children(struct btr_buffer *btrb, if (btrn->start.tv_sec == 0) btrn->start = *now; FOR_EACH_CHILD(ch, btrn) { - struct btr_buffer_reference *br = zalloc(sizeof(*br)); - br->btrb = btrb; - br->consumed = consumed; - list_add_tail(&br->node, &ch->input_queue); - btrb->refcount++; + struct btr_buffer_reference *br = get_last_input_br(ch); + if (may_merge_btrb(btrb, br)) { + br->btrb->size += btrb->size; + free(btrb); + } else { + br = zalloc(sizeof(*br)); + br->btrb = btrb; + br->consumed = consumed; + list_add_tail(&br->node, &ch->input_queue); + btrb->refcount++; + } if (ch->start.tv_sec == 0) ch->start = *now; } diff --git a/list.h b/list.h index 78c302fa..82f5b36d 100644 --- a/list.h +++ b/list.h @@ -161,3 +161,5 @@ static inline int list_is_singular(const struct list_head *head) */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member)