8023461: Thread holding lock at safepoint that vm can block on: MethodCompileQueue_lock

Reviewed-by: kvn, iveresov
This commit is contained in:
Vladimir Ivanov 2014-03-11 15:06:34 +04:00
parent 54db2c2d61
commit 38d80b03c4
5 changed files with 86 additions and 33 deletions

View file

@ -704,13 +704,39 @@ CompileTask* CompileQueue::get() {
return NULL; return NULL;
} }
CompileTask* task = CompilationPolicy::policy()->select_task(this); CompileTask* task;
{
No_Safepoint_Verifier nsv;
task = CompilationPolicy::policy()->select_task(this);
}
remove(task); remove(task);
purge_stale_tasks(); // may temporarily release MCQ lock
return task; return task;
} }
void CompileQueue::remove(CompileTask* task) // Clean & deallocate stale compile tasks.
{ // Temporarily releases MethodCompileQueue lock.
void CompileQueue::purge_stale_tasks() {
assert(lock()->owned_by_self(), "must own lock");
if (_first_stale != NULL) {
// Stale tasks are purged when MCQ lock is released,
// but _first_stale updates are protected by MCQ lock.
// Once task processing starts and MCQ lock is released,
// other compiler threads can reuse _first_stale.
CompileTask* head = _first_stale;
_first_stale = NULL;
{
MutexUnlocker ul(lock());
for (CompileTask* task = head; task != NULL; ) {
CompileTask* next_task = task->next();
CompileTaskWrapper ctw(task); // Frees the task
task = next_task;
}
}
}
}
void CompileQueue::remove(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock"); assert(lock()->owned_by_self(), "must own lock");
if (task->prev() != NULL) { if (task->prev() != NULL) {
task->prev()->set_next(task->next()); task->prev()->set_next(task->next());
@ -730,6 +756,16 @@ void CompileQueue::remove(CompileTask* task)
--_size; --_size;
} }
void CompileQueue::remove_and_mark_stale(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
remove(task);
// Enqueue the task for reclamation (should be done outside MCQ lock)
task->set_next(_first_stale);
task->set_prev(NULL);
_first_stale = task;
}
// methods in the compile queue need to be marked as used on the stack // methods in the compile queue need to be marked as used on the stack
// so that they don't get reclaimed by Redefine Classes // so that they don't get reclaimed by Redefine Classes
void CompileQueue::mark_on_stack() { void CompileQueue::mark_on_stack() {
@ -2006,7 +2042,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
// Note that the queued_for_compilation bits are cleared without // Note that the queued_for_compilation bits are cleared without
// protection of a mutex. [They were set by the requester thread, // protection of a mutex. [They were set by the requester thread,
// when adding the task to the complie queue -- at which time the // when adding the task to the compile queue -- at which time the
// compile queue lock was held. Subsequently, we acquired the compile // compile queue lock was held. Subsequently, we acquired the compile
// queue lock to get this task off the compile queue; thus (to belabour // queue lock to get this task off the compile queue; thus (to belabour
// the point somewhat) our clearing of the bits must be occurring // the point somewhat) our clearing of the bits must be occurring

View file

@ -196,7 +196,11 @@ class CompileQueue : public CHeapObj<mtCompiler> {
CompileTask* _first; CompileTask* _first;
CompileTask* _last; CompileTask* _last;
CompileTask* _first_stale;
int _size; int _size;
void purge_stale_tasks();
public: public:
CompileQueue(const char* name, Monitor* lock) { CompileQueue(const char* name, Monitor* lock) {
_name = name; _name = name;
@ -204,6 +208,7 @@ class CompileQueue : public CHeapObj<mtCompiler> {
_first = NULL; _first = NULL;
_last = NULL; _last = NULL;
_size = 0; _size = 0;
_first_stale = NULL;
} }
const char* name() const { return _name; } const char* name() const { return _name; }
@ -211,6 +216,7 @@ class CompileQueue : public CHeapObj<mtCompiler> {
void add(CompileTask* task); void add(CompileTask* task);
void remove(CompileTask* task); void remove(CompileTask* task);
void remove_and_mark_stale(CompileTask* task);
CompileTask* first() { return _first; } CompileTask* first() { return _first; }
CompileTask* last() { return _last; } CompileTask* last() { return _last; }
@ -219,6 +225,7 @@ class CompileQueue : public CHeapObj<mtCompiler> {
bool is_empty() const { return _first == NULL; } bool is_empty() const { return _first == NULL; }
int size() const { return _size; } int size() const { return _size; }
// Redefine Classes support // Redefine Classes support
void mark_on_stack(); void mark_on_stack();
void free_all(); void free_all();

View file

@ -200,10 +200,11 @@ class Method : public Metadata {
// Tracking number of breakpoints, for fullspeed debugging. // Tracking number of breakpoints, for fullspeed debugging.
// Only mutated by VM thread. // Only mutated by VM thread.
u2 number_of_breakpoints() const { u2 number_of_breakpoints() const {
if (method_counters() == NULL) { MethodCounters* mcs = method_counters();
if (mcs == NULL) {
return 0; return 0;
} else { } else {
return method_counters()->number_of_breakpoints(); return mcs->number_of_breakpoints();
} }
} }
void incr_number_of_breakpoints(TRAPS) { void incr_number_of_breakpoints(TRAPS) {
@ -220,8 +221,9 @@ class Method : public Metadata {
} }
// Initialization only // Initialization only
void clear_number_of_breakpoints() { void clear_number_of_breakpoints() {
if (method_counters() != NULL) { MethodCounters* mcs = method_counters();
method_counters()->clear_number_of_breakpoints(); if (mcs != NULL) {
mcs->clear_number_of_breakpoints();
} }
} }
@ -268,10 +270,11 @@ class Method : public Metadata {
} }
int interpreter_throwout_count() const { int interpreter_throwout_count() const {
if (method_counters() == NULL) { MethodCounters* mcs = method_counters();
if (mcs == NULL) {
return 0; return 0;
} else { } else {
return method_counters()->interpreter_throwout_count(); return mcs->interpreter_throwout_count();
} }
} }
@ -346,26 +349,28 @@ class Method : public Metadata {
return method_counters()->interpreter_invocation_count(); return method_counters()->interpreter_invocation_count();
} }
} }
void set_prev_event_count(int count, TRAPS) { void set_prev_event_count(int count) {
MethodCounters* mcs = get_method_counters(CHECK); MethodCounters* mcs = method_counters();
if (mcs != NULL) { if (mcs != NULL) {
mcs->set_interpreter_invocation_count(count); mcs->set_interpreter_invocation_count(count);
} }
} }
jlong prev_time() const { jlong prev_time() const {
return method_counters() == NULL ? 0 : method_counters()->prev_time(); MethodCounters* mcs = method_counters();
return mcs == NULL ? 0 : mcs->prev_time();
} }
void set_prev_time(jlong time, TRAPS) { void set_prev_time(jlong time) {
MethodCounters* mcs = get_method_counters(CHECK); MethodCounters* mcs = method_counters();
if (mcs != NULL) { if (mcs != NULL) {
mcs->set_prev_time(time); mcs->set_prev_time(time);
} }
} }
float rate() const { float rate() const {
return method_counters() == NULL ? 0 : method_counters()->rate(); MethodCounters* mcs = method_counters();
return mcs == NULL ? 0 : mcs->rate();
} }
void set_rate(float rate, TRAPS) { void set_rate(float rate) {
MethodCounters* mcs = get_method_counters(CHECK); MethodCounters* mcs = method_counters();
if (mcs != NULL) { if (mcs != NULL) {
mcs->set_rate(rate); mcs->set_rate(rate);
} }
@ -390,9 +395,12 @@ class Method : public Metadata {
static MethodCounters* build_method_counters(Method* m, TRAPS); static MethodCounters* build_method_counters(Method* m, TRAPS);
int interpreter_invocation_count() { int interpreter_invocation_count() {
if (TieredCompilation) return invocation_count(); if (TieredCompilation) {
else return (method_counters() == NULL) ? 0 : return invocation_count();
method_counters()->interpreter_invocation_count(); } else {
MethodCounters* mcs = method_counters();
return (mcs == NULL) ? 0 : mcs->interpreter_invocation_count();
}
} }
int increment_interpreter_invocation_count(TRAPS) { int increment_interpreter_invocation_count(TRAPS) {
if (TieredCompilation) ShouldNotReachHere(); if (TieredCompilation) ShouldNotReachHere();

View file

@ -495,8 +495,8 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
#ifdef TIERED #ifdef TIERED
mcs->set_rate(0.0F); mcs->set_rate(0.0F);
mh->set_prev_event_count(0, THREAD); mh->set_prev_event_count(0);
mh->set_prev_time(0, THREAD); mh->set_prev_time(0);
#endif #endif
} }
WB_END WB_END

View file

@ -75,11 +75,14 @@ void AdvancedThresholdPolicy::initialize() {
// update_rate() is called from select_task() while holding a compile queue lock. // update_rate() is called from select_task() while holding a compile queue lock.
void AdvancedThresholdPolicy::update_rate(jlong t, Method* m) { void AdvancedThresholdPolicy::update_rate(jlong t, Method* m) {
JavaThread* THREAD = JavaThread::current(); // 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)) { if (is_old(m)) {
// We don't remove old methods from the queue, // We don't remove old methods from the queue,
// so we can just zero the rate. // so we can just zero the rate.
m->set_rate(0, THREAD); m->set_rate(0);
return; return;
} }
@ -95,14 +98,15 @@ void AdvancedThresholdPolicy::update_rate(jlong t, Method* m) {
if (delta_s >= TieredRateUpdateMinTime) { if (delta_s >= TieredRateUpdateMinTime) {
// And we must've taken the previous point at least 1ms before. // And we must've taken the previous point at least 1ms before.
if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) { if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) {
m->set_prev_time(t, THREAD); m->set_prev_time(t);
m->set_prev_event_count(event_count, THREAD); m->set_prev_event_count(event_count);
m->set_rate((float)delta_e / (float)delta_t, THREAD); // Rate is events per millisecond m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond
} else } else {
if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) { if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) {
// If nothing happened for 25ms, zero the rate. Don't modify prev values. // If nothing happened for 25ms, zero the rate. Don't modify prev values.
m->set_rate(0, THREAD); m->set_rate(0);
} }
}
} }
} }
@ -164,7 +168,6 @@ CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) {
for (CompileTask* task = compile_queue->first(); task != NULL;) { for (CompileTask* task = compile_queue->first(); task != NULL;) {
CompileTask* next_task = task->next(); CompileTask* next_task = task->next();
Method* method = task->method(); Method* method = task->method();
MethodData* mdo = method->method_data();
update_rate(t, method); update_rate(t, method);
if (max_task == NULL) { if (max_task == NULL) {
max_task = task; max_task = task;
@ -175,8 +178,7 @@ CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) {
if (PrintTieredEvents) { if (PrintTieredEvents) {
print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level());
} }
CompileTaskWrapper ctw(task); // Frees the task compile_queue->remove_and_mark_stale(task);
compile_queue->remove(task);
method->clear_queued_for_compilation(); method->clear_queued_for_compilation();
task = next_task; task = next_task;
continue; continue;