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