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 org.mmtk.policy.Space; 016import org.mmtk.utility.Log; 017import org.mmtk.utility.gcspy.GCspy; 018import org.mmtk.utility.gcspy.Subspace; 019import org.mmtk.vm.gcspy.ServerSpace; 020import org.mmtk.vm.gcspy.ServerInterpreter; 021import org.mmtk.vm.gcspy.Stream; 022import org.mmtk.vm.VM; 023 024import org.vmmagic.unboxed.*; 025import org.vmmagic.pragma.*; 026 027/** 028 * Abstract GCspy driver for MMTk collectors.<p> 029 * 030 * This class implements for the MMTk a base driver for a GCspy space. 031 * All drivers for GCspy spaces should inherit from this class. 032 */ 033@Uninterruptible 034public abstract class AbstractDriver { 035 036 /**************************************************************************** 037 * 038 * Class variables 039 */ 040 041 // Controls used for tile presentation 042 043 /** The tile is used */ 044 protected static final byte CONTROL_USED = 1; 045 /** The tile is a background tile */ 046 protected static final byte CONTROL_BACKGROUND = 2; 047 /** The tile is unused */ 048 protected static final byte CONTROL_UNUSED = 4; 049 /** The tile is a separator */ 050 protected static final byte CONTROL_SEPARATOR = 8; 051 /** The tile is a link */ 052 protected static final byte CONTROL_LINK = 16; 053 054 055 private static final int MAX_STREAMS = 64; // Max number of streams 056 057 private static final boolean DEBUG = false; 058 protected String myClass; // used in debugging messages 059 060 061 /**************************************************************************** 062 * 063 * Instance variables 064 */ 065 066 /** The owning GCspy server */ 067 protected final ServerInterpreter server; 068 /** The name of the GCspy space driver */ 069 protected final String name; 070 /** The GCspy space abstraction */ 071 protected final ServerSpace serverSpace; 072 /** The MMTK space */ 073 protected final Space mmtkSpace; 074 /** The GCspy space's block size */ 075 protected int blockSize; 076 /** The maximum number of tiles in this GCspy space */ 077 protected int maxTileNum; 078 /** This space's streams */ 079 protected Stream[] streams; 080 /** control values for tiles in this space */ 081 protected byte[] control; 082 /** Has this space changed? */ 083 protected boolean changed = true; 084 085 086 /** 087 * Create a new driver for this collector. 088 * 089 * @param server The ServerInterpreter that owns this GCspy space. 090 * @param name The name of this driver. 091 * @param mmtkSpace The MMTk space represented by this driver. 092 * @param blockSize The tile size. 093 * @param mainSpace Is this the main space? 094 */ 095 public AbstractDriver(ServerInterpreter server, 096 String name, 097 Space mmtkSpace, 098 int blockSize, 099 boolean mainSpace) { 100 this.server = server; 101 this.name = name; 102 this.mmtkSpace = mmtkSpace; 103 this.blockSize = blockSize; 104 myClass = getClass().getName(); 105 maxTileNum = countTileNum(mmtkSpace.getExtent(), blockSize); 106 control = (byte[])GCspy.util.createDataArray(new byte[0], maxTileNum); 107 // to avoid allocation during GC we preallocate the streams array 108 streams = new Stream[MAX_STREAMS]; 109 serverSpace = createServerSpace(server, name, maxTileNum, mainSpace); 110 } 111 112 /** 113 * Creates a subspace for this space. 114 * Subspace provide useful facilities for contiguous spaces, even if 115 * a space contains only one. 116 * @param mmtkSpace The MMTk space 117 * @return the created subspace 118 */ 119 @Interruptible 120 protected Subspace createSubspace(Space mmtkSpace) { 121 Address start = mmtkSpace.getStart(); 122 return new Subspace(start, start, 0, blockSize, 0); 123 } 124 125 /** 126 * Create a new GCspy ServerSpace and add it to the ServerInterpreter. 127 * @param server the GCspy ServerInterpreter. 128 * @param spaceName The name of this driver. 129 * @param maxTileNum the maximum number of tiles in this space. 130 * @param mainSpace Is this the main space? 131 * @return the created server space 132 */ 133 @Interruptible 134 protected ServerSpace createServerSpace(ServerInterpreter server, 135 String spaceName, 136 int maxTileNum, 137 boolean mainSpace) { 138 // Set the block label 139 String tmp = "Block Size: " + ((blockSize < 1024) ? 140 blockSize + " bytes\n" : 141 (blockSize / 1024) + " Kbytes\n"); 142 143 // Create a single GCspy Space 144 return VM.newGCspyServerSpace(server, // the server 145 spaceName, // space name 146 getDriverName(), // driver (space) name 147 "Block ", // space title 148 tmp, // block info 149 maxTileNum, // number of tiles 150 "UNUSED", // the label for unused blocks 151 mainSpace); // main space 152 } 153 154 /** 155 * Get the name of this driver type. 156 * @return The name of this driver. 157 */ 158 protected abstract String getDriverName(); 159 160 /** 161 * Get the maximum number of tiles in this space. 162 * @return the maximum number of tiles in the space. 163 */ 164 public int getMaxTileNum() { 165 return maxTileNum; 166 } 167 168 /** 169 * The GCspy space managed by this driver. 170 * @return the GCspy server space. 171 */ 172 public ServerSpace getServerSpace() { 173 return serverSpace; 174 } 175 176 /** 177 * Add a stream to the driver. This also sets the stream's id 178 * (unique for this space). 179 * @param stream The stream 180 * @exception IndexOutOfBoundsException if more than MAX_STREAMS are added 181 */ 182 @Interruptible 183 public void addStream(Stream stream) { 184 int id = 0; 185 while (id < MAX_STREAMS) { 186 if (streams[id] == null) { 187 streams[id] = stream; 188 if (DEBUG) { 189 Log.write("Adding stream with id="); 190 Log.writeln(id); 191 } 192 Address stream_ = serverSpace.addStream(id); 193 stream.setStream(id, stream_); 194 return; 195 } 196 id++; 197 } 198 throw new IndexOutOfBoundsException("Too many streams added to driver " + name); 199 } 200 201 /** 202 * Count number of tiles in an address range. 203 * @param start The start of the range. 204 * @param end The end of the range. 205 * @param tileSize The size of each tile. 206 * @return The number of tiles in this range. 207 */ 208 protected int countTileNum(Address start, Address end, int tileSize) { 209 if (end.LE(start)) return 0; 210 int diff = end.diff(start).toInt(); 211 return countTileNum(diff, tileSize); 212 } 213 214 /** 215 * Count number of tiles in an address range. 216 * @param extent The extent of the range. 217 * @param tileSize The size of each tile. 218 * @return The number of tiles in this range. 219 */ 220 protected int countTileNum(Extent extent, int tileSize) { 221 int diff = extent.toInt(); 222 return countTileNum(diff, tileSize); 223 } 224 225 private int countTileNum(int diff, int tileSize) { 226 int tiles = diff / tileSize; 227 if ((diff % tileSize) != 0) 228 ++tiles; 229 return tiles; 230 } 231 232 /** 233 * Indicate the limits of a space. 234 * 235 * @param start the Address of the start of the space. 236 * @param end the Address of the end of the space. 237 */ 238 public void setRange(Address start, Address end) {} 239 240 /** 241 * Indicate the limits of a space. 242 * 243 * @param start the Address of the start of the space. 244 * @param extent the extent of the space. 245 */ 246 public void setRange(Address start, Extent extent) { 247 setRange(start, start.plus(extent)); 248 } 249 250 /** 251 * Setup the tile names in a subspace. Tile names are typically 252 * address ranges but may be anything (e.g. a size class if the 253 * space is a segregated free-list manager, or a class name if the 254 * space represents the class instances loaded). 255 * 256 * @param subspace the Subspace 257 * @param numTiles the number of tiles to name 258 */ 259 protected void setTilenames(Subspace subspace, int numTiles) { 260 Address start = subspace.getStart(); 261 int first = subspace.getFirstIndex(); 262 int bs = subspace.getBlockSize(); 263 264 for (int i = 0; i < numTiles; ++i) { 265 if (subspace.indexInRange(i)) 266 serverSpace.setTilename(i, start.plus((i - first) * bs), 267 start.plus((i + 1 - first) * bs)); 268 } 269 } 270 271 /** 272 * The "typical" maximum number of objects in each tile. 273 * @param blockSize The size of a tile 274 * @return The maximum number of objects in a tile 275 */ 276 public int maxObjectsPerBlock(int blockSize) { 277 // Maybe a misuse of ServerInterpreter but it's a convenient 278 // VM-dependent class 279 return blockSize / GCspy.server.computeHeaderSize(); 280 } 281 282 /** 283 * @param event The current event 284 * @return whether the server is connected to a GCspy client 285 */ 286 public boolean isConnected(int event) { 287 return server.isConnected(event); 288 } 289 290 /** 291 * Reset the statistics for a space. 292 * In this base driver, we simply note that the data has changed. 293 */ 294 protected void resetData() { 295 changed = true; 296 } 297 298 /** 299 * Scan an object found at a location. 300 * Collectors typically call this method to update GCspy statistics. 301 * The driver may or may not accumulate values found, depending on 302 * the value of total. 303 * @param obj the reference to the object found 304 * @param total Whether to total the statistics 305 */ 306 public void scan(ObjectReference obj, boolean total) {} 307 308 /** 309 * Scan an object found at a location. 310 * Collectors typically call this method to update GCspy statistics 311 * The driver will accumulate values found. 312 * @param obj the reference to the object found 313 */ 314 public void scan(ObjectReference obj) { 315 scan(obj, true); 316 } 317 318 /** 319 * Scan an object found at a location. 320 * Collectors typically call this method to update GCspy statistics. 321 * The driver may or may not accumulate values found, depending on 322 * the value of total. 323 * @param obj the reference to the object found 324 * @param total Whether to total the statistics 325 */ 326 public void scan(Address obj, boolean total) {} 327 328 /** 329 * Scan an object found at a location. 330 * Collectors typically call this method to update GCspy statistics 331 * The driver will accumulate values found. 332 * @param obj the reference to the object found 333 */ 334 public void scan(Address obj) {} 335 336 /** 337 * Handle a direct reference from the immortal space.<p> 338 * This is an empty implementation. Subclasses may override this method 339 * to increment their <code>refFromImmortal</code> Stream. 340 * 341 * @param addr The Address 342 * @return {@code true} if the given Address is in this subspace. Always {@code false} here. 343 */ 344 public boolean handleReferenceFromImmortalSpace(Address addr) { 345 return false; 346 } 347 348 /** 349 * Set space info. 350 * This simply reports the size of the current space. 351 * Drivers that want to send something more complex than 352 * "Current Size: size\n" 353 * must override this method. 354 * 355 * @param size the size of the space 356 */ 357 protected void setSpaceInfo(Offset size) { 358 // - sprintf(tmp, "Current Size: %s\n", gcspy_formatSize(size)); 359 Address tmp = GCspy.util.formatSize("Current Size: %s\n", 128, size.toInt()); 360 serverSpace.spaceInfo(tmp); 361 GCspy.util.free(tmp); 362 } 363 364 365 /**************************************************************************** 366 * 367 * Control values 368 */ 369 370 /** 371 * Is a tile used? 372 * @param val the control value. 373 * @return {@code true} if the tile is used 374 */ 375 protected static boolean controlIsUsed(byte val) { 376 return (val & CONTROL_USED) != 0; 377 } 378 379 /** 380 * Is a tile a background pseudo-tile? 381 * @param val the control value. 382 * @return {@code true} if the tile is a background tile 383 */ 384 protected static boolean controlIsBackground(byte val) { 385 return (val & CONTROL_BACKGROUND) != 0; 386 } 387 388 /** 389 * Is a tile unused? 390 * @param val the control value. 391 * @return {@code true} if the tile is unused 392 */ 393 protected static boolean controlIsUnused(byte val) { 394 return (val & CONTROL_UNUSED) != 0; 395 } 396 397 /** 398 * Is this a separator? 399 * @param val the control value. 400 * @return {@code true} if this is a separator 401 */ 402 protected static boolean controlIsSeparator(byte val) { 403 return (val & CONTROL_SEPARATOR) != 0; 404 } 405 406 /** 407 * Initialise the value of a control. 408 * @param index The index of the tile. 409 * @param value The new value of the control 410 */ 411 protected void initControl(int index, byte value) { 412 control[index] = value; 413 } 414 415 /** 416 * Add a control to the tile 417 * @param index The index of the tile. 418 * @param value The control to add. 419 */ 420 protected void addControl(int index, byte value) { 421 control[index] |= value; 422 } 423 424 /** Set the control 425 * @param index the index of the tile 426 * @param value The value to set 427 */ 428 protected void setControl(int index, byte value) { 429 control[index] &= value; 430 } 431 432 /** 433 * Get the controls for a tile. 434 * @param index The index of the tile. 435 * @return The value of the controls 436 */ 437 public byte getControl(int index) { 438 return control[index]; 439 } 440 441 /** 442 * Initialise control values in all tiles 443 */ 444 protected void initControls() { 445 for (int index = 0; index < control.length; ++index) { 446 initControl(index, CONTROL_USED); 447 } 448 } 449 450 /** 451 * Set the control value in each tile in a region. 452 * @param tag The control tag. 453 * @param start The start index of the region. 454 * @param len The number of tiles in the region. 455 */ 456 protected void controlValues(byte tag, int start, int len) { 457 if (DEBUG) { 458 Log.write("AbstractDriver.controlValues for space "); 459 Log.write(name); 460 Log.write(", control length=", control.length); 461 Log.write(" writing controls from ", start); 462 Log.writeln(" to ", start + len); 463 } 464 changed = true; 465 for (int i = start; i < (start + len); ++i) { 466 // Cannot be both USED and UNUSED or BACKGROUND 467 if (controlIsBackground(tag) || controlIsUnused(tag)) 468 setControl(i, (byte)~CONTROL_USED); 469 else if (controlIsUsed(tag)) 470 setControl(i, (byte)~CONTROL_UNUSED); 471 addControl(i, tag); 472 } 473 } 474 475 /** 476 * Transmit the streams for this space. A driver will typically 477 * <ol> 478 * <li> Determine whether a GCspy client is connected and interested in 479 * this event, e.g. 480 * <pre>server.isConnected(event)</pre> 481 * <li> Setup the summaries for each stream, e.g. 482 * <pre>stream.setSummary(values...);</pre> 483 * <li> Setup the control information for each tile. e.g. 484 * <pre>controlValues(CONTROL_USED, start, numBlocks);</pre> 485 * <pre>controlValues(CONTROL_UNUSED, end, remainingBlocks);</pre> 486 * <li> Set up the space information, e.g. 487 * <pre>setSpace(info);</pre> 488 * <li> Send the data for all streams, e.g. 489 * <pre>send(event, numTiles);</pre> 490 * Note that AbstractDriver.send takes care of sending the information 491 * for all streams (including control data). 492 * </ol> 493 * 494 * @param event The event 495 */ 496 public abstract void transmit(int event); 497 498 /** 499 * Send all the streams for this space if it has changed. 500 * Assume that the data has been gathered and that summary info 501 * and control values have been set before this is called. 502 * 503 * @param event the event 504 * @param numTiles the number of blocks in this space 505 */ 506 protected void send(int event, int numTiles) { 507 if (changed) { 508 serverSpace.startCommunication(); 509 for (int i = 0; i < MAX_STREAMS; i++) 510 if (streams[i] != null) 511 streams[i].send(event, numTiles); 512 serverSpace.sendControls(this, numTiles); 513 serverSpace.endCommunication(); 514 } 515 } 516}