Mercurial > hg > graal-compiler
comparison src/share/vm/runtime/sweeper.cpp @ 1202:5f24d0319e54
4360113: Evict nmethods when code cache gets full
Summary: Speculatively unload the oldest nmethods when code cache gets full.
Reviewed-by: never, kvn
Contributed-by: eric.caspole@amd.com
author | kvn |
---|---|
date | Fri, 29 Jan 2010 09:27:22 -0800 |
parents | a1423fe86a18 |
children | bfe29ec02863 |
comparison
equal
deleted
inserted
replaced
1201:24128c2ffa87 | 1202:5f24d0319e54 |
---|---|
31 int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass | 31 int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass |
32 | 32 |
33 jint NMethodSweeper::_locked_seen = 0; | 33 jint NMethodSweeper::_locked_seen = 0; |
34 jint NMethodSweeper::_not_entrant_seen_on_stack = 0; | 34 jint NMethodSweeper::_not_entrant_seen_on_stack = 0; |
35 bool NMethodSweeper::_rescan = false; | 35 bool NMethodSweeper::_rescan = false; |
36 bool NMethodSweeper::_was_full = false; | |
37 jint NMethodSweeper::_advise_to_sweep = 0; | |
38 jlong NMethodSweeper::_last_was_full = 0; | |
39 uint NMethodSweeper::_highest_marked = 0; | |
40 long NMethodSweeper::_was_full_traversal = 0; | |
36 | 41 |
37 class MarkActivationClosure: public CodeBlobClosure { | 42 class MarkActivationClosure: public CodeBlobClosure { |
38 public: | 43 public: |
39 virtual void do_code_blob(CodeBlob* cb) { | 44 virtual void do_code_blob(CodeBlob* cb) { |
40 // If we see an activation belonging to a non_entrant nmethod, we mark it. | 45 // If we see an activation belonging to a non_entrant nmethod, we mark it. |
112 // matter much. | 117 // matter much. |
113 if (PrintMethodFlushing) { | 118 if (PrintMethodFlushing) { |
114 tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep"); | 119 tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep"); |
115 } | 120 } |
116 } | 121 } |
122 | |
123 if (UseCodeCacheFlushing) { | |
124 if (!CodeCache::needs_flushing()) { | |
125 // In a safepoint, no race with setters | |
126 _advise_to_sweep = 0; | |
127 } | |
128 | |
129 if (was_full()) { | |
130 // There was some progress so attempt to restart the compiler | |
131 jlong now = os::javaTimeMillis(); | |
132 jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; | |
133 jlong curr_interval = now - _last_was_full; | |
134 if ((!CodeCache::needs_flushing()) && (curr_interval > max_interval)) { | |
135 CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); | |
136 set_was_full(false); | |
137 | |
138 // Update the _last_was_full time so we can tell how fast the | |
139 // code cache is filling up | |
140 _last_was_full = os::javaTimeMillis(); | |
141 | |
142 if (PrintMethodFlushing) { | |
143 tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", | |
144 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
145 } | |
146 if (LogCompilation && (xtty != NULL)) { | |
147 ttyLocker ttyl; | |
148 xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
149 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
150 xtty->stamp(); | |
151 xtty->end_elem(); | |
152 } | |
153 } | |
154 } | |
155 } | |
117 } | 156 } |
118 | 157 |
119 | 158 |
120 void NMethodSweeper::process_nmethod(nmethod *nm) { | 159 void NMethodSweeper::process_nmethod(nmethod *nm) { |
121 // Skip methods that are currently referenced by the VM | 160 // Skip methods that are currently referenced by the VM |
135 // we reclame it. When we have seen a zombie method twice, we know that | 174 // we reclame it. When we have seen a zombie method twice, we know that |
136 // there are no inline caches that referes to it. | 175 // there are no inline caches that referes to it. |
137 if (nm->is_marked_for_reclamation()) { | 176 if (nm->is_marked_for_reclamation()) { |
138 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); | 177 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); |
139 if (PrintMethodFlushing && Verbose) { | 178 if (PrintMethodFlushing && Verbose) { |
140 tty->print_cr("### Nmethod 0x%x (marked for reclamation) being flushed", nm); | 179 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); |
141 } | 180 } |
142 nm->flush(); | 181 nm->flush(); |
143 } else { | 182 } else { |
144 if (PrintMethodFlushing && Verbose) { | 183 if (PrintMethodFlushing && Verbose) { |
145 tty->print_cr("### Nmethod 0x%x (zombie) being marked for reclamation", nm); | 184 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); |
146 } | 185 } |
147 nm->mark_for_reclamation(); | 186 nm->mark_for_reclamation(); |
148 _rescan = true; | 187 _rescan = true; |
149 } | 188 } |
150 } else if (nm->is_not_entrant()) { | 189 } else if (nm->is_not_entrant()) { |
151 // If there is no current activations of this method on the | 190 // If there is no current activations of this method on the |
152 // stack we can safely convert it to a zombie method | 191 // stack we can safely convert it to a zombie method |
153 if (nm->can_not_entrant_be_converted()) { | 192 if (nm->can_not_entrant_be_converted()) { |
154 if (PrintMethodFlushing && Verbose) { | 193 if (PrintMethodFlushing && Verbose) { |
155 tty->print_cr("### Nmethod 0x%x (not entrant) being made zombie", nm); | 194 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); |
156 } | 195 } |
157 nm->make_zombie(); | 196 nm->make_zombie(); |
158 _rescan = true; | 197 _rescan = true; |
159 } else { | 198 } else { |
160 // Still alive, clean up its inline caches | 199 // Still alive, clean up its inline caches |
165 _not_entrant_seen_on_stack++; | 204 _not_entrant_seen_on_stack++; |
166 } | 205 } |
167 } else if (nm->is_unloaded()) { | 206 } else if (nm->is_unloaded()) { |
168 // Unloaded code, just make it a zombie | 207 // Unloaded code, just make it a zombie |
169 if (PrintMethodFlushing && Verbose) | 208 if (PrintMethodFlushing && Verbose) |
170 tty->print_cr("### Nmethod 0x%x (unloaded) being made zombie", nm); | 209 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); |
171 if (nm->is_osr_method()) { | 210 if (nm->is_osr_method()) { |
172 // No inline caches will ever point to osr methods, so we can just remove it | 211 // No inline caches will ever point to osr methods, so we can just remove it |
173 nm->flush(); | 212 nm->flush(); |
174 } else { | 213 } else { |
175 nm->make_zombie(); | 214 nm->make_zombie(); |
176 _rescan = true; | 215 _rescan = true; |
177 } | 216 } |
178 } else { | 217 } else { |
179 assert(nm->is_alive(), "should be alive"); | 218 assert(nm->is_alive(), "should be alive"); |
219 | |
220 if (UseCodeCacheFlushing) { | |
221 if ((nm->method()->code() != nm) && !(nm->is_locked_by_vm()) && !(nm->is_osr_method()) && | |
222 (_traversals > _was_full_traversal+2) && (((uint)nm->compile_id()) < _highest_marked) && | |
223 CodeCache::needs_flushing()) { | |
224 // This method has not been called since the forced cleanup happened | |
225 nm->make_not_entrant(); | |
226 } | |
227 } | |
228 | |
180 // Clean-up all inline caches that points to zombie/non-reentrant methods | 229 // Clean-up all inline caches that points to zombie/non-reentrant methods |
181 nm->cleanup_inline_caches(); | 230 nm->cleanup_inline_caches(); |
182 } | 231 } |
183 } | 232 } |
233 | |
234 // Code cache unloading: when compilers notice the code cache is getting full, | |
235 // they will call a vm op that comes here. This code attempts to speculatively | |
236 // unload the oldest half of the nmethods (based on the compile job id) by | |
237 // saving the old code in a list in the CodeCache. Then | |
238 // execution resumes. If a method so marked is not called by the second | |
239 // safepoint from the current one, the nmethod will be marked non-entrant and | |
240 // got rid of by normal sweeping. If the method is called, the methodOop's | |
241 // _code field is restored and the methodOop/nmethod | |
242 // go back to their normal state. | |
243 void NMethodSweeper::handle_full_code_cache(bool is_full) { | |
244 // Only the first one to notice can advise us to start early cleaning | |
245 if (!is_full){ | |
246 jint old = Atomic::cmpxchg( 1, &_advise_to_sweep, 0 ); | |
247 if (old != 0) { | |
248 return; | |
249 } | |
250 } | |
251 | |
252 if (is_full) { | |
253 // Since code cache is full, immediately stop new compiles | |
254 bool did_set = CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation); | |
255 if (!did_set) { | |
256 // only the first to notice can start the cleaning, | |
257 // others will go back and block | |
258 return; | |
259 } | |
260 set_was_full(true); | |
261 | |
262 // If we run out within MinCodeCacheFlushingInterval of the last unload time, give up | |
263 jlong now = os::javaTimeMillis(); | |
264 jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; | |
265 jlong curr_interval = now - _last_was_full; | |
266 if (curr_interval < max_interval) { | |
267 _rescan = true; | |
268 if (PrintMethodFlushing) { | |
269 tty->print_cr("### handle full too often, turning off compiler"); | |
270 } | |
271 if (LogCompilation && (xtty != NULL)) { | |
272 ttyLocker ttyl; | |
273 xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
274 curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
275 xtty->stamp(); | |
276 xtty->end_elem(); | |
277 } | |
278 return; | |
279 } | |
280 } | |
281 | |
282 VM_HandleFullCodeCache op(is_full); | |
283 VMThread::execute(&op); | |
284 | |
285 // rescan again as soon as possible | |
286 _rescan = true; | |
287 } | |
288 | |
289 void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { | |
290 // If there was a race in detecting full code cache, only run | |
291 // one vm op for it or keep the compiler shut off | |
292 | |
293 debug_only(jlong start = os::javaTimeMillis();) | |
294 | |
295 if ((!was_full()) && (is_full)) { | |
296 if (!CodeCache::needs_flushing()) { | |
297 if (PrintMethodFlushing) { | |
298 tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", | |
299 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
300 } | |
301 if (LogCompilation && (xtty != NULL)) { | |
302 ttyLocker ttyl; | |
303 xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
304 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
305 xtty->stamp(); | |
306 xtty->end_elem(); | |
307 } | |
308 CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); | |
309 return; | |
310 } | |
311 } | |
312 | |
313 // Traverse the code cache trying to dump the oldest nmethods | |
314 uint curr_max_comp_id = CompileBroker::get_compilation_id(); | |
315 uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; | |
316 if (PrintMethodFlushing && Verbose) { | |
317 tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes", | |
318 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
319 } | |
320 if (LogCompilation && (xtty != NULL)) { | |
321 ttyLocker ttyl; | |
322 xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
323 CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
324 xtty->stamp(); | |
325 xtty->end_elem(); | |
326 } | |
327 | |
328 nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); | |
329 jint disconnected = 0; | |
330 jint made_not_entrant = 0; | |
331 while ((nm != NULL)){ | |
332 uint curr_comp_id = nm->compile_id(); | |
333 | |
334 // OSR methods cannot be flushed like this. Also, don't flush native methods | |
335 // since they are part of the JDK in most cases | |
336 if (nm->is_in_use() && (!nm->is_osr_method()) && (!nm->is_locked_by_vm()) && | |
337 (!nm->is_native_method()) && ((curr_comp_id < flush_target))) { | |
338 | |
339 if ((nm->method()->code() == nm)) { | |
340 // This method has not been previously considered for | |
341 // unloading or it was restored already | |
342 CodeCache::speculatively_disconnect(nm); | |
343 disconnected++; | |
344 } else if (nm->is_speculatively_disconnected()) { | |
345 // This method was previously considered for preemptive unloading and was not called since then | |
346 nm->method()->invocation_counter()->decay(); | |
347 nm->method()->backedge_counter()->decay(); | |
348 nm->make_not_entrant(); | |
349 made_not_entrant++; | |
350 } | |
351 | |
352 if (curr_comp_id > _highest_marked) { | |
353 _highest_marked = curr_comp_id; | |
354 } | |
355 } | |
356 nm = CodeCache::alive_nmethod(CodeCache::next(nm)); | |
357 } | |
358 | |
359 if (LogCompilation && (xtty != NULL)) { | |
360 ttyLocker ttyl; | |
361 xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", | |
362 disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); | |
363 xtty->stamp(); | |
364 xtty->end_elem(); | |
365 } | |
366 | |
367 // Shut off compiler. Sweeper will run exiting from this safepoint | |
368 // and turn it back on if it clears enough space | |
369 if (was_full()) { | |
370 _last_was_full = os::javaTimeMillis(); | |
371 CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation); | |
372 } | |
373 | |
374 // After two more traversals the sweeper will get rid of unrestored nmethods | |
375 _was_full_traversal = _traversals; | |
376 #ifdef ASSERT | |
377 jlong end = os::javaTimeMillis(); | |
378 if(PrintMethodFlushing && Verbose) { | |
379 tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start); | |
380 } | |
381 #endif | |
382 } |