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