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 */ 013package org.mmtk.plan; 014 015import org.mmtk.utility.Log; 016import org.mmtk.utility.heap.HeapGrowthManager; 017import org.mmtk.utility.options.Options; 018import org.mmtk.vm.Monitor; 019import org.mmtk.vm.VM; 020 021import org.vmmagic.pragma.*; 022 023@Uninterruptible 024public 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 final 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}