]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
btr: Merge buffers on insertion.
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 30 Dec 2022 13:09:51 +0000 (14:09 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Wed, 8 May 2024 17:45:52 +0000 (19:45 +0200)
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%.

buffer_tree.c
list.h

index 5d97f86fc4b7140c563d9a9b47ca680133a92946..36a7e6e1804d1094e440b03e6e60e5f3931de777 100644 (file)
@@ -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 78c302fa322fe6bc2dae2926e95e58189c10c944..82f5b36dbd5468a35e3b752b41bc017d65bf9a28 100644 (file)
--- 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)