From: Robert Haas Date: Fri, 21 Mar 2014 11:36:22 +0000 (-0400) Subject: sb_create_private_allocator X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=8e9b1e9c95d2d3b1b7ab1379851629b9909bbb67;p=users%2Frhaas%2Fpostgres.git sb_create_private_allocator --- diff --git a/src/backend/utils/mmgr/sb_alloc.c b/src/backend/utils/mmgr/sb_alloc.c index 8967c0923e..7128391b79 100644 --- a/src/backend/utils/mmgr/sb_alloc.c +++ b/src/backend/utils/mmgr/sb_alloc.c @@ -14,3 +14,93 @@ #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; +}