C++程序  |  221行  |  4.85 KB

/*-------------------------------------------------------------------------
 * drawElements C++ Base Library
 * -----------------------------
 *
 * Copyright 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Fast ordered append-only container
 *//*--------------------------------------------------------------------*/

#include "deAppendList.hpp"
#include "deThread.hpp"
#include "deSpinBarrier.hpp"
#include "deSharedPtr.hpp"

#include <vector>
#include <algorithm>

namespace de
{

namespace
{

using std::vector;

struct TestElem
{
	deUint32	threadNdx;
	deUint32	elemNdx;

	TestElem (deUint32 threadNdx_, deUint32 elemNdx_)
		: threadNdx	(threadNdx_)
		, elemNdx	(elemNdx_)
	{}

	TestElem (void)
		: threadNdx	(0)
		, elemNdx	(0)
	{}
};

struct SharedState
{
	deUint32				numElements;
	SpinBarrier				barrier;
	AppendList<TestElem>	testList;

	SharedState (deUint32 numThreads, deUint32 numElements_, deUint32 numElementsHint)
		: numElements	(numElements_)
		, barrier		(numThreads)
		, testList		(numElementsHint)
	{}
};

class TestThread : public Thread
{
public:
	TestThread (SharedState* shared, deUint32 threadNdx)
		: m_shared		(shared)
		, m_threadNdx	(threadNdx)
	{}

	void run (void)
	{
		const deUint32	syncPerElems	= 10000;

		for (deUint32 elemNdx = 0; elemNdx < m_shared->numElements; elemNdx++)
		{
			if (elemNdx % syncPerElems == 0)
				m_shared->barrier.sync(SpinBarrier::WAIT_MODE_AUTO);

			m_shared->testList.append(TestElem(m_threadNdx, elemNdx));
		}
	}

private:
	SharedState* const	m_shared;
	const deUint32		m_threadNdx;
};

typedef SharedPtr<TestThread> TestThreadSp;

void runAppendListTest (deUint32 numThreads, deUint32 numElements, deUint32 numElementsHint)
{
	SharedState				sharedState		(numThreads, numElements, numElementsHint);
	vector<TestThreadSp>	threads			(numThreads);

	for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
	{
		threads[threadNdx] = TestThreadSp(new TestThread(&sharedState, threadNdx));
		threads[threadNdx]->start();
	}

	for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
		threads[threadNdx]->join();

	DE_TEST_ASSERT(sharedState.testList.size() == (size_t)numElements*(size_t)numThreads);

	{
		vector<deUint32>	countByThread	(numThreads);

		std::fill(countByThread.begin(), countByThread.end(), 0);

		for (AppendList<TestElem>::const_iterator elemIter = sharedState.testList.begin();
			 elemIter != sharedState.testList.end();
			 ++elemIter)
		{
			const TestElem&	elem	= *elemIter;

			DE_TEST_ASSERT(de::inBounds(elem.threadNdx, 0u, numThreads));
			DE_TEST_ASSERT(countByThread[elem.threadNdx] == elem.elemNdx);

			countByThread[elem.threadNdx] += 1;
		}

		for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
			DE_TEST_ASSERT(countByThread[threadNdx] == numElements);
	}
}

class ObjCountElem
{
public:
	ObjCountElem (int* liveCount)
		: m_liveCount(liveCount)
	{
		*m_liveCount += 1;
	}

	~ObjCountElem (void)
	{
		*m_liveCount -= 1;
	}

	ObjCountElem (const ObjCountElem& other)
		: m_liveCount(other.m_liveCount)
	{
		*m_liveCount += 1;
	}

	ObjCountElem& operator= (const ObjCountElem& other)
	{
		m_liveCount = other.m_liveCount;
		*m_liveCount += 1;
		return *this;
	}

private:
	int* m_liveCount;
};

void runClearTest (deUint32 numElements1, deUint32 numElements2, deUint32 numElementsHint)
{
	int		liveCount	= 0;

	{
		de::AppendList<ObjCountElem>	testList	(numElementsHint);

		for (deUint32 ndx = 0; ndx < numElements1; ++ndx)
			testList.append(ObjCountElem(&liveCount));

		DE_TEST_ASSERT(liveCount == (int)numElements1);

		testList.clear();

		DE_TEST_ASSERT(liveCount == 0);

		for (deUint32 ndx = 0; ndx < numElements2; ++ndx)
			testList.append(ObjCountElem(&liveCount));

		DE_TEST_ASSERT(liveCount == (int)numElements2);
	}

	DE_TEST_ASSERT(liveCount == 0);
}

} // anonymous

void AppendList_selfTest (void)
{
	// Single-threaded
	runAppendListTest(1, 1000, 500);
	runAppendListTest(1, 1000, 2000);
	runAppendListTest(1, 35, 1);

	// Multi-threaded
	runAppendListTest(2, 10000, 500);
	runAppendListTest(2, 100, 10);

	if (deGetNumAvailableLogicalCores() >= 4)
	{
		runAppendListTest(4, 10000, 500);
		runAppendListTest(4, 100, 10);
	}

	// Dtor + clear()
	runClearTest(1, 1, 1);
	runClearTest(1, 2, 10);
	runClearTest(50, 25, 10);
	runClearTest(9, 50, 10);
	runClearTest(10, 50, 10);
	runClearTest(50, 9, 10);
	runClearTest(50, 10, 10);
}

} // de