Work on code which computes how the memory should be split between compressed and uncompressed data.

This commit is contained in:
David Williams
2013-07-19 16:43:59 +02:00
parent ef6bd31651
commit 7cd115b33d
2 changed files with 50 additions and 12 deletions

View File

@ -347,7 +347,7 @@ namespace PolyVox
mutable UncompressedBlock<VoxelType>* m_pLastAccessedBlock;
uint32_t m_uMaxNumberOfUncompressedBlocks;
uint32_t m_uCompressedBlockMemoryLimitInBytes;
uint32_t m_uTargetMemoryLimitInBytes;
// The size of the volume
Region m_regValidRegionInBlocks;

View File

@ -246,23 +246,57 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::setTargetMemoryLimitInBytes(uint32_t uTargetMemoryLimitInBytes)
{
// Set the limit, and then work out how big the uncompressed cache should be.
m_uTargetMemoryLimitInBytes = uTargetMemoryLimitInBytes;
// The size of a single uncompressed block of data.
uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
// The idea number of uncompressed blocks is chosen by gut feeling as much as anything. Part of the
// rationale is that it should let us iterate along any edge without data being pushed out of the cache.
uint32_t uIdealNoOfUncompressedBlocks = m_regValidRegionInBlocks.getWidthInVoxels() + m_regValidRegionInBlocks.getHeightInVoxels() * m_regValidRegionInBlocks.getDepthInVoxels();
// When deciding how to split the memory between compressed and uncompressed blocks it is useful to know the dimensions of the
// volume in blocks. After sorting, the array below will hold the smallest dimension in [0] and the largest dimension in [2].
const uint32_t uNoOfDimensions = 3;
uint32_t uSortedDimensionsInBlocks[uNoOfDimensions];
uSortedDimensionsInBlocks[0] = (getEnclosingRegion().getWidthInVoxels() >> m_uBlockSideLengthPower) + 1;
uSortedDimensionsInBlocks[1] = (getEnclosingRegion().getHeightInVoxels() >> m_uBlockSideLengthPower) + 1;
uSortedDimensionsInBlocks[2] = (getEnclosingRegion().getDepthInVoxels() >> m_uBlockSideLengthPower) + 1;
std::sort(uSortedDimensionsInBlocks, uSortedDimensionsInBlocks + uNoOfDimensions);
// Let's (arbitrarily?) say that we should never use more than half the available memory for the uncompressed block cache.
uint32_t uMaxMemoryForUncompressedBlocks = uTargetMemoryLimitInBytes / 2;
const uint32_t uLongestEdgeInBlocks = uSortedDimensionsInBlocks[2];
const uint32_t uLargestFaceSizeInBlocks = uSortedDimensionsInBlocks[1] * uSortedDimensionsInBlocks[2];
uint32_t uMaxFittableNoOfUncompressedBlocks = uMaxMemoryForUncompressedBlocks / uUncompressedBlockSizeInBytes;
// In the ideal situation we will be able to keep an entire face of blocks decompressed in the cache, and still have significant memory
// left for storing a large number of compressed block. Failing this, we would at least like to be able to keep enough blocks decompressed
// to iterate over the longest edge. Otherwise we will find that excessive compression and decompresion occurs. In both cases we multiply
// by an extra factor make sure there is space for storing some compressed data as well.
const uint32_t uFactor = 2; // Just to make sure we leave some space for compressed data as well
const uint32_t uIdealMemoryTarget = uLargestFaceSizeInBlocks * uUncompressedBlockSizeInBytes * uFactor;
const uint32_t uAcceptableMemoryTarget = uLongestEdgeInBlocks * uUncompressedBlockSizeInBytes * uFactor;
setMaxNumberOfUncompressedBlocks((std::min)(uIdealNoOfUncompressedBlocks, uMaxFittableNoOfUncompressedBlocks));
if(uTargetMemoryLimitInBytes >= uIdealMemoryTarget)
{
logDebug() << "The target memory limit (" << uTargetMemoryLimitInBytes << "bytes) is plenty for a volume of this size)";
uint32_t uUncompressedBlockCacheSizeInBytes = m_uMaxNumberOfUncompressedBlocks * uUncompressedBlockSizeInBytes;
// The added value below is just some extra 'grace' space.
setMaxNumberOfUncompressedBlocks(uLargestFaceSizeInBlocks + uSortedDimensionsInBlocks[1]);
}
else if(uTargetMemoryLimitInBytes >= uAcceptableMemoryTarget)
{
logDebug() << "The target memory limit (" << uTargetMemoryLimitInBytes << "bytes) should be acceptable for a volume of this size)";
m_uCompressedBlockMemoryLimitInBytes = uTargetMemoryLimitInBytes - uUncompressedBlockCacheSizeInBytes;
// Let's (arbitrarily) use 1/4 of the available memory for the cache, while making sure that it is as long as the longest side.
uint32_t uMaxFittableUncompressedBlocks = uTargetMemoryLimitInBytes / uUncompressedBlockSizeInBytes;
setMaxNumberOfUncompressedBlocks((std::max)(uMaxFittableUncompressedBlocks / 4, uLongestEdgeInBlocks));
}
else
{
logWarning() << "The target memory limit (" << uTargetMemoryLimitInBytes << "bytes) is too low for a volume of this size)";
logWarning() << "Excessive block thrashing may occur and the target memory limit may not be honored";
// We still have to do something. Let's still use 1/4 of the memory for the cache, but also set a minimum size.
const uint32_t uMinNoOfUncompressedBlocks = 8; // Chosen because it just feels about right.
uint32_t uMaxFittableUncompressedBlocks = uTargetMemoryLimitInBytes / uUncompressedBlockSizeInBytes;
setMaxNumberOfUncompressedBlocks((std::max)(uMaxFittableUncompressedBlocks / 4, uMinNoOfUncompressedBlocks));
}
}
////////////////////////////////////////////////////////////////////////////////
@ -277,6 +311,10 @@ namespace PolyVox
clearBlockCache();
m_uMaxNumberOfUncompressedBlocks = uMaxNumberOfUncompressedBlocks;
uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
logDebug() << "The maximum number of uncompresed blocks has been set to " << m_uMaxNumberOfUncompressedBlocks
<< ", which is " << m_uMaxNumberOfUncompressedBlocks * uUncompressedBlockSizeInBytes << " bytes";
}
////////////////////////////////////////////////////////////////////////////////
@ -781,7 +819,7 @@ namespace PolyVox
//uint32_t uMemoryToReclaim = uMemoryUsedForCompressedBlocks - m_uCompressedBlockMemoryLimitInBytes;
//while(uMemoryToReclaim > 0)
while(calculateBlockMemoryUsage() > m_uCompressedBlockMemoryLimitInBytes) //FIXME - This calculation of size is slow and should be outside the loop.
/*while(calculateBlockMemoryUsage() > m_uCompressedBlockMemoryLimitInBytes) //FIXME - This calculation of size is slow and should be outside the loop.
{
// find the least recently used block
typename CompressedBlockMap::iterator i;
@ -799,7 +837,7 @@ namespace PolyVox
//uMemoryToReclaim -= itUnloadBlock->second->calculateSizeInBytes();
eraseBlock(itUnloadBlock);
}
}*/
}
template <typename VoxelType>