< prev index next >

src/hotspot/share/runtime/mutexLocker.cpp

Print this page
@@ -21,19 +21,22 @@
   * questions.
   *
   */
  
  #include "precompiled.hpp"
+ #include "compiler/compiler_globals.hpp"
  #include "gc/shared/gc_globals.hpp"
  #include "logging/log.hpp"
  #include "logging/logStream.hpp"
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
+ #include "runtime/java.hpp"
  #include "runtime/javaThread.hpp"
  #include "runtime/mutexLocker.hpp"
  #include "runtime/safepoint.hpp"
  #include "runtime/vmThread.hpp"
+ #include "services/management.hpp"
  #include "utilities/vmError.hpp"
  
  // Mutexes used in the VM (see comment in mutexLocker.hpp):
  
  Mutex*   Patching_lock                = nullptr;

@@ -78,20 +81,27 @@
  Mutex*   MarkStackChunkList_lock      = nullptr;
  Mutex*   MonitoringSupport_lock       = nullptr;
  Monitor* ConcurrentGCBreakpoints_lock = nullptr;
  Mutex*   Compile_lock                 = nullptr;
  Monitor* MethodCompileQueue_lock      = nullptr;
+ Monitor* MethodCompileQueueC1_lock    = nullptr;
+ Monitor* MethodCompileQueueC2_lock    = nullptr;
+ Monitor* MethodCompileQueueC3_lock    = nullptr;
+ Monitor* MethodCompileQueueSC1_lock   = nullptr;
+ Monitor* MethodCompileQueueSC2_lock   = nullptr;
  Monitor* CompileThread_lock           = nullptr;
  Monitor* Compilation_lock             = nullptr;
  Mutex*   CompileTaskAlloc_lock        = nullptr;
  Mutex*   CompileStatistics_lock       = nullptr;
  Mutex*   DirectivesStack_lock         = nullptr;
  Monitor* Terminator_lock              = nullptr;
  Monitor* InitCompleted_lock           = nullptr;
  Monitor* BeforeExit_lock              = nullptr;
  Monitor* Notify_lock                  = nullptr;
  Mutex*   ExceptionCache_lock          = nullptr;
+ Mutex*   TrainingData_lock            = nullptr;
+ Monitor* TrainingReplayQueue_lock     = nullptr;
  #ifndef PRODUCT
  Mutex*   FullGCALot_lock              = nullptr;
  #endif
  
  Mutex*   tty_lock                     = nullptr;

@@ -145,10 +155,11 @@
  Mutex*   DumpRegion_lock              = nullptr;
  Mutex*   ClassListFile_lock           = nullptr;
  Mutex*   UnregisteredClassesTable_lock= nullptr;
  Mutex*   LambdaFormInvokers_lock      = nullptr;
  Mutex*   ScratchObjects_lock          = nullptr;
+ Mutex*   ArchivedObjectTables_lock    = nullptr;
  #endif // INCLUDE_CDS
  Mutex*   Bootclasspath_lock           = nullptr;
  
  #if INCLUDE_JVMCI
  Monitor* JVMCI_lock                   = nullptr;

@@ -182,11 +193,13 @@
  }
  #endif
  
  static void add_mutex(Mutex* var) {
    assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX");
-   _mutex_array[_num_mutex++] = var;
+   int id = _num_mutex++;
+   _mutex_array[id] = var;
+ //  var->set_id(id);
  }
  
  #define MUTEX_STORAGE_NAME(name) name##_storage
  #define MUTEX_STORAGE(name, type) alignas(type) static uint8_t MUTEX_STORAGE_NAME(name)[sizeof(type)]
  #define MUTEX_DEF(name, type, pri, ...) {                                                       \

@@ -261,10 +274,25 @@
  
    MUTEX_DEFN(JfieldIdCreation_lock           , PaddedMutex  , safepoint);
  
    MUTEX_DEFN(CompiledIC_lock                 , PaddedMutex  , nosafepoint);  // locks VtableStubs_lock
    MUTEX_DEFN(MethodCompileQueue_lock         , PaddedMonitor, safepoint);
