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    
014    package org.mmtk.policy.immix;
015    
016    import static org.mmtk.policy.immix.ImmixConstants.*;
017    
018    
019    import org.mmtk.utility.Constants;
020    import org.mmtk.utility.Log;
021    import org.mmtk.utility.heap.FreeListPageResource;
022    import org.mmtk.utility.options.DefragFreeHeadroom;
023    import org.mmtk.utility.options.DefragFreeHeadroomFraction;
024    import org.mmtk.utility.options.DefragHeadroom;
025    import org.mmtk.utility.options.DefragHeadroomFraction;
026    import org.mmtk.utility.options.DefragLineReuseRatio;
027    import org.mmtk.utility.options.DefragSimpleSpillThreshold;
028    import org.mmtk.utility.options.DefragStress;
029    import org.mmtk.utility.options.Options;
030    import org.mmtk.utility.statistics.EventCounter;
031    import org.mmtk.utility.statistics.SizeCounter;
032    import org.mmtk.vm.Collection;
033    import org.mmtk.vm.VM;
034    import org.vmmagic.pragma.Uninterruptible;
035    
036    @Uninterruptible
037    public class Defrag  implements Constants {
038    
039    
040      private int defragHeadroomPages = 0;
041      private int defragFreeHeadroomPages = 0;
042      private boolean inDefragCollection = false;
043      private int debugBytesDefraged = 0;
044      private int availableCleanPagesForDefrag;
045      private boolean defragSpaceExhausted = true;
046      private int[][] spillMarkHistograms = new int[MAX_COLLECTORS][SPILL_HISTOGRAM_BUCKETS];
047      private int[] spillAvailHistogram = new int[SPILL_HISTOGRAM_BUCKETS];
048      public static SizeCounter defragCleanBytesUsed = new SizeCounter("cleanUsed");
049      /* verbose stats (used only on stats runs since they induce overhead when gathred) */
050      public static SizeCounter defragBytesNotFreed = new SizeCounter("bytesNotFreed");
051      public static SizeCounter defragBytesFreed = new SizeCounter("bytesFreed");
052      public static SizeCounter defragCleanBytesAvailable = new SizeCounter("cleanAvail");
053    
054      private final FreeListPageResource pr;
055      private boolean debugCollectionTypeDetermined = false;
056      static short defragSpillThreshold = 0;
057      static short defragReusableMarkStateThreshold = 0;
058      public static EventCounter defrags = new EventCounter("defrags");
059    
060      static {
061        Options.defragLineReuseRatio = new DefragLineReuseRatio();
062        Options.defragHeadroom = new DefragHeadroom();
063        Options.defragHeadroomFraction = new DefragHeadroomFraction();
064        Options.defragFreeHeadroom = new DefragFreeHeadroom();
065        Options.defragFreeHeadroomFraction = new DefragFreeHeadroomFraction();
066        Options.defragSimpleSpillThreshold = new DefragSimpleSpillThreshold();
067        Options.defragStress = new DefragStress();
068        defragReusableMarkStateThreshold = (short) (Options.defragLineReuseRatio.getValue() * MAX_BLOCK_MARK_STATE);
069      }
070    
071      Defrag(FreeListPageResource pr) {
072        this.pr = pr;
073      }
074    
075      boolean inDefrag() { return inDefragCollection; }
076    
077      void prepare(ChunkList chunkMap, ImmixSpace space) {
078        if (defragHeadroomPages > 0)
079          pr.unconditionallyReleasePages(defragHeadroomPages);
080    
081        availableCleanPagesForDefrag = VM.activePlan.global().getTotalPages() - VM.activePlan.global().getPagesReserved();
082        if (availableCleanPagesForDefrag < 0) availableCleanPagesForDefrag = 0;
083        defragSpaceExhausted = false;
084        availableCleanPagesForDefrag += defragFreeHeadroomPages;
085        if (inDefragCollection) {
086          if (Options.verbose.getValue() > 0) {
087            Log.write("[Defrag]");
088          }
089          chunkMap.consolidateMap();
090          establishDefragSpillThreshold(chunkMap, space);
091          defrags.inc();
092          defragCleanBytesAvailable.inc(availableCleanPagesForDefrag<<LOG_BYTES_IN_PAGE);
093        }
094        availableCleanPagesForDefrag += VM.activePlan.global().getCollectionReserve();
095      }
096    
097      void globalRelease() {
098        if (Options.defragHeadroom.getPages() > 0)
099          defragHeadroomPages = Options.defragHeadroom.getPages();
100        else if (Options.defragHeadroomFraction.getValue() > 0)
101          defragHeadroomPages = (int) (pr.reservedPages() * Options.defragHeadroomFraction.getValue());
102        else
103          defragHeadroomPages = 0;
104        if (Options.defragFreeHeadroom.getPages() > 0)
105          defragFreeHeadroomPages = Options.defragFreeHeadroom.getPages();
106        else if (Options.defragFreeHeadroomFraction.getValue() > 0)
107          defragFreeHeadroomPages = (int) (pr.reservedPages() * Options.defragFreeHeadroomFraction.getValue());
108        else
109          defragFreeHeadroomPages = 0;
110    
111        if (defragHeadroomPages > 0)
112          pr.unconditionallyReservePages(defragHeadroomPages);
113    
114        if (inDefragCollection && Options.verbose.getValue() > 2) {
115          Log.write("(Defrag summary: cu: "); defragCleanBytesUsed.printCurrentVolume();
116          Log.write(" nf: "); defragBytesNotFreed.printCurrentVolume();
117          Log.write(" fr: "); defragBytesFreed.printCurrentVolume();
118          Log.write(" av: "); defragCleanBytesAvailable.printCurrentVolume();
119          Log.write(")");
120        }
121    
122        inDefragCollection = false;
123        debugCollectionTypeDetermined = false;
124      }
125    
126      void decideWhetherToDefrag(boolean emergencyCollection, boolean collectWholeHeap, int collectionAttempt, int collectionTrigger, boolean exhaustedReusableSpace) {
127        boolean userTriggered = collectionTrigger == Collection.EXTERNAL_GC_TRIGGER && Options.fullHeapSystemGC.getValue();
128        inDefragCollection =  (collectionAttempt > 1) ||
129            emergencyCollection ||
130            collectWholeHeap && (Options.defragStress.getValue() || userTriggered);
131        if (inDefragCollection) {
132          debugBytesDefraged = 0;
133        }
134        debugCollectionTypeDetermined = true;
135      }
136    
137      boolean determined(boolean inDefrag) { return debugCollectionTypeDetermined && !(inDefrag ^ inDefragCollection); }
138    
139      void getBlock() {
140        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!inDefragCollection || !defragSpaceExhausted);
141        if (availableCleanPagesForDefrag <= 0)
142          defragSpaceExhausted = true;
143        availableCleanPagesForDefrag -= PAGES_IN_BLOCK;
144        debugBytesDefraged += BYTES_IN_BLOCK;
145        Defrag.defragCleanBytesUsed.inc(BYTES_IN_BLOCK);
146      }
147    
148      private void establishDefragSpillThreshold(ChunkList chunkMap, ImmixSpace space) {
149        int cleanLines = space.getAvailableLines(spillAvailHistogram);
150        int availableLines = cleanLines + availableCleanPagesForDefrag<<(LOG_BYTES_IN_PAGE - LOG_BYTES_IN_LINE);
151    
152        int requiredLines = 0;
153        short threshold = (short) MAX_CONSV_SPILL_COUNT;
154        int limit = (int) (availableLines / Options.defragLineReuseRatio.getValue());
155        if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) {
156          Log.write("[threshold: "); Log.write("cl: "); Log.write(cleanLines);
157          Log.write(" al: "); Log.write(availableLines);
158          Log.write(" lm: "); Log.write(limit);
159        }
160        int collectors = VM.activePlan.collectorCount();
161        for (short index = MAX_CONSV_SPILL_COUNT; index >= TMP_MIN_SPILL_THRESHOLD && limit > requiredLines; index--) {
162          threshold = (short) index;
163          int thisBucketMark = 0;
164          int thisBucketAvail = 0;
165          for (int c = 0; c < collectors; c++) thisBucketMark += spillMarkHistograms[c][threshold];
166    
167          thisBucketAvail = spillAvailHistogram[threshold];
168          limit -= thisBucketAvail;
169          requiredLines += thisBucketMark;
170          if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) {
171            Log.write(" ("); Log.write(index); Log.write(" "); Log.write(limit); Log.write(","); Log.write(requiredLines); Log.write(")");
172          }
173        }
174        if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) {
175          Log.write(" threshold: "); Log.write(threshold); Log.write("]");
176        }
177        defragSpillThreshold = threshold;
178      }
179    
180    
181      boolean spaceExhausted() { return defragSpaceExhausted; }
182    
183      int[] getAndZeroSpillMarkHistogram(int ordinal) {
184        int[] rtn = spillMarkHistograms[ordinal];
185        for (int i = 0; i < SPILL_HISTOGRAM_BUCKETS; i++)
186          rtn[i] = 0;
187        return rtn;
188      }
189    }