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 }