blob: 5ec24bce173f2006a30ec75c0ede2d4487420c9a [file] [log] [blame]
Mathieu Chartier0e4627e2012-10-23 16:13:36 -07001/*
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
David Sehrc431b9d2018-03-02 12:01:51 -080021#include "base/atomic.h"
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080022#include "common_runtime_test.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080023#include "mirror/object_array-inl.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070024#include "thread-current-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025#include "thread_pool.h"
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070026
27namespace art {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070028class CheckWaitTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070029 public:
Hans Boehm5567c112014-12-02 18:31:31 -080030 CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070031 : barrier_(barrier),
32 count1_(count1),
Hans Boehm5567c112014-12-02 18:31:31 -080033 count2_(count2) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070034
Andreas Gampefa6a1b02018-09-07 08:11:55 -070035 void Run(Thread* self) override {
Hans Boehm5567c112014-12-02 18:31:31 -080036 LOG(INFO) << "Before barrier" << *self;
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070037 ++*count1_;
38 barrier_->Wait(self);
39 ++*count2_;
Hans Boehm5567c112014-12-02 18:31:31 -080040 LOG(INFO) << "After barrier" << *self;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070041 }
42
Andreas Gampefa6a1b02018-09-07 08:11:55 -070043 void Finalize() override {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070044 delete this;
45 }
Brian Carlstrom0cd7ec22013-07-17 23:40:20 -070046
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070047 private:
48 Barrier* const barrier_;
49 AtomicInteger* const count1_;
50 AtomicInteger* const count2_;
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070051};
52
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080053class BarrierTest : public CommonRuntimeTest {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070054 public:
55 static int32_t num_threads;
56};
57
58int32_t BarrierTest::num_threads = 4;
59
60// Check that barrier wait and barrier increment work.
61TEST_F(BarrierTest, CheckWait) {
62 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -080063 ThreadPool thread_pool("Barrier test thread pool", num_threads);
Hans Boehm5567c112014-12-02 18:31:31 -080064 Barrier barrier(num_threads + 1); // One extra Wait() in main thread.
65 Barrier timeout_barrier(0); // Only used for sleeping on timeout.
Brian Carlstrom93ba8932013-07-17 21:31:49 -070066 AtomicInteger count1(0);
67 AtomicInteger count2(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070068 for (int32_t i = 0; i < num_threads; ++i) {
Hans Boehm5567c112014-12-02 18:31:31 -080069 thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070070 }
71 thread_pool.StartWorkers(self);
Orion Hodson88591fe2018-03-06 13:35:43 +000072 while (count1.load(std::memory_order_relaxed) != num_threads) {
Hans Boehm5567c112014-12-02 18:31:31 -080073 timeout_barrier.Increment(self, 1, 100); // sleep 100 msecs
74 }
75 // Count 2 should still be zero since no thread should have gone past the barrier.
Orion Hodson88591fe2018-03-06 13:35:43 +000076 EXPECT_EQ(0, count2.load(std::memory_order_relaxed));
Hans Boehm5567c112014-12-02 18:31:31 -080077 // Perform one additional Wait(), allowing pool threads to proceed.
78 barrier.Wait(self);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070079 // Wait for all the threads to finish.
Ian Rogers1d54e732013-05-02 21:10:01 -070080 thread_pool.Wait(self, true, false);
Hans Boehm5567c112014-12-02 18:31:31 -080081 // Both counts should be equal to num_threads now.
Orion Hodson88591fe2018-03-06 13:35:43 +000082 EXPECT_EQ(count1.load(std::memory_order_relaxed), num_threads);
83 EXPECT_EQ(count2.load(std::memory_order_relaxed), num_threads);
Hans Boehm5567c112014-12-02 18:31:31 -080084 timeout_barrier.Init(self, 0); // Reset to zero for destruction.
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070085}
86
Mathieu Chartier02b6a782012-10-26 13:51:26 -070087class CheckPassTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070088 public:
Mathieu Chartier02b6a782012-10-26 13:51:26 -070089 CheckPassTask(Barrier* barrier, AtomicInteger* count, size_t subtasks)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070090 : barrier_(barrier),
91 count_(count),
Brian Carlstrom0cd7ec22013-07-17 23:40:20 -070092 subtasks_(subtasks) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070093
Andreas Gampefa6a1b02018-09-07 08:11:55 -070094 void Run(Thread* self) override {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070095 for (size_t i = 0; i < subtasks_; ++i) {
96 ++*count_;
97 // Pass through to next subtask.
98 barrier_->Pass(self);
99 }
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700100 }
101
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700102 void Finalize() override {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700103 delete this;
104 }
105 private:
106 Barrier* const barrier_;
107 AtomicInteger* const count_;
108 const size_t subtasks_;
109};
110
111// Check that barrier pass through works.
112TEST_F(BarrierTest, CheckPass) {
113 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -0800114 ThreadPool thread_pool("Barrier test thread pool", num_threads);
Mathieu Chartier35883cc2012-11-13 14:08:12 -0800115 Barrier barrier(0);
Brian Carlstrom93ba8932013-07-17 21:31:49 -0700116 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700117 const int32_t num_tasks = num_threads * 4;
118 const int32_t num_sub_tasks = 128;
119 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700120 thread_pool.AddTask(self, new CheckPassTask(&barrier, &count, num_sub_tasks));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700121 }
122 thread_pool.StartWorkers(self);
123 const int32_t expected_total_tasks = num_sub_tasks * num_tasks;
124 // Wait for all the tasks to complete using the barrier.
125 barrier.Increment(self, expected_total_tasks);
126 // The total number of completed tasks should be equal to expected_total_tasks.
Orion Hodson88591fe2018-03-06 13:35:43 +0000127 EXPECT_EQ(count.load(std::memory_order_relaxed), expected_total_tasks);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700128}
129
130} // namespace art