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