Improved test for PagedVolume::Chunk performance.

This commit is contained in:
David Williams 2015-03-26 23:45:01 +01:00
parent 1d24b189ca
commit 322bedc009
3 changed files with 84 additions and 30 deletions

View File

@ -51,8 +51,12 @@ namespace PolyVox
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1);
Region reg(v3dLower, v3dUpper); Region reg(v3dLower, v3dUpper);
// Page the data in // A valid pager is normally present - this check is mostly to ease unit testing.
m_pPager->pageIn(reg, this); if (m_pPager)
{
// Page the data in
m_pPager->pageIn(reg, this);
}
// We'll use this later to decide if data needs to be paged out again. // We'll use this later to decide if data needs to be paged out again.
m_bDataModified = false; m_bDataModified = false;
@ -61,7 +65,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::Chunk::~Chunk() PagedVolume<VoxelType>::Chunk::~Chunk()
{ {
if (m_bDataModified) if (m_bDataModified && m_pPager)
{ {
// From the coordinates of the chunk we deduce the coordinates of the contained voxels. // From the coordinates of the chunk we deduce the coordinates of the contained voxels.
Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength); Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength);

View File

@ -268,15 +268,15 @@ TestVolume::TestVolume()
} }
// Note - We are reusing the FilePager for testing... watch out for conflicts with the main volume. // Note - We are reusing the FilePager for testing... watch out for conflicts with the main volume.
m_pPagedVolumeChunk = new PagedVolume<int32_t>::Chunk(Vector3DInt32(10000, 10000, 10000), m_uChunkSideLength, m_pFilePager); m_pPagedVolumeChunk = new PagedVolume<uint32_t>::Chunk(Vector3DInt32(10000, 10000, 10000), m_uChunkSideLength, nullptr);
int32_t i = 0; std::mt19937 rng;
for (uint16_t z = 0; z < m_uChunkSideLength; z++) for (uint16_t z = 0; z < m_uChunkSideLength; z++)
{ {
for (uint16_t y = 0; y < m_uChunkSideLength; y++) for (uint16_t y = 0; y < m_uChunkSideLength; y++)
{ {
for (uint16_t x = 0; x < m_uChunkSideLength; x++) for (uint16_t x = 0; x < m_uChunkSideLength; x++)
{ {
m_pPagedVolumeChunk->setVoxel(x, y, z, ++i); m_pPagedVolumeChunk->setVoxel(x, y, z, static_cast<uint32_t>(rng()));
} }
} }
} }
@ -468,30 +468,80 @@ void TestVolume::testPagedVolumeSamplersWithExternalBackwards()
QCOMPARE(result, static_cast<int32_t>(-993539594)); QCOMPARE(result, static_cast<int32_t>(-993539594));
} }
int32_t TestVolume::testPagedVolumeChunkAccess(uint32_t locality) int32_t TestVolume::testPagedVolumeChunkAccess(uint16_t localityMask)
{ {
std::mt19937 rng; std::mt19937 rng;
int32_t result = 0; int32_t sum = 0;
uint16_t x = rng() % m_uChunkSideLength; uint16_t x = 0;
uint16_t y = rng() % m_uChunkSideLength; uint16_t y = 0;
uint16_t z = rng() % m_uChunkSideLength; uint16_t z = 0;
for (uint32_t ct = 0; ct < 1000000; ct++) // Used to constrain the range, as '&=m_uChunkSideLengthMask' should be faster than '%=m_uChunkSideLength'.
uint16_t m_uChunkSideLengthMask = m_uChunkSideLength - 1;
for (int32_t ct = 0; ct < 1000000; ct++)
{ {
uint16_t xOffset = rng() % locality; // Random number generation is relatively slow compared to retireving a voxel, so if we are not
uint16_t yOffset = rng() % locality; // careful the process of choosing which voxel to get can become slower than actually getting it.
uint16_t zOffset = rng() % locality; // Therefore we use the same random number multiple times by getting different bits from it.
x += xOffset; uint32_t rand = rng();
y += yOffset;
z += zOffset; // We have 32 random bits and we make 27 (3*9) calls to getVoxel(). This means we
x %= m_uChunkSideLength; // stop using the lower bits before they all get set to zero from the right-shifting.
y %= m_uChunkSideLength; // An odd number means we have an imbalance between the number of times we go forward vs.
z %= m_uChunkSideLength; // backwards, so overall we will drift around the volume even if locality is constrained.
int32_t voxel = m_pPagedVolumeChunk->getVoxel(x, y, z); for (uint32_t i = 0; i < 3; i++)
result = cantorTupleFunction(result, voxel); {
x += rand & localityMask; // Move x forwardsby a small amount, limited by localityMask.
x &= m_uChunkSideLengthMask; // Ensure it is within the valid range.
sum += m_pPagedVolumeChunk->getVoxel(x, y, z); // Get the voxel value and use it.
rand >>= 1; // Shift the bits so we use different ones next time.
y -= rand & localityMask; // This one (and some others) are negative so sometimes we go backwards.
y &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
z += rand & localityMask;
z &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
x -= rand & localityMask;
x &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
y += rand & localityMask;
y &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
z -= rand & localityMask;
z &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
x += rand & localityMask;
x &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
y -= rand & localityMask;
y &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
z += rand & localityMask;
z &= m_uChunkSideLengthMask;
sum += m_pPagedVolumeChunk->getVoxel(x, y, z);
rand >>= 1;
}
} }
return result; // It's important to use the voxel values, otherwise
// the compiler optimizes out the calls to getVoxel().
return sum;
} }
void TestVolume::testPagedVolumeChunkLocalAccess() void TestVolume::testPagedVolumeChunkLocalAccess()
@ -499,9 +549,9 @@ void TestVolume::testPagedVolumeChunkLocalAccess()
int32_t result = 0; int32_t result = 0;
QBENCHMARK QBENCHMARK
{ {
result = testPagedVolumeChunkAccess(3); // Small value for good locality result = testPagedVolumeChunkAccess(0x0003); // Small value for good locality
} }
QCOMPARE(result, static_cast<int32_t>(145244783)); QCOMPARE(result, static_cast<int32_t>(1856742828));
} }
void TestVolume::testPagedVolumeChunkRandomAccess() void TestVolume::testPagedVolumeChunkRandomAccess()
@ -509,9 +559,9 @@ void TestVolume::testPagedVolumeChunkRandomAccess()
int32_t result = 0; int32_t result = 0;
QBENCHMARK QBENCHMARK
{ {
result = testPagedVolumeChunkAccess(1000000); // Large value for poor locality (random access) result = testPagedVolumeChunkAccess(0xFFFF); // Large value for poor locality (random access)
} }
QCOMPARE(result, static_cast<int32_t>(-254578110)); QCOMPARE(result, static_cast<int32_t>(1550197176));
} }
QTEST_MAIN(TestVolume) QTEST_MAIN(TestVolume)

View File

@ -61,7 +61,7 @@ private slots:
void testPagedVolumeChunkRandomAccess(); void testPagedVolumeChunkRandomAccess();
private: private:
int32_t testPagedVolumeChunkAccess(uint32_t locality); int32_t testPagedVolumeChunkAccess(uint16_t localityMask);
static const uint16_t m_uChunkSideLength = 32; static const uint16_t m_uChunkSideLength = 32;
@ -73,7 +73,7 @@ private:
PolyVox::RawVolume<int32_t>* m_pRawVolume; PolyVox::RawVolume<int32_t>* m_pRawVolume;
PolyVox::PagedVolume<int32_t>* m_pPagedVolume; PolyVox::PagedVolume<int32_t>* m_pPagedVolume;
PolyVox::PagedVolume<int32_t>::Chunk* m_pPagedVolumeChunk; PolyVox::PagedVolume<uint32_t>::Chunk* m_pPagedVolumeChunk;
}; };
#endif #endif