< prev index next >

src/hotspot/share/runtime/deoptimization.cpp

Print this page
@@ -74,10 +74,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"

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

@@ -271,11 +273,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();

@@ -843,11 +845,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.
  

@@ -1742,16 +1744,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);
+   CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
+   assert(cm != nullptr, "only compiled methods can deopt");
+   DeoptAction action = (cm->is_not_entrant() ? Action_make_not_entrant : Action_none);
+   ScopeDesc* cur_sd = cm->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(reason, action, bc);
  
    if (LogCompilation && xtty != nullptr) {
-     CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
-     assert(cm != 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()));
      cm->log_identity(xtty);
      xtty->end_head();
      for (ScopeDesc* sd = cm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {

@@ -1997,11 +2002,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

@@ -2596,22 +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) {
+ 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;

@@ -2866,47 +2871,55 @@
    }
    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(outputStream* st) {
    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);
+ #define PRINT_STAT_LINE(name, r) \
+       st->print_cr("%d (%4.1f%%) %s", (int)(r), ((r) == total ? 100.0 : (((r) * 100.0) / total)), name);
+   PRINT_STAT_LINE("total", total);
+   if (total > 0) {
      // 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",
+             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);
+             }
+             os::snprintf_checked(name, sizeof(name), "%-34s %16s %16s",
                      trap_reason_name(reason),
                      trap_action_name(action),
-                     Bytecodes::is_defined(bc)? Bytecodes::name(bc): "other");
+                     bc_name);
              juint r = counter >> LSB_BITS;
-             tty->print_cr("  %40s: " UINT32_FORMAT " (%.1f%%)", name, r, (r * 100.0) / total);
+             st->print_cr("  %s: " UINT32_FORMAT_W(5) " (%4.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
  

@@ -2951,5 +2964,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 >