]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Memory statistics split into Effective and Overhead
authorMaria Matejka <mq@ucw.cz>
Fri, 26 Nov 2021 23:21:12 +0000 (00:21 +0100)
committerMaria Matejka <mq@ucw.cz>
Sat, 27 Nov 2021 21:54:15 +0000 (22:54 +0100)
This feature is intended mostly for checking that BIRD's allocation
strategies don't consume much memory space. There are some cases where
withdrawing routes in a specific order lead to memory fragmentation and
this output should give the user at least a notion of how much memory is
actually used for data storage and how much memory is "just allocated"
or used for overhead.

Also raising the "system allocator overhead estimation" from 8 to 16
bytes; it is probably even more. I've found 16 as a local minimum in
best scenarios among reachable machines. I couldn't find any reasonable
method to estimate this value when BIRD starts up.

This commit also fixes the inaccurate computation of memory overhead for
slabs where the "system allocater overhead estimation" was improperly
added to the size of mmap-ed memory.

lib/mempool.c
lib/resource.c
lib/resource.h
lib/slab.c
nest/cmds.c

index 758882ce251251821ebcf483cdfadf2f46aef1c0..90d7c7743396a67a48f7ef84cd6f1d0c3785a588 100644 (file)
@@ -45,7 +45,7 @@ struct linpool {
 static void lp_free(resource *);
 static void lp_dump(resource *);
 static resource *lp_lookup(resource *, unsigned long);
-static size_t lp_memsize(resource *r);
+static struct resmem lp_memsize(resource *r);
 
 static struct resclass lp_class = {
   "LinPool",
@@ -287,7 +287,7 @@ lp_dump(resource *r)
        m->total_large);
 }
 
-static size_t
+static struct resmem
 lp_memsize(resource *r)
 {
   linpool *m = (linpool *) r;
@@ -299,9 +299,11 @@ lp_memsize(resource *r)
   for(c=m->first_large; c; c=c->next)
     cnt++;
 
-  return ALLOC_OVERHEAD + sizeof(struct linpool) +
-    cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)) +
-    m->total + m->total_large;
+  return (struct resmem) {
+    .effective = m->total + m->total_large,
+    .overhead = ALLOC_OVERHEAD + sizeof(struct linpool) +
+    cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)),
+  };
 }
 
 
index 4c4b92ecd85d84da08f716477f972279cd44c848..5d4c7780dd5d4fbdc038f182484b5b575b78d5a9 100644 (file)
@@ -2,6 +2,7 @@
  *     BIRD Resource Manager
  *
  *     (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ *     (c) 2021 Maria Matejka <mq@jmq.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
@@ -37,7 +38,7 @@ struct pool {
 static void pool_dump(resource *);
 static void pool_free(resource *);
 static resource *pool_lookup(resource *, unsigned long);
-static size_t pool_memsize(resource *P);
+static struct resmem pool_memsize(resource *P);
 
 static struct resclass pool_class = {
   "Pool",
@@ -97,15 +98,22 @@ pool_dump(resource *P)
   indent -= 3;
 }
 
-static size_t
+static struct resmem
 pool_memsize(resource *P)
 {
   pool *p = (pool *) P;
   resource *r;
-  size_t sum = sizeof(pool) + ALLOC_OVERHEAD;
+  struct resmem sum = {
+    .effective = 0,
+    .overhead = sizeof(pool) + ALLOC_OVERHEAD,
+  };
 
   WALK_LIST(r, p->inside)
-    sum += rmemsize(r);
+  {
+    struct resmem add = rmemsize(r);
+    sum.effective += add.effective;
+    sum.overhead += add.overhead;
+  }
 
   return sum;
 }
@@ -193,14 +201,17 @@ rdump(void *res)
     debug("NULL\n");
 }
 
-size_t
+struct resmem
 rmemsize(void *res)
 {
   resource *r = res;
   if (!r)
-    return 0;
+    return (struct resmem) {};
   if (!r->class->memsize)
-    return r->class->size + ALLOC_OVERHEAD;
+    return (struct resmem) {
+      .effective = r->class->size - sizeof(resource),
+      .overhead = ALLOC_OVERHEAD + sizeof(resource),
+    };
   return r->class->memsize(r);
 }
 
@@ -305,11 +316,14 @@ mbl_lookup(resource *r, unsigned long a)
   return NULL;
 }
 
