Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/barrier.h"
6 : #include "src/base/platform/platform.h"
7 : #include "src/base/platform/time.h"
8 : #include "testing/gtest/include/gtest/gtest.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 : namespace heap {
13 :
14 : namespace {
15 :
16 : // Large timeout that will not trigger in tests.
17 : constexpr base::TimeDelta test_timeout = base::TimeDelta::FromHours(3);
18 :
19 : } // namespace
20 :
21 15418 : TEST(OneshotBarrier, InitializeNotDone) {
22 : OneshotBarrier barrier(test_timeout);
23 : EXPECT_FALSE(barrier.DoneForTesting());
24 1 : }
25 :
26 15418 : TEST(OneshotBarrier, DoneAfterWait_Sequential) {
27 : OneshotBarrier barrier(test_timeout);
28 : barrier.Start();
29 1 : barrier.Wait();
30 1 : EXPECT_TRUE(barrier.DoneForTesting());
31 1 : }
32 :
33 : namespace {
34 :
35 4 : class ThreadWaitingOnBarrier final : public base::Thread {
36 : public:
37 : ThreadWaitingOnBarrier()
38 4 : : base::Thread(Options("ThreadWaitingOnBarrier")), barrier_(nullptr) {}
39 :
40 4 : void Initialize(OneshotBarrier* barrier) { barrier_ = barrier; }
41 :
42 4 : void Run() final { barrier_->Wait(); }
43 :
44 : private:
45 : OneshotBarrier* barrier_;
46 : };
47 :
48 : } // namespace
49 :
50 15418 : TEST(OneshotBarrier, DoneAfterWait_Concurrent) {
51 : const int kThreadCount = 2;
52 : OneshotBarrier barrier(test_timeout);
53 8 : ThreadWaitingOnBarrier threads[kThreadCount];
54 5 : for (int i = 0; i < kThreadCount; i++) {
55 2 : threads[i].Initialize(&barrier);
56 : // All threads need to call Wait() to be done.
57 : barrier.Start();
58 : }
59 5 : for (int i = 0; i < kThreadCount; i++) {
60 2 : threads[i].Start();
61 : }
62 5 : for (int i = 0; i < kThreadCount; i++) {
63 2 : threads[i].Join();
64 : }
65 1 : EXPECT_TRUE(barrier.DoneForTesting());
66 1 : }
67 :
68 15418 : TEST(OneshotBarrier, EarlyFinish_Concurrent) {
69 : const int kThreadCount = 2;
70 : OneshotBarrier barrier(test_timeout);
71 8 : ThreadWaitingOnBarrier threads[kThreadCount];
72 : // Test that one thread that actually finishes processing work before other
73 : // threads call Start() will move the barrier in Done state.
74 : barrier.Start();
75 1 : barrier.Wait();
76 1 : EXPECT_TRUE(barrier.DoneForTesting());
77 5 : for (int i = 0; i < kThreadCount; i++) {
78 2 : threads[i].Initialize(&barrier);
79 : // All threads need to call Wait() to be done.
80 : barrier.Start();
81 : }
82 5 : for (int i = 0; i < kThreadCount; i++) {
83 2 : threads[i].Start();
84 : }
85 5 : for (int i = 0; i < kThreadCount; i++) {
86 2 : threads[i].Join();
87 : }
88 1 : EXPECT_TRUE(barrier.DoneForTesting());
89 1 : }
90 :
91 : namespace {
92 :
93 1 : class CountingThread final : public base::Thread {
94 : public:
95 : CountingThread(OneshotBarrier* barrier, base::Mutex* mutex, size_t* work)
96 : : base::Thread(Options("CountingThread")),
97 : barrier_(barrier),
98 : mutex_(mutex),
99 : work_(work),
100 1 : processed_work_(0) {}
101 :
102 1 : void Run() final {
103 1 : do {
104 1 : ProcessWork();
105 1 : } while (!barrier_->Wait());
106 : // Main thread is not processing work, so we need one last step.
107 1 : ProcessWork();
108 1 : }
109 :
110 : size_t processed_work() const { return processed_work_; }
111 :
112 : private:
113 2 : void ProcessWork() {
114 2 : base::MutexGuard guard(mutex_);
115 2 : processed_work_ += *work_;
116 2 : *work_ = 0;
117 2 : }
118 :
119 : OneshotBarrier* const barrier_;
120 : base::Mutex* const mutex_;
121 : size_t* const work_;
122 : size_t processed_work_;
123 : };
124 :
125 : } // namespace
126 :
127 15418 : TEST(OneshotBarrier, Processing_Concurrent) {
128 1 : const size_t kWorkCounter = 173173;
129 : OneshotBarrier barrier(test_timeout);
130 2 : base::Mutex mutex;
131 1 : size_t work = 0;
132 : CountingThread counting_thread(&barrier, &mutex, &work);
133 : barrier.Start();
134 : barrier.Start();
135 2 : EXPECT_FALSE(barrier.DoneForTesting());
136 1 : counting_thread.Start();
137 :
138 346347 : for (size_t i = 0; i < kWorkCounter; i++) {
139 : {
140 : base::MutexGuard guard(&mutex);
141 173173 : work++;
142 : }
143 173173 : barrier.NotifyAll();
144 : }
145 1 : barrier.Wait();
146 1 : counting_thread.Join();
147 1 : EXPECT_TRUE(barrier.DoneForTesting());
148 2 : EXPECT_EQ(kWorkCounter, counting_thread.processed_work());
149 1 : }
150 :
151 : } // namespace heap
152 : } // namespace internal
153 9249 : } // namespace v8
|