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.plan.semispace.gcspy;
014
015 import org.mmtk.plan.Phase;
016 import org.mmtk.plan.semispace.SSMutator;
017 import org.mmtk.policy.CopySpace;
018 import org.mmtk.policy.Space;
019 import org.mmtk.policy.ImmortalLocal;
020 import org.mmtk.utility.Log;
021 import org.mmtk.utility.alloc.BumpPointer;
022 import org.mmtk.utility.alloc.Allocator;
023 import org.mmtk.utility.gcspy.GCspy;
024 import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
025
026 import org.vmmagic.pragma.*;
027 import org.vmmagic.unboxed.*;
028
029 /**
030 * This class implements <i>per-mutator thread</i> behavior and state for the
031 * <i>SSGCspy</i> plan.
032 *
033 * See {@link SSGCspy} for an overview of the GC-spy mechanisms.
034 * <p>
035 *
036 * @see SSMutator
037 * @see SSGCspy
038 * @see SSGCspyCollector
039 * @see org.mmtk.plan.StopTheWorldMutator
040 * @see org.mmtk.plan.MutatorContext
041 */
042 @Uninterruptible public class SSGCspyMutator extends SSMutator {
043
044 /*****************************************************************************
045 * Instance fields
046 */
047
048 private static final boolean DEBUG = false;
049
050 private static final boolean LOS_TOSPACE = true; // gather from tospace
051 private static final boolean LOS_FROMSPACE = false; // gather from fromspace
052
053 /** Per-mutator allocator into GCspy's space */
054 private BumpPointer gcspy = new ImmortalLocal(SSGCspy.gcspySpace);
055
056
057
058 /*****************************************************************************
059 *
060 * Mutator-time allocation
061 */
062
063 /**
064 * Allocate space (for an object)
065 *
066 * @param bytes The size of the space to be allocated (in bytes)
067 * @param align The requested alignment.
068 * @param offset The alignment offset.
069 * @param allocator The allocator number to be used for this allocation
070 * @param site Allocation site
071 * @return The address of the first byte of the allocated region
072 */
073 @Inline
074 public Address alloc(int bytes, int align, int offset, int allocator, int site) {
075 if (allocator == SSGCspy.ALLOC_GCSPY)
076 return gcspy.alloc(bytes, align, offset);
077 else
078 return super.alloc(bytes, align, offset, allocator, site);
079 }
080
081 /**
082 * Perform post-allocation actions. For many allocators none are required.
083 *
084 * @param object The newly allocated object
085 * @param typeRef The type reference for the instance being created
086 * @param bytes The size of the space to be allocated (in bytes)
087 * @param allocator The allocator number to be used for this allocation
088 */
089 @Inline
090 public void postAlloc(ObjectReference object, ObjectReference typeRef,
091 int bytes, int allocator) {
092 if (allocator == SSGCspy.ALLOC_GCSPY)
093 SSGCspy.gcspySpace.initializeHeader(object);
094 else
095 super.postAlloc(object, typeRef, bytes, allocator);
096 }
097
098 /**
099 * Return the allocator instance associated with a space
100 * <code>space</code>, for this plan instance.
101 *
102 * @param space The space for which the allocator instance is desired.
103 * @return The allocator instance associated with this plan instance
104 * which is allocating into <code>space</code>, or <code>null</code>
105 * if no appropriate allocator can be established.
106 */
107 public Allocator getAllocatorFromSpace(Space space) {
108 if (space == SSGCspy.gcspySpace) return gcspy;
109 return super.getAllocatorFromSpace(space);
110 }
111
112 /*****************************************************************************
113 *
114 * Collection
115 */
116
117 /**
118 * Perform a per-mutator collection phase.
119 * Before a collection, we need to discover
120 * <ul>
121 * <li>the tospace objects copied by the collector in the last GC cycle
122 * <li>the ojects allocated since by the mutator.
123 * <li>all immortal objects allocated by the mutator
124 * <li>all large objects allocated by the mutator
125 * </ul>
126 * After the semispace has been copied, we need to discover
127 * <ul>
128 * <li>the tospace objects copied by the collector
129 * <li>all immortal objects allocated by the mutator
130 * <li>all large objects allocated by the mutator
131 * </ul>
132 */
133 @Inline
134 public final void collectionPhase(short phaseId, boolean primary) {
135 if (DEBUG) { Log.write("--Phase Mutator."); Log.writeln(Phase.getName(phaseId)); }
136
137 // TODO do we need to worry any longer about primary??
138 if (phaseId == SSGCspy.PREPARE) {
139 //if (primary)
140 gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
141 super.collectionPhase(phaseId, primary);
142 return;
143 }
144
145 if (phaseId == SSGCspy.RELEASE) {
146 //if (primary)
147 gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
148 super.collectionPhase(phaseId, primary);
149 //if (primary)
150 gcspyGatherData(SSGCspy.AFTER_COLLECTION);
151 return;
152 }
153
154 super.collectionPhase(phaseId, primary);
155 }
156
157 /**
158 * Gather data for GCspy for the semispaces, the immortal space and the large
159 * object space.
160 * <p>
161 * This method sweeps the semispace under consideration to gather data.
162 * Alternatively and more efficiently, 'used space' can obviously be
163 * discovered in constant time simply by comparing the start and the end
164 * addresses of the semispace. However, per-object information can only be
165 * gathered by sweeping through the space and we do this here for tutorial
166 * purposes.
167 *
168 * @param event
169 * The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
170 * AFTER_COLLECTION
171 */
172 private void gcspyGatherData(int event) {
173 if(DEBUG) {
174 Log.writeln("SSGCspyMutator.gcspyGatherData, event=", event);
175 Log.writeln("SSGCspyMutator.gcspyGatherData, port=", GCspy.getGCspyPort());
176 }
177
178 // If port = 0 there can be no GCspy client connected
179 if (GCspy.getGCspyPort() == 0)
180 return;
181
182 // If the server is connected to a client that is interested in this
183 // event, then we gather data. But first we start a timer to
184 // compensate for the time spent gathering data here.
185 if (GCspy.server.isConnected(event)) {
186
187 if (DEBUG) {
188 if (SSGCspy.hi)
189 Log.write("\nMutator Examining Lowspace (event ", event);
190 else
191 Log.write("\nMutator Examining Highspace (event ", event);
192 Log.write(")");
193 SSGCspy.reportSpaces(); Log.writeln();
194 }
195
196 if (event == SSGCspy.BEFORE_COLLECTION) {
197 // Before the flip
198 // Mutator has not rebound toSpace yet
199 GCspy.server.startCompensationTimer();
200
201 // -- Handle the semispaces
202 // Here I need to scan newly allocated objects
203 if (DEBUG) {
204 //debugSpaces(SSGCspy.fromSpace());
205 debugSpaces(SSGCspy.toSpace());
206 Log.write("SSGCspyMutator.gcspyGatherData reset, gather and transmit driver ");
207 //Log.writeln(SSGCspy.fromSpace().getName());
208 Log.writeln(SSGCspy.toSpace().getName());
209 }
210 //ss.gcspyGatherData(fromSpaceDriver(), SSGCspy.fromSpace());
211 ss.gcspyGatherData(toSpaceDriver(), SSGCspy.toSpace());
212
213 // -- Handle the immortal space --
214 gatherImmortal(event);
215
216 // -- Handle the LOSes
217
218 // reset, collect and scan los data for the nursery and tospace
219 SSGCspy.losNurseryDriver.resetData();
220 los.gcspyGatherData(event, SSGCspy.losNurseryDriver);
221 SSGCspy.losDriver.resetData();
222 los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
223
224 // transmit the data
225 GCspy.server.stopCompensationTimer();
226 //fromSpaceDriver().transmit(event);
227 toSpaceDriver().transmit(event);
228 SSGCspy.immortalDriver.transmit(event);
229 SSGCspy.losNurseryDriver.transmit(event);
230 SSGCspy.losDriver.transmit(event);
231 SSGCspy.plosNurseryDriver.transmit(event);
232 SSGCspy.plosDriver.transmit(event);
233
234 // As this follows Collector.gcspyGatherData, I'll safepoint here
235 // This is a safepoint for the server, i.e. it is a point at which
236 // the server can pause.
237 GCspy.server.serverSafepoint(event);
238 } else if (event == SSGCspy.SEMISPACE_COPIED) {
239 // We have flipped
240 // toSpace still has not been rebound
241
242 // -- Handle the semispaces
243 if (DEBUG) {
244 //debugSpaces(SSGCspy.toSpace());
245 debugSpaces(SSGCspy.fromSpace());
246 Log.writeln("SSGCspyMutator.gcspyGatherData: do nothing");
247 }
248
249 // -- Handle the immortal space --
250 GCspy.server.startCompensationTimer();
251 gatherImmortal(event);
252
253 // reset, scan and send the los for the nursery and tospace
254 // and fromspace as well if full heap collection
255 SSGCspy.losNurseryDriver.resetData();
256 los.gcspyGatherData(event, SSGCspy.losNurseryDriver);
257 SSGCspy.losDriver.resetData();
258 los.gcspyGatherData(event, SSGCspy.losDriver, LOS_FROMSPACE);
259 los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
260
261 // transmit
262 GCspy.server.stopCompensationTimer();
263 SSGCspy.immortalDriver.transmit(event);
264 SSGCspy.losNurseryDriver.transmit(event);
265 SSGCspy.losDriver.transmit(event);
266 SSGCspy.plosNurseryDriver.transmit(event);
267 SSGCspy.plosDriver.transmit(event);
268
269 // As this follows Collector.gcspyGatherData, I'll safepoint here
270 // This is a safepoint for the server, i.e. it is a point at which
271 // the server can pause.
272 GCspy.server.serverSafepoint(event);
273 } else if (event == SSGCspy.AFTER_COLLECTION) {
274 // We have flipped
275 // And toSpace has been rebound
276
277 GCspy.server.startCompensationTimer();
278
279 // -- Handle the semispaces
280 if (DEBUG) debugSpaces(SSGCspy.toSpace());
281
282 // -- Handle the immortal space --
283 gatherImmortal(event);
284
285 // -- Handle the LOSes
286
287 // reset, scan and send the los
288 SSGCspy.losNurseryDriver.resetData();
289 SSGCspy.losDriver.resetData();
290 // no need to scan empty nursery
291 los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
292
293 //transmit
294 GCspy.server.stopCompensationTimer();
295 SSGCspy.immortalDriver.transmit(event);
296 SSGCspy.losNurseryDriver.transmit(event);
297 SSGCspy.losDriver.transmit(event);
298 SSGCspy.plosNurseryDriver.transmit(event);
299 SSGCspy.plosDriver.transmit(event);
300
301 // Reset fromspace
302 if (DEBUG) {
303 Log.write("SSGCspyMutator.gcspyGatherData: reset and zero range for driver ");
304 Log.write(SSGCspy.toSpace().getName());
305 }
306 }
307
308 }
309 // else Log.write("not transmitting...");
310 }
311
312 /**
313 * Gather data for the immortal space
314 * @param event
315 * The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
316 * AFTER_COLLECTION
317 */
318 private void gatherImmortal(int event) {
319 // We want to do this at every GCspy event
320 if (DEBUG) {
321 Log.write("SSGCspyMutator.gcspyGatherData: gather data for immortal space ");
322 Log.write(SSGCspy.immortalSpace.getStart()); Log.writeln("-",immortal.getCursor());
323 }
324 SSGCspy.immortalDriver.resetData();
325 immortal.gcspyGatherData(SSGCspy.immortalDriver);
326 if (DEBUG) Log.writeln("Finished immortal space.");
327 }
328
329 /**
330 * Debugging info for the semispaces
331 * @param scannedSpace the space to output debug for.
332 */
333 private void debugSpaces(CopySpace scannedSpace) {
334 Log.write("SSGCspyMutator.gcspyGatherData: gather data for active semispace ");
335 Log.write(scannedSpace.getStart()); Log.write("-",ss.getCursor()); Log.flush();
336 Log.write(". The space is: "); Log.writeln(ss.getSpace().getName());
337 Log.write("scannedSpace is "); Log.writeln(scannedSpace.getName());
338 Log.write("The range is "); Log.write(ss.getSpace().getStart());
339 Log.write(" to "); Log.writeln(ss.getCursor());
340 SSGCspy.reportSpaces();
341 }
342
343 /** @return the driver for toSpace */
344 private LinearSpaceDriver toSpaceDriver() {
345 return SSGCspy.hi ? SSGCspy.ss1Driver : SSGCspy.ss0Driver;
346 }
347
348 }