221 lines
4.8 KiB
C++
221 lines
4.8 KiB
C++
/*-------------------------------------------------------------------------
|
|
* 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
|