< prev index next >

src/hotspot/share/runtime/deoptimization.cpp

Print this page
*** 78,10 ***
--- 78,11 ---
  #include "runtime/keepStackGCProcessed.hpp"
  #include "runtime/lightweightSynchronizer.hpp"
  #include "runtime/lockStack.inline.hpp"
  #include "runtime/objectMonitor.inline.hpp"
  #include "runtime/osThread.hpp"
+ #include "runtime/perfData.inline.hpp"
  #include "runtime/safepointVerifiers.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/stackFrameStream.inline.hpp"
  #include "runtime/stackValue.hpp"

*** 92,10 ***
--- 93,11 ---
  #include "runtime/threadWXSetters.inline.hpp"
  #include "runtime/vframe.hpp"
  #include "runtime/vframeArray.hpp"
  #include "runtime/vframe_hp.hpp"
  #include "runtime/vmOperations.hpp"
+ #include "services/management.hpp"
  #include "utilities/checkedCast.hpp"
  #include "utilities/events.hpp"
  #include "utilities/growableArray.hpp"
  #include "utilities/macros.hpp"
  #include "utilities/preserveException.hpp"

*** 275,11 ***
  
  // In order to make fetch_unroll_info work properly with escape
  // analysis, the method was changed from JRT_LEAF to JRT_BLOCK_ENTRY.
  // The actual reallocation of previously eliminated objects occurs in realloc_objects,
  // which is called from the method fetch_unroll_info_helper below.
! JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* current, int exec_mode))
    // fetch_unroll_info() is called at the beginning of the deoptimization
    // handler. Note this fact before we start generating temporary frames
    // that can confuse an asynchronous stack walker. This counter is
    // decremented at the end of unpack_frames().
    current->inc_in_deopt_handler();
--- 277,11 ---
  
  // In order to make fetch_unroll_info work properly with escape
  // analysis, the method was changed from JRT_LEAF to JRT_BLOCK_ENTRY.
  // The actual reallocation of previously eliminated objects occurs in realloc_objects,
  // which is called from the method fetch_unroll_info_helper below.
! JRT_BLOCK_ENTRY_PROF(Deoptimization::UnrollBlock*, Deoptimization, fetch_unroll_info, Deoptimization::fetch_unroll_info(JavaThread* current, int exec_mode))
    // fetch_unroll_info() is called at the beginning of the deoptimization
    // handler. Note this fact before we start generating temporary frames
    // that can confuse an asynchronous stack walker. This counter is
    // decremented at the end of unpack_frames().
    current->inc_in_deopt_handler();

*** 847,11 ***
    }
  }
  #endif
  
  // Return BasicType of value being returned
! JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
    assert(thread == JavaThread::current(), "pre-condition");
  
    // We are already active in the special DeoptResourceMark any ResourceObj's we
    // allocate will be freed at the end of the routine.
  
--- 849,11 ---
    }
  }
  #endif
  
  // Return BasicType of value being returned
! JRT_LEAF_PROF_NO_THREAD(BasicType, Deoptimization, unpack_frames, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
    assert(thread == JavaThread::current(), "pre-condition");
  
    // We are already active in the special DeoptResourceMark any ResourceObj's we
    // allocate will be freed at the end of the routine.
  

*** 1758,16 ***
  #endif
  
  void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
    assert(fr.can_be_deoptimized(), "checking frame type");
  
!   gather_statistics(reason, Action_none, Bytecodes::_illegal);
  
    if (LogCompilation && xtty != nullptr) {
-     nmethod* nm = fr.cb()->as_nmethod_or_null();
-     assert(nm != nullptr, "only compiled methods can deopt");
- 
      ttyLocker ttyl;
      xtty->begin_head("deoptimized thread='" UINTX_FORMAT "' reason='%s' pc='" INTPTR_FORMAT "'",(uintx)thread->osthread()->thread_id(), trap_reason_name(reason), p2i(fr.pc()));
      nm->log_identity(xtty);
      xtty->end_head();
      for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {
--- 1760,19 ---
  #endif
  
  void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
    assert(fr.can_be_deoptimized(), "checking frame type");
  
!   nmethod* nm = fr.cb()->as_nmethod_or_null();
+   assert(nm != nullptr, "only compiled methods can deopt");
+   DeoptAction action = (nm->is_not_entrant() ? Action_make_not_entrant : Action_none);
+   ScopeDesc* cur_sd = nm->scope_desc_at(fr.pc());
+   Bytecodes::Code bc = (cur_sd->bci() == -1 ? Bytecodes::_nop // deopt on method entry
+                                             : cur_sd->method()->java_code_at(cur_sd->bci()));
+   gather_statistics(nm, reason, action, bc);
  
    if (LogCompilation && xtty != nullptr) {
      ttyLocker ttyl;
      xtty->begin_head("deoptimized thread='" UINTX_FORMAT "' reason='%s' pc='" INTPTR_FORMAT "'",(uintx)thread->osthread()->thread_id(), trap_reason_name(reason), p2i(fr.pc()));
      nm->log_identity(xtty);
      xtty->end_head();
      for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {

*** 2013,11 ***
      ls.print_cr("pc=" INTPTR_FORMAT " relative_pc=" INTPTR_FORMAT,
               pc, fr.pc() - nm->code_begin());
    }
  }
  
! JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint trap_request)) {
    HandleMark hm(current);
  
    // uncommon_trap() is called at the beginning of the uncommon trap
    // handler. Note this fact before we start generating temporary frames
    // that can confuse an asynchronous stack walker. This counter is
--- 2018,11 ---
      ls.print_cr("pc=" INTPTR_FORMAT " relative_pc=" INTPTR_FORMAT,
               pc, fr.pc() - nm->code_begin());
    }
  }
  
