< prev index next > src/hotspot/share/runtime/deoptimization.cpp
Print this page
#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"
#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"
// 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();
}
}
#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.
#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()) {
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
}
#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:
bool create_if_missing = ProfileTraps;
methodHandle profiled_method;
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;
}
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
}
}
}
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.
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;
}
}
}
}
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);
+ }
+
+ #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) {
int Deoptimization::trap_state_has_reason(int trap_state, int reason) {
return 0;
}
- void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action,
+ 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 >