< prev index next >

src/hotspot/share/runtime/deoptimization.cpp

Print this page
@@ -75,10 +75,11 @@
  #include "runtime/javaThread.hpp"
  #include "runtime/jniHandles.inline.hpp"
  #include "runtime/keepStackGCProcessed.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"

@@ -89,10 +90,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"

@@ -272,11 +274,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))
+ 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();

@@ -844,11 +846,11 @@
    }
  }
  #endif
  
  // Return BasicType of value being returned
- JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
+ 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.
  

@@ -1746,16 +1748,19 @@
  #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);
+   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) {
-     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()) {

@@ -2001,11 +2006,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)) {
+ 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

@@ -2077,11 +2082,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);
+     gather_statistics(nm, reason, action, trap_bc);
  
      // Ensure that we can record deopt. history:
      // Need MDO to record RTM code generation state.
      bool create_if_missing = ProfileTraps RTM_OPT_ONLY( || UseRTMLocking );
  

@@ -2600,22 +2605,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) {
+ 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 +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)
  };
  
- 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];
+ 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 < BC_CASE_LIMIT; bc_case++) {
+     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 +2835,34 @@
        }
      }
    }
    if (bc_counter_addr == nullptr) {
      // Overflow, or no given bytecode.
-     bc_counter_addr = &cases[BC_CASE_LIMIT-1];
+     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[Reason_none][0][0];
+   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 +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[reason][1+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 +2886,69 @@
    }
    return counter;
  }
  
  void Deoptimization::print_statistics() {
-   juint total = total_deoptimization_count();
+   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;
-   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);
+ #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_hist[reason][1+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) {
-             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");
+             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;
-             tty->print_cr("  %40s: " UINT32_FORMAT " (%.1f%%)", name, r, (r * 100.0) / total);
+             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
-     if (xtty != nullptr)  xtty->tail("statistics");
+ #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);
+ }
+ 
  #else // COMPILER2_OR_JVMCI
  
  
  // Stubs for C1 only system.
  bool Deoptimization::trap_state_is_recompiled(int trap_state) {

@@ -2955,5 +2990,48 @@
    jio_snprintf(buf, buflen, "#%d", trap_state);
    return buf;
  }
  
  #endif // COMPILER2_OR_JVMCI
+ 
+ #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 = %4ldms (elapsed) %4ldms (thread) (%5ld events)", #sub "::" #name, \
+                  _perf_##sub##_##name##_timer->elapsed_counter_value_ms(), \
+                  _perf_##sub##_##name##_timer->thread_counter_value_ms(), \
+                  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
< prev index next >