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