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