diff options
| -rw-r--r-- | runtime/jit/jit.cc | 19 | ||||
| -rw-r--r-- | runtime/jit/jit.h | 14 | ||||
| -rw-r--r-- | runtime/thread_pool.cc | 6 | ||||
| -rw-r--r-- | runtime/thread_pool.h | 7 | ||||
| -rw-r--r-- | runtime/thread_pool_test.cc | 18 | ||||
| -rw-r--r-- | test/913-heaps/heaps.cc | 9 | ||||
| -rw-r--r-- | test/913-heaps/src/Main.java | 4 |
7 files changed, 62 insertions, 15 deletions
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 23a5ddd071..803e9d5e61 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -701,5 +701,24 @@ void Jit::WaitForCompilationToFinish(Thread* self) { } } +ScopedJitSuspend::ScopedJitSuspend() { + jit::Jit* jit = Runtime::Current()->GetJit(); + was_on_ = (jit != nullptr) && (jit->GetThreadPool() != nullptr); + if (was_on_) { + Thread* self = Thread::Current(); + jit->WaitForCompilationToFinish(self); + jit->GetThreadPool()->StopWorkers(self); + jit->WaitForCompilationToFinish(self); + } +} + +ScopedJitSuspend::~ScopedJitSuspend() { + if (was_on_) { + DCHECK(Runtime::Current()->GetJit() != nullptr); + DCHECK(Runtime::Current()->GetJit()->GetThreadPool() != nullptr); + Runtime::Current()->GetJit()->GetThreadPool()->StartWorkers(Thread::Current()); + } +} + } // namespace jit } // namespace art diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index a7824378c2..a230c78033 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -175,6 +175,10 @@ class Jit { static bool LoadCompilerLibrary(std::string* error_msg); + ThreadPool* GetThreadPool() const { + return thread_pool_.get(); + } + private: Jit(); @@ -278,6 +282,16 @@ class JitOptions { DISALLOW_COPY_AND_ASSIGN(JitOptions); }; +// Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce. +class ScopedJitSuspend { + public: + ScopedJitSuspend(); + ~ScopedJitSuspend(); + + private: + bool was_on_; +}; + } // namespace jit } // namespace art diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index b14f340c4c..65fd99985b 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -177,7 +177,7 @@ Task* ThreadPool::GetTask(Thread* self) { } ++waiting_count_; - if (waiting_count_ == GetThreadCount() && tasks_.empty()) { + if (waiting_count_ == GetThreadCount() && !HasOutstandingTasks()) { // We may be done, lets broadcast to the completion condition. completion_condition_.Broadcast(self); } @@ -200,7 +200,7 @@ Task* ThreadPool::TryGetTask(Thread* self) { } Task* ThreadPool::TryGetTaskLocked() { - if (started_ && !tasks_.empty()) { + if (HasOutstandingTasks()) { Task* task = tasks_.front(); tasks_.pop_front(); return task; @@ -218,7 +218,7 @@ void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) { } // Wait until each thread is waiting and the task list is empty. MutexLock mu(self, task_queue_lock_); - while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) { + while (!shutting_down_ && (waiting_count_ != GetThreadCount() || HasOutstandingTasks())) { if (!may_hold_locks) { completion_condition_.Wait(self); } else { diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h index b6c6f02db8..2ff33a6053 100644 --- a/runtime/thread_pool.h +++ b/runtime/thread_pool.h @@ -100,7 +100,8 @@ class ThreadPool { ThreadPool(const char* name, size_t num_threads); virtual ~ThreadPool(); - // Wait for all tasks currently on queue to get completed. + // Wait for all tasks currently on queue to get completed. If the pool has been stopped, only + // wait till all already running tasks are done. void Wait(Thread* self, bool do_work, bool may_hold_locks) REQUIRES(!task_queue_lock_); size_t GetTaskCount(Thread* self) REQUIRES(!task_queue_lock_); @@ -130,6 +131,10 @@ class ThreadPool { return shutting_down_; } + bool HasOutstandingTasks() const REQUIRES(task_queue_lock_) { + return started_ && !tasks_.empty(); + } + const std::string name_; Mutex task_queue_lock_; ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_); diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index d5f17d17b1..2ae2ecff4e 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -98,6 +98,24 @@ TEST_F(ThreadPoolTest, StopStart) { thread_pool.Wait(self, false, false); } +TEST_F(ThreadPoolTest, StopWait) { + Thread* self = Thread::Current(); + ThreadPool thread_pool("Thread pool test thread pool", num_threads); + + AtomicInteger count(0); + static const int32_t num_tasks = num_threads * 100; + for (int32_t i = 0; i < num_tasks; ++i) { + thread_pool.AddTask(self, new CountTask(&count)); + } + + // Signal the threads to start processing tasks. + thread_pool.StartWorkers(self); + usleep(200); + thread_pool.StopWorkers(self); + + thread_pool.Wait(self, false, false); // We should not deadlock here. +} + class TreeTask : public Task { public: TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth) diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc index 0c627d6af8..49437b150f 100644 --- a/test/913-heaps/heaps.cc +++ b/test/913-heaps/heaps.cc @@ -261,6 +261,8 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env std::vector<std::string> lines_; }; + jit::ScopedJitSuspend sjs; // Wait to avoid JIT influence (e.g., JNI globals). + // If jniRef isn't null, add a local and a global ref. ScopedLocalRef<jobject> jni_local_ref(env, nullptr); jobject jni_global_ref = nullptr; @@ -299,12 +301,5 @@ jint OnLoad(JavaVM* vm, return 0; } -extern "C" JNIEXPORT void JNICALL Java_Main_waitForJitCompilation(JNIEnv*, jclass) { - jit::Jit* jit = Runtime::Current()->GetJit(); - if (jit != nullptr) { - jit->WaitForCompilationToFinish(Thread::Current()); - } -} - } // namespace Test913Heaps } // namespace art diff --git a/test/913-heaps/src/Main.java b/test/913-heaps/src/Main.java index fc00ada916..a6ace9aeba 100644 --- a/test/913-heaps/src/Main.java +++ b/test/913-heaps/src/Main.java @@ -101,8 +101,6 @@ public class Main { private static void doFollowReferencesTestImpl(A root, int stopAfter, int followSet, Object asRoot, Verifier v, String additionalEnabled) { - waitForJitCompilation(); // Wait to avoid JIT influence (e.g., JNI globals). - String[] lines = followReferences(0, null, root, stopAfter, followSet, asRoot); @@ -388,6 +386,4 @@ public class Main { private static native String[] followReferences(int heapFilter, Class<?> klassFilter, Object initialObject, int stopAfter, int followSet, Object jniRef); - - private static native void waitForJitCompilation(); } |