Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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 "thread_pool.h" |
| 24 | #include "UniquePtr.h" |
| 25 | |
| 26 | namespace art { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 27 | class CheckWaitTask : public Task { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 28 | public: |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 29 | CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2, |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 30 | AtomicInteger* count3) |
| 31 | : barrier_(barrier), |
| 32 | count1_(count1), |
| 33 | count2_(count2), |
| 34 | count3_(count3) { |
| 35 | |
| 36 | } |
| 37 | |
| 38 | void Run(Thread* self) { |
| 39 | LOG(INFO) << "Before barrier 1 " << self; |
| 40 | ++*count1_; |
| 41 | barrier_->Wait(self); |
| 42 | ++*count2_; |
| 43 | LOG(INFO) << "Before barrier 2 " << self; |
| 44 | barrier_->Wait(self); |
| 45 | ++*count3_; |
| 46 | LOG(INFO) << "After barrier 2 " << self; |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | virtual void Finalize() { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 50 | delete this; |
| 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; |
| 71 | AtomicInteger count1 = 0; |
| 72 | AtomicInteger count2 = 0; |
| 73 | AtomicInteger count3 = 0; |
| 74 | for (int32_t i = 0; i < num_threads; ++i) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 75 | thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2, &count3)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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); |
| 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 | |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 97 | class CheckPassTask : public Task { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 98 | public: |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 99 | CheckPassTask(Barrier* barrier, AtomicInteger* count, size_t subtasks) |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 100 | : barrier_(barrier), |
| 101 | count_(count), |
| 102 | subtasks_(subtasks) { |
| 103 | |
| 104 | } |
| 105 | |
| 106 | void Run(Thread* self) { |
| 107 | for (size_t i = 0; i < subtasks_; ++i) { |
| 108 | ++*count_; |
| 109 | // Pass through to next subtask. |
| 110 | barrier_->Pass(self); |
| 111 | } |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | void Finalize() { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 115 | delete this; |
| 116 | } |
| 117 | private: |
| 118 | Barrier* const barrier_; |
| 119 | AtomicInteger* const count_; |
| 120 | const size_t subtasks_; |
| 121 | }; |
| 122 | |
| 123 | // Check that barrier pass through works. |
| 124 | TEST_F(BarrierTest, CheckPass) { |
| 125 | Thread* self = Thread::Current(); |
| 126 | ThreadPool thread_pool(num_threads); |
| 127 | Barrier barrier; |
| 128 | AtomicInteger count = 0; |
| 129 | const int32_t num_tasks = num_threads * 4; |
| 130 | const int32_t num_sub_tasks = 128; |
| 131 | for (int32_t i = 0; i < num_tasks; ++i) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 132 | thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 133 | } |
| 134 | thread_pool.StartWorkers(self); |
| 135 | const int32_t expected_total_tasks = num_sub_tasks * num_tasks; |
| 136 | // Wait for all the tasks to complete using the barrier. |
| 137 | barrier.Increment(self, expected_total_tasks); |
| 138 | // The total number of completed tasks should be equal to expected_total_tasks. |
| 139 | EXPECT_EQ(count, expected_total_tasks); |
| 140 | } |
| 141 | |
| 142 | } // namespace art |