! JRT_ENTRY_PROF(void, Deoptimization, uncommon_trap_inner, Deoptimization::uncommon_trap_inner(JavaThread* current, jint trap_request)) {
    HandleMark hm(current);
  
    // uncommon_trap() is called at the beginning of the uncommon trap
    // handler. Note this fact before we start generating temporary frames
    // that can confuse an asynchronous stack walker. This counter is

*** 2089,11 ***
      }
  #endif
  
      Bytecodes::Code trap_bc     = trap_method->java_code_at(trap_bci);
      // Record this event in the histogram.
!     gather_statistics(reason, action, trap_bc);
  
      // Ensure that we can record deopt. history:
      bool create_if_missing = ProfileTraps;
  
      methodHandle profiled_method;
--- 2094,11 ---
      }
  #endif
  
      Bytecodes::Code trap_bc     = trap_method->java_code_at(trap_bci);
      // Record this event in the histogram.
!     gather_statistics(nm, reason, action, trap_bc);
  
      // Ensure that we can record deopt. history:
      bool create_if_missing = ProfileTraps;
  
      methodHandle profiled_method;

*** 2601,22 ***
                             ignore_this_trap_count,
                             ignore_maybe_prior_trap,
                             ignore_maybe_prior_recompile);
  }
  
! Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* current, jint trap_request, jint exec_mode) {
    // Enable WXWrite: current function is called from methods compiled by C2 directly
    MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, current));
  
    // Still in Java no safepoints
    {
      // This enters VM and may safepoint
      uncommon_trap_inner(current, trap_request);
    }
    HandleMark hm(current);
    return fetch_unroll_info_helper(current, exec_mode);
! }
  
  // Local derived constants.
  // Further breakdown of DataLayout::trap_state, as promised by DataLayout.
  const int DS_REASON_MASK   = ((uint)DataLayout::trap_mask) >> 1;
  const int DS_RECOMPILE_BIT = DataLayout::trap_mask - DS_REASON_MASK;
--- 2606,22 ---
                             ignore_this_trap_count,
                             ignore_maybe_prior_trap,
                             ignore_maybe_prior_recompile);
  }
  
! PROF_ENTRY(Deoptimization::UnrollBlock*, Deoptimization, uncommon_trap, Deoptimization::uncommon_trap(JavaThread* current, jint trap_request, jint exec_mode))
    // Enable WXWrite: current function is called from methods compiled by C2 directly
    MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, current));
  
    // Still in Java no safepoints
    {
      // This enters VM and may safepoint
      uncommon_trap_inner(current, trap_request);
    }
    HandleMark hm(current);
    return fetch_unroll_info_helper(current, exec_mode);
! PROF_END
  
  // Local derived constants.
  // Further breakdown of DataLayout::trap_state, as promised by DataLayout.
  const int DS_REASON_MASK   = ((uint)DataLayout::trap_mask) >> 1;
  const int DS_RECOMPILE_BIT = DataLayout::trap_mask - DS_REASON_MASK;

*** 2801,32 ***
    }
    return buf;
  }
  
  juint Deoptimization::_deoptimization_hist
          [Deoptimization::Reason_LIMIT]
      [1 + Deoptimization::Action_LIMIT]
          [Deoptimization::BC_CASE_LIMIT]
    = {0};
  
  enum {
    LSB_BITS = 8,
    LSB_MASK = right_n_bits(LSB_BITS)
  };
  
