blob: 78c89c13c7597b0f69e38a808059300916e5a141 [file] [log] [blame]
/*
* 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.GCspyPlan;
import org.mmtk.plan.Phase;
import org.mmtk.plan.TransitiveClosure;
import org.mmtk.plan.semispace.SS;
import org.mmtk.policy.CopySpace;
import org.mmtk.policy.LargeObjectSpace;
import org.mmtk.utility.gcspy.drivers.AbstractDriver;
import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
import org.mmtk.utility.gcspy.drivers.ImmortalSpaceDriver;
import org.mmtk.utility.gcspy.drivers.TreadmillDriver;
import org.mmtk.utility.gcspy.GCspy;
import org.mmtk.utility.Log;
import org.mmtk.utility.options.Options;
import org.vmmagic.pragma.*;
/**
* This class extends a simple semi-space collector to instrument it for
* GCspy. <p>
*
* See the Jones & Lins GC book, section 2.2 for an overview of the basic
* algorithm. This implementation also includes a large object space
* (LOS), and an uncollected "immortal" space.<p>
*
* All plans make a clear distinction between <i>global</i> and
* <i>thread-local</i> activities. Global activities must be
* synchronized, whereas no synchronization is required for
* thread-local activities. Instances of Plan map 1:1 to "kernel
* threads" (aka CPUs). Thus instance
* methods allow fast, unsychronized access to Plan utilities such as
* allocation and collection. Each instance rests on static resources
* (such as memory and virtual memory resources) which are "global"
* and therefore "static" members of Plan. This mapping of threads to
* instances is crucial to understanding the correctness and
* performance proprties of this plan.
*
* FIXME This seems to have changed
* The order of phases and GCspy actions is important here. It is:
* PREPARE phase
* SSGCspyMutator.gcspyGatherData(SSGCspy.BEFORE_COLLECTION); // safepoint
* SSMutator.PREPARE // FIXME DOES NOT ss.rebind(SS.toSpace());
*
* PREPARE phase
* SS.PREPARE // flip semispaces
* gcspySpace.prepare();
* SSGCspyCollector.gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
* SSCollector.PREPARE // ss.rebind(SS.toSpace());
*
*
* FORWARD_FINALIZABLE phase
* SSCollector.FORWARD_FINALIZABLE
* SSGCspyCollector.gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
*
* RELEASE phase
* SSGCspyMutator.gcspyGatherData(SSGCspy.SEMISPACE_COPIED); // safepoint
* SSMutator.RELEASE // FIXME ss.rebind(SS.toSpace());
* SSGCspyMutator.gcspyGatherData(SSGCspy.AFTER_COLLECTION);
*
* RELEASE phase
* SSCollector.RELEASE
* SSGCspyCollector.gcspyGatherData(SSGCspy.AFTER_COLLECTION);
* SS.RELEASE
* gcspySpace.release();
* SSGCspy.gcspyGatherData(); // safepoint
*
* Note that SSMutator has changed the point at which it rebinds toSpace
* from PREPARE (2.4.6) to after RELEASE (3.x.x).
*
--Phase Collector.initiate
--Phase Mutator.initiate-mutator
--Phase Mutator.prepare-mutator
SSGCspyMutator.gcspyGatherData, event=0
--Phase Plan.prepare
--Phase Collector.prepare
SSGCspyCollector.gcspyGatherData, event=0
--Phase Collector.precopy
--Phase Collector.bootimage-root
--Phase Collector.root
--Phase Plan.root
--Phase Collector.start-closure
--Phase Collector.soft-ref
--Phase Collector.complete-closure
--Phase Collector.weak-ref
--Phase Collector.finalize
--Phase Collector.complete-closure
--Phase Collector.phantom-ref
--Phase Collector.forward-ref
--Phase Collector.forward-finalize
SSGCspyCollector.gcspyGatherData, event=1
--Phase Mutator.release-mutator
SSGCspyMutator.gcspyGatherData, event=1
SSGCspyMutator.gcspyGatherData, event=2
--Phase Collector.release
SSGCspyCollector.gcspyGatherData, event=2
--Phase Plan.release
SSGCspy.gcspyGatherData, event=2
--Phase Collector.complete
--Phase Plan.complete
*/
@Uninterruptible public class SSGCspy extends SS implements GCspyPlan {
/****************************************************************************
*
* Class variables
*/
// The events, BEFORE_COLLECTION, SEMISPACE_COPIED or AFTER_COLLECTION
/**
* Before a collection has started,
* i.e. before SS.collectionPhase(SS.PREPARE,..).
*/
static final int BEFORE_COLLECTION = 0;
/**
* After the semispace has been copied and the large object space has been traced
* At this time the Large Object Space has not been swept.
*/
static final int SEMISPACE_COPIED = BEFORE_COLLECTION + 1;
/**
* The collection is complete,
* i.e. immediately after SS.collectionPhase(SS.RELEASE,..).
* The Large Object Space has been swept.
*/
static final int AFTER_COLLECTION = SEMISPACE_COPIED + 1;
static int gcspyEvent_ = BEFORE_COLLECTION;
// The specific drivers for this collector
static LinearSpaceDriver ss0Driver;
static LinearSpaceDriver ss1Driver;
static ImmortalSpaceDriver immortalDriver;
static TreadmillDriver losNurseryDriver;
static TreadmillDriver losDriver;
static TreadmillDriver plosNurseryDriver;
static TreadmillDriver plosDriver;
private static final boolean DEBUG = false;
static {
GCspy.createOptions();
}
/**
* Start the server and wait if necessary.
* This method has the following responsibilities.
* <ol>
* <li> Create and initialise the GCspy server by calling.
* <pre>server = ServerInterpreter.init(name, portNumber, verbose);</pre>
* <li> Add each event to the ServerInterpreter
* <pre>server.addEvent(eventID, eventName);</pre>
* <li> Set some general information about the server (e.g. name of the collector, build, etc).
* <pre>server.setGeneralInfo(info); </pre>
* <li> Create new drivers for each component to be visualised.
* <pre>myDriver = new MyDriver(server, args...);</pre>
* Drivers extend AbstractDriver and register their spce with the
* ServerInterpreter. In addition to the server, drivers will take as
* arguments the name of the space, the MMTk space, the tilesize, and
* whether this space is to be the main space in the visualiser.
* </ol>
*
* WARNING: allocates memory.
* @param wait Whether to wait
* @param port The port to talk to the GCspy client (e.g. visualiser)
*/
@Interruptible
public final void startGCspyServer(int port, boolean wait) {
GCspy.server.init("SemiSpaceServerInterpreter", port, true/*verbose*/);
if (DEBUG) Log.writeln("SSGCspy: ServerInterpreter initialised");
GCspy.server.addEvent(BEFORE_COLLECTION, "Before collection");
GCspy.server.addEvent(SEMISPACE_COPIED, "Semispace copied; LOS traced");
GCspy.server.addEvent(AFTER_COLLECTION, "After collection; LOS swept");
GCspy.server.setGeneralInfo(
"SSGCspy\n\nRichard Jones, October 2006\\http://www.cs.kent.ac.uk/~rej/");
if (DEBUG) Log.writeln("SSGCspy: events added to ServerInterpreter");
// Initialise each driver
ss0Driver = newLinearSpaceDriver("Semispace 0 Space", copySpace0, true);
ss1Driver = newLinearSpaceDriver("Semispace 1 Space", copySpace1, false);
immortalDriver = new ImmortalSpaceDriver(
GCspy.server, "Immortal Space", immortalSpace,
Options.gcspyTileSize.getValue(), false);
losNurseryDriver = newTreadmillDriver("LOS Nursery", loSpace);
losDriver = newTreadmillDriver("LOS", loSpace);
if (DEBUG) Log.write("SemiServerInterpreter initialised\n");
// Register drivers to allow immortal space to notify direct references
immortalDriver.registerDriversForReferenceNotification(
new AbstractDriver[] {ss0Driver, ss1Driver, immortalDriver,
losNurseryDriver, losDriver,
plosNurseryDriver, plosDriver});
if (DEBUG) Log.writeln("SSGCspy: registered drivers");
gcspyEvent_ = BEFORE_COLLECTION;
// Start the server
GCspy.server.startServer(wait);
}
/**
* Create a new LinearSpaceDriver
* TODO is this the best name or should we call it LargeObjectSpaceDriver?
* @param name Name of the space
* @param space The space
* @return A new GCspy driver for this space
*/
@Interruptible
private LinearSpaceDriver newLinearSpaceDriver(String name, CopySpace space, boolean mainSpace) {
// TODO What if tileSize is too small (i.e. too many tiles for GCspy buffer)
// TODO stop the GCspy spaces in the visualiser from fluctuating in size
// so much as we resize them.
return new LinearSpaceDriver(GCspy.server, name, space,
Options.gcspyTileSize.getValue(), mainSpace);
}
/**
* Create a new TreadmillDriver
* TODO is this the best name or should we call it LargeObjectSpaceDriver?
* @param name Name of the space
* @param space The space
* @return A new GCspy driver for this space
*/
@Interruptible
private TreadmillDriver newTreadmillDriver(String name, LargeObjectSpace space) {
return new TreadmillDriver(GCspy.server, name, space,
Options.gcspyTileSize.getValue(), MAX_NON_LOS_COPY_BYTES, false);
}
/****************************************************************************
*
* Collection
*/
/**
* Perform a (global) collection phase.
*
* @param phaseId Collection phase
*/
@Inline
public void collectionPhase(short phaseId) {
if (DEBUG) { Log.write("--Phase Plan."); Log.writeln(Phase.getName(phaseId)); }
if (phaseId == SSGCspy.PREPARE) {
super.collectionPhase(phaseId);
gcspySpace.prepare();
return;
}
if (phaseId == SSGCspy.RELEASE) {
super.collectionPhase(phaseId);
gcspySpace.release();
//if (primary)
gcspyGatherData(SSGCspy.AFTER_COLLECTION);
return;
}
super.collectionPhase(phaseId);
}
/**
* Gather data for GCspy for the semispaces, the immortal space and the large
* object space.
* <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("SSGCspy.gcspyGatherData, event=", event);
Log.writeln("SSGCspy.gcspyGatherData, port=", GCspy.getGCspyPort());
}
// If port = 0 there can be no GCspy client connected
if (GCspy.getGCspyPort() == 0)
return;
// This is a safepoint for the server, i.e. it is a point at which
// the server can pause.
// The Mutator is called after the Collector so the Mutator must set the safepoint
if(DEBUG) Log.writeln("SSGCspy safepoint");
GCspy.server.serverSafepoint(event);
}
/****************************************************************************
*
* Accounting
*/
/**
* Return the number of pages reserved for use given the pending
* allocation. This is <i>exclusive of</i> space reserved for
* copying.
*
* @return The number of pages reserved given the pending
* allocation, excluding space reserved for copying.
*/
public final int getPagesUsed() {
return super.getPagesUsed() + gcspySpace.reservedPages();
}
/**
* Report information on the semispaces
*/
static void reportSpaces() {
Log.write("\n Low semispace: ");
Log.write(SSGCspy.copySpace0.getStart());
Log.write(" - ");
Log.write(SSGCspy.copySpace0.getStart()
.plus(SSGCspy.copySpace0.getExtent()));
Log.write("\n High semispace: ");
Log.write(SSGCspy.copySpace1.getStart());
Log.write(" - ");
Log.write(SSGCspy.copySpace1.getStart()
.plus(SSGCspy.copySpace1.getExtent()));
Log.flush();
}
/**
* Register specialized methods.
*/
@Interruptible
protected void registerSpecializedMethods() {
super.registerSpecializedMethods();
TransitiveClosure.registerSpecializedScan(SCAN_SS, SSGCspyTraceLocal.class);
}
}