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 27namespace art { 28class 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 53class BarrierTest : public CommonRuntimeTest { 54 public: 55 static int32_t num_threads; 56}; 57 58int32_t BarrierTest::num_threads = 4; 59 60// Check that barrier wait and barrier increment work. 61TEST_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 87class 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. 112TEST_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