6953144: Tiered compilation

Infrastructure for tiered compilation support (interpreter + c1 + c2) for 32 and 64 bit. Simple tiered policy implementation.

Reviewed-by: kvn, never, phh, twisti
This commit is contained in:
Igor Veresov 2010-09-03 17:51:07 -07:00
parent 6e78f6cb4b
commit 2c66a6c3fd
104 changed files with 7720 additions and 1701 deletions

View file

@ -123,20 +123,12 @@ int CompileBroker::_sum_standard_bytes_compiled = 0;
int CompileBroker::_sum_nmethod_size = 0;
int CompileBroker::_sum_nmethod_code_size = 0;
CompileQueue* CompileBroker::_method_queue = NULL;
CompileQueue* CompileBroker::_c2_method_queue = NULL;
CompileQueue* CompileBroker::_c1_method_queue = NULL;
CompileTask* CompileBroker::_task_free_list = NULL;
GrowableArray<CompilerThread*>* CompileBroker::_method_threads = NULL;
// CompileTaskWrapper
//
// Assign this task to the current thread. Deallocate the task
// when the compilation is complete.
class CompileTaskWrapper : StackObj {
public:
CompileTaskWrapper(CompileTask* task);
~CompileTaskWrapper();
};
CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
CompilerThread* thread = CompilerThread::current();
@ -246,6 +238,12 @@ void CompileTask::print() {
bool_to_str(_is_complete), bool_to_str(_is_success));
}
void CompileTask::print_compilation(outputStream *st, methodOop method, char* method_name) {
nmethod::print_compilation(st, method_name,/*title*/ NULL, method,
is_blocking(), compile_id(), osr_bci(), comp_level());
}
// ------------------------------------------------------------------
// CompileTask::print_line_on_error
//
@ -258,32 +256,13 @@ void CompileTask::print() {
//
void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
methodOop method = (methodOop)JNIHandles::resolve(_method);
// print compiler name
st->print("%s:", CompileBroker::compiler(comp_level())->name());
// print compilation number
st->print("%3d", compile_id());
// print method attributes
const bool is_osr = osr_bci() != CompileBroker::standard_entry_bci;
{ const char blocking_char = is_blocking() ? 'b' : ' ';
const char compile_type = is_osr ? '%' : ' ';
const char sync_char = method->is_synchronized() ? 's' : ' ';
const char exception_char = method->has_exception_handler() ? '!' : ' ';
const char tier_char =
is_highest_tier_compile(comp_level()) ? ' ' : ('0' + comp_level());
st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, tier_char);
char* method_name = NULL;
if (method != NULL) {
method_name = method->name_and_sig_as_C_string(buf, buflen);
}
// Use buf to get method name and signature
if (method != NULL) st->print("%s", method->name_and_sig_as_C_string(buf, buflen));
// print osr_bci if any
if (is_osr) st->print(" @ %d", osr_bci());
// print method size
st->print_cr(" (%d bytes)", method->code_size());
print_compilation(st, method, method_name);
}
// ------------------------------------------------------------------
@ -298,29 +277,7 @@ void CompileTask::print_line() {
// print compiler name if requested
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler(comp_level())->name());
// print compilation number
tty->print("%3d", compile_id());
// print method attributes
const bool is_osr = osr_bci() != CompileBroker::standard_entry_bci;
{ const char blocking_char = is_blocking() ? 'b' : ' ';
const char compile_type = is_osr ? '%' : ' ';
const char sync_char = method->is_synchronized() ? 's' : ' ';
const char exception_char = method->has_exception_handler() ? '!' : ' ';
const char tier_char =
is_highest_tier_compile(comp_level()) ? ' ' : ('0' + comp_level());
tty->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, tier_char);
}
// print method name
method->print_short_name(tty);
// print osr_bci if any
if (is_osr) tty->print(" @ %d", osr_bci());
// print method size
tty->print_cr(" (%d bytes)", method->code_size());
print_compilation(tty, method(), NULL);
}
@ -427,6 +384,7 @@ void CompileQueue::add(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
task->set_next(NULL);
task->set_prev(NULL);
if (_last == NULL) {
// The compile queue is empty.
@ -437,8 +395,10 @@ void CompileQueue::add(CompileTask* task) {
// Append the task to the queue.
assert(_last->next() == NULL, "not last");
_last->set_next(task);
task->set_prev(_last);
_last = task;
}
++_size;
// Mark the method as being in the compile queue.
((methodOop)JNIHandles::resolve(task->method_handle()))->set_queued_for_compilation();
@ -452,10 +412,9 @@ void CompileQueue::add(CompileTask* task) {
}
// Notify CompilerThreads that a task is available.
lock()->notify();
lock()->notify_all();
}
// ------------------------------------------------------------------
// CompileQueue::get
//
@ -464,7 +423,6 @@ CompileTask* CompileQueue::get() {
NMethodSweeper::possibly_sweep();
MutexLocker locker(lock());
// Wait for an available CompileTask.
while (_first == NULL) {
// There is no work to be done right now. Wait.
@ -481,19 +439,31 @@ CompileTask* CompileQueue::get() {
lock()->wait();
}
}
CompileTask* task = _first;
// Update queue first and last
_first =_first->next();
if (_first == NULL) {
_last = NULL;
}
CompileTask* task = CompilationPolicy::policy()->select_task(this);
remove(task);
return task;
}
void CompileQueue::remove(CompileTask* task)
{
assert(lock()->owned_by_self(), "must own lock");
if (task->prev() != NULL) {
task->prev()->set_next(task->next());
} else {
// max is the first element
assert(task == _first, "Sanity");
_first = task->next();
}
if (task->next() != NULL) {
task->next()->set_prev(task->prev());
} else {
// max is the last element
assert(task == _last, "Sanity");
_last = task->prev();
}
--_size;
}
// ------------------------------------------------------------------
// CompileQueue::print
@ -545,7 +515,6 @@ CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS)
}
}
// ------------------------------------------------------------------
// CompileBroker::compilation_init
//
@ -554,18 +523,18 @@ void CompileBroker::compilation_init() {
_last_method_compiled[0] = '\0';
// Set the interface to the current compiler(s).
int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
#ifdef COMPILER1
_compilers[0] = new Compiler();
#ifndef COMPILER2
_compilers[1] = _compilers[0];
#endif
if (c1_count > 0) {
_compilers[0] = new Compiler();
}
#endif // COMPILER1
#ifdef COMPILER2
_compilers[1] = new C2Compiler();
#ifndef COMPILER1
_compilers[0] = _compilers[1];
#endif
if (c2_count > 0) {
_compilers[1] = new C2Compiler();
}
#endif // COMPILER2
#ifdef SHARK
@ -580,9 +549,7 @@ void CompileBroker::compilation_init() {
_task_free_list = NULL;
// Start the CompilerThreads
init_compiler_threads(compiler_count());
init_compiler_threads(c1_count, c2_count);
// totalTime performance counter is always created as it is required
// by the implementation of java.lang.management.CompilationMBean.
{
@ -770,23 +737,38 @@ CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQue
// CompileBroker::init_compiler_threads
//
// Initialize the compilation queue
void CompileBroker::init_compiler_threads(int compiler_count) {
void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) {
EXCEPTION_MARK;
assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?");
if (c2_compiler_count > 0) {
_c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock);
}
if (c1_compiler_count > 0) {
_c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock);
}
int compiler_count = c1_compiler_count + c2_compiler_count;
_method_queue = new CompileQueue("MethodQueue", MethodCompileQueue_lock);
_method_threads =
new (ResourceObj::C_HEAP) GrowableArray<CompilerThread*>(compiler_count, true);
char name_buffer[256];
int i;
for (i = 0; i < compiler_count; i++) {
for (int i = 0; i < c2_compiler_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "CompilerThread%d", i);
sprintf(name_buffer, "C2 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _method_queue, counters, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, CHECK);
_method_threads->append(new_thread);
}
for (int i = c2_compiler_count; i < compiler_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "C1 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, CHECK);
_method_threads->append(new_thread);
}
if (UsePerfData) {
PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes,
compiler_count, CHECK);
@ -796,7 +778,9 @@ void CompileBroker::init_compiler_threads(int compiler_count) {
// ------------------------------------------------------------------
// CompileBroker::is_idle
bool CompileBroker::is_idle() {
if (!_method_queue->is_empty()) {
if (_c2_method_queue != NULL && !_c2_method_queue->is_empty()) {
return false;
} else if (_c1_method_queue != NULL && !_c1_method_queue->is_empty()) {
return false;
} else {
int num_threads = _method_threads->length();
@ -859,6 +843,7 @@ void CompileBroker::compile_method_base(methodHandle method,
return;
}
// If this method is already in the compile queue, then
// we do not block the current thread.
if (compilation_is_in_queue(method, osr_bci)) {
@ -876,10 +861,11 @@ void CompileBroker::compile_method_base(methodHandle method,
// Outputs from the following MutexLocker block:
CompileTask* task = NULL;
bool blocking = false;
CompileQueue* queue = compile_queue(comp_level);
// Acquire our lock.
{
MutexLocker locker(_method_queue->lock(), THREAD);
MutexLocker locker(queue->lock(), THREAD);
// Make sure the method has not slipped into the queues since
// last we checked; note that those checks were "fast bail-outs".
@ -945,7 +931,7 @@ void CompileBroker::compile_method_base(methodHandle method,
// and in that case it's best to protect both the testing (here) of
// these bits, and their updating (here and elsewhere) under a
// common lock.
task = create_compile_task(_method_queue,
task = create_compile_task(queue,
compile_id, method,
osr_bci, comp_level,
hot_method, hot_count, comment,
@ -959,6 +945,7 @@ void CompileBroker::compile_method_base(methodHandle method,
nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
int comp_level,
methodHandle hot_method, int hot_count,
const char* comment, TRAPS) {
// make sure arguments make sense
@ -967,26 +954,9 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods");
assert(!instanceKlass::cast(method->method_holder())->is_not_initialized(), "method holder must be initialized");
int comp_level = CompilationPolicy::policy()->compilation_level(method, osr_bci);
#ifdef TIERED
if (TieredCompilation && StressTieredRuntime) {
static int flipper = 0;
if (is_even(flipper++)) {
comp_level = CompLevel_fast_compile;
} else {
comp_level = CompLevel_full_optimization;
}
if (!TieredCompilation) {
comp_level = CompLevel_highest_tier;
}
#ifdef SPARC
// QQQ FIX ME
// C2 only returns long results in G1 and c1 doesn't understand so disallow c2
// compiles of long results
if (TieredCompilation && method()->result_type() == T_LONG) {
comp_level = CompLevel_fast_compile;
}
#endif // SPARC
#endif // TIERED
// return quickly if possible
@ -1000,12 +970,10 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
if (osr_bci == InvocationEntryBci) {
// standard compilation
nmethod* method_code = method->code();
if (method_code != NULL
#ifdef TIERED
&& ( method_code->is_compiled_by_c2() || comp_level == CompLevel_fast_compile )
#endif // TIERED
) {
return method_code;
if (method_code != NULL) {
if (compilation_is_complete(method, osr_bci, comp_level)) {
return method_code;
}
}
if (method->is_not_compilable(comp_level)) return NULL;
@ -1021,10 +989,11 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
// osr compilation
#ifndef TIERED
// seems like an assert of dubious value
assert(comp_level == CompLevel_full_optimization,
assert(comp_level == CompLevel_highest_tier,
"all OSR compiles are assumed to be at a single compilation lavel");
#endif // TIERED
nmethod* nm = method->lookup_osr_nmethod_for(osr_bci);
// We accept a higher level osr method
nmethod* nm = method->lookup_osr_nmethod_for(osr_bci, comp_level, false);
if (nm != NULL) return nm;
if (method->is_not_osr_compilable()) return NULL;
}
@ -1071,8 +1040,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
// If the compiler is shut off due to code cache flushing or otherwise,
// fail out now so blocking compiles dont hang the java thread
if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) {
method->invocation_counter()->decay();
method->backedge_counter()->decay();
CompilationPolicy::policy()->delay_compilation(method());
return NULL;
}
@ -1088,7 +1056,8 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
}
// return requested nmethod
return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci);
// We accept a higher level osr method
return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false);
}
@ -1104,7 +1073,7 @@ bool CompileBroker::compilation_is_complete(methodHandle method,
if (method->is_not_osr_compilable()) {
return true;
} else {
nmethod* result = method->lookup_osr_nmethod_for(osr_bci);
nmethod* result = method->lookup_osr_nmethod_for(osr_bci, comp_level, true);
return (result != NULL);
}
} else {
@ -1113,15 +1082,7 @@ bool CompileBroker::compilation_is_complete(methodHandle method,
} else {
nmethod* result = method->code();
if (result == NULL) return false;
#ifdef TIERED
if (comp_level == CompLevel_fast_compile) {
// At worst the code is from c1
return true;
}
// comp level must be full opt
return result->is_compiled_by_c2();
#endif // TIERED
return true;
return comp_level == result->comp_level();
}
}
}
@ -1139,11 +1100,10 @@ bool CompileBroker::compilation_is_complete(methodHandle method,
// versa). This can be remedied by a full queue search to disambiguate
// cases. If it is deemed profitible, this may be done.
bool CompileBroker::compilation_is_in_queue(methodHandle method,
int osr_bci) {
int osr_bci) {
return method->queued_for_compilation();
}
// ------------------------------------------------------------------
// CompileBroker::compilation_is_prohibited
//
@ -1151,11 +1111,9 @@ bool CompileBroker::compilation_is_in_queue(methodHandle method,
bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level) {
bool is_native = method->is_native();
// Some compilers may not support the compilation of natives.
// QQQ this needs some work ought to only record not compilable at
// the specified level
if (is_native &&
(!CICompileNatives || !compiler(comp_level)->supports_native())) {
method->set_not_compilable_quietly();
method->set_not_compilable_quietly(comp_level);
return true;
}
@ -1194,7 +1152,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
// compilations may be numbered separately from regular compilations
// if certain debugging flags are used.
uint CompileBroker::assign_compile_id(methodHandle method, int osr_bci) {
assert(_method_queue->lock()->owner() == JavaThread::current(),
assert(MethodCompileQueue_lock->owner() == Thread::current(),
"must hold the compilation queue lock");
bool is_osr = (osr_bci != standard_entry_bci);
assert(!method->is_native(), "no longer compile natives");
@ -1643,7 +1601,6 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
#endif
}
// ------------------------------------------------------------------
// CompileBroker::handle_full_code_cache
//
@ -1883,12 +1840,12 @@ void CompileBroker::print_times() {
CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count);
tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count);
if (compiler(CompLevel_fast_compile)) {
compiler(CompLevel_fast_compile)->print_timers();
if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier))
compiler(CompLevel_highest_tier)->print_timers();
if (compiler(CompLevel_simple) != NULL) {
compiler(CompLevel_simple)->print_timers();
}
if (compiler(CompLevel_full_optimization) != NULL) {
compiler(CompLevel_full_optimization)->print_timers();
}
tty->cr();
int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled;
tty->print_cr(" Total compiled bytecodes : %6d bytes", tcb);