]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.garbage] runtime: bitmap allocation data structs
authorRick Hudson <rlh@golang.org>
Thu, 4 Feb 2016 16:41:48 +0000 (11:41 -0500)
committerRick Hudson <rlh@golang.org>
Wed, 27 Apr 2016 21:54:35 +0000 (21:54 +0000)
The bitmap allocation data structure prototypes. Before
this is released these underlying data structures need
to be more performant but the signatures of helper
functions utilizing these structures will remain stable.

Change-Id: I5ace12f2fb512a7038a52bbde2bfb7e98783bcbe
Reviewed-on: https://go-review.googlesource.com/19221
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/runtime/malloc.go
src/runtime/mheap.go
src/runtime/msize.go

index 5f1e2f64c018bb072a82b477f3cf73ebe0d9fa0c..fe13b8b9a3a1663f61e44205cddb5a18359c1fcd 100644 (file)
@@ -97,6 +97,9 @@ const (
        pageShift = _PageShift
        pageSize  = _PageSize
        pageMask  = _PageMask
+       // By construction, single page spans of the smallest object class
+       // have the most objects per span.
+       maxObjsPerSpan = pageSize / 8
 
        mSpanInUse = _MSpanInUse
 
index 895af9f07c2da52a767437c4f3177b4d53a9cb74..8c843be9464322621505cdc375258363accc5d41 100644 (file)
@@ -117,9 +117,41 @@ type mspan struct {
        prev **mspan    // previous span's next field, or list head's first field if none
        list *mSpanList // For debugging. TODO: Remove.
 
-       start    pageID    // starting page number
-       npages   uintptr   // number of pages in span
-       freelist gclinkptr // list of free objects
+       start         pageID    // starting page number
+       npages        uintptr   // number of pages in span
+       freelist      gclinkptr // list of free objects for _MSpanInUse
+       stackfreelist gclinkptr // list of free stacks, avoids overloading freelist for _MSpanStack
+
+       // freeindex is the slot index between 0 and nelems at which to begin scanning
+       // for the next free object in this span.
+       // Each allocation scans allocBits starting at freeindex until it encounters a 0
+       // indicating a free object. freeindex is then adjusted so that subsequent scans begin
+       // just past the the newly discovered free object.
+       //
+       // If freeindex == nelem, this span has no free objects.
+       //
+       // allocBits is a bitmap of objects in this span.
+       // If n >= freeindex and allocBits[n/8] & (1<<(n%8)) is 0
+       // then object n is free;
+       // otherwise, object n is allocated. Bits starting at nelem are
+       // undefined and should never be referenced.
+       //
+       // Object n starts at address n*elemsize + (start << pageShift).
+       freeindex  uintptr
+       allocBits  *[maxObjsPerSpan / 8]uint8
+       gcmarkBits *[maxObjsPerSpan / 8]uint8
+       nelems     uintptr // number of object in the span.
+       // TODO(rlh) consider moving some of these fields into seperate arrays.
+       // Put another way is an array of structs a better idea than a struct of arrays.
+
+       // allocBits and gcmarkBits currently point to either markbits1
+       // or markbits2. At the end of a GC cycle allocBits and
+       // gcmarkBits swap roles simply by swapping pointers.
+       // This level of indirection also facilitates an implementation
+       // where markbits1 and markbits2 are not inlined in mspan.
+       markbits1 [maxObjsPerSpan / 8]uint8 // A bit for each obj.
+       markbits2 [maxObjsPerSpan / 8]uint8 // A bit for each obj.
+
        // sweep generation:
        // if sweepgen == h->sweepgen - 2, the span needs sweeping
        // if sweepgen == h->sweepgen - 1, the span is currently being swept
index 21fe2f4c615ca77c7f7e0482b732d62d812fc808..18577b309bda5961d411ea49d85f9f9c92db3315 100644 (file)
@@ -55,7 +55,7 @@ var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
 
 func sizeToClass(size int32) int32 {
        if size > _MaxSmallSize {
-               throw("SizeToClass - invalid size")
+               throw("invalid size")
        }
        if size > 1024-8 {
                return int32(size_to_class128[(size-1024+127)>>7])
@@ -79,7 +79,7 @@ func initSizes() {
                        }
                }
                if align&(align-1) != 0 {
-                       throw("InitSizes - bug")
+                       throw("incorrect alignment")
                }
 
                // Make the allocnpages big enough that
@@ -106,10 +106,18 @@ func initSizes() {
                sizeclass++
        }
        if sizeclass != _NumSizeClasses {
-               print("sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
-               throw("InitSizes - bad NumSizeClasses")
+               print("runtime: sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
+               throw("bad NumSizeClasses")
+       }
+       // Check maxObjsPerSpan => number of objects invariant.
+       for i, size := range class_to_size {
+               if size != 0 && class_to_allocnpages[i]*pageSize/size > maxObjsPerSpan {
+                       throw("span contains too many objects")
+               }
+               if size == 0 && i != 0 {
+                       throw("size is 0 but class is not 0")
+               }
        }
-
        // Initialize the size_to_class tables.
        nextsize := 0
        for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
@@ -128,12 +136,12 @@ func initSizes() {
                for n := int32(0); n < _MaxSmallSize; n++ {
                        sizeclass := sizeToClass(n)
                        if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n {
-                               print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+                               print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
                                print("incorrect SizeToClass\n")
                                goto dump
                        }
                        if sizeclass > 1 && class_to_size[sizeclass-1] >= n {
-                               print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+                               print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
                                print("SizeToClass too big\n")
                                goto dump
                        }
@@ -155,18 +163,18 @@ func initSizes() {
 
 dump:
        if true {
-               print("NumSizeClasses=", _NumSizeClasses, "\n")
+               print("runtime: NumSizeClasses=", _NumSizeClasses, "\n")
                print("runtime·class_to_size:")
                for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ {
                        print(" ", class_to_size[sizeclass], "")
                }
                print("\n\n")
-               print("size_to_class8:")
+               print("runtime: size_to_class8:")
                for i := 0; i < len(size_to_class8); i++ {
                        print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n")
                }
                print("\n")
-               print("size_to_class128:")
+               print("runtime: size_to_class128:")
                for i := 0; i < len(size_to_class128); i++ {
                        print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n")
                }