• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CountTask(AtomicInteger * count)28   explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {}
29 
Run(Thread * self)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 
Finalize()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.
TEST_F(ThreadPoolTest,CheckRun)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 
TEST_F(ThreadPoolTest,StopStart)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:
TreeTask(ThreadPool * const thread_pool,AtomicInteger * count,int depth)105   TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
106       : thread_pool_(thread_pool),
107         count_(count),
108         depth_(depth) {}
109 
Run(Thread * self)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 
Finalize()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.
TEST_F(ThreadPoolTest,RecursiveTest)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