1 /* |
1 /* |
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
34 #include "runtime/compilationPolicy.hpp" |
34 #include "runtime/compilationPolicy.hpp" |
35 #include "runtime/mutexLocker.hpp" |
35 #include "runtime/mutexLocker.hpp" |
36 #include "runtime/os.hpp" |
36 #include "runtime/os.hpp" |
37 #include "runtime/sweeper.hpp" |
37 #include "runtime/sweeper.hpp" |
38 #include "runtime/vm_operations.hpp" |
38 #include "runtime/vm_operations.hpp" |
|
39 #include "trace/tracing.hpp" |
39 #include "utilities/events.hpp" |
40 #include "utilities/events.hpp" |
40 #include "utilities/xmlstream.hpp" |
41 #include "utilities/xmlstream.hpp" |
41 |
42 |
42 #ifdef ASSERT |
43 #ifdef ASSERT |
43 |
44 |
128 |
129 |
129 |
130 |
130 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed |
131 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed |
131 nmethod* NMethodSweeper::_current = NULL; // Current nmethod |
132 nmethod* NMethodSweeper::_current = NULL; // Current nmethod |
132 int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache |
133 int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache |
|
134 int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep |
|
135 int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep |
|
136 int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep |
133 |
137 |
134 volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass |
138 volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass |
135 volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. |
139 volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. |
136 |
140 |
137 jint NMethodSweeper::_locked_seen = 0; |
141 jint NMethodSweeper::_locked_seen = 0; |
141 jlong NMethodSweeper::_last_full_flush_time = 0; |
145 jlong NMethodSweeper::_last_full_flush_time = 0; |
142 int NMethodSweeper::_highest_marked = 0; |
146 int NMethodSweeper::_highest_marked = 0; |
143 int NMethodSweeper::_dead_compile_ids = 0; |
147 int NMethodSweeper::_dead_compile_ids = 0; |
144 long NMethodSweeper::_last_flush_traversal_id = 0; |
148 long NMethodSweeper::_last_flush_traversal_id = 0; |
145 |
149 |
|
150 int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache |
|
151 int NMethodSweeper::_total_nof_methods_reclaimed = 0; |
|
152 jlong NMethodSweeper::_total_time_sweeping = 0; |
|
153 jlong NMethodSweeper::_total_time_this_sweep = 0; |
|
154 jlong NMethodSweeper::_peak_sweep_time = 0; |
|
155 jlong NMethodSweeper::_peak_sweep_fraction_time = 0; |
|
156 jlong NMethodSweeper::_total_disconnect_time = 0; |
|
157 jlong NMethodSweeper::_peak_disconnect_time = 0; |
|
158 |
146 class MarkActivationClosure: public CodeBlobClosure { |
159 class MarkActivationClosure: public CodeBlobClosure { |
147 public: |
160 public: |
148 virtual void do_code_blob(CodeBlob* cb) { |
161 virtual void do_code_blob(CodeBlob* cb) { |
149 // If we see an activation belonging to a non_entrant nmethod, we mark it. |
162 // If we see an activation belonging to a non_entrant nmethod, we mark it. |
150 if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { |
163 if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { |
174 if (!sweep_in_progress() && _resweep) { |
187 if (!sweep_in_progress() && _resweep) { |
175 _seen = 0; |
188 _seen = 0; |
176 _invocations = NmethodSweepFraction; |
189 _invocations = NmethodSweepFraction; |
177 _current = CodeCache::first_nmethod(); |
190 _current = CodeCache::first_nmethod(); |
178 _traversals += 1; |
191 _traversals += 1; |
|
192 _total_time_this_sweep = 0; |
|
193 |
179 if (PrintMethodFlushing) { |
194 if (PrintMethodFlushing) { |
180 tty->print_cr("### Sweep: stack traversal %d", _traversals); |
195 tty->print_cr("### Sweep: stack traversal %d", _traversals); |
181 } |
196 } |
182 Threads::nmethods_do(&mark_activation_closure); |
197 Threads::nmethods_do(&mark_activation_closure); |
183 |
198 |
227 _sweep_started = 0; |
242 _sweep_started = 0; |
228 } |
243 } |
229 } |
244 } |
230 |
245 |
231 void NMethodSweeper::sweep_code_cache() { |
246 void NMethodSweeper::sweep_code_cache() { |
232 #ifdef ASSERT |
247 |
233 jlong sweep_start; |
248 jlong sweep_start_counter = os::elapsed_counter(); |
234 if (PrintMethodFlushing) { |
249 |
235 sweep_start = os::javaTimeMillis(); |
250 _flushed_count = 0; |
236 } |
251 _zombified_count = 0; |
237 #endif |
252 _marked_count = 0; |
|
253 |
238 if (PrintMethodFlushing && Verbose) { |
254 if (PrintMethodFlushing && Verbose) { |
239 tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); |
255 tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); |
240 } |
256 } |
241 |
257 |
242 if (!CompileBroker::should_compile_new_jobs()) { |
258 if (!CompileBroker::should_compile_new_jobs()) { |
300 if (PrintMethodFlushing) { |
316 if (PrintMethodFlushing) { |
301 tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep"); |
317 tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep"); |
302 } |
318 } |
303 } |
319 } |
304 |
320 |
|
321 jlong sweep_end_counter = os::elapsed_counter(); |
|
322 jlong sweep_time = sweep_end_counter - sweep_start_counter; |
|
323 _total_time_sweeping += sweep_time; |
|
324 _total_time_this_sweep += sweep_time; |
|
325 _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time); |
|
326 _total_nof_methods_reclaimed += _flushed_count; |
|
327 |
|
328 EventSweepCodeCache event(UNTIMED); |
|
329 if (event.should_commit()) { |
|
330 event.set_starttime(sweep_start_counter); |
|
331 event.set_endtime(sweep_end_counter); |
|
332 event.set_sweepIndex(_traversals); |
|
333 event.set_sweepFractionIndex(NmethodSweepFraction - _invocations + 1); |
|
334 event.set_sweptCount(todo); |
|
335 event.set_flushedCount(_flushed_count); |
|
336 event.set_markedCount(_marked_count); |
|
337 event.set_zombifiedCount(_zombified_count); |
|
338 event.commit(); |
|
339 } |
|
340 |
305 #ifdef ASSERT |
341 #ifdef ASSERT |
306 if(PrintMethodFlushing) { |
342 if(PrintMethodFlushing) { |
307 jlong sweep_end = os::javaTimeMillis(); |
343 tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, (jlong)sweep_time); |
308 tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); |
|
309 } |
344 } |
310 #endif |
345 #endif |
311 |
346 |
312 if (_invocations == 1) { |
347 if (_invocations == 1) { |
|
348 _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep); |
313 log_sweep("finished"); |
349 log_sweep("finished"); |
314 } |
350 } |
315 |
351 |
316 // Sweeper is the only case where memory is released, |
352 // Sweeper is the only case where memory is released, |
317 // check here if it is time to restart the compiler. |
353 // check here if it is time to restart the compiler. |
386 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); |
422 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); |
387 if (PrintMethodFlushing && Verbose) { |
423 if (PrintMethodFlushing && Verbose) { |
388 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); |
424 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); |
389 } |
425 } |
390 release_nmethod(nm); |
426 release_nmethod(nm); |
|
427 _flushed_count++; |
391 } else { |
428 } else { |
392 if (PrintMethodFlushing && Verbose) { |
429 if (PrintMethodFlushing && Verbose) { |
393 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); |
430 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); |
394 } |
431 } |
395 nm->mark_for_reclamation(); |
432 nm->mark_for_reclamation(); |
396 _resweep = true; |
433 _resweep = true; |
|
434 _marked_count++; |
397 SWEEP(nm); |
435 SWEEP(nm); |
398 } |
436 } |
399 } else if (nm->is_not_entrant()) { |
437 } else if (nm->is_not_entrant()) { |
400 // If there is no current activations of this method on the |
438 // If there is no current activations of this method on the |
401 // stack we can safely convert it to a zombie method |
439 // stack we can safely convert it to a zombie method |
403 if (PrintMethodFlushing && Verbose) { |
441 if (PrintMethodFlushing && Verbose) { |
404 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); |
442 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); |
405 } |
443 } |
406 nm->make_zombie(); |
444 nm->make_zombie(); |
407 _resweep = true; |
445 _resweep = true; |
|
446 _zombified_count++; |
408 SWEEP(nm); |
447 SWEEP(nm); |
409 } else { |
448 } else { |
410 // Still alive, clean up its inline caches |
449 // Still alive, clean up its inline caches |
411 MutexLocker cl(CompiledIC_lock); |
450 MutexLocker cl(CompiledIC_lock); |
412 nm->cleanup_inline_caches(); |
451 nm->cleanup_inline_caches(); |
418 } |
457 } |
419 } else if (nm->is_unloaded()) { |
458 } else if (nm->is_unloaded()) { |
420 // Unloaded code, just make it a zombie |
459 // Unloaded code, just make it a zombie |
421 if (PrintMethodFlushing && Verbose) |
460 if (PrintMethodFlushing && Verbose) |
422 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); |
461 tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); |
|
462 |
423 if (nm->is_osr_method()) { |
463 if (nm->is_osr_method()) { |
424 SWEEP(nm); |
464 SWEEP(nm); |
425 // No inline caches will ever point to osr methods, so we can just remove it |
465 // No inline caches will ever point to osr methods, so we can just remove it |
426 release_nmethod(nm); |
466 release_nmethod(nm); |
|
467 _flushed_count++; |
427 } else { |
468 } else { |
428 nm->make_zombie(); |
469 nm->make_zombie(); |
429 _resweep = true; |
470 _resweep = true; |
|
471 _zombified_count++; |
430 SWEEP(nm); |
472 SWEEP(nm); |
431 } |
473 } |
432 } else { |
474 } else { |
433 assert(nm->is_alive(), "should be alive"); |
475 assert(nm->is_alive(), "should be alive"); |
434 |
476 |
482 |
524 |
483 void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { |
525 void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { |
484 // If there was a race in detecting full code cache, only run |
526 // If there was a race in detecting full code cache, only run |
485 // one vm op for it or keep the compiler shut off |
527 // one vm op for it or keep the compiler shut off |
486 |
528 |
487 debug_only(jlong start = os::javaTimeMillis();) |
529 jlong disconnect_start_counter = os::elapsed_counter(); |
488 |
530 |
489 // Traverse the code cache trying to dump the oldest nmethods |
531 // Traverse the code cache trying to dump the oldest nmethods |
490 int curr_max_comp_id = CompileBroker::get_compilation_id(); |
532 int curr_max_comp_id = CompileBroker::get_compilation_id(); |
491 int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; |
533 int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; |
492 |
534 |
539 // traversal cycle and turn it back on if it clears enough space. |
581 // traversal cycle and turn it back on if it clears enough space. |
540 if (is_full) { |
582 if (is_full) { |
541 _last_full_flush_time = os::javaTimeMillis(); |
583 _last_full_flush_time = os::javaTimeMillis(); |
542 } |
584 } |
543 |
585 |
|
586 jlong disconnect_end_counter = os::elapsed_counter(); |
|
587 jlong disconnect_time = disconnect_end_counter - disconnect_start_counter; |
|
588 _total_disconnect_time += disconnect_time; |
|
589 _peak_disconnect_time = MAX2(disconnect_time, _peak_disconnect_time); |
|
590 |
|
591 EventCleanCodeCache event(UNTIMED); |
|
592 if (event.should_commit()) { |
|
593 event.set_starttime(disconnect_start_counter); |
|
594 event.set_endtime(disconnect_end_counter); |
|
595 event.set_disconnectedCount(disconnected); |
|
596 event.set_madeNonEntrantCount(made_not_entrant); |
|
597 event.commit(); |
|
598 } |
|
599 _number_of_flushes++; |
|
600 |
544 // After two more traversals the sweeper will get rid of unrestored nmethods |
601 // After two more traversals the sweeper will get rid of unrestored nmethods |
545 _last_flush_traversal_id = _traversals; |
602 _last_flush_traversal_id = _traversals; |
546 _resweep = true; |
603 _resweep = true; |
547 #ifdef ASSERT |
604 #ifdef ASSERT |
548 jlong end = os::javaTimeMillis(); |
605 |
549 if(PrintMethodFlushing && Verbose) { |
606 if(PrintMethodFlushing && Verbose) { |
550 tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start); |
607 tty->print_cr("### sweeper: unload time: " INT64_FORMAT, (jlong)disconnect_time); |
551 } |
608 } |
552 #endif |
609 #endif |
553 } |
610 } |
554 |
611 |
555 |
612 |