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 }