1 module d.gc.sizeclass; 2 3 import d.gc.spec; 4 5 enum ClassCount { 6 Tiny = getTinyClassCount(), 7 Small = getSmallClassCount(), 8 Large = getLargeClassCount(), 9 Total = getTotalClassCount(), 10 Lookup = getLookupClassCount(), 11 } 12 13 enum SizeClass { 14 Small = getSizeFromBinID(ClassCount.Small - 1), 15 Large = getSizeFromBinID(ClassCount.Large - 1), 16 } 17 18 size_t getAllocSize(size_t size) { 19 if (LgTiny < LgQuantum && size < (1UL << LgQuantum)) { 20 // Not the fastest way to handle this. 21 import d.gc.util; 22 auto s = pow2ceil(size); 23 24 enum T = 1UL << LgTiny; 25 return (s < T) ? T : s; 26 } 27 28 import d.gc.util; 29 auto shift = 30 (size < (1UL << LgQuantum + 2)) ? LgQuantum : lg2floor(size - 1) - 2; 31 32 return (((size - 1) >> shift) + 1) << shift; 33 } 34 35 ubyte getBinID(size_t size) { 36 if (LgTiny < LgQuantum && size < (1UL << LgQuantum)) { 37 // Not the fastest way to handle this. 38 import d.gc.util; 39 auto ret = lg2floor(pow2ceil(size) >> LgTiny); 40 41 // TODO: out contract. 42 assert(ret < ubyte.max); 43 return cast(ubyte) ret; 44 } 45 46 // Faster way to compute x = lg2floor(pow2ceil(size)); 47 import d.gc.util; 48 auto shift = 49 (size < (1UL << (LgQuantum + 2))) ? LgQuantum : lg2floor(size - 1) - 2; 50 51 auto mod = (size - 1) >> shift; 52 auto ret = (shift - LgQuantum) * 4 + mod + ClassCount.Tiny; 53 54 // TODO: out contract. 55 assert(ret < ubyte.max); 56 return cast(ubyte) ret; 57 } 58 59 size_t getSizeFromBinID(uint binID) { 60 if (binID < ClassCount.Small) { 61 import d.gc.bin; 62 auto ret = binInfos[binID].itemSize; 63 64 // XXX: out contract 65 assert(binID == getBinID(ret)); 66 assert(ret == getAllocSize(ret)); 67 return ret; 68 } 69 70 auto largeBinID = binID - ClassCount.Small; 71 auto shift = largeBinID / 4 + LgPageSize; 72 size_t bits = (largeBinID % 4) | 0x04; 73 74 auto ret = bits << shift; 75 76 // XXX: out contract 77 assert(binID == getBinID(ret)); 78 assert(ret == getAllocSize(ret)); 79 return ret; 80 } 81 82 auto getBinInfos() { 83 import d.gc.bin; 84 BinInfo[ClassCount.Small] bins; 85 86 void delegate(uint id, uint grp, uint delta, uint ndelta) dg = void; 87 auto dgSt = cast(BinInfoComputerDg*) &dg; 88 89 dgSt.fun = binInfoComputer; 90 dgSt.bins = &bins; 91 92 computeSizeClass(dg); 93 94 return bins; 95 } 96 97 private: 98 99 enum LgSizeClass { 100 LgSmall = LgPageSize + 2, 101 LgLarge = LgSmall + 7, 102 } 103 104 // XXX: find a better way to do all this. 105 // This is kind of convoluted as I want to avoid alloc. 106 struct BinInfoComputerDg { 107 void* bins; 108 void* fun; 109 } 110 111 void binInfoComputer(void* binsPtr, uint id, uint grp, uint delta, 112 uint ndelta) { 113 import d.gc.bin; 114 auto bins = cast(BinInfo*) binsPtr; 115 116 // XXX: 1UL is useless here, but there is a bug in type 117 // promotion for >= so we need it. 118 auto s = (1UL << grp) + (ndelta << delta); 119 if (s >= (1UL << LgSizeClass.LgSmall)) { 120 return; 121 } 122 123 assert(s < ushort.max); 124 auto itemSize = cast(ushort) s; 125 126 ubyte[4] npLookup; 127 128 // XXX: use array initializer. 129 npLookup[0] = cast(ubyte) (((s - 1) >> LgPageSize) + 1); 130 npLookup[1] = 5; 131 npLookup[2] = 3; 132 npLookup[3] = 7; 133 134 auto shift = cast(ubyte) delta; 135 if (grp == delta) { 136 auto tag = (ndelta + 1) / 2; 137 shift = cast(ubyte) (delta + tag - 2); 138 } 139 140 auto needPages = npLookup[(itemSize >> shift) % 4]; 141 142 uint p = needPages; 143 auto slots = cast(ushort) ((p << LgPageSize) / s); 144 145 assert(id < ClassCount.Small); 146 bins[id] = BinInfo(itemSize, shift, needPages, slots); 147 } 148 149 // 64 bits tiny, 128 bits quantum. 150 enum LgTiny = 3; 151 enum LgQuantum = 4; 152 153 auto getTotalClassCount() { 154 uint count = 0; 155 156 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 157 count++; 158 }); 159 160 return count; 161 } 162 163 auto getTinyClassCount() { 164 uint count = 0; 165 166 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 167 if (grp < LgQuantum) { 168 count++; 169 } 170 }); 171 172 return count; 173 } 174 175 auto getSmallClassCount() { 176 uint count = 0; 177 178 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 179 if (grp < LgSizeClass.LgSmall) { 180 count++; 181 } 182 }); 183 184 return count; 185 } 186 187 auto getLargeClassCount() { 188 uint count = 0; 189 190 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 191 if (grp < LgSizeClass.LgLarge) { 192 count++; 193 } 194 }); 195 196 return count + 1; 197 } 198 199 auto getLookupClassCount() { 200 uint count = 0; 201 202 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 203 if (grp < LgPageSize) { 204 count++; 205 } 206 }); 207 208 return count + 1; 209 } 210 211 void computeSizeClass( 212 void delegate(uint id, uint grp, uint delta, uint ndelta) fun 213 ) { 214 uint id = 0; 215 216 // Tiny sizes. 217 foreach (grp; LgTiny .. LgQuantum) { 218 fun(id++, grp, grp, 0); 219 } 220 221 // First group is kind of special. 222 foreach (i; 0 .. 3) { 223 fun(id++, LgQuantum, LgQuantum, i); 224 } 225 226 // Most size classes falls here. 227 foreach (grp; LgQuantum + 2 .. SizeofPtr * 8) { 228 foreach (i; 0 .. 4) { 229 fun(id++, grp, grp - 2, i); 230 } 231 } 232 233 // We want to be able to store the binID in a byte. 234 assert(id <= ubyte.max); 235 } 236 237 void printfAlloc(size_t s) { 238 import d.gc.util, core.stdc.stdio; 239 printf("%lu :\t%lu\t%hhu\n".ptr, s, getAllocSize(s), getBinID(s)); 240 } 241 242 void main() { 243 computeSizeClass((uint id, uint grp, uint delta, uint ndelta) { 244 import core.stdc.stdio; 245 printf("%d\t%d\t%d\t%d\t0x%lx\n".ptr, id, grp, delta, ndelta, 246 (1UL << grp) + ndelta * (1UL << delta)); 247 }); 248 249 import core.stdc.stdio; 250 printf("total: %d\tsmall: %d\tlarge: %d\tlookup: %d\n".ptr, 251 ClassCount.Total, ClassCount.Small, ClassCount.Large, 252 ClassCount.Lookup); 253 254 auto bins = getBinInfos(); 255 256 printf("bins:\n".ptr); 257 foreach (i; 0 .. ClassCount.Small) { 258 auto b = bins[i]; 259 printf("id: %d\tsize: %hd\tneedPages: %hhd\tslots: %hd\n".ptr, i, 260 b.itemSize, b.needPages, b.slots); 261 } 262 263 printf("allocs:\n".ptr); 264 printfAlloc(0); 265 printfAlloc(5); 266 printfAlloc(8); 267 printfAlloc(9); 268 printfAlloc(16); 269 printfAlloc(17); 270 printfAlloc(32); 271 printfAlloc(33); 272 printfAlloc(48); 273 printfAlloc(49); 274 printfAlloc(64); 275 printfAlloc(65); 276 printfAlloc(80); 277 printfAlloc(81); 278 printfAlloc(96); 279 printfAlloc(97); 280 printfAlloc(112); 281 printfAlloc(113); 282 printfAlloc(128); 283 printfAlloc(129); 284 printfAlloc(160); 285 printfAlloc(161); 286 printfAlloc(192); 287 288 printfAlloc(1UL << 63); 289 printfAlloc((1UL << 63) + 1); 290 printfAlloc((1UL << 63) + (1UL << 61)); 291 printfAlloc((1UL << 63) + (1UL << 61) + 1); 292 printfAlloc((1UL << 63) + (2UL << 61)); 293 printfAlloc((1UL << 63) + (2UL << 61) + 1); 294 printfAlloc((1UL << 63) + (3UL << 61)); 295 printfAlloc((1UL << 63) + (3UL << 61) + 1); 296 }