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 }