src/share/vm/runtime/sweeper.cpp

Print this page
rev 5099 : dummy
rev 5100 : dummy

*** 141,152 **** jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; bool NMethodSweeper::_resweep = false; jint NMethodSweeper::_flush_token = 0; jlong NMethodSweeper::_last_full_flush_time = 0; - int NMethodSweeper::_highest_marked = 0; - int NMethodSweeper::_dead_compile_ids = 0; long NMethodSweeper::_last_flush_traversal_id = 0; int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache int NMethodSweeper::_total_nof_methods_reclaimed = 0; jlong NMethodSweeper::_total_time_sweeping = 0; --- 141,150 ----
*** 157,169 **** jlong NMethodSweeper::_peak_disconnect_time = 0; class MarkActivationClosure: public CodeBlobClosure { public: virtual void do_code_blob(CodeBlob* cb) { // If we see an activation belonging to a non_entrant nmethod, we mark it. ! if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { ! ((nmethod*)cb)->mark_as_seen_on_stack(); } } }; static MarkActivationClosure mark_activation_closure; --- 155,171 ---- jlong NMethodSweeper::_peak_disconnect_time = 0; class MarkActivationClosure: public CodeBlobClosure { public: virtual void do_code_blob(CodeBlob* cb) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*)cb; + nm->set_hotness_counter(NMethodSweeper::hc_reset_value); // If we see an activation belonging to a non_entrant nmethod, we mark it. ! if (nm->is_not_entrant()) { ! nm->mark_as_seen_on_stack(); ! } } } }; static MarkActivationClosure mark_activation_closure;
*** 307,317 **** assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were // nmethods we were unable to process either because they were ! // locked or were still on stack. We don't have to aggresively // clean them up so just stop scanning. We could scan once more // but that complicates the control logic and it's unlikely to // matter much. if (PrintMethodFlushing) { tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep"); --- 309,319 ---- assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were // nmethods we were unable to process either because they were ! // locked or were still on stack. We don't have to aggressively // clean them up so just stop scanning. We could scan once more // but that complicates the control logic and it's unlikely to // matter much. if (PrintMethodFlushing) { tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep");
*** 390,411 **** nm->flush(); } void NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); - // Make sure this nmethod doesn't get unloaded during the scan, ! // since the locks acquired below might safepoint. NMethodMarker nmm(nm); SWEEP(nm); // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods if (nm->is_alive()) { ! // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } else { _locked_seen++; --- 392,413 ---- nm->flush(); } void NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); // Make sure this nmethod doesn't get unloaded during the scan, ! // since the locks acquired might below the safepoint. NMethodMarker nmm(nm); + nm->dec_hotness_counter(NMethodSweeper::hc_dec_value); SWEEP(nm); // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods if (nm->is_alive()) { ! // Clean-up all inline caches that point to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } else { _locked_seen++;
*** 413,424 **** } return; } if (nm->is_zombie()) { ! // If it is first time, we see nmethod then we mark it. Otherwise, ! // we reclame it. When we have seen a zombie method twice, we know that // there are no inline caches that refer to it. if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); --- 415,426 ---- } return; } if (nm->is_zombie()) { ! // If it is the first time we see nmethod then we mark it. Otherwise, ! // we reclaim it. When we have seen a zombie method twice, we know that // there are no inline caches that refer to it. if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm);
*** 433,443 **** _resweep = true; _marked_count++; SWEEP(nm); } } else if (nm->is_not_entrant()) { ! // If there is no current activations of this method on the // stack we can safely convert it to a zombie method if (nm->can_not_entrant_be_converted()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } --- 435,445 ---- _resweep = true; _marked_count++; SWEEP(nm); } } else if (nm->is_not_entrant()) { ! // If there are no current activations of this method on the // stack we can safely convert it to a zombie method if (nm->can_not_entrant_be_converted()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); }
*** 471,500 **** _zombified_count++; SWEEP(nm); } } else { assert(nm->is_alive(), "should be alive"); - if (UseCodeCacheFlushing) { ! if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() && ! (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) { // This method has not been called since the forced cleanup happened nm->make_not_entrant(); } } ! // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } } // Code cache unloading: when compilers notice the code cache is getting full, // they will call a vm op that comes here. This code attempts to speculatively ! // unload the oldest half of the nmethods (based on the compile job id) by ! // saving the old code in a list in the CodeCache. Then // execution resumes. If a method so marked is not called by the second sweeper // stack traversal after the current one, the nmethod will be marked non-entrant and // got rid of by normal sweeping. If the method is called, the Method*'s // _code field is restored and the Method*/nmethod // go back to their normal state. --- 473,507 ---- _zombified_count++; SWEEP(nm); } } else { assert(nm->is_alive(), "should be alive"); if (UseCodeCacheFlushing) { ! if (!nm->is_locked_by_vm() && !nm->is_osr_method()) { ! if (!nm->is_speculatively_disconnected()) { ! // This method is cold and the code cache fills up => get rid of it. ! double threshold = -100 + (CodeCache::reverse_free_ratio() * NmethodSweepActivity); ! if (nm->get_hotness_counter() < threshold) { ! nm->make_not_entrant(); ! } ! } else if (nm->is_speculatively_disconnected() && (_traversals > _last_flush_traversal_id + 2)) { // This method has not been called since the forced cleanup happened nm->make_not_entrant(); } } ! } // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } } // Code cache unloading: when compilers notice the code cache is getting full, // they will call a vm op that comes here. This code attempts to speculatively ! // unload the coldest part (the part is defined by CodeCacheFlushingFraction) of ! // the nmethods by saving the cold code in a list in the CodeCache. Then // execution resumes. If a method so marked is not called by the second sweeper // stack traversal after the current one, the nmethod will be marked non-entrant and // got rid of by normal sweeping. If the method is called, the Method*'s // _code field is restored and the Method*/nmethod // go back to their normal state.
*** 520,580 **** // resweep again as soon as possible _resweep = true; } void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { // If there was a race in detecting full code cache, only run // one vm op for it or keep the compiler shut off - jlong disconnect_start_counter = os::elapsed_counter(); - // Traverse the code cache trying to dump the oldest nmethods - int curr_max_comp_id = CompileBroker::get_compilation_id(); - int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; - - log_sweep("start_cleaning"); - - nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); jint disconnected = 0; jint made_not_entrant = 0; jint nmethod_count = 0; ! while ((nm != NULL)){ ! int curr_comp_id = nm->compile_id(); ! // OSR methods cannot be flushed like this. Also, don't flush native methods ! // since they are part of the JDK in most cases ! if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) { ! // only count methods that can be speculatively disconnected ! nmethod_count++; ! if (nm->is_in_use() && (curr_comp_id < flush_target)) { ! if ((nm->method()->code() == nm)) { ! // This method has not been previously considered for ! // unloading or it was restored already ! CodeCache::speculatively_disconnect(nm); ! disconnected++; } else if (nm->is_speculatively_disconnected()) { // This method was previously considered for preemptive unloading and was not called since then CompilationPolicy::policy()->delay_compilation(nm->method()); nm->make_not_entrant(); made_not_entrant++; } ! if (curr_comp_id > _highest_marked) { ! _highest_marked = curr_comp_id; } } } - nm = CodeCache::alive_nmethod(CodeCache::next(nm)); } - // remember how many compile_ids wheren't seen last flush. - _dead_compile_ids = curr_max_comp_id - nmethod_count; - log_sweep("stop_cleaning", "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", disconnected, made_not_entrant); // Shut off compiler. Sweeper will start over with a new stack scan and --- 527,601 ---- // resweep again as soon as possible _resweep = true; } + int NMethodSweeper::sort_nmentod_by_hotness(nmethod** nm1, nmethod** nm2) { + return ((*(nm1))->get_hotness_counter() > (*nm2)->get_hotness_counter()); + } + void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { // If there was a race in detecting full code cache, only run // one vm op for it or keep the compiler shut off jlong disconnect_start_counter = os::elapsed_counter(); jint disconnected = 0; jint made_not_entrant = 0; jint nmethod_count = 0; ! log_sweep("start_cleaning"); ! { ! ResourceMark rm; ! GrowableArray<nmethod*>* live_methods= new GrowableArray<nmethod*>(); ! nmethod* nm = CodeCache::next_nmethod(CodeCache::first()); ! size_t methods_to_flush = CodeCache::nof_nmethods() / CodeCacheFlushingFraction; ! size_t methods_will_be_flushed = 0; ! size_t nmethods = 0; ! // See how many methods are 'in flight' of being flushed ! while ((nm != NULL) && (methods_will_be_flushed < methods_to_flush)) { ! // OSR methods cannot be flushed like this. Also, don't flush native methods ! // since they are part of the JDK in most cases ! if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method() && nm->is_alive()) { ! if ((nm->is_in_use()) && (nm->method()->code() == nm)) { ! live_methods->append(nm); } else if (nm->is_speculatively_disconnected()) { // This method was previously considered for preemptive unloading and was not called since then CompilationPolicy::policy()->delay_compilation(nm->method()); nm->make_not_entrant(); made_not_entrant++; + methods_will_be_flushed++; + } else { + methods_will_be_flushed++; + } + } + nm = CodeCache::next_nmethod(nm); } ! // Speculatively disconnect methods until we reach 'memory_to_flush' ! if (methods_will_be_flushed < methods_to_flush) { ! live_methods->sort(sort_nmentod_by_hotness); ! //Iterate over sorted array and speculatively disconnect these nmethods ! for (int i = 0; i < live_methods->length(); i++) { ! nm = live_methods->at(i); ! if (methods_will_be_flushed < methods_to_flush) { ! // Method was not previously disconnected ! if ((nm->method()->code() == nm)) { ! CodeCache::speculatively_disconnect(nm); ! disconnected++; ! methods_will_be_flushed++; ! } ! } else { ! // The requested number of nmethods is scheduled for flushing ! break; } } } } log_sweep("stop_cleaning", "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", disconnected, made_not_entrant); // Shut off compiler. Sweeper will start over with a new stack scan and