-static size_t
+static struct resmem
 mbl_memsize(resource *r)
 {
   struct mblock *m = (struct mblock *) r;
-  return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
+  return (struct resmem) {
+    .effective = m->size,
+    .overhead = ALLOC_OVERHEAD + sizeof(struct mblock),
+  };
 }
 
 static struct resclass mb_class = {
index 76e3745fee0dcb4deedd4ec20a11f69078eb7be9..9ec41ed8e81b4b98a54ba64130ee26c960e39e13 100644 (file)
@@ -2,6 +2,7 @@
  *     BIRD Resource Manager
  *
  *     (c) 1998--1999 Martin Mares <mj@ucw.cz>
+ *     (c) 2021 Maria Matejka <mq@jmq.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
 #include "lib/lists.h"
 
+struct resmem {
+  size_t effective;                    /* Memory actually used for data storage */
+  size_t overhead;                     /* Overhead memory imposed by allocator strategies */
+};
+
 /* Resource */
 
 typedef struct resource {
@@ -26,11 +32,11 @@ struct resclass {
   void (*free)(resource *);            /* Freeing function */
   void (*dump)(resource *);            /* Dump to debug output */
   resource *(*lookup)(resource *, unsigned long);      /* Look up address (only for debugging) */
-  size_t (*memsize)(resource *);       /* Return size of memory used by the resource, may be NULL */
+  struct resmem (*memsize)(resource *);        /* Return size of memory used by the resource, may be NULL */
 };
 
 /* Estimate of system allocator overhead per item, for memory consumtion stats */
-#define ALLOC_OVERHEAD         8
+#define ALLOC_OVERHEAD         16
 
 /* Generic resource manipulation */
 
@@ -40,7 +46,7 @@ void resource_init(void);
 pool *rp_new(pool *, const char *);    /* Create new pool */
 void rfree(void *);                    /* Free single resource */
 void rdump(void *);                    /* Dump to debug output */
-size_t rmemsize(void *res);            /* Return size of memory used by the resource */
+struct resmem rmemsize(void *res);             /* Return size of memory used by the resource */
 void rlookup(unsigned long);           /* Look up address (only for debugging) */
 void rmove(void *, pool *);            /* Move to a different pool */
 
index b0a01ae793edf84500b267800cb17077aeff35e6..6cab6b7b525c44d75222675c70a0c52b04a19ec6 100644 (file)
@@ -42,7 +42,7 @@
 static void slab_free(resource *r);
 static void slab_dump(resource *r);
 static resource *slab_lookup(resource *r, unsigned long addr);
-static size_t slab_memsize(resource *r);
+static struct resmem slab_memsize(resource *r);
 
 #ifdef FAKE_SLAB
 
@@ -128,7 +128,7 @@ slab_dump(resource *r)
   debug("(%d objects per %d bytes)\n", cnt, s->size);
 }
 
-static size_t
+static struct resmem
 slab_memsize(resource *r)
 {
   slab *s = (slab *) r;
@@ -138,7 +138,10 @@ slab_memsize(resource *r)
   WALK_LIST(o, s->objs)
     cnt++;
 
-  return ALLOC_OVERHEAD + sizeof(struct slab) + cnt * (ALLOC_OVERHEAD + s->size);
+  return (struct resmem) {
+    .effective = cnt * s->size,
+    .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + cnt * ALLOC_OVERHEAD,
+  };
 }
 
 
@@ -363,21 +366,33 @@ slab_dump(resource *r)
   debug("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size);
 }
 
-static size_t
+static struct resmem
 slab_memsize(resource *r)
 {
   slab *s = (slab *) r;
   size_t heads = 0;
   struct sl_head *h;
 
-  WALK_LIST(h, s->empty_heads)
+  WALK_LIST(h, s->full_heads)
     heads++;
+
+  size_t items = heads * s->objs_per_slab;
+
   WALK_LIST(h, s->partial_heads)
+  {
     heads++;
-  WALK_LIST(h, s->full_heads)
+    items += h->num_full;
+  }
+
+  WALK_LIST(h, s->empty_heads)
     heads++;
 
-  return ALLOC_OVERHEAD + sizeof(struct slab) + heads * (ALLOC_OVERHEAD + get_page_size());
+  size_t eff = items * s->obj_size;
+
+  return (struct resmem) {
+    .effective = eff,
+    .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + heads * get_page_size() - eff,
+  };
 }
 
 static resource *
index f58923a76e3f983c40f8f6604ab8bd670e26a957..1a16f9c7d231e2268633989397ee9be7a5558fe9 100644 (file)
@@ -67,18 +67,43 @@ cmd_show_symbols(struct sym_show_data *sd)
   }
 }
 
-static void
-print_size(char *dsc, size_t val)
+#define SIZE_SUFFIX    " kMGT"
+#define SIZE_FORMAT    "% 4u.%1u % 1cB"
+#define SIZE_ARGS(a)   (a).val, (a).decimal, SIZE_SUFFIX[(a).magnitude]
+
+struct size_args {
+  u64 val:48;
+  u64 decimal:8;
+  u64 magnitude:8;
+};
+
+static struct size_args
+get_size_args(u64 val)
 {
-  char *px = " kMG";
-  int i = 0;
-  while ((val >= 10000) && (i < 3))
+#define VALDEC 10 /* One decimal place */
+  val *= VALDEC;
+
+  uint i = 0;
+  while ((val >= 10000 * VALDEC) && (i < 4))
     {
       val = (val + 512) / 1024;
       i++;
     }
 
-  cli_msg(-1018, "%-17s %4u %cB", dsc, (unsigned) val, px[i]);
+  return (struct size_args) {
+    .val = (val / VALDEC),
+    .decimal = (val % VALDEC),
+    .magnitude = i,
+  };
+}
+
+static void
+print_size(char *dsc, struct resmem vals)
+{
+  struct size_args effective = get_size_args(vals.effective);
+  struct size_args overhead = get_size_args(vals.overhead);
+
+  cli_msg(-1018, "%-17s " SIZE_FORMAT "   " SIZE_FORMAT, dsc, SIZE_ARGS(effective), SIZE_ARGS(overhead));
 }
 
 extern pool *rt_table_pool;
@@ -88,13 +113,14 @@ void
 cmd_show_memory(void)
 {
   cli_msg(-1018, "BIRD memory usage");
+  cli_msg(-1018, "%-17s Effective    Overhead", "");
   print_size("Routing tables:", rmemsize(rt_table_pool));
   print_size("Route attributes:", rmemsize(rta_pool));
   print_size("Protocols:", rmemsize(proto_pool));
-  size_t total = rmemsize(&root_pool);
+  struct resmem total = rmemsize(&root_pool);
 #ifdef HAVE_MMAP
-  print_size("Standby memory:", get_page_size() * pages_kept);
-  total += get_page_size() * pages_kept;
+  print_size("Standby memory:", (struct resmem) { .overhead = get_page_size() * pages_kept });
+  total.overhead += get_page_size() * pages_kept;
 #endif
   print_size("Total:", total);
   cli_msg(0, "");