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