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 }