This is the code that updates the compiler thread count:
static bool can_remove(CompilerThread *ct, bool do_it) {
assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
if (!ReduceNumberOfCompilerThreads) return false;
AbstractCompiler *compiler = ct->compiler();
int compiler_count = compiler->num_compiler_threads();
bool c1 = compiler->is_c1();
// Keep at least 1 compiler thread of each type.
if (compiler_count < 2) return false;
// Keep thread alive for at least some time.
if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false;
// We only allow the last compiler thread of each type to get removed.
jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
: CompileBroker::compiler2_object(compiler_count - 1);
if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) {
if (do_it) {
assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
compiler->set_num_compiler_threads(compiler_count - 1);
}
return true;
}
return false;
}
We read the count initially with no lock held:
int compiler_count = compiler->num_compiler_threads();
we then later update the count with the lock held:
assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
compiler->set_num_compiler_threads(compiler_count - 1);
but by this time the local variable "compiler_count" may not contain the current number of compiler threads and so we will set the wrong value. Further the count may also have changed when we use it here:
jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
: CompileBroker::compiler2_object(compiler_count - 1);
In addition there is logic to try and ensure we always keep at least one compiler thread but this seems to be executed with no locking so multiple threads can execute:
if (compiler_count < 2) return false;
and all see a count >=2 but then all continue to exit thus leaving zero compiler threads running.
static bool can_remove(CompilerThread *ct, bool do_it) {
assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
if (!ReduceNumberOfCompilerThreads) return false;
AbstractCompiler *compiler = ct->compiler();
int compiler_count = compiler->num_compiler_threads();
bool c1 = compiler->is_c1();
// Keep at least 1 compiler thread of each type.
if (compiler_count < 2) return false;
// Keep thread alive for at least some time.
if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false;
// We only allow the last compiler thread of each type to get removed.
jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
: CompileBroker::compiler2_object(compiler_count - 1);
if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) {
if (do_it) {
assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
compiler->set_num_compiler_threads(compiler_count - 1);
}
return true;
}
return false;
}
We read the count initially with no lock held:
int compiler_count = compiler->num_compiler_threads();
we then later update the count with the lock held:
assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
compiler->set_num_compiler_threads(compiler_count - 1);
but by this time the local variable "compiler_count" may not contain the current number of compiler threads and so we will set the wrong value. Further the count may also have changed when we use it here:
jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
: CompileBroker::compiler2_object(compiler_count - 1);
In addition there is logic to try and ensure we always keep at least one compiler thread but this seems to be executed with no locking so multiple threads can execute:
if (compiler_count < 2) return false;
and all see a count >=2 but then all continue to exit thus leaving zero compiler threads running.
- relates to
-
JDK-8198756 Lazy allocation of compiler threads
- Resolved