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    }