| /* |
| * This file is part of the Jikes RVM project (http://jikesrvm.org). |
| * |
| * This file is licensed to You under the Eclipse Public License (EPL); |
| * You may not use this file except in compliance with the License. You |
| * may obtain a copy of the License at |
| * |
| * http://www.opensource.org/licenses/eclipse-1.0.php |
| * |
| * See the COPYRIGHT.txt file distributed with this work for information |
| * regarding copyright ownership. |
| */ |
| |
| package org.mmtk.policy.immix; |
| |
| import static org.mmtk.policy.immix.ImmixConstants.*; |
| |
| |
| import org.mmtk.utility.Constants; |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.heap.FreeListPageResource; |
| import org.mmtk.utility.options.DefragFreeHeadroom; |
| import org.mmtk.utility.options.DefragFreeHeadroomFraction; |
| import org.mmtk.utility.options.DefragHeadroom; |
| import org.mmtk.utility.options.DefragHeadroomFraction; |
| import org.mmtk.utility.options.DefragLineReuseRatio; |
| import org.mmtk.utility.options.DefragSimpleSpillThreshold; |
| import org.mmtk.utility.options.DefragStress; |
| import org.mmtk.utility.options.Options; |
| import org.mmtk.utility.statistics.EventCounter; |
| import org.mmtk.utility.statistics.SizeCounter; |
| import org.mmtk.vm.Collection; |
| import org.mmtk.vm.VM; |
| import org.vmmagic.pragma.Uninterruptible; |
| |
| @Uninterruptible |
| public class Defrag implements Constants { |
| |
| |
| private int defragHeadroomPages = 0; |
| private int defragFreeHeadroomPages = 0; |
| private boolean inDefragCollection = false; |
| private int debugBytesDefraged = 0; |
| private int availableCleanPagesForDefrag; |
| private boolean defragSpaceExhausted = true; |
| private int[][] spillMarkHistograms = new int[MAX_COLLECTORS][SPILL_HISTOGRAM_BUCKETS]; |
| private int[] spillAvailHistogram = new int[SPILL_HISTOGRAM_BUCKETS]; |
| public static SizeCounter defragCleanBytesUsed = new SizeCounter("cleanUsed"); |
| /* verbose stats (used only on stats runs since they induce overhead when gathred) */ |
| public static SizeCounter defragBytesNotFreed = new SizeCounter("bytesNotFreed"); |
| public static SizeCounter defragBytesFreed = new SizeCounter("bytesFreed"); |
| public static SizeCounter defragCleanBytesAvailable = new SizeCounter("cleanAvail"); |
| |
| private final FreeListPageResource pr; |
| private boolean debugCollectionTypeDetermined = false; |
| static short defragSpillThreshold = 0; |
| static short defragReusableMarkStateThreshold = 0; |
| public static EventCounter defrags = new EventCounter("defrags"); |
| |
| static { |
| Options.defragLineReuseRatio = new DefragLineReuseRatio(); |
| Options.defragHeadroom = new DefragHeadroom(); |
| Options.defragHeadroomFraction = new DefragHeadroomFraction(); |
| Options.defragFreeHeadroom = new DefragFreeHeadroom(); |
| Options.defragFreeHeadroomFraction = new DefragFreeHeadroomFraction(); |
| Options.defragSimpleSpillThreshold = new DefragSimpleSpillThreshold(); |
| Options.defragStress = new DefragStress(); |
| defragReusableMarkStateThreshold = (short) (Options.defragLineReuseRatio.getValue() * MAX_BLOCK_MARK_STATE); |
| } |
| |
| Defrag(FreeListPageResource pr) { |
| this.pr = pr; |
| } |
| |
| boolean inDefrag() { return inDefragCollection; } |
| |
| void prepare(ChunkList chunkMap, ImmixSpace space) { |
| if (defragHeadroomPages > 0) |
| pr.unconditionallyReleasePages(defragHeadroomPages); |
| |
| availableCleanPagesForDefrag = VM.activePlan.global().getTotalPages() - VM.activePlan.global().getPagesReserved(); |
| if (availableCleanPagesForDefrag < 0) availableCleanPagesForDefrag = 0; |
| defragSpaceExhausted = false; |
| availableCleanPagesForDefrag += defragFreeHeadroomPages; |
| if (inDefragCollection) { |
| if (Options.verbose.getValue() > 0) { |
| Log.write("[Defrag]"); |
| } |
| chunkMap.consolidateMap(); |
| establishDefragSpillThreshold(chunkMap, space); |
| defrags.inc(); |
| defragCleanBytesAvailable.inc(availableCleanPagesForDefrag<<LOG_BYTES_IN_PAGE); |
| } |
| availableCleanPagesForDefrag += VM.activePlan.global().getCollectionReserve(); |
| } |
| |
| void globalRelease() { |
| if (Options.defragHeadroom.getPages() > 0) |
| defragHeadroomPages = Options.defragHeadroom.getPages(); |
| else if (Options.defragHeadroomFraction.getValue() > 0) |
| defragHeadroomPages = (int) (pr.reservedPages() * Options.defragHeadroomFraction.getValue()); |
| else |
| defragHeadroomPages = 0; |
| if (Options.defragFreeHeadroom.getPages() > 0) |
| defragFreeHeadroomPages = Options.defragFreeHeadroom.getPages(); |
| else if (Options.defragFreeHeadroomFraction.getValue() > 0) |
| defragFreeHeadroomPages = (int) (pr.reservedPages() * Options.defragFreeHeadroomFraction.getValue()); |
| else |
| defragFreeHeadroomPages = 0; |
| |
| if (defragHeadroomPages > 0) |
| pr.unconditionallyReservePages(defragHeadroomPages); |
| |
| if (inDefragCollection && Options.verbose.getValue() > 2) { |
| Log.write("(Defrag summary: cu: "); defragCleanBytesUsed.printCurrentVolume(); |
| Log.write(" nf: "); defragBytesNotFreed.printCurrentVolume(); |
| Log.write(" fr: "); defragBytesFreed.printCurrentVolume(); |
| Log.write(" av: "); defragCleanBytesAvailable.printCurrentVolume(); |
| Log.write(")"); |
| } |
| |
| inDefragCollection = false; |
| debugCollectionTypeDetermined = false; |
| } |
| |
| void decideWhetherToDefrag(boolean emergencyCollection, boolean collectWholeHeap, int collectionAttempt, int collectionTrigger, boolean exhaustedReusableSpace) { |
| boolean userTriggered = collectionTrigger == Collection.EXTERNAL_GC_TRIGGER && Options.fullHeapSystemGC.getValue(); |
| inDefragCollection = (collectionAttempt > 1) || |
| emergencyCollection || |
| collectWholeHeap && (Options.defragStress.getValue() || userTriggered); |
| if (inDefragCollection) { |
| debugBytesDefraged = 0; |
| } |
| debugCollectionTypeDetermined = true; |
| } |
| |
| boolean determined(boolean inDefrag) { return debugCollectionTypeDetermined && !(inDefrag ^ inDefragCollection); } |
| |
| void getBlock() { |
| if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!inDefragCollection || !defragSpaceExhausted); |
| if (availableCleanPagesForDefrag <= 0) |
| defragSpaceExhausted = true; |
| availableCleanPagesForDefrag -= PAGES_IN_BLOCK; |
| debugBytesDefraged += BYTES_IN_BLOCK; |
| Defrag.defragCleanBytesUsed.inc(BYTES_IN_BLOCK); |
| } |
| |
| private void establishDefragSpillThreshold(ChunkList chunkMap, ImmixSpace space) { |
| int cleanLines = space.getAvailableLines(spillAvailHistogram); |
| int availableLines = cleanLines + availableCleanPagesForDefrag<<(LOG_BYTES_IN_PAGE - LOG_BYTES_IN_LINE); |
| |
| int requiredLines = 0; |
| short threshold = (short) MAX_CONSV_SPILL_COUNT; |
| int limit = (int) (availableLines / Options.defragLineReuseRatio.getValue()); |
| if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) { |
| Log.write("[threshold: "); Log.write("cl: "); Log.write(cleanLines); |
| Log.write(" al: "); Log.write(availableLines); |
| Log.write(" lm: "); Log.write(limit); |
| } |
| int collectors = VM.activePlan.collectorCount(); |
| for (short index = MAX_CONSV_SPILL_COUNT; index >= TMP_MIN_SPILL_THRESHOLD && limit > requiredLines; index--) { |
| threshold = (short) index; |
| int thisBucketMark = 0; |
| int thisBucketAvail = 0; |
| for (int c = 0; c < collectors; c++) thisBucketMark += spillMarkHistograms[c][threshold]; |
| |
| thisBucketAvail = spillAvailHistogram[threshold]; |
| limit -= thisBucketAvail; |
| requiredLines += thisBucketMark; |
| if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) { |
| Log.write(" ("); Log.write(index); Log.write(" "); Log.write(limit); Log.write(","); Log.write(requiredLines); Log.write(")"); |
| } |
| } |
| if (VM.VERIFY_ASSERTIONS && Options.verbose.getValue() > 2) { |
| Log.write(" threshold: "); Log.write(threshold); Log.write("]"); |
| } |
| defragSpillThreshold = threshold; |
| } |
| |
| |
| boolean spaceExhausted() { return defragSpaceExhausted; } |
| |
| int[] getAndZeroSpillMarkHistogram(int ordinal) { |
| int[] rtn = spillMarkHistograms[ordinal]; |
| for (int i = 0; i < SPILL_HISTOGRAM_BUCKETS; i++) |
| rtn[i] = 0; |
| return rtn; |
| } |
| } |