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;
014
015 import org.mmtk.utility.Log;
016 import org.mmtk.utility.heap.HeapGrowthManager;
017 import org.mmtk.utility.options.Options;
018 import org.mmtk.vm.Monitor;
019 import org.mmtk.vm.VM;
020
021 import org.vmmagic.pragma.*;
022
023 @Uninterruptible
024 public class ControllerCollectorContext extends CollectorContext {
025
026 /** The lock to use to manage collection */
027 private Monitor lock;
028
029 /** The set of worker threads to use */
030 private ParallelCollectorGroup workers;
031
032 /** Flag used to control the 'race to request' */
033 private boolean requestFlag;
034
035 /** The current request index */
036 private int requestCount;
037
038 /** The request index that was last completed */
039 private int lastRequestCount = -1;
040
041 /** Is there concurrent collection activity */
042 private boolean concurrentCollection = false;
043
044 /**
045 * Create a controller context.
046 *
047 * @param workers The worker group to use for collection.
048 */
049 public ControllerCollectorContext(ParallelCollectorGroup workers) {
050 this.workers = workers;
051 }
052
053 @Override
054 @Interruptible
055 public void initCollector(int id) {
056 super.initCollector(id);
057 lock = VM.newHeavyCondLock("CollectorControlLock");
058 }
059
060 /**
061 * Main execution loop.
062 */
063 @Override
064 @Unpreemptible
065 public void run() {
066 while(true) {
067 // Wait for a collection request.
068 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Waiting for request...]");
069 waitForRequest();
070 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Request recieved.]");
071
072 // The start time.
073 long startTime = VM.statistics.nanoTime();
074
075 if (concurrentCollection) {
076 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping concurrent collectors...]");
077 Plan.concurrentWorkers.abortCycle();
078 Plan.concurrentWorkers.waitForCycle();
079 Phase.clearConcurrentPhase();
080 // Collector must re-request concurrent collection in this case.
081 concurrentCollection = false;
082 }
083
084 // Stop all mutator threads
085 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping the world...]");
086 VM.collection.stopAllMutators();
087
088 // Was this user triggered?
089 boolean userTriggeredCollection = Plan.isUserTriggeredCollection();
090 boolean internalTriggeredCollection = Plan.isInternalTriggeredCollection();
091
092 // Clear the request
093 clearRequest();
094
095 // Trigger GC.
096 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering worker threads...]");
097 workers.triggerCycle();
098
099 // Wait for GC threads to complete.
100 workers.waitForCycle();
101 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Worker threads complete!]");
102
103 // Heap growth logic
104 long elapsedTime = VM.statistics.nanoTime() - startTime;
105 HeapGrowthManager.recordGCTime(VM.statistics.nanosToMillis(elapsedTime));
106 if (VM.activePlan.global().lastCollectionFullHeap() && !internalTriggeredCollection) {
107 if (Options.variableSizeHeap.getValue() && !userTriggeredCollection) {
108 // Don't consider changing the heap size if the application triggered the collection
109 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Considering heap size.]");
110 HeapGrowthManager.considerHeapSize();
111 }
112 HeapGrowthManager.reset();
113 }
114
115 // Reset the triggering information.
116 Plan.resetCollectionTrigger();
117
118 // Resume all mutators
119 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Resuming mutators...]");
120 VM.collection.resumeAllMutators();
121
122 // Start threads that will perform concurrent collection work alongside mutators.
123 if (concurrentCollection) {
124 if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering concurrent collectors...]");
125 Plan.concurrentWorkers.triggerCycle();
126 }
127 }
128 }
129
130 /**
131 * Request that concurrent collection is performed after this stop-the-world increment.
132 */
133 public void requestConcurrentCollection() {
134 concurrentCollection = true;
135 }
136
137 /**
138 * Request a collection.
139 */
140 public void request() {
141 if (requestFlag) {
142 return;
143 }
144 lock.lock();
145 if (!requestFlag) {
146 requestFlag = true;
147 requestCount++;
148 lock.broadcast();
149 }
150 lock.unlock();
151 }
152
153 /**
154 * Clear the collection request, making future requests incur an
155 * additional collection cycle.
156 */
157 private void clearRequest() {
158 lock.lock();
159 requestFlag = false;
160 lock.unlock();
161 }
162
163 /**
164 * Wait until a request is received.
165 */
166 private void waitForRequest() {
167 lock.lock();
168 lastRequestCount++;
169 while (lastRequestCount == requestCount) {
170 lock.await();
171 }
172 lock.unlock();
173 }
174 }