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" |
| 25 | #include "UniquePtr.h" |
| 26 | |
| 27 | namespace art { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 28 | class CheckWaitTask : public Task { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 29 | public: |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 30 | CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2, |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 31 | AtomicInteger* count3) |
| 32 | : barrier_(barrier), |
| 33 | count1_(count1), |
| 34 | count2_(count2), |
Brian Carlstrom | 0cd7ec2 | 2013-07-17 23:40:20 -0700 | [diff] [blame] | 35 | count3_(count3) {} |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 36 | |
| 37 | void Run(Thread* self) { |
Ian Rogers | 23055dc | 2013-04-18 16:29:16 -0700 | [diff] [blame] | 38 | LOG(INFO) << "Before barrier 1 " << *self; |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 39 | ++*count1_; |
| 40 | barrier_->Wait(self); |
| 41 | ++*count2_; |
Ian Rogers | 23055dc | 2013-04-18 16:29:16 -0700 | [diff] [blame] | 42 | LOG(INFO) << "Before barrier 2 " << *self; |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 43 | barrier_->Wait(self); |
| 44 | ++*count3_; |
Ian Rogers | 23055dc | 2013-04-18 16:29:16 -0700 | [diff] [blame] | 45 | LOG(INFO) << "After barrier 2 " << *self; |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | virtual void Finalize() { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 49 | delete this; |
| 50 | } |
Brian Carlstrom | 0cd7ec2 | 2013-07-17 23:40:20 -0700 | [diff] [blame] | 51 | |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 52 | private: |
| 53 | Barrier* const barrier_; |
| 54 | AtomicInteger* const count1_; |
| 55 | AtomicInteger* const count2_; |
| 56 | AtomicInteger* const count3_; |
| 57 | }; |
| 58 | |
Brian Carlstrom | a1ce1fe | 2014-02-24 23:23:58 -0800 | [diff] [blame] | 59 | class BarrierTest : public CommonRuntimeTest { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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(); |
Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 69 | ThreadPool thread_pool("Barrier test thread pool", num_threads); |
Mathieu Chartier | 35883cc | 2012-11-13 14:08:12 -0800 | [diff] [blame] | 70 | Barrier barrier(0); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 71 | AtomicInteger count1(0); |
| 72 | AtomicInteger count2(0); |
| 73 | AtomicInteger count3(0); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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. |
Ian Rogers | 1d54e73 | 2013-05-02 21:10:01 -0700 | [diff] [blame] | 90 | thread_pool.Wait(self, true, false); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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), |
Brian Carlstrom | 0cd7ec2 | 2013-07-17 23:40:20 -0700 | [diff] [blame] | 102 | subtasks_(subtasks) {} |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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 | } |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | void Finalize() { |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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(); |
Mathieu Chartier | bcd5e9d | 2013-11-13 14:33:28 -0800 | [diff] [blame] | 124 | ThreadPool thread_pool("Barrier test thread pool", num_threads); |
Mathieu Chartier | 35883cc | 2012-11-13 14:08:12 -0800 | [diff] [blame] | 125 | Barrier barrier(0); |
Brian Carlstrom | 93ba893 | 2013-07-17 21:31:49 -0700 | [diff] [blame] | 126 | AtomicInteger count(0); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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) { |
Mathieu Chartier | 02b6a78 | 2012-10-26 13:51:26 -0700 | [diff] [blame] | 130 | thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks)); |
Mathieu Chartier | 0e4627e | 2012-10-23 16:13:36 -0700 | [diff] [blame] | 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 |