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