void SACFlush(SAC sac) { Index i, j; Size prevSize; mps_sac_t esac; AVERT(SAC, sac); esac = ExternalSACOfSAC(sac); for (j = sac->middleIndex + 1, i = 0; j < sac->classesCount; ++j, i += 2) { sacClassFlush(sac, i, esac->_freelists[i]._size, esac->_freelists[i]._count); AVER(esac->_freelists[i]._blocks == NULL); } /* no need to flush overlarge, there's nothing there */ prevSize = esac->_middle; for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) { sacClassFlush(sac, i, prevSize, esac->_freelists[i]._count); AVER(esac->_freelists[i]._blocks == NULL); prevSize = esac->_freelists[i]._size; } /* flush smallest class */ sacClassFlush(sac, i, prevSize, esac->_freelists[i]._count); AVER(esac->_freelists[i]._blocks == NULL); }
static void sacFind(Index *iReturn, Size *blockSizeReturn, SAC sac, Size size) { Index i, j; mps_sac_t esac; esac = ExternalSACOfSAC(sac); if (size > esac->_middle) { i = 0; j = sac->middleIndex + 1; AVER(j <= sac->classesCount); while (size > esac->_freelists[i]._size) { AVER(j < sac->classesCount); i += 2; ++j; } *blockSizeReturn = esac->_freelists[i]._size; } else { Size prevSize = esac->_middle; i = 1; j = sac->middleIndex; while (size <= esac->_freelists[i]._size) { AVER(j > 0); prevSize = esac->_freelists[i]._size; i += 2; --j; } *blockSizeReturn = prevSize; } *iReturn = i; }
ATTRIBUTE_UNUSED static Bool SACCheck(SAC sac) { Index i, j; Bool b; Size prevSize; mps_sac_t esac; CHECKS(SAC, sac); esac = ExternalSACOfSAC(sac); CHECKU(Pool, sac->pool); CHECKL(sac->classesCount > 0); CHECKL(sac->classesCount > sac->middleIndex); CHECKL(BoolCheck(esac->_trapped)); CHECKL(esac->_middle > 0); /* check classes above middle */ prevSize = esac->_middle; for (j = sac->middleIndex + 1, i = 0; j < sac->classesCount; ++j, i += 2) { CHECKL(prevSize < esac->_freelists[i]._size); b = sacFreeListBlockCheck(&(esac->_freelists[i])); if (!b) return b; prevSize = esac->_freelists[i]._size; } /* check overlarge class */ CHECKL(prevSize < esac->_freelists[i]._size); b = sacFreeListBlockCheck(&(esac->_freelists[i])); if (!b) return b; CHECKL(esac->_freelists[i]._size == SizeMAX); CHECKL(esac->_freelists[i]._count == 0); CHECKL(esac->_freelists[i]._count_max == 0); CHECKL(esac->_freelists[i]._blocks == NULL); /* check classes below middle */ prevSize = esac->_middle; for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) { CHECKL(prevSize > esac->_freelists[i]._size); b = sacFreeListBlockCheck(&(esac->_freelists[i])); if (!b) return b; prevSize = esac->_freelists[i]._size; } /* check smallest class */ CHECKL(prevSize > esac->_freelists[i]._size); CHECKL(esac->_freelists[i]._size == 0); b = sacFreeListBlockCheck(&(esac->_freelists[i])); return b; }
static void sacClassFlush(SAC sac, Index i, Size blockSize, Count blockCount) { Addr cb, fl; Count j; mps_sac_t esac; esac = ExternalSACOfSAC(sac); for (j = 0, fl = esac->_freelists[i]._blocks; j < blockCount; ++j) { /* @@@@ ignoring shields for now */ cb = fl; fl = *ADDR_PTR(Addr, cb); PoolFree(sac->pool, cb, blockSize); } esac->_freelists[i]._count -= blockCount; esac->_freelists[i]._blocks = fl; }
Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit) { Index i; Count blockCount, j; Size blockSize; Addr p, fl; Res res = ResOK; /* stop compiler complaining */ mps_sac_t esac; AVER(p_o != NULL); AVERT(SAC, sac); AVER(size != 0); AVERT(Bool, hasReservoirPermit); esac = ExternalSACOfSAC(sac); sacFind(&i, &blockSize, sac, size); /* Check it's empty (in the future, there will be other cases). */ AVER(esac->_freelists[i]._count == 0); /* Fill 1/3 of the cache for this class. */ blockCount = esac->_freelists[i]._count_max / 3; /* Adjust size for the overlarge class. */ if (blockSize == SizeMAX) /* .align: align 'cause some classes don't accept unaligned. */ blockSize = SizeAlignUp(size, PoolAlignment(sac->pool)); for (j = 0, fl = esac->_freelists[i]._blocks; j <= blockCount; ++j) { res = PoolAlloc(&p, sac->pool, blockSize, hasReservoirPermit); if (res != ResOK) break; /* @@@@ ignoring shields for now */ *ADDR_PTR(Addr, p) = fl; fl = p; } /* If didn't get any, just return. */ if (j == 0) { AVER(res != ResOK); return res; } /* Take the last one off, and return it. */ esac->_freelists[i]._count = j - 1; *p_o = fl; /* @@@@ ignoring shields for now */ esac->_freelists[i]._blocks = *ADDR_PTR(Addr, fl); return ResOK; }
void SACEmpty(SAC sac, Addr p, Size size) { Index i; Size blockSize; mps_sac_t esac; AVERT(SAC, sac); AVER(p != NULL); AVER(PoolHasAddr(sac->pool, p)); AVER(size > 0); esac = ExternalSACOfSAC(sac); sacFind(&i, &blockSize, sac, size); /* Check it's full (in the future, there will be other cases). */ AVER(esac->_freelists[i]._count == esac->_freelists[i]._count_max); /* Adjust size for the overlarge class. */ if (blockSize == SizeMAX) /* see .align */ blockSize = SizeAlignUp(size, PoolAlignment(sac->pool)); if (esac->_freelists[i]._count_max > 0) { Count blockCount; /* Flush 2/3 of the cache for this class. */ /* Computed as count - count/3, so that the rounding works out right. */ blockCount = esac->_freelists[i]._count; blockCount -= esac->_freelists[i]._count / 3; sacClassFlush(sac, i, blockSize, (blockCount > 0) ? blockCount : 1); /* Leave the current one in the cache. */ esac->_freelists[i]._count += 1; /* @@@@ ignoring shields for now */ *ADDR_PTR(Addr, p) = esac->_freelists[i]._blocks; esac->_freelists[i]._blocks = p; } else { /* Free even the current one. */ PoolFree(sac->pool, p, blockSize); } }
Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, SACClasses classes) { void *p; SAC sac; Res res; Index i, j; Index middleIndex; /* index of the size in the middle */ Size prevSize; unsigned totalFreq = 0; mps_sac_t esac; AVER(sacReturn != NULL); AVERT(Pool, pool); AVER(classesCount > 0); /* In this cache type, there is no upper limit on classesCount. */ prevSize = sizeof(Addr) - 1; /* must large enough for freelist link */ /* @@@@ It would be better to dynamically adjust the smallest class */ /* to be large enough, but that gets complicated, if you have to */ /* merge classes because of the adjustment. */ for (i = 0; i < classesCount; ++i) { AVER(classes[i]._block_size > 0); AVER(SizeIsAligned(classes[i]._block_size, PoolAlignment(pool))); AVER(prevSize < classes[i]._block_size); prevSize = classes[i]._block_size; /* no restrictions on count */ /* no restrictions on frequency */ } /* Calculate frequency scale */ for (i = 0; i < classesCount; ++i) { unsigned oldFreq = totalFreq; totalFreq += classes[i]._frequency; AVER(oldFreq <= totalFreq); /* check for overflow */ UNUSED(oldFreq); /* <code/mpm.c#check.unused> */ } /* Find middle one */ totalFreq /= 2; for (i = 0; i < classesCount; ++i) { if (totalFreq < classes[i]._frequency) break; totalFreq -= classes[i]._frequency; } if (totalFreq <= classes[i]._frequency / 2) middleIndex = i; else middleIndex = i + 1; /* there must exist another class at i+1 */ /* Allocate SAC */ res = ControlAlloc(&p, PoolArena(pool), sacSize(middleIndex, classesCount), FALSE); if(res != ResOK) goto failSACAlloc; sac = p; /* Move classes in place */ /* It's important this matches SACFind. */ esac = ExternalSACOfSAC(sac); for (j = middleIndex + 1, i = 0; j < classesCount; ++j, i += 2) { esac->_freelists[i]._size = classes[j]._block_size; esac->_freelists[i]._count = 0; esac->_freelists[i]._count_max = classes[j]._cached_count; esac->_freelists[i]._blocks = NULL; } esac->_freelists[i]._size = SizeMAX; esac->_freelists[i]._count = 0; esac->_freelists[i]._count_max = 0; esac->_freelists[i]._blocks = NULL; for (j = middleIndex, i = 1; j > 0; --j, i += 2) { esac->_freelists[i]._size = classes[j-1]._block_size; esac->_freelists[i]._count = 0; esac->_freelists[i]._count_max = classes[j]._cached_count; esac->_freelists[i]._blocks = NULL; } esac->_freelists[i]._size = 0; esac->_freelists[i]._count = 0; esac->_freelists[i]._count_max = classes[j]._cached_count; esac->_freelists[i]._blocks = NULL; /* finish init */ esac->_trapped = FALSE; esac->_middle = classes[middleIndex]._block_size; sac->pool = pool; sac->classesCount = classesCount; sac->middleIndex = middleIndex; sac->sig = SACSig; AVERT(SAC, sac); *sacReturn = sac; return ResOK; failSACAlloc: return res; }