Mercurial > hg > truffle
diff src/share/vm/runtime/sweeper.cpp @ 1644:2a47bd84841f
6965184: possible races in make_not_entrant_or_zombie
Reviewed-by: kvn
author | never |
---|---|
date | Thu, 08 Jul 2010 14:29:44 -0700 |
parents | ff38d05ea86f |
children | 8d5934a77f10 |
line wrap: on
line diff
--- a/src/share/vm/runtime/sweeper.cpp Wed Jul 07 12:40:01 2010 -0700 +++ b/src/share/vm/runtime/sweeper.cpp Thu Jul 08 14:29:44 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,15 @@ long NMethodSweeper::_traversals = 0; // No. of stack traversals performed nmethod* NMethodSweeper::_current = NULL; // Current nmethod -int NMethodSweeper::_seen = 0 ; // No. of blobs we have currently processed in current pass of CodeCache -int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache + +volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass +volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; bool NMethodSweeper::_rescan = false; bool NMethodSweeper::_do_sweep = false; -jint NMethodSweeper::_sweep_started = 0; bool NMethodSweeper::_was_full = false; jint NMethodSweeper::_advise_to_sweep = 0; jlong NMethodSweeper::_last_was_full = 0; @@ -108,23 +109,14 @@ // code cache is filling up _last_was_full = os::javaTimeMillis(); - if (PrintMethodFlushing) { - tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("restart_compiler"); } } } } void NMethodSweeper::possibly_sweep() { + assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); if ((!MethodFlushing) || (!_do_sweep)) return; if (_invocations > 0) { @@ -133,32 +125,31 @@ if (old != 0) { return; } - sweep_code_cache(); + if (_invocations > 0) { + sweep_code_cache(); + _invocations--; + } + _sweep_started = 0; } - _sweep_started = 0; } void NMethodSweeper::sweep_code_cache() { #ifdef ASSERT jlong sweep_start; - if(PrintMethodFlushing) { + if (PrintMethodFlushing) { sweep_start = os::javaTimeMillis(); } #endif if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_blobs(), _invocations); + tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); } - // We want to visit all nmethods after NmethodSweepFraction invocations. - // If invocation is 1 we do the rest - int todo = CodeCache::nof_blobs(); - if (_invocations > 1) { - todo = (CodeCache::nof_blobs() - _seen) / _invocations; - } - - // Compilers may check to sweep more often than stack scans happen, - // don't keep trying once it is all scanned - _invocations--; + // We want to visit all nmethods after NmethodSweepFraction + // invocations so divide the remaining number of nmethods by the + // remaining number of invocations. This is only an estimate since + // the number of nmethods changes during the sweep so the final + // stage must iterate until it there are no more nmethods. + int todo = (CodeCache::nof_nmethods() - _seen) / _invocations; assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here"); assert(!CodeCache_lock->owned_by_self(), "just checking"); @@ -166,11 +157,12 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - for(int i = 0; i < todo && _current != NULL; i++) { + // The last invocation iterates until there are no more nmethods + for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) { - // Since we will give up the CodeCache_lock, always skip ahead to an nmethod. - // Other blobs can be deleted by other threads - // Read next before we potentially delete current + // Since we will give up the CodeCache_lock, always skip ahead + // to the next nmethod. Other blobs can be deleted by other + // threads but nmethods are only reclaimed by the sweeper. nmethod* next = CodeCache::next_nmethod(_current); // Now ready to process nmethod and give up CodeCache_lock @@ -183,6 +175,8 @@ } } + assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); + if (_current == NULL && !_rescan && (_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 @@ -201,6 +195,10 @@ tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); } #endif + + if (_invocations == 1) { + log_sweep("finished"); + } } @@ -223,7 +221,7 @@ 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 referes to it. + // 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) { @@ -320,16 +318,8 @@ jlong curr_interval = now - _last_was_full; if (curr_interval < max_interval) { _rescan = true; - if (PrintMethodFlushing) { - tty->print_cr("### handle full too often, turning off compiler"); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'", + curr_interval/1000); return; } } @@ -349,17 +339,7 @@ if ((!was_full()) && (is_full)) { if (!CodeCache::needs_flushing()) { - if (PrintMethodFlushing) { - tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("restart_compiler"); CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); return; } @@ -368,17 +348,7 @@ // Traverse the code cache trying to dump the oldest nmethods uint curr_max_comp_id = CompileBroker::get_compilation_id(); uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; - if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + log_sweep("start_cleaning"); nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); jint disconnected = 0; @@ -411,13 +381,9 @@ nm = CodeCache::alive_nmethod(CodeCache::next(nm)); } - if (LogCompilation && (xtty != NULL)) { - ttyLocker ttyl; - xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()); - xtty->stamp(); - xtty->end_elem(); - } + 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 // traversal cycle and turn it back on if it clears enough space. @@ -435,3 +401,38 @@ } #endif } + + +// Print out some state information about the current sweep and the +// state of the code cache if it's requested. +void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { + if (PrintMethodFlushing) { + ttyLocker ttyl; + tty->print("### sweeper: %s ", msg); + if (format != NULL) { + va_list ap; + va_start(ap, format); + tty->vprint(format, ap); + va_end(ap); + } + tty->print_cr(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" + " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", + CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); + } + + if (LogCompilation && (xtty != NULL)) { + ttyLocker ttyl; + xtty->begin_elem("sweeper state='%s' traversals=`" INTX_FORMAT "' ", msg, (intx)traversal_count()); + if (format != NULL) { + va_list ap; + va_start(ap, format); + xtty->vprint(format, ap); + va_end(ap); + } + xtty->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" + " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", + CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); + xtty->stamp(); + xtty->end_elem(); + } +}