+   if (UseGlobalCompileQueueLock) {
+     MethodCompileQueueC1_lock  = MethodCompileQueue_lock;
+     MethodCompileQueueC2_lock  = MethodCompileQueue_lock;
+     MethodCompileQueueC3_lock  = MethodCompileQueue_lock;
+     MethodCompileQueueSC1_lock = MethodCompileQueue_lock;
+     MethodCompileQueueSC2_lock = MethodCompileQueue_lock;
+   } else {
+     MUTEX_DEFN(MethodCompileQueueC1_lock     , PaddedMonitor, safepoint);
+     MUTEX_DEFN(MethodCompileQueueC2_lock     , PaddedMonitor, safepoint);
+     MUTEX_DEFN(MethodCompileQueueC3_lock     , PaddedMonitor, safepoint);
+     MUTEX_DEFN(MethodCompileQueueSC1_lock    , PaddedMonitor, safepoint);
+     MUTEX_DEFN(MethodCompileQueueSC2_lock    , PaddedMonitor, safepoint);
+   }
+   MUTEX_DEFL(TrainingData_lock               , PaddedMutex  , MethodCompileQueue_lock);
+   MUTEX_DEFN(TrainingReplayQueue_lock        , PaddedMonitor, safepoint);
    MUTEX_DEFN(CompileStatistics_lock          , PaddedMutex  , safepoint);
    MUTEX_DEFN(DirectivesStack_lock            , PaddedMutex  , nosafepoint);
  
    MUTEX_DEFN(JvmtiVTMSTransition_lock        , PaddedMonitor, safepoint);   // used for Virtual Thread Mount State transition management
    MUTEX_DEFN(EscapeBarrier_lock              , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI

@@ -277,13 +305,11 @@
    MUTEX_DEFN(PeriodicTask_lock               , PaddedMonitor, safepoint, true);
    MUTEX_DEFN(RedefineClasses_lock            , PaddedMonitor, safepoint);
    MUTEX_DEFN(Verify_lock                     , PaddedMutex  , safepoint);
    MUTEX_DEFN(ClassLoaderDataGraph_lock       , PaddedMutex  , safepoint);
  
-   if (WhiteBoxAPI) {
-     MUTEX_DEFN(Compilation_lock              , PaddedMonitor, nosafepoint);
-   }
+   MUTEX_DEFN(Compilation_lock                , PaddedMonitor, nosafepoint);
  
  #if INCLUDE_JFR
    MUTEX_DEFN(JfrBuffer_lock                  , PaddedMutex  , event);
    MUTEX_DEFN(JfrMsg_lock                     , PaddedMonitor, event);
    MUTEX_DEFN(JfrStacktrace_lock              , PaddedMutex  , event);

@@ -307,10 +333,11 @@
    MUTEX_DEFN(DumpRegion_lock                 , PaddedMutex  , nosafepoint);
    MUTEX_DEFN(ClassListFile_lock              , PaddedMutex  , nosafepoint);
    MUTEX_DEFN(UnregisteredClassesTable_lock   , PaddedMutex  , nosafepoint-1);
    MUTEX_DEFN(LambdaFormInvokers_lock         , PaddedMutex  , safepoint);
    MUTEX_DEFN(ScratchObjects_lock             , PaddedMutex  , nosafepoint-1); // Holds DumpTimeTable_lock
+   MUTEX_DEFN(ArchivedObjectTables_lock       , PaddedMutex  , nosafepoint);
  #endif // INCLUDE_CDS
    MUTEX_DEFN(Bootclasspath_lock              , PaddedMutex  , nosafepoint);
  
  #if INCLUDE_JVMCI
    // JVMCIRuntime::_lock must be acquired before JVMCI_lock to avoid deadlock

@@ -325,11 +352,11 @@
    // tty_lock is held when printing nmethod and its relocations which use this lock.
    MUTEX_DEFL(ExternalsRecorder_lock         , PaddedMutex  , tty_lock);
  
    MUTEX_DEFL(Threads_lock                   , PaddedMonitor, CompileThread_lock, true);
    MUTEX_DEFL(Compile_lock                   , PaddedMutex  , MethodCompileQueue_lock);
-   MUTEX_DEFL(Heap_lock                      , PaddedMonitor, AdapterHandlerLibrary_lock);
+   MUTEX_DEFL(Heap_lock                      , PaddedMonitor, TrainingData_lock  /*AdapterHandlerLibrary_lock*/);
  
    MUTEX_DEFL(PerfDataMemAlloc_lock          , PaddedMutex  , Heap_lock);
    MUTEX_DEFL(PerfDataManager_lock           , PaddedMutex  , Heap_lock);
    MUTEX_DEFL(VMOperation_lock               , PaddedMonitor, Heap_lock, true);
    MUTEX_DEFL(ClassInitError_lock            , PaddedMonitor, Threads_lock);

@@ -362,10 +389,109 @@
  #undef MUTEX_DEFN
  #undef MUTEX_DEF
  #undef MUTEX_STORAGE
  #undef MUTEX_STORAGE_NAME
  
+ static const int MAX_NAMES = 200;
+ static const char* _names[MAX_NAMES] = { nullptr };
+ static bool _is_unique[MAX_NAMES] = { false };
+ static int _num_names = 0;
+ 
+ PerfCounter** MutexLockerImpl::_perf_lock_count     = nullptr;
+ PerfCounter** MutexLockerImpl::_perf_lock_wait_time = nullptr;
+ PerfCounter** MutexLockerImpl::_perf_lock_hold_time = nullptr;
+ 
+ void MutexLockerImpl::init_counters() {
+   if (ProfileVMLocks && UsePerfData) {
+     ResourceMark rm;
+     EXCEPTION_MARK;
+     _perf_lock_count     = NEW_C_HEAP_ARRAY(PerfCounter*, MAX_NAMES + 1, mtInternal);
+     _perf_lock_wait_time = NEW_C_HEAP_ARRAY(PerfCounter*, MAX_NAMES + 1, mtInternal);
+     _perf_lock_hold_time = NEW_C_HEAP_ARRAY(PerfCounter*, MAX_NAMES + 1, mtInternal);
+ 
+     NEWPERFEVENTCOUNTER(_perf_lock_count[0],     SUN_RT, PerfDataManager::counter_name("Other", "Count"));
+     NEWPERFEVENTCOUNTER(_perf_lock_wait_time[0], SUN_RT, PerfDataManager::counter_name("Other", "BeforeTime"));
+     NEWPERFEVENTCOUNTER(_perf_lock_hold_time[0], SUN_RT, PerfDataManager::counter_name("Other", "AfterTime"));
+     for (int i = 0; i < MAX_NAMES; i++) {
+       ResourceMark rm;
+       const char* counter_name = _names[i];
+       if (counter_name == nullptr) {
+         stringStream ss;
+         ss.print("UnnamedMutex#%d", i);
+         counter_name = ss.as_string();
+       }
+       NEWPERFEVENTCOUNTER(_perf_lock_count[i + 1],     SUN_RT, PerfDataManager::counter_name(counter_name, "Count"));
+       NEWPERFEVENTCOUNTER(_perf_lock_wait_time[i + 1], SUN_RT, PerfDataManager::counter_name(counter_name, "BeforeTime"));
+       NEWPERFEVENTCOUNTER(_perf_lock_hold_time[i + 1], SUN_RT, PerfDataManager::counter_name(counter_name, "AfterTime"));
+     }
+     if (HAS_PENDING_EXCEPTION) {
+       vm_exit_during_initialization("MutexLockerImpl::init_counters() failed unexpectedly");
+     }
+   }
+ }
+ 
+ int MutexLockerImpl::name2id(const char* name) {
+   if (ProfileVMLocks && UsePerfData) {
+     for (int i = 0; i < _num_names; i++) {
+       if (strcmp(_names[i], name) == 0) {
+         _is_unique[i] = false;
+         return i;
+       }
+     }
+     if (_num_names < MAX_NAMES) {
+       int new_id = _num_names++;
+       _names[new_id] = os::strdup(name, mtInternal);
+       _is_unique[new_id] = true;
+       return new_id;
+     }
+     log_debug(init)("Unnamed: %s", name); // no slots left
+   }
+   return -1;
+ }
+ 
+ void MutexLockerImpl::print_counter_on(outputStream* st, const char* name, bool is_unique, int idx) {
+   jlong count = _perf_lock_count[idx]->get_value();
+   if (count > 0) {
+     st->print_cr("  %3d: %s%40s = " JLONG_FORMAT_W(5) "us (" JLONG_FORMAT_W(5) "us) / " JLONG_FORMAT_W(9) " events",
+                  idx, (is_unique ? " " : "M"), name,
+                  Management::ticks_to_us(_perf_lock_hold_time[idx]->get_value()),
+                  Management::ticks_to_us(_perf_lock_wait_time[idx]->get_value()),
+                  count);
+   }
+ }
+ 
+ static jlong accumulate_lock_counters(PerfCounter** lock_counters) {
+   jlong acc = 0;
+   for (int i = 0; i < _num_names + 1; i++) { // 0 slot is reserved for unnamed locks
+     if (lock_counters[i] == nullptr) {
+       break;
+     }
+     acc += lock_counters[i]->get_value();
+   }
+   return acc;
+ }
+ 
+ void MutexLockerImpl::print_counters_on(outputStream* st) {
+   if (ProfileVMLocks && UsePerfData) {
+     jlong total_count     = accumulate_lock_counters(_perf_lock_count);
+     jlong total_wait_time = accumulate_lock_counters(_perf_lock_wait_time);
+     jlong total_hold_time = accumulate_lock_counters(_perf_lock_hold_time);
+ 
+     st->print_cr("MutexLocker: Total: %d named locks (%d unique names); hold = " JLONG_FORMAT "us (wait = " JLONG_FORMAT "us) / " JLONG_FORMAT " events for thread \"main\"",
+                  _num_mutex, _num_names,
+                  Management::ticks_to_us(total_hold_time),
+                  Management::ticks_to_us(total_wait_time),
+                  total_count);
+     for (int i = 0; i < _num_names; i++) {
+       print_counter_on(st, _names[i], _is_unique[i], i+1);
+     }
+     print_counter_on(st, "Unnamed / Other", false /*is_unique*/, 0);
+   } else {
+     st->print_cr("MutexLocker: no info (%s is disabled)", (UsePerfData ? "ProfileVMLocks" : "UsePerfData"));
+   }
+ }
+ 
  void MutexLockerImpl::post_initialize() {
    // Print mutex ranks if requested.
    LogTarget(Info, vmmutex) lt;
    if (lt.is_enabled()) {
      ResourceMark rm;
< prev index next >