001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.mmtk.plan.stickyimmix;
014
015 import org.mmtk.plan.TransitiveClosure;
016 import org.mmtk.plan.immix.Immix;
017 import org.mmtk.utility.Log;
018 import org.mmtk.utility.deque.SharedDeque;
019 import org.mmtk.utility.options.Options;
020 import org.mmtk.utility.statistics.BooleanCounter;
021 import org.mmtk.utility.statistics.Stats;
022 import org.mmtk.vm.Collection;
023
024 import org.vmmagic.pragma.*;
025
026 /**
027 * This class implements the global state of a simple sticky mark bits collector,
028 * based on an immix collector. The sticky mark bits algorithm is
029 * due to Demmers et al. (http://doi.acm.org/10.1145/96709.96735), and allows
030 * generational collection to be performed in a non-moving heap by overloading
031 * the role of mark bits to also indicate whether an object is new (nursery) or
032 * not. Thus nursery objects are identified by a bit in their header, not by
033 * where they lie within the address space. While Demmers et al. did their work
034 * in a conservative collector, here we have an exact collector, so we can use
035 * a regular write barrier, and don't need to use page protection etc.
036 *
037 * See the PLDI'08 paper by Blackburn and McKinley for a description
038 * of the algorithm: http://doi.acm.org/10.1145/1375581.1375586
039 *
040 * All plans make a clear distinction between <i>global</i> and
041 * <i>thread-local</i> activities, and divides global and local state
042 * into separate class hierarchies. Global activities must be
043 * synchronized, whereas no synchronization is required for
044 * thread-local activities. There is a single instance of Plan (or the
045 * appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
046 * threads" (aka CPUs or in Jikes RVM, Processors). Thus instance
047 * methods of PlanLocal allow fast, unsychronized access to functions such as
048 * allocation and collection.
049 *
050 * The global instance defines and manages static resources
051 * (such as memory and virtual memory resources). This mapping of threads to
052 * instances is crucial to understanding the correctness and
053 * performance properties of MMTk plans.
054 */
055 @Uninterruptible
056 public class StickyImmix extends Immix {
057
058 /****************************************************************************
059 * Constants
060 */
061 /** If true, then new PLOS objects are collected at each nursery GC */
062 static final boolean NURSERY_COLLECT_PLOS = true;
063 /** If true then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
064 static final boolean MAJOR_GC_ONLY = false;
065 /** estimated collection yield */
066 protected static final float SURVIVAL_ESTIMATE = (float) 0.8;
067
068 public static int SCAN_NURSERY = 2;
069
070 /****************************************************************************
071 * Class variables
072 */
073 private static int lastCommittedImmixPages = 0;
074
075 /* statistics */
076 public static BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);
077
078 /****************************************************************************
079 * Instance variables
080 */
081 /* Remset pool */
082 public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
083
084 /**
085 * Constructor.
086 *
087 */
088 public StickyImmix() {
089 collectWholeHeap = nextGCWholeHeap = false;
090 }
091
092 /*****************************************************************************
093 *
094 * Collection
095 */
096
097 /**
098 * A user-triggered GC has been initiated.
099 */
100 public void userTriggeredGC() {
101 nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
102 }
103
104 /**
105 * Force the next collection to be full heap.
106 */
107 @Override
108 public void forceFullHeapCollection() {
109 nextGCWholeHeap = true;
110 }
111
112 /**
113 * Perform a (global) collection phase.
114 *
115 * @param phaseId Collection phase to execute.
116 */
117 @Inline
118 @Override
119 public final void collectionPhase(short phaseId) {
120
121 if (phaseId == SET_COLLECTION_KIND) {
122 collectWholeHeap = requiresFullHeapCollection();
123 if (Stats.gatheringStats() && collectWholeHeap) fullHeap.set();
124 super.collectionPhase(phaseId);
125 return;
126 }
127
128 if (!collectWholeHeap && phaseId == PREPARE) {
129 immixTrace.prepare();
130 immixSpace.prepare(false);
131 return;
132 }
133
134 if (phaseId == RELEASE) {
135 if (collectWholeHeap) {
136 super.collectionPhase(RELEASE);
137 } else {
138 immixTrace.release();
139 lastGCWasDefrag = immixSpace.release(false);
140 }
141 modPool.reset();
142 lastCommittedImmixPages = immixSpace.committedPages();
143 nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
144 return;
145 }
146
147 super.collectionPhase(phaseId);
148 }
149
150 /*****************************************************************************
151 *
152 * Accounting
153 */
154
155 /**
156 * This method controls the triggering of a GC. It is called periodically
157 * during allocation. Returns true to trigger a collection.
158 *
159 * @param spaceFull Space request failed, must recover pages within 'space'.
160 * @return True if a collection is requested by the plan.
161 */
162 public final boolean collectionRequired(boolean spaceFull) {
163 boolean nurseryFull = immixSpace.getPagesAllocated() > Options.nurserySize.getMaxNursery();
164 return super.collectionRequired(spaceFull) || nurseryFull;
165 }
166
167 /**
168 * Determine whether this GC should be a full heap collection.
169 *
170 * @return True if this GC should be a full heap collection.
171 */
172 protected boolean requiresFullHeapCollection() {
173 if (collectionTrigger == Collection.EXTERNAL_GC_TRIGGER && Options.fullHeapSystemGC.getValue()) {
174 return true;
175 }
176 if (nextGCWholeHeap || collectionAttempt > 1) {
177 // Forces full heap collection
178 return true;
179 }
180 if (loSpace.allocationFailed()) {
181 // We need space from the nursery
182 return true;
183 }
184
185 // Estimate the yield from small nursery pages
186 int smallNurseryPages = immixSpace.committedPages() - lastCommittedImmixPages;
187 int smallNurseryYield = (int)(smallNurseryPages * SURVIVAL_ESTIMATE);
188
189 if (smallNurseryYield < getPagesRequired()) {
190 // Our total yield is insufficient.
191 return true;
192 }
193
194 if (immixSpace.allocationFailed()) {
195 if (smallNurseryYield < immixSpace.requiredPages()) {
196 // We have run out of VM pages in the nursery
197 return true;
198 }
199 }
200
201 return false;
202 }
203
204 /**
205 * Print pre-collection statistics. In this class we prefix the output
206 * indicating whether the collection was full heap or not.
207 */
208 @Override
209 public void printPreStats() {
210 if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
211 Log.write("[Full heap]");
212 super.printPreStats();
213 }
214
215 /**
216 * @return Is current GC only collecting objects allocated since last GC.
217 */
218 public final boolean isCurrentGCNursery() {
219 return !collectWholeHeap;
220 }
221
222 /**
223 * @return Is last GC a full collection?
224 */
225 public final boolean isLastGCFull() {
226 return collectWholeHeap;
227 }
228
229 /**
230 * Register specialized methods.
231 */
232 @Interruptible
233 protected void registerSpecializedMethods() {
234 TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyImmixNurseryTraceLocal.class);
235 super.registerSpecializedMethods();
236 }
237 }