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 17 #include "thread_pool.h" 18 19 #include <string> 20 21 #include "atomic.h" 22 #include "common_runtime_test.h" 23 #include "thread-inl.h" 24 25 namespace art { 26 27 class CountTask : public Task { 28 public: 29 explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {} 30 31 void Run(Thread* self) { 32 if (verbose_) { 33 LOG(INFO) << "Running: " << *self; 34 } 35 // Simulate doing some work. 36 usleep(100); 37 // Increment the counter which keeps track of work completed. 38 ++*count_; 39 } 40 41 void Finalize() { 42 if (verbose_) { 43 LOG(INFO) << "Finalizing: " << *Thread::Current(); 44 } 45 delete this; 46 } 47 48 private: 49 AtomicInteger* const count_; 50 const bool verbose_; 51 }; 52 53 class ThreadPoolTest : public CommonRuntimeTest { 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(); 63 ThreadPool thread_pool("Thread pool test thread pool", num_threads); 64 AtomicInteger count(0); 65 static const int32_t num_tasks = num_threads * 4; 66 for (int32_t i = 0; i < num_tasks; ++i) { 67 thread_pool.AddTask(self, new CountTask(&count)); 68 } 69 thread_pool.StartWorkers(self); 70 // Wait for tasks to complete. 71 thread_pool.Wait(self, true, false); 72 // Make sure that we finished all the work. 73 EXPECT_EQ(num_tasks, count.LoadSequentiallyConsistent()); 74 } 75 76 TEST_F(ThreadPoolTest, StopStart) { 77 Thread* self = Thread::Current(); 78 ThreadPool thread_pool("Thread pool test thread pool", num_threads); 79 AtomicInteger count(0); 80 static const int32_t num_tasks = num_threads * 4; 81 for (int32_t i = 0; i < num_tasks; ++i) { 82 thread_pool.AddTask(self, new CountTask(&count)); 83 } 84 usleep(200); 85 // Check that no threads started prematurely. 86 EXPECT_EQ(0, count.LoadSequentiallyConsistent()); 87 // Signal the threads to start processing tasks. 88 thread_pool.StartWorkers(self); 89 usleep(200); 90 thread_pool.StopWorkers(self); 91 AtomicInteger bad_count(0); 92 thread_pool.AddTask(self, new CountTask(&bad_count)); 93 usleep(200); 94 // Ensure that the task added after the workers were stopped doesn't get run. 95 EXPECT_EQ(0, bad_count.LoadSequentiallyConsistent()); 96 // Allow tasks to finish up and delete themselves. 97 thread_pool.StartWorkers(self); 98 thread_pool.Wait(self, false, false); 99 } 100 101 class TreeTask : public Task { 102 public: 103 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth) 104 : thread_pool_(thread_pool), 105 count_(count), 106 depth_(depth) {} 107 108 void Run(Thread* self) { 109 if (depth_ > 1) { 110 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); 111 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); 112 } 113 // Increment the counter which keeps track of work completed. 114 ++*count_; 115 } 116 117 void Finalize() { 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(); 130 ThreadPool thread_pool("Thread pool test thread pool", num_threads); 131 AtomicInteger count(0); 132 static const int depth = 8; 133 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth)); 134 thread_pool.StartWorkers(self); 135 thread_pool.Wait(self, true, false); 136 EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); 137 } 138 139 } // namespace art 140