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 }