Add thread pool class
Added a thread pool class loosely based on google3 code.
Modified the compiler to have a single thread pool instead of creating new threads in ForAll.
Moved barrier to be in top level directory as it is not GC specific code.
Performance Timings:
Reference:
boot.oat: 14.306596s
time mm oat-target:
real 2m33.748s
user 10m23.190s
sys 5m54.140s
Thread pool:
boot.oat: 13.111049s
time mm oat-target:
real 2m29.372s
user 10m3.130s
sys 5m46.290s
The speed increase is probably just noise.
Change-Id: If3c1280cbaa4c7e4361127d064ac744ea12cdf49
diff --git a/src/thread_pool_test.cc b/src/thread_pool_test.cc
new file mode 100644
index 0000000..783f786
--- /dev/null
+++ b/src/thread_pool_test.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <string>
+
+#include "atomic_integer.h"
+#include "common_test.h"
+#include "thread_pool.h"
+
+namespace art {
+
+class CountClosure : public Closure {
+ public:
+ CountClosure(AtomicInteger* count) : count_(count) {
+
+ }
+
+ void Run(Thread* /* self */) {
+ // Simulate doing some work.
+ usleep(100);
+ // Increment the counter which keeps track of work completed.
+ ++*count_;
+ delete this;
+ }
+
+ private:
+ AtomicInteger* const count_;
+};
+
+class ThreadPoolTest : public CommonTest {
+ public:
+ static int32_t num_threads;
+};
+
+int32_t ThreadPoolTest::num_threads = 4;
+
+// Check that the thread pool actually runs tasks that you assign it.
+TEST_F(ThreadPoolTest, CheckRun) {
+ Thread* self = Thread::Current();
+ ThreadPool thread_pool(num_threads);
+ AtomicInteger count = 0;
+ static const int32_t num_tasks = num_threads * 4;
+ for (int32_t i = 0; i < num_tasks; ++i) {
+ thread_pool.AddTask(self, new CountClosure(&count));
+ }
+ thread_pool.StartWorkers(self);
+ // Wait for tasks to complete.
+ thread_pool.Wait(self);
+ // Make sure that we finished all the work.
+ EXPECT_EQ(num_tasks, count);
+}
+
+TEST_F(ThreadPoolTest, StopStart) {
+ Thread* self = Thread::Current();
+ ThreadPool thread_pool(num_threads);
+ AtomicInteger count = 0;
+ static const int32_t num_tasks = num_threads * 4;
+ for (int32_t i = 0; i < num_tasks; ++i) {
+ thread_pool.AddTask(self, new CountClosure(&count));
+ }
+ usleep(200);
+ // Check that no threads started prematurely.
+ EXPECT_EQ(0, count);
+ // Signal the threads to start processing tasks.
+ thread_pool.StartWorkers(self);
+ usleep(200);
+ thread_pool.StopWorkers(self);
+ AtomicInteger bad_count = 0;
+ thread_pool.AddTask(self, new CountClosure(&bad_count));
+ usleep(200);
+ // Ensure that the task added after the workers were stopped doesn't get run.
+ EXPECT_EQ(0, bad_count);
+}
+
+class TreeClosure : public Closure {
+ public:
+ TreeClosure(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
+ : thread_pool_(thread_pool),
+ count_(count),
+ depth_(depth) {
+
+ }
+
+ void Run(Thread* self) {
+ if (depth_ > 1) {
+ thread_pool_->AddTask(self, new TreeClosure(thread_pool_, count_, depth_ - 1));
+ thread_pool_->AddTask(self, new TreeClosure(thread_pool_, count_, depth_ - 1));
+ }
+ // Increment the counter which keeps track of work completed.
+ ++*count_;
+ delete this;
+ }
+
+ private:
+ ThreadPool* const thread_pool_;
+ AtomicInteger* const count_;
+ const int depth_;
+};
+
+// Test that adding new tasks from within a task works.
+TEST_F(ThreadPoolTest, RecursiveTest) {
+ Thread* self = Thread::Current();
+ ThreadPool thread_pool(num_threads);
+ AtomicInteger count = 0;
+ static const int depth = 8;
+ thread_pool.AddTask(self, new TreeClosure(&thread_pool, &count, depth));
+ thread_pool.StartWorkers(self);
+ thread_pool.Wait(self);
+ EXPECT_EQ((1 << depth) - 1, count);
+}
+
+} // namespace art