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 "barrier.h"
     18 
     19 #include <string>
     20 
     21 #include "atomic.h"
     22 #include "common_runtime_test.h"
     23 #include "mirror/object_array-inl.h"
     24 #include "thread_pool.h"
     25 #include "thread-inl.h"
     26 
     27 namespace art {
     28 class CheckWaitTask : public Task {
     29  public:
     30   CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2)
     31       : barrier_(barrier),
     32         count1_(count1),
     33         count2_(count2) {}
     34 
     35   void Run(Thread* self) {
     36     LOG(INFO) << "Before barrier" << *self;
     37     ++*count1_;
     38     barrier_->Wait(self);
     39     ++*count2_;
     40     LOG(INFO) << "After barrier" << *self;
     41   }
     42 
     43   virtual void Finalize() {
     44     delete this;
     45   }
     46 
     47  private:
     48   Barrier* const barrier_;
     49   AtomicInteger* const count1_;
     50   AtomicInteger* const count2_;
     51 };
     52 
     53 class BarrierTest : public CommonRuntimeTest {
     54  public:
     55   static int32_t num_threads;
     56 };
     57 
     58 int32_t BarrierTest::num_threads = 4;
     59 
     60 // Check that barrier wait and barrier increment work.
     61 TEST_F(BarrierTest, CheckWait) {
     62   Thread* self = Thread::Current();
     63   ThreadPool thread_pool("Barrier test thread pool", num_threads);
     64   Barrier barrier(num_threads + 1);  // One extra Wait() in main thread.
     65   Barrier timeout_barrier(0);  // Only used for sleeping on timeout.
     66   AtomicInteger count1(0);
     67   AtomicInteger count2(0);
     68   for (int32_t i = 0; i < num_threads; ++i) {
     69     thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2));
     70   }
     71   thread_pool.StartWorkers(self);
     72   while (count1.LoadRelaxed() != num_threads) {
     73     timeout_barrier.Increment(self, 1, 100);  // sleep 100 msecs
     74   }
     75   // Count 2 should still be zero since no thread should have gone past the barrier.
     76   EXPECT_EQ(0, count2.LoadRelaxed());
     77   // Perform one additional Wait(), allowing pool threads to proceed.
     78   barrier.Wait(self);
     79   // Wait for all the threads to finish.
     80   thread_pool.Wait(self, true, false);
     81   // Both counts should be equal to num_threads now.
     82   EXPECT_EQ(count1.LoadRelaxed(), num_threads);
     83   EXPECT_EQ(count2.LoadRelaxed(), num_threads);
     84   timeout_barrier.Init(self, 0);  // Reset to zero for destruction.
     85 }
     86 
     87 class CheckPassTask : public Task {
     88  public:
     89   CheckPassTask(Barrier* barrier, AtomicInteger* count, size_t subtasks)
     90       : barrier_(barrier),
     91         count_(count),
     92         subtasks_(subtasks) {}
     93 
     94   void Run(Thread* self) {
     95     for (size_t i = 0; i < subtasks_; ++i) {
     96       ++*count_;
     97       // Pass through to next subtask.
     98       barrier_->Pass(self);
     99     }
    100   }
    101 
    102   void Finalize() {
    103     delete this;
    104   }
    105  private:
    106   Barrier* const barrier_;
    107   AtomicInteger* const count_;
    108   const size_t subtasks_;
    109 };
    110 
    111 // Check that barrier pass through works.
    112 TEST_F(BarrierTest, CheckPass) {
    113   Thread* self = Thread::Current();
    114   ThreadPool thread_pool("Barrier test thread pool", num_threads);
    115   Barrier barrier(0);
    116   AtomicInteger count(0);
    117   const int32_t num_tasks = num_threads * 4;
    118   const int32_t num_sub_tasks = 128;
    119   for (int32_t i = 0; i < num_tasks; ++i) {
    120     thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks));
    121   }
    122   thread_pool.StartWorkers(self);
    123   const int32_t expected_total_tasks = num_sub_tasks * num_tasks;
    124   // Wait for all the tasks to complete using the barrier.
    125   barrier.Increment(self, expected_total_tasks);
    126   // The total number of completed tasks should be equal to expected_total_tasks.
    127   EXPECT_EQ(count.LoadRelaxed(), expected_total_tasks);
    128 }
    129 
    130 }  // namespace art
    131