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