| /* |
| * 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.plan.semispace.gcspy; |
| |
| import org.mmtk.plan.Phase; |
| import org.mmtk.plan.semispace.SS; |
| import org.mmtk.plan.semispace.SSCollector; |
| import org.mmtk.policy.CopySpace; |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.gcspy.GCspy; |
| import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver; |
| import org.mmtk.vm.VM; |
| |
| import org.vmmagic.unboxed.*; |
| import org.vmmagic.pragma.*; |
| |
| /** |
| * This class implements <i>per-collector thread</i> behavior and state for the |
| * <i>SSGCspy</i> plan.<p> |
| * |
| * See {@link SSGCspy} for an overview of the GC-spy mechanisms.<p> |
| * |
| * @see SSCollector |
| * @see SSGCspy |
| * @see SSGCspyMutator |
| * @see org.mmtk.plan.StopTheWorldCollector |
| * @see org.mmtk.plan.CollectorContext |
| * @see org.mmtk.plan.SimplePhase |
| */ |
| @Uninterruptible public class SSGCspyCollector extends SSCollector { |
| |
| /**************************************************************************** |
| * |
| * Initialization |
| */ |
| |
| /***************************************************************************** |
| * Instance fields |
| */ |
| |
| private static final boolean DEBUG = false; |
| |
| /** |
| * Constructor |
| */ |
| public SSGCspyCollector() { |
| super(new SSGCspyTraceLocal(global().ssTrace)); |
| } |
| |
| |
| /**************************************************************************** |
| * |
| * Data gathering |
| */ |
| |
| /** |
| * Perform a (local) collection phase. |
| * Before a collection, we need to discover |
| * <ul> |
| * <li>the tospace objects copied by the collector in the last GC cycle |
| * <li>the semispace objects allocated since by the mutator. |
| * <li>all immortal objects allocated by the mutator |
| * <li>all large objects allocated by the mutator |
| * </ul> |
| * After the semispace has been copied, we need to discover |
| * <ul> |
| * <li>the tospace objects copied by the collector |
| * <li>all immortal objects allocated by the mutator |
| * <li>all large objects allocated by the mutator |
| * </ul> |
| */ |
| @Inline |
| public final void collectionPhase(short phaseId, boolean primary) { |
| if (DEBUG) { Log.write("--Phase Collector."); Log.writeln(Phase.getName(phaseId)); } |
| |
| //TODO do we need to worry any longer about primary?? |
| if (phaseId == SS.PREPARE) { |
| //if (primary) |
| gcspyGatherData(SSGCspy.BEFORE_COLLECTION); |
| super.collectionPhase(phaseId, primary); |
| return; |
| } |
| |
| if (phaseId == SS.FORWARD_FINALIZABLE) { |
| super.collectionPhase(phaseId, primary); |
| //if (primary) |
| gcspyGatherData(SSGCspy.SEMISPACE_COPIED); |
| return; |
| } |
| |
| if (phaseId == SS.RELEASE) { |
| //if (primary) |
| //gcspyGatherData(SSGCspy.SEMISPACE_COPIED); |
| super.collectionPhase(phaseId, primary); |
| //if (primary) |
| gcspyGatherData(SSGCspy.AFTER_COLLECTION); |
| return; |
| } |
| |
| super.collectionPhase(phaseId, primary); |
| } |
| |
| /** |
| * Gather data for GCspy for the semispaces only. |
| * <p> |
| * This method sweeps the semispace under consideration to gather data. |
| * Alternatively and more efficiently, 'used space' can obviously be |
| * discovered in constant time simply by comparing the start and the end |
| * addresses of the semispace. However, per-object information can only be |
| * gathered by sweeping through the space and we do this here for tutorial |
| * purposes. |
| * |
| * @param event |
| * The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or |
| * AFTER_COLLECTION |
| */ |
| private void gcspyGatherData(int event) { |
| if(DEBUG) { |
| Log.writeln("SSGCspyCollector.gcspyGatherData, event=", event); |
| Log.writeln("SSGCspyCollector.gcspyGatherData, port=", GCspy.getGCspyPort()); |
| } |
| |
| // If port = 0 there can be no GCspy client connected |
| if (GCspy.getGCspyPort() == 0) |
| return; |
| |
| // If the server is connected to a client that is interested in this |
| // event, then we gather data. But first we start a timer to |
| // compensate for the time spent gathering data here. |
| if (GCspy.server.isConnected(event)) { |
| |
| if (DEBUG) { |
| if (SSGCspy.hi) |
| Log.write("\nCollector Examining Lowspace (event ", event); |
| else |
| Log.write("\nCollector Examining Highspace (event ", event); |
| Log.write(")"); |
| SSGCspy.reportSpaces(); Log.writeln(); |
| } |
| |
| if (event == SSGCspy.BEFORE_COLLECTION) { |
| if (DEBUG) debugSpaces(SSGCspy.fromSpace()); |
| |
| // Just send the old values again |
| if (DEBUG) { |
| Log.write("SSGCspyCollector.gcspyGatherData transmit driver, "); |
| Log.writeln(SSGCspy.fromSpace().getName()); |
| } |
| |
| fromSpaceDriver().transmit(event); |
| // Mutator.gcspyGatherData follows so leave safepoint to there. |
| } else if (event == SSGCspy.SEMISPACE_COPIED) { |
| if (DEBUG) debugSpaces(SSGCspy.toSpace()); |
| |
| // We need to reset, scan and send values for tospace |
| // We'll leave resetting fromspace to AFTER_COLLECTION |
| if (DEBUG) { |
| Log.write("SSGCspyCollector.gcspyGatherData reset, gather and transmit driver "); |
| Log.writeln(SSGCspy.toSpace().getName()); |
| } |
| |
| GCspy.server.startCompensationTimer(); |
| toSpaceDriver().resetData(); |
| ss.gcspyGatherData(toSpaceDriver(), SSGCspy.toSpace()); |
| GCspy.server.stopCompensationTimer(); |
| toSpaceDriver().transmit(event); |
| |
| // We'll leave the safepoint to RELEASE |
| } else if (event == SSGCspy.AFTER_COLLECTION) { |
| if (DEBUG) { |
| Log.write("SSGCspyCollector.gcspyGatherData transmit toSpaceDriver, "); |
| Log.writeln(SSGCspy.toSpace().getName()); |
| Log.write("SSGCspyCollector.gcspyGatherData reset fromSpaceDriver, "); |
| Log.writeln(SSGCspy.fromSpace().getName()); |
| } |
| |
| toSpaceDriver().transmit(event); |
| |
| // Here we reset fromspace data |
| fromSpaceDriver().resetData(); |
| Address start = SSGCspy.fromSpace().getStart(); |
| fromSpaceDriver().setRange(start, start); |
| fromSpaceDriver().transmit(event); |
| } |
| |
| } |
| // else Log.write("not transmitting..."); |
| } |
| |
| /** |
| * Print some debugging info |
| * @param scannedSpace |
| */ |
| private void debugSpaces(CopySpace scannedSpace) { |
| Log.write("SSGCspyCollector.gcspyGatherData: gather data for active semispace "); |
| Log.write(scannedSpace.getStart()); Log.write("-",ss.getCursor()); Log.flush(); |
| Log.write(". The space is: "); Log.writeln(ss.getSpace().getName()); |
| Log.write("scannedSpace is "); Log.writeln(scannedSpace.getName()); |
| Log.write("The range is "); Log.write(ss.getSpace().getStart()); |
| Log.write(" to "); Log.writeln(ss.getCursor()); |
| SSGCspy.reportSpaces(); |
| } |
| |
| /** |
| * Reset all root streams.<p> |
| */ |
| void resetRootStreams() { |
| SSGCspy.ss0Driver.resetRootsStream(); |
| SSGCspy.ss1Driver.resetRootsStream(); |
| SSGCspy.immortalDriver.resetRootsStream(); |
| SSGCspy.losNurseryDriver.resetRootsStream(); |
| SSGCspy.losDriver.resetRootsStream(); |
| SSGCspy.plosNurseryDriver.resetRootsStream(); |
| SSGCspy.plosDriver.resetRootsStream(); |
| ss.getCursor(); |
| } |
| |
| /** |
| * Pass a root to all drivers.<p> |
| * @param addr The Address of the object to be checked |
| */ |
| protected void checkAllDriversForRootAddress(Address addr) { |
| if(addr.isZero()) |
| return; |
| |
| SSGCspy.ss0Driver.handleRoot(addr); |
| SSGCspy.ss1Driver.handleRoot(addr); |
| SSGCspy.immortalDriver.handleRoot(addr); |
| SSGCspy.losNurseryDriver.handleRoot(addr); |
| SSGCspy.losDriver.handleRoot(addr); |
| SSGCspy.plosNurseryDriver.handleRoot(addr); |
| SSGCspy.plosDriver.handleRoot(addr); |
| } |
| |
| /**************************************************************************** |
| * |
| * Miscellaneous |
| */ |
| |
| /** @return The active global plan as an <code>SSGCspy</code> instance. */ |
| @Inline |
| private static SSGCspy global() { |
| return (SSGCspy) VM.activePlan.global(); |
| } |
| |
| /** @return the driver for toSpace */ |
| private LinearSpaceDriver toSpaceDriver() { |
| return SSGCspy.hi ? SSGCspy.ss1Driver : SSGCspy.ss0Driver; |
| } |
| |
| /** @return the driver for fromSpace */ |
| private LinearSpaceDriver fromSpaceDriver() { |
| return SSGCspy.hi ? SSGCspy.ss0Driver : SSGCspy.ss1Driver; |
| } |
| } |