! void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action,
-                                        Bytecodes::Code bc) {
-   assert(reason >= 0 && reason < Reason_LIMIT, "oob");
-   assert(action >= 0 && action < Action_LIMIT, "oob");
-   _deoptimization_hist[Reason_none][0][0] += 1;  // total
-   _deoptimization_hist[reason][0][0]      += 1;  // per-reason total
-   juint* cases = _deoptimization_hist[reason][1+action];
    juint* bc_counter_addr = nullptr;
    juint  bc_counter      = 0;
    // Look for an unused counter, or an exact match to this BC.
    if (bc != Bytecodes::_illegal) {
!     for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
        juint* counter_addr = &cases[bc_case];
        juint  counter = *counter_addr;
        if ((counter == 0 && bc_counter_addr == nullptr)
            || (Bytecodes::Code)(counter & LSB_MASK) == bc) {
          // this counter is either free or is already devoted to this BC
--- 2806,27 ---
    }
    return buf;
  }
  
  juint Deoptimization::_deoptimization_hist
+         [1 + 4 + 5] // total + online + archived
          [Deoptimization::Reason_LIMIT]
      [1 + Deoptimization::Action_LIMIT]
          [Deoptimization::BC_CASE_LIMIT]
    = {0};
  
  enum {
    LSB_BITS = 8,
    LSB_MASK = right_n_bits(LSB_BITS)
  };
  
! static void update(juint* cases, Bytecodes::Code bc) {
    juint* bc_counter_addr = nullptr;
    juint  bc_counter      = 0;
    // Look for an unused counter, or an exact match to this BC.
    if (bc != Bytecodes::_illegal) {
!     for (int bc_case = 0; bc_case < Deoptimization::BC_CASE_LIMIT; bc_case++) {
        juint* counter_addr = &cases[bc_case];
        juint  counter = *counter_addr;
        if ((counter == 0 && bc_counter_addr == nullptr)
            || (Bytecodes::Code)(counter & LSB_MASK) == bc) {
          // this counter is either free or is already devoted to this BC

*** 2835,18 ***
        }
      }
    }
    if (bc_counter_addr == nullptr) {
      // Overflow, or no given bytecode.
!     bc_counter_addr = &cases[BC_CASE_LIMIT-1];
      bc_counter = (*bc_counter_addr & ~LSB_MASK);  // clear LSB
    }
    *bc_counter_addr = bc_counter + (1 << LSB_BITS);
  }
  
  jint Deoptimization::total_deoptimization_count() {
!   return _deoptimization_hist[Reason_none][0][0];
  }
  
  // Get the deopt count for a specific reason and a specific action. If either
  // one of 'reason' or 'action' is null, the method returns the sum of all
  // deoptimizations with the specific 'action' or 'reason' respectively.
--- 2835,34 ---
        }
      }
    }
    if (bc_counter_addr == nullptr) {
      // Overflow, or no given bytecode.
!     bc_counter_addr = &cases[Deoptimization::BC_CASE_LIMIT-1];
      bc_counter = (*bc_counter_addr & ~LSB_MASK);  // clear LSB
    }
    *bc_counter_addr = bc_counter + (1 << LSB_BITS);
  }
  
+ 
+ void Deoptimization::gather_statistics(nmethod* nm, DeoptReason reason, DeoptAction action,
+                                        Bytecodes::Code bc) {
+   assert(reason >= 0 && reason < Reason_LIMIT, "oob");
+   assert(action >= 0 && action < Action_LIMIT, "oob");
+   _deoptimization_hist[0][Reason_none][0][0] += 1;  // total
+   _deoptimization_hist[0][reason][0][0]      += 1;  // per-reason total
+ 
+   update(_deoptimization_hist[0][reason][1+action], bc);
+ 
+   uint lvl = nm->comp_level() + (nm->is_scc() ? 4 : 0) + (nm->preloaded() ? 1 : 0);
+   _deoptimization_hist[lvl][Reason_none][0][0] += 1;  // total
+   _deoptimization_hist[lvl][reason][0][0]      += 1;  // per-reason total
+   update(_deoptimization_hist[lvl][reason][1+action], bc);
+ }
+ 
  jint Deoptimization::total_deoptimization_count() {
!   return _deoptimization_hist[0][Reason_none][0][0];
  }
  
  // Get the deopt count for a specific reason and a specific action. If either
  // one of 'reason' or 'action' is null, the method returns the sum of all
  // deoptimizations with the specific 'action' or 'reason' respectively.

