summaryrefslogtreecommitdiff
path: root/src/runtime/msize.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2008-12-18 15:42:28 -0800
committerRuss Cox <rsc@golang.org>2008-12-18 15:42:28 -0800
commitfbc8538a295e36d100fa93d0224fa65f224944ff (patch)
tree50267429e2432b2039d63c2514b6099a2421d455 /src/runtime/msize.c
parent9ddb54a85641f93ae062ac57d8d13377110b1239 (diff)
downloadgolang-fbc8538a295e36d100fa93d0224fa65f224944ff.tar.gz
malloc in runtime (not used by default)
R=r DELTA=1551 (1550 added, 0 deleted, 1 changed) OCL=21404 CL=21538
Diffstat (limited to 'src/runtime/msize.c')
-rw-r--r--src/runtime/msize.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/runtime/msize.c b/src/runtime/msize.c
new file mode 100644
index 000000000..84de243f6
--- /dev/null
+++ b/src/runtime/msize.c
@@ -0,0 +1,164 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "malloc.h"
+
+int32 class_to_size[NumSizeClasses];
+int32 class_to_allocnpages[NumSizeClasses];
+int32 class_to_transfercount[NumSizeClasses];
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up). Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up). The arrays are filled in
+// by InitSizes.
+
+static int32 size_to_class8[1024/8 + 1];
+static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
+
+int32
+SizeToClass(int32 size)
+{
+ if(size > MaxSmallSize)
+ throw("SizeToClass - invalid size");
+ if(size > 1024-8)
+ return size_to_class128[(size-1024+127) >> 7];
+ return size_to_class8[(size+7)>>3];
+}
+
+void
+InitSizes(void)
+{
+ int32 align, sizeclass, size, i, nextsize, n;
+ uintptr allocsize, npages;
+
+ // Initialize the class_to_size table (and choose class sizes in the process).
+ class_to_size[0] = 0;
+ sizeclass = 1; // 0 means no class
+ align = 8;
+ for(size = align; size <= MaxSmallSize; size += align) {
+ if((size&(size-1)) == 0) { // bump alignment once in a while
+ if(size >= 2048)
+ align = 256;
+ else if(size >= 128)
+ align = size / 8;
+ else if(size >= 16)
+ align = 16; // required for x86 SSE instructions, if we want to use them
+ }
+ if((align&(align-1)) != 0)
+ throw("InitSizes - bug");
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize = PageSize;
+ while(allocsize%size > (PageSize/8))
+ allocsize += PageSize;
+ npages = allocsize >> PageShift;
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if(sizeclass > 1
+ && npages == class_to_allocnpages[sizeclass-1]
+ && allocsize/size == allocsize/class_to_size[sizeclass-1]) {
+ class_to_size[sizeclass-1] = size;
+ continue;
+ }
+
+ class_to_allocnpages[sizeclass] = npages;
+ class_to_size[sizeclass] = size;
+ sizeclass++;
+ }
+ if(sizeclass != NumSizeClasses) {
+ printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ throw("InitSizes - bad NumSizeClasses");
+ }
+
+ // Initialize the size_to_class tables.
+ nextsize = 0;
+ for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8)
+ size_to_class8[nextsize/8] = sizeclass;
+ if(nextsize >= 1024)
+ for(; nextsize <= class_to_size[sizeclass]; nextsize += 128)
+ size_to_class128[(nextsize-1024)/128] = sizeclass;
+ }
+
+ // Double-check SizeToClass.
+ if(0) {
+ for(n=0; n < MaxSmallSize; n++) {
+ sizeclass = SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) {
+ printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
+ printf("incorrect SizeToClass");
+ goto dump;
+ }
+ if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) {
+ printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
+ printf("SizeToClass too big");
+ goto dump;
+ }
+ }
+ }
+
+ // Initialize the class_to_transfercount table.
+ for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ n = 64*1024 / class_to_size[sizeclass];
+ if(n < 2)
+ n = 2;
+ if(n > 32)
+ n = 32;
+ class_to_transfercount[sizeclass] = n;
+ }
+ return;
+
+dump:
+ if(1){
+ printf("NumSizeClasses=%d\n", NumSizeClasses);
+ printf("class_to_size:");
+ for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+ printf(" %d", class_to_size[sizeclass]);
+ printf("\n\n");
+ printf("size_to_class8:");
+ for(i=0; i<nelem(size_to_class8); i++)
+ printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]);
+ printf("\n");
+ printf("size_to_class128:");
+ for(i=0; i<nelem(size_to_class128); i++)
+ printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]);
+ printf("\n");
+ }
+ throw("InitSizes failed");
+}
+