thread_pool_test.cc revision 3e5cf305db800b2989ad57b7cde8fb3cc9fa1b9e
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 24namespace art { 25 26class 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 52class ThreadPoolTest : public CommonRuntimeTest { 53 public: 54 static int32_t num_threads; 55}; 56 57int32_t ThreadPoolTest::num_threads = 4; 58 59// Check that the thread pool actually runs tasks that you assign it. 60TEST_F(ThreadPoolTest, CheckRun) { 61 Thread* self = Thread::Current(); 62 ThreadPool thread_pool("Thread pool test 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.LoadSequentiallyConsistent()); 73} 74 75TEST_F(ThreadPoolTest, StopStart) { 76 Thread* self = Thread::Current(); 77 ThreadPool thread_pool("Thread pool test 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.LoadSequentiallyConsistent()); 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.LoadSequentiallyConsistent()); 95 // Allow tasks to finish up and delete themselves. 96 thread_pool.StartWorkers(self); 97 while (count.LoadSequentiallyConsistent() != num_tasks && 98 bad_count.LoadSequentiallyConsistent() != 1) { 99 usleep(200); 100 } 101 thread_pool.StopWorkers(self); 102} 103 104class TreeTask : public Task { 105 public: 106 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth) 107 : thread_pool_(thread_pool), 108 count_(count), 109 depth_(depth) {} 110 111 void Run(Thread* self) { 112 if (depth_ > 1) { 113 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); 114 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1)); 115 } 116 // Increment the counter which keeps track of work completed. 117 ++*count_; 118 } 119 120 void Finalize() { 121 delete this; 122 } 123 124 private: 125 ThreadPool* const thread_pool_; 126 AtomicInteger* const count_; 127 const int depth_; 128}; 129 130// Test that adding new tasks from within a task works. 131TEST_F(ThreadPoolTest, RecursiveTest) { 132 Thread* self = Thread::Current(); 133 ThreadPool thread_pool("Thread pool test thread pool", num_threads); 134 AtomicInteger count(0); 135 static const int depth = 8; 136 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth)); 137 thread_pool.StartWorkers(self); 138 thread_pool.Wait(self, true, false); 139 EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); 140} 141 142} // namespace art 143