github.com/robhaswell/grandperspective-scan@v0.1.0/test/go-go1.7.1/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.go 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 // Size classes. Computed and initialized by InitSizes. 31 // 32 // SizeToClass(0 <= n <= MaxSmallSize) returns the size class, 33 // 1 <= sizeclass < NumSizeClasses, for n. 34 // Size class 0 is reserved to mean "not small". 35 // 36 // class_to_size[i] = largest size in class i 37 // class_to_allocnpages[i] = number of pages to allocate when 38 // making new objects in class i 39 40 // The SizeToClass lookup is implemented using two arrays, 41 // one mapping sizes <= 1024 to their class and one mapping 42 // sizes >= 1024 and <= MaxSmallSize to their class. 43 // All objects are 8-aligned, so the first array is indexed by 44 // the size divided by 8 (rounded up). Objects >= 1024 bytes 45 // are 128-aligned, so the second array is indexed by the 46 // size divided by 128 (rounded up). The arrays are filled in 47 // by InitSizes. 48 49 var class_to_size [_NumSizeClasses]int32 50 var class_to_allocnpages [_NumSizeClasses]int32 51 var class_to_divmagic [_NumSizeClasses]divMagic 52 53 var size_to_class8 [1024/8 + 1]int8 54 var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 55 56 func sizeToClass(size int32) int32 { 57 if size > _MaxSmallSize { 58 throw("invalid size") 59 } 60 if size > 1024-8 { 61 return int32(size_to_class128[(size-1024+127)>>7]) 62 } 63 return int32(size_to_class8[(size+7)>>3]) 64 } 65 66 func initSizes() { 67 // Initialize the runtime·class_to_size table (and choose class sizes in the process). 68 class_to_size[0] = 0 69 sizeclass := 1 // 0 means no class 70 align := 8 71 for size := align; size <= _MaxSmallSize; size += align { 72 if size&(size-1) == 0 { // bump alignment once in a while 73 if size >= 2048 { 74 align = 256 75 } else if size >= 128 { 76 align = size / 8 77 } else if size >= 16 { 78 align = 16 // required for x86 SSE instructions, if we want to use them 79 } 80 } 81 if align&(align-1) != 0 { 82 throw("incorrect alignment") 83 } 84 85 // Make the allocnpages big enough that 86 // the leftover is less than 1/8 of the total, 87 // so wasted space is at most 12.5%. 88 allocsize := _PageSize 89 for allocsize%size > allocsize/8 { 90 allocsize += _PageSize 91 } 92 npages := allocsize >> _PageShift 93 94 // If the previous sizeclass chose the same 95 // allocation size and fit the same number of 96 // objects into the page, we might as well 97 // use just this size instead of having two 98 // different sizes. 99 if sizeclass > 1 && npages == int(class_to_allocnpages[sizeclass-1]) && allocsize/size == allocsize/int(class_to_size[sizeclass-1]) { 100 class_to_size[sizeclass-1] = int32(size) 101 continue 102 } 103 104 class_to_allocnpages[sizeclass] = int32(npages) 105 class_to_size[sizeclass] = int32(size) 106 sizeclass++ 107 } 108 if sizeclass != _NumSizeClasses { 109 print("runtime: sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n") 110 throw("bad NumSizeClasses") 111 } 112 // Check maxObjsPerSpan => number of objects invariant. 113 for i, size := range class_to_size { 114 if size != 0 && class_to_allocnpages[i]*pageSize/size > maxObjsPerSpan { 115 throw("span contains too many objects") 116 } 117 if size == 0 && i != 0 { 118 throw("size is 0 but class is not 0") 119 } 120 } 121 // Initialize the size_to_class tables. 122 nextsize := 0 123 for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ { 124 for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 { 125 size_to_class8[nextsize/8] = int8(sizeclass) 126 } 127 if nextsize >= 1024 { 128 for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 { 129 size_to_class128[(nextsize-1024)/128] = int8(sizeclass) 130 } 131 } 132 } 133 134 // Double-check SizeToClass. 135 if false { 136 for n := int32(0); n < _MaxSmallSize; n++ { 137 sizeclass := sizeToClass(n) 138 if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n { 139 print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n") 140 print("incorrect SizeToClass\n") 141 goto dump 142 } 143 if sizeclass > 1 && class_to_size[sizeclass-1] >= n { 144 print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n") 145 print("SizeToClass too big\n") 146 goto dump 147 } 148 } 149 } 150 151 testdefersizes() 152 153 // Copy out for statistics table. 154 for i := 0; i < len(class_to_size); i++ { 155 memstats.by_size[i].size = uint32(class_to_size[i]) 156 } 157 158 for i := 1; i < len(class_to_size); i++ { 159 class_to_divmagic[i] = computeDivMagic(uint32(class_to_size[i])) 160 } 161 162 return 163 164 dump: 165 if true { 166 print("runtime: NumSizeClasses=", _NumSizeClasses, "\n") 167 print("runtime·class_to_size:") 168 for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ { 169 print(" ", class_to_size[sizeclass], "") 170 } 171 print("\n\n") 172 print("runtime: size_to_class8:") 173 for i := 0; i < len(size_to_class8); i++ { 174 print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n") 175 } 176 print("\n") 177 print("runtime: size_to_class128:") 178 for i := 0; i < len(size_to_class128); i++ { 179 print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n") 180 } 181 print("\n") 182 } 183 throw("InitSizes failed") 184 } 185 186 // Returns size of the memory block that mallocgc will allocate if you ask for the size. 187 func roundupsize(size uintptr) uintptr { 188 if size < _MaxSmallSize { 189 if size <= 1024-8 { 190 return uintptr(class_to_size[size_to_class8[(size+7)>>3]]) 191 } else { 192 return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]]) 193 } 194 } 195 if size+_PageSize < size { 196 return size 197 } 198 return round(size, _PageSize) 199 } 200 201 // divMagic holds magic constants to implement division 202 // by a particular constant as a shift, multiply, and shift. 203 // That is, given 204 // m = computeMagic(d) 205 // then 206 // n/d == ((n>>m.shift) * m.mul) >> m.shift2 207 // 208 // The magic computation picks m such that 209 // d = d₁*d₂ 210 // d₂= 2^m.shift 211 // m.mul = ⌈2^m.shift2 / d₁⌉ 212 // 213 // The magic computation here is tailored for malloc block sizes 214 // and does not handle arbitrary d correctly. Malloc block sizes d are 215 // always even, so the first shift implements the factors of 2 in d 216 // and then the mul and second shift implement the odd factor 217 // that remains. Because the first shift divides n by at least 2 (actually 8) 218 // before the multiply gets involved, the huge corner cases that 219 // require additional adjustment are impossible, so the usual 220 // fixup is not needed. 221 // 222 // For more details see Hacker's Delight, Chapter 10, and 223 // http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html 224 // http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html 225 type divMagic struct { 226 shift uint8 227 mul uint32 228 shift2 uint8 229 baseMask uintptr 230 } 231 232 func computeDivMagic(d uint32) divMagic { 233 var m divMagic 234 235 // If the size is a power of two, heapBitsForObject can divide even faster by masking. 236 // Compute this mask. 237 if d&(d-1) == 0 { 238 // It is a power of 2 (assuming dinptr != 1) 239 m.baseMask = ^(uintptr(d) - 1) 240 } else { 241 m.baseMask = 0 242 } 243 244 // Compute pre-shift by factoring power of 2 out of d. 245 for d&1 == 0 { 246 m.shift++ 247 d >>= 1 248 } 249 250 // Compute largest k such that ⌈2^k / d⌉ fits in a 32-bit int. 251 // This is always a good enough approximation. 252 // We could use smaller k for some divisors but there's no point. 253 k := uint8(63) 254 d64 := uint64(d) 255 for ((1<<k)+d64-1)/d64 >= 1<<32 { 256 k-- 257 } 258 m.mul = uint32(((1 << k) + d64 - 1) / d64) // ⌈2^k / d⌉ 259 m.shift2 = k 260 261 return m 262 }