8165056: move JIT Compiler related files from runtime/ to compiler/ directory
Reviewed-by: kvn, coleenp, dholmes
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -33,13 +33,13 @@
#include "ci/ciKlass.hpp"
#include "ci/ciMemberName.hpp"
#include "ci/ciUtilities.inline.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecode.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/sharedRuntime.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/bitMap.inline.hpp"
--- a/src/hotspot/share/c1/c1_Runtime1.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -37,6 +37,7 @@
#include "code/pcDesc.hpp"
#include "code/scopeDesc.hpp"
#include "code/vtableStubs.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
@@ -55,7 +56,6 @@
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/classfile/classLoader.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/classfile/classLoader.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -57,7 +57,6 @@
#include "oops/symbol.hpp"
#include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
--- a/src/hotspot/share/code/codeCache.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/code/codeCache.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -33,6 +33,7 @@
#include "code/icBuffer.hpp"
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
@@ -46,7 +47,6 @@
#include "oops/oop.inline.hpp"
#include "oops/verifyOopClosure.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/compilationPolicy.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderDataGraph.inline.hpp"
+#include "code/compiledIC.hpp"
+#include "code/nmethod.hpp"
+#include "code/scopeDesc.hpp"
+#include "compiler/compilationPolicy.hpp"
+#include "compiler/tieredThresholdPolicy.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/nativeLookup.hpp"
+#include "runtime/frame.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.hpp"
+#include "runtime/vframe.hpp"
+#include "runtime/vmOperations.hpp"
+#include "utilities/events.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#ifdef COMPILER1
+#include "c1/c1_Compiler.hpp"
+#endif
+#ifdef COMPILER2
+#include "opto/c2compiler.hpp"
+#endif
+
+CompilationPolicy* CompilationPolicy::_policy;
+
+// Determine compilation policy based on command line argument
+void compilationPolicy_init() {
+ #ifdef TIERED
+ if (TieredCompilation) {
+ CompilationPolicy::set_policy(new TieredThresholdPolicy());
+ } else {
+ CompilationPolicy::set_policy(new SimpleCompPolicy());
+ }
+ #else
+ CompilationPolicy::set_policy(new SimpleCompPolicy());
+ #endif
+
+ CompilationPolicy::policy()->initialize();
+}
+
+// Returns true if m must be compiled before executing it
+// This is intended to force compiles for methods (usually for
+// debugging) that would otherwise be interpreted for some reason.
+bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level) {
+ // Don't allow Xcomp to cause compiles in replay mode
+ if (ReplayCompiles) return false;
+
+ if (m->has_compiled_code()) return false; // already compiled
+ if (!can_be_compiled(m, comp_level)) return false;
+
+ return !UseInterpreter || // must compile all methods
+ (UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
+}
+
+void CompilationPolicy::compile_if_required(const methodHandle& selected_method, TRAPS) {
+ if (must_be_compiled(selected_method)) {
+ // This path is unusual, mostly used by the '-Xcomp' stress test mode.
+
+ // Note: with several active threads, the must_be_compiled may be true
+ // while can_be_compiled is false; remove assert
+ // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
+ if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) {
+ // don't force compilation, resolve was on behalf of compiler
+ return;
+ }
+ if (selected_method->method_holder()->is_not_initialized()) {
+ // 'is_not_initialized' means not only '!is_initialized', but also that
+ // initialization has not been started yet ('!being_initialized')
+ // Do not force compilation of methods in uninitialized classes.
+ // Note that doing this would throw an assert later,
+ // in CompileBroker::compile_method.
+ // We sometimes use the link resolver to do reflective lookups
+ // even before classes are initialized.
+ return;
+ }
+ CompileBroker::compile_method(selected_method, InvocationEntryBci,
+ CompilationPolicy::policy()->initial_compile_level(),
+ methodHandle(), 0, CompileTask::Reason_MustBeCompiled, CHECK);
+ }
+}
+
+// Returns true if m is allowed to be compiled
+bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) {
+ // allow any levels for WhiteBox
+ assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
+
+ if (m->is_abstract()) return false;
+ if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
+
+ // Math intrinsics should never be compiled as this can lead to
+ // monotonicity problems because the interpreter will prefer the
+ // compiled code to the intrinsic version. This can't happen in
+ // production because the invocation counter can't be incremented
+ // but we shouldn't expose the system to this problem in testing
+ // modes.
+ if (!AbstractInterpreter::can_be_compiled(m)) {
+ return false;
+ }
+ if (comp_level == CompLevel_all) {
+ if (TieredCompilation) {
+ // enough to be compilable at any level for tiered
+ return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
+ } else {
+ // must be compilable at available level for non-tiered
+ return !m->is_not_compilable(CompLevel_highest_tier);
+ }
+ } else if (is_compile(comp_level)) {
+ return !m->is_not_compilable(comp_level);
+ }
+ return false;
+}
+
+// Returns true if m is allowed to be osr compiled
+bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) {
+ bool result = false;
+ if (comp_level == CompLevel_all) {
+ if (TieredCompilation) {
+ // enough to be osr compilable at any level for tiered
+ result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization);
+ } else {
+ // must be osr compilable at available level for non-tiered
+ result = !m->is_not_osr_compilable(CompLevel_highest_tier);
+ }
+ } else if (is_compile(comp_level)) {
+ result = !m->is_not_osr_compilable(comp_level);
+ }
+ return (result && can_be_compiled(m, comp_level));
+}
+
+bool CompilationPolicy::is_compilation_enabled() {
+ // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler
+ return CompileBroker::should_compile_new_jobs();
+}
+
+CompileTask* CompilationPolicy::select_task_helper(CompileQueue* compile_queue) {
+ // Remove unloaded methods from the queue
+ for (CompileTask* task = compile_queue->first(); task != NULL; ) {
+ CompileTask* next = task->next();
+ if (task->is_unloaded()) {
+ compile_queue->remove_and_mark_stale(task);
+ }
+ task = next;
+ }
+#if INCLUDE_JVMCI
+ if (UseJVMCICompiler && !BackgroundCompilation) {
+ /*
+ * In blocking compilation mode, the CompileBroker will make
+ * compilations submitted by a JVMCI compiler thread non-blocking. These
+ * compilations should be scheduled after all blocking compilations
+ * to service non-compiler related compilations sooner and reduce the
+ * chance of such compilations timing out.
+ */
+ for (CompileTask* task = compile_queue->first(); task != NULL; task = task->next()) {
+ if (task->is_blocking()) {
+ return task;
+ }
+ }
+ }
+#endif
+ return compile_queue->first();
+}
+
+#ifndef PRODUCT
+void SimpleCompPolicy::trace_osr_completion(nmethod* osr_nm) {
+ if (TraceOnStackReplacement) {
+ if (osr_nm == NULL) tty->print_cr("compilation failed");
+ else tty->print_cr("nmethod " INTPTR_FORMAT, p2i(osr_nm));
+ }
+}
+#endif // !PRODUCT
+
+void SimpleCompPolicy::initialize() {
+ // Setup the compiler thread numbers
+ if (CICompilerCountPerCPU) {
+ // Example: if CICompilerCountPerCPU is true, then we get
+ // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine.
+ // May help big-app startup time.
+ _compiler_count = MAX2(log2_int(os::active_processor_count())-1,1);
+ // Make sure there is enough space in the code cache to hold all the compiler buffers
+ size_t buffer_size = 1;
+#ifdef COMPILER1
+ buffer_size = is_client_compilation_mode_vm() ? Compiler::code_buffer_size() : buffer_size;
+#endif
+#ifdef COMPILER2
+ buffer_size = is_server_compilation_mode_vm() ? C2Compiler::initial_code_buffer_size() : buffer_size;
+#endif
+ int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size;
+ if (_compiler_count > max_count) {
+ // Lower the compiler count such that all buffers fit into the code cache
+ _compiler_count = MAX2(max_count, 1);
+ }
+ FLAG_SET_ERGO(CICompilerCount, _compiler_count);
+ } else {
+ _compiler_count = CICompilerCount;
+ }
+}
+
+// Note: this policy is used ONLY if TieredCompilation is off.
+// compiler_count() behaves the following way:
+// - with TIERED build (with both COMPILER1 and COMPILER2 defined) it should return
+// zero for the c1 compilation levels in server compilation mode runs
+// and c2 compilation levels in client compilation mode runs.
+// - with COMPILER2 not defined it should return zero for c2 compilation levels.
+// - with COMPILER1 not defined it should return zero for c1 compilation levels.
+// - if neither is defined - always return zero.
+int SimpleCompPolicy::compiler_count(CompLevel comp_level) {
+ assert(!TieredCompilation, "This policy should not be used with TieredCompilation");
+ if (COMPILER2_PRESENT(is_server_compilation_mode_vm() && is_c2_compile(comp_level) ||)
+ is_client_compilation_mode_vm() && is_c1_compile(comp_level)) {
+ return _compiler_count;
+ }
+ return 0;
+}
+
+void SimpleCompPolicy::reset_counter_for_invocation_event(const methodHandle& m) {
+ // Make sure invocation and backedge counter doesn't overflow again right away
+ // as would be the case for native methods.
+
+ // BUT also make sure the method doesn't look like it was never executed.
+ // Set carry bit and reduce counter's value to min(count, CompileThreshold/2).
+ MethodCounters* mcs = m->method_counters();
+ assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
+ mcs->invocation_counter()->set_carry();
+ mcs->backedge_counter()->set_carry();
+
+ assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed");
+}
+
+void SimpleCompPolicy::reset_counter_for_back_branch_event(const methodHandle& m) {
+ // Delay next back-branch event but pump up invocation counter to trigger
+ // whole method compilation.
+ MethodCounters* mcs = m->method_counters();
+ assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
+ InvocationCounter* i = mcs->invocation_counter();
+ InvocationCounter* b = mcs->backedge_counter();
+
+ // Don't set invocation_counter's value too low otherwise the method will
+ // look like immature (ic < ~5300) which prevents the inlining based on
+ // the type profiling.
+ i->set(i->state(), CompileThreshold);
+ // Don't reset counter too low - it is used to check if OSR method is ready.
+ b->set(b->state(), CompileThreshold / 2);
+}
+
+//
+// CounterDecay
+//
+// Iterates through invocation counters and decrements them. This
+// is done at each safepoint.
+//
+class CounterDecay : public AllStatic {
+ static jlong _last_timestamp;
+ static void do_method(Method* m) {
+ MethodCounters* mcs = m->method_counters();
+ if (mcs != NULL) {
+ mcs->invocation_counter()->decay();
+ }
+ }
+public:
+ static void decay();
+ static bool is_decay_needed() {
+ return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength;
+ }
+};
+
+jlong CounterDecay::_last_timestamp = 0;
+
+void CounterDecay::decay() {
+ _last_timestamp = os::javaTimeMillis();
+
+ // This operation is going to be performed only at the end of a safepoint
+ // and hence GC's will not be going on, all Java mutators are suspended
+ // at this point and hence SystemDictionary_lock is also not needed.
+ assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
+ size_t nclasses = ClassLoaderDataGraph::num_instance_classes();
+ size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
+ CounterHalfLifeTime);
+ for (size_t i = 0; i < classes_per_tick; i++) {
+ InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class();
+ if (k != NULL) {
+ k->methods_do(do_method);
+ }
+ }
+}
+
+// Called at the end of the safepoint
+void SimpleCompPolicy::do_safepoint_work() {
+ if(UseCounterDecay && CounterDecay::is_decay_needed()) {
+ CounterDecay::decay();
+ }
+}
+
+void SimpleCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
+ ScopeDesc* sd = trap_scope;
+ MethodCounters* mcs;
+ InvocationCounter* c;
+ for (; !sd->is_top(); sd = sd->sender()) {
+ mcs = sd->method()->method_counters();
+ if (mcs != NULL) {
+ // Reset ICs of inlined methods, since they can trigger compilations also.
+ mcs->invocation_counter()->reset();
+ }
+ }
+ mcs = sd->method()->method_counters();
+ if (mcs != NULL) {
+ c = mcs->invocation_counter();
+ if (is_osr) {
+ // It was an OSR method, so bump the count higher.
+ c->set(c->state(), CompileThreshold);
+ } else {
+ c->reset();
+ }
+ mcs->backedge_counter()->reset();
+ }
+}
+
+// This method can be called by any component of the runtime to notify the policy
+// that it's recommended to delay the compilation of this method.
+void SimpleCompPolicy::delay_compilation(Method* method) {
+ MethodCounters* mcs = method->method_counters();
+ if (mcs != NULL) {
+ mcs->invocation_counter()->decay();
+ mcs->backedge_counter()->decay();
+ }
+}
+
+void SimpleCompPolicy::disable_compilation(Method* method) {
+ MethodCounters* mcs = method->method_counters();
+ if (mcs != NULL) {
+ mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
+ mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing);
+ }
+}
+
+CompileTask* SimpleCompPolicy::select_task(CompileQueue* compile_queue) {
+ return select_task_helper(compile_queue);
+}
+
+bool SimpleCompPolicy::is_mature(Method* method) {
+ MethodData* mdo = method->method_data();
+ assert(mdo != NULL, "Should be");
+ uint current = mdo->mileage_of(method);
+ uint initial = mdo->creation_mileage();
+ if (current < initial)
+ return true; // some sort of overflow
+ uint target;
+ if (ProfileMaturityPercentage <= 0)
+ target = (uint) -ProfileMaturityPercentage; // absolute value
+ else
+ target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 );
+ return (current >= initial + target);
+}
+
+nmethod* SimpleCompPolicy::event(const methodHandle& method, const methodHandle& inlinee, int branch_bci,
+ int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
+ assert(comp_level == CompLevel_none, "This should be only called from the interpreter");
+ NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci));
+ if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
+ // If certain JVMTI events (e.g. frame pop event) are requested then the
+ // thread is forced to remain in interpreted code. This is
+ // implemented partly by a check in the run_compiled_code
+ // section of the interpreter whether we should skip running
+ // compiled code, and partly by skipping OSR compiles for
+ // interpreted-only threads.
+ if (bci != InvocationEntryBci) {
+ reset_counter_for_back_branch_event(method);
+ return NULL;
+ }
+ }
+ if (ReplayCompiles) {
+ // Don't trigger other compiles in testing mode
+ if (bci == InvocationEntryBci) {
+ reset_counter_for_invocation_event(method);
+ } else {
+ reset_counter_for_back_branch_event(method);
+ }
+ return NULL;
+ }
+
+ if (bci == InvocationEntryBci) {
+ // when code cache is full, compilation gets switched off, UseCompiler
+ // is set to false
+ if (!method->has_compiled_code() && UseCompiler) {
+ method_invocation_event(method, thread);
+ } else {
+ // Force counter overflow on method entry, even if no compilation
+ // happened. (The method_invocation_event call does this also.)
+ reset_counter_for_invocation_event(method);
+ }
+ // compilation at an invocation overflow no longer goes and retries test for
+ // compiled method. We always run the loser of the race as interpreted.
+ // so return NULL
+ return NULL;
+ } else {
+ // counter overflow in a loop => try to do on-stack-replacement
+ nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
+ NOT_PRODUCT(trace_osr_request(method, osr_nm, bci));
+ // when code cache is full, we should not compile any more...
+ if (osr_nm == NULL && UseCompiler) {
+ method_back_branch_event(method, bci, thread);
+ osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
+ }
+ if (osr_nm == NULL) {
+ reset_counter_for_back_branch_event(method);
+ return NULL;
+ }
+ return osr_nm;
+ }
+ return NULL;
+}
+
+#ifndef PRODUCT
+void SimpleCompPolicy::trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci) {
+ if (TraceInvocationCounterOverflow) {
+ MethodCounters* mcs = m->method_counters();
+ assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
+ InvocationCounter* ic = mcs->invocation_counter();
+ InvocationCounter* bc = mcs->backedge_counter();
+ ResourceMark rm;
+ if (bci == InvocationEntryBci) {
+ tty->print("comp-policy cntr ovfl @ %d in entry of ", bci);
+ } else {
+ tty->print("comp-policy cntr ovfl @ %d in loop of ", bci);
+ }
+ m->print_value();
+ tty->cr();
+ ic->print();
+ bc->print();
+ if (ProfileInterpreter) {
+ if (bci != InvocationEntryBci) {
+ MethodData* mdo = m->method_data();
+ if (mdo != NULL) {
+ ProfileData *pd = mdo->bci_to_data(branch_bci);
+ if (pd == NULL) {
+ tty->print_cr("back branch count = N/A (missing ProfileData)");
+ } else {
+ tty->print_cr("back branch count = %d", pd->as_JumpData()->taken());
+ }
+ }
+ }
+ }
+ }
+}
+
+void SimpleCompPolicy::trace_osr_request(const methodHandle& method, nmethod* osr, int bci) {
+ if (TraceOnStackReplacement) {
+ ResourceMark rm;
+ tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for ");
+ method->print_short_name(tty);
+ tty->print_cr(" at bci %d", bci);
+ }
+}
+#endif // !PRODUCT
+
+void SimpleCompPolicy::method_invocation_event(const methodHandle& m, JavaThread* thread) {
+ const int comp_level = CompLevel_highest_tier;
+ const int hot_count = m->invocation_count();
+ reset_counter_for_invocation_event(m);
+
+ if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
+ CompiledMethod* nm = m->code();
+ if (nm == NULL ) {
+ CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, CompileTask::Reason_InvocationCount, thread);
+ }
+ }
+}
+
+void SimpleCompPolicy::method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread) {
+ const int comp_level = CompLevel_highest_tier;
+ const int hot_count = m->backedge_count();
+
+ if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) {
+ CompileBroker::compile_method(m, bci, comp_level, m, hot_count, CompileTask::Reason_BackedgeCount, thread);
+ NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/compilationPolicy.hpp Wed Oct 09 12:43:32 2019 -0700
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_COMPILER_COMPILATIONPOLICY_HPP
+#define SHARE_COMPILER_COMPILATIONPOLICY_HPP
+
+#include "code/nmethod.hpp"
+#include "compiler/compileBroker.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/vmOperations.hpp"
+#include "utilities/growableArray.hpp"
+
+// The CompilationPolicy selects which method (if any) should be compiled.
+// It also decides which methods must always be compiled (i.e., are never
+// interpreted).
+class CompileTask;
+class CompileQueue;
+
+class CompilationPolicy : public CHeapObj<mtCompiler> {
+ static CompilationPolicy* _policy;
+
+ // m must be compiled before executing it
+ static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_all);
+
+public:
+ // If m must_be_compiled then request a compilation from the CompileBroker.
+ // This supports the -Xcomp option.
+ static void compile_if_required(const methodHandle& m, TRAPS);
+
+ // m is allowed to be compiled
+ static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_all);
+ // m is allowed to be osr compiled
+ static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_all);
+ static bool is_compilation_enabled();
+ static void set_policy(CompilationPolicy* policy) { _policy = policy; }
+ static CompilationPolicy* policy() { return _policy; }
+
+ static CompileTask* select_task_helper(CompileQueue* compile_queue);
+
+ // Return initial compile level that is used with Xcomp
+ virtual CompLevel initial_compile_level() = 0;
+ virtual int compiler_count(CompLevel comp_level) = 0;
+ // main notification entry, return a pointer to an nmethod if the OSR is required,
+ // returns NULL otherwise.
+ virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) = 0;
+ // safepoint() is called at the end of the safepoint
+ virtual void do_safepoint_work() = 0;
+ // reprofile request
+ virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0;
+ // delay_compilation(method) can be called by any component of the runtime to notify the policy
+ // that it's recommended to delay the compilation of this method.
+ virtual void delay_compilation(Method* method) = 0;
+ // disable_compilation() is called whenever the runtime decides to disable compilation of the
+ // specified method.
+ virtual void disable_compilation(Method* method) = 0;
+ // Select task is called by CompileBroker. The queue is guaranteed to have at least one
+ // element and is locked. The function should select one and return it.
+ virtual CompileTask* select_task(CompileQueue* compile_queue) = 0;
+ // Tell the runtime if we think a given method is adequately profiled.
+ virtual bool is_mature(Method* method) = 0;
+ // Do policy initialization
+ virtual void initialize() = 0;
+ virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; }
+};
+
+// A simple compilation policy.
+class SimpleCompPolicy : public CompilationPolicy {
+ int _compiler_count;
+ private:
+ static void trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci);
+ static void trace_osr_request(const methodHandle& method, nmethod* osr, int bci);
+ static void trace_osr_completion(nmethod* osr_nm);
+ void reset_counter_for_invocation_event(const methodHandle& method);
+ void reset_counter_for_back_branch_event(const methodHandle& method);
+ void method_invocation_event(const methodHandle& m, JavaThread* thread);
+ void method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread);
+ public:
+ SimpleCompPolicy() : _compiler_count(0) { }
+ virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; }
+ virtual int compiler_count(CompLevel comp_level);
+ virtual void do_safepoint_work();
+ virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
+ virtual void delay_compilation(Method* method);
+ virtual void disable_compilation(Method* method);
+ virtual bool is_mature(Method* method);
+ virtual void initialize();
+ virtual CompileTask* select_task(CompileQueue* compile_queue);
+ virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
+};
+
+
+#endif // SHARE_COMPILER_COMPILATIONPOLICY_HPP
--- a/src/hotspot/share/compiler/compileBroker.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/compiler/compileBroker.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -30,6 +30,7 @@
#include "code/codeCache.hpp"
#include "code/codeHeapState.hpp"
#include "code/dependencyContext.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
@@ -48,7 +49,6 @@
#include "prims/whitebox.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/tieredThresholdPolicy.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "compiler/compileBroker.hpp"
+#include "compiler/compilerOracle.hpp"
+#include "compiler/tieredThresholdPolicy.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/safepointVerifiers.hpp"
+#include "code/scopeDesc.hpp"
+#include "oops/method.inline.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmci.hpp"
+#endif
+
+#ifdef TIERED
+
+#include "c1/c1_Compiler.hpp"
+#include "opto/c2compiler.hpp"
+
+template<CompLevel level>
+bool TieredThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) {
+ double threshold_scaling;
+ if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) {
+ scale *= threshold_scaling;
+ }
+ switch(level) {
+ case CompLevel_aot:
+ return (i >= Tier3AOTInvocationThreshold * scale) ||
+ (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale);
+ case CompLevel_none:
+ case CompLevel_limited_profile:
+ return (i >= Tier3InvocationThreshold * scale) ||
+ (i >= Tier3MinInvocationThreshold * scale && i + b >= Tier3CompileThreshold * scale);
+ case CompLevel_full_profile:
+ return (i >= Tier4InvocationThreshold * scale) ||
+ (i >= Tier4MinInvocationThreshold * scale && i + b >= Tier4CompileThreshold * scale);
+ }
+ return true;
+}
+
+template<CompLevel level>
+bool TieredThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) {
+ double threshold_scaling;
+ if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) {
+ scale *= threshold_scaling;
+ }
+ switch(level) {
+ case CompLevel_aot:
+ return b >= Tier3AOTBackEdgeThreshold * scale;
+ case CompLevel_none:
+ case CompLevel_limited_profile:
+ return b >= Tier3BackEdgeThreshold * scale;
+ case CompLevel_full_profile:
+ return b >= Tier4BackEdgeThreshold * scale;
+ }
+ return true;
+}
+
+// Simple methods are as good being compiled with C1 as C2.
+// Determine if a given method is such a case.
+bool TieredThresholdPolicy::is_trivial(Method* method) {
+ if (method->is_accessor() ||
+ method->is_constant_getter()) {
+ return true;
+ }
+ return false;
+}
+
+bool TieredThresholdPolicy::should_compile_at_level_simple(Method* method) {
+ if (TieredThresholdPolicy::is_trivial(method)) {
+ return true;
+ }
+#if INCLUDE_JVMCI
+ if (UseJVMCICompiler) {
+ AbstractCompiler* comp = CompileBroker::compiler(CompLevel_full_optimization);
+ if (comp != NULL && comp->is_jvmci() && ((JVMCICompiler*) comp)->force_comp_at_level_simple(method)) {
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+CompLevel TieredThresholdPolicy::comp_level(Method* method) {
+ CompiledMethod *nm = method->code();
+ if (nm != NULL && nm->is_in_use()) {
+ return (CompLevel)nm->comp_level();
+ }
+ return CompLevel_none;
+}
+
+void TieredThresholdPolicy::print_counters(const char* prefix, const methodHandle& mh) {
+ int invocation_count = mh->invocation_count();
+ int backedge_count = mh->backedge_count();
+ MethodData* mdh = mh->method_data();
+ int mdo_invocations = 0, mdo_backedges = 0;
+ int mdo_invocations_start = 0, mdo_backedges_start = 0;
+ if (mdh != NULL) {
+ mdo_invocations = mdh->invocation_count();
+ mdo_backedges = mdh->backedge_count();
+ mdo_invocations_start = mdh->invocation_count_start();
+ mdo_backedges_start = mdh->backedge_count_start();
+ }
+ tty->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix,
+ invocation_count, backedge_count, prefix,
+ mdo_invocations, mdo_invocations_start,
+ mdo_backedges, mdo_backedges_start);
+ tty->print(" %smax levels=%d,%d", prefix,
+ mh->highest_comp_level(), mh->highest_osr_comp_level());
+}
+
+// Print an event.
+void TieredThresholdPolicy::print_event(EventType type, const methodHandle& mh, const methodHandle& imh,
+ int bci, CompLevel level) {
+ bool inlinee_event = mh() != imh();
+
+ ttyLocker tty_lock;
+ tty->print("%lf: [", os::elapsedTime());
+
+ switch(type) {
+ case CALL:
+ tty->print("call");
+ break;
+ case LOOP:
+ tty->print("loop");
+ break;
+ case COMPILE:
+ tty->print("compile");
+ break;
+ case REMOVE_FROM_QUEUE:
+ tty->print("remove-from-queue");
+ break;
+ case UPDATE_IN_QUEUE:
+ tty->print("update-in-queue");
+ break;
+ case REPROFILE:
+ tty->print("reprofile");
+ break;
+ case MAKE_NOT_ENTRANT:
+ tty->print("make-not-entrant");
+ break;
+ default:
+ tty->print("unknown");
+ }
+
+ tty->print(" level=%d ", level);
+
+ ResourceMark rm;
+ char *method_name = mh->name_and_sig_as_C_string();
+ tty->print("[%s", method_name);
+ if (inlinee_event) {
+ char *inlinee_name = imh->name_and_sig_as_C_string();
+ tty->print(" [%s]] ", inlinee_name);
+ }
+ else tty->print("] ");
+ tty->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile),
+ CompileBroker::queue_size(CompLevel_full_optimization));
+
+ print_specific(type, mh, imh, bci, level);
+
+ if (type != COMPILE) {
+ print_counters("", mh);
+ if (inlinee_event) {
+ print_counters("inlinee ", imh);
+ }
+ tty->print(" compilable=");
+ bool need_comma = false;
+ if (!mh->is_not_compilable(CompLevel_full_profile)) {
+ tty->print("c1");
+ need_comma = true;
+ }
+ if (!mh->is_not_osr_compilable(CompLevel_full_profile)) {
+ if (need_comma) tty->print(",");
+ tty->print("c1-osr");
+ need_comma = true;
+ }
+ if (!mh->is_not_compilable(CompLevel_full_optimization)) {
+ if (need_comma) tty->print(",");
+ tty->print("c2");
+ need_comma = true;
+ }
+ if (!mh->is_not_osr_compilable(CompLevel_full_optimization)) {
+ if (need_comma) tty->print(",");
+ tty->print("c2-osr");
+ }
+ tty->print(" status=");
+ if (mh->queued_for_compilation()) {
+ tty->print("in-queue");
+ } else tty->print("idle");
+ }
+ tty->print_cr("]");
+}
+
+void TieredThresholdPolicy::initialize() {
+ int count = CICompilerCount;
+ bool c1_only = TieredStopAtLevel < CompLevel_full_optimization;
+#ifdef _LP64
+ // Turn on ergonomic compiler count selection
+ if (FLAG_IS_DEFAULT(CICompilerCountPerCPU) && FLAG_IS_DEFAULT(CICompilerCount)) {
+ FLAG_SET_DEFAULT(CICompilerCountPerCPU, true);
+ }
+ if (CICompilerCountPerCPU) {
+ // Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n
+ int log_cpu = log2_int(os::active_processor_count());
+ int loglog_cpu = log2_int(MAX2(log_cpu, 1));
+ count = MAX2(log_cpu * loglog_cpu * 3 / 2, 2);
+ // Make sure there is enough space in the code cache to hold all the compiler buffers
+ size_t c1_size = Compiler::code_buffer_size();
+ size_t c2_size = C2Compiler::initial_code_buffer_size();
+ size_t buffer_size = c1_only ? c1_size : (c1_size/3 + 2*c2_size/3);
+ int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size;
+ if (count > max_count) {
+ // Lower the compiler count such that all buffers fit into the code cache
+ count = MAX2(max_count, c1_only ? 1 : 2);
+ }
+ FLAG_SET_ERGO(CICompilerCount, count);
+ }
+#else
+ // On 32-bit systems, the number of compiler threads is limited to 3.
+ // On these systems, the virtual address space available to the JVM
+ // is usually limited to 2-4 GB (the exact value depends on the platform).
+ // As the compilers (especially C2) can consume a large amount of
+ // memory, scaling the number of compiler threads with the number of
+ // available cores can result in the exhaustion of the address space
+ /// available to the VM and thus cause the VM to crash.
+ if (FLAG_IS_DEFAULT(CICompilerCount)) {
+ count = 3;
+ FLAG_SET_ERGO(CICompilerCount, count);
+ }
+#endif
+
+ if (c1_only) {
+ // No C2 compiler thread required
+ set_c1_count(count);
+ } else {
+ set_c1_count(MAX2(count / 3, 1));
+ set_c2_count(MAX2(count - c1_count(), 1));
+ }
+ assert(count == c1_count() + c2_count(), "inconsistent compiler thread count");
+
+ // Some inlining tuning
+#ifdef X86
+ if (FLAG_IS_DEFAULT(InlineSmallCode)) {
+ FLAG_SET_DEFAULT(InlineSmallCode, 2000);
+ }
+#endif
+
+#if defined SPARC || defined AARCH64
+ if (FLAG_IS_DEFAULT(InlineSmallCode)) {
+ FLAG_SET_DEFAULT(InlineSmallCode, 2500);
+ }
+#endif
+
+ set_increase_threshold_at_ratio();
+ set_start_time(os::javaTimeMillis());
+}
+
+void TieredThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) {
+ if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) {
+ counter->set_carry_flag();
+ }
+}
+
+// Set carry flags on the counters if necessary
+void TieredThresholdPolicy::handle_counter_overflow(Method* method) {
+ MethodCounters *mcs = method->method_counters();
+ if (mcs != NULL) {
+ set_carry_if_necessary(mcs->invocation_counter());
+ set_carry_if_necessary(mcs->backedge_counter());
+ }
+ MethodData* mdo = method->method_data();
+ if (mdo != NULL) {
+ set_carry_if_necessary(mdo->invocation_counter());
+ set_carry_if_necessary(mdo->backedge_counter());
+ }
+}
+
+// Called with the queue locked and with at least one element
+CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) {
+ CompileTask *max_blocking_task = NULL;
+ CompileTask *max_task = NULL;
+ Method* max_method = NULL;
+ jlong t = os::javaTimeMillis();
+ // Iterate through the queue and find a method with a maximum rate.
+ for (CompileTask* task = compile_queue->first(); task != NULL;) {
+ CompileTask* next_task = task->next();
+ Method* method = task->method();
+ // If a method was unloaded or has been stale for some time, remove it from the queue.
+ // Blocking tasks and tasks submitted from whitebox API don't become stale
+ if (task->is_unloaded() || (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, method) && !is_old(method))) {
+ if (!task->is_unloaded()) {
+ if (PrintTieredEvents) {
+ print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel) task->comp_level());
+ }
+ method->clear_queued_for_compilation();
+ }
+ compile_queue->remove_and_mark_stale(task);
+ task = next_task;
+ continue;
+ }
+ update_rate(t, method);
+ if (max_task == NULL || compare_methods(method, max_method)) {
+ // Select a method with the highest rate
+ max_task = task;
+ max_method = method;
+ }
+
+ if (task->is_blocking()) {
+ if (max_blocking_task == NULL || compare_methods(method, max_blocking_task->method())) {
+ max_blocking_task = task;
+ }
+ }
+
+ task = next_task;
+ }
+
+ if (max_blocking_task != NULL) {
+ // In blocking compilation mode, the CompileBroker will make
+ // compilations submitted by a JVMCI compiler thread non-blocking. These
+ // compilations should be scheduled after all blocking compilations
+ // to service non-compiler related compilations sooner and reduce the
+ // chance of such compilations timing out.
+ max_task = max_blocking_task;
+ max_method = max_task->method();
+ }
+
+ if (max_task != NULL && max_task->comp_level() == CompLevel_full_profile &&
+ TieredStopAtLevel > CompLevel_full_profile &&
+ max_method != NULL && is_method_profiled(max_method)) {
+ max_task->set_comp_level(CompLevel_limited_profile);
+
+ if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) {
+ if (PrintTieredEvents) {
+ print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
+ }
+ compile_queue->remove_and_mark_stale(max_task);
+ max_method->clear_queued_for_compilation();
+ return NULL;
+ }
+
+ if (PrintTieredEvents) {
+ print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
+ }
+ }
+
+ return max_task;
+}
+
+void TieredThresholdPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
+ for (ScopeDesc* sd = trap_scope;; sd = sd->sender()) {
+ if (PrintTieredEvents) {
+ methodHandle mh(sd->method());
+ print_event(REPROFILE, mh, mh, InvocationEntryBci, CompLevel_none);
+ }
+ MethodData* mdo = sd->method()->method_data();
+ if (mdo != NULL) {
+ mdo->reset_start_counters();
+ }
+ if (sd->is_top()) break;
+ }
+}
+
+nmethod* TieredThresholdPolicy::event(const methodHandle& method, const methodHandle& inlinee,
+ int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
+ if (comp_level == CompLevel_none &&
+ JvmtiExport::can_post_interpreter_events() &&
+ thread->is_interp_only_mode()) {
+ return NULL;
+ }
+ if (ReplayCompiles) {
+ // Don't trigger other compiles in testing mode
+ return NULL;
+ }
+
+ handle_counter_overflow(method());
+ if (method() != inlinee()) {
+ handle_counter_overflow(inlinee());
+ }
+
+ if (PrintTieredEvents) {
+ print_event(bci == InvocationEntryBci ? CALL : LOOP, method, inlinee, bci, comp_level);
+ }
+
+ if (bci == InvocationEntryBci) {
+ method_invocation_event(method, inlinee, comp_level, nm, thread);
+ } else {
+ // method == inlinee if the event originated in the main method
+ method_back_branch_event(method, inlinee, bci, comp_level, nm, thread);
+ // Check if event led to a higher level OSR compilation
+ CompLevel expected_comp_level = comp_level;
+ if (inlinee->is_not_osr_compilable(expected_comp_level)) {
+ // It's not possble to reach the expected level so fall back to simple.
+ expected_comp_level = CompLevel_simple;
+ }
+ nmethod* osr_nm = inlinee->lookup_osr_nmethod_for(bci, expected_comp_level, false);
+ assert(osr_nm == NULL || osr_nm->comp_level() >= expected_comp_level, "lookup_osr_nmethod_for is broken");
+ if (osr_nm != NULL) {
+ // Perform OSR with new nmethod
+ return osr_nm;
+ }
+ }
+ return NULL;
+}
+
+// Check if the method can be compiled, change level if necessary
+void TieredThresholdPolicy::compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) {
+ assert(level <= TieredStopAtLevel, "Invalid compilation level");
+ if (level == CompLevel_none) {
+ return;
+ }
+ if (level == CompLevel_aot) {
+ if (mh->has_aot_code()) {
+ if (PrintTieredEvents) {
+ print_event(COMPILE, mh, mh, bci, level);
+ }
+ MutexLocker ml(Compile_lock);
+ NoSafepointVerifier nsv;
+ if (mh->has_aot_code() && mh->code() != mh->aot_code()) {
+ mh->aot_code()->make_entrant();
+ if (mh->has_compiled_code()) {
+ mh->code()->make_not_entrant();
+ }
+ MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+ Method::set_code(mh, mh->aot_code());
+ }
+ }
+ return;
+ }
+
+ // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling
+ // in the interpreter and then compile with C2 (the transition function will request that,
+ // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with
+ // pure C1.
+ if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) {
+ if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) {
+ compile(mh, bci, CompLevel_simple, thread);
+ }
+ return;
+ }
+ if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) {
+ if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) {
+ nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false);
+ if (osr_nm != NULL && osr_nm->comp_level() > CompLevel_simple) {
+ // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted.
+ osr_nm->make_not_entrant();
+ }
+ compile(mh, bci, CompLevel_simple, thread);
+ }
+ return;
+ }
+ if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) {
+ return;
+ }
+ if (!CompileBroker::compilation_is_in_queue(mh)) {
+ if (PrintTieredEvents) {
+ print_event(COMPILE, mh, mh, bci, level);
+ }
+ submit_compile(mh, bci, level, thread);
+ }
+}
+
+// Update the rate and submit compile
+void TieredThresholdPolicy::submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) {
+ int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count();
+ update_rate(os::javaTimeMillis(), mh());
+ CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, thread);
+}
+
+// Print an event.
+void TieredThresholdPolicy::print_specific(EventType type, const methodHandle& mh, const methodHandle& imh,
+ int bci, CompLevel level) {
+ tty->print(" rate=");
+ if (mh->prev_time() == 0) tty->print("n/a");
+ else tty->print("%f", mh->rate());
+
+ tty->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback),
+ threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback));
+
+}
+
+// update_rate() is called from select_task() while holding a compile queue lock.
+void TieredThresholdPolicy::update_rate(jlong t, Method* m) {
+ // Skip update if counters are absent.
+ // Can't allocate them since we are holding compile queue lock.
+ if (m->method_counters() == NULL) return;
+
+ if (is_old(m)) {
+ // We don't remove old methods from the queue,
+ // so we can just zero the rate.
+ m->set_rate(0);
+ return;
+ }
+
+ // We don't update the rate if we've just came out of a safepoint.
+ // delta_s is the time since last safepoint in milliseconds.
+ jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms();
+ jlong delta_t = t - (m->prev_time() != 0 ? m->prev_time() : start_time()); // milliseconds since the last measurement
+ // How many events were there since the last time?
+ int event_count = m->invocation_count() + m->backedge_count();
+ int delta_e = event_count - m->prev_event_count();
+
+ // We should be running for at least 1ms.
+ if (delta_s >= TieredRateUpdateMinTime) {
+ // And we must've taken the previous point at least 1ms before.
+ if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) {
+ m->set_prev_time(t);
+ m->set_prev_event_count(event_count);
+ m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond
+ } else {
+ if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) {
+ // If nothing happened for 25ms, zero the rate. Don't modify prev values.
+ m->set_rate(0);
+ }
+ }
+ }
+}
+
+// Check if this method has been stale for a given number of milliseconds.
+// See select_task().
+bool TieredThresholdPolicy::is_stale(jlong t, jlong timeout, Method* m) {
+ jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms();
+ jlong delta_t = t - m->prev_time();
+ if (delta_t > timeout && delta_s > timeout) {
+ int event_count = m->invocation_count() + m->backedge_count();
+ int delta_e = event_count - m->prev_event_count();
+ // Return true if there were no events.
+ return delta_e == 0;
+ }
+ return false;
+}
+
+// We don't remove old methods from the compile queue even if they have
+// very low activity. See select_task().
+bool TieredThresholdPolicy::is_old(Method* method) {
+ return method->invocation_count() > 50000 || method->backedge_count() > 500000;
+}
+
+double TieredThresholdPolicy::weight(Method* method) {
+ return (double)(method->rate() + 1) *
+ (method->invocation_count() + 1) * (method->backedge_count() + 1);
+}
+
+// Apply heuristics and return true if x should be compiled before y
+bool TieredThresholdPolicy::compare_methods(Method* x, Method* y) {
+ if (x->highest_comp_level() > y->highest_comp_level()) {
+ // recompilation after deopt
+ return true;
+ } else
+ if (x->highest_comp_level() == y->highest_comp_level()) {
+ if (weight(x) > weight(y)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Is method profiled enough?
+bool TieredThresholdPolicy::is_method_profiled(Method* method) {
+ MethodData* mdo = method->method_data();
+ if (mdo != NULL) {
+ int i = mdo->invocation_count_delta();
+ int b = mdo->backedge_count_delta();
+ return call_predicate_helper<CompLevel_full_profile>(i, b, 1, method);
+ }
+ return false;
+}
+
+double TieredThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) {
+ double queue_size = CompileBroker::queue_size(level);
+ int comp_count = compiler_count(level);
+ double k = queue_size / (feedback_k * comp_count) + 1;
+
+ // Increase C1 compile threshold when the code cache is filled more
+ // than specified by IncreaseFirstTierCompileThresholdAt percentage.
+ // The main intention is to keep enough free space for C2 compiled code
+ // to achieve peak performance if the code cache is under stress.
+ if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) {
+ double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level));
+ if (current_reverse_free_ratio > _increase_threshold_at_ratio) {
+ k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio);
+ }
+ }
+ return k;
+}
+
+// Call and loop predicates determine whether a transition to a higher
+// compilation level should be performed (pointers to predicate functions
+// are passed to common()).
+// Tier?LoadFeedback is basically a coefficient that determines of
+// how many methods per compiler thread can be in the queue before
+// the threshold values double.
+bool TieredThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) {
+ switch(cur_level) {
+ case CompLevel_aot: {
+ double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ return loop_predicate_helper<CompLevel_aot>(i, b, k, method);
+ }
+ case CompLevel_none:
+ case CompLevel_limited_profile: {
+ double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ return loop_predicate_helper<CompLevel_none>(i, b, k, method);
+ }
+ case CompLevel_full_profile: {
+ double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback);
+ return loop_predicate_helper<CompLevel_full_profile>(i, b, k, method);
+ }
+ default:
+ return true;
+ }
+}
+
+bool TieredThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) {
+ switch(cur_level) {
+ case CompLevel_aot: {
+ double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ return call_predicate_helper<CompLevel_aot>(i, b, k, method);
+ }
+ case CompLevel_none:
+ case CompLevel_limited_profile: {
+ double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+ return call_predicate_helper<CompLevel_none>(i, b, k, method);
+ }
+ case CompLevel_full_profile: {
+ double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback);
+ return call_predicate_helper<CompLevel_full_profile>(i, b, k, method);
+ }
+ default:
+ return true;
+ }
+}
+
+// Determine is a method is mature.
+bool TieredThresholdPolicy::is_mature(Method* method) {
+ if (should_compile_at_level_simple(method)) return true;
+ MethodData* mdo = method->method_data();
+ if (mdo != NULL) {
+ int i = mdo->invocation_count();
+ int b = mdo->backedge_count();
+ double k = ProfileMaturityPercentage / 100.0;
+ return call_predicate_helper<CompLevel_full_profile>(i, b, k, method) ||
+ loop_predicate_helper<CompLevel_full_profile>(i, b, k, method);
+ }
+ return false;
+}
+
+// If a method is old enough and is still in the interpreter we would want to
+// start profiling without waiting for the compiled method to arrive.
+// We also take the load on compilers into the account.
+bool TieredThresholdPolicy::should_create_mdo(Method* method, CompLevel cur_level) {
+ if (cur_level == CompLevel_none &&
+ CompileBroker::queue_size(CompLevel_full_optimization) <=
+ Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
+ int i = method->invocation_count();
+ int b = method->backedge_count();
+ double k = Tier0ProfilingStartPercentage / 100.0;
+ return call_predicate_helper<CompLevel_none>(i, b, k, method) || loop_predicate_helper<CompLevel_none>(i, b, k, method);
+ }
+ return false;
+}
+
+// Inlining control: if we're compiling a profiled method with C1 and the callee
+// is known to have OSRed in a C2 version, don't inline it.
+bool TieredThresholdPolicy::should_not_inline(ciEnv* env, ciMethod* callee) {
+ CompLevel comp_level = (CompLevel)env->comp_level();
+ if (comp_level == CompLevel_full_profile ||
+ comp_level == CompLevel_limited_profile) {
+ return callee->highest_osr_comp_level() == CompLevel_full_optimization;
+ }
+ return false;
+}
+
+// Create MDO if necessary.
+void TieredThresholdPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) {
+ if (mh->is_native() ||
+ mh->is_abstract() ||
+ mh->is_accessor() ||
+ mh->is_constant_getter()) {
+ return;
+ }
+ if (mh->method_data() == NULL) {
+ Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR);
+ }
+}
+
+
+/*
+ * Method states:
+ * 0 - interpreter (CompLevel_none)
+ * 1 - pure C1 (CompLevel_simple)
+ * 2 - C1 with invocation and backedge counting (CompLevel_limited_profile)
+ * 3 - C1 with full profiling (CompLevel_full_profile)
+ * 4 - C2 (CompLevel_full_optimization)
+ *
+ * Common state transition patterns:
+ * a. 0 -> 3 -> 4.
+ * The most common path. But note that even in this straightforward case
+ * profiling can start at level 0 and finish at level 3.
+ *
+ * b. 0 -> 2 -> 3 -> 4.
+ * This case occurs when the load on C2 is deemed too high. So, instead of transitioning
+ * into state 3 directly and over-profiling while a method is in the C2 queue we transition to
+ * level 2 and wait until the load on C2 decreases. This path is disabled for OSRs.
+ *
+ * c. 0 -> (3->2) -> 4.
+ * In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough
+ * to enable the profiling to fully occur at level 0. In this case we change the compilation level
+ * of the method to 2 while the request is still in-queue, because it'll allow it to run much faster
+ * without full profiling while c2 is compiling.
+ *
+ * d. 0 -> 3 -> 1 or 0 -> 2 -> 1.
+ * After a method was once compiled with C1 it can be identified as trivial and be compiled to
+ * level 1. These transition can also occur if a method can't be compiled with C2 but can with C1.
+ *
+ * e. 0 -> 4.
+ * This can happen if a method fails C1 compilation (it will still be profiled in the interpreter)
+ * or because of a deopt that didn't require reprofiling (compilation won't happen in this case because
+ * the compiled version already exists).
+ *
+ * Note that since state 0 can be reached from any other state via deoptimization different loops
+ * are possible.
+ *
+ */
+
+// Common transition function. Given a predicate determines if a method should transition to another level.
+CompLevel TieredThresholdPolicy::common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback) {
+ CompLevel next_level = cur_level;
+ int i = method->invocation_count();
+ int b = method->backedge_count();
+
+ if (should_compile_at_level_simple(method)) {
+ next_level = CompLevel_simple;
+ } else {
+ switch(cur_level) {
+ default: break;
+ case CompLevel_aot: {
+ // If we were at full profile level, would we switch to full opt?
+ if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
+ next_level = CompLevel_full_optimization;
+ } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+ Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+ (this->*p)(i, b, cur_level, method))) {
+ next_level = CompLevel_full_profile;
+ }
+ }
+ break;
+ case CompLevel_none:
+ // If we were at full profile level, would we switch to full opt?
+ if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
+ next_level = CompLevel_full_optimization;
+ } else if ((this->*p)(i, b, cur_level, method)) {
+#if INCLUDE_JVMCI
+ if (EnableJVMCI && UseJVMCICompiler) {
+ // Since JVMCI takes a while to warm up, its queue inevitably backs up during
+ // early VM execution. As of 2014-06-13, JVMCI's inliner assumes that the root
+ // compilation method and all potential inlinees have mature profiles (which
+ // includes type profiling). If it sees immature profiles, JVMCI's inliner
+ // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to
+ // exploring/inlining too many graphs). Since a rewrite of the inliner is
+ // in progress, we simply disable the dialing back heuristic for now and will
+ // revisit this decision once the new inliner is completed.
+ next_level = CompLevel_full_profile;
+ } else
+#endif
+ {
+ // C1-generated fully profiled code is about 30% slower than the limited profile
+ // code that has only invocation and backedge counters. The observation is that
+ // if C2 queue is large enough we can spend too much time in the fully profiled code
+ // while waiting for C2 to pick the method from the queue. To alleviate this problem
+ // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long
+ // we choose to compile a limited profiled version and then recompile with full profiling
+ // when the load on C2 goes down.
+ if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) >
+ Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
+ next_level = CompLevel_limited_profile;
+ } else {
+ next_level = CompLevel_full_profile;
+ }
+ }
+ }
+ break;
+ case CompLevel_limited_profile:
+ if (is_method_profiled(method)) {
+ // Special case: we got here because this method was fully profiled in the interpreter.
+ next_level = CompLevel_full_optimization;
+ } else {
+ MethodData* mdo = method->method_data();
+ if (mdo != NULL) {
+ if (mdo->would_profile()) {
+ if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+ Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+ (this->*p)(i, b, cur_level, method))) {
+ next_level = CompLevel_full_profile;
+ }
+ } else {
+ next_level = CompLevel_full_optimization;
+ }
+ } else {
+ // If there is no MDO we need to profile
+ if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+ Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+ (this->*p)(i, b, cur_level, method))) {
+ next_level = CompLevel_full_profile;
+ }
+ }
+ }
+ break;
+ case CompLevel_full_profile:
+ {
+ MethodData* mdo = method->method_data();
+ if (mdo != NULL) {
+ if (mdo->would_profile()) {
+ int mdo_i = mdo->invocation_count_delta();
+ int mdo_b = mdo->backedge_count_delta();
+ if ((this->*p)(mdo_i, mdo_b, cur_level, method)) {
+ next_level = CompLevel_full_optimization;
+ }
+ } else {
+ next_level = CompLevel_full_optimization;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return MIN2(next_level, (CompLevel)TieredStopAtLevel);
+}
+
+// Determine if a method should be compiled with a normal entry point at a different level.
+CompLevel TieredThresholdPolicy::call_event(Method* method, CompLevel cur_level, JavaThread * thread) {
+ CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(),
+ common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true));
+ CompLevel next_level = common(&TieredThresholdPolicy::call_predicate, method, cur_level);
+
+ // If OSR method level is greater than the regular method level, the levels should be
+ // equalized by raising the regular method level in order to avoid OSRs during each
+ // invocation of the method.
+ if (osr_level == CompLevel_full_optimization && cur_level == CompLevel_full_profile) {
+ MethodData* mdo = method->method_data();
+ guarantee(mdo != NULL, "MDO should not be NULL");
+ if (mdo->invocation_count() >= 1) {
+ next_level = CompLevel_full_optimization;
+ }
+ } else {
+ next_level = MAX2(osr_level, next_level);
+ }
+ return next_level;
+}
+
+// Determine if we should do an OSR compilation of a given method.
+CompLevel TieredThresholdPolicy::loop_event(Method* method, CompLevel cur_level, JavaThread* thread) {
+ CompLevel next_level = common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true);
+ if (cur_level == CompLevel_none) {
+ // If there is a live OSR method that means that we deopted to the interpreter
+ // for the transition.
+ CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level);
+ if (osr_level > CompLevel_none) {
+ return osr_level;
+ }
+ }
+ return next_level;
+}
+
+bool TieredThresholdPolicy::maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread) {
+ if (UseAOT) {
+ if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) {
+ // If the current level is full profile or interpreter and we're switching to any other level,
+ // activate the AOT code back first so that we won't waste time overprofiling.
+ compile(mh, InvocationEntryBci, CompLevel_aot, thread);
+ // Fall through for JIT compilation.
+ }
+ if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) {
+ // If the next level is limited profile, use the aot code (if there is any),
+ // since it's essentially the same thing.
+ compile(mh, InvocationEntryBci, CompLevel_aot, thread);
+ // Not need to JIT, we're done.
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// Handle the invocation event.
+void TieredThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
+ CompLevel level, CompiledMethod* nm, JavaThread* thread) {
+ if (should_create_mdo(mh(), level)) {
+ create_mdo(mh, thread);
+ }
+ CompLevel next_level = call_event(mh(), level, thread);
+ if (next_level != level) {
+ if (maybe_switch_to_aot(mh, level, next_level, thread)) {
+ // No JITting necessary
+ return;
+ }
+ if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
+ compile(mh, InvocationEntryBci, next_level, thread);
+ }
+ }
+}
+
+// Handle the back branch event. Notice that we can compile the method
+// with a regular entry from here.
+void TieredThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh,
+ int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) {
+ if (should_create_mdo(mh(), level)) {
+ create_mdo(mh, thread);
+ }
+ // Check if MDO should be created for the inlined method
+ if (should_create_mdo(imh(), level)) {
+ create_mdo(imh, thread);
+ }
+
+ if (is_compilation_enabled()) {
+ CompLevel next_osr_level = loop_event(imh(), level, thread);
+ CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level();
+ // At the very least compile the OSR version
+ if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) {
+ compile(imh, bci, next_osr_level, thread);
+ }
+
+ // Use loop event as an opportunity to also check if there's been
+ // enough calls.
+ CompLevel cur_level, next_level;
+ if (mh() != imh()) { // If there is an enclosing method
+ if (level == CompLevel_aot) {
+ // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling.
+ if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) {
+ compile(mh, InvocationEntryBci, MIN2((CompLevel)TieredStopAtLevel, CompLevel_full_profile), thread);
+ }
+ } else {
+ // Current loop event level is not AOT
+ guarantee(nm != NULL, "Should have nmethod here");
+ cur_level = comp_level(mh());
+ next_level = call_event(mh(), cur_level, thread);
+
+ if (max_osr_level == CompLevel_full_optimization) {
+ // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts
+ bool make_not_entrant = false;
+ if (nm->is_osr_method()) {
+ // This is an osr method, just make it not entrant and recompile later if needed
+ make_not_entrant = true;
+ } else {
+ if (next_level != CompLevel_full_optimization) {
+ // next_level is not full opt, so we need to recompile the
+ // enclosing method without the inlinee
+ cur_level = CompLevel_none;
+ make_not_entrant = true;
+ }
+ }
+ if (make_not_entrant) {
+ if (PrintTieredEvents) {
+ int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
+ print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level);
+ }
+ nm->make_not_entrant();
+ }
+ }
+ // Fix up next_level if necessary to avoid deopts
+ if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) {
+ next_level = CompLevel_full_profile;
+ }
+ if (cur_level != next_level) {
+ if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
+ compile(mh, InvocationEntryBci, next_level, thread);
+ }
+ }
+ }
+ } else {
+ cur_level = comp_level(mh());
+ next_level = call_event(mh(), cur_level, thread);
+ if (next_level != cur_level) {
+ if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
+ compile(mh, InvocationEntryBci, next_level, thread);
+ }
+ }
+ }
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/tieredThresholdPolicy.hpp Wed Oct 09 12:43:32 2019 -0700
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP
+#define SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP
+
+#include "code/nmethod.hpp"
+#include "compiler/compilationPolicy.hpp"
+#include "oops/methodData.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#ifdef TIERED
+
+class CompileTask;
+class CompileQueue;
+/*
+ * The system supports 5 execution levels:
+ * * level 0 - interpreter
+ * * level 1 - C1 with full optimization (no profiling)
+ * * level 2 - C1 with invocation and backedge counters
+ * * level 3 - C1 with full profiling (level 2 + MDO)
+ * * level 4 - C2
+ *
+ * Levels 0, 2 and 3 periodically notify the runtime about the current value of the counters
+ * (invocation counters and backedge counters). The frequency of these notifications is
+ * different at each level. These notifications are used by the policy to decide what transition
+ * to make.
+ *
+ * Execution starts at level 0 (interpreter), then the policy can decide either to compile the
+ * method at level 3 or level 2. The decision is based on the following factors:
+ * 1. The length of the C2 queue determines the next level. The observation is that level 2
+ * is generally faster than level 3 by about 30%, therefore we would want to minimize the time
+ * a method spends at level 3. We should only spend the time at level 3 that is necessary to get
+ * adequate profiling. So, if the C2 queue is long enough it is more beneficial to go first to
+ * level 2, because if we transitioned to level 3 we would be stuck there until our C2 compile
+ * request makes its way through the long queue. When the load on C2 recedes we are going to
+ * recompile at level 3 and start gathering profiling information.
+ * 2. The length of C1 queue is used to dynamically adjust the thresholds, so as to introduce
+ * additional filtering if the compiler is overloaded. The rationale is that by the time a
+ * method gets compiled it can become unused, so it doesn't make sense to put too much onto the
+ * queue.
+ *
+ * After profiling is completed at level 3 the transition is made to level 4. Again, the length
+ * of the C2 queue is used as a feedback to adjust the thresholds.
+ *
+ * After the first C1 compile some basic information is determined about the code like the number
+ * of the blocks and the number of the loops. Based on that it can be decided that a method
+ * is trivial and compiling it with C1 will yield the same code. In this case the method is
+ * compiled at level 1 instead of 4.
+ *
+ * We also support profiling at level 0. If C1 is slow enough to produce the level 3 version of
+ * the code and the C2 queue is sufficiently small we can decide to start profiling in the
+ * interpreter (and continue profiling in the compiled code once the level 3 version arrives).
+ * If the profiling at level 0 is fully completed before level 3 version is produced, a level 2
+ * version is compiled instead in order to run faster waiting for a level 4 version.
+ *
+ * Compile queues are implemented as priority queues - for each method in the queue we compute
+ * the event rate (the number of invocation and backedge counter increments per unit of time).
+ * When getting an element off the queue we pick the one with the largest rate. Maintaining the
+ * rate also allows us to remove stale methods (the ones that got on the queue but stopped
+ * being used shortly after that).
+*/
+
+/* Command line options:
+ * - Tier?InvokeNotifyFreqLog and Tier?BackedgeNotifyFreqLog control the frequency of method
+ * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread
+ * makes a call into the runtime.
+ *
+ * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control
+ * compilation thresholds.
+ * Level 2 thresholds are not used and are provided for option-compatibility and potential future use.
+ * Other thresholds work as follows:
+ *
+ * Transition from interpreter (level 0) to C1 with full profiling (level 3) happens when
+ * the following predicate is true (X is the level):
+ *
+ * i > TierXInvocationThreshold * s || (i > TierXMinInvocationThreshold * s && i + b > TierXCompileThreshold * s),
+ *
+ * where $i$ is the number of method invocations, $b$ number of backedges and $s$ is the scaling
+ * coefficient that will be discussed further.
+ * The intuition is to equalize the time that is spend profiling each method.
+ * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be
+ * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come
+ * from Method* and for 3->4 transition they come from MDO (since profiled invocations are
+ * counted separately). Finally, if a method does not contain anything worth profiling, a transition
+ * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than
+ * what is specified by Tier4InvocationThreshold).
+ *
+ * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates.
+ *
+ * - Tier?LoadFeedback options are used to automatically scale the predicates described above depending
+ * on the compiler load. The scaling coefficients are computed as follows:
+ *
+ * s = queue_size_X / (TierXLoadFeedback * compiler_count_X) + 1,
+ *
+ * where queue_size_X is the current size of the compiler queue of level X, and compiler_count_X
+ * is the number of level X compiler threads.
+ *
+ * Basically these parameters describe how many methods should be in the compile queue
+ * per compiler thread before the scaling coefficient increases by one.
+ *
+ * This feedback provides the mechanism to automatically control the flow of compilation requests
+ * depending on the machine speed, mutator load and other external factors.
+ *
+ * - Tier3DelayOn and Tier3DelayOff parameters control another important feedback loop.
+ * Consider the following observation: a method compiled with full profiling (level 3)
+ * is about 30% slower than a method at level 2 (just invocation and backedge counters, no MDO).
+ * Normally, the following transitions will occur: 0->3->4. The problem arises when the C2 queue
+ * gets congested and the 3->4 transition is delayed. While the method is the C2 queue it continues
+ * executing at level 3 for much longer time than is required by the predicate and at suboptimal speed.
+ * The idea is to dynamically change the behavior of the system in such a way that if a substantial
+ * load on C2 is detected we would first do the 0->2 transition allowing a method to run faster.
+ * And then when the load decreases to allow 2->3 transitions.
+ *
+ * Tier3Delay* parameters control this switching mechanism.
+ * Tier3DelayOn is the number of methods in the C2 queue per compiler thread after which the policy
+ * no longer does 0->3 transitions but does 0->2 transitions instead.
+ * Tier3DelayOff switches the original behavior back when the number of methods in the C2 queue
+ * per compiler thread falls below the specified amount.
+ * The hysteresis is necessary to avoid jitter.
+ *
+ * - TieredCompileTaskTimeout is the amount of time an idle method can spend in the compile queue.
+ * Basically, since we use the event rate d(i + b)/dt as a value of priority when selecting a method to
+ * compile from the compile queue, we also can detect stale methods for which the rate has been
+ * 0 for some time in the same iteration. Stale methods can appear in the queue when an application
+ * abruptly changes its behavior.
+ *
+ * - TieredStopAtLevel, is used mostly for testing. It allows to bypass the policy logic and stick
+ * to a given level. For example it's useful to set TieredStopAtLevel = 1 in order to compile everything
+ * with pure c1.
+ *
+ * - Tier0ProfilingStartPercentage allows the interpreter to start profiling when the inequalities in the
+ * 0->3 predicate are already exceeded by the given percentage but the level 3 version of the
+ * method is still not ready. We can even go directly from level 0 to 4 if c1 doesn't produce a compiled
+ * version in time. This reduces the overall transition to level 4 and decreases the startup time.
+ * Note that this behavior is also guarded by the Tier3Delay mechanism: when the c2 queue is too long
+ * these is not reason to start profiling prematurely.
+ *
+ * - TieredRateUpdateMinTime and TieredRateUpdateMaxTime are parameters of the rate computation.
+ * Basically, the rate is not computed more frequently than TieredRateUpdateMinTime and is considered
+ * to be zero if no events occurred in TieredRateUpdateMaxTime.
+ */
+
+class TieredThresholdPolicy : public CompilationPolicy {
+ jlong _start_time;
+ int _c1_count, _c2_count;
+
+ // Check if the counter is big enough and set carry (effectively infinity).
+ inline void set_carry_if_necessary(InvocationCounter *counter);
+ // Set carry flags in the counters (in Method* and MDO).
+ inline void handle_counter_overflow(Method* method);
+ // Call and loop predicates determine whether a transition to a higher compilation
+ // level should be performed (pointers to predicate functions are passed to common_TF().
+ // Predicates also take compiler load into account.
+ typedef bool (TieredThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method);
+ bool call_predicate(int i, int b, CompLevel cur_level, Method* method);
+ bool loop_predicate(int i, int b, CompLevel cur_level, Method* method);
+ // Common transition function. Given a predicate determines if a method should transition to another level.
+ CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false);
+ // Transition functions.
+ // call_event determines if a method should be compiled at a different
+ // level with a regular invocation entry.
+ CompLevel call_event(Method* method, CompLevel cur_level, JavaThread* thread);
+ // loop_event checks if a method should be OSR compiled at a different
+ // level.
+ CompLevel loop_event(Method* method, CompLevel cur_level, JavaThread* thread);
+ void print_counters(const char* prefix, const methodHandle& mh);
+ // Has a method been long around?
+ // We don't remove old methods from the compile queue even if they have
+ // very low activity (see select_task()).
+ inline bool is_old(Method* method);
+ // Was a given method inactive for a given number of milliseconds.
+ // If it is, we would remove it from the queue (see select_task()).
+ inline bool is_stale(jlong t, jlong timeout, Method* m);
+ // Compute the weight of the method for the compilation scheduling
+ inline double weight(Method* method);
+ // Apply heuristics and return true if x should be compiled before y
+ inline bool compare_methods(Method* x, Method* y);
+ // Compute event rate for a given method. The rate is the number of event (invocations + backedges)
+ // per millisecond.
+ inline void update_rate(jlong t, Method* m);
+ // Compute threshold scaling coefficient
+ inline double threshold_scale(CompLevel level, int feedback_k);
+ // If a method is old enough and is still in the interpreter we would want to
+ // start profiling without waiting for the compiled method to arrive. This function
+ // determines whether we should do that.
+ inline bool should_create_mdo(Method* method, CompLevel cur_level);
+ // Create MDO if necessary.
+ void create_mdo(const methodHandle& mh, JavaThread* thread);
+ // Is method profiled enough?
+ bool is_method_profiled(Method* method);
+
+ double _increase_threshold_at_ratio;
+
+ bool maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread);
+
+ int c1_count() const { return _c1_count; }
+ int c2_count() const { return _c2_count; }
+ void set_c1_count(int x) { _c1_count = x; }
+ void set_c2_count(int x) { _c2_count = x; }
+
+ enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT };
+ void print_event(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level);
+ // Print policy-specific information if necessary
+ void print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level);
+ // Check if the method can be compiled, change level if necessary
+ void compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread);
+ // Submit a given method for compilation
+ void submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread);
+ // Simple methods are as good being compiled with C1 as C2.
+ // This function tells if it's such a function.
+ inline static bool is_trivial(Method* method);
+ // Force method to be compiled at CompLevel_simple?
+ inline static bool should_compile_at_level_simple(Method* method);
+
+ // Predicate helpers are used by .*_predicate() methods as well as others.
+ // They check the given counter values, multiplied by the scale against the thresholds.
+ template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale, Method* method);
+ template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale, Method* method);
+
+ // Get a compilation level for a given method.
+ static CompLevel comp_level(Method* method);
+ void method_invocation_event(const methodHandle& method, const methodHandle& inlinee,
+ CompLevel level, CompiledMethod* nm, JavaThread* thread);
+ void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee,
+ int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread);
+
+ void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); }
+ void set_start_time(jlong t) { _start_time = t; }
+ jlong start_time() const { return _start_time; }
+
+public:
+ TieredThresholdPolicy() : _start_time(0), _c1_count(0), _c2_count(0) { }
+ virtual int compiler_count(CompLevel comp_level) {
+ if (is_c1_compile(comp_level)) return c1_count();
+ if (is_c2_compile(comp_level)) return c2_count();
+ return 0;
+ }
+ virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, CompLevel_initial_compile); }
+ virtual void do_safepoint_work() { }
+ virtual void delay_compilation(Method* method) { }
+ virtual void disable_compilation(Method* method) { }
+ virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
+ virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee,
+ int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
+ // Select task is called by CompileBroker. We should return a task or NULL.
+ virtual CompileTask* select_task(CompileQueue* compile_queue);
+ // Tell the runtime if we think a given method is adequately profiled.
+ virtual bool is_mature(Method* method);
+ // Initialize: set compiler thread count
+ virtual void initialize();
+ virtual bool should_not_inline(ciEnv* env, ciMethod* callee);
+};
+
+#endif // TIERED
+
+#endif // SHARE_COMPILER_TIEREDTHRESHOLDPOLICY_HPP
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -28,6 +28,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
@@ -52,7 +53,6 @@
#include "prims/nativeLookup.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
--- a/src/hotspot/share/interpreter/linkResolver.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/interpreter/linkResolver.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -30,6 +30,7 @@
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/bootstrapInfo.hpp"
@@ -48,7 +49,6 @@
#include "oops/oop.inline.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/jvmci/compilerRuntime.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/jvmci/compilerRuntime.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -25,11 +25,11 @@
#include "aot/aotLoader.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "interpreter/linkResolver.hpp"
#include "jvmci/compilerRuntime.hpp"
#include "oops/cpCache.inline.hpp"
#include "oops/oop.inline.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/oops/method.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/oops/method.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -28,6 +28,7 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "code/debugInfoRec.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodeTracer.hpp"
@@ -54,7 +55,6 @@
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
--- a/src/hotspot/share/oops/methodData.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/oops/methodData.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compilerOracle.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/bytecodeStream.hpp"
@@ -34,7 +35,6 @@
#include "oops/methodData.inline.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/orderAccess.hpp"
--- a/src/hotspot/share/prims/jni.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/prims/jni.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -65,7 +65,6 @@
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
@@ -88,6 +87,9 @@
#include "utilities/histogram.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmciCompiler.hpp"
+#endif
static jint CurrentVersion = JNI_VERSION_10;
--- a/src/hotspot/share/prims/methodHandles.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/prims/methodHandles.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -41,7 +41,6 @@
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/methodHandles.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/prims/whitebox.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/prims/whitebox.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -32,6 +32,7 @@
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/methodMatcher.hpp"
#include "compiler/directivesParser.hpp"
#include "gc/shared/gcConfig.hpp"
@@ -58,7 +59,6 @@
#include "prims/wbtestmethods/parserTests.hpp"
#include "prims/whitebox.inline.hpp"
#include "runtime/arguments.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/flags/jvmFlag.hpp"
--- a/src/hotspot/share/runtime/compilationPolicy.cpp Thu Oct 10 21:54:54 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,506 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "classfile/classLoaderDataGraph.inline.hpp"
-#include "code/compiledIC.hpp"
-#include "code/nmethod.hpp"
-#include "code/scopeDesc.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/nativeLookup.hpp"
-#include "runtime/compilationPolicy.hpp"
-#include "runtime/frame.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.hpp"
-#include "runtime/tieredThresholdPolicy.hpp"
-#include "runtime/vframe.hpp"
-#include "runtime/vmOperations.hpp"
-#include "utilities/events.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-#ifdef COMPILER1
-#include "c1/c1_Compiler.hpp"
-#endif
-#ifdef COMPILER2
-#include "opto/c2compiler.hpp"
-#endif
-
-CompilationPolicy* CompilationPolicy::_policy;
-
-// Determine compilation policy based on command line argument
-void compilationPolicy_init() {
- #ifdef TIERED
- if (TieredCompilation) {
- CompilationPolicy::set_policy(new TieredThresholdPolicy());
- } else {
- CompilationPolicy::set_policy(new SimpleCompPolicy());
- }
- #else
- CompilationPolicy::set_policy(new SimpleCompPolicy());
- #endif
-
- CompilationPolicy::policy()->initialize();
-}
-
-// Returns true if m must be compiled before executing it
-// This is intended to force compiles for methods (usually for
-// debugging) that would otherwise be interpreted for some reason.
-bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level) {
- // Don't allow Xcomp to cause compiles in replay mode
- if (ReplayCompiles) return false;
-
- if (m->has_compiled_code()) return false; // already compiled
- if (!can_be_compiled(m, comp_level)) return false;
-
- return !UseInterpreter || // must compile all methods
- (UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
-}
-
-void CompilationPolicy::compile_if_required(const methodHandle& selected_method, TRAPS) {
- if (must_be_compiled(selected_method)) {
- // This path is unusual, mostly used by the '-Xcomp' stress test mode.
-
- // Note: with several active threads, the must_be_compiled may be true
- // while can_be_compiled is false; remove assert
- // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
- if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) {
- // don't force compilation, resolve was on behalf of compiler
- return;
- }
- if (selected_method->method_holder()->is_not_initialized()) {
- // 'is_not_initialized' means not only '!is_initialized', but also that
- // initialization has not been started yet ('!being_initialized')
- // Do not force compilation of methods in uninitialized classes.
- // Note that doing this would throw an assert later,
- // in CompileBroker::compile_method.
- // We sometimes use the link resolver to do reflective lookups
- // even before classes are initialized.
- return;
- }
- CompileBroker::compile_method(selected_method, InvocationEntryBci,
- CompilationPolicy::policy()->initial_compile_level(),
- methodHandle(), 0, CompileTask::Reason_MustBeCompiled, CHECK);
- }
-}
-
-// Returns true if m is allowed to be compiled
-bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) {
- // allow any levels for WhiteBox
- assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
-
- if (m->is_abstract()) return false;
- if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
-
- // Math intrinsics should never be compiled as this can lead to
- // monotonicity problems because the interpreter will prefer the
- // compiled code to the intrinsic version. This can't happen in
- // production because the invocation counter can't be incremented
- // but we shouldn't expose the system to this problem in testing
- // modes.
- if (!AbstractInterpreter::can_be_compiled(m)) {
- return false;
- }
- if (comp_level == CompLevel_all) {
- if (TieredCompilation) {
- // enough to be compilable at any level for tiered
- return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
- } else {
- // must be compilable at available level for non-tiered
- return !m->is_not_compilable(CompLevel_highest_tier);
- }
- } else if (is_compile(comp_level)) {
- return !m->is_not_compilable(comp_level);
- }
- return false;
-}
-
-// Returns true if m is allowed to be osr compiled
-bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) {
- bool result = false;
- if (comp_level == CompLevel_all) {
- if (TieredCompilation) {
- // enough to be osr compilable at any level for tiered
- result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization);
- } else {
- // must be osr compilable at available level for non-tiered
- result = !m->is_not_osr_compilable(CompLevel_highest_tier);
- }
- } else if (is_compile(comp_level)) {
- result = !m->is_not_osr_compilable(comp_level);
- }
- return (result && can_be_compiled(m, comp_level));
-}
-
-bool CompilationPolicy::is_compilation_enabled() {
- // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler
- return CompileBroker::should_compile_new_jobs();
-}
-
-CompileTask* CompilationPolicy::select_task_helper(CompileQueue* compile_queue) {
- // Remove unloaded methods from the queue
- for (CompileTask* task = compile_queue->first(); task != NULL; ) {
- CompileTask* next = task->next();
- if (task->is_unloaded()) {
- compile_queue->remove_and_mark_stale(task);
- }
- task = next;
- }
-#if INCLUDE_JVMCI
- if (UseJVMCICompiler && !BackgroundCompilation) {
- /*
- * In blocking compilation mode, the CompileBroker will make
- * compilations submitted by a JVMCI compiler thread non-blocking. These
- * compilations should be scheduled after all blocking compilations
- * to service non-compiler related compilations sooner and reduce the
- * chance of such compilations timing out.
- */
- for (CompileTask* task = compile_queue->first(); task != NULL; task = task->next()) {
- if (task->is_blocking()) {
- return task;
- }
- }
- }
-#endif
- return compile_queue->first();
-}
-
-#ifndef PRODUCT
-void SimpleCompPolicy::trace_osr_completion(nmethod* osr_nm) {
- if (TraceOnStackReplacement) {
- if (osr_nm == NULL) tty->print_cr("compilation failed");
- else tty->print_cr("nmethod " INTPTR_FORMAT, p2i(osr_nm));
- }
-}
-#endif // !PRODUCT
-
-void SimpleCompPolicy::initialize() {
- // Setup the compiler thread numbers
- if (CICompilerCountPerCPU) {
- // Example: if CICompilerCountPerCPU is true, then we get
- // max(log2(8)-1,1) = 2 compiler threads on an 8-way machine.
- // May help big-app startup time.
- _compiler_count = MAX2(log2_int(os::active_processor_count())-1,1);
- // Make sure there is enough space in the code cache to hold all the compiler buffers
- size_t buffer_size = 1;
-#ifdef COMPILER1
- buffer_size = is_client_compilation_mode_vm() ? Compiler::code_buffer_size() : buffer_size;
-#endif
-#ifdef COMPILER2
- buffer_size = is_server_compilation_mode_vm() ? C2Compiler::initial_code_buffer_size() : buffer_size;
-#endif
- int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size;
- if (_compiler_count > max_count) {
- // Lower the compiler count such that all buffers fit into the code cache
- _compiler_count = MAX2(max_count, 1);
- }
- FLAG_SET_ERGO(CICompilerCount, _compiler_count);
- } else {
- _compiler_count = CICompilerCount;
- }
-}
-
-// Note: this policy is used ONLY if TieredCompilation is off.
-// compiler_count() behaves the following way:
-// - with TIERED build (with both COMPILER1 and COMPILER2 defined) it should return
-// zero for the c1 compilation levels in server compilation mode runs
-// and c2 compilation levels in client compilation mode runs.
-// - with COMPILER2 not defined it should return zero for c2 compilation levels.
-// - with COMPILER1 not defined it should return zero for c1 compilation levels.
-// - if neither is defined - always return zero.
-int SimpleCompPolicy::compiler_count(CompLevel comp_level) {
- assert(!TieredCompilation, "This policy should not be used with TieredCompilation");
- if (COMPILER2_PRESENT(is_server_compilation_mode_vm() && is_c2_compile(comp_level) ||)
- is_client_compilation_mode_vm() && is_c1_compile(comp_level)) {
- return _compiler_count;
- }
- return 0;
-}
-
-void SimpleCompPolicy::reset_counter_for_invocation_event(const methodHandle& m) {
- // Make sure invocation and backedge counter doesn't overflow again right away
- // as would be the case for native methods.
-
- // BUT also make sure the method doesn't look like it was never executed.
- // Set carry bit and reduce counter's value to min(count, CompileThreshold/2).
- MethodCounters* mcs = m->method_counters();
- assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
- mcs->invocation_counter()->set_carry();
- mcs->backedge_counter()->set_carry();
-
- assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed");
-}
-
-void SimpleCompPolicy::reset_counter_for_back_branch_event(const methodHandle& m) {
- // Delay next back-branch event but pump up invocation counter to trigger
- // whole method compilation.
- MethodCounters* mcs = m->method_counters();
- assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
- InvocationCounter* i = mcs->invocation_counter();
- InvocationCounter* b = mcs->backedge_counter();
-
- // Don't set invocation_counter's value too low otherwise the method will
- // look like immature (ic < ~5300) which prevents the inlining based on
- // the type profiling.
- i->set(i->state(), CompileThreshold);
- // Don't reset counter too low - it is used to check if OSR method is ready.
- b->set(b->state(), CompileThreshold / 2);
-}
-
-//
-// CounterDecay
-//
-// Iterates through invocation counters and decrements them. This
-// is done at each safepoint.
-//
-class CounterDecay : public AllStatic {
- static jlong _last_timestamp;
- static void do_method(Method* m) {
- MethodCounters* mcs = m->method_counters();
- if (mcs != NULL) {
- mcs->invocation_counter()->decay();
- }
- }
-public:
- static void decay();
- static bool is_decay_needed() {
- return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength;
- }
-};
-
-jlong CounterDecay::_last_timestamp = 0;
-
-void CounterDecay::decay() {
- _last_timestamp = os::javaTimeMillis();
-
- // This operation is going to be performed only at the end of a safepoint
- // and hence GC's will not be going on, all Java mutators are suspended
- // at this point and hence SystemDictionary_lock is also not needed.
- assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
- size_t nclasses = ClassLoaderDataGraph::num_instance_classes();
- size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
- CounterHalfLifeTime);
- for (size_t i = 0; i < classes_per_tick; i++) {
- InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class();
- if (k != NULL) {
- k->methods_do(do_method);
- }
- }
-}
-
-// Called at the end of the safepoint
-void SimpleCompPolicy::do_safepoint_work() {
- if(UseCounterDecay && CounterDecay::is_decay_needed()) {
- CounterDecay::decay();
- }
-}
-
-void SimpleCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
- ScopeDesc* sd = trap_scope;
- MethodCounters* mcs;
- InvocationCounter* c;
- for (; !sd->is_top(); sd = sd->sender()) {
- mcs = sd->method()->method_counters();
- if (mcs != NULL) {
- // Reset ICs of inlined methods, since they can trigger compilations also.
- mcs->invocation_counter()->reset();
- }
- }
- mcs = sd->method()->method_counters();
- if (mcs != NULL) {
- c = mcs->invocation_counter();
- if (is_osr) {
- // It was an OSR method, so bump the count higher.
- c->set(c->state(), CompileThreshold);
- } else {
- c->reset();
- }
- mcs->backedge_counter()->reset();
- }
-}
-
-// This method can be called by any component of the runtime to notify the policy
-// that it's recommended to delay the compilation of this method.
-void SimpleCompPolicy::delay_compilation(Method* method) {
- MethodCounters* mcs = method->method_counters();
- if (mcs != NULL) {
- mcs->invocation_counter()->decay();
- mcs->backedge_counter()->decay();
- }
-}
-
-void SimpleCompPolicy::disable_compilation(Method* method) {
- MethodCounters* mcs = method->method_counters();
- if (mcs != NULL) {
- mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
- mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing);
- }
-}
-
-CompileTask* SimpleCompPolicy::select_task(CompileQueue* compile_queue) {
- return select_task_helper(compile_queue);
-}
-
-bool SimpleCompPolicy::is_mature(Method* method) {
- MethodData* mdo = method->method_data();
- assert(mdo != NULL, "Should be");
- uint current = mdo->mileage_of(method);
- uint initial = mdo->creation_mileage();
- if (current < initial)
- return true; // some sort of overflow
- uint target;
- if (ProfileMaturityPercentage <= 0)
- target = (uint) -ProfileMaturityPercentage; // absolute value
- else
- target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 );
- return (current >= initial + target);
-}
-
-nmethod* SimpleCompPolicy::event(const methodHandle& method, const methodHandle& inlinee, int branch_bci,
- int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
- assert(comp_level == CompLevel_none, "This should be only called from the interpreter");
- NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci));
- if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
- // If certain JVMTI events (e.g. frame pop event) are requested then the
- // thread is forced to remain in interpreted code. This is
- // implemented partly by a check in the run_compiled_code
- // section of the interpreter whether we should skip running
- // compiled code, and partly by skipping OSR compiles for
- // interpreted-only threads.
- if (bci != InvocationEntryBci) {
- reset_counter_for_back_branch_event(method);
- return NULL;
- }
- }
- if (ReplayCompiles) {
- // Don't trigger other compiles in testing mode
- if (bci == InvocationEntryBci) {
- reset_counter_for_invocation_event(method);
- } else {
- reset_counter_for_back_branch_event(method);
- }
- return NULL;
- }
-
- if (bci == InvocationEntryBci) {
- // when code cache is full, compilation gets switched off, UseCompiler
- // is set to false
- if (!method->has_compiled_code() && UseCompiler) {
- method_invocation_event(method, thread);
- } else {
- // Force counter overflow on method entry, even if no compilation
- // happened. (The method_invocation_event call does this also.)
- reset_counter_for_invocation_event(method);
- }
- // compilation at an invocation overflow no longer goes and retries test for
- // compiled method. We always run the loser of the race as interpreted.
- // so return NULL
- return NULL;
- } else {
- // counter overflow in a loop => try to do on-stack-replacement
- nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
- NOT_PRODUCT(trace_osr_request(method, osr_nm, bci));
- // when code cache is full, we should not compile any more...
- if (osr_nm == NULL && UseCompiler) {
- method_back_branch_event(method, bci, thread);
- osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
- }
- if (osr_nm == NULL) {
- reset_counter_for_back_branch_event(method);
- return NULL;
- }
- return osr_nm;
- }
- return NULL;
-}
-
-#ifndef PRODUCT
-void SimpleCompPolicy::trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci) {
- if (TraceInvocationCounterOverflow) {
- MethodCounters* mcs = m->method_counters();
- assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
- InvocationCounter* ic = mcs->invocation_counter();
- InvocationCounter* bc = mcs->backedge_counter();
- ResourceMark rm;
- if (bci == InvocationEntryBci) {
- tty->print("comp-policy cntr ovfl @ %d in entry of ", bci);
- } else {
- tty->print("comp-policy cntr ovfl @ %d in loop of ", bci);
- }
- m->print_value();
- tty->cr();
- ic->print();
- bc->print();
- if (ProfileInterpreter) {
- if (bci != InvocationEntryBci) {
- MethodData* mdo = m->method_data();
- if (mdo != NULL) {
- ProfileData *pd = mdo->bci_to_data(branch_bci);
- if (pd == NULL) {
- tty->print_cr("back branch count = N/A (missing ProfileData)");
- } else {
- tty->print_cr("back branch count = %d", pd->as_JumpData()->taken());
- }
- }
- }
- }
- }
-}
-
-void SimpleCompPolicy::trace_osr_request(const methodHandle& method, nmethod* osr, int bci) {
- if (TraceOnStackReplacement) {
- ResourceMark rm;
- tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for ");
- method->print_short_name(tty);
- tty->print_cr(" at bci %d", bci);
- }
-}
-#endif // !PRODUCT
-
-void SimpleCompPolicy::method_invocation_event(const methodHandle& m, JavaThread* thread) {
- const int comp_level = CompLevel_highest_tier;
- const int hot_count = m->invocation_count();
- reset_counter_for_invocation_event(m);
-
- if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
- CompiledMethod* nm = m->code();
- if (nm == NULL ) {
- CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, CompileTask::Reason_InvocationCount, thread);
- }
- }
-}
-
-void SimpleCompPolicy::method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread) {
- const int comp_level = CompLevel_highest_tier;
- const int hot_count = m->backedge_count();
-
- if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) {
- CompileBroker::compile_method(m, bci, comp_level, m, hot_count, CompileTask::Reason_BackedgeCount, thread);
- NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
- }
-}
--- a/src/hotspot/share/runtime/compilationPolicy.hpp Thu Oct 10 21:54:54 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_RUNTIME_COMPILATIONPOLICY_HPP
-#define SHARE_RUNTIME_COMPILATIONPOLICY_HPP
-
-#include "code/nmethod.hpp"
-#include "compiler/compileBroker.hpp"
-#include "memory/allocation.hpp"
-#include "runtime/vmOperations.hpp"
-#include "utilities/growableArray.hpp"
-
-// The CompilationPolicy selects which method (if any) should be compiled.
-// It also decides which methods must always be compiled (i.e., are never
-// interpreted).
-class CompileTask;
-class CompileQueue;
-
-class CompilationPolicy : public CHeapObj<mtCompiler> {
- static CompilationPolicy* _policy;
-
- // m must be compiled before executing it
- static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_all);
-
-public:
- // If m must_be_compiled then request a compilation from the CompileBroker.
- // This supports the -Xcomp option.
- static void compile_if_required(const methodHandle& m, TRAPS);
-
- // m is allowed to be compiled
- static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_all);
- // m is allowed to be osr compiled
- static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_all);
- static bool is_compilation_enabled();
- static void set_policy(CompilationPolicy* policy) { _policy = policy; }
- static CompilationPolicy* policy() { return _policy; }
-
- static CompileTask* select_task_helper(CompileQueue* compile_queue);
-
- // Return initial compile level that is used with Xcomp
- virtual CompLevel initial_compile_level() = 0;
- virtual int compiler_count(CompLevel comp_level) = 0;
- // main notification entry, return a pointer to an nmethod if the OSR is required,
- // returns NULL otherwise.
- virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) = 0;
- // safepoint() is called at the end of the safepoint
- virtual void do_safepoint_work() = 0;
- // reprofile request
- virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0;
- // delay_compilation(method) can be called by any component of the runtime to notify the policy
- // that it's recommended to delay the compilation of this method.
- virtual void delay_compilation(Method* method) = 0;
- // disable_compilation() is called whenever the runtime decides to disable compilation of the
- // specified method.
- virtual void disable_compilation(Method* method) = 0;
- // Select task is called by CompileBroker. The queue is guaranteed to have at least one
- // element and is locked. The function should select one and return it.
- virtual CompileTask* select_task(CompileQueue* compile_queue) = 0;
- // Tell the runtime if we think a given method is adequately profiled.
- virtual bool is_mature(Method* method) = 0;
- // Do policy initialization
- virtual void initialize() = 0;
- virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; }
-};
-
-// A simple compilation policy.
-class SimpleCompPolicy : public CompilationPolicy {
- int _compiler_count;
- private:
- static void trace_frequency_counter_overflow(const methodHandle& m, int branch_bci, int bci);
- static void trace_osr_request(const methodHandle& method, nmethod* osr, int bci);
- static void trace_osr_completion(nmethod* osr_nm);
- void reset_counter_for_invocation_event(const methodHandle& method);
- void reset_counter_for_back_branch_event(const methodHandle& method);
- void method_invocation_event(const methodHandle& m, JavaThread* thread);
- void method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread);
- public:
- SimpleCompPolicy() : _compiler_count(0) { }
- virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; }
- virtual int compiler_count(CompLevel comp_level);
- virtual void do_safepoint_work();
- virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
- virtual void delay_compilation(Method* method);
- virtual void disable_compilation(Method* method);
- virtual bool is_mature(Method* method);
- virtual void initialize();
- virtual CompileTask* select_task(CompileQueue* compile_queue);
- virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
-};
-
-
-#endif // SHARE_RUNTIME_COMPILATIONPOLICY_HPP
--- a/src/hotspot/share/runtime/deoptimization.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/deoptimization.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -31,6 +31,7 @@
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
#include "code/scopeDesc.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
@@ -48,7 +49,6 @@
#include "oops/verifyOopClosure.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
--- a/src/hotspot/share/runtime/java.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/java.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -56,7 +56,6 @@
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/runtime/javaCalls.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/javaCalls.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -26,6 +26,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/nmethod.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
@@ -33,7 +34,6 @@
#include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jniCheck.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaCalls.hpp"
--- a/src/hotspot/share/runtime/safepoint.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/safepoint.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -33,6 +33,7 @@
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
#include "code/scopeDesc.hpp"
+#include "compiler/compilationPolicy.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gcLocker.hpp"
#include "gc/shared/oopStorage.hpp"
@@ -47,7 +48,6 @@
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -57,7 +57,6 @@
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
--- a/src/hotspot/share/runtime/sweeper.cpp Thu Oct 10 21:54:54 2019 +0200
+++ b/src/hotspot/share/runtime/sweeper.cpp Wed Oct 09 12:43:32 2019 -0700
@@ -38,7 +38,6 @@
#include "memory/universe.hpp"
#include "oops/method.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/compilationPolicy.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/handshake.hpp"
#include "runtime/mutexLocker.hpp"
--- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Thu Oct 10 21:54:54 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1005 +0,0 @@
-/*
- * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "compiler/compileBroker.hpp"
-#include "compiler/compilerOracle.hpp"
-#include "memory/resourceArea.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/safepointVerifiers.hpp"
-#include "runtime/tieredThresholdPolicy.hpp"
-#include "code/scopeDesc.hpp"
-#include "oops/method.inline.hpp"
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci.hpp"
-#endif
-
-#ifdef TIERED
-
-#include "c1/c1_Compiler.hpp"
-#include "opto/c2compiler.hpp"
-
-template<CompLevel level>
-bool TieredThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) {
- double threshold_scaling;
- if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) {
- scale *= threshold_scaling;
- }
- switch(level) {
- case CompLevel_aot:
- return (i >= Tier3AOTInvocationThreshold * scale) ||
- (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale);
- case CompLevel_none:
- case CompLevel_limited_profile:
- return (i >= Tier3InvocationThreshold * scale) ||
- (i >= Tier3MinInvocationThreshold * scale && i + b >= Tier3CompileThreshold * scale);
- case CompLevel_full_profile:
- return (i >= Tier4InvocationThreshold * scale) ||
- (i >= Tier4MinInvocationThreshold * scale && i + b >= Tier4CompileThreshold * scale);
- }
- return true;
-}
-
-template<CompLevel level>
-bool TieredThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) {
- double threshold_scaling;
- if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) {
- scale *= threshold_scaling;
- }
- switch(level) {
- case CompLevel_aot:
- return b >= Tier3AOTBackEdgeThreshold * scale;
- case CompLevel_none:
- case CompLevel_limited_profile:
- return b >= Tier3BackEdgeThreshold * scale;
- case CompLevel_full_profile:
- return b >= Tier4BackEdgeThreshold * scale;
- }
- return true;
-}
-
-// Simple methods are as good being compiled with C1 as C2.
-// Determine if a given method is such a case.
-bool TieredThresholdPolicy::is_trivial(Method* method) {
- if (method->is_accessor() ||
- method->is_constant_getter()) {
- return true;
- }
- return false;
-}
-
-bool TieredThresholdPolicy::should_compile_at_level_simple(Method* method) {
- if (TieredThresholdPolicy::is_trivial(method)) {
- return true;
- }
-#if INCLUDE_JVMCI
- if (UseJVMCICompiler) {
- AbstractCompiler* comp = CompileBroker::compiler(CompLevel_full_optimization);
- if (comp != NULL && comp->is_jvmci() && ((JVMCICompiler*) comp)->force_comp_at_level_simple(method)) {
- return true;
- }
- }
-#endif
- return false;
-}
-
-CompLevel TieredThresholdPolicy::comp_level(Method* method) {
- CompiledMethod *nm = method->code();
- if (nm != NULL && nm->is_in_use()) {
- return (CompLevel)nm->comp_level();
- }
- return CompLevel_none;
-}
-
-void TieredThresholdPolicy::print_counters(const char* prefix, const methodHandle& mh) {
- int invocation_count = mh->invocation_count();
- int backedge_count = mh->backedge_count();
- MethodData* mdh = mh->method_data();
- int mdo_invocations = 0, mdo_backedges = 0;
- int mdo_invocations_start = 0, mdo_backedges_start = 0;
- if (mdh != NULL) {
- mdo_invocations = mdh->invocation_count();
- mdo_backedges = mdh->backedge_count();
- mdo_invocations_start = mdh->invocation_count_start();
- mdo_backedges_start = mdh->backedge_count_start();
- }
- tty->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix,
- invocation_count, backedge_count, prefix,
- mdo_invocations, mdo_invocations_start,
- mdo_backedges, mdo_backedges_start);
- tty->print(" %smax levels=%d,%d", prefix,
- mh->highest_comp_level(), mh->highest_osr_comp_level());
-}
-
-// Print an event.
-void TieredThresholdPolicy::print_event(EventType type, const methodHandle& mh, const methodHandle& imh,
- int bci, CompLevel level) {
- bool inlinee_event = mh() != imh();
-
- ttyLocker tty_lock;
- tty->print("%lf: [", os::elapsedTime());
-
- switch(type) {
- case CALL:
- tty->print("call");
- break;
- case LOOP:
- tty->print("loop");
- break;
- case COMPILE:
- tty->print("compile");
- break;
- case REMOVE_FROM_QUEUE:
- tty->print("remove-from-queue");
- break;
- case UPDATE_IN_QUEUE:
- tty->print("update-in-queue");
- break;
- case REPROFILE:
- tty->print("reprofile");
- break;
- case MAKE_NOT_ENTRANT:
- tty->print("make-not-entrant");
- break;
- default:
- tty->print("unknown");
- }
-
- tty->print(" level=%d ", level);
-
- ResourceMark rm;
- char *method_name = mh->name_and_sig_as_C_string();
- tty->print("[%s", method_name);
- if (inlinee_event) {
- char *inlinee_name = imh->name_and_sig_as_C_string();
- tty->print(" [%s]] ", inlinee_name);
- }
- else tty->print("] ");
- tty->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile),
- CompileBroker::queue_size(CompLevel_full_optimization));
-
- print_specific(type, mh, imh, bci, level);
-
- if (type != COMPILE) {
- print_counters("", mh);
- if (inlinee_event) {
- print_counters("inlinee ", imh);
- }
- tty->print(" compilable=");
- bool need_comma = false;
- if (!mh->is_not_compilable(CompLevel_full_profile)) {
- tty->print("c1");
- need_comma = true;
- }
- if (!mh->is_not_osr_compilable(CompLevel_full_profile)) {
- if (need_comma) tty->print(",");
- tty->print("c1-osr");
- need_comma = true;
- }
- if (!mh->is_not_compilable(CompLevel_full_optimization)) {
- if (need_comma) tty->print(",");
- tty->print("c2");
- need_comma = true;
- }
- if (!mh->is_not_osr_compilable(CompLevel_full_optimization)) {
- if (need_comma) tty->print(",");
- tty->print("c2-osr");
- }
- tty->print(" status=");
- if (mh->queued_for_compilation()) {
- tty->print("in-queue");
- } else tty->print("idle");
- }
- tty->print_cr("]");
-}
-
-void TieredThresholdPolicy::initialize() {
- int count = CICompilerCount;
- bool c1_only = TieredStopAtLevel < CompLevel_full_optimization;
-#ifdef _LP64
- // Turn on ergonomic compiler count selection
- if (FLAG_IS_DEFAULT(CICompilerCountPerCPU) && FLAG_IS_DEFAULT(CICompilerCount)) {
- FLAG_SET_DEFAULT(CICompilerCountPerCPU, true);
- }
- if (CICompilerCountPerCPU) {
- // Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n
- int log_cpu = log2_int(os::active_processor_count());
- int loglog_cpu = log2_int(MAX2(log_cpu, 1));
- count = MAX2(log_cpu * loglog_cpu * 3 / 2, 2);
- // Make sure there is enough space in the code cache to hold all the compiler buffers
- size_t c1_size = Compiler::code_buffer_size();
- size_t c2_size = C2Compiler::initial_code_buffer_size();
- size_t buffer_size = c1_only ? c1_size : (c1_size/3 + 2*c2_size/3);
- int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size;
- if (count > max_count) {
- // Lower the compiler count such that all buffers fit into the code cache
- count = MAX2(max_count, c1_only ? 1 : 2);
- }
- FLAG_SET_ERGO(CICompilerCount, count);
- }
-#else
- // On 32-bit systems, the number of compiler threads is limited to 3.
- // On these systems, the virtual address space available to the JVM
- // is usually limited to 2-4 GB (the exact value depends on the platform).
- // As the compilers (especially C2) can consume a large amount of
- // memory, scaling the number of compiler threads with the number of
- // available cores can result in the exhaustion of the address space
- /// available to the VM and thus cause the VM to crash.
- if (FLAG_IS_DEFAULT(CICompilerCount)) {
- count = 3;
- FLAG_SET_ERGO(CICompilerCount, count);
- }
-#endif
-
- if (c1_only) {
- // No C2 compiler thread required
- set_c1_count(count);
- } else {
- set_c1_count(MAX2(count / 3, 1));
- set_c2_count(MAX2(count - c1_count(), 1));
- }
- assert(count == c1_count() + c2_count(), "inconsistent compiler thread count");
-
- // Some inlining tuning
-#ifdef X86
- if (FLAG_IS_DEFAULT(InlineSmallCode)) {
- FLAG_SET_DEFAULT(InlineSmallCode, 2000);
- }
-#endif
-
-#if defined SPARC || defined AARCH64
- if (FLAG_IS_DEFAULT(InlineSmallCode)) {
- FLAG_SET_DEFAULT(InlineSmallCode, 2500);
- }
-#endif
-
- set_increase_threshold_at_ratio();
- set_start_time(os::javaTimeMillis());
-}
-
-void TieredThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) {
- if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) {
- counter->set_carry_flag();
- }
-}
-
-// Set carry flags on the counters if necessary
-void TieredThresholdPolicy::handle_counter_overflow(Method* method) {
- MethodCounters *mcs = method->method_counters();
- if (mcs != NULL) {
- set_carry_if_necessary(mcs->invocation_counter());
- set_carry_if_necessary(mcs->backedge_counter());
- }
- MethodData* mdo = method->method_data();
- if (mdo != NULL) {
- set_carry_if_necessary(mdo->invocation_counter());
- set_carry_if_necessary(mdo->backedge_counter());
- }
-}
-
-// Called with the queue locked and with at least one element
-CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) {
- CompileTask *max_blocking_task = NULL;
- CompileTask *max_task = NULL;
- Method* max_method = NULL;
- jlong t = os::javaTimeMillis();
- // Iterate through the queue and find a method with a maximum rate.
- for (CompileTask* task = compile_queue->first(); task != NULL;) {
- CompileTask* next_task = task->next();
- Method* method = task->method();
- // If a method was unloaded or has been stale for some time, remove it from the queue.
- // Blocking tasks and tasks submitted from whitebox API don't become stale
- if (task->is_unloaded() || (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, method) && !is_old(method))) {
- if (!task->is_unloaded()) {
- if (PrintTieredEvents) {
- print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel) task->comp_level());
- }
- method->clear_queued_for_compilation();
- }
- compile_queue->remove_and_mark_stale(task);
- task = next_task;
- continue;
- }
- update_rate(t, method);
- if (max_task == NULL || compare_methods(method, max_method)) {
- // Select a method with the highest rate
- max_task = task;
- max_method = method;
- }
-
- if (task->is_blocking()) {
- if (max_blocking_task == NULL || compare_methods(method, max_blocking_task->method())) {
- max_blocking_task = task;
- }
- }
-
- task = next_task;
- }
-
- if (max_blocking_task != NULL) {
- // In blocking compilation mode, the CompileBroker will make
- // compilations submitted by a JVMCI compiler thread non-blocking. These
- // compilations should be scheduled after all blocking compilations
- // to service non-compiler related compilations sooner and reduce the
- // chance of such compilations timing out.
- max_task = max_blocking_task;
- max_method = max_task->method();
- }
-
- if (max_task != NULL && max_task->comp_level() == CompLevel_full_profile &&
- TieredStopAtLevel > CompLevel_full_profile &&
- max_method != NULL && is_method_profiled(max_method)) {
- max_task->set_comp_level(CompLevel_limited_profile);
-
- if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) {
- if (PrintTieredEvents) {
- print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
- }
- compile_queue->remove_and_mark_stale(max_task);
- max_method->clear_queued_for_compilation();
- return NULL;
- }
-
- if (PrintTieredEvents) {
- print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
- }
- }
-
- return max_task;
-}
-
-void TieredThresholdPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
- for (ScopeDesc* sd = trap_scope;; sd = sd->sender()) {
- if (PrintTieredEvents) {
- methodHandle mh(sd->method());
- print_event(REPROFILE, mh, mh, InvocationEntryBci, CompLevel_none);
- }
- MethodData* mdo = sd->method()->method_data();
- if (mdo != NULL) {
- mdo->reset_start_counters();
- }
- if (sd->is_top()) break;
- }
-}
-
-nmethod* TieredThresholdPolicy::event(const methodHandle& method, const methodHandle& inlinee,
- int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
- if (comp_level == CompLevel_none &&
- JvmtiExport::can_post_interpreter_events() &&
- thread->is_interp_only_mode()) {
- return NULL;
- }
- if (ReplayCompiles) {
- // Don't trigger other compiles in testing mode
- return NULL;
- }
-
- handle_counter_overflow(method());
- if (method() != inlinee()) {
- handle_counter_overflow(inlinee());
- }
-
- if (PrintTieredEvents) {
- print_event(bci == InvocationEntryBci ? CALL : LOOP, method, inlinee, bci, comp_level);
- }
-
- if (bci == InvocationEntryBci) {
- method_invocation_event(method, inlinee, comp_level, nm, thread);
- } else {
- // method == inlinee if the event originated in the main method
- method_back_branch_event(method, inlinee, bci, comp_level, nm, thread);
- // Check if event led to a higher level OSR compilation
- CompLevel expected_comp_level = comp_level;
- if (inlinee->is_not_osr_compilable(expected_comp_level)) {
- // It's not possble to reach the expected level so fall back to simple.
- expected_comp_level = CompLevel_simple;
- }
- nmethod* osr_nm = inlinee->lookup_osr_nmethod_for(bci, expected_comp_level, false);
- assert(osr_nm == NULL || osr_nm->comp_level() >= expected_comp_level, "lookup_osr_nmethod_for is broken");
- if (osr_nm != NULL) {
- // Perform OSR with new nmethod
- return osr_nm;
- }
- }
- return NULL;
-}
-
-// Check if the method can be compiled, change level if necessary
-void TieredThresholdPolicy::compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) {
- assert(level <= TieredStopAtLevel, "Invalid compilation level");
- if (level == CompLevel_none) {
- return;
- }
- if (level == CompLevel_aot) {
- if (mh->has_aot_code()) {
- if (PrintTieredEvents) {
- print_event(COMPILE, mh, mh, bci, level);
- }
- MutexLocker ml(Compile_lock);
- NoSafepointVerifier nsv;
- if (mh->has_aot_code() && mh->code() != mh->aot_code()) {
- mh->aot_code()->make_entrant();
- if (mh->has_compiled_code()) {
- mh->code()->make_not_entrant();
- }
- MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
- Method::set_code(mh, mh->aot_code());
- }
- }
- return;
- }
-
- // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling
- // in the interpreter and then compile with C2 (the transition function will request that,
- // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with
- // pure C1.
- if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) {
- if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) {
- compile(mh, bci, CompLevel_simple, thread);
- }
- return;
- }
- if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) {
- if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) {
- nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false);
- if (osr_nm != NULL && osr_nm->comp_level() > CompLevel_simple) {
- // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted.
- osr_nm->make_not_entrant();
- }
- compile(mh, bci, CompLevel_simple, thread);
- }
- return;
- }
- if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) {
- return;
- }
- if (!CompileBroker::compilation_is_in_queue(mh)) {
- if (PrintTieredEvents) {
- print_event(COMPILE, mh, mh, bci, level);
- }
- submit_compile(mh, bci, level, thread);
- }
-}
-
-// Update the rate and submit compile
-void TieredThresholdPolicy::submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread) {
- int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count();
- update_rate(os::javaTimeMillis(), mh());
- CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, thread);
-}
-
-// Print an event.
-void TieredThresholdPolicy::print_specific(EventType type, const methodHandle& mh, const methodHandle& imh,
- int bci, CompLevel level) {
- tty->print(" rate=");
- if (mh->prev_time() == 0) tty->print("n/a");
- else tty->print("%f", mh->rate());
-
- tty->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback),
- threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback));
-
-}
-
-// update_rate() is called from select_task() while holding a compile queue lock.
-void TieredThresholdPolicy::update_rate(jlong t, Method* m) {
- // Skip update if counters are absent.
- // Can't allocate them since we are holding compile queue lock.
- if (m->method_counters() == NULL) return;
-
- if (is_old(m)) {
- // We don't remove old methods from the queue,
- // so we can just zero the rate.
- m->set_rate(0);
- return;
- }
-
- // We don't update the rate if we've just came out of a safepoint.
- // delta_s is the time since last safepoint in milliseconds.
- jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms();
- jlong delta_t = t - (m->prev_time() != 0 ? m->prev_time() : start_time()); // milliseconds since the last measurement
- // How many events were there since the last time?
- int event_count = m->invocation_count() + m->backedge_count();
- int delta_e = event_count - m->prev_event_count();
-
- // We should be running for at least 1ms.
- if (delta_s >= TieredRateUpdateMinTime) {
- // And we must've taken the previous point at least 1ms before.
- if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) {
- m->set_prev_time(t);
- m->set_prev_event_count(event_count);
- m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond
- } else {
- if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) {
- // If nothing happened for 25ms, zero the rate. Don't modify prev values.
- m->set_rate(0);
- }
- }
- }
-}
-
-// Check if this method has been stale for a given number of milliseconds.
-// See select_task().
-bool TieredThresholdPolicy::is_stale(jlong t, jlong timeout, Method* m) {
- jlong delta_s = t - SafepointTracing::end_of_last_safepoint_epoch_ms();
- jlong delta_t = t - m->prev_time();
- if (delta_t > timeout && delta_s > timeout) {
- int event_count = m->invocation_count() + m->backedge_count();
- int delta_e = event_count - m->prev_event_count();
- // Return true if there were no events.
- return delta_e == 0;
- }
- return false;
-}
-
-// We don't remove old methods from the compile queue even if they have
-// very low activity. See select_task().
-bool TieredThresholdPolicy::is_old(Method* method) {
- return method->invocation_count() > 50000 || method->backedge_count() > 500000;
-}
-
-double TieredThresholdPolicy::weight(Method* method) {
- return (double)(method->rate() + 1) *
- (method->invocation_count() + 1) * (method->backedge_count() + 1);
-}
-
-// Apply heuristics and return true if x should be compiled before y
-bool TieredThresholdPolicy::compare_methods(Method* x, Method* y) {
- if (x->highest_comp_level() > y->highest_comp_level()) {
- // recompilation after deopt
- return true;
- } else
- if (x->highest_comp_level() == y->highest_comp_level()) {
- if (weight(x) > weight(y)) {
- return true;
- }
- }
- return false;
-}
-
-// Is method profiled enough?
-bool TieredThresholdPolicy::is_method_profiled(Method* method) {
- MethodData* mdo = method->method_data();
- if (mdo != NULL) {
- int i = mdo->invocation_count_delta();
- int b = mdo->backedge_count_delta();
- return call_predicate_helper<CompLevel_full_profile>(i, b, 1, method);
- }
- return false;
-}
-
-double TieredThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) {
- double queue_size = CompileBroker::queue_size(level);
- int comp_count = compiler_count(level);
- double k = queue_size / (feedback_k * comp_count) + 1;
-
- // Increase C1 compile threshold when the code cache is filled more
- // than specified by IncreaseFirstTierCompileThresholdAt percentage.
- // The main intention is to keep enough free space for C2 compiled code
- // to achieve peak performance if the code cache is under stress.
- if ((TieredStopAtLevel == CompLevel_full_optimization) && (level != CompLevel_full_optimization)) {
- double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level));
- if (current_reverse_free_ratio > _increase_threshold_at_ratio) {
- k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio);
- }
- }
- return k;
-}
-
-// Call and loop predicates determine whether a transition to a higher
-// compilation level should be performed (pointers to predicate functions
-// are passed to common()).
-// Tier?LoadFeedback is basically a coefficient that determines of
-// how many methods per compiler thread can be in the queue before
-// the threshold values double.
-bool TieredThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) {
- switch(cur_level) {
- case CompLevel_aot: {
- double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
- return loop_predicate_helper<CompLevel_aot>(i, b, k, method);
- }
- case CompLevel_none:
- case CompLevel_limited_profile: {
- double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
- return loop_predicate_helper<CompLevel_none>(i, b, k, method);
- }
- case CompLevel_full_profile: {
- double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback);
- return loop_predicate_helper<CompLevel_full_profile>(i, b, k, method);
- }
- default:
- return true;
- }
-}
-
-bool TieredThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) {
- switch(cur_level) {
- case CompLevel_aot: {
- double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
- return call_predicate_helper<CompLevel_aot>(i, b, k, method);
- }
- case CompLevel_none:
- case CompLevel_limited_profile: {
- double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
- return call_predicate_helper<CompLevel_none>(i, b, k, method);
- }
- case CompLevel_full_profile: {
- double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback);
- return call_predicate_helper<CompLevel_full_profile>(i, b, k, method);
- }
- default:
- return true;
- }
-}
-
-// Determine is a method is mature.
-bool TieredThresholdPolicy::is_mature(Method* method) {
- if (should_compile_at_level_simple(method)) return true;
- MethodData* mdo = method->method_data();
- if (mdo != NULL) {
- int i = mdo->invocation_count();
- int b = mdo->backedge_count();
- double k = ProfileMaturityPercentage / 100.0;
- return call_predicate_helper<CompLevel_full_profile>(i, b, k, method) ||
- loop_predicate_helper<CompLevel_full_profile>(i, b, k, method);
- }
- return false;
-}
-
-// If a method is old enough and is still in the interpreter we would want to
-// start profiling without waiting for the compiled method to arrive.
-// We also take the load on compilers into the account.
-bool TieredThresholdPolicy::should_create_mdo(Method* method, CompLevel cur_level) {
- if (cur_level == CompLevel_none &&
- CompileBroker::queue_size(CompLevel_full_optimization) <=
- Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
- int i = method->invocation_count();
- int b = method->backedge_count();
- double k = Tier0ProfilingStartPercentage / 100.0;
- return call_predicate_helper<CompLevel_none>(i, b, k, method) || loop_predicate_helper<CompLevel_none>(i, b, k, method);
- }
- return false;
-}
-
-// Inlining control: if we're compiling a profiled method with C1 and the callee
-// is known to have OSRed in a C2 version, don't inline it.
-bool TieredThresholdPolicy::should_not_inline(ciEnv* env, ciMethod* callee) {
- CompLevel comp_level = (CompLevel)env->comp_level();
- if (comp_level == CompLevel_full_profile ||
- comp_level == CompLevel_limited_profile) {
- return callee->highest_osr_comp_level() == CompLevel_full_optimization;
- }
- return false;
-}
-
-// Create MDO if necessary.
-void TieredThresholdPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) {
- if (mh->is_native() ||
- mh->is_abstract() ||
- mh->is_accessor() ||
- mh->is_constant_getter()) {
- return;
- }
- if (mh->method_data() == NULL) {
- Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR);
- }
-}
-
-
-/*
- * Method states:
- * 0 - interpreter (CompLevel_none)
- * 1 - pure C1 (CompLevel_simple)
- * 2 - C1 with invocation and backedge counting (CompLevel_limited_profile)
- * 3 - C1 with full profiling (CompLevel_full_profile)
- * 4 - C2 (CompLevel_full_optimization)
- *
- * Common state transition patterns:
- * a. 0 -> 3 -> 4.
- * The most common path. But note that even in this straightforward case
- * profiling can start at level 0 and finish at level 3.
- *
- * b. 0 -> 2 -> 3 -> 4.
- * This case occurs when the load on C2 is deemed too high. So, instead of transitioning
- * into state 3 directly and over-profiling while a method is in the C2 queue we transition to
- * level 2 and wait until the load on C2 decreases. This path is disabled for OSRs.
- *
- * c. 0 -> (3->2) -> 4.
- * In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough
- * to enable the profiling to fully occur at level 0. In this case we change the compilation level
- * of the method to 2 while the request is still in-queue, because it'll allow it to run much faster
- * without full profiling while c2 is compiling.
- *
- * d. 0 -> 3 -> 1 or 0 -> 2 -> 1.
- * After a method was once compiled with C1 it can be identified as trivial and be compiled to
- * level 1. These transition can also occur if a method can't be compiled with C2 but can with C1.
- *
- * e. 0 -> 4.
- * This can happen if a method fails C1 compilation (it will still be profiled in the interpreter)
- * or because of a deopt that didn't require reprofiling (compilation won't happen in this case because
- * the compiled version already exists).
- *
- * Note that since state 0 can be reached from any other state via deoptimization different loops
- * are possible.
- *
- */
-
-// Common transition function. Given a predicate determines if a method should transition to another level.
-CompLevel TieredThresholdPolicy::common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback) {
- CompLevel next_level = cur_level;
- int i = method->invocation_count();
- int b = method->backedge_count();
-
- if (should_compile_at_level_simple(method)) {
- next_level = CompLevel_simple;
- } else {
- switch(cur_level) {
- default: break;
- case CompLevel_aot: {
- // If we were at full profile level, would we switch to full opt?
- if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
- next_level = CompLevel_full_optimization;
- } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
- Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
- (this->*p)(i, b, cur_level, method))) {
- next_level = CompLevel_full_profile;
- }
- }
- break;
- case CompLevel_none:
- // If we were at full profile level, would we switch to full opt?
- if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
- next_level = CompLevel_full_optimization;
- } else if ((this->*p)(i, b, cur_level, method)) {
-#if INCLUDE_JVMCI
- if (EnableJVMCI && UseJVMCICompiler) {
- // Since JVMCI takes a while to warm up, its queue inevitably backs up during
- // early VM execution. As of 2014-06-13, JVMCI's inliner assumes that the root
- // compilation method and all potential inlinees have mature profiles (which
- // includes type profiling). If it sees immature profiles, JVMCI's inliner
- // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to
- // exploring/inlining too many graphs). Since a rewrite of the inliner is
- // in progress, we simply disable the dialing back heuristic for now and will
- // revisit this decision once the new inliner is completed.
- next_level = CompLevel_full_profile;
- } else
-#endif
- {
- // C1-generated fully profiled code is about 30% slower than the limited profile
- // code that has only invocation and backedge counters. The observation is that
- // if C2 queue is large enough we can spend too much time in the fully profiled code
- // while waiting for C2 to pick the method from the queue. To alleviate this problem
- // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long
- // we choose to compile a limited profiled version and then recompile with full profiling
- // when the load on C2 goes down.
- if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) >
- Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
- next_level = CompLevel_limited_profile;
- } else {
- next_level = CompLevel_full_profile;
- }
- }
- }
- break;
- case CompLevel_limited_profile:
- if (is_method_profiled(method)) {
- // Special case: we got here because this method was fully profiled in the interpreter.
- next_level = CompLevel_full_optimization;
- } else {
- MethodData* mdo = method->method_data();
- if (mdo != NULL) {
- if (mdo->would_profile()) {
- if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
- Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
- (this->*p)(i, b, cur_level, method))) {
- next_level = CompLevel_full_profile;
- }
- } else {
- next_level = CompLevel_full_optimization;
- }
- } else {
- // If there is no MDO we need to profile
- if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
- Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
- (this->*p)(i, b, cur_level, method))) {
- next_level = CompLevel_full_profile;
- }
- }
- }
- break;
- case CompLevel_full_profile:
- {
- MethodData* mdo = method->method_data();
- if (mdo != NULL) {
- if (mdo->would_profile()) {
- int mdo_i = mdo->invocation_count_delta();
- int mdo_b = mdo->backedge_count_delta();
- if ((this->*p)(mdo_i, mdo_b, cur_level, method)) {
- next_level = CompLevel_full_optimization;
- }
- } else {
- next_level = CompLevel_full_optimization;
- }
- }
- }
- break;
- }
- }
- return MIN2(next_level, (CompLevel)TieredStopAtLevel);
-}
-
-// Determine if a method should be compiled with a normal entry point at a different level.
-CompLevel TieredThresholdPolicy::call_event(Method* method, CompLevel cur_level, JavaThread * thread) {
- CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(),
- common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true));
- CompLevel next_level = common(&TieredThresholdPolicy::call_predicate, method, cur_level);
-
- // If OSR method level is greater than the regular method level, the levels should be
- // equalized by raising the regular method level in order to avoid OSRs during each
- // invocation of the method.
- if (osr_level == CompLevel_full_optimization && cur_level == CompLevel_full_profile) {
- MethodData* mdo = method->method_data();
- guarantee(mdo != NULL, "MDO should not be NULL");
- if (mdo->invocation_count() >= 1) {
- next_level = CompLevel_full_optimization;
- }
- } else {
- next_level = MAX2(osr_level, next_level);
- }
- return next_level;
-}
-
-// Determine if we should do an OSR compilation of a given method.
-CompLevel TieredThresholdPolicy::loop_event(Method* method, CompLevel cur_level, JavaThread* thread) {
- CompLevel next_level = common(&TieredThresholdPolicy::loop_predicate, method, cur_level, true);
- if (cur_level == CompLevel_none) {
- // If there is a live OSR method that means that we deopted to the interpreter
- // for the transition.
- CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level);
- if (osr_level > CompLevel_none) {
- return osr_level;
- }
- }
- return next_level;
-}
-
-bool TieredThresholdPolicy::maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread) {
- if (UseAOT) {
- if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) {
- // If the current level is full profile or interpreter and we're switching to any other level,
- // activate the AOT code back first so that we won't waste time overprofiling.
- compile(mh, InvocationEntryBci, CompLevel_aot, thread);
- // Fall through for JIT compilation.
- }
- if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) {
- // If the next level is limited profile, use the aot code (if there is any),
- // since it's essentially the same thing.
- compile(mh, InvocationEntryBci, CompLevel_aot, thread);
- // Not need to JIT, we're done.
- return true;
- }
- }
- return false;
-}
-
-
-// Handle the invocation event.
-void TieredThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
- CompLevel level, CompiledMethod* nm, JavaThread* thread) {
- if (should_create_mdo(mh(), level)) {
- create_mdo(mh, thread);
- }
- CompLevel next_level = call_event(mh(), level, thread);
- if (next_level != level) {
- if (maybe_switch_to_aot(mh, level, next_level, thread)) {
- // No JITting necessary
- return;
- }
- if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
- compile(mh, InvocationEntryBci, next_level, thread);
- }
- }
-}
-
-// Handle the back branch event. Notice that we can compile the method
-// with a regular entry from here.
-void TieredThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh,
- int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) {
- if (should_create_mdo(mh(), level)) {
- create_mdo(mh, thread);
- }
- // Check if MDO should be created for the inlined method
- if (should_create_mdo(imh(), level)) {
- create_mdo(imh, thread);
- }
-
- if (is_compilation_enabled()) {
- CompLevel next_osr_level = loop_event(imh(), level, thread);
- CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level();
- // At the very least compile the OSR version
- if (!CompileBroker::compilation_is_in_queue(imh) && (next_osr_level != level)) {
- compile(imh, bci, next_osr_level, thread);
- }
-
- // Use loop event as an opportunity to also check if there's been
- // enough calls.
- CompLevel cur_level, next_level;
- if (mh() != imh()) { // If there is an enclosing method
- if (level == CompLevel_aot) {
- // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling.
- if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) {
- compile(mh, InvocationEntryBci, MIN2((CompLevel)TieredStopAtLevel, CompLevel_full_profile), thread);
- }
- } else {
- // Current loop event level is not AOT
- guarantee(nm != NULL, "Should have nmethod here");
- cur_level = comp_level(mh());
- next_level = call_event(mh(), cur_level, thread);
-
- if (max_osr_level == CompLevel_full_optimization) {
- // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts
- bool make_not_entrant = false;
- if (nm->is_osr_method()) {
- // This is an osr method, just make it not entrant and recompile later if needed
- make_not_entrant = true;
- } else {
- if (next_level != CompLevel_full_optimization) {
- // next_level is not full opt, so we need to recompile the
- // enclosing method without the inlinee
- cur_level = CompLevel_none;
- make_not_entrant = true;
- }
- }
- if (make_not_entrant) {
- if (PrintTieredEvents) {
- int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
- print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level);
- }
- nm->make_not_entrant();
- }
- }
- // Fix up next_level if necessary to avoid deopts
- if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) {
- next_level = CompLevel_full_profile;
- }
- if (cur_level != next_level) {
- if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
- compile(mh, InvocationEntryBci, next_level, thread);
- }
- }
- }
- } else {
- cur_level = comp_level(mh());
- next_level = call_event(mh(), cur_level, thread);
- if (next_level != cur_level) {
- if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
- compile(mh, InvocationEntryBci, next_level, thread);
- }
- }
- }
- }
-}
-
-#endif
--- a/src/hotspot/share/runtime/tieredThresholdPolicy.hpp Thu Oct 10 21:54:54 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP
-#define SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP
-
-#include "code/nmethod.hpp"
-#include "oops/methodData.hpp"
-#include "runtime/compilationPolicy.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-#ifdef TIERED
-
-class CompileTask;
-class CompileQueue;
-/*
- * The system supports 5 execution levels:
- * * level 0 - interpreter
- * * level 1 - C1 with full optimization (no profiling)
- * * level 2 - C1 with invocation and backedge counters
- * * level 3 - C1 with full profiling (level 2 + MDO)
- * * level 4 - C2
- *
- * Levels 0, 2 and 3 periodically notify the runtime about the current value of the counters
- * (invocation counters and backedge counters). The frequency of these notifications is
- * different at each level. These notifications are used by the policy to decide what transition
- * to make.
- *
- * Execution starts at level 0 (interpreter), then the policy can decide either to compile the
- * method at level 3 or level 2. The decision is based on the following factors:
- * 1. The length of the C2 queue determines the next level. The observation is that level 2
- * is generally faster than level 3 by about 30%, therefore we would want to minimize the time
- * a method spends at level 3. We should only spend the time at level 3 that is necessary to get
- * adequate profiling. So, if the C2 queue is long enough it is more beneficial to go first to
- * level 2, because if we transitioned to level 3 we would be stuck there until our C2 compile
- * request makes its way through the long queue. When the load on C2 recedes we are going to
- * recompile at level 3 and start gathering profiling information.
- * 2. The length of C1 queue is used to dynamically adjust the thresholds, so as to introduce
- * additional filtering if the compiler is overloaded. The rationale is that by the time a
- * method gets compiled it can become unused, so it doesn't make sense to put too much onto the
- * queue.
- *
- * After profiling is completed at level 3 the transition is made to level 4. Again, the length
- * of the C2 queue is used as a feedback to adjust the thresholds.
- *
- * After the first C1 compile some basic information is determined about the code like the number
- * of the blocks and the number of the loops. Based on that it can be decided that a method
- * is trivial and compiling it with C1 will yield the same code. In this case the method is
- * compiled at level 1 instead of 4.
- *
- * We also support profiling at level 0. If C1 is slow enough to produce the level 3 version of
- * the code and the C2 queue is sufficiently small we can decide to start profiling in the
- * interpreter (and continue profiling in the compiled code once the level 3 version arrives).
- * If the profiling at level 0 is fully completed before level 3 version is produced, a level 2
- * version is compiled instead in order to run faster waiting for a level 4 version.
- *
- * Compile queues are implemented as priority queues - for each method in the queue we compute
- * the event rate (the number of invocation and backedge counter increments per unit of time).
- * When getting an element off the queue we pick the one with the largest rate. Maintaining the
- * rate also allows us to remove stale methods (the ones that got on the queue but stopped
- * being used shortly after that).
-*/
-
-/* Command line options:
- * - Tier?InvokeNotifyFreqLog and Tier?BackedgeNotifyFreqLog control the frequency of method
- * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread
- * makes a call into the runtime.
- *
- * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control
- * compilation thresholds.
- * Level 2 thresholds are not used and are provided for option-compatibility and potential future use.
- * Other thresholds work as follows:
- *
- * Transition from interpreter (level 0) to C1 with full profiling (level 3) happens when
- * the following predicate is true (X is the level):
- *
- * i > TierXInvocationThreshold * s || (i > TierXMinInvocationThreshold * s && i + b > TierXCompileThreshold * s),
- *
- * where $i$ is the number of method invocations, $b$ number of backedges and $s$ is the scaling
- * coefficient that will be discussed further.
- * The intuition is to equalize the time that is spend profiling each method.
- * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be
- * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come
- * from Method* and for 3->4 transition they come from MDO (since profiled invocations are
- * counted separately). Finally, if a method does not contain anything worth profiling, a transition
- * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than
- * what is specified by Tier4InvocationThreshold).
- *
- * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates.
- *
- * - Tier?LoadFeedback options are used to automatically scale the predicates described above depending
- * on the compiler load. The scaling coefficients are computed as follows:
- *
- * s = queue_size_X / (TierXLoadFeedback * compiler_count_X) + 1,
- *
- * where queue_size_X is the current size of the compiler queue of level X, and compiler_count_X
- * is the number of level X compiler threads.
- *
- * Basically these parameters describe how many methods should be in the compile queue
- * per compiler thread before the scaling coefficient increases by one.
- *
- * This feedback provides the mechanism to automatically control the flow of compilation requests
- * depending on the machine speed, mutator load and other external factors.
- *
- * - Tier3DelayOn and Tier3DelayOff parameters control another important feedback loop.
- * Consider the following observation: a method compiled with full profiling (level 3)
- * is about 30% slower than a method at level 2 (just invocation and backedge counters, no MDO).
- * Normally, the following transitions will occur: 0->3->4. The problem arises when the C2 queue
- * gets congested and the 3->4 transition is delayed. While the method is the C2 queue it continues
- * executing at level 3 for much longer time than is required by the predicate and at suboptimal speed.
- * The idea is to dynamically change the behavior of the system in such a way that if a substantial
- * load on C2 is detected we would first do the 0->2 transition allowing a method to run faster.
- * And then when the load decreases to allow 2->3 transitions.
- *
- * Tier3Delay* parameters control this switching mechanism.
- * Tier3DelayOn is the number of methods in the C2 queue per compiler thread after which the policy
- * no longer does 0->3 transitions but does 0->2 transitions instead.
- * Tier3DelayOff switches the original behavior back when the number of methods in the C2 queue
- * per compiler thread falls below the specified amount.
- * The hysteresis is necessary to avoid jitter.
- *
- * - TieredCompileTaskTimeout is the amount of time an idle method can spend in the compile queue.
- * Basically, since we use the event rate d(i + b)/dt as a value of priority when selecting a method to
- * compile from the compile queue, we also can detect stale methods for which the rate has been
- * 0 for some time in the same iteration. Stale methods can appear in the queue when an application
- * abruptly changes its behavior.
- *
- * - TieredStopAtLevel, is used mostly for testing. It allows to bypass the policy logic and stick
- * to a given level. For example it's useful to set TieredStopAtLevel = 1 in order to compile everything
- * with pure c1.
- *
- * - Tier0ProfilingStartPercentage allows the interpreter to start profiling when the inequalities in the
- * 0->3 predicate are already exceeded by the given percentage but the level 3 version of the
- * method is still not ready. We can even go directly from level 0 to 4 if c1 doesn't produce a compiled
- * version in time. This reduces the overall transition to level 4 and decreases the startup time.
- * Note that this behavior is also guarded by the Tier3Delay mechanism: when the c2 queue is too long
- * these is not reason to start profiling prematurely.
- *
- * - TieredRateUpdateMinTime and TieredRateUpdateMaxTime are parameters of the rate computation.
- * Basically, the rate is not computed more frequently than TieredRateUpdateMinTime and is considered
- * to be zero if no events occurred in TieredRateUpdateMaxTime.
- */
-
-class TieredThresholdPolicy : public CompilationPolicy {
- jlong _start_time;
- int _c1_count, _c2_count;
-
- // Check if the counter is big enough and set carry (effectively infinity).
- inline void set_carry_if_necessary(InvocationCounter *counter);
- // Set carry flags in the counters (in Method* and MDO).
- inline void handle_counter_overflow(Method* method);
- // Call and loop predicates determine whether a transition to a higher compilation
- // level should be performed (pointers to predicate functions are passed to common_TF().
- // Predicates also take compiler load into account.
- typedef bool (TieredThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method);
- bool call_predicate(int i, int b, CompLevel cur_level, Method* method);
- bool loop_predicate(int i, int b, CompLevel cur_level, Method* method);
- // Common transition function. Given a predicate determines if a method should transition to another level.
- CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false);
- // Transition functions.
- // call_event determines if a method should be compiled at a different
- // level with a regular invocation entry.
- CompLevel call_event(Method* method, CompLevel cur_level, JavaThread* thread);
- // loop_event checks if a method should be OSR compiled at a different
- // level.
- CompLevel loop_event(Method* method, CompLevel cur_level, JavaThread* thread);
- void print_counters(const char* prefix, const methodHandle& mh);
- // Has a method been long around?
- // We don't remove old methods from the compile queue even if they have
- // very low activity (see select_task()).
- inline bool is_old(Method* method);
- // Was a given method inactive for a given number of milliseconds.
- // If it is, we would remove it from the queue (see select_task()).
- inline bool is_stale(jlong t, jlong timeout, Method* m);
- // Compute the weight of the method for the compilation scheduling
- inline double weight(Method* method);
- // Apply heuristics and return true if x should be compiled before y
- inline bool compare_methods(Method* x, Method* y);
- // Compute event rate for a given method. The rate is the number of event (invocations + backedges)
- // per millisecond.
- inline void update_rate(jlong t, Method* m);
- // Compute threshold scaling coefficient
- inline double threshold_scale(CompLevel level, int feedback_k);
- // If a method is old enough and is still in the interpreter we would want to
- // start profiling without waiting for the compiled method to arrive. This function
- // determines whether we should do that.
- inline bool should_create_mdo(Method* method, CompLevel cur_level);
- // Create MDO if necessary.
- void create_mdo(const methodHandle& mh, JavaThread* thread);
- // Is method profiled enough?
- bool is_method_profiled(Method* method);
-
- double _increase_threshold_at_ratio;
-
- bool maybe_switch_to_aot(const methodHandle& mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread);
-
- int c1_count() const { return _c1_count; }
- int c2_count() const { return _c2_count; }
- void set_c1_count(int x) { _c1_count = x; }
- void set_c2_count(int x) { _c2_count = x; }
-
- enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT };
- void print_event(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level);
- // Print policy-specific information if necessary
- void print_specific(EventType type, const methodHandle& mh, const methodHandle& imh, int bci, CompLevel level);
- // Check if the method can be compiled, change level if necessary
- void compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread);
- // Submit a given method for compilation
- void submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread);
- // Simple methods are as good being compiled with C1 as C2.
- // This function tells if it's such a function.
- inline static bool is_trivial(Method* method);
- // Force method to be compiled at CompLevel_simple?
- inline static bool should_compile_at_level_simple(Method* method);
-
- // Predicate helpers are used by .*_predicate() methods as well as others.
- // They check the given counter values, multiplied by the scale against the thresholds.
- template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale, Method* method);
- template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale, Method* method);
-
- // Get a compilation level for a given method.
- static CompLevel comp_level(Method* method);
- void method_invocation_event(const methodHandle& method, const methodHandle& inlinee,
- CompLevel level, CompiledMethod* nm, JavaThread* thread);
- void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee,
- int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread);
-
- void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); }
- void set_start_time(jlong t) { _start_time = t; }
- jlong start_time() const { return _start_time; }
-
-public:
- TieredThresholdPolicy() : _start_time(0), _c1_count(0), _c2_count(0) { }
- virtual int compiler_count(CompLevel comp_level) {
- if (is_c1_compile(comp_level)) return c1_count();
- if (is_c2_compile(comp_level)) return c2_count();
- return 0;
- }
- virtual CompLevel initial_compile_level() { return MIN2((CompLevel)TieredStopAtLevel, CompLevel_initial_compile); }
- virtual void do_safepoint_work() { }
- virtual void delay_compilation(Method* method) { }
- virtual void disable_compilation(Method* method) { }
- virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
- virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee,
- int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
- // Select task is called by CompileBroker. We should return a task or NULL.
- virtual CompileTask* select_task(CompileQueue* compile_queue);
- // Tell the runtime if we think a given method is adequately profiled.
- virtual bool is_mature(Method* method);
- // Initialize: set compiler thread count
- virtual void initialize();
- virtual bool should_not_inline(ciEnv* env, ciMethod* callee);
-};
-
-#endif // TIERED
-
-#endif // SHARE_RUNTIME_TIEREDTHRESHOLDPOLICY_HPP