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