Mercurial > hg > graal-jvmci-8
view src/share/vm/runtime/compilationPolicy.cpp @ 94:0834225a7916
6634032: CMS: Need CMSInitiatingPermOccupancyFraction for perm, divorcing from CMSInitiatingOccupancyFraction
Summary: The option CMSInitiatingPermOccupancyFraction now controls perm triggering threshold. Even though the actual value of the threshold has not yet been changed, so there is no change in policy, we now have the infrastructure in place for dynamically deciding when to collect the perm gen, an issue that will be addressed in the near future.
Reviewed-by: jmasa
author | ysr |
---|---|
date | Sun, 16 Mar 2008 21:57:25 -0700 |
parents | a61af66fc99e |
children | ddb7834449d0 |
line wrap: on
line source
/* * Copyright 2000-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ # include "incls/_precompiled.incl" # include "incls/_compilationPolicy.cpp.incl" CompilationPolicy* CompilationPolicy::_policy; elapsedTimer CompilationPolicy::_accumulated_time; bool CompilationPolicy::_in_vm_startup; // Determine compilation policy based on command line argument void compilationPolicy_init() { CompilationPolicy::set_in_vm_startup(DelayCompilationDuringStartup); switch(CompilationPolicyChoice) { case 0: CompilationPolicy::set_policy(new SimpleCompPolicy()); break; case 1: #ifdef COMPILER2 CompilationPolicy::set_policy(new StackWalkCompPolicy()); #else Unimplemented(); #endif break; default: fatal("CompilationPolicyChoice must be in the range: [0-1]"); } } void CompilationPolicy::completed_vm_startup() { if (TraceCompilationPolicy) { tty->print("CompilationPolicy: completed vm startup.\n"); } _in_vm_startup = false; } // 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::mustBeCompiled(methodHandle m) { if (m->has_compiled_code()) return false; // already compiled if (!canBeCompiled(m)) return false; return !UseInterpreter || // must compile all methods (UseCompiler && AlwaysCompileLoopMethods && m->has_loops()); // eagerly compile loop methods } // Returns true if m is allowed to be compiled bool CompilationPolicy::canBeCompiled(methodHandle m) { if (m->is_abstract()) return false; if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; return !m->is_not_compilable(); } #ifndef PRODUCT void CompilationPolicy::print_time() { tty->print_cr ("Accumulated compilationPolicy times:"); tty->print_cr ("---------------------------"); tty->print_cr (" Total: %3.3f sec.", _accumulated_time.seconds()); } static void trace_osr_completion(nmethod* osr_nm) { if (TraceOnStackReplacement) { if (osr_nm == NULL) tty->print_cr("compilation failed"); else tty->print_cr("nmethod " INTPTR_FORMAT, osr_nm); } } #endif // !PRODUCT void CompilationPolicy::reset_counter_for_invocation_event(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). m->invocation_counter()->set_carry(); m->backedge_counter()->set_carry(); assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed"); } void CompilationPolicy::reset_counter_for_back_branch_event(methodHandle m) { // Delay next back-branch event but pump up invocation counter to triger // whole method compilation. InvocationCounter* i = m->invocation_counter(); InvocationCounter* b = m->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); } // SimpleCompPolicy - compile current method void SimpleCompPolicy::method_invocation_event( methodHandle m, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->invocation_count(); reset_counter_for_invocation_event(m); const char* comment = "count"; if (!delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler) { nmethod* nm = m->code(); if (nm == NULL ) { const char* comment = "count"; CompileBroker::compile_method(m, InvocationEntryBci, m, hot_count, comment, CHECK); } else { #ifdef TIERED if (nm->is_compiled_by_c1()) { const char* comment = "tier1 overflow"; CompileBroker::compile_method(m, InvocationEntryBci, m, hot_count, comment, CHECK); } #endif // TIERED } } } void SimpleCompPolicy::method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->backedge_count(); const char* comment = "backedge_count"; if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m)) { CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));) } } int SimpleCompPolicy::compilation_level(methodHandle m, int branch_bci) { #ifdef TIERED if (!TieredCompilation) { return CompLevel_highest_tier; } if (/* m()->tier1_compile_done() && */ // QQQ HACK FIX ME set tier1_compile_done!! !m()->is_native()) { // Grab the nmethod so it doesn't go away while it's being queried nmethod* code = m()->code(); if (code != NULL && code->is_compiled_by_c1()) { return CompLevel_highest_tier; } } return CompLevel_fast_compile; #else return CompLevel_highest_tier; #endif // TIERED } // StackWalkCompPolicy - walk up stack to find a suitable method to compile #ifdef COMPILER2 const char* StackWalkCompPolicy::_msg = NULL; // Consider m for compilation void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->invocation_count(); reset_counter_for_invocation_event(m); const char* comment = "count"; if (m->code() == NULL && !delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler) { ResourceMark rm(THREAD); JavaThread *thread = (JavaThread*)THREAD; frame fr = thread->last_frame(); assert(fr.is_interpreted_frame(), "must be interpreted"); assert(fr.interpreter_frame_method() == m(), "bad method"); if (TraceCompilationPolicy) { tty->print("method invocation trigger: "); m->print_short_name(tty); tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", (address)m(), m->code_size()); } RegisterMap reg_map(thread, false); javaVFrame* triggerVF = thread->last_java_vframe(®_map); // triggerVF is the frame that triggered its counter RFrame* first = new InterpretedRFrame(triggerVF->fr(), thread, m); if (first->top_method()->code() != NULL) { // called obsolete method/nmethod -- no need to recompile if (TraceCompilationPolicy) tty->print_cr(" --> " INTPTR_FORMAT, first->top_method()->code()); } else if (compilation_level(m, InvocationEntryBci) == CompLevel_fast_compile) { // Tier1 compilation policy avaoids stack walking. CompileBroker::compile_method(m, InvocationEntryBci, m, hot_count, comment, CHECK); } else { if (TimeCompilationPolicy) accumulated_time()->start(); GrowableArray<RFrame*>* stack = new GrowableArray<RFrame*>(50); stack->push(first); RFrame* top = findTopInlinableFrame(stack); if (TimeCompilationPolicy) accumulated_time()->stop(); assert(top != NULL, "findTopInlinableFrame returned null"); if (TraceCompilationPolicy) top->print(); CompileBroker::compile_method(top->top_method(), InvocationEntryBci, m, hot_count, comment, CHECK); } } } void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int branch_bci, int loop_top_bci, TRAPS) { assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); int hot_count = m->backedge_count(); const char* comment = "backedge_count"; if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m)) { CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));) } } int StackWalkCompPolicy::compilation_level(methodHandle m, int osr_bci) { int comp_level = CompLevel_full_optimization; if (TieredCompilation && osr_bci == InvocationEntryBci) { if (CompileTheWorld) { // Under CTW, the first compile is tier1, the second tier2 if (m->highest_tier_compile() == CompLevel_none) { comp_level = CompLevel_fast_compile; } } else if (!m->has_osr_nmethod()) { // Before tier1 is done, use invocation_count + backedge_count to // compare against the threshold. After that, the counters may/will // be reset, so rely on the straight interpreter_invocation_count. if (m->highest_tier_compile() == CompLevel_initial_compile) { if (m->interpreter_invocation_count() < Tier2CompileThreshold) { comp_level = CompLevel_fast_compile; } } else if (m->invocation_count() + m->backedge_count() < Tier2CompileThreshold) { comp_level = CompLevel_fast_compile; } } } return comp_level; } RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray<RFrame*>* stack) { // go up the stack until finding a frame that (probably) won't be inlined // into its caller RFrame* current = stack->at(0); // current choice for stopping assert( current && !current->is_compiled(), "" ); const char* msg = NULL; while (1) { // before going up the stack further, check if doing so would get us into // compiled code RFrame* next = senderOf(current, stack); if( !next ) // No next frame up the stack? break; // Then compile with current frame methodHandle m = current->top_method(); methodHandle next_m = next->top_method(); if (TraceCompilationPolicy && Verbose) { tty->print("[caller: "); next_m->print_short_name(tty); tty->print("] "); } if( !Inline ) { // Inlining turned off msg = "Inlining turned off"; break; } if (next_m->is_not_compilable()) { // Did fail to compile this before/ msg = "caller not compilable"; break; } if (next->num() > MaxRecompilationSearchLength) { // don't go up too high when searching for recompilees msg = "don't go up any further: > MaxRecompilationSearchLength"; break; } if (next->distance() > MaxInterpretedSearchLength) { // don't go up too high when searching for recompilees msg = "don't go up any further: next > MaxInterpretedSearchLength"; break; } // Compiled frame above already decided not to inline; // do not recompile him. if (next->is_compiled()) { msg = "not going up into optimized code"; break; } // Interpreted frame above us was already compiled. Do not force // a recompile, although if the frame above us runs long enough an // OSR might still happen. if( current->is_interpreted() && next_m->has_compiled_code() ) { msg = "not going up -- already compiled caller"; break; } // Compute how frequent this call site is. We have current method 'm'. // We know next method 'next_m' is interpreted. Find the call site and // check the various invocation counts. int invcnt = 0; // Caller counts if (ProfileInterpreter) { invcnt = next_m->interpreter_invocation_count(); } int cnt = 0; // Call site counts if (ProfileInterpreter && next_m->method_data() != NULL) { ResourceMark rm; int bci = next->top_vframe()->bci(); ProfileData* data = next_m->method_data()->bci_to_data(bci); if (data != NULL && data->is_CounterData()) cnt = data->as_CounterData()->count(); } // Caller counts / call-site counts; i.e. is this call site // a hot call site for method next_m? int freq = (invcnt) ? cnt/invcnt : cnt; // Check size and frequency limits if ((msg = shouldInline(m, freq, cnt)) != NULL) { break; } // Check inlining negative tests if ((msg = shouldNotInline(m)) != NULL) { break; } // If the caller method is too big or something then we do not want to // compile it just to inline a method if (!canBeCompiled(next_m)) { msg = "caller cannot be compiled"; break; } if( next_m->name() == vmSymbols::class_initializer_name() ) { msg = "do not compile class initializer (OSR ok)"; break; } if (TraceCompilationPolicy && Verbose) { tty->print("\n\t check caller: "); next_m->print_short_name(tty); tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", (address)next_m(), next_m->code_size()); } current = next; } assert( !current || !current->is_compiled(), "" ); if (TraceCompilationPolicy && msg) tty->print("(%s)\n", msg); return current; } RFrame* StackWalkCompPolicy::senderOf(RFrame* rf, GrowableArray<RFrame*>* stack) { RFrame* sender = rf->caller(); if (sender && sender->num() == stack->length()) stack->push(sender); return sender; } const char* StackWalkCompPolicy::shouldInline(methodHandle m, float freq, int cnt) { // Allows targeted inlining // positive filter: should send be inlined? returns NULL (--> yes) // or rejection msg int max_size = MaxInlineSize; int cost = m->code_size(); // Check for too many throws (and not too huge) if (m->interpreter_throwout_count() > InlineThrowCount && cost < InlineThrowMaxSize ) { return NULL; } // bump the max size if the call is frequent if ((freq >= InlineFrequencyRatio) || (cnt >= InlineFrequencyCount)) { if (TraceFrequencyInlining) { tty->print("(Inlined frequent method)\n"); m->print(); } max_size = FreqInlineSize; } if (cost > max_size) { return (_msg = "too big"); } return NULL; } const char* StackWalkCompPolicy::shouldNotInline(methodHandle m) { // negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg if (m->is_abstract()) return (_msg = "abstract method"); // note: we allow ik->is_abstract() if (!instanceKlass::cast(m->method_holder())->is_initialized()) return (_msg = "method holder not initialized"); if (m->is_native()) return (_msg = "native method"); nmethod* m_code = m->code(); if( m_code != NULL && m_code->instructions_size() > InlineSmallCode ) return (_msg = "already compiled into a big method"); // use frequency-based objections only for non-trivial methods if (m->code_size() <= MaxTrivialSize) return NULL; if (UseInterpreter) { // don't use counts with -Xcomp if ((m->code() == NULL) && m->was_never_executed()) return (_msg = "never executed"); if (!m->was_executed_more_than(MIN2(MinInliningThreshold, CompileThreshold >> 1))) return (_msg = "executed < MinInliningThreshold times"); } if (methodOopDesc::has_unloaded_classes_in_signature(m, JavaThread::current())) return (_msg = "unloaded signature classes"); return NULL; } #endif // COMPILER2