blob: 2cfe81abb18c98308349b714087c1da8c35a0c15 [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.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;
}
}
}