/* * 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; } }