| 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); | 
| Mathieu Chartier | 7947b54 | 2014-11-09 12:30:50 -0800 | [diff] [blame] | 98 | thread_pool.Wait(self, false, false); | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 99 | } | 
|  | 100 |  | 
| Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 101 | class TreeTask : public Task { | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 102 | public: | 
| Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 103 | TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth) | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 104 | : thread_pool_(thread_pool), | 
|  | 105 | count_(count), | 
| Brian Carlstrom | 0cd7ec2 | 2013-07-17 23:40:20 -0700 | [diff] [blame] | 106 | depth_(depth) {} | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 107 |  | 
|  | 108 | void Run(Thread* self) { | 
|  | 109 | if (depth_ > 1) { | 
| Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 110 | thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); | 
|  | 111 | thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 112 | } | 
|  | 113 | // Increment the counter which keeps track of work completed. | 
|  | 114 | ++*count_; | 
| Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 115 | } | 
|  | 116 |  | 
|  | 117 | void Finalize() { | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 118 | delete this; | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | private: | 
|  | 122 | ThreadPool* const thread_pool_; | 
|  | 123 | AtomicInteger* const count_; | 
|  | 124 | const int depth_; | 
|  | 125 | }; | 
|  | 126 |  | 
|  | 127 | // Test that adding new tasks from within a task works. | 
|  | 128 | TEST_F(ThreadPoolTest, RecursiveTest) { | 
|  | 129 | Thread* self = Thread::Current(); | 
| Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 130 | ThreadPool thread_pool("Thread pool test thread pool", num_threads); | 
| Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 131 | AtomicInteger count(0); | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 132 | static const int depth = 8; | 
| Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 133 | thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth)); | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 134 | thread_pool.StartWorkers(self); | 
| Ian Rogers | 1d54e73 | 2013-05-02 21:10:01 -0700 | [diff] [blame] | 135 | thread_pool.Wait(self, true, false); | 
| Ian Rogers | 3e5cf30 | 2014-05-20 16:40:37 -0700 | [diff] [blame] | 136 | EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); | 
| Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 137 | } | 
|  | 138 |  | 
|  | 139 | }  // namespace art |