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