sb_create_private_allocator
authorRobert Haas <rhaas@postgresql.org>
Fri, 21 Mar 2014 11:36:22 +0000 (07:36 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 21 Mar 2014 11:36:22 +0000 (07:36 -0400)
src/backend/utils/mmgr/sb_alloc.c

index 8967c0923ee9802b37dc20fb02f0e6e9a5d7bb4f..7128391b79de547cee9e68731f38ad746de4ad7e 100644 (file)
 #include "postgres.h"
 
 #include "utils/sb_alloc.h"
+
+/*
+ * Small allocations are handled by dividing a relatively large chunk of
+ * memory called a superblock into many small objects of equal size.  The
+ * chunk sizes are defined by the following array.  Larger size classes are
+ * spaced more widely than smaller size classes.  We fudge the spacing for
+ * size classes >1k to avoid space wastage: based on the knowledge that we
+ * plan to allocate 64k superblocks, we bump the maximum object size up
+ * to the largest multiple of 8 bytes that still lets us fit the same
+ * number of objects into one superblock.
+ *
+ * NB: Because of this fudging, if the size of a superblock is ever changed,
+ * these size classes should be reworked to be optimal for the new size.
+ *
+ * NB: The optimal spacing for size classes, as well as the size of the
+ * superblocks themselves, is not a question that has one right answer.
+ * Some allocators (such as tcmalloc) use more closely-spaced size classes
+ * than we do here, while others (like aset.c) use more widely-spaced classes.
+ * Spacing the classes more closely avoids wasting memory within individual
+ * chunks, but also means a larger number of potentially-unfilled superblocks.
+ * This system is really only suitable for allocating relatively large amounts
+ * of memory, where the unfilled superblocks will be a small percentage of
+ * the total allocations.
+ */
+static const uint16 sb_size_classes[] = {
+       8, 16, 24, 32, 40, 48, 56, 64,  /* 8 classes separated by 8 bytes */
+       80, 96, 112, 128,                               /* 4 classes separated by 16 bytes */
+       160, 192, 224, 256,                             /* 4 classes separated by 32 bytes */
+       320, 384, 448, 512,                             /* 4 classes separated by 64 bytes */
+       640, 768, 896, 1024,                    /* 4 classes separated by 128 bytes */
+       1280, 1560, 1816, 2048,                 /* 4 classes separated by ~256 bytes */
+       2616, 3120, 3640, 4096,                 /* 4 classes separated by ~512 bytes */
+       5456, 6552, 7280, 8192                  /* 4 classes separated by ~1024 bytes */
+};
+
+#if 0
+/*
+ * The following lookup table is used to map the size of small objects
+ * (less than 1kB) onto the corresponding size class.  To use this table,
+ * round the size of the object up to the next multiple of 8 bytes, and then
+ * index into this array.
+ */
+static char sb_size_class_map[] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+       12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+       16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+       18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
+       20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+       21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+       22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+       23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23
+};
+#define MSPAN_SIZE_CLASS_MAP_QUANTUM   8
+#endif
+
+/*
+ * Create a backend-private allocator.
+ */
+sb_allocator *
+sb_create_private_allocator(void)
+{
+       uint16  num_size_classes = lengthof(sb_size_classes);
+       Size    allocator_size;
+       int             heapno;
+       int             fclass;
+       sb_allocator *a;
+       char   *base = NULL;
+
+       allocator_size = offsetof(sb_allocator, heaps);
+       allocator_size += sizeof(sb_heap) * num_size_classes;
+       a = malloc(allocator_size);
+       if (a == NULL)
+               ereport(ERROR,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+
+       a->private = true;
+       a->heaps_per_size_class = 1;
+       a->num_size_classes = num_size_classes;
+       for (heapno = 0; heapno < num_size_classes; ++heapno)
+       {
+               sb_heap *heap = &a->heaps[heapno];
+
+               relptr_store(base, heap->lock, (LWLock *) NULL);
+               for (fclass = 0; fclass < SB_FULLNESS_CLASSES; ++fclass)
+                       relptr_store(base, heap->spans[fclass], (sb_span *) NULL);
+       }
+
+       return a;
+}