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 }