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.policy.Space;
018 import org.mmtk.utility.Log;
019 import org.mmtk.utility.deque.SharedDeque;
020 import org.mmtk.utility.options.Options;
021 import org.mmtk.utility.statistics.BooleanCounter;
022 import org.mmtk.utility.statistics.Stats;
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.<p>
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<p>
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.<p>
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.<p>
054 */
055 @Uninterruptible
056 public class StickyImmix extends Immix {
057
058 /****************************************************************************
059 * Constants
060 */
061
062 /** If true, then new PLOS objects are collected at each nursery GC */
063 static final boolean NURSERY_COLLECT_PLOS = true;
064 /** If true then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
065 static final boolean MAJOR_GC_ONLY = false;
066 /** estimated collection yield */
067 protected static final float SURVIVAL_ESTIMATE = (float) 0.8;
068
069 public static int SCAN_NURSERY = 2;
070
071 /****************************************************************************
072 * Class variables
073 */
074
075 /**
076 * TODO: this field is unused, somebody with MMTk knowledge needs to look at it
077 */
078 private static int lastCommittedImmixPages = 0;
079
080 /* statistics */
081 public static BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);
082
083 /****************************************************************************
084 * Instance variables
085 */
086
087 /** Remset pool */
088 public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
089
090 /**
091 * Constructor.
092 *
093 */
094 public StickyImmix() {
095 collectWholeHeap = nextGCWholeHeap = false;
096 }
097
098 /*****************************************************************************
099 *
100 * Collection
101 */
102
103 /**
104 * A user-triggered GC has been initiated.
105 */
106 public void userTriggeredGC() {
107 nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
108 }
109
110 @Override
111 public void forceFullHeapCollection() {
112 nextGCWholeHeap = true;
113 }
114
115 @Inline
116 @Override
117 public final void collectionPhase(short phaseId) {
118
119 if (phaseId == SET_COLLECTION_KIND) {
120 super.collectionPhase(phaseId);
121 collectWholeHeap = requiresFullHeapCollection();
122 if (Stats.gatheringStats() && collectWholeHeap) fullHeap.set();
123 return;
124 }
125
126 if (!collectWholeHeap && phaseId == PREPARE) {
127 immixTrace.prepare();
128 immixSpace.prepare(false);
129 return;
130 }
131
132 if (phaseId == RELEASE) {
133 if (collectWholeHeap) {
134 super.collectionPhase(RELEASE);
135 } else {
136 immixTrace.release();
137 lastGCWasDefrag = immixSpace.release(false);
138 }
139 modPool.reset();
140 lastCommittedImmixPages = immixSpace.committedPages();
141 nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
142 return;
143 }
144
145 super.collectionPhase(phaseId);
146 }
147
148 /*****************************************************************************
149 *
150 * Accounting
151 */
152
153 /**
154 * {@inheritDoc}
155 */
156 @Override
157 public final boolean collectionRequired(boolean spaceFull, Space space) {
158 boolean nurseryFull = immixSpace.getPagesAllocated() > Options.nurserySize.getMaxNursery();
159 if (spaceFull && space != immixSpace) nextGCWholeHeap = true;
160 return super.collectionRequired(spaceFull, space) || nurseryFull;
161 }
162
163 /**
164 * Determine whether this GC should be a full heap collection.
165 *
166 * @return True if this GC should be a full heap collection.
167 */
168 protected boolean requiresFullHeapCollection() {
169 if (userTriggeredCollection && Options.fullHeapSystemGC.getValue()) {
170 return true;
171 }
172
173 if (nextGCWholeHeap || collectionAttempt > 1) {
174 // Forces full heap collection
175 return true;
176 }
177
178 return false;
179 }
180
181 @Override
182 public int getCollectionReserve() {
183 return super.getCollectionReserve() + immixSpace.defragHeadroomPages();
184 }
185
186 /**
187 * {@inheritDoc}
188 * In this class we prefix the output
189 * indicating whether the collection was full heap or not.
190 */
191 @Override
192 public void printPreStats() {
193 if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
194 Log.write("[Full heap]");
195 super.printPreStats();
196 }
197
198 @Override
199 public final boolean isCurrentGCNursery() {
200 return !collectWholeHeap;
201 }
202
203 public final boolean isLastGCFull() {
204 return collectWholeHeap;
205 }
206
207 @Override
208 @Interruptible
209 protected void registerSpecializedMethods() {
210 TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyImmixNurseryTraceLocal.class);
211 super.registerSpecializedMethods();
212 }
213 }