/* * 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.gcspy.drivers; import org.mmtk.policy.LargeObjectSpace; import org.mmtk.utility.gcspy.Color; import org.mmtk.utility.gcspy.StreamConstants; import org.mmtk.utility.gcspy.Subspace; import org.mmtk.vm.gcspy.IntStream; import org.mmtk.vm.gcspy.ShortStream; import org.mmtk.vm.gcspy.ServerInterpreter; import org.mmtk.utility.Conversions; import org.mmtk.utility.Log; import org.mmtk.vm.VM; import org.vmmagic.unboxed.*; import org.vmmagic.pragma.*; /** * This class implements a simple driver for the MMTk LargeObjectSpace. */ @Uninterruptible public class TreadmillDriver extends AbstractDriver { private static final boolean DEBUG = false; // The streams protected IntStream usedSpaceStream; protected ShortStream objectsStream; protected ShortStream rootsStream; protected ShortStream refFromImmortalStream; protected Subspace subspace; // A single subspace for this space protected int allTileNum; // total number of tiles // Overall statistics protected int totalObjects = 0; // total number of objects allocated protected int totalUsedSpace = 0; // total space used protected int totalRoots = 0; // total of roots protected int totalRefFromImmortal = 0; // total direct references from the immortal space protected Address maxAddr; // the largest address seen protected int threshold; /** * Create a new driver for this collector * * @param server The name of the GCspy server that owns this space * @param spaceName The name of this driver * @param lospace the large object space for this allocator * @param blockSize The tile size * @param threshold the size threshold of the LOS * @param mainSpace Is this the main space? */ public TreadmillDriver( ServerInterpreter server, String spaceName, LargeObjectSpace lospace, int blockSize, int threshold, boolean mainSpace) { //TODO blocksize should be a multiple of treadmill granularity super(server, spaceName, lospace, blockSize, mainSpace); if (DEBUG) { Log.write("TreadmillDriver for "); Log.write(spaceName); Log.write(", blocksize="); Log.write(blockSize); Log.write(", start="); Log.write(lospace.getStart()); Log.write(", extent="); Log.write(lospace.getExtent()); Log.write(", maxTileNum="); Log.writeln(maxTileNum); } this.threshold = threshold; // Initialise a subspace and 2 Streams subspace = createSubspace(lospace); allTileNum = 0; maxAddr = lospace.getStart(); usedSpaceStream = createUsedSpaceStream(); objectsStream = createObjectsStream(); rootsStream = createRootsStream(); refFromImmortalStream = createRefFromImmortalStream(); serverSpace.resize(0); // the collector must call resize() before gathering data // Initialise the statistics resetData(); } /** * Get the name of this driver type. * @return The name, "MMTk TreadmillDriver" for this driver. */ protected String getDriverName() { return "MMTk TreadmillDriver"; } // private creator methods for the streams @Interruptible private IntStream createUsedSpaceStream() { return VM.newGCspyIntStream( this, "Used Space stream", // stream name 0, // min. data value blockSize, // max. data value 0, // zero value 0, // default value "Space used: ", // value prefix " bytes", // value suffix StreamConstants.PRESENTATION_PERCENT, // presentation style StreamConstants.PAINT_STYLE_ZERO, // paint style 0, // index of the max stream (only needed if presentation is *_VAR) Color.Red, // tile colour true); // summary enabled } @Interruptible private ShortStream createObjectsStream() { return VM.newGCspyShortStream( this, "Objects stream", (short)0, (short)(blockSize/threshold), (short)0, (short)0, "No. of objects = ", " objects", StreamConstants.PRESENTATION_PLUS, StreamConstants.PAINT_STYLE_ZERO, 0, Color.Green, true); } @Interruptible private ShortStream createRootsStream() { return VM.newGCspyShortStream( this, "Roots stream", (short)0, // Say, typical size = 4 * typical scalar size? (short)(maxObjectsPerBlock(blockSize)/8), (short)0, (short)0, "Roots: ", " objects", StreamConstants.PRESENTATION_PLUS, StreamConstants.PAINT_STYLE_ZERO, 0, Color.Blue, true); } @Interruptible private ShortStream createRefFromImmortalStream() { return VM.newGCspyShortStream( this, "References from Immortal stream", (short)0, // Say, typical size = 4 * typical scalar size? (short)(maxObjectsPerBlock(blockSize)/8), (short)0, (short)0, "References from immortal space: ", " references", StreamConstants.PRESENTATION_PLUS, StreamConstants.PAINT_STYLE_ZERO, 0, Color.Blue, true); } /** * Reset the tile stats for all streams, including values used for summaries */ public void resetData() { super.resetData(); // Reset all the streams usedSpaceStream.resetData(); objectsStream.resetData(); refFromImmortalStream.resetData(); // Reset the summary counts totalUsedSpace = 0; totalObjects = 0; totalRefFromImmortal = 0; } /** * Update the tile statistics * In this case, we are accounting for super-page objects, rather than * simply for the objects they contain. * * @param addr The address of the superpage */ public void scan(Address addr) { int index = subspace.getIndex(addr); int length = ((LargeObjectSpace)mmtkSpace).getSize(addr).toInt(); if (DEBUG) { Log.write("TreadmillDriver: super=", addr); Log.write(", index=", index); Log.write(", pages=", length); Log.write(", bytes=", Conversions.pagesToBytes(length).toInt()); Log.writeln(", max=", usedSpaceStream.getMaxValue()); } totalObjects++; totalUsedSpace += length; objectsStream.increment(index, (short)1); int remainder = subspace.spaceRemaining(addr); usedSpaceStream.distribute(index, remainder, blockSize, length); Address tmp = addr.plus(length); if (tmp.GT(maxAddr)) maxAddr = tmp; } /** * Transmit the data if this event is of interest to the client * @param event The event, either BEFORE_COLLECTION, SEMISPACE_COPIED * or AFTER_COLLECTION */ public void transmit(int event) { if (!isConnected(event)) return; // At this point, we've filled the tiles with data, // however, we don't know the size of the space // Calculate the highest indexed tile used so far, and update the subspace Address start = subspace.getStart(); int required = countTileNum(start, maxAddr, blockSize); int current = subspace.getBlockNum(); if (required > current || maxAddr != subspace.getEnd()) { subspace.reset(start, maxAddr, 0, required); allTileNum = required; serverSpace.resize(allTileNum); setTilenames(subspace, allTileNum); } // Set the summaries setupSummaries(); // set the control info: all of space is USED controlValues(CONTROL_USED, subspace.getFirstIndex(), subspace.getBlockNum()); // send the space info Offset size = subspace.getEnd().diff(subspace.getStart()); setSpaceInfo(size); // Send the streams send(event, allTileNum); } /** * Setup summaries part of the <code>transmit</code> method.<p> * Override this method to setup summaries of additional streams in subclasses. */ protected void setupSummaries() { usedSpaceStream.setSummary(totalUsedSpace, subspace.getEnd().diff(subspace.getStart()).toInt()); objectsStream.setSummary(totalObjects); rootsStream.setSummary(totalRoots); refFromImmortalStream.setSummary(totalRefFromImmortal); } /** * Handle a root address * * @param addr Root Address * @return true if the given Address is in this subspace. */ public boolean handleRoot(Address addr) { if(subspace.addressInRange(addr)) { // increment tile int index = subspace.getIndex(addr); rootsStream.increment(index, (short)1); // increment summary this.totalRoots++; return true; } else { return false; } } /** * Reset the roots Stream. <br> * The roots Stream has to be reset seperately because we do not * gather data in the usual way using <code>scan()</code>. */ public void resetRootsStream() { rootsStream.resetData(); totalRoots = 0; } /** * Handle a direct reference from the immortal space. * * @param addr The Address * @return true if the given Address is in this subspace. */ public boolean handleReferenceFromImmortalSpace(Address addr) { if(subspace.addressInRange(addr)) { // increment tile int index = subspace.getIndex(addr); refFromImmortalStream.increment(index, (short)1); // increment summary this.totalRefFromImmortal++; return true; } else { return false; } } }