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.Space; 020import org.mmtk.utility.Log; 021import org.mmtk.utility.gcspy.Color; 022import org.mmtk.utility.gcspy.LinearScan; 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.ObjectReference; 032import org.vmmagic.unboxed.Offset; 033 034/** 035 * GCspy driver for the MMTk ContigousSpace.<p> 036 * 037 * This class implements a simple driver for contiguous MMTk spaces 038 * such as CopySpace and ImmortalSpace. 039 */ 040@Uninterruptible public class LinearSpaceDriver extends AbstractDriver { 041 042 // The GCspy streams 043 protected IntStream scalarUsedSpaceStream; 044 protected IntStream arrayUsedSpaceStream; 045 protected ShortStream scalarObjectsStream; 046 protected ShortStream arrayObjectsStream; 047 protected ShortStream arrayPrimitiveStream; 048 protected ShortStream rootsStream; 049 protected ShortStream refFromImmortalStream; 050 051 protected Subspace subspace; // A subspace for all of this space 052 protected int allTileNum; // total number of tiles 053 054 // Overall statistics 055 protected int totalScalarObjects = 0; // total number of objects allocated 056 protected int totalArrayObjects = 0; 057 protected int totalPrimitives = 0; 058 protected int totalScalarUsedSpace = 0; // total space used 059 protected int totalArrayUsedSpace = 0; 060 protected int totalRoots = 0; 061 protected int totalRefFromImmortal = 0; 062 063 private final LinearScan scanner; // A scanner to trace objects 064 065 // Debugging 066 protected Address lastAddress = Address.zero(); 067 protected int lastSize = 0; 068 private static final boolean DEBUG = false; 069 070 071 /** 072 * Create a new driver for a contiguous MMTk space. 073 * 074 * @param server The GCspy ServerInterpreter 075 * @param spaceName The name of this GCspy space 076 * @param mmtkSpace The MMTk space 077 * @param blockSize The tile size 078 * @param mainSpace Is this the main space? 079 */ 080 public LinearSpaceDriver(ServerInterpreter server, 081 String spaceName, 082 Space mmtkSpace, 083 int blockSize, 084 boolean mainSpace) { 085 086 super(server, spaceName, mmtkSpace, blockSize, mainSpace); 087 088 if (DEBUG) { 089 Log.write("LinearSpaceDriver for "); Log.write(spaceName); 090 Log.write(", blocksize="); Log.write(blockSize); 091 Log.write(", start="); Log.write(mmtkSpace.getStart()); 092 Log.write(", extent="); Log.write(mmtkSpace.getExtent()); 093 Log.write(", maxTileNum="); Log.writeln(maxTileNum); 094 } 095 096 // Initialise a subspace and 4 Streams 097 subspace = createSubspace(mmtkSpace); 098 allTileNum = 0; 099 scalarUsedSpaceStream = createScalarUsedSpaceStream(); 100 arrayUsedSpaceStream = createArrayUsedSpaceStream(); 101 scalarObjectsStream = createScalarObjectsStream(); 102 arrayPrimitiveStream = createArrayPrimitiveStream(); 103 arrayObjectsStream = createArrayObjectsStream(); 104 rootsStream = createRootsStream(); 105 refFromImmortalStream = createRefFromImmortalStream(); 106 serverSpace.resize(0); // the collector must call resize() before gathering data 107 108 // Initialise the statistics 109 resetData(); 110 scanner = new LinearScan(this); 111 } 112 113 @Override 114 protected String getDriverName() { 115 return "MMTk LinearSpaceDriver"; 116 } 117 118 /* 119 * Private creator methods to create the Streams. 120 */ 121 122 123 @Interruptible 124 private IntStream createScalarUsedSpaceStream() { 125 return VM.newGCspyIntStream( 126 this, 127 "Scalar Used Space stream", // stream name 128 0, // min. data value 129 blockSize, // max. data value 130 0, // zero value 131 0, // default value 132 "Scalars and primitive arrays: ", // value prefix 133 " bytes", // value suffix 134 PRESENTATION_PERCENT, // presentation style 135 PAINT_STYLE_ZERO, // paint style 136 0, // index of max stream (only needed if the presentation is *_VAR) 137 Color.Red, // tile colour 138 true); // summary enabled 139 } 140 141 @Interruptible 142 private IntStream createArrayUsedSpaceStream() { 143 return VM.newGCspyIntStream( 144 this, 145 "Array Used Space stream", 146 0, 147 blockSize, 148 0, 149 0, 150 "Reference arrays: ", 151 " bytes", 152 PRESENTATION_PERCENT, 153 PAINT_STYLE_ZERO, 154 0, 155 Color.Blue, 156 true); 157 } 158 159 @Interruptible 160 private ShortStream createScalarObjectsStream() { 161 return VM.newGCspyShortStream( 162 this, 163 "Scalar Objects stream", 164 (short)0, 165 // Say, max value = 50% of max possible 166 (short)(maxObjectsPerBlock(blockSize) / 2), 167 (short)0, 168 (short)0, 169 "Scalars: ", 170 " objects", 171 PRESENTATION_PLUS, 172 PAINT_STYLE_ZERO, 173 0, 174 Color.Green, 175 true); 176 } 177 178 @Interruptible 179 private ShortStream createArrayPrimitiveStream() { 180 return VM.newGCspyShortStream( 181 this, 182 "Array Primitive stream", 183 (short)0, 184 // Say, typical primitive array size = 4 * typical scalar size? 185 (short)(maxObjectsPerBlock(blockSize) / 8), 186 (short)0, 187 (short)0, 188 "Primitive arrays: ", 189 " objects", 190 PRESENTATION_PLUS, 191 PAINT_STYLE_ZERO, 192 0, 193 Color.Yellow, 194 true); 195 } 196 197 @Interruptible 198 private ShortStream createArrayObjectsStream() { 199 return VM.newGCspyShortStream( 200 this, 201 "Array Objects stream", 202 (short)0, 203 // Say, typical ref array size = 4 * typical scalar size? 204 (short)(maxObjectsPerBlock(blockSize) / 8), 205 (short)0, 206 (short)0, 207 "Reference arrays: ", 208 " objects", 209 PRESENTATION_PLUS, 210 PAINT_STYLE_ZERO, 211 0, 212 Color.Cyan, 213 true); 214 } 215 216 @Interruptible 217 private ShortStream createRootsStream() { 218 return VM.newGCspyShortStream( 219 this, 220 "Roots stream", 221 (short)0, 222 // Say, typical size = 4 * typical scalar size? 223 (short)(maxObjectsPerBlock(blockSize) / 8), 224 (short)0, 225 (short)0, 226 "Roots: ", 227 " objects", 228 PRESENTATION_PLUS, 229 PAINT_STYLE_ZERO, 230 0, 231 Color.Blue, 232 true); 233 } 234 235 @Interruptible 236 private ShortStream createRefFromImmortalStream() { 237 return VM.newGCspyShortStream( 238 this, 239 "References from immortal stream", 240 (short)0, 241 // Say, typical size = 4 * typical scalar size? 242 (short)(maxObjectsPerBlock(blockSize) / 8), 243 (short)0, 244 (short)0, 245 "References from immortal space: ", 246 " references", 247 PRESENTATION_PLUS, 248 PAINT_STYLE_ZERO, 249 0, 250 Color.Blue, 251 true); 252 } 253 254 /** 255 * Reset the statistics for all the streams, including totals used for summaries 256 */ 257 @Override 258 public void resetData() { 259 super.resetData(); 260 261 // Reset all the streams 262 scalarUsedSpaceStream.resetData(); 263 arrayUsedSpaceStream.resetData(); 264 scalarObjectsStream.resetData(); 265 arrayObjectsStream.resetData(); 266 arrayPrimitiveStream.resetData(); 267 refFromImmortalStream.resetData(); 268 269 // Reset the summary counts 270 totalScalarObjects = 0; 271 totalArrayObjects = 0; 272 totalPrimitives = 0; 273 totalScalarUsedSpace = 0; 274 totalArrayUsedSpace = 0; 275 totalRefFromImmortal = 0; 276 } 277 278 /** 279 * BumpPointer.linearScan needs a LinearScan object, which we provide here. 280 * @return the scanner for this driver 281 */ 282 public LinearScan getScanner() { 283 return scanner; 284 } 285 286 /** 287 * Set the current address range of a contiguous space 288 * @param start the start of the contiguous space 289 * @param end the end of the contiguous space 290 */ 291 @Override 292 public void setRange(Address start, Address end) { 293 int current = subspace.getBlockNum(); 294 int required = countTileNum(start, end, subspace.getBlockSize()); 295 296 // Reset the subspace 297 if (required != current) 298 subspace.reset(start, end, 0, required); 299 300 if (DEBUG) { 301 Log.write("\nContiguousSpaceDriver.setRange for contiguous space: "); 302 Log.write(subspace.getFirstIndex()); Log.write("-", subspace.getBlockNum()); 303 Log.write(" (", start); Log.write("-", end); Log.write(")"); 304 } 305 306 // Reset the driver 307 // Note release() only resets a CopySpace's cursor (and optionally zeroes 308 // or mprotects the pages); it doesn't make the pages available to other 309 // spaces. If pages were to be released, change the test here to 310 // if (allTileNum != required) { 311 if (allTileNum < required) { 312 if (DEBUG) { 313 Log.write(", resize from ", allTileNum); 314 Log.write(" to ", required); 315 } 316 allTileNum = required; 317 serverSpace.resize(allTileNum); 318 setTilenames(subspace, allTileNum); 319 } 320 if (DEBUG) Log.writeln(); 321 } 322 323 324 /** 325 * Update the tile statistics 326 * @param obj The current object 327 */ 328 @Override 329 public void scan(ObjectReference obj) { 330 scan(obj, true); 331 } 332 333 /** 334 * Update the tile statistics 335 * @param obj The current object 336 * @param total Whether to accumulate the values 337 */ 338 @Override 339 public void scan(ObjectReference obj, boolean total) { 340 boolean isArray = VM.objectModel.isArray(obj); 341 int length = VM.objectModel.getCurrentSize(obj); 342 Address addr = obj.toAddress(); 343 344 if (VM.VERIFY_ASSERTIONS) { 345 if (addr.LT(lastAddress.plus(lastSize))) { 346 Log.write("\nContiguousSpaceDriver finds addresses going backwards: "); 347 Log.write("last="); Log.write(lastAddress); 348 Log.write(" last size="); Log.write(lastSize); 349 Log.writeln(" current=", addr); 350 } 351 lastAddress = addr; 352 lastSize = length; 353 } 354 355 // Update the stats 356 if (subspace.addressInRange(addr)) { 357 int index = subspace.getIndex(addr); 358 int remainder = subspace.spaceRemaining(addr); 359 if (isArray) { 360 arrayObjectsStream.increment(index, (short)1); 361 arrayUsedSpaceStream.distribute(index, remainder, blockSize, length); 362 if (total) { 363 totalArrayObjects++; 364 totalArrayUsedSpace += length; 365 } 366 } else { 367 if (!this.scanCheckPrimitiveArray(obj, index, total, length)) { 368 // real object 369 scalarObjectsStream.increment(index, (short)1); 370 if (total) { 371 totalScalarObjects++; 372 totalScalarUsedSpace += length; 373 } 374 } 375 scalarUsedSpaceStream.distribute(index, remainder, blockSize, length); 376 } 377 } 378 } 379 380 /** 381 * Check if this Object is an array of primitives.<br> 382 * Part of the public scan() method. 383 * 384 * @param obj The Object to check 385 * @param index Index of the tile 386 * @param total Increment summary 387 * @param length Current size of the Object, will be added to array space summary. 388 * @return {@code true} if this Object is an array of primitives. 389 */ 390 protected boolean scanCheckPrimitiveArray(ObjectReference obj, int index, boolean total, int length) { 391 if (VM.objectModel.isPrimitiveArray(obj)) { 392 arrayPrimitiveStream.increment(index, (short)1); 393 if (total) { 394 totalPrimitives++; 395 totalScalarUsedSpace += length; 396 } 397 return true; 398 } else { 399 return false; 400 } 401 } 402 403 /** 404 * Transmit the data if this event is of interest to the client.<p> 405 * Implemented using the algorithm pattern, subclasses can override parts of it. 406 * @param event The event, defined in the Plan 407 */ 408 @Override 409 public void transmit(int event) { 410 if (!server.isConnected(event)) 411 return; 412 413 if (DEBUG) { 414 Log.write("CONNECTED\n"); 415 Log.write(myClass); 416 Log.write(".send: numTiles=", allTileNum); 417 //Log.write("LinearSpaceDriver.transmit: numTiles=", allTileNum); 418 Log.writeln(", control.length=", control.length); 419 Log.flush(); 420 } 421 422 // Setup the summaries 423 setupSummaries(); 424 425 // Setup the control info 426 setupControlInfo(); 427 428 // Setup the space info 429 Offset size = subspace.getEnd().diff(subspace.getStart()); 430 setSpaceInfo(size); 431 432 // Send the all streams 433 send(event, allTileNum); 434 435 // Debugging 436 if (VM.VERIFY_ASSERTIONS) { 437 lastAddress = Address.zero(); 438 lastSize = 0; 439 } 440 } 441 442 /** 443 * Setup summaries part of the <code>transmit</code> method.<p> 444 * Override this method to setup summaries of additional streams in subclasses. 445 */ 446 protected void setupSummaries() { 447 scalarUsedSpaceStream.setSummary(totalScalarUsedSpace, 448 subspace.getEnd().diff(subspace.getStart()).toInt()); 449 arrayUsedSpaceStream.setSummary(totalArrayUsedSpace, 450 subspace.getEnd().diff(subspace.getStart()).toInt()); 451 scalarObjectsStream.setSummary(totalScalarObjects); 452 arrayObjectsStream.setSummary(totalArrayObjects); 453 arrayPrimitiveStream.setSummary(totalPrimitives); 454 rootsStream.setSummary(totalRoots); 455 refFromImmortalStream.setSummary(totalRefFromImmortal); 456 } 457 458 /** 459 * Setup control info part of the <code>transmit</code> method.<p> 460 * Override this method to change the controls for your own driver subclass. 461 */ 462 protected void setupControlInfo() { 463 int numBlocks = subspace.getBlockNum(); 464 controlValues(CONTROL_USED, subspace.getFirstIndex(), numBlocks); 465 if (DEBUG) { 466 Log.write("LinearSpaceDriver.transmitSetupControlInfo: allTileNum=", allTileNum); 467 Log.writeln(", numBlocks=", numBlocks); 468 } 469 if (numBlocks < allTileNum) 470 controlValues(CONTROL_UNUSED, 471 subspace.getFirstIndex() + numBlocks, 472 allTileNum - numBlocks); 473 } 474 475 /** 476 * Handle a root address 477 * 478 * @param addr Root Address 479 * @return {@code true} if the given Address is in this subspace. 480 */ 481 public boolean handleRoot(Address addr) { 482 if (subspace.addressInRange(addr)) { 483 // increment tile 484 int index = subspace.getIndex(addr); 485 rootsStream.increment(index, (short)1); 486 // increment summary 487 this.totalRoots++; 488 return true; 489 } else { 490 return false; 491 } 492 } 493 494 /** 495 * Reset the roots Stream 496 * The roots Stream has to be reset separately because we do not 497 * gather data in the usual way using <code>scan()</code>. 498 */ 499 public void resetRootsStream() { 500 rootsStream.resetData(); 501 totalRoots = 0; 502 } 503 504 /** 505 * Handle a direct reference from the immortal space. 506 * 507 * @param addr The Address 508 * @return {@code true} if the given Address is in this subspace. 509 */ 510 @Override 511 public boolean handleReferenceFromImmortalSpace(Address addr) { 512 if (subspace.addressInRange(addr)) { 513 // increment tile 514 int index = subspace.getIndex(addr); 515 refFromImmortalStream.increment(index, (short)1); 516 // increment summary 517 this.totalRefFromImmortal++; 518 return true; 519 } else { 520 return false; 521 } 522 } 523 524}