github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/runtime/msize.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Malloc small size classes. 6 // 7 // See malloc.h for overview. 8 // 9 // The size classes are chosen so that rounding an allocation 10 // request up to the next size class wastes at most 12.5% (1.125x). 11 // 12 // Each size class has its own page count that gets allocated 13 // and chopped up when new objects of the size class are needed. 14 // That page count is chosen so that chopping up the run of 15 // pages into objects of the given size wastes at most 12.5% (1.125x) 16 // of the memory. It is not necessary that the cutoff here be 17 // the same as above. 18 // 19 // The two sources of waste multiply, so the worst possible case 20 // for the above constraints would be that allocations of some 21 // size might have a 26.6% (1.266x) overhead. 22 // In practice, only one of the wastes comes into play for a 23 // given size (sizes < 512 waste mainly on the round-up, 24 // sizes > 512 waste mainly on the page chopping). 25 // 26 // TODO(rsc): Compute max waste for any given size. 27 28 package runtime 29 30 //var class_to_size [_NumSizeClasses]int32 31 //var class_to_allocnpages [_NumSizeClasses]int32 32 33 // The SizeToClass lookup is implemented using two arrays, 34 // one mapping sizes <= 1024 to their class and one mapping 35 // sizes >= 1024 and <= MaxSmallSize to their class. 36 // All objects are 8-aligned, so the first array is indexed by 37 // the size divided by 8 (rounded up). Objects >= 1024 bytes 38 // are 128-aligned, so the second array is indexed by the 39 // size divided by 128 (rounded up). The arrays are filled in 40 // by InitSizes. 41 //var size_to_class8 [1024/8 + 1]int8 42 //var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 43 44 func sizeToClass(size int32) int32 { 45 if size > _MaxSmallSize { 46 gothrow("SizeToClass - invalid size") 47 } 48 if size > 1024-8 { 49 return int32(size_to_class128[(size-1024+127)>>7]) 50 } 51 return int32(size_to_class8[(size+7)>>3]) 52 } 53 54 func initSizes() { 55 // Initialize the runtime·class_to_size table (and choose class sizes in the process). 56 class_to_size[0] = 0 57 sizeclass := 1 // 0 means no class 58 align := 8 59 for size := align; size <= _MaxSmallSize; size += align { 60 if size&(size-1) == 0 { // bump alignment once in a while 61 if size >= 2048 { 62 align = 256 63 } else if size >= 128 { 64 align = size / 8 65 } else if size >= 16 { 66 align = 16 // required for x86 SSE instructions, if we want to use them 67 } 68 } 69 if align&(align-1) != 0 { 70 gothrow("InitSizes - bug") 71 } 72 73 // Make the allocnpages big enough that 74 // the leftover is less than 1/8 of the total, 75 // so wasted space is at most 12.5%. 76 allocsize := _PageSize 77 for allocsize%size > allocsize/8 { 78 allocsize += _PageSize 79 } 80 npages := allocsize >> _PageShift 81 82 // If the previous sizeclass chose the same 83 // allocation size and fit the same number of 84 // objects into the page, we might as well 85 // use just this size instead of having two 86 // different sizes. 87 if sizeclass > 1 && npages == int(class_to_allocnpages[sizeclass-1]) && allocsize/size == allocsize/int(class_to_size[sizeclass-1]) { 88 class_to_size[sizeclass-1] = int32(size) 89 continue 90 } 91 92 class_to_allocnpages[sizeclass] = int32(npages) 93 class_to_size[sizeclass] = int32(size) 94 sizeclass++ 95 } 96 if sizeclass != _NumSizeClasses { 97 print("sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n") 98 gothrow("InitSizes - bad NumSizeClasses") 99 } 100 101 // Initialize the size_to_class tables. 102 nextsize := 0 103 for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ { 104 for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 { 105 size_to_class8[nextsize/8] = int8(sizeclass) 106 } 107 if nextsize >= 1024 { 108 for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 { 109 size_to_class128[(nextsize-1024)/128] = int8(sizeclass) 110 } 111 } 112 } 113 114 // Double-check SizeToClass. 115 if false { 116 for n := int32(0); n < _MaxSmallSize; n++ { 117 sizeclass := sizeToClass(n) 118 if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n { 119 print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n") 120 print("incorrect SizeToClass\n") 121 goto dump 122 } 123 if sizeclass > 1 && class_to_size[sizeclass-1] >= n { 124 print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n") 125 print("SizeToClass too big\n") 126 goto dump 127 } 128 } 129 } 130 131 testdefersizes() 132 133 // Copy out for statistics table. 134 for i := 0; i < len(class_to_size); i++ { 135 memstats.by_size[i].size = uint32(class_to_size[i]) 136 } 137 return 138 139 dump: 140 if true { 141 print("NumSizeClasses=", _NumSizeClasses, "\n") 142 print("runtime·class_to_size:") 143 for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ { 144 print(" ", class_to_size[sizeclass], "") 145 } 146 print("\n\n") 147 print("size_to_class8:") 148 for i := 0; i < len(size_to_class8); i++ { 149 print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n") 150 } 151 print("\n") 152 print("size_to_class128:") 153 for i := 0; i < len(size_to_class128); i++ { 154 print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n") 155 } 156 print("\n") 157 } 158 gothrow("InitSizes failed") 159 } 160 161 // Returns size of the memory block that mallocgc will allocate if you ask for the size. 162 func roundupsize(size uintptr) uintptr { 163 if size < _MaxSmallSize { 164 if size <= 1024-8 { 165 return uintptr(class_to_size[size_to_class8[(size+7)>>3]]) 166 } else { 167 return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]]) 168 } 169 } 170 if size+_PageSize < size { 171 return size 172 } 173 return round(size, _PageSize) 174 }