< prev index next >
src/hotspot/share/compiler/compileBroker.cpp
Print this page
@@ -2742,10 +2742,11 @@
// That's a tradeoff which keeps together important blocks of output.
// At the same time, continuous tty_lock hold time is kept in check,
// preventing concurrently printing threads from stalling a long time.
void CompileBroker::print_heapinfo(outputStream* out, const char* function, size_t granularity) {
TimeStamp ts_total;
+ TimeStamp ts_global;
TimeStamp ts;
bool allFun = !strcmp(function, "all");
bool aggregate = !strcmp(function, "aggregate") || !strcmp(function, "analyze") || allFun;
bool usedSpace = !strcmp(function, "UsedSpace") || allFun;
@@ -2771,48 +2772,82 @@
if (aggregate) {
print_info(out);
}
// We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this function.
- // That helps us getting a consistent view on the CodeHeap, at least for the "all" function.
+ // That prevents other threads from destroying (making inconsistent) our view on the CodeHeap.
// When we request individual parts of the analysis via the jcmd interface, it is possible
// that in between another thread (another jcmd user or the vm running into CodeCache OOM)
- // updated the aggregated data. That's a tolerable tradeoff because we can't hold a lock
- // across user interaction.
+ // updated the aggregated data. We will then see a modified, but again consistent, view
+ // on the CodeHeap. That's a tolerable tradeoff we have to accept because we can't hold
+ // a lock across user interaction.
+
+ // We should definitely acquire this lock before acquiring Compile_lock and CodeCache_lock.
+ // CodeHeapStateAnalytics_lock may be held by a concurrent thread for a long time,
+ // leading to an unnecessarily long hold time of the other locks we acquired before.
ts.update(); // record starting point
- MutexLockerEx mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag);
- out->cr();
- out->print_cr("__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________", ts.seconds());
- out->cr();
+ MutexLockerEx mu0(CodeHeapStateAnalytics_lock);
+ out->print_cr("\n__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________\n", ts.seconds());
+
+ // Holding the CodeCache_lock protects from concurrent alterations of the CodeCache.
+ // Unfortunately, such protection is not sufficient:
+ // When a new nmethod is created via ciEnv::register_method(), the
+ // Compile_lock is taken first. After some initializations,
+ // nmethod::new_nmethod() takes over, grabbing the CodeCache_lock
+ // immediately (after finalizing the oop references). To lock out concurrent
+ // modifiers, we have to grab both locks as well in the described sequence.
+ //
+ // If we serve an "allFun" call, it is beneficial to hold CodeCache_lock and Compile_lock
+ // for the entire duration of aggregation and printing. That makes sure we see
+ // a consistent picture and do not run into issues caused by concurrent alterations.
+ bool should_take_Compile_lock = !SafepointSynchronize::is_at_safepoint() &&
+ !Compile_lock->owned_by_self();
+ bool should_take_CodeCache_lock = !SafepointSynchronize::is_at_safepoint() &&
+ !CodeCache_lock->owned_by_self();
+ Mutex* global_lock_1 = allFun ? (should_take_Compile_lock ? Compile_lock : NULL) : NULL;
+ Monitor* global_lock_2 = allFun ? (should_take_CodeCache_lock ? CodeCache_lock : NULL) : NULL;
+ Mutex* function_lock_1 = allFun ? NULL : (should_take_Compile_lock ? Compile_lock : NULL);
+ Monitor* function_lock_2 = allFun ? NULL : (should_take_CodeCache_lock ? CodeCache_lock : NULL);
+ ts_global.update(); // record starting point
+ MutexLockerEx mu1(global_lock_1, Mutex::_no_safepoint_check_flag);
+ MutexLockerEx mu2(global_lock_2, Mutex::_no_safepoint_check_flag);
+ if ((global_lock_1 != NULL) || (global_lock_2 != NULL)) {
+ out->print_cr("\n__ Compile & CodeCache (global) lock wait took %10.3f seconds _________\n", ts_global.seconds());
+ ts_global.update(); // record starting point
+ }
if (aggregate) {
- // It is sufficient to hold the CodeCache_lock only for the aggregate step.
- // All other functions operate on aggregated data - except MethodNames, but that should be safe.
- // The separate CodeHeapStateAnalytics_lock protects the printing functions against
- // concurrent aggregate steps. Acquire this lock before acquiring the CodeCache_lock.
- // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time,
- // leading to an unnecessarily long hold time of the CodeCache_lock.
ts.update(); // record starting point
- MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- out->cr();
- out->print_cr("__ CodeCache lock wait took %10.3f seconds _________", ts.seconds());
- out->cr();
+ MutexLockerEx mu11(function_lock_1, Mutex::_no_safepoint_check_flag);
+ MutexLockerEx mu22(function_lock_2, Mutex::_no_safepoint_check_flag);
+ if ((function_lock_1 != NULL) || (function_lock_2 != NULL)) {
+ out->print_cr("\n__ Compile & CodeCache (function) lock wait took %10.3f seconds _________\n", ts.seconds());
+ }
ts.update(); // record starting point
CodeCache::aggregate(out, granularity);
- out->cr();
- out->print_cr("__ CodeCache lock hold took %10.3f seconds _________", ts.seconds());
- out->cr();
+ if ((function_lock_1 != NULL) || (function_lock_2 != NULL)) {
+ out->print_cr("\n__ Compile & CodeCache (function) lock hold took %10.3f seconds _________\n", ts.seconds());
+ }
}
if (usedSpace) CodeCache::print_usedSpace(out);
if (freeSpace) CodeCache::print_freeSpace(out);
if (methodCount) CodeCache::print_count(out);
if (methodSpace) CodeCache::print_space(out);
if (methodAge) CodeCache::print_age(out);
- if (methodNames) CodeCache::print_names(out);
+ if (methodNames) {
+ if (allFun) {
+ // print_names() can only be used safely if the locks have been continuously held
+ // since aggregation begin. That is true only for function "all".
+ CodeCache::print_names(out);
+ } else {
+ out->print_cr("\nCodeHeapStateAnalytics: Function 'MethodNames' is only available as part of function 'all'");
+ }
+ }
if (discard) CodeCache::discard(out);
- out->cr();
- out->print_cr("__ CodeHeapStateAnalytics total duration %10.3f seconds _________", ts_total.seconds());
- out->cr();
+ if ((global_lock_1 != NULL) || (global_lock_2 != NULL)) {
+ out->print_cr("\n__ Compile & CodeCache (global) lock hold took %10.3f seconds _________\n", ts_global.seconds());
+ }
+ out->print_cr("\n__ CodeHeapStateAnalytics total duration %10.3f seconds _________\n", ts_total.seconds());
}
< prev index next >