Home | History | Annotate | Download | only in decpp
      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 	deUint32	threadNdx;
     43 	deUint32	elemNdx;
     44 
     45 	TestElem (deUint32 threadNdx_, deUint32 elemNdx_)
     46 		: threadNdx	(threadNdx_)
     47 		, elemNdx	(elemNdx_)
     48 	{}
     49 
     50 	TestElem (void)
     51 		: threadNdx	(0)
     52 		, elemNdx	(0)
     53 	{}
     54 };
     55 
     56 struct SharedState
     57 {
     58 	deUint32				numElements;
     59 	SpinBarrier				barrier;
     60 	AppendList<TestElem>	testList;
     61 
     62 	SharedState (deUint32 numThreads, deUint32 numElements_, deUint32 numElementsHint)
     63 		: numElements	(numElements_)
     64 		, barrier		(numThreads)
     65 		, testList		(numElementsHint)
     66 	{}
     67 };
     68 
     69 class TestThread : public Thread
     70 {
     71 public:
     72 	TestThread (SharedState* shared, deUint32 threadNdx)
     73 		: m_shared		(shared)
     74 		, m_threadNdx	(threadNdx)
     75 	{}
     76 
     77 	void run (void)
     78 	{
     79 		const deUint32	syncPerElems	= 10000;
     80 
     81 		for (deUint32 elemNdx = 0; elemNdx < m_shared->numElements; elemNdx++)
     82 		{
     83 			if (elemNdx % syncPerElems == 0)
     84 				m_shared->barrier.sync(SpinBarrier::WAIT_MODE_AUTO);
     85 
     86 			m_shared->testList.append(TestElem(m_threadNdx, elemNdx));
     87 		}
     88 	}
     89 
     90 private:
     91 	SharedState* const	m_shared;
     92 	const deUint32		m_threadNdx;
     93 };
     94 
     95 typedef SharedPtr<TestThread> TestThreadSp;
     96 
     97 void runAppendListTest (deUint32 numThreads, deUint32 numElements, deUint32 numElementsHint)
     98 {
     99 	SharedState				sharedState		(numThreads, numElements, numElementsHint);
    100 	vector<TestThreadSp>	threads			(numThreads);
    101 
    102 	for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
    103 	{
    104 		threads[threadNdx] = TestThreadSp(new TestThread(&sharedState, threadNdx));
    105 		threads[threadNdx]->start();
    106 	}
    107 
    108 	for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
    109 		threads[threadNdx]->join();
    110 
    111 	DE_TEST_ASSERT(sharedState.testList.size() == (size_t)numElements*(size_t)numThreads);
    112 
    113 	{
    114 		vector<deUint32>	countByThread	(numThreads);
    115 
    116 		std::fill(countByThread.begin(), countByThread.end(), 0);
    117 
    118 		for (AppendList<TestElem>::const_iterator elemIter = sharedState.testList.begin();
    119 			 elemIter != sharedState.testList.end();
    120 			 ++elemIter)
    121 		{
    122 			const TestElem&	elem	= *elemIter;
    123 
    124 			DE_TEST_ASSERT(de::inBounds(elem.threadNdx, 0u, numThreads));
    125 			DE_TEST_ASSERT(countByThread[elem.threadNdx] == elem.elemNdx);
    126 
    127 			countByThread[elem.threadNdx] += 1;
    128 		}
    129 
    130 		for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
    131 			DE_TEST_ASSERT(countByThread[threadNdx] == numElements);
    132 	}
    133 }
    134 
    135 class ObjCountElem
    136 {
    137 public:
    138 	ObjCountElem (int* liveCount)
    139 		: m_liveCount(liveCount)
    140 	{
    141 		*m_liveCount += 1;
    142 	}
    143 
    144 	~ObjCountElem (void)
    145 	{
    146 		*m_liveCount -= 1;
    147 	}
    148 
    149 	ObjCountElem (const ObjCountElem& other)
    150 		: m_liveCount(other.m_liveCount)
    151 	{
    152 		*m_liveCount += 1;
    153 	}
    154 
    155 	ObjCountElem& operator= (const ObjCountElem& other)
    156 	{
    157 		m_liveCount = other.m_liveCount;
    158 		*m_liveCount += 1;
    159 		return *this;
    160 	}
    161 
    162 private:
    163 	int* m_liveCount;
    164 };
    165 
    166 void runClearTest (deUint32 numElements1, deUint32 numElements2, deUint32 numElementsHint)
    167 {
    168 	int		liveCount	= 0;
    169 
    170 	{
    171 		de::AppendList<ObjCountElem>	testList	(numElementsHint);
    172 
    173 		for (deUint32 ndx = 0; ndx < numElements1; ++ndx)
    174 			testList.append(ObjCountElem(&liveCount));
    175 
    176 		DE_TEST_ASSERT(liveCount == (int)numElements1);
    177 
    178 		testList.clear();
    179 
    180 		DE_TEST_ASSERT(liveCount == 0);
    181 
    182 		for (deUint32 ndx = 0; ndx < numElements2; ++ndx)
    183 			testList.append(ObjCountElem(&liveCount));
    184 
    185 		DE_TEST_ASSERT(liveCount == (int)numElements2);
    186 	}
    187 
    188 	DE_TEST_ASSERT(liveCount == 0);
    189 }
    190 
    191 } // anonymous
    192 
    193 void AppendList_selfTest (void)
    194 {
    195 	// Single-threaded
    196 	runAppendListTest(1, 1000, 500);
    197 	runAppendListTest(1, 1000, 2000);
    198 	runAppendListTest(1, 35, 1);
    199 
    200 	// Multi-threaded
    201 	runAppendListTest(2, 10000, 500);
    202 	runAppendListTest(2, 100, 10);
    203 
    204 	if (deGetNumAvailableLogicalCores() >= 4)
    205 	{
    206 		runAppendListTest(4, 10000, 500);
    207 		runAppendListTest(4, 100, 10);
    208 	}
    209 
    210 	// Dtor + clear()
    211 	runClearTest(1, 1, 1);
    212 	runClearTest(1, 2, 10);
    213 	runClearTest(50, 25, 10);
    214 	runClearTest(9, 50, 10);
    215 	runClearTest(10, 50, 10);
    216 	runClearTest(50, 9, 10);
    217 	runClearTest(50, 10, 10);
    218 }
    219 
    220 } // de
    221