*** 2858,11 ***
    juint counter = 0;
    for (int reason = 0; reason < Reason_LIMIT; reason++) {
      if (reason_str == nullptr || !strcmp(reason_str, trap_reason_name(reason))) {
        for (int action = 0; action < Action_LIMIT; action++) {
          if (action_str == nullptr || !strcmp(action_str, trap_action_name(action))) {
!           juint* cases = _deoptimization_hist[reason][1+action];
            for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
              counter += cases[bc_case] >> LSB_BITS;
            }
          }
        }
--- 2874,11 ---
    juint counter = 0;
    for (int reason = 0; reason < Reason_LIMIT; reason++) {
      if (reason_str == nullptr || !strcmp(reason_str, trap_reason_name(reason))) {
        for (int action = 0; action < Action_LIMIT; action++) {
          if (action_str == nullptr || !strcmp(action_str, trap_action_name(action))) {
!           juint* cases = _deoptimization_hist[0][reason][1+action];
            for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
              counter += cases[bc_case] >> LSB_BITS;
            }
          }
        }

*** 2870,50 ***
    }
    return counter;
  }
  
  void Deoptimization::print_statistics() {
!   juint total = total_deoptimization_count();
    juint account = total;
!   if (total != 0) {
!     ttyLocker ttyl;
!     if (xtty != nullptr)  xtty->head("statistics type='deoptimization'");
!     tty->print_cr("Deoptimization traps recorded:");
-     #define PRINT_STAT_LINE(name, r) \
-       tty->print_cr("  %4d (%4.1f%%) %s", (int)(r), ((r) * 100.0) / total, name);
      PRINT_STAT_LINE("total", total);
      // For each non-zero entry in the histogram, print the reason,
      // the action, and (if specifically known) the type of bytecode.
      for (int reason = 0; reason < Reason_LIMIT; reason++) {
        for (int action = 0; action < Action_LIMIT; action++) {
!         juint* cases = _deoptimization_hist[reason][1+action];
          for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
            juint counter = cases[bc_case];
            if (counter != 0) {
-             char name[1*K];
              Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK);
!             if (bc_case == BC_CASE_LIMIT && (int)bc == 0)
!               bc = Bytecodes::_illegal;
!             os::snprintf_checked(name, sizeof(name), "%s/%s/%s",
!                     trap_reason_name(reason),
!                     trap_action_name(action),
!                     Bytecodes::is_defined(bc)? Bytecodes::name(bc): "other");
              juint r = counter >> LSB_BITS;
!             tty->print_cr("  %40s: " UINT32_FORMAT " (%.1f%%)", name, r, (r * 100.0) / total);
              account -= r;
            }
          }
        }
      }
      if (account != 0) {
        PRINT_STAT_LINE("unaccounted", account);
      }
!     #undef PRINT_STAT_LINE
-     if (xtty != nullptr)  xtty->tail("statistics");
    }
  }
  
  #else // COMPILER2_OR_JVMCI
  
  
  // Stubs for C1 only system.
  bool Deoptimization::trap_state_is_recompiled(int trap_state) {
--- 2886,112 ---
    }
    return counter;
  }
  
  void Deoptimization::print_statistics() {
!   ttyLocker ttyl;
+   if (xtty != nullptr)  xtty->head("statistics type='deoptimization'");
+   tty->print_cr("Deoptimization traps recorded:");
+   print_statistics_on(tty);
+   if (xtty != nullptr)  xtty->tail("statistics");
+ }
+ 
+ void Deoptimization::print_statistics_on(const char* title, int lvl, outputStream* st) {
+   juint total = _deoptimization_hist[lvl][Reason_none][0][0];
    juint account = total;
! #define PRINT_STAT_LINE(name, r) \
!       st->print_cr("    %d (%4.1f%%) %s", (int)(r), ((r) == total ? 100.0 : (((r) * 100.0) / total)), name);
!   if (total > 0) {
!     st->print("  %s: ", title);
      PRINT_STAT_LINE("total", total);
      // For each non-zero entry in the histogram, print the reason,
      // the action, and (if specifically known) the type of bytecode.
      for (int reason = 0; reason < Reason_LIMIT; reason++) {
        for (int action = 0; action < Action_LIMIT; action++) {
!         juint* cases = Deoptimization::_deoptimization_hist[lvl][reason][1+action];
          for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
            juint counter = cases[bc_case];
            if (counter != 0) {
              Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK);
!             const char* bc_name = "other";
!             if (bc_case == (BC_CASE_LIMIT-1) && bc == Bytecodes::_nop) {
!               // overwritten
!             } else if (Bytecodes::is_defined(bc)) {
!               bc_name = Bytecodes::name(bc);
!             }
              juint r = counter >> LSB_BITS;
!             st->print_cr("    %-34s %16s %16s: " UINT32_FORMAT_W(5) " (%4.1f%%)",
+                          trap_reason_name(reason), trap_action_name(action), bc_name,
+                          r, (r * 100.0) / total);
              account -= r;
            }
          }
        }
      }
      if (account != 0) {
        PRINT_STAT_LINE("unaccounted", account);
      }
