1 // Copyright 2019 The Marl Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "marl_test.h"
16 
17 #include "marl/memory.h"
18 #include "marl/pool.h"
19 #include "marl/waitgroup.h"
20 
TEST_P(WithBoundScheduler,UnboundedPool_ConstructDestruct)21 TEST_P(WithBoundScheduler, UnboundedPool_ConstructDestruct) {
22   marl::UnboundedPool<int> pool;
23 }
24 
TEST_P(WithBoundScheduler,BoundedPool_ConstructDestruct)25 TEST_P(WithBoundScheduler, BoundedPool_ConstructDestruct) {
26   marl::BoundedPool<int, 10> pool;
27 }
28 
TEST_P(WithBoundScheduler,UnboundedPoolLoan_GetNull)29 TEST_P(WithBoundScheduler, UnboundedPoolLoan_GetNull) {
30   marl::UnboundedPool<int>::Loan loan;
31   ASSERT_EQ(loan.get(), nullptr);
32 }
33 
TEST_P(WithBoundScheduler,BoundedPoolLoan_GetNull)34 TEST_P(WithBoundScheduler, BoundedPoolLoan_GetNull) {
35   marl::BoundedPool<int, 10>::Loan loan;
36   ASSERT_EQ(loan.get(), nullptr);
37 }
38 
TEST_P(WithBoundScheduler,UnboundedPool_Borrow)39 TEST_P(WithBoundScheduler, UnboundedPool_Borrow) {
40   marl::UnboundedPool<int> pool;
41   for (int i = 0; i < 100; i++) {
42     pool.borrow();
43   }
44 }
45 
TEST_P(WithBoundScheduler,UnboundedPool_ConcurrentBorrow)46 TEST_P(WithBoundScheduler, UnboundedPool_ConcurrentBorrow) {
47   marl::UnboundedPool<int> pool;
48   constexpr int iterations = 10000;
49   marl::WaitGroup wg(iterations);
50   for (int i = 0; i < iterations; i++) {
51     marl::schedule([=] {
52       pool.borrow();
53       wg.done();
54     });
55   }
56   wg.wait();
57 }
58 
TEST_P(WithBoundScheduler,BoundedPool_Borrow)59 TEST_P(WithBoundScheduler, BoundedPool_Borrow) {
60   marl::BoundedPool<int, 100> pool;
61   for (int i = 0; i < 100; i++) {
62     pool.borrow();
63   }
64 }
65 
TEST_P(WithBoundScheduler,BoundedPool_ConcurrentBorrow)66 TEST_P(WithBoundScheduler, BoundedPool_ConcurrentBorrow) {
67   marl::BoundedPool<int, 10> pool;
68   constexpr int iterations = 10000;
69   marl::WaitGroup wg(iterations);
70   for (int i = 0; i < iterations; i++) {
71     marl::schedule([=] {
72       pool.borrow();
73       wg.done();
74     });
75   }
76   wg.wait();
77 }
78 
79 struct CtorDtorCounter {
CtorDtorCounterCtorDtorCounter80   CtorDtorCounter() { ctor_count++; }
~CtorDtorCounterCtorDtorCounter81   ~CtorDtorCounter() { dtor_count++; }
resetCtorDtorCounter82   static void reset() {
83     ctor_count = 0;
84     dtor_count = 0;
85   }
86   static int ctor_count;
87   static int dtor_count;
88 };
89 
90 int CtorDtorCounter::ctor_count = -1;
91 int CtorDtorCounter::dtor_count = -1;
92 
TEST_P(WithBoundScheduler,UnboundedPool_PolicyReconstruct)93 TEST_P(WithBoundScheduler, UnboundedPool_PolicyReconstruct) {
94   CtorDtorCounter::reset();
95   marl::UnboundedPool<CtorDtorCounter, marl::PoolPolicy::Reconstruct> pool;
96   ASSERT_EQ(CtorDtorCounter::ctor_count, 0);
97   ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
98   {
99     auto loan = pool.borrow();
100     ASSERT_EQ(CtorDtorCounter::ctor_count, 1);
101     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
102   }
103   ASSERT_EQ(CtorDtorCounter::ctor_count, 1);
104   ASSERT_EQ(CtorDtorCounter::dtor_count, 1);
105   {
106     auto loan = pool.borrow();
107     ASSERT_EQ(CtorDtorCounter::ctor_count, 2);
108     ASSERT_EQ(CtorDtorCounter::dtor_count, 1);
109   }
110   ASSERT_EQ(CtorDtorCounter::ctor_count, 2);
111   ASSERT_EQ(CtorDtorCounter::dtor_count, 2);
112 }
113 
TEST_P(WithBoundScheduler,BoundedPool_PolicyReconstruct)114 TEST_P(WithBoundScheduler, BoundedPool_PolicyReconstruct) {
115   CtorDtorCounter::reset();
116   marl::BoundedPool<CtorDtorCounter, 10, marl::PoolPolicy::Reconstruct> pool;
117   ASSERT_EQ(CtorDtorCounter::ctor_count, 0);
118   ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
119   {
120     auto loan = pool.borrow();
121     ASSERT_EQ(CtorDtorCounter::ctor_count, 1);
122     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
123   }
124   ASSERT_EQ(CtorDtorCounter::ctor_count, 1);
125   ASSERT_EQ(CtorDtorCounter::dtor_count, 1);
126   {
127     auto loan = pool.borrow();
128     ASSERT_EQ(CtorDtorCounter::ctor_count, 2);
129     ASSERT_EQ(CtorDtorCounter::dtor_count, 1);
130   }
131   ASSERT_EQ(CtorDtorCounter::ctor_count, 2);
132   ASSERT_EQ(CtorDtorCounter::dtor_count, 2);
133 }
134 
TEST_P(WithBoundScheduler,UnboundedPool_PolicyPreserve)135 TEST_P(WithBoundScheduler, UnboundedPool_PolicyPreserve) {
136   CtorDtorCounter::reset();
137   {
138     marl::UnboundedPool<CtorDtorCounter, marl::PoolPolicy::Preserve> pool;
139     int ctor_count;
140     {
141       auto loan = pool.borrow();
142       ASSERT_NE(CtorDtorCounter::ctor_count, 0);
143       ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
144       ctor_count = CtorDtorCounter::ctor_count;
145     }
146     ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
147     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
148     {
149       auto loan = pool.borrow();
150       ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
151       ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
152     }
153     ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
154     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
155   }
156   ASSERT_EQ(CtorDtorCounter::ctor_count, CtorDtorCounter::dtor_count);
157 }
158 
TEST_P(WithBoundScheduler,BoundedPool_PolicyPreserve)159 TEST_P(WithBoundScheduler, BoundedPool_PolicyPreserve) {
160   CtorDtorCounter::reset();
161   {
162     marl::BoundedPool<CtorDtorCounter, 10, marl::PoolPolicy::Preserve> pool;
163     int ctor_count;
164     {
165       auto loan = pool.borrow();
166       ASSERT_NE(CtorDtorCounter::ctor_count, 0);
167       ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
168       ctor_count = CtorDtorCounter::ctor_count;
169     }
170     ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
171     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
172     {
173       auto loan = pool.borrow();
174       ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
175       ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
176     }
177     ASSERT_EQ(CtorDtorCounter::ctor_count, ctor_count);
178     ASSERT_EQ(CtorDtorCounter::dtor_count, 0);
179   }
180   ASSERT_EQ(CtorDtorCounter::ctor_count, CtorDtorCounter::dtor_count);
181 }
182 
183 struct alignas(64) StructWithAlignment {
184   uint8_t i;
185   uint8_t padding[63];
186 };
187 
TEST_P(WithBoundScheduler,BoundedPool_AlignedTypes)188 TEST_P(WithBoundScheduler, BoundedPool_AlignedTypes) {
189   marl::BoundedPool<StructWithAlignment, 100> pool;
190   for (int i = 0; i < 100; i++) {
191     auto loan = pool.borrow();
192     ASSERT_EQ(reinterpret_cast<uintptr_t>(&loan->i) &
193                   (alignof(StructWithAlignment) - 1),
194               0U);
195   }
196 }
197 
TEST_P(WithBoundScheduler,UnboundedPool_AlignedTypes)198 TEST_P(WithBoundScheduler, UnboundedPool_AlignedTypes) {
199   marl::UnboundedPool<StructWithAlignment> pool;
200   for (int i = 0; i < 100; i++) {
201     auto loan = pool.borrow();
202     ASSERT_EQ(reinterpret_cast<uintptr_t>(&loan->i) &
203                   (alignof(StructWithAlignment) - 1),
204               0U);
205   }
206 }
207