pcsx-redux/third_party/EASTL/benchmark/source/BenchmarkSet.cpp
Nicolas 'Pixel' Noble d63f87a7f4 Adding EASTL.
2022-06-29 19:37:35 -07:00

353 lines
10 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#include "EASTLBenchmark.h"
#include "EASTLTest.h"
#include <EAStdC/EAStopwatch.h>
#include <EASTL/set.h>
#include <EASTL/vector.h>
#include <EASTL/algorithm.h>
EA_DISABLE_ALL_VC_WARNINGS()
#include <set>
#include <algorithm>
EA_RESTORE_ALL_VC_WARNINGS()
using namespace EA;
typedef std::set<uint32_t> StdSetUint32;
typedef eastl::set<uint32_t> EaSetUint32;
namespace
{
template <typename Container>
void TestInsert(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
stopwatch.Restart();
c.insert(pArrayBegin, pArrayEnd);
stopwatch.Stop();
// Intentionally push back a high uint32_t value. We do this so that
// later upper_bound, lower_bound and equal_range never return end().
c.insert(0xffffffff);
}
template <typename Container>
void TestIteration(EA::StdC::Stopwatch& stopwatch, const Container& c)
{
stopwatch.Restart();
typename Container::const_iterator it = eastl::find(c.begin(), c.end(), uint32_t(9999999));
stopwatch.Stop();
if(it != c.end())
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)*it);
}
template <typename Container>
void TestFind(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
uint32_t temp = 0;
typename Container::iterator it;
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
{
it = c.find(*pArrayBegin++);
temp += *it;
}
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)temp);
}
template <typename Container>
void TestCount(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
typename Container::size_type temp = 0;
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
temp += c.count(*pArrayBegin++);
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)temp);
}
template <typename Container>
void TestLowerBound(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
uint32_t temp = 0;
typename Container::iterator it;
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
{
it = c.lower_bound(*pArrayBegin++);
temp += *it; // We know that it != end because earlier we inserted 0xffffffff.
}
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)temp);
}
template <typename Container>
void TestUpperBound(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
uint32_t temp = 0;
typename Container::iterator it;
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
{
it = c.upper_bound(*pArrayBegin++);
temp += *it; // We know that it != end because earlier we inserted 0xffffffff.
}
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)temp);
}
template <typename Container>
void TestEqualRange(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
uint32_t temp = 0;
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
{
temp += *(c.equal_range(*pArrayBegin++).first); // We know that it != end because earlier we inserted 0xffffffff.
}
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)temp);
}
template <typename Container>
void TestEraseValue(EA::StdC::Stopwatch& stopwatch, Container& c, const uint32_t* pArrayBegin, const uint32_t* pArrayEnd)
{
stopwatch.Restart();
while(pArrayBegin != pArrayEnd)
c.erase(*pArrayBegin++);
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)c.size());
}
template <typename Container>
void TestErasePosition(EA::StdC::Stopwatch& stopwatch, Container& c)
{
typename Container::size_type j, jEnd;
typename Container::iterator it;
stopwatch.Restart();
for(j = 0, jEnd = c.size() / 3, it = c.begin(); j < jEnd; ++j)
{
// The erase fucntion is supposed to return an iterator, but the C++ standard was
// not initially clear about it and some STL implementations don't do it correctly.
#if (((defined(_MSC_VER) || defined(_CPPLIB_VER)) && !defined(_HAS_STRICT_CONFORMANCE))) // _CPPLIB_VER is something defined by Dinkumware STL.
it = c.erase(it);
#else
// This pathway may execute at a slightly different speed than the
// standard behaviour, but that's fine for the benchmark because the
// benchmark is measuring the speed of erasing while iterating, and
// however it needs to get done by the given STL is how it is measured.
const typename Container::iterator itErase(it++);
c.erase(itErase);
#endif
++it;
++it;
}
stopwatch.Stop();
}
template <typename Container>
void TestEraseRange(EA::StdC::Stopwatch& stopwatch, Container& c)
{
typename Container::size_type j, jEnd;
typename Container::iterator it1 = c.begin();
typename Container::iterator it2 = c.begin();
for(j = 0, jEnd = c.size() / 3; j < jEnd; ++j)
++it2;
stopwatch.Restart();
c.erase(it1, it2);
stopwatch.Stop();
}
template <typename Container>
void TestClear(EA::StdC::Stopwatch& stopwatch, Container& c)
{
stopwatch.Restart();
c.clear();
stopwatch.Stop();
sprintf(Benchmark::gScratchBuffer, "%u", (unsigned)c.size());
}
} // namespace
void BenchmarkSet()
{
EASTLTest_Printf("Set\n");
EA::UnitTest::Rand rng(EA::UnitTest::GetRandSeed());
EA::StdC::Stopwatch stopwatch1(EA::StdC::Stopwatch::kUnitsCPUCycles);
EA::StdC::Stopwatch stopwatch2(EA::StdC::Stopwatch::kUnitsCPUCycles);
{
eastl::vector<uint32_t> intVector(10000);
for(eastl_size_t i = 0, iEnd = intVector.size(); i < iEnd; i++)
intVector[i] = (uint32_t)rng.RandLimit(((uint32_t)iEnd / 2)); // This will result in duplicates and even a few triplicates.
for(int i = 0; i < 2; i++)
{
StdSetUint32 stdSetUint32;
EaSetUint32 eaSetUint32;
///////////////////////////////
// Test insert(const value_type&)
///////////////////////////////
TestInsert(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestInsert(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/insert", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test iteration
///////////////////////////////
TestIteration(stopwatch1, stdSetUint32);
TestIteration(stopwatch2, eaSetUint32);
if(i == 1)
Benchmark::AddResult("set<uint32_t>/iteration", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test find
///////////////////////////////
TestFind(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestFind(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/find", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test count
///////////////////////////////
TestCount(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestCount(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/count", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test lower_bound
///////////////////////////////
TestLowerBound(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestLowerBound(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/lower_bound", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test upper_bound
///////////////////////////////
TestUpperBound(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestUpperBound(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/upper_bound", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test equal_range
///////////////////////////////
TestEqualRange(stopwatch1, stdSetUint32, intVector.data(), intVector.data() + intVector.size());
TestEqualRange(stopwatch2, eaSetUint32, intVector.data(), intVector.data() + intVector.size());
if(i == 1)
Benchmark::AddResult("set<uint32_t>/equal_range", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test erase(const key_type& key)
///////////////////////////////
TestEraseValue(stopwatch1, stdSetUint32, &intVector[0], &intVector[intVector.size() / 2]);
TestEraseValue(stopwatch2, eaSetUint32, &intVector[0], &intVector[intVector.size() / 2]);
if(i == 1)
Benchmark::AddResult("set<uint32_t>/erase/val", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test erase(iterator position)
///////////////////////////////
TestErasePosition(stopwatch1, stdSetUint32);
TestErasePosition(stopwatch2, eaSetUint32);
if(i == 1)
Benchmark::AddResult("set<uint32_t>/erase/pos", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime(),
GetStdSTLType() == kSTLMS ? "MS uses a code bloating implementation of erase." : NULL);
///////////////////////////////
// Test erase(iterator first, iterator last)
///////////////////////////////
TestEraseRange(stopwatch1, stdSetUint32);
TestEraseRange(stopwatch2, eaSetUint32);
if(i == 1)
Benchmark::AddResult("set<uint32_t>/erase range", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
///////////////////////////////
// Test clear()
///////////////////////////////
TestClear(stopwatch1, stdSetUint32);
TestClear(stopwatch2, eaSetUint32);
if(i == 1)
Benchmark::AddResult("set<uint32_t>/clear", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
}
}
}