| /* |
| * 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.Space; |
| import org.mmtk.utility.Log; |
| import org.mmtk.utility.gcspy.GCspy; |
| import org.mmtk.utility.gcspy.Subspace; |
| import org.mmtk.vm.gcspy.ServerSpace; |
| import org.mmtk.vm.gcspy.ServerInterpreter; |
| import org.mmtk.vm.gcspy.Stream; |
| import org.mmtk.vm.VM; |
| |
| import org.vmmagic.unboxed.*; |
| import org.vmmagic.pragma.*; |
| |
| /** |
| * Abstract GCspy driver for MMTk collectors. |
| * |
| * This class implements for the MMTk a base driver for a GCspy space. |
| * All drivers for GCspy spaces should inherit from this class. |
| */ |
| @Uninterruptible |
| public abstract class AbstractDriver { |
| |
| /**************************************************************************** |
| * |
| * Class variables |
| */ |
| |
| // Controls used for tile presentation |
| /** The tile is used */ |
| protected static final byte CONTROL_USED = 1; |
| /** The tile is a background tile */ |
| protected static final byte CONTROL_BACKGROUND = 2; |
| /** The tile is unused */ |
| protected static final byte CONTROL_UNUSED = 4; |
| /** The tile is a separator */ |
| protected static final byte CONTROL_SEPARATOR = 8; |
| /** The tile is a link */ |
| protected static final byte CONTROL_LINK = 16; |
| |
| |
| private static final int MAX_STREAMS = 64; // Max number of streams |
| |
| private static final boolean DEBUG = false; |
| protected String myClass; // used in debugging messages |
| |
| |
| /**************************************************************************** |
| * |
| * Instance variables |
| */ |
| |
| /** The owning GCspy server */ |
| protected final ServerInterpreter server; |
| /** The name of the GCspy space driver */ |
| protected final String name; |
| /** The GCspy space abstraction */ |
| protected final ServerSpace serverSpace; |
| /** The MMTK space */ |
| protected final Space mmtkSpace; |
| /** The GCspy space's block size */ |
| protected int blockSize; |
| /** The maximum number of tiles in this GCspy space */ |
| protected int maxTileNum; |
| /** This space's streams */ |
| protected Stream[] streams; |
| /** control values for tiles in this space */ |
| protected byte[] control; |
| /** Has this space changed? */ |
| protected boolean changed = true; |
| |
| |
| /** |
| * Create a new driver for this collector. |
| * |
| * @param server The ServerInterpreter that owns this GCspy space. |
| * @param name The name of this driver. |
| * @param mmtkSpace The MMTk space represented by this driver. |
| * @param blockSize The tile size. |
| * @param mainSpace Is this the main space? |
| */ |
| public AbstractDriver(ServerInterpreter server, |
| String name, |
| Space mmtkSpace, |
| int blockSize, |
| boolean mainSpace) { |
| this.server = server; |
| this.name = name; |
| this.mmtkSpace = mmtkSpace; |
| this.blockSize = blockSize; |
| myClass = getClass().getName(); |
| maxTileNum = countTileNum(mmtkSpace.getExtent(), blockSize); |
| control = (byte[])GCspy.util.createDataArray(new byte[0], maxTileNum); |
| // to avoid allocation during GC we preallocate the streams array |
| streams = new Stream[MAX_STREAMS]; |
| serverSpace = createServerSpace(server, name, maxTileNum, mainSpace); |
| } |
| |
| /** |
| * Create a subspace for this space. |
| * Subspace provide useful facilities for contiguous spaces, even if |
| * a space contains only one. |
| * @param mmtkSpace The MMTk space |
| */ |
| @Interruptible |
| protected Subspace createSubspace(Space mmtkSpace) { |
| Address start = mmtkSpace.getStart(); |
| return new Subspace(start, start, 0, blockSize, 0); |
| } |
| |
| /** |
| * Create a new GCspy ServerSpace and add it to the ServerInterpreter. |
| * @param server the GCspy ServerInterpreter. |
| * @param spaceName The name of this driver. |
| * @param maxTileNum the maximum number of tiles in this space. |
| * @param mainSpace Is this the main space? |
| */ |
| @Interruptible |
| protected ServerSpace createServerSpace(ServerInterpreter server, |
| String spaceName, |
| int maxTileNum, |
| boolean mainSpace) { |
| // Set the block label |
| String tmp = "Block Size: " + ((blockSize < 1024) ? |
| blockSize + " bytes\n": |
| (blockSize / 1024) + " Kbytes\n"); |
| |
| // Create a single GCspy Space |
| return VM.newGCspyServerSpace(server, // the server |
| spaceName, // space name |
| getDriverName(), // driver (space) name |
| "Block ", // space title |
| tmp, // block info |
| maxTileNum, // number of tiles |
| "UNUSED", // the label for unused blocks |
| mainSpace); // main space |
| } |
| |
| /** |
| * Get the name of this driver type. |
| * @return The name of this driver. |
| */ |
| protected abstract String getDriverName(); |
| |
| /** |
| * Get the maximum number of tiles in this space. |
| * @return the maximum number of tiles in the space. |
| */ |
| public int getMaxTileNum() { |
| return maxTileNum; |
| } |
| |
| /** |
| * The GCspy space managed by this driver. |
| * @return the GCspy server space. |
| */ |
| public ServerSpace getServerSpace() { return serverSpace; } |
| |
| /** |
| * Add a stream to the driver. This also sets the stream's id |
| * (unique for this space). |
| * @param stream The stream |
| * @exception IndexOutOfBoundsException if more than MAX_STREAMS are added |
| */ |
| @Interruptible |
| public void addStream(Stream stream) { |
| int id = 0; |
| while (id < MAX_STREAMS) { |
| if (streams[id] == null) { |
| streams[id] = stream; |
| if (DEBUG) { Log.write("Adding stream with id="); Log.writeln(id); } |
| Address stream_ = serverSpace.addStream(id); |
| stream.setStream(id, stream_); |
| return; |
| } |
| id++; |
| } |
| throw new IndexOutOfBoundsException("Too many streams added to driver "+name); |
| } |
| |
| /** |
| * Count number of tiles in an address range. |
| * @param start The start of the range. |
| * @param end The end of the range. |
| * @param tileSize The size of each tile. |
| * @return The number of tiles in this range. |
| */ |
| protected int countTileNum(Address start, Address end, int tileSize) { |
| if (end.LE(start)) return 0; |
| int diff = end.diff(start).toInt(); |
| return countTileNum(diff, tileSize); |
| } |
| |
| /** |
| * Count number of tiles in an address range. |
| * @param extent The extent of the range. |
| * @param tileSize The size of each tile. |
| * @return The number of tiles in this range. |
| */ |
| protected int countTileNum(Extent extent, int tileSize) { |
| int diff = extent.toInt(); |
| return countTileNum(diff, tileSize); |
| } |
| |
| private int countTileNum(int diff, int tileSize) { |
| int tiles = diff / tileSize; |
| if ((diff % tileSize) != 0) |
| ++tiles; |
| return tiles; |
| } |
| |
| /** |
| * Indicate the limits of a space. |
| * |
| * @param start the Address of the start of the space. |
| * @param end the Address of the end of the space. |
| */ |
| public void setRange(Address start, Address end) {} |
| |
| /** |
| * Indicate the limits of a space. |
| * |
| * @param start the Address of the start of the space. |
| * @param extent the extent of the space. |
| */ |
| public void setRange(Address start, Extent extent) { |
| setRange(start, start.plus(extent)); |
| } |
| |
| /** |
| * Setup the tile names in a subspace. Tile names are typically |
| * address ranges but may be anything (e.g. a size class if the |
| * space is a segregated free-list manager, or a class name if the |
| * space represents the class instances loaded). |
| * |
| * @param subspace the Subspace |
| * @param numTiles the number of tiles to name |
| */ |
| protected void setTilenames(Subspace subspace, int numTiles) { |
| Address start = subspace.getStart(); |
| int first = subspace.getFirstIndex(); |
| int bs = subspace.getBlockSize(); |
| |
| for (int i = 0; i < numTiles; ++i) { |
| if (subspace.indexInRange(i)) |
| serverSpace.setTilename(i, start.plus((i - first) * bs), |
| start.plus((i + 1 - first) * bs)); |
| } |
| } |
| |
| /** |
| * The "typical" maximum number of objects in each tile. |
| * @param blockSize The size of a tile |
| * @return The maximum number of objects in a tile |
| */ |
| public int maxObjectsPerBlock(int blockSize) { |
| // Maybe a misuse of ServerInterpreter but it's a convenient |
| // VM-dependent class |
| return blockSize / GCspy.server.computeHeaderSize(); |
| } |
| |
| /** |
| * Is the server connected to a GCspy client? |
| * @param event The current event |
| */ |
| public boolean isConnected(int event) { |
| return server.isConnected(event); |
| } |
| |
| /** |
| * Reset the statistics for a space. |
| * In this base driver, we simply note that the data has changed. |
| */ |
| protected void resetData() { changed = true; } |
| |
| /** |
| * Scan an object found at a location. |
| * Collectors typically call this method to update GCspy statistics. |
| * The driver may or may not accumulate values found, depending on |
| * the value of total. |
| * @param obj the reference to the object found |
| * @param total Whether to total the statistics |
| */ |
| public void scan(ObjectReference obj, boolean total) {} |
| |
| /** |
| * Scan an object found at a location. |
| * Collectors typically call this method to update GCspy statistics |
| * The driver will accumulate values found. |
| * @param obj the reference to the object found |
| */ |
| public void scan(ObjectReference obj) { scan(obj, true); } |
| |
| /** |
| * Scan an object found at a location. |
| * Collectors typically call this method to update GCspy statistics. |
| * The driver may or may not accumulate values found, depending on |
| * the value of total. |
| * @param obj the reference to the object found |
| * @param total Whether to total the statistics |
| */ |
| public void scan(Address obj, boolean total) {} |
| |
| /** |
| * Scan an object found at a location. |
| * Collectors typically call this method to update GCspy statistics |
| * The driver will accumulate values found. |
| * @param obj the reference to the object found |
| */ |
| public void scan(Address obj) {} |
| |
| /** |
| * Handle a direct reference from the immortal space.<p> |
| * This is an empty implementation. Subclasses may override this method |
| * to increment their <code>refFromImmortal</code> Stream. |
| * |
| * @param addr The Address |
| * @return true if the given Address is in this subspace. Always false here. |
| */ |
| public boolean handleReferenceFromImmortalSpace(Address addr) { |
| return false; |
| } |
| |
| /** |
| * Set space info. |
| * This simply reports the size of the current space. |
| * Drivers that want to send something more complex than |
| * "Current Size: size\n" |
| * must override this method. |
| * |
| * @param size the size of the space |
| */ |
| protected void setSpaceInfo(Offset size) { |
| // - sprintf(tmp, "Current Size: %s\n", gcspy_formatSize(size)); |
| Address tmp = GCspy.util.formatSize("Current Size: %s\n", 128, size.toInt()); |
| serverSpace.spaceInfo(tmp); |
| GCspy.util.free(tmp); |
| } |
| |
| |
| /**************************************************************************** |
| * |
| * Control values |
| */ |
| |
| /** |
| * Is a tile used? |
| * @param val the control value. |
| * @return true if the tile is used |
| */ |
| protected static boolean controlIsUsed(byte val) { |
| return (val & CONTROL_USED) != 0; |
| } |
| |
| /** |
| * Is a tile a background pseudo-tile? |
| * @param val the control value. |
| * @return true if the tile is a background tile |
| */ |
| protected static boolean controlIsBackground(byte val) { |
| return (val & CONTROL_BACKGROUND) != 0; |
| } |
| |
| /** |
| * Is a tile unused? |
| * @param val the control value. |
| * @return true if the tile is unused |
| */ |
| protected static boolean controlIsUnused(byte val) { |
| return (val & CONTROL_UNUSED) != 0; |
| } |
| |
| /** |
| * Is this a separator? |
| * @param val the control value. |
| * @return true if this is a separator |
| */ |
| protected static boolean controlIsSeparator(byte val) { |
| return (val & CONTROL_SEPARATOR) != 0; |
| } |
| |
| /** |
| * Initialise the value of a control. |
| * @param index The index of the tile. |
| * @param value The new value of the control |
| */ |
| protected void initControl(int index, byte value) { |
| control[index] = value; |
| } |
| |
| /** |
| * Add a control to the tile |
| * @param index The index of the tile. |
| * @param value The control to add. |
| */ |
| protected void addControl(int index, byte value) { |
| control[index] |= value; |
| } |
| |
| /** Set the control |
| * @param value The value to set |
| */ |
| protected void setControl(int index, byte value) { |
| control[index] &= value; |
| } |
| |
| /** |
| * Get the controls for a tile. |
| * @param index The index of the tile. |
| * @return The value of the controls |
| */ |
| public byte getControl(int index) { |
| return control[index]; |
| } |
| |
| /** |
| * Initialise control values in all tiles |
| */ |
| protected void initControls() { |
| for (int index = 0; index < control.length; ++index) { |
| initControl(index, CONTROL_USED); |
| } |
| } |
| |
| /** |
| * Set the control value in each tile in a region. |
| * @param tag The control tag. |
| * @param start The start index of the region. |
| * @param len The number of tiles in the region. |
| */ |
| protected void controlValues(byte tag, int start, int len) { |
| if (DEBUG) { |
| Log.write("AbstractDriver.controlValues for space "); |
| Log.write(name); |
| Log.write(", control length=", control.length); |
| Log.write(" writing controls from ", start); |
| Log.writeln(" to ", start + len); |
| } |
| changed = true; |
| for (int i = start; i < (start+len); ++i) { |
| // Cannot be both USED and UNUSED or BACKGROUND |
| if (controlIsBackground(tag) || controlIsUnused(tag)) |
| setControl(i, (byte)~CONTROL_USED); |
| else if (controlIsUsed(tag)) |
| setControl(i, (byte)~CONTROL_UNUSED); |
| addControl(i, tag); |
| } |
| } |
| |
| /** |
| * Transmit the streams for this space. A driver will typically |
| * <ol> |
| * <li> Determine whether a GCspy client is connected and interested in |
| * this event, e.g. |
| * <pre>server.isConnected(event)</pre> |
| * <li> Setup the summaries for each stream, e.g. |
| * <pre>stream.setSummary(values...);</pre> |
| * <li> Setup the control information for each tile. e.g. |
| * <pre>controlValues(CONTROL_USED, start, numBlocks);</pre> |
| * <pre>controlValues(CONTROL_UNUSED, end, remainingBlocks);</pre> |
| * <li> Set up the space information, e.g. |
| * <pre>setSpace(info);</pre> |
| * <li> Send the data for all streams, e.g. |
| * <pre>send(event, numTiles);</pre> |
| * Note that AbstractDriver.send takes care of sending the information |
| * for all streams (including control data). |
| * |
| * @param event The event |
| */ |
| public abstract void transmit(int event); |
| |
| /** |
| * Send all the streams for this space if it has changed. |
| * Assume that the data has been gathered and that summary info |
| * and control values have been set before this is called. |
| * |
| * @param event the event |
| * @param numTiles the number of blocks in this space |
| */ |
| protected void send(int event, int numTiles) { |
| if (changed) { |
| serverSpace.startCommunication(); |
| for (int i = 0; i < MAX_STREAMS; i++) |
| if (streams[i] != null) |
| streams[i].send(event, numTiles); |
| serverSpace.sendControls(this, numTiles); |
| serverSpace.endCommunication(); |
| } |
| } |
| } |