! #undef PRINT_STAT_LINE
    }
  }
  
+ void Deoptimization::print_statistics_on(outputStream* st) {
+ //  print_statistics_on("Total", 0, st);
+   print_statistics_on("Tier1", 1, st);
+   print_statistics_on("Tier2", 2, st);
+   print_statistics_on("Tier3", 3, st);
+   print_statistics_on("Tier4", 4, st);
+ 
+   print_statistics_on("SC Tier1", 5, st);
+   print_statistics_on("SC Tier2", 6, st);
+   print_statistics_on("SC Tier4", 8, st);
+   print_statistics_on("SC Tier5 (preloaded)", 9, st);
+ }
+ 
+ #define DO_COUNTERS(macro) \
+   macro(Deoptimization, fetch_unroll_info)   \
+   macro(Deoptimization, unpack_frames) \
+   macro(Deoptimization, uncommon_trap_inner) \
+   macro(Deoptimization, uncommon_trap)
+ 
+ #define INIT_COUNTER(sub, name) \
+   NEWPERFTICKCOUNTERS(_perf_##sub##_##name##_timer, SUN_RT, #sub "::" #name) \
+   NEWPERFEVENTCOUNTER(_perf_##sub##_##name##_count, SUN_RT, #sub "::" #name "_count");
+ 
+ void Deoptimization::init_counters() {
+   if (ProfileRuntimeCalls && UsePerfData) {
+     EXCEPTION_MARK;
+ 
+     DO_COUNTERS(INIT_COUNTER)
+ 
+     if (HAS_PENDING_EXCEPTION) {
+       vm_exit_during_initialization("jvm_perf_init failed unexpectedly");
+     }
+   }
+ }
+ #undef INIT_COUNTER
+ 
+ #define PRINT_COUNTER(sub, name) { \
+   jlong count = _perf_##sub##_##name##_count->get_value(); \
+   if (count > 0) { \
+     st->print_cr("  %-50s = " JLONG_FORMAT_W(6) "us (elapsed) " JLONG_FORMAT_W(6) "us (thread) (" JLONG_FORMAT_W(5) " events)", #sub "::" #name, \
+                  _perf_##sub##_##name##_timer->elapsed_counter_value_us(), \
+                  _perf_##sub##_##name##_timer->thread_counter_value_us(), \
+                  count); \
+   }}
+ 
+ void Deoptimization::print_counters_on(outputStream* st) {
+   if (ProfileRuntimeCalls && UsePerfData) {
+     DO_COUNTERS(PRINT_COUNTER)
+   } else {
+     st->print_cr("  Deoptimization: no info (%s is disabled)", (UsePerfData ? "ProfileRuntimeCalls" : "UsePerfData"));
+   }
+ }
+ 
+ #undef PRINT_COUNTER
+ #undef DO_COUNTERS
+ 
  #else // COMPILER2_OR_JVMCI
  
  
  // Stubs for C1 only system.
  bool Deoptimization::trap_state_is_recompiled(int trap_state) {

*** 2943,17 ***
  
  int Deoptimization::trap_state_has_reason(int trap_state, int reason) {
    return 0;
  }
  
! void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action,
                                         Bytecodes::Code bc) {
    // no update
  }
  
  const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
                                                int trap_state) {
    jio_snprintf(buf, buflen, "#%d", trap_state);
    return buf;
  }
  
  #endif // COMPILER2_OR_JVMCI
--- 3021,29 ---
  
  int Deoptimization::trap_state_has_reason(int trap_state, int reason) {
    return 0;
  }
  
! void Deoptimization::gather_statistics(nmethod* nm, DeoptReason reason, DeoptAction action,
                                         Bytecodes::Code bc) {
    // no update
  }
  
  const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
                                                int trap_state) {
    jio_snprintf(buf, buflen, "#%d", trap_state);
    return buf;
  }
  
+ void Deoptimization::init_counters() {
+   // nothing to do
+ }
+ 
+ void Deoptimization::print_counters_on(outputStream* st) {
+   // no output
+ }
+ 
+ void Deoptimization::print_statistics_on(outputStream* st) {
+   // no output
+ }
+ 
  #endif // COMPILER2_OR_JVMCI
< prev index next >