< prev index next >

src/hotspot/share/compiler/compileBroker.cpp

Print this page

        

*** 2765,2826 **** if (aggregate) { print_info(out); } // We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this function. ! // That prevents another thread from destroying 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. ! // 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 ! MutexLocker mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag); out->print_cr("\n__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________\n", ts.seconds()); ! // If we serve an "allFun" call, it is beneficial to hold the CodeCache_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 ! // the CodeHeap being altered concurrently. ! Mutex* global_lock = allFun ? CodeCache_lock : NULL; ! Mutex* function_lock = allFun ? NULL : CodeCache_lock; ts_global.update(); // record starting point ! MutexLocker mu2(global_lock, Mutex::_no_safepoint_check_flag); ! if (global_lock != NULL) { ! out->print_cr("\n__ CodeCache (global) lock wait took %10.3f seconds _________\n", ts_global.seconds()); ts_global.update(); // record starting point } if (aggregate) { ts.update(); // record starting point ! MutexLocker mu3(function_lock, Mutex::_no_safepoint_check_flag); ! if (function_lock != NULL) { ! out->print_cr("\n__ CodeCache (function) lock wait took %10.3f seconds _________\n", ts.seconds()); } ts.update(); // record starting point CodeCache::aggregate(out, granularity); ! if (function_lock != NULL) { ! out->print_cr("\n__ 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) { ! // print_names() has shown to be sensitive to concurrent CodeHeap modifications. ! // Therefore, request the CodeCache_lock before calling... ! MutexLocker mu3(function_lock, Mutex::_no_safepoint_check_flag); CodeCache::print_names(out); } if (discard) CodeCache::discard(out); ! if (global_lock != NULL) { ! out->print_cr("\n__ 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()); } --- 2765,2846 ---- if (aggregate) { print_info(out); } // We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this 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. 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 ! MutexLocker mu0(CodeHeapStateAnalytics_lock, Mutex::_safepoint_check_flag); 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 ! MutexLocker mu1(global_lock_1, Mutex::_safepoint_check_flag); ! MutexLocker 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) { ts.update(); // record starting point ! MutexLocker mu11(function_lock_1, Mutex::_safepoint_check_flag); ! MutexLocker mu22(function_lock_2, Mutex::_no_safepoint_check_flag); ! if ((function_lock_1 != NULL) || (function_lock_1 != 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); ! if ((function_lock_1 != NULL) || (function_lock_1 != 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) { ! 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); ! 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 >