1 /*-------------------------------------------------------------------------
2 * drawElements C++ Base Library
3 * -----------------------------
4 *
5 * Copyright 2015 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Fast ordered append-only container
22 *//*--------------------------------------------------------------------*/
23
24 #include "deAppendList.hpp"
25 #include "deThread.hpp"
26 #include "deSpinBarrier.hpp"
27 #include "deSharedPtr.hpp"
28
29 #include <vector>
30 #include <algorithm>
31
32 namespace de
33 {
34
35 namespace
36 {
37
38 using std::vector;
39
40 struct TestElem
41 {
42 uint32_t threadNdx;
43 uint32_t elemNdx;
44
TestElemde::__anon367df1c80111::TestElem45 TestElem(uint32_t threadNdx_, uint32_t elemNdx_) : threadNdx(threadNdx_), elemNdx(elemNdx_)
46 {
47 }
48
TestElemde::__anon367df1c80111::TestElem49 TestElem(void) : threadNdx(0), elemNdx(0)
50 {
51 }
52 };
53
54 struct SharedState
55 {
56 uint32_t numElements;
57 SpinBarrier barrier;
58 AppendList<TestElem> testList;
59
SharedStatede::__anon367df1c80111::SharedState60 SharedState(uint32_t numThreads, uint32_t numElements_, uint32_t numElementsHint)
61 : numElements(numElements_)
62 , barrier(numThreads)
63 , testList(numElementsHint)
64 {
65 }
66 };
67
68 class TestThread : public Thread
69 {
70 public:
TestThread(SharedState * shared,uint32_t threadNdx)71 TestThread(SharedState *shared, uint32_t threadNdx) : m_shared(shared), m_threadNdx(threadNdx)
72 {
73 }
74
run(void)75 void run(void)
76 {
77 const uint32_t syncPerElems = 10000;
78
79 for (uint32_t elemNdx = 0; elemNdx < m_shared->numElements; elemNdx++)
80 {
81 if (elemNdx % syncPerElems == 0)
82 m_shared->barrier.sync(SpinBarrier::WAIT_MODE_AUTO);
83
84 m_shared->testList.append(TestElem(m_threadNdx, elemNdx));
85 }
86 }
87
88 private:
89 SharedState *const m_shared;
90 const uint32_t m_threadNdx;
91 };
92
93 typedef SharedPtr<TestThread> TestThreadSp;
94
runAppendListTest(uint32_t numThreads,uint32_t numElements,uint32_t numElementsHint)95 void runAppendListTest(uint32_t numThreads, uint32_t numElements, uint32_t numElementsHint)
96 {
97 SharedState sharedState(numThreads, numElements, numElementsHint);
98 vector<TestThreadSp> threads(numThreads);
99
100 for (uint32_t threadNdx = 0; threadNdx < numThreads; ++threadNdx)
101 {
102 threads[threadNdx] = TestThreadSp(new TestThread(&sharedState, threadNdx));
103 threads[threadNdx]->start();
104 }
105
106 for (uint32_t threadNdx = 0; threadNdx < numThreads; ++threadNdx)
107 threads[threadNdx]->join();
108
109 DE_TEST_ASSERT(sharedState.testList.size() == (size_t)numElements * (size_t)numThreads);
110
111 {
112 vector<uint32_t> countByThread(numThreads);
113
114 std::fill(countByThread.begin(), countByThread.end(), 0);
115
116 for (AppendList<TestElem>::const_iterator elemIter = sharedState.testList.begin();
117 elemIter != sharedState.testList.end(); ++elemIter)
118 {
119 const TestElem &elem = *elemIter;
120
121 DE_TEST_ASSERT(de::inBounds(elem.threadNdx, 0u, numThreads));
122 DE_TEST_ASSERT(countByThread[elem.threadNdx] == elem.elemNdx);
123
124 countByThread[elem.threadNdx] += 1;
125 }
126
127 for (uint32_t threadNdx = 0; threadNdx < numThreads; ++threadNdx)
128 DE_TEST_ASSERT(countByThread[threadNdx] == numElements);
129 }
130 }
131
132 class ObjCountElem
133 {
134 public:
ObjCountElem(int * liveCount)135 ObjCountElem(int *liveCount) : m_liveCount(liveCount)
136 {
137 *m_liveCount += 1;
138 }
139
~ObjCountElem(void)140 ~ObjCountElem(void)
141 {
142 *m_liveCount -= 1;
143 }
144
ObjCountElem(const ObjCountElem & other)145 ObjCountElem(const ObjCountElem &other) : m_liveCount(other.m_liveCount)
146 {
147 *m_liveCount += 1;
148 }
149
operator =(const ObjCountElem & other)150 ObjCountElem &operator=(const ObjCountElem &other)
151 {
152 m_liveCount = other.m_liveCount;
153 *m_liveCount += 1;
154 return *this;
155 }
156
157 private:
158 int *m_liveCount;
159 };
160
runClearTest(uint32_t numElements1,uint32_t numElements2,uint32_t numElementsHint)161 void runClearTest(uint32_t numElements1, uint32_t numElements2, uint32_t numElementsHint)
162 {
163 int liveCount = 0;
164
165 {
166 de::AppendList<ObjCountElem> testList(numElementsHint);
167
168 for (uint32_t ndx = 0; ndx < numElements1; ++ndx)
169 testList.append(ObjCountElem(&liveCount));
170
171 DE_TEST_ASSERT(liveCount == (int)numElements1);
172
173 testList.clear();
174
175 DE_TEST_ASSERT(liveCount == 0);
176
177 for (uint32_t ndx = 0; ndx < numElements2; ++ndx)
178 testList.append(ObjCountElem(&liveCount));
179
180 DE_TEST_ASSERT(liveCount == (int)numElements2);
181 }
182
183 DE_TEST_ASSERT(liveCount == 0);
184 }
185
186 } // namespace
187
AppendList_selfTest(void)188 void AppendList_selfTest(void)
189 {
190 // Single-threaded
191 runAppendListTest(1, 1000, 500);
192 runAppendListTest(1, 1000, 2000);
193 runAppendListTest(1, 35, 1);
194
195 // Multi-threaded
196 runAppendListTest(2, 10000, 500);
197 runAppendListTest(2, 100, 10);
198
199 if (deGetNumAvailableLogicalCores() >= 4)
200 {
201 runAppendListTest(4, 10000, 500);
202 runAppendListTest(4, 100, 10);
203 }
204
205 // Dtor + clear()
206 runClearTest(1, 1, 1);
207 runClearTest(1, 2, 10);
208 runClearTest(50, 25, 10);
209 runClearTest(9, 50, 10);
210 runClearTest(10, 50, 10);
211 runClearTest(50, 9, 10);
212 runClearTest(50, 10, 10);
213 }
214
215 } // namespace de
216