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