/* flip.c
*
* COPYRIGHT (c) 1993 by AT&T Bell Laboratories.
*
* This code determines which generations to flip and what the
* to-space sizes should be.
*/
#include "ml-base.h"
#include "ml-limits.h"
#include "ml-state.h"
#include "heap.h"
#include "heap-monitor.h"
#if defined(VERBOSE)
extern char *ArenaName[NUM_ARENAS+1];
#endif
/* Flip:
*
* Determine which generations need to be flipped and flip them. Return
* the number of flipped generations (which will be at least min_gc_level).
* It is assumed that the fist generation is always flipped (i.e., that
* min_gc_level > 1).
*/
int Flip (heap_t *heap, int min_gc_level)
{
int i, j, prevGC, numGCs;
Addr_t newSz, prevOldSz[NUM_ARENAS], minSize[NUM_ARENAS];
arena_t *ap;
#ifdef VERBOSE
SayDebug ("Flip: min_gc_level = %d\n", min_gc_level);
#endif
for (i = 0; i < NUM_ARENAS; i++)
prevOldSz[i] = heap->allocSzB;
prevGC = heap->numMinorGCs;
for (i = 0; i < heap->numGens; i++) {
gen_t *g = heap->gen[i];
/* Check to see if generation (i+1) should be flipped */
#ifdef VERBOSE
SayDebug ("checking generation %d\n", i+1);
#endif
if (i >= min_gc_level) {
for (j = 0; j < NUM_ARENAS; j++) {
arena_t *ap = g->arena[j];
#ifdef VERBOSE
SayDebug (" %s: avail = %d, prev = %d\n",
ArenaName[j+1], (isACTIVE(ap) ? AVAIL_SPACE(ap) : 0), prevOldSz[j]);
#endif
if ((isACTIVE(ap) ? AVAIL_SPACE(ap) : 0) < prevOldSz[j])
goto flip;
}
/* Here we don't need to flip gen[i] */
return i;
}
flip:; /* Here we need to flip gen[i] */
numGCs = prevGC - g->lastPrevGC;
#ifdef VERBOSE
SayDebug ("Flip generation %d: (%d GCs)\n", i+1, numGCs);
#endif
/* Compute the space requirements for this generation, make the old
* to-space into from-space, and allocate a new to-space.
*/
for (j = 0; j < NUM_ARENAS; j++) {
Addr_t minSz, thisMinSz;
ap = g->arena[j];
if (isACTIVE(ap)) {
FLIP_ARENA(ap);
HeapMon_MarkFromSp (heap, ap->frspBase, ap->frspSizeB);
thisMinSz = ((Addr_t)(ap->frspTop) - (Addr_t)(ap->oldTop));
}
else {
ap->frspSizeB = 0; /* to ensure accurate stats */
if ((ap->reqSizeB == 0) && (prevOldSz[j] == 0))
continue;
else
thisMinSz = 0;
}
minSz = prevOldSz[j] + thisMinSz + ap->reqSizeB;
if (j == PAIR_INDX)
/* first slot isn't used, but may need the space for poly = */
minSz += 2*WORD_SZB;
minSize[j] = minSz;
#ifdef OLD_POLICY
/* The desired size is the minimum size times the ratio for the arena,
* but it shouldn't exceed the maximum size for the arena (unless
* minSz > maxSizeB).
*/
newSz = (ap->ratio * minSz) / RATIO_UNIT;
if (newSz < minSz+ap->reqSizeB)
newSz = minSz+ap->reqSizeB;
#endif
/* The desired size is one that will allow "ratio" GCs of the
* previous generation before this has to be collected again.
* We approximate this as ((f*ratio) / n), where
* f == # of bytes forwarded since the last collection of this generation
* n == # of collections of the previous generation since the last
* collection of this generation
* We also need to allow space for young objects in this generation,
* but the new size shouldn't exceed the maximum size for the arena
* (unless minSz > maxSizeB).
*/
newSz = prevOldSz[j] + ap->reqSizeB + (g->ratio * (thisMinSz / numGCs));
if (newSz < minSz)
newSz = minSz;
#ifdef VERBOSE
SayDebug (" %s: min = %d, prev = %d, thisMin = %d, req = %d, new = %d, max = %d\n",
ArenaName[j+1], minSz, prevOldSz[j], thisMinSz, ap->reqSizeB, newSz, ap->maxSizeB);
#endif
if (newSz > ap->maxSizeB)
newSz = (minSz > ap->maxSizeB) ? minSz : ap->maxSizeB;
if (newSz > 0) {
ap->tospSizeB = RND_MEMOBJ_SZB(newSz);
#ifdef VERBOSE
SayDebug (" alloc %d\n", ap->tospSizeB);
#endif
}
else {
ap->nextw = NIL(ml_val_t *);
ap->tospTop = NIL(ml_val_t *);
ap->tospSizeB = 0;
}
/* Note: any data between ap->oldTop and ap->nextw is "young", and
* should stay in this generation.
*/
if (ap->frspSizeB > 0)
prevOldSz[j] = (Addr_t)(ap->oldTop) - (Addr_t)(ap->frspBase);
else
prevOldSz[j] = 0;
}
g->lastPrevGC = prevGC;
g->numGCs++;
prevGC = g->numGCs;
g->fromObj = g->toObj;
if (NewGeneration(g) == FAILURE) {
/* try to allocate the minimum size */
Error ("unable to allocate to-space for generation %d; trying smaller size\n", i+1);
for (j = 0; j < NUM_ARENAS; j++) {
g->arena[j]->tospSizeB = RND_MEMOBJ_SZB(minSize[j]);
}
if (NewGeneration(g) == FAILURE)
Die("unable to allocate minimum size\n");
}
#ifdef TOSPACE_ID
for (j = 0; j < NUM_ARENAS; j++) {
arena_t *ap = g->arena[j];
if (isACTIVE(ap))
MarkRegion (BIBOP, ap->tospBase, ap->tospSizeB, TOSPACE_AID(i+1));
}
#endif
if (isACTIVE(g->arena[ARRAY_INDX]))
NewDirtyVector(g);
}
return heap->numGens;
} /* end of Flip */
syntax highlighted by Code2HTML, v. 0.9.1