From: <jik...@li...> - 2013-05-01 22:46:13
|
details: http://hg.code.sourceforge.net/p/jikesrvm/code/rev/a02789db0330 changeset: 10629:a02789db0330 user: Steve Blackburn <Ste...@an...> date: Thu May 02 08:45:58 2013 +1000 description: RVM-1029 Implementation of abbreviated stack scanning, a concrete application of RVM-1006. Enable with -X:gc:useShortStackScans=true. diffstat: MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ScanThread.java | 51 ++++++++++---- MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Scanning.java | 42 +++++++----- MMTk/src/org/mmtk/plan/Plan.java | 1 + MMTk/src/org/mmtk/plan/Simple.java | 2 +- MMTk/src/org/mmtk/plan/generational/Gen.java | 6 + MMTk/src/org/mmtk/plan/generational/GenCollector.java | 5 +- MMTk/src/org/mmtk/utility/options/Options.java | 1 + MMTk/src/org/mmtk/utility/options/UseShortStackScans.java | 28 ++++++++ MMTk/src/org/mmtk/vm/Scanning.java | 28 +++++++- 9 files changed, 128 insertions(+), 36 deletions(-) diffs (truncated from 367 to 300 lines): diff --git a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ScanThread.java b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ScanThread.java --- a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ScanThread.java +++ b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ScanThread.java @@ -28,6 +28,7 @@ import org.jikesrvm.scheduler.RVMThread; import org.mmtk.plan.TraceLocal; import org.mmtk.utility.Log; +import org.mmtk.utility.options.Options; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.Untraced; @@ -116,6 +117,7 @@ private CompiledMethod compiledMethod; private int compiledMethodType; private boolean failed; + private boolean reinstallReturnBarrier; /*********************************************************************** * @@ -128,9 +130,10 @@ * @param thread The thread to be scanned * @param trace The trace instance to use for reporting references. * @param processCodeLocations Should code locations be processed? + * @param newRootsSufficient Is a partial stack scan sufficient, or must we do a full scan? */ public static void scanThread(RVMThread thread, TraceLocal trace, - boolean processCodeLocations) { + boolean processCodeLocations, boolean newRootsSufficient) { if (DEFAULT_VERBOSITY>=1) { VM.sysWriteln("scanning ",thread.getThreadSlot()); } @@ -144,7 +147,7 @@ regs.clear(); regs.setInnermost(ip,fp); - scanThread(thread, trace, processCodeLocations, gprs, Address.zero()); + scanThread(thread, trace, processCodeLocations, gprs, Address.zero(), newRootsSufficient); } /** @@ -168,10 +171,11 @@ * stack being scanned (normally extracted from the thread). * @param topFrame The top frame of the stack being scanned, or zero * if this is to be inferred from the thread (normally the case). + * @param newRootsSufficent Is a partial stack scan sufficient, or must we do a full scan? */ private static void scanThread(RVMThread thread, TraceLocal trace, boolean processCodeLocations, - Address gprs, Address topFrame) { + Address gprs, Address topFrame, boolean newRootsSufficent) { // figure out if the thread should be scanned at all; if not, exit if (thread.getExecStatus()==RVMThread.NEW || thread.getIsAboutToTerminate()) { return; @@ -191,8 +195,15 @@ /* Grab the ScanThread instance associated with this thread */ ScanThread scanner = RVMThread.getCurrentThread().getCollectorThread().getThreadScanner(); + /* Expicitly establish the stopping point for this scan (not necessarily the bottom of stack) */ + Address sentinalFp = newRootsSufficent && Options.useShortStackScans.getValue() ? thread.getNextUnencounteredFrame() : ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP; + + /* stack trampoline will be freshly reinstalled at end of thread scan */ + if (Options.useReturnBarrier.getValue() || Options.useShortStackScans.getValue()) + thread.deInstallStackTrampoline(); + /* scan the stack */ - scanner.startScan(trace, processCodeLocations, thread, gprs, ip, fp, initialIPLoc, topFrame); + scanner.startScan(trace, processCodeLocations, thread, gprs, ip, fp, initialIPLoc, topFrame, sentinalFp); } /** @@ -213,11 +224,13 @@ * we're about to scan. * @param fp The frame pointer for the top frame of the stack we're * about to scan. + * @param sentinelFp The frame pointer at which the stack scan should stop. */ private void startScan(TraceLocal trace, boolean processCodeLocations, RVMThread thread, Address gprs, Address ip, - Address fp, Address initialIPLoc, Address topFrame) { + Address fp, Address initialIPLoc, Address topFrame, + Address sentinelFp) { this.trace = trace; this.processCodeLocations = processCodeLocations; this.thread = thread; @@ -226,13 +239,13 @@ this.fp = fp; this.initialIPLoc = initialIPLoc; this.topFrame = topFrame; - scanThreadInternal(gprs, DEFAULT_VERBOSITY); + scanThreadInternal(gprs, DEFAULT_VERBOSITY, sentinelFp); if (failed) { - /* reinitialize and rescan verbosly on failure */ + /* reinitialize and rescan verbosely on failure */ this.ip = ip; this.fp = fp; this.topFrame = topFrame; - scanThreadInternal(gprs, FAILURE_VERBOSITY); + scanThreadInternal(gprs, FAILURE_VERBOSITY, sentinelFp); VM.sysFail("Error encountered while scanning stack"); } } @@ -247,7 +260,7 @@ * @param verbosity The level of verbosity to be used when * performing the scan. */ - private void scanThreadInternal(Address gprs, int verbosity) { + private void scanThreadInternal(Address gprs, int verbosity, Address sentinelFp) { if (false) { VM.sysWriteln("Scanning thread ",thread.getThreadSlot()," from thread ",RVMThread.getCurrentThreadSlot()); } @@ -269,10 +282,11 @@ /* scan each frame if a non-empty stack */ if (fp.NE(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) { prevFp = Address.zero(); + reinstallReturnBarrier = Options.useReturnBarrier.getValue() || Options.useShortStackScans.getValue(); /* At start of loop: fp -> frame for method invocation being processed ip -> instruction pointer in the method (normally a call site) */ - while (Magic.getCallerFramePointer(fp).NE(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) { + while (Magic.getCallerFramePointer(fp).NE(sentinelFp)) { if (false) { VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," at fp = ",fp); } @@ -375,11 +389,18 @@ iterator.cleanupPointers(); - /* skip preceeding native frames if this frame is a native bridge */ - if (compiledMethodType != CompiledMethod.TRAP && - compiledMethod.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { - fp = RuntimeEntrypoints.unwindNativeStackFrameForGC(fp); - if (verbosity >= 2) Log.write("scanFrame skipping native C frames\n"); + if (compiledMethodType != CompiledMethod.TRAP) { + /* skip preceding native frames if this frame is a native bridge */ + if (compiledMethod.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { + fp = RuntimeEntrypoints.unwindNativeStackFrameForGC(fp); + if (verbosity >= 2) Log.write("scanFrame skipping native C frames\n"); + } + + /* reinstall the return barrier if necessary (and verbosity indicates that this is a regular scan) */ + if (reinstallReturnBarrier && verbosity == DEFAULT_VERBOSITY) { + thread.installStackTrampolineBridge(fp); + reinstallReturnBarrier = false; + } } return fp; } diff --git a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Scanning.java b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Scanning.java --- a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Scanning.java +++ b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Scanning.java @@ -79,8 +79,9 @@ } @Override - public void notifyInitialThreadScanComplete() { - CompiledMethods.snipObsoleteCompiledMethods(); + public void notifyInitialThreadScanComplete(boolean partialScan) { + if (!partialScan) + CompiledMethods.snipObsoleteCompiledMethods(); /* flush out any remset entries generated during the above activities */ Selected.Mutator.get().flushRememberedSets(); } @@ -152,23 +153,30 @@ } /** - * Computes roots pointed to by threads, their associated registers - * and stacks. This method places these roots in the root values, - * root locations and interior root locations queues. This method - * should not have side effects (such as copying or forwarding of - * objects). There are a number of important preconditions: - * - * <ul> - * <li> The <code>threadCounter</code> must be reset so that load - * balancing parallel GC can share the work of scanning threads. - * </ul> - * - * TODO try to rewrite using chunking to avoid the per-thread synchronization? - * - * @param trace The trace to use for computing roots. + * {@inheritDoc} */ @Override public void computeThreadRoots(TraceLocal trace) { + computeThreadRoots(trace, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void computeNewThreadRoots(TraceLocal trace) { + computeThreadRoots(trace, true); + } + + /** + * Compute roots pointed to by threads. + * + * @param trace The trace to use for computing roots. + * @param newRootsSufficient True if it sufficient for this method to only + * compute those roots that are new since the previous stack scan. If false + * then all roots must be computed (both new and preexisting). + */ + private void computeThreadRoots(TraceLocal trace, boolean newRootsSufficient) { boolean processCodeLocations = MemoryManagerConstants.MOVES_CODE; /* scan all threads */ @@ -180,7 +188,7 @@ if (thread == null || thread.isCollectorThread()) continue; /* scan the thread (stack etc.) */ - ScanThread.scanThread(thread, trace, processCodeLocations); + ScanThread.scanThread(thread, trace, processCodeLocations, newRootsSufficient); } /* flush out any remset entries generated during the above activities */ diff --git a/MMTk/src/org/mmtk/plan/Plan.java b/MMTk/src/org/mmtk/plan/Plan.java --- a/MMTk/src/org/mmtk/plan/Plan.java +++ b/MMTk/src/org/mmtk/plan/Plan.java @@ -175,6 +175,7 @@ Options.debugAddress = new DebugAddress(); Options.perfEvents = new PerfEvents(); Options.useReturnBarrier = new UseReturnBarrier(); + Options.useShortStackScans = new UseShortStackScans(); Options.threads = new Threads(); Options.cycleTriggerThreshold = new CycleTriggerThreshold(); Map.finalizeStaticSpaceMap(); diff --git a/MMTk/src/org/mmtk/plan/Simple.java b/MMTk/src/org/mmtk/plan/Simple.java --- a/MMTk/src/org/mmtk/plan/Simple.java +++ b/MMTk/src/org/mmtk/plan/Simple.java @@ -224,7 +224,7 @@ } if (phaseId == STACK_ROOTS) { - VM.scanning.notifyInitialThreadScanComplete(); + VM.scanning.notifyInitialThreadScanComplete(false); setGCStatus(GC_PROPER); return; } diff --git a/MMTk/src/org/mmtk/plan/generational/Gen.java b/MMTk/src/org/mmtk/plan/generational/Gen.java --- a/MMTk/src/org/mmtk/plan/generational/Gen.java +++ b/MMTk/src/org/mmtk/plan/generational/Gen.java @@ -188,6 +188,12 @@ return; } + if (phaseId == STACK_ROOTS) { + VM.scanning.notifyInitialThreadScanComplete(!traceFullHeap()); + setGCStatus(GC_PROPER); + return; + } + if (phaseId == CLOSURE) { if (!traceFullHeap()) { nurseryTrace.prepare(); diff --git a/MMTk/src/org/mmtk/plan/generational/GenCollector.java b/MMTk/src/org/mmtk/plan/generational/GenCollector.java --- a/MMTk/src/org/mmtk/plan/generational/GenCollector.java +++ b/MMTk/src/org/mmtk/plan/generational/GenCollector.java @@ -93,7 +93,10 @@ nurseryTrace.prepare(); return; } - + if (phaseId == Simple.STACK_ROOTS && !global().gcFullHeap) { + VM.scanning.computeNewThreadRoots(getCurrentTrace()); + return; + } if (phaseId == StopTheWorld.ROOTS) { VM.scanning.computeGlobalRoots(getCurrentTrace()); if (!Gen.USE_NON_HEAP_OBJECT_REFERENCE_WRITE_BARRIER || global().traceFullHeap()) { diff --git a/MMTk/src/org/mmtk/utility/options/Options.java b/MMTk/src/org/mmtk/utility/options/Options.java --- a/MMTk/src/org/mmtk/utility/options/Options.java +++ b/MMTk/src/org/mmtk/utility/options/Options.java @@ -61,6 +61,7 @@ public static Threads threads; public static TraceRate traceRate; public static UseReturnBarrier useReturnBarrier; + public static UseShortStackScans useShortStackScans; public static VariableSizeHeap variableSizeHeap; public static VerboseFragmentationStats verboseFragmentationStats; public static Verbose verbose; diff --git a/MMTk/src/org/mmtk/utility/options/UseShortStackScans.java b/MMTk/src/org/mmtk/utility/options/UseShortStackScans.java new file mode 100644 --- /dev/null +++ b/MMTk/src/org/mmtk/utility/options/UseShortStackScans.java @@ -0,0 +1,28 @@ +/* + * 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.utility.options; |