10e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier/* 20e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Copyright (C) 2012 The Android Open Source Project 30e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 40e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Licensed under the Apache License, Version 2.0 (the "License"); 50e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * you may not use this file except in compliance with the License. 60e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * You may obtain a copy of the License at 70e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 80e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * http://www.apache.org/licenses/LICENSE-2.0 90e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Unless required by applicable law or agreed to in writing, software 110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * distributed under the License is distributed on an "AS IS" BASIS, 120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * See the License for the specific language governing permissions and 140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * limitations under the License. 150e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier */ 160e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "barrier.h" 180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include <string> 200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 218f4b056427a9d2321e3aa4f21ca8ffb18b3e5ae6David Sehr#include "base/atomic.h" 22a1ce1fef2d49d1d537776a5308ace7102a815fe5Brian Carlstrom#include "common_runtime_test.h" 232dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/object_array-inl.h" 24b486a98aadc95d80548953410cf23edba62259faAndreas Gampe#include "thread-current-inl.h" 258cf9cb386cd9286d67e879f1ee501ec00d72a4e1Andreas Gampe#include "thread_pool.h" 260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiernamespace art { 2802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass CheckWaitTask : public Task { 290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 305567c11b9157eec110c0631aa2bff5836631e868Hans Boehm CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2) 310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier : barrier_(barrier), 320e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier count1_(count1), 335567c11b9157eec110c0631aa2bff5836631e868Hans Boehm count2_(count2) {} 340e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 350e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void Run(Thread* self) { 365567c11b9157eec110c0631aa2bff5836631e868Hans Boehm LOG(INFO) << "Before barrier" << *self; 370e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ++*count1_; 380e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier barrier_->Wait(self); 390e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ++*count2_; 405567c11b9157eec110c0631aa2bff5836631e868Hans Boehm LOG(INFO) << "After barrier" << *self; 4102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 4202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 4302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Finalize() { 440e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier delete this; 450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 460cd7ec2dcd8d7ba30bf3ca420b40dac52849876cBrian Carlstrom 470e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier private: 480e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Barrier* const barrier_; 490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier AtomicInteger* const count1_; 500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier AtomicInteger* const count2_; 510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 520e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 53a1ce1fef2d49d1d537776a5308ace7102a815fe5Brian Carlstromclass BarrierTest : public CommonRuntimeTest { 540e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 550e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier static int32_t num_threads; 560e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 570e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 580e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierint32_t BarrierTest::num_threads = 4; 590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier// Check that barrier wait and barrier increment work. 610e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierTEST_F(BarrierTest, CheckWait) { 620e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Thread* self = Thread::Current(); 63bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier ThreadPool thread_pool("Barrier test thread pool", num_threads); 645567c11b9157eec110c0631aa2bff5836631e868Hans Boehm Barrier barrier(num_threads + 1); // One extra Wait() in main thread. 655567c11b9157eec110c0631aa2bff5836631e868Hans Boehm Barrier timeout_barrier(0); // Only used for sleeping on timeout. 6693ba893c20532990a430741e0a97212900094e8cBrian Carlstrom AtomicInteger count1(0); 6793ba893c20532990a430741e0a97212900094e8cBrian Carlstrom AtomicInteger count2(0); 680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier for (int32_t i = 0; i < num_threads; ++i) { 695567c11b9157eec110c0631aa2bff5836631e868Hans Boehm thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2)); 700e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier thread_pool.StartWorkers(self); 725567c11b9157eec110c0631aa2bff5836631e868Hans Boehm while (count1.LoadRelaxed() != num_threads) { 735567c11b9157eec110c0631aa2bff5836631e868Hans Boehm timeout_barrier.Increment(self, 1, 100); // sleep 100 msecs 745567c11b9157eec110c0631aa2bff5836631e868Hans Boehm } 755567c11b9157eec110c0631aa2bff5836631e868Hans Boehm // Count 2 should still be zero since no thread should have gone past the barrier. 765567c11b9157eec110c0631aa2bff5836631e868Hans Boehm EXPECT_EQ(0, count2.LoadRelaxed()); 775567c11b9157eec110c0631aa2bff5836631e868Hans Boehm // Perform one additional Wait(), allowing pool threads to proceed. 785567c11b9157eec110c0631aa2bff5836631e868Hans Boehm barrier.Wait(self); 790e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait for all the threads to finish. 801d54e73444e017d3a65234e0f193846f3e27472bIan Rogers thread_pool.Wait(self, true, false); 815567c11b9157eec110c0631aa2bff5836631e868Hans Boehm // Both counts should be equal to num_threads now. 825567c11b9157eec110c0631aa2bff5836631e868Hans Boehm EXPECT_EQ(count1.LoadRelaxed(), num_threads); 835567c11b9157eec110c0631aa2bff5836631e868Hans Boehm EXPECT_EQ(count2.LoadRelaxed(), num_threads); 845567c11b9157eec110c0631aa2bff5836631e868Hans Boehm timeout_barrier.Init(self, 0); // Reset to zero for destruction. 850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 860e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 8702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass CheckPassTask : public Task { 880e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 8902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier CheckPassTask(Barrier* barrier, AtomicInteger* count, size_t subtasks) 900e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier : barrier_(barrier), 910e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier count_(count), 920cd7ec2dcd8d7ba30bf3ca420b40dac52849876cBrian Carlstrom subtasks_(subtasks) {} 930e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 940e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void Run(Thread* self) { 950e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier for (size_t i = 0; i < subtasks_; ++i) { 960e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ++*count_; 970e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Pass through to next subtask. 980e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier barrier_->Pass(self); 990e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 10102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier void Finalize() { 1030e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier delete this; 1040e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 1050e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier private: 1060e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Barrier* const barrier_; 1070e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier AtomicInteger* const count_; 1080e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const size_t subtasks_; 1090e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 1100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 1110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier// Check that barrier pass through works. 1120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierTEST_F(BarrierTest, CheckPass) { 1130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Thread* self = Thread::Current(); 114bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier ThreadPool thread_pool("Barrier test thread pool", num_threads); 11535883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier Barrier barrier(0); 11693ba893c20532990a430741e0a97212900094e8cBrian Carlstrom AtomicInteger count(0); 1170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const int32_t num_tasks = num_threads * 4; 1180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const int32_t num_sub_tasks = 128; 1190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier for (int32_t i = 0; i < num_tasks; ++i) { 12002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks)); 1210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 1220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier thread_pool.StartWorkers(self); 1230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const int32_t expected_total_tasks = num_sub_tasks * num_tasks; 1240e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait for all the tasks to complete using the barrier. 1250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier barrier.Increment(self, expected_total_tasks); 1260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // The total number of completed tasks should be equal to expected_total_tasks. 1273e5cf305db800b2989ad57b7cde8fb3cc9fa1b9eIan Rogers EXPECT_EQ(count.LoadRelaxed(), expected_total_tasks); 1280e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 1290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 1300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} // namespace art 131