blob: a9beb266b7a9c80e7fd46d362b2d3a2772ca3511 [file] [log] [blame]
/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.plan.stickyimmix;
import org.mmtk.plan.TransitiveClosure;
import org.mmtk.plan.immix.Immix;
import org.mmtk.utility.Log;
import org.mmtk.utility.deque.SharedDeque;
import org.mmtk.utility.options.Options;
import org.mmtk.utility.statistics.BooleanCounter;
import org.mmtk.utility.statistics.Stats;
import org.mmtk.vm.Collection;
import org.vmmagic.pragma.*;
/**
* This class implements the global state of a simple sticky mark bits collector,
* based on an immix collector. The sticky mark bits algorithm is
* due to Demmers et al. (http://doi.acm.org/10.1145/96709.96735), and allows
* generational collection to be performed in a non-moving heap by overloading
* the role of mark bits to also indicate whether an object is new (nursery) or
* not. Thus nursery objects are identified by a bit in their header, not by
* where they lie within the address space. While Demmers et al. did their work
* in a conservative collector, here we have an exact collector, so we can use
* a regular write barrier, and don't need to use page protection etc.
*
* See the PLDI'08 paper by Blackburn and McKinley for a description
* of the algorithm: http://doi.acm.org/10.1145/1375581.1375586
*
* All plans make a clear distinction between <i>global</i> and
* <i>thread-local</i> activities, and divides global and local state
* into separate class hierarchies. Global activities must be
* synchronized, whereas no synchronization is required for
* thread-local activities. There is a single instance of Plan (or the
* appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
* threads" (aka CPUs or in Jikes RVM, Processors). Thus instance
* methods of PlanLocal allow fast, unsychronized access to functions such as
* allocation and collection.
*
* The global instance defines and manages static resources
* (such as memory and virtual memory resources). This mapping of threads to
* instances is crucial to understanding the correctness and
* performance properties of MMTk plans.
*/
@Uninterruptible
public class StickyImmix extends Immix {
/****************************************************************************
* Constants
*/
/** If true, then new PLOS objects are collected at each nursery GC */
static final boolean NURSERY_COLLECT_PLOS = true;
/** If true then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
static final boolean MAJOR_GC_ONLY = false;
/** estimated collection yield */
protected static final float SURVIVAL_ESTIMATE = (float) 0.8;
public static int SCAN_NURSERY = 2;
/****************************************************************************
* Class variables
*/
private static int lastCommittedImmixPages = 0;
/* statistics */
public static BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);
/****************************************************************************
* Instance variables
*/
/* Remset pool */
public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
/**
* Constructor.
*
*/
public StickyImmix() {
collectWholeHeap = nextGCWholeHeap = false;
}
/*****************************************************************************
*
* Collection
*/
/**
* A user-triggered GC has been initiated.
*/
public void userTriggeredGC() {
nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
}
/**
* Force the next collection to be full heap.
*/
@Override
public void forceFullHeapCollection() {
nextGCWholeHeap = true;
}
/**
* Perform a (global) collection phase.
*
* @param phaseId Collection phase to execute.
*/
@Inline
@Override
public final void collectionPhase(short phaseId) {
if (phaseId == SET_COLLECTION_KIND) {
collectWholeHeap = requiresFullHeapCollection();
if (Stats.gatheringStats() && collectWholeHeap) fullHeap.set();
super.collectionPhase(phaseId);
return;
}
if (!collectWholeHeap && phaseId == PREPARE) {
immixTrace.prepare();
immixSpace.prepare(false);
return;
}
if (phaseId == RELEASE) {
if (collectWholeHeap) {
super.collectionPhase(RELEASE);
} else {
immixTrace.release();
lastGCWasDefrag = immixSpace.release(false);
}
modPool.reset();
lastCommittedImmixPages = immixSpace.committedPages();
nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
return;
}
super.collectionPhase(phaseId);
}
/*****************************************************************************
*
* Accounting
*/
/**
* This method controls the triggering of a GC. It is called periodically
* during allocation. Returns true to trigger a collection.
*
* @param spaceFull Space request failed, must recover pages within 'space'.
* @return True if a collection is requested by the plan.
*/
public final boolean collectionRequired(boolean spaceFull) {
boolean nurseryFull = immixSpace.getPagesAllocated() > Options.nurserySize.getMaxNursery();
return super.collectionRequired(spaceFull) || nurseryFull;
}
/**
* Determine whether this GC should be a full heap collection.
*
* @return True if this GC should be a full heap collection.
*/
protected boolean requiresFullHeapCollection() {
if (collectionTrigger == Collection.EXTERNAL_GC_TRIGGER && Options.fullHeapSystemGC.getValue()) {
return true;
}
if (nextGCWholeHeap || collectionAttempt > 1) {
// Forces full heap collection
return true;
}
if (loSpace.allocationFailed()) {
// We need space from the nursery
return true;
}
// Estimate the yield from small nursery pages
int smallNurseryPages = immixSpace.committedPages() - lastCommittedImmixPages;
int smallNurseryYield = (int)(smallNurseryPages * SURVIVAL_ESTIMATE);
if (smallNurseryYield < getPagesRequired()) {
// Our total yield is insufficient.
return true;
}
if (immixSpace.allocationFailed()) {
if (smallNurseryYield < immixSpace.requiredPages()) {
// We have run out of VM pages in the nursery
return true;
}
}
return false;
}
/**
* Print pre-collection statistics. In this class we prefix the output
* indicating whether the collection was full heap or not.
*/
@Override
public void printPreStats() {
if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
Log.write("[Full heap]");
super.printPreStats();
}
/**
* @return Is current GC only collecting objects allocated since last GC.
*/
public final boolean isCurrentGCNursery() {
return !collectWholeHeap;
}
/**
* @return Is last GC a full collection?
*/
public final boolean isLastGCFull() {
return collectWholeHeap;
}
/**
* Register specialized methods.
*/
@Interruptible
protected void registerSpecializedMethods() {
TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyImmixNurseryTraceLocal.class);
super.registerSpecializedMethods();
}
}