001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.mmtk.utility.gcspy.drivers; 014 015import static org.mmtk.utility.gcspy.StreamConstants.PAINT_STYLE_ZERO; 016import static org.mmtk.utility.gcspy.StreamConstants.PRESENTATION_PERCENT; 017import static org.mmtk.utility.gcspy.StreamConstants.PRESENTATION_PLUS; 018 019import org.mmtk.policy.LargeObjectSpace; 020import org.mmtk.utility.Conversions; 021import org.mmtk.utility.Log; 022import org.mmtk.utility.gcspy.Color; 023import org.mmtk.utility.gcspy.Subspace; 024import org.mmtk.vm.VM; 025import org.mmtk.vm.gcspy.IntStream; 026import org.mmtk.vm.gcspy.ServerInterpreter; 027import org.mmtk.vm.gcspy.ShortStream; 028import org.vmmagic.pragma.Interruptible; 029import org.vmmagic.pragma.Uninterruptible; 030import org.vmmagic.unboxed.Address; 031import org.vmmagic.unboxed.Offset; 032 033 034/** 035 * This class implements a simple driver for the MMTk LargeObjectSpace. 036 */ 037@Uninterruptible public class TreadmillDriver extends AbstractDriver { 038 039 private static final boolean DEBUG = false; 040 041 // The streams 042 protected IntStream usedSpaceStream; 043 protected ShortStream objectsStream; 044 protected ShortStream rootsStream; 045 protected ShortStream refFromImmortalStream; 046 047 protected Subspace subspace; // A single subspace for this space 048 protected int allTileNum; // total number of tiles 049 050 // Overall statistics 051 protected int totalObjects = 0; // total number of objects allocated 052 protected int totalUsedSpace = 0; // total space used 053 protected int totalRoots = 0; // total of roots 054 protected int totalRefFromImmortal = 0; // total direct references from the immortal space 055 protected Address maxAddr; // the largest address seen 056 protected int threshold; 057 058 059 /** 060 * Create a new driver for this collector 061 * 062 * @param server The name of the GCspy server that owns this space 063 * @param spaceName The name of this driver 064 * @param lospace the large object space for this allocator 065 * @param blockSize The tile size 066 * @param threshold the size threshold of the LOS 067 * @param mainSpace Is this the main space? 068 */ 069 public TreadmillDriver( 070 ServerInterpreter server, 071 String spaceName, 072 LargeObjectSpace lospace, 073 int blockSize, 074 int threshold, 075 boolean mainSpace) { 076 //TODO blocksize should be a multiple of treadmill granularity 077 super(server, spaceName, lospace, blockSize, mainSpace); 078 079 if (DEBUG) { 080 Log.write("TreadmillDriver for "); Log.write(spaceName); 081 Log.write(", blocksize="); Log.write(blockSize); 082 Log.write(", start="); Log.write(lospace.getStart()); 083 Log.write(", extent="); Log.write(lospace.getExtent()); 084 Log.write(", maxTileNum="); Log.writeln(maxTileNum); 085 } 086 087 this.threshold = threshold; 088 089 // Initialise a subspace and 2 Streams 090 subspace = createSubspace(lospace); 091 allTileNum = 0; 092 maxAddr = lospace.getStart(); 093 usedSpaceStream = createUsedSpaceStream(); 094 objectsStream = createObjectsStream(); 095 rootsStream = createRootsStream(); 096 refFromImmortalStream = createRefFromImmortalStream(); 097 serverSpace.resize(0); // the collector must call resize() before gathering data 098 099 // Initialise the statistics 100 resetData(); 101 } 102 103 /** 104 * @return The name, "MMTk TreadmillDriver" for this driver. 105 */ 106 @Override 107 protected String getDriverName() { 108 return "MMTk TreadmillDriver"; 109 } 110 111 // private creator methods for the streams 112 @Interruptible 113 private IntStream createUsedSpaceStream() { 114 return VM.newGCspyIntStream( 115 this, 116 "Used Space stream", // stream name 117 0, // min. data value 118 blockSize, // max. data value 119 0, // zero value 120 0, // default value 121 "Space used: ", // value prefix 122 " bytes", // value suffix 123 PRESENTATION_PERCENT, // presentation style 124 PAINT_STYLE_ZERO, // paint style 125 0, // index of the max stream (only needed if presentation is *_VAR) 126 Color.Red, // tile colour 127 true); // summary enabled 128 } 129 130 @Interruptible 131 private ShortStream createObjectsStream() { 132 return VM.newGCspyShortStream( 133 this, 134 "Objects stream", 135 (short)0, 136 (short)(blockSize / threshold), 137 (short)0, 138 (short)0, 139 "No. of objects = ", 140 " objects", 141 PRESENTATION_PLUS, 142 PAINT_STYLE_ZERO, 143 0, 144 Color.Green, 145 true); 146 } 147 148 @Interruptible 149 private ShortStream createRootsStream() { 150 return VM.newGCspyShortStream( 151 this, 152 "Roots stream", 153 (short)0, 154 // Say, typical size = 4 * typical scalar size? 155 (short)(maxObjectsPerBlock(blockSize) / 8), 156 (short)0, 157 (short)0, 158 "Roots: ", 159 " objects", 160 PRESENTATION_PLUS, 161 PAINT_STYLE_ZERO, 162 0, 163 Color.Blue, 164 true); 165 } 166 167 @Interruptible 168 private ShortStream createRefFromImmortalStream() { 169 return VM.newGCspyShortStream( 170 this, 171 "References from Immortal stream", 172 (short)0, 173 // Say, typical size = 4 * typical scalar size? 174 (short)(maxObjectsPerBlock(blockSize) / 8), 175 (short)0, 176 (short)0, 177 "References from immortal space: ", 178 " references", 179 PRESENTATION_PLUS, 180 PAINT_STYLE_ZERO, 181 0, 182 Color.Blue, 183 true); 184 } 185 186 /** 187 * Reset the tile stats for all streams, including values used for summaries 188 */ 189 @Override 190 public void resetData() { 191 super.resetData(); 192 193 // Reset all the streams 194 usedSpaceStream.resetData(); 195 objectsStream.resetData(); 196 refFromImmortalStream.resetData(); 197 198 // Reset the summary counts 199 totalUsedSpace = 0; 200 totalObjects = 0; 201 totalRefFromImmortal = 0; 202 } 203 204 205 /** 206 * Update the tile statistics 207 * In this case, we are accounting for super-page objects, rather than 208 * simply for the objects they contain. 209 * 210 * @param addr The address of the superpage 211 */ 212 @Override 213 public void scan(Address addr) { 214 215 int index = subspace.getIndex(addr); 216 int length = ((LargeObjectSpace)mmtkSpace).getSize(addr).toInt(); 217 218 if (DEBUG) { 219 Log.write("TreadmillDriver: super=", addr); 220 Log.write(", index=", index); 221 Log.write(", pages=", length); 222 Log.write(", bytes=", Conversions.pagesToBytes(length).toInt()); 223 Log.writeln(", max=", usedSpaceStream.getMaxValue()); 224 } 225 226 totalObjects++; 227 totalUsedSpace += length; 228 objectsStream.increment(index, (short)1); 229 int remainder = subspace.spaceRemaining(addr); 230 usedSpaceStream.distribute(index, remainder, blockSize, length); 231 232 Address tmp = addr.plus(length); 233 if (tmp.GT(maxAddr)) maxAddr = tmp; 234 } 235 236 /** 237 * Transmit the data if this event is of interest to the client 238 * @param event The event, either BEFORE_COLLECTION, SEMISPACE_COPIED 239 * or AFTER_COLLECTION 240 */ 241 @Override 242 public void transmit(int event) { 243 if (!isConnected(event)) 244 return; 245 246 // At this point, we've filled the tiles with data, 247 // however, we don't know the size of the space 248 // Calculate the highest indexed tile used so far, and update the subspace 249 Address start = subspace.getStart(); 250 int required = countTileNum(start, maxAddr, blockSize); 251 int current = subspace.getBlockNum(); 252 if (required > current || maxAddr.NE(subspace.getEnd())) { 253 subspace.reset(start, maxAddr, 0, required); 254 allTileNum = required; 255 serverSpace.resize(allTileNum); 256 setTilenames(subspace, allTileNum); 257 } 258 259 // Set the summaries 260 setupSummaries(); 261 262 // set the control info: all of space is USED 263 controlValues(CONTROL_USED, 264 subspace.getFirstIndex(), subspace.getBlockNum()); 265 266 // send the space info 267 Offset size = subspace.getEnd().diff(subspace.getStart()); 268 setSpaceInfo(size); 269 270 // Send the streams 271 send(event, allTileNum); 272 } 273 274 /** 275 * Setup summaries part of the <code>transmit</code> method.<p> 276 * Override this method to setup summaries of additional streams in subclasses. 277 */ 278 protected void setupSummaries() { 279 usedSpaceStream.setSummary(totalUsedSpace, 280 subspace.getEnd().diff(subspace.getStart()).toInt()); 281 objectsStream.setSummary(totalObjects); 282 rootsStream.setSummary(totalRoots); 283 refFromImmortalStream.setSummary(totalRefFromImmortal); 284 } 285 286 287 /** 288 * Handle a root address 289 * 290 * @param addr Root Address 291 * @return {@code true} if the given Address is in this subspace. 292 */ 293 public boolean handleRoot(Address addr) { 294 if (subspace.addressInRange(addr)) { 295 // increment tile 296 int index = subspace.getIndex(addr); 297 rootsStream.increment(index, (short)1); 298 // increment summary 299 this.totalRoots++; 300 return true; 301 } else { 302 return false; 303 } 304 } 305 306 /** 307 * Reset the roots Stream. <br> 308 * The roots Stream has to be reset separately because we do not 309 * gather data in the usual way using <code>scan()</code>. 310 */ 311 public void resetRootsStream() { 312 rootsStream.resetData(); 313 totalRoots = 0; 314 } 315 316 /** 317 * Handle a direct reference from the immortal space. 318 * 319 * @param addr The Address 320 * @return {@code true} if the given Address is in this subspace. 321 */ 322 @Override 323 public boolean handleReferenceFromImmortalSpace(Address addr) { 324 if (subspace.addressInRange(addr)) { 325 // increment tile 326 int index = subspace.getIndex(addr); 327 refFromImmortalStream.increment(index, (short)1); 328 // increment summary 329 this.totalRefFromImmortal++; 330 return true; 331 } else { 332 return false; 333 } 334 } 335}