Home | History | Annotate | Download | only in runtime
      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