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.GCspyPlan;
016    import org.mmtk.plan.Phase;
017    import org.mmtk.plan.TransitiveClosure;
018    import org.mmtk.plan.semispace.SS;
019    import org.mmtk.policy.CopySpace;
020    import org.mmtk.policy.LargeObjectSpace;
021    import org.mmtk.utility.gcspy.drivers.AbstractDriver;
022    import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
023    import org.mmtk.utility.gcspy.drivers.ImmortalSpaceDriver;
024    import org.mmtk.utility.gcspy.drivers.TreadmillDriver;
025    import org.mmtk.utility.gcspy.GCspy;
026    import org.mmtk.utility.Log;
027    import org.mmtk.utility.options.Options;
028    
029    import org.vmmagic.pragma.*;
030    
031    /**
032     * This class extends a simple semi-space collector to instrument it for
033     * GCspy. <p>
034     *
035     * See the Jones & Lins GC book, section 2.2 for an overview of the basic
036     * algorithm. This implementation also includes a large object space
037     * (LOS), and an uncollected "immortal" space.<p>
038     *
039     * All plans make a clear distinction between <i>global</i> and
040     * <i>thread-local</i> activities.  Global activities must be
041     * synchronized, whereas no synchronization is required for
042     * thread-local activities.  Instances of Plan map 1:1 to "kernel
043     * threads" (aka CPUs).  Thus instance
044     * methods allow fast, unsychronized access to Plan utilities such as
045     * allocation and collection.  Each instance rests on static resources
046     * (such as memory and virtual memory resources) which are "global"
047     * and therefore "static" members of Plan.  This mapping of threads to
048     * instances is crucial to understanding the correctness and
049     * performance proprties of this plan.
050     * <p>
051     * FIXME This seems to have changed
052     * The order of phases and GCspy actions is important here. It is:
053     * <pre>
054     *   PREPARE phase
055     *      SSGCspyMutator.gcspyGatherData(SSGCspy.BEFORE_COLLECTION); // safepoint
056     *      SSMutator.PREPARE // FIXME DOES NOT ss.rebind(SS.toSpace());
057     *
058     *   PREPARE phase
059     *      SS.PREPARE // flip semispaces
060     *      gcspySpace.prepare();
061     *      SSGCspyCollector.gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
062     *      SSCollector.PREPARE // ss.rebind(SS.toSpace());
063     *
064     *
065     *   FORWARD_FINALIZABLE phase
066     *      SSCollector.FORWARD_FINALIZABLE
067     *      SSGCspyCollector.gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
068     *
069     *   RELEASE phase
070     *      SSGCspyMutator.gcspyGatherData(SSGCspy.SEMISPACE_COPIED); // safepoint
071     *      SSMutator.RELEASE // FIXME ss.rebind(SS.toSpace());
072     *      SSGCspyMutator.gcspyGatherData(SSGCspy.AFTER_COLLECTION);
073     *
074     *   RELEASE phase
075     *      SSCollector.RELEASE
076     *      SSGCspyCollector.gcspyGatherData(SSGCspy.AFTER_COLLECTION);
077     *      SS.RELEASE
078     *      gcspySpace.release();
079     *      SSGCspy.gcspyGatherData(); // safepoint
080     *</pre>
081     * Note that SSMutator has changed the point at which it rebinds toSpace
082     * from PREPARE (2.4.6) to after RELEASE (3.x.x).
083     *<pre>
084     --Phase Collector.initiate
085     --Phase Mutator.initiate-mutator
086     --Phase Mutator.prepare-mutator
087         SSGCspyMutator.gcspyGatherData, event=0
088     --Phase Plan.prepare
089     --Phase Collector.prepare
090         SSGCspyCollector.gcspyGatherData, event=0
091     --Phase Collector.bootimage-root
092     --Phase Collector.root
093     --Phase Plan.root
094     --Phase Collector.start-closure
095     --Phase Collector.soft-ref
096     --Phase Collector.complete-closure
097     --Phase Collector.weak-ref
098     --Phase Collector.finalize
099     --Phase Collector.complete-closure
100     --Phase Collector.phantom-ref
101     --Phase Collector.forward-ref
102     --Phase Collector.forward-finalize
103         SSGCspyCollector.gcspyGatherData, event=1
104     --Phase Mutator.release-mutator
105         SSGCspyMutator.gcspyGatherData, event=1
106         SSGCspyMutator.gcspyGatherData, event=2
107     --Phase Collector.release
108         SSGCspyCollector.gcspyGatherData, event=2
109     --Phase Plan.release
110         SSGCspy.gcspyGatherData, event=2
111     --Phase Collector.complete
112     --Phase Plan.complete
113     </pre>
114     */
115    @Uninterruptible public class SSGCspy extends SS implements GCspyPlan {
116    
117      /****************************************************************************
118       *
119       * Class variables
120       */
121    
122      // The events, BEFORE_COLLECTION, SEMISPACE_COPIED or AFTER_COLLECTION
123    
124      /**
125       * Before a collection has started,
126       * i.e. before SS.collectionPhase(SS.PREPARE,..).
127       */
128      static final int BEFORE_COLLECTION = 0;
129    
130      /**
131       * After the semispace has been copied and the large object space has been traced
132       * At this time the Large Object Space has not been swept.
133       */
134      static final int SEMISPACE_COPIED  = BEFORE_COLLECTION + 1;
135    
136      /**
137       * The collection is complete,
138       * i.e. immediately after SS.collectionPhase(SS.RELEASE,..).
139       * The Large Object Space has been swept.
140       */
141      static final int AFTER_COLLECTION  = SEMISPACE_COPIED + 1;
142    
143      static int gcspyEvent_ = BEFORE_COLLECTION;
144    
145      // The specific drivers for this collector
146      static LinearSpaceDriver ss0Driver;
147      static LinearSpaceDriver ss1Driver;
148      static ImmortalSpaceDriver immortalDriver;
149      static TreadmillDriver losNurseryDriver;
150      static TreadmillDriver losDriver;
151      static TreadmillDriver plosNurseryDriver;
152      static TreadmillDriver plosDriver;
153    
154      private static final boolean DEBUG = false;
155    
156    
157      static {
158        GCspy.createOptions();
159      }
160    
161      /**
162       * Start the server and wait if necessary.
163       * This method has the following responsibilities.
164       * <ol>
165       * <li> Create and initialise the GCspy server by calling.
166       *      <pre>server = ServerInterpreter.init(name, portNumber, verbose);</pre>
167       * <li> Add each event to the ServerInterpreter
168       *      <pre>server.addEvent(eventID, eventName);</pre>
169       * <li> Set some general information about the server (e.g. name of the collector, build, etc).
170       *      <pre>server.setGeneralInfo(info); </pre>
171       * <li> Create new drivers for each component to be visualised.
172       *      <pre>myDriver = new MyDriver(server, args...);</pre>
173       *      Drivers extend AbstractDriver and register their spce with the
174       *      ServerInterpreter. In addition to the server, drivers will take as
175       *      arguments the name of the space, the MMTk space, the tilesize, and
176       *      whether this space is to be the main space in the visualiser.
177       * </ol>
178       *
179       * WARNING: allocates memory.
180       * @param wait Whether to wait
181       * @param port The port to talk to the GCspy client (e.g. visualiser)
182       */
183      @Override
184      @Interruptible
185      public final void startGCspyServer(int port, boolean wait) {
186        GCspy.server.init("SemiSpaceServerInterpreter", port, true/*verbose*/);
187        if (DEBUG) Log.writeln("SSGCspy: ServerInterpreter initialised");
188    
189        GCspy.server.addEvent(BEFORE_COLLECTION, "Before collection");
190        GCspy.server.addEvent(SEMISPACE_COPIED, "Semispace copied; LOS traced");
191        GCspy.server.addEvent(AFTER_COLLECTION, "After collection; LOS swept");
192        GCspy.server.setGeneralInfo(
193            "SSGCspy\n\nRichard Jones, October 2006\\http://www.cs.kent.ac.uk/~rej/");
194        if (DEBUG) Log.writeln("SSGCspy: events added to ServerInterpreter");
195    
196        // Initialise each driver
197        ss0Driver      = newLinearSpaceDriver("Semispace 0 Space", copySpace0, true);
198        ss1Driver      = newLinearSpaceDriver("Semispace 1 Space", copySpace1, false);
199        immortalDriver = new ImmortalSpaceDriver(
200                             GCspy.server,  "Immortal Space", immortalSpace,
201                             Options.gcspyTileSize.getValue(), false);
202        losNurseryDriver  = newTreadmillDriver("LOS Nursery", loSpace);
203        losDriver         = newTreadmillDriver("LOS", loSpace);
204    
205        if (DEBUG) Log.write("SemiServerInterpreter initialised\n");
206    
207        // Register drivers to allow immortal space to notify direct references
208        immortalDriver.registerDriversForReferenceNotification(
209          new AbstractDriver[] {ss0Driver, ss1Driver, immortalDriver,
210                                losNurseryDriver, losDriver,
211                                plosNurseryDriver, plosDriver});
212        if (DEBUG) Log.writeln("SSGCspy: registered drivers");
213    
214        gcspyEvent_ = BEFORE_COLLECTION;
215    
216        // Start the server
217        GCspy.server.startServer(wait);
218      }
219    
220      /**
221       * Create a new LinearSpaceDriver
222       * TODO is this the best name or should we call it LargeObjectSpaceDriver?
223       * @param name Name of the space
224       * @param space The space
225       * @return A new GCspy driver for this space
226       */
227      @Interruptible
228      private LinearSpaceDriver newLinearSpaceDriver(String name, CopySpace space, boolean mainSpace) {
229        // TODO What if tileSize is too small (i.e. too many tiles for GCspy buffer)
230        // TODO stop the GCspy spaces in the visualiser from fluctuating in size
231        // so much as we resize them.
232        return new LinearSpaceDriver(GCspy.server, name, space,
233                Options.gcspyTileSize.getValue(), mainSpace);
234      }
235    
236      /**
237       * Create a new TreadmillDriver
238       * TODO is this the best name or should we call it LargeObjectSpaceDriver?
239       * @param name Name of the space
240       * @param space The space
241       * @return A new GCspy driver for this space
242       */
243      @Interruptible
244      private TreadmillDriver newTreadmillDriver(String name, LargeObjectSpace space) {
245        return new TreadmillDriver(GCspy.server, name, space,
246                Options.gcspyTileSize.getValue(), MAX_NON_LOS_COPY_BYTES, false);
247      }
248    
249      /****************************************************************************
250       *
251       * Collection
252       */
253    
254      /**
255       * {@inheritDoc}
256       */
257      @Override
258      @Inline
259      public void collectionPhase(short phaseId) {
260        if (DEBUG) { Log.write("--Phase Plan."); Log.writeln(Phase.getName(phaseId)); }
261    
262        if (phaseId == SSGCspy.PREPARE) {
263          super.collectionPhase(phaseId);
264          gcspySpace.prepare();
265          return;
266        }
267    
268        if (phaseId == SSGCspy.RELEASE) {
269          super.collectionPhase(phaseId);
270          gcspySpace.release();
271          //if (primary)
272           gcspyGatherData(SSGCspy.AFTER_COLLECTION);
273          return;
274        }
275    
276        super.collectionPhase(phaseId);
277      }
278    
279      /**
280       * Gather data for GCspy for the semispaces, the immortal space and the large
281       * object space.
282       * <p>
283       * This method sweeps the semispace under consideration to gather data.
284       * Alternatively and more efficiently, 'used space' can obviously be
285       * discovered in constant time simply by comparing the start and the end
286       * addresses of the semispace. However, per-object information can only be
287       * gathered by sweeping through the space and we do this here for tutorial
288       * purposes.
289       *
290       * @param event
291       *          The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
292       *          AFTER_COLLECTION
293       */
294      private void gcspyGatherData(int event) {
295        if(DEBUG) {
296          Log.writeln("SSGCspy.gcspyGatherData, event=", event);
297          Log.writeln("SSGCspy.gcspyGatherData, port=", GCspy.getGCspyPort());
298        }
299    
300        // If port = 0 there can be no GCspy client connected
301        if (GCspy.getGCspyPort() == 0)
302          return;
303    
304        // This is a safepoint for the server, i.e. it is a point at which
305        // the server can pause.
306        // The Mutator is called after the Collector so the Mutator must set the safepoint
307        if(DEBUG) Log.writeln("SSGCspy safepoint");
308        GCspy.server.serverSafepoint(event);
309      }
310    
311      /****************************************************************************
312       *
313       * Accounting
314       */
315    
316      /**
317       * Return the number of pages reserved for use given the pending
318       * allocation.  This is <i>exclusive of</i> space reserved for
319       * copying.
320       */
321      @Override
322      public final int getPagesUsed() {
323        return super.getPagesUsed() + gcspySpace.reservedPages();
324      }
325    
326    
327      /**
328       * Report information on the semispaces
329       */
330      static void reportSpaces() {
331        Log.write("\n  Low semispace:  ");
332        Log.write(SSGCspy.copySpace0.getStart());
333        Log.write(" - ");
334        Log.write(SSGCspy.copySpace0.getStart()
335            .plus(SSGCspy.copySpace0.getExtent()));
336        Log.write("\n  High semispace: ");
337        Log.write(SSGCspy.copySpace1.getStart());
338        Log.write(" - ");
339        Log.write(SSGCspy.copySpace1.getStart()
340            .plus(SSGCspy.copySpace1.getExtent()));
341        Log.flush();
342      }
343    
344      @Override
345      @Interruptible
346      protected void registerSpecializedMethods() {
347        super.registerSpecializedMethods();
348        TransitiveClosure.registerSpecializedScan(SCAN_SS, SSGCspyTraceLocal.class);
349      }
350    }