Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Brian Carlstrom | a1ce1fe | 2014-02-24 23:23:58 -0800 | [diff] [blame] | 17 | #include "thread_pool.h" |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 18 | |
| 19 | #include <string> |
| 20 | |
Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 21 | #include "atomic.h" |
Brian Carlstrom | a1ce1fe | 2014-02-24 23:23:58 -0800 | [diff] [blame] | 22 | #include "common_runtime_test.h" |
Ian Rogers | e63db27 | 2014-07-15 15:36:11 -0700 | [diff] [blame] | 23 | #include "thread-inl.h" |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 24 | |
| 25 | namespace art { |
| 26 | |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 27 | class CountTask : public Task { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 28 | public: |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 29 | explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {} |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 30 | |
Ian Rogers | d914eb2 | 2013-04-18 16:11:15 -0700 | [diff] [blame] | 31 | void Run(Thread* self) { |
| 32 | if (verbose_) { |
| 33 | LOG(INFO) << "Running: " << *self; |
| 34 | } |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 35 | // Simulate doing some work. |
| 36 | usleep(100); |
| 37 | // Increment the counter which keeps track of work completed. |
| 38 | ++*count_; |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | void Finalize() { |
Ian Rogers | d914eb2 | 2013-04-18 16:11:15 -0700 | [diff] [blame] | 42 | if (verbose_) { |
| 43 | LOG(INFO) << "Finalizing: " << *Thread::Current(); |
| 44 | } |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 45 | delete this; |
| 46 | } |
| 47 | |
| 48 | private: |
| 49 | AtomicInteger* const count_; |
Ian Rogers | d914eb2 | 2013-04-18 16:11:15 -0700 | [diff] [blame] | 50 | const bool verbose_; |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 51 | }; |
| 52 | |
Brian Carlstrom | a1ce1fe | 2014-02-24 23:23:58 -0800 | [diff] [blame] | 53 | class ThreadPoolTest : public CommonRuntimeTest { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 54 | public: |
| 55 | static int32_t num_threads; |
| 56 | }; |
| 57 | |
| 58 | int32_t ThreadPoolTest::num_threads = 4; |
| 59 | |
| 60 | // Check that the thread pool actually runs tasks that you assign it. |
| 61 | TEST_F(ThreadPoolTest, CheckRun) { |
| 62 | Thread* self = Thread::Current(); |
Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 63 | ThreadPool thread_pool("Thread pool test thread pool", num_threads); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 64 | AtomicInteger count(0); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 65 | static const int32_t num_tasks = num_threads * 4; |
| 66 | for (int32_t i = 0; i < num_tasks; ++i) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 67 | thread_pool.AddTask(self, new CountTask(&count)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 68 | } |
| 69 | thread_pool.StartWorkers(self); |
| 70 | // Wait for tasks to complete. |
Ian Rogers | 1d54e73 | 2013-05-02 21:10:01 -0700 | [diff] [blame] | 71 | thread_pool.Wait(self, true, false); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 72 | // Make sure that we finished all the work. |
Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 73 | EXPECT_EQ(num_tasks, count.LoadSequentiallyConsistent()); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | TEST_F(ThreadPoolTest, StopStart) { |
| 77 | Thread* self = Thread::Current(); |
Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 78 | ThreadPool thread_pool("Thread pool test thread pool", num_threads); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 79 | AtomicInteger count(0); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 80 | static const int32_t num_tasks = num_threads * 4; |
| 81 | for (int32_t i = 0; i < num_tasks; ++i) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 82 | thread_pool.AddTask(self, new CountTask(&count)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 83 | } |
| 84 | usleep(200); |
| 85 | // Check that no threads started prematurely. |
Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 86 | EXPECT_EQ(0, count.LoadSequentiallyConsistent()); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 87 | // Signal the threads to start processing tasks. |
| 88 | thread_pool.StartWorkers(self); |
| 89 | usleep(200); |
| 90 | thread_pool.StopWorkers(self); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 91 | AtomicInteger bad_count(0); |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 92 | thread_pool.AddTask(self, new CountTask(&bad_count)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 93 | usleep(200); |
| 94 | // Ensure that the task added after the workers were stopped doesn't get run. |
Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 95 | EXPECT_EQ(0, bad_count.LoadSequentiallyConsistent()); |
Ian Rogers | d914eb2 | 2013-04-18 16:11:15 -0700 | [diff] [blame] | 96 | // Allow tasks to finish up and delete themselves. |
| 97 | thread_pool.StartWorkers(self); |
Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 98 | while (count.LoadSequentiallyConsistent() != num_tasks && |
| 99 | bad_count.LoadSequentiallyConsistent() != 1) { |
Ian Rogers | d914eb2 | 2013-04-18 16:11:15 -0700 | [diff] [blame] | 100 | usleep(200); |
| 101 | } |
| 102 | thread_pool.StopWorkers(self); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 105 | class TreeTask : public Task { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 106 | public: |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 107 | TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth) |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 108 | : thread_pool_(thread_pool), |
| 109 | count_(count), |
Brian Carlstrom | 0cd7ec2 | 2013-07-17 23:40:20 -0700 | [diff] [blame] | 110 | depth_(depth) {} |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 111 | |
| 112 | void Run(Thread* self) { |
| 113 | if (depth_ > 1) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 114 | thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); |
| 115 | thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 116 | } |
| 117 | // Increment the counter which keeps track of work completed. |
| 118 | ++*count_; |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | void Finalize() { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 122 | delete this; |
| 123 | } |
| 124 | |
| 125 | private: |
| 126 | ThreadPool* const thread_pool_; |
| 127 | AtomicInteger* const count_; |
| 128 | const int depth_; |
| 129 | }; |
| 130 | |
| 131 | // Test that adding new tasks from within a task works. |
| 132 | TEST_F(ThreadPoolTest, RecursiveTest) { |
| 133 | Thread* self = Thread::Current(); |
Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 134 | ThreadPool thread_pool("Thread pool test thread pool", num_threads); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 135 | AtomicInteger count(0); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 136 | static const int depth = 8; |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 137 | thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 138 | thread_pool.StartWorkers(self); |
Ian Rogers | 1d54e73 | 2013-05-02 21:10:01 -0700 | [diff] [blame] | 139 | thread_pool.Wait(self, true, false); |
Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 140 | EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | } // namespace art |