]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Stonehenge: multi-slab allocator
authorMaria Matejka <mq@ucw.cz>
Tue, 24 Dec 2024 11:18:39 +0000 (12:18 +0100)
committerMaria Matejka <mq@ucw.cz>
Thu, 9 Jan 2025 09:08:27 +0000 (10:08 +0100)
To mid-term allocate and free lots of small blocks in a fast pace,
mb_alloc is too slow and causes heap bloating. We can already allocate
blocks from slabs, and if we allow for a little bit of inefficiency,
we can just use multiple slabs with stepped sizes.

This technique is already used in ea_list allocation which is gonna be
converted to Stonehenge.

lib/resource.h
lib/slab.c

index 48bf1f9ba5355110e875add8ffcf387c91555a79..12b78851073693ebd9cc25b39a041e617501b2be 100644 (file)
@@ -139,6 +139,20 @@ void *sl_allocz(slab *);
 void sl_free(void *);
 void sl_delete(slab *);
 
+/* A whole stonehenge of slabs */
+
+typedef struct stonehenge stonehenge;
+typedef struct sth_block {
+  void *block;
+  bool large;
+} sth_block;
+
+stonehenge *sth_new(pool *);
+sth_block sth_alloc(stonehenge *, uint size);
+sth_block sth_allocz(stonehenge *, uint size);
+void sth_free(sth_block);
+void sth_delete(stonehenge *);
+
 /*
  * Low-level memory allocation functions, please don't use
  * outside resource manager and possibly sysdep code.
index ca971f9fb359ba8849da996ea21e8e51b5598bf1..d68bfef1e0817ad37d37b2941eca0a127f75886e 100644 (file)
@@ -469,4 +469,66 @@ slab_lookup(resource *r, unsigned long a)
   return NULL;
 }
 
+static const uint stonehenge_sizes[] = { 56, 112, 168, 288, 448, 800, 1344 };
+
+struct stonehenge {
+  pool *p;
+  slab *s[ARRAY_SIZE(stonehenge_sizes)];
+};
+
+sth_block
+sth_alloc(stonehenge *sth, uint size)
+{
+  for (uint i=0; i<ARRAY_SIZE(stonehenge_sizes); i++)
+    if (size <= stonehenge_sizes[i])
+    {
+      if (!sth->s[i])
+       sth->s[i] = sl_new(sth->p, stonehenge_sizes[i]);
+
+      return (sth_block) { .block = sl_alloc(sth->s[i]), };
+    }
+
+  return (sth_block) {
+    .block = mb_alloc(sth->p, size),
+    .large = 1,
+  };
+}
+
+sth_block
+sth_allocz(stonehenge *sth, uint size)
+{
+  sth_block b = sth_alloc(sth, size);
+  bzero(b.block, size);
+  return b;
+}
+
+void
+sth_free(sth_block b)
+{
+  if (b.large)
+    mb_free(b.block);
+  else
+    sl_free(b.block);
+}
+
+stonehenge *
+sth_new(pool *pp)
+{
+  stonehenge tmps = {
+    .p = rp_new(pp, pp->domain, "Stonehenge"),
+  };
+
+  stonehenge *s = sth_alloc(&tmps, sizeof(stonehenge)).block;
+  *s = tmps;
+  return s;
+}
+
+void sth_delete(stonehenge *s)
+{
+  pool *p = s->p;
+  sth_free((sth_block) { s });
+  rp_free(p);
+}
+
+
 #endif