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 static org.mmtk.utility.gcspy.StreamConstants.PAINT_STYLE_ZERO;
016import static org.mmtk.utility.gcspy.StreamConstants.PRESENTATION_PERCENT;
017import static org.mmtk.utility.gcspy.StreamConstants.PRESENTATION_PLUS;
018
019import org.mmtk.policy.LargeObjectSpace;
020import org.mmtk.utility.Conversions;
021import org.mmtk.utility.Log;
022import org.mmtk.utility.gcspy.Color;
023import org.mmtk.utility.gcspy.Subspace;
024import org.mmtk.vm.VM;
025import org.mmtk.vm.gcspy.IntStream;
026import org.mmtk.vm.gcspy.ServerInterpreter;
027import org.mmtk.vm.gcspy.ShortStream;
028import org.vmmagic.pragma.Interruptible;
029import org.vmmagic.pragma.Uninterruptible;
030import org.vmmagic.unboxed.Address;
031import org.vmmagic.unboxed.Offset;
032
033
034/**
035 * This class implements a simple driver for the MMTk LargeObjectSpace.
036 */
037@Uninterruptible public class TreadmillDriver extends AbstractDriver {
038
039  private static final boolean DEBUG = false;
040
041  // The streams
042  protected IntStream   usedSpaceStream;
043  protected ShortStream objectsStream;
044  protected ShortStream rootsStream;
045  protected ShortStream refFromImmortalStream;
046
047  protected Subspace subspace;            // A single subspace for this space
048  protected int allTileNum;               // total number of tiles
049
050  // Overall statistics
051  protected int totalObjects         = 0; // total number of objects allocated
052  protected int totalUsedSpace       = 0; // total space used
053  protected int totalRoots           = 0; // total of roots
054  protected int totalRefFromImmortal = 0; // total direct references from the immortal space
055  protected Address maxAddr;              // the largest address seen
056  protected int threshold;
057
058
059  /**
060   * Create a new driver for this collector
061   *
062   * @param server The name of the GCspy server that owns this space
063   * @param spaceName The name of this driver
064   * @param lospace the large object space for this allocator
065   * @param blockSize The tile size
066   * @param threshold the size threshold of the LOS
067   * @param mainSpace Is this the main space?
068   */
069  public TreadmillDriver(
070                         ServerInterpreter server,
071                         String spaceName,
072                         LargeObjectSpace lospace,
073                         int blockSize,
074                         int threshold,
075                         boolean mainSpace) {
076    //TODO blocksize should be a multiple of treadmill granularity
077    super(server, spaceName, lospace, blockSize, mainSpace);
078
079    if (DEBUG) {
080      Log.write("TreadmillDriver for "); Log.write(spaceName);
081      Log.write(", blocksize="); Log.write(blockSize);
082      Log.write(", start="); Log.write(lospace.getStart());
083      Log.write(", extent="); Log.write(lospace.getExtent());
084      Log.write(", maxTileNum="); Log.writeln(maxTileNum);
085    }
086
087    this.threshold = threshold;
088
089    // Initialise a subspace and 2 Streams
090    subspace = createSubspace(lospace);
091    allTileNum = 0;
092    maxAddr = lospace.getStart();
093    usedSpaceStream       = createUsedSpaceStream();
094    objectsStream         = createObjectsStream();
095    rootsStream           = createRootsStream();
096    refFromImmortalStream = createRefFromImmortalStream();
097    serverSpace.resize(0); // the collector must call resize() before gathering data
098
099    // Initialise the statistics
100    resetData();
101  }
102
103  /**
104   * @return The name, "MMTk TreadmillDriver" for this driver.
105   */
106  @Override
107  protected String getDriverName() {
108    return "MMTk TreadmillDriver";
109  }
110
111  // private creator methods for the streams
112  @Interruptible
113  private IntStream createUsedSpaceStream() {
114    return VM.newGCspyIntStream(
115                     this,
116                     "Used Space stream",                    // stream name
117                     0,                                      // min. data value
118                     blockSize,                              // max. data value
119                     0,                                      // zero value
120                     0,                                      // default value
121                    "Space used: ",                          // value prefix
122                    " bytes",                                // value suffix
123                     PRESENTATION_PERCENT,   // presentation style
124                     PAINT_STYLE_ZERO,       // paint style
125                     0,                                      // index of the max stream (only needed if presentation is *_VAR)
126                     Color.Red,                              // tile colour
127                     true);                                  // summary enabled
128  }
129
130  @Interruptible
131  private ShortStream createObjectsStream() {
132    return VM.newGCspyShortStream(
133                     this,
134                     "Objects stream",
135                     (short)0,
136                     (short)(blockSize / threshold),
137                     (short)0,
138                     (short)0,
139                     "No. of objects = ",
140                     " objects",
141                     PRESENTATION_PLUS,
142                     PAINT_STYLE_ZERO,
143                     0,
144                     Color.Green,
145                     true);
146  }
147
148  @Interruptible
149  private ShortStream createRootsStream() {
150    return VM.newGCspyShortStream(
151                     this,
152                     "Roots stream",
153                     (short)0,
154                     // Say, typical size = 4 * typical scalar size?
155                     (short)(maxObjectsPerBlock(blockSize) / 8),
156                     (short)0,
157                     (short)0,
158                     "Roots: ",
159                     " objects",
160                     PRESENTATION_PLUS,
161                     PAINT_STYLE_ZERO,
162                     0,
163                     Color.Blue,
164                     true);
165  }
166
167  @Interruptible
168  private ShortStream createRefFromImmortalStream() {
169    return VM.newGCspyShortStream(
170                     this,
171                     "References from Immortal stream",
172                     (short)0,
173                     // Say, typical size = 4 * typical scalar size?
174                     (short)(maxObjectsPerBlock(blockSize) / 8),
175                     (short)0,
176                     (short)0,
177                     "References from immortal space: ",
178                     " references",
179                     PRESENTATION_PLUS,
180                     PAINT_STYLE_ZERO,
181                     0,
182                     Color.Blue,
183                     true);
184  }
185
186  /**
187   * Reset the tile stats for all streams, including values used for summaries
188   */
189  @Override
190  public void resetData() {
191    super.resetData();
192
193    // Reset all the streams
194    usedSpaceStream.resetData();
195    objectsStream.resetData();
196    refFromImmortalStream.resetData();
197
198    // Reset the summary counts
199    totalUsedSpace = 0;
200    totalObjects = 0;
201    totalRefFromImmortal = 0;
202  }
203
204
205  /**
206   * Update the tile statistics
207   * In this case, we are accounting for super-page objects, rather than
208   * simply for the objects they contain.
209   *
210   * @param addr The address of the superpage
211   */
212  @Override
213  public void scan(Address addr) {
214
215    int index = subspace.getIndex(addr);
216    int length = ((LargeObjectSpace)mmtkSpace).getSize(addr).toInt();
217
218    if (DEBUG) {
219      Log.write("TreadmillDriver: super=", addr);
220      Log.write(", index=", index);
221      Log.write(", pages=", length);
222      Log.write(", bytes=", Conversions.pagesToBytes(length).toInt());
223      Log.writeln(", max=", usedSpaceStream.getMaxValue());
224    }
225
226    totalObjects++;
227    totalUsedSpace += length;
228    objectsStream.increment(index, (short)1);
229    int remainder = subspace.spaceRemaining(addr);
230    usedSpaceStream.distribute(index, remainder, blockSize, length);
231
232    Address tmp = addr.plus(length);
233    if (tmp.GT(maxAddr)) maxAddr = tmp;
234  }
235
236  /**
237   * Transmit the data if this event is of interest to the client
238   * @param event The event, either BEFORE_COLLECTION, SEMISPACE_COPIED
239   * or AFTER_COLLECTION
240   */
241  @Override
242  public void transmit(int event) {
243    if (!isConnected(event))
244      return;
245
246    // At this point, we've filled the tiles with data,
247    // however, we don't know the size of the space
248    // Calculate the highest indexed tile used so far, and update the subspace
249    Address start = subspace.getStart();
250    int required = countTileNum(start, maxAddr, blockSize);
251    int current = subspace.getBlockNum();
252    if (required > current || maxAddr.NE(subspace.getEnd())) {
253      subspace.reset(start, maxAddr, 0, required);
254      allTileNum = required;
255      serverSpace.resize(allTileNum);
256      setTilenames(subspace, allTileNum);
257    }
258
259    // Set the summaries
260    setupSummaries();
261
262    // set the control info: all of space is USED
263    controlValues(CONTROL_USED,
264                  subspace.getFirstIndex(), subspace.getBlockNum());
265
266    // send the space info
267    Offset size = subspace.getEnd().diff(subspace.getStart());
268    setSpaceInfo(size);
269
270    // Send the streams
271    send(event, allTileNum);
272  }
273
274  /**
275   * Setup summaries part of the <code>transmit</code> method.<p>
276   * Override this method to setup summaries of additional streams in subclasses.
277   */
278  protected void setupSummaries() {
279    usedSpaceStream.setSummary(totalUsedSpace,
280                               subspace.getEnd().diff(subspace.getStart()).toInt());
281    objectsStream.setSummary(totalObjects);
282    rootsStream.setSummary(totalRoots);
283    refFromImmortalStream.setSummary(totalRefFromImmortal);
284  }
285
286
287  /**
288   * Handle a root address
289   *
290   * @param addr Root Address
291   * @return {@code true} if the given Address is in this subspace.
292   */
293  public boolean handleRoot(Address addr) {
294    if (subspace.addressInRange(addr)) {
295      // increment tile
296      int index = subspace.getIndex(addr);
297      rootsStream.increment(index, (short)1);
298      // increment summary
299      this.totalRoots++;
300      return true;
301    } else {
302      return false;
303    }
304  }
305
306  /**
307   * Reset the roots Stream. <br>
308   * The roots Stream has to be reset separately because we do not
309   * gather data in the usual way using <code>scan()</code>.
310   */
311  public void resetRootsStream() {
312    rootsStream.resetData();
313    totalRoots = 0;
314  }
315
316  /**
317   * Handle a direct reference from the immortal space.
318   *
319   * @param addr The Address
320   * @return {@code true} if the given Address is in this subspace.
321   */
322  @Override
323  public boolean handleReferenceFromImmortalSpace(Address addr) {
324    if (subspace.addressInRange(addr)) {
325      // increment tile
326      int index = subspace.getIndex(addr);
327      refFromImmortalStream.increment(index, (short)1);
328      // increment summary
329      this.totalRefFromImmortal++;
330      return true;
331    } else {
332      return false;
333    }
334  }
335}