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