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.SS;
017    import org.mmtk.plan.semispace.SSCollector;
018    import org.mmtk.policy.CopySpace;
019    import org.mmtk.utility.Log;
020    import org.mmtk.utility.gcspy.GCspy;
021    import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
022    import org.mmtk.vm.VM;
023    
024    import org.vmmagic.unboxed.*;
025    import org.vmmagic.pragma.*;
026    
027    /**
028     * This class implements <i>per-collector thread</i> behavior and state for the
029     * <i>SSGCspy</i> plan.<p>
030     *
031     * See {@link SSGCspy} for an overview of the GC-spy mechanisms.<p>
032     *
033     * @see SSCollector
034     * @see SSGCspy
035     * @see SSGCspyMutator
036     * @see org.mmtk.plan.StopTheWorldCollector
037     * @see org.mmtk.plan.CollectorContext
038     * @see org.mmtk.plan.SimplePhase
039     */
040    @Uninterruptible public class SSGCspyCollector extends SSCollector {
041    
042      /****************************************************************************
043       *
044       * Initialization
045       */
046    
047      /*****************************************************************************
048       * Instance fields
049       */
050    
051      private static final boolean DEBUG = false;
052    
053      /**
054       * Constructor
055       */
056      public SSGCspyCollector() {
057        super(new SSGCspyTraceLocal(global().ssTrace));
058      }
059    
060    
061      /****************************************************************************
062       *
063       * Data gathering
064       */
065    
066      /**
067       * Perform a (local) collection phase.
068       * Before a collection, we need to discover
069       * <ul>
070       * <li>the tospace objects copied by the collector in the last GC cycle
071       * <li>the semispace objects allocated since by the mutator.
072       * <li>all immortal objects allocated by the mutator
073       * <li>all large objects allocated by the mutator
074       * </ul>
075       * After the semispace has been copied, we need to discover
076       * <ul>
077       * <li>the tospace objects copied by the collector
078       * <li>all immortal objects allocated by the mutator
079       * <li>all large objects allocated by the mutator
080       * </ul>
081       */
082      @Inline
083      public final void collectionPhase(short phaseId, boolean primary) {
084        if (DEBUG) { Log.write("--Phase Collector."); Log.writeln(Phase.getName(phaseId)); }
085    
086        //TODO do we need to worry any longer about primary??
087        if (phaseId == SS.PREPARE) {
088          //if (primary)
089            gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
090          super.collectionPhase(phaseId, primary);
091          return;
092        }
093    
094        if (phaseId == SS.FORWARD_FINALIZABLE) {
095          super.collectionPhase(phaseId, primary);
096          //if (primary)
097            gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
098          return;
099        }
100    
101        if (phaseId == SS.RELEASE) {
102          //if (primary)
103            //gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
104          super.collectionPhase(phaseId, primary);
105          //if (primary)
106            gcspyGatherData(SSGCspy.AFTER_COLLECTION);
107          return;
108        }
109    
110        super.collectionPhase(phaseId, primary);
111      }
112    
113      /**
114       * Gather data for GCspy for the semispaces only.
115       * <p>
116       * This method sweeps the semispace under consideration to gather data.
117       * Alternatively and more efficiently, 'used space' can obviously be
118       * discovered in constant time simply by comparing the start and the end
119       * addresses of the semispace. However, per-object information can only be
120       * gathered by sweeping through the space and we do this here for tutorial
121       * purposes.
122       *
123       * @param event
124       *          The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
125       *          AFTER_COLLECTION
126       */
127      private void gcspyGatherData(int event) {
128        if(DEBUG) {
129          Log.writeln("SSGCspyCollector.gcspyGatherData, event=", event);
130          Log.writeln("SSGCspyCollector.gcspyGatherData, port=", GCspy.getGCspyPort());
131        }
132    
133        // If port = 0 there can be no GCspy client connected
134        if (GCspy.getGCspyPort() == 0)
135          return;
136    
137        // If the server is connected to a client that is interested in this
138        // event, then we gather data. But first we start a timer to
139        // compensate for the time spent gathering data here.
140        if (GCspy.server.isConnected(event)) {
141    
142          if (DEBUG) {
143            if (SSGCspy.hi)
144              Log.write("\nCollector Examining Lowspace (event ", event);
145            else
146              Log.write("\nCollector Examining Highspace (event ", event);
147            Log.write(")");
148            SSGCspy.reportSpaces(); Log.writeln();
149          }
150    
151          if (event == SSGCspy.BEFORE_COLLECTION) {
152            if (DEBUG) debugSpaces(SSGCspy.fromSpace());
153    
154            // Just send the old values again
155            if (DEBUG) {
156              Log.write("SSGCspyCollector.gcspyGatherData transmit driver, ");
157              Log.writeln(SSGCspy.fromSpace().getName());
158            }
159    
160            fromSpaceDriver().transmit(event);
161            // Mutator.gcspyGatherData follows so leave safepoint to there.
162          } else if (event == SSGCspy.SEMISPACE_COPIED) {
163            if (DEBUG) debugSpaces(SSGCspy.toSpace());
164    
165            // We need to reset, scan and send values for tospace
166            // We'll leave resetting fromspace to AFTER_COLLECTION
167            if (DEBUG) {
168              Log.write("SSGCspyCollector.gcspyGatherData reset, gather and transmit driver ");
169              Log.writeln(SSGCspy.toSpace().getName());
170            }
171    
172            GCspy.server.startCompensationTimer();
173            toSpaceDriver().resetData();
174            ss.gcspyGatherData(toSpaceDriver(), SSGCspy.toSpace());
175            GCspy.server.stopCompensationTimer();
176            toSpaceDriver().transmit(event);
177    
178            // We'll leave the safepoint to RELEASE
179          } else if (event == SSGCspy.AFTER_COLLECTION) {
180            if (DEBUG) {
181              Log.write("SSGCspyCollector.gcspyGatherData transmit toSpaceDriver, ");
182              Log.writeln(SSGCspy.toSpace().getName());
183              Log.write("SSGCspyCollector.gcspyGatherData reset fromSpaceDriver, ");
184              Log.writeln(SSGCspy.fromSpace().getName());
185            }
186    
187            toSpaceDriver().transmit(event);
188    
189            // Here we reset fromspace data
190            fromSpaceDriver().resetData();
191            Address start = SSGCspy.fromSpace().getStart();
192            fromSpaceDriver().setRange(start, start);
193            fromSpaceDriver().transmit(event);
194          }
195    
196        }
197        // else Log.write("not transmitting...");
198      }
199    
200      /**
201       * Print some debugging info
202       * @param scannedSpace
203       */
204      private void debugSpaces(CopySpace scannedSpace) {
205        Log.write("SSGCspyCollector.gcspyGatherData: gather data for active semispace ");
206        Log.write(scannedSpace.getStart()); Log.write("-",ss.getCursor()); Log.flush();
207        Log.write(". The space is: "); Log.writeln(ss.getSpace().getName());
208        Log.write("scannedSpace is "); Log.writeln(scannedSpace.getName());
209        Log.write("The range is "); Log.write(ss.getSpace().getStart());
210        Log.write(" to "); Log.writeln(ss.getCursor());
211        SSGCspy.reportSpaces();
212      }
213    
214      /**
215       * Reset all root streams.<p>
216       */
217      void resetRootStreams() {
218        SSGCspy.ss0Driver.resetRootsStream();
219        SSGCspy.ss1Driver.resetRootsStream();
220        SSGCspy.immortalDriver.resetRootsStream();
221        SSGCspy.losNurseryDriver.resetRootsStream();
222        SSGCspy.losDriver.resetRootsStream();
223        SSGCspy.plosNurseryDriver.resetRootsStream();
224        SSGCspy.plosDriver.resetRootsStream();
225        ss.getCursor();
226      }
227    
228      /**
229       * Pass a root to all drivers.<p>
230       * @param addr The Address of the object to be checked
231       */
232      protected void checkAllDriversForRootAddress(Address addr) {
233        if(addr.isZero())
234          return;
235    
236        SSGCspy.ss0Driver.handleRoot(addr);
237        SSGCspy.ss1Driver.handleRoot(addr);
238        SSGCspy.immortalDriver.handleRoot(addr);
239        SSGCspy.losNurseryDriver.handleRoot(addr);
240        SSGCspy.losDriver.handleRoot(addr);
241        SSGCspy.plosNurseryDriver.handleRoot(addr);
242        SSGCspy.plosDriver.handleRoot(addr);
243      }
244    
245      /****************************************************************************
246       *
247       * Miscellaneous
248       */
249    
250      /** @return The active global plan as an <code>SSGCspy</code> instance. */
251      @Inline
252      private static SSGCspy global() {
253        return (SSGCspy) VM.activePlan.global();
254      }
255    
256      /** @return the driver for toSpace */
257      private LinearSpaceDriver toSpaceDriver() {
258        return SSGCspy.hi ? SSGCspy.ss1Driver : SSGCspy.ss0Driver;
259      }
260    
261      /** @return the driver for fromSpace */
262      private LinearSpaceDriver fromSpaceDriver() {
263        return SSGCspy.hi ? SSGCspy.ss0Driver : SSGCspy.ss1Driver;
264      }
265    }