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_integer.h" 22 #include "common_test.h" 23 #include "mirror/object_array-inl.h" 24 #include "thread_pool.h" 25 #include "UniquePtr.h" 26 27 namespace art { 28 class CheckWaitTask : public Task { 29 public: 30 CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2, 31 AtomicInteger* count3) 32 : barrier_(barrier), 33 count1_(count1), 34 count2_(count2), 35 count3_(count3) {} 36 37 void Run(Thread* self) { 38 LOG(INFO) << "Before barrier 1 " << *self; 39 ++*count1_; 40 barrier_->Wait(self); 41 ++*count2_; 42 LOG(INFO) << "Before barrier 2 " << *self; 43 barrier_->Wait(self); 44 ++*count3_; 45 LOG(INFO) << "After barrier 2 " << *self; 46 } 47 48 virtual void Finalize() { 49 delete this; 50 } 51 52 private: 53 Barrier* const barrier_; 54 AtomicInteger* const count1_; 55 AtomicInteger* const count2_; 56 AtomicInteger* const count3_; 57 }; 58 59 class BarrierTest : public CommonTest { 60 public: 61 static int32_t num_threads; 62 }; 63 64 int32_t BarrierTest::num_threads = 4; 65 66 // Check that barrier wait and barrier increment work. 67 TEST_F(BarrierTest, CheckWait) { 68 Thread* self = Thread::Current(); 69 ThreadPool thread_pool(num_threads); 70 Barrier barrier(0); 71 AtomicInteger count1(0); 72 AtomicInteger count2(0); 73 AtomicInteger count3(0); 74 for (int32_t i = 0; i < num_threads; ++i) { 75 thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2, &count3)); 76 } 77 thread_pool.StartWorkers(self); 78 barrier.Increment(self, num_threads); 79 // At this point each thread should have passed through the barrier. The first count should be 80 // equal to num_threads. 81 EXPECT_EQ(num_threads, count1); 82 // Count 3 should still be zero since no thread should have gone past the second barrier. 83 EXPECT_EQ(0, count3); 84 // Now lets tell the threads to pass again. 85 barrier.Increment(self, num_threads); 86 // Count 2 should be equal to num_threads since each thread must have passed the second barrier 87 // at this point. 88 EXPECT_EQ(num_threads, count2); 89 // Wait for all the threads to finish. 90 thread_pool.Wait(self, true, false); 91 // All three counts should be equal to num_threads now. 92 EXPECT_EQ(count1, count2); 93 EXPECT_EQ(count2, count3); 94 EXPECT_EQ(num_threads, count3); 95 } 96 97 class CheckPassTask : public Task { 98 public: 99 CheckPassTask(Barrier* barrier, AtomicInteger* count, size_t subtasks) 100 : barrier_(barrier), 101 count_(count), 102 subtasks_(subtasks) {} 103 104 void Run(Thread* self) { 105 for (size_t i = 0; i < subtasks_; ++i) { 106 ++*count_; 107 // Pass through to next subtask. 108 barrier_->Pass(self); 109 } 110 } 111 112 void Finalize() { 113 delete this; 114 } 115 private: 116 Barrier* const barrier_; 117 AtomicInteger* const count_; 118 const size_t subtasks_; 119 }; 120 121 // Check that barrier pass through works. 122 TEST_F(BarrierTest, CheckPass) { 123 Thread* self = Thread::Current(); 124 ThreadPool thread_pool(num_threads); 125 Barrier barrier(0); 126 AtomicInteger count(0); 127 const int32_t num_tasks = num_threads * 4; 128 const int32_t num_sub_tasks = 128; 129 for (int32_t i = 0; i < num_tasks; ++i) { 130 thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks)); 131 } 132 thread_pool.StartWorkers(self); 133 const int32_t expected_total_tasks = num_sub_tasks * num_tasks; 134 // Wait for all the tasks to complete using the barrier. 135 barrier.Increment(self, expected_total_tasks); 136 // The total number of completed tasks should be equal to expected_total_tasks. 137 EXPECT_EQ(count, expected_total_tasks); 138 } 139 140 } // namespace art 141