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 }