Refactoring of statistics API. COMPATIBILITY BREAKING!

See structures: Statistics, DetailedStatistics, TotalStatistics, functions: Pool::GetStatistics, Pool::CalculateStatistics, VirtualBlock::GetStatistics, VirtualBlock::CalculateStatistics, Allocator::CalculateStatistics.

Switched to TSLF algorithm as the default. Removed: POOL_FLAG_ALGORITHM_TLSF, VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF.
This commit is contained in:
Adam Sawicki 2022-02-23 10:30:34 +01:00
parent 7ab674b85a
commit 92d23c0cba
3 changed files with 415 additions and 450 deletions

View File

@ -163,7 +163,9 @@ class VirtualBlockPimpl;
class Pool;
class Allocator;
struct StatInfo;
struct Statistics;
struct DetailedStatistics;
struct TotalStatistics;
/// \brief Unique identifier of single allocation done inside the memory heap.
typedef UINT64 AllocHandle;
@ -198,6 +200,12 @@ enum ALLOCATION_FLAGS
Set this flag if the allocation should have its own dedicated memory allocation (committed resource with implicit heap).
Use it for special, big resources, like fullscreen textures used as render targets.
- When used with functions like D3D12MA::Allocator::CreateResource, it will use `ID3D12Device::CreateCommittedResource`,
so the created allocation will contain a resource (D3D12MA::Allocation::GetResource() `!= NULL`) but will not have
a heap (D3D12MA::Allocation::GetHeap() `== NULL`), as the heap is implicit.
- When used with raw memory allocation like D3D12MA::Allocator::AllocateMemory, it will use `ID3D12Device::CreateHeap`,
so the created allocation will contain a heap (D3D12MA::Allocation::GetHeap() `!= NULL`) and its offset will always be 0.
*/
ALLOCATION_FLAG_COMMITTED = 0x1,
@ -214,6 +222,8 @@ enum ALLOCATION_FLAGS
/** Create allocation only if additional memory required for it, if any, won't exceed
memory budget. Otherwise return `E_OUTOFMEMORY`.
\warning Currently this feature is not fully implemented yet.
*/
ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,
@ -453,18 +463,6 @@ enum POOL_FLAGS
/// Zero
POOL_FLAG_NONE = 0,
/** \brief Enables alternative, TLSF allocation algorithm in virtual block.
This algorithm is based on 2-level lists dividing address space into smaller
chunks. The first level is aligned to power of two which serves as buckets for requested
memory to fall into, and the second level is lineary subdivided into lists of free memory.
This algorithm aims to achieve bounded response time even in the worst case scenario.
Allocation time can be sometimes slightly longer than compared to other algorithms
but in return the application can avoid stalls in case of fragmentation, giving
predictable results, suitable for real-time use cases.
*/
POOL_FLAG_ALGORITHM_TLSF = 0x1,
/** \brief Enables alternative, linear allocation algorithm in this pool.
Specify this flag to enable linear allocation algorithm, which always creates
@ -476,10 +474,10 @@ enum POOL_FLAGS
ring buffer, and double stack.
For details, see documentation chapter \ref linear_algorithm.
*/
POOL_FLAG_ALGORITHM_LINEAR = 0x2,
POOL_FLAG_ALGORITHM_LINEAR = 0x1,
// Bit mask to extract only `ALGORITHM` bits from entire set of flags.
POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_TLSF | POOL_FLAG_ALGORITHM_LINEAR
POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR
};
/// \brief Parameters of created D3D12MA::Pool object. To be used with D3D12MA::Allocator::CreatePool.
@ -554,9 +552,13 @@ public:
*/
POOL_DESC GetDesc() const;
/** \brief Retrieves statistics from the current state of this pool.
/** \brief TODO
*/
void CalculateStats(StatInfo* pStats);
void GetStatistics(Statistics* pStats);
/** \brief TODO
*/
void CalculateStatistics(DetailedStatistics* pStats);
/** \brief Associates a name with the pool. This name is for use in debug diagnostics and tools.
@ -649,59 +651,50 @@ struct ALLOCATOR_DESC
*/
const UINT HEAP_TYPE_COUNT = 4;
/**
\brief Calculated statistics of memory usage in entire allocator.
/** \brief TODO
*/
struct StatInfo
struct Statistics
{
/// Number of memory blocks (heaps) allocated.
UINT BlockCount;
/// Number of D3D12MA::Allocation objects allocated.
UINT AllocationCount;
/// Number of free ranges of memory between allocations.
UINT UnusedRangeCount;
UINT64 BlockBytes;
/// Total number of bytes occupied by all allocations.
UINT64 UsedBytes;
/// Total number of bytes occupied by unused ranges.
UINT64 UnusedBytes;
UINT64 AllocationBytes;
};
struct DetailedStatistics
{
Statistics Stats;
UINT UnusedRangeCount;
UINT64 AllocationSizeMin;
UINT64 AllocationSizeAvg;
UINT64 AllocationSizeMax;
UINT64 UnusedRangeSizeMin;
UINT64 UnusedRangeSizeAvg;
UINT64 UnusedRangeSizeMax;
};
/**
\brief General statistics from the current state of the allocator.
*/
struct Stats
struct TotalStatistics
{
/// Total statistics from all heap types.
StatInfo Total;
/**
One StatInfo for each type of heap located at the following indices:
/** \brief
One element for each type of heap located at the following indices:
0 - DEFAULT, 1 - UPLOAD, 2 - READBACK, 3 - CUSTOM.
*/
StatInfo HeapType[HEAP_TYPE_COUNT];
DetailedStatistics HeapType[HEAP_TYPE_COUNT];
/// Total statistics from all heap types.
DetailedStatistics Total;
};
/** \brief Statistics of current memory usage and available budget, in bytes, for GPU or CPU memory.
*/
struct Budget
{
/** \brief Sum size of all memory blocks allocated from particular heap type, in bytes.
/** \brief TODO
*/
UINT64 BlockBytes;
/** \brief Sum size of all allocations created in particular heap type, in bytes.
Always less or equal than `BlockBytes`.
Difference `BlockBytes - AllocationBytes` is the amount of memory allocated but unused -
available for new allocations or wasted due to fragmentation.
*/
UINT64 AllocationBytes;
Statistics Stats;
/** \brief Estimated current memory usage of the program, in bytes.
Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if enabled.
@ -711,7 +704,6 @@ struct Budget
memory blocks allocated outside of this library, if any.
*/
UINT64 UsageBytes;
/** \brief Estimated amount of memory available to the program, in bytes.
Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if enabled.
@ -876,9 +868,9 @@ public:
*/
void SetCurrentFrameIndex(UINT frameIndex);
/** \brief Retrieves statistics from the current state of the allocator.
/** \brief TODO
*/
void CalculateStats(Stats* pStats);
void CalculateStatistics(TotalStatistics* pStats);
/** \brief Retrieves information about current memory budget.
@ -924,18 +916,6 @@ enum VIRTUAL_BLOCK_FLAGS
/// Zero
VIRTUAL_BLOCK_FLAG_NONE = 0,
/** \brief Enables alternative, TLSF allocation algorithm in virtual block.
This algorithm is based on 2-level lists dividing address space into smaller
chunks. The first level is aligned to power of two which serves as buckets for requested
memory to fall into, and the second level is lineary subdivided into lists of free memory.
This algorithm aims to achieve bounded response time even in the worst case scenario.
Allocation time can be sometimes slightly longer than compared to other algorithms
but in return the application can avoid stalls in case of fragmentation, giving
predictable results, suitable for real-time use cases.
*/
VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF = POOL_FLAG_ALGORITHM_TLSF,
/** \brief Enables alternative, linear allocation algorithm in this virtual block.
Specify this flag to enable linear allocation algorithm, which always creates
@ -1065,9 +1045,12 @@ public:
*/
void SetAllocationUserData(VirtualAllocation allocation, void* pUserData);
/** \brief Retrieves statistics from the current state of the block.
/** \brief TODO
*/
void CalculateStats(StatInfo* pInfo) const;
void GetStatistics(Statistics* pStats) const;
/** \brief TODO
*/
void CalculateStatistics(DetailedStatistics* pStats) const;
/** \brief Builds and returns statistics as a string in JSON format, including the list of allocations with their parameters.
@param[out] ppStatsString Must be freed using VirtualBlock::FreeStatsString.

View File

@ -554,25 +554,55 @@ static const WCHAR* const HeapTypeNames[] = {
// Stat helper functions
static void AddStatInfo(StatInfo& dst, const StatInfo& src)
static void ClearStatistics(Statistics& outStats)
{
dst.BlockCount += src.BlockCount;
dst.AllocationCount += src.AllocationCount;
dst.UnusedRangeCount += src.UnusedRangeCount;
dst.UsedBytes += src.UsedBytes;
dst.UnusedBytes += src.UnusedBytes;
dst.AllocationSizeMin = D3D12MA_MIN(dst.AllocationSizeMin, src.AllocationSizeMin);
dst.AllocationSizeMax = D3D12MA_MAX(dst.AllocationSizeMax, src.AllocationSizeMax);
dst.UnusedRangeSizeMin = D3D12MA_MIN(dst.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
dst.UnusedRangeSizeMax = D3D12MA_MAX(dst.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
outStats.BlockCount = 0;
outStats.AllocationCount = 0;
outStats.BlockBytes = 0;
outStats.AllocationBytes = 0;
}
static void PostProcessStatInfo(StatInfo& statInfo)
static void ClearDetailedStatistics(DetailedStatistics& outStats)
{
statInfo.AllocationSizeAvg = statInfo.AllocationCount ?
statInfo.UsedBytes / statInfo.AllocationCount : 0;
statInfo.UnusedRangeSizeAvg = statInfo.UnusedRangeCount ?
statInfo.UnusedBytes / statInfo.UnusedRangeCount : 0;
ClearStatistics(outStats.Stats);
outStats.UnusedRangeCount = 0;
outStats.AllocationSizeMin = UINT64_MAX;
outStats.AllocationSizeMax = 0;
outStats.UnusedRangeSizeMin = UINT64_MAX;
outStats.UnusedRangeSizeMax = 0;
}
static void AddStatistics(Statistics& inoutStats, const Statistics& src)
{
inoutStats.BlockCount += src.BlockCount;
inoutStats.AllocationCount += src.AllocationCount;
inoutStats.BlockBytes += src.BlockBytes;
inoutStats.AllocationBytes += src.AllocationBytes;
}
static void AddDetailedStatistics(DetailedStatistics& inoutStats, const DetailedStatistics& src)
{
AddStatistics(inoutStats.Stats, src.Stats);
inoutStats.UnusedRangeCount += src.UnusedRangeCount;
inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, src.AllocationSizeMin);
inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, src.AllocationSizeMax);
inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
}
static void AddDetailedStatisticsAllocation(DetailedStatistics& inoutStats, UINT64 size)
{
inoutStats.Stats.AllocationCount++;
inoutStats.Stats.AllocationBytes += size;
inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, size);
inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, size);
}
static void AddDetailedStatisticsUnusedRange(DetailedStatistics& inoutStats, UINT64 size)
{
inoutStats.UnusedRangeCount++;
inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, size);
inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, size);
}
static UINT64 HeapFlagsToAlignment(D3D12_HEAP_FLAGS flags)
@ -2717,7 +2747,8 @@ public:
virtual void SetAllocationUserData(AllocHandle allocHandle, void* userData) = 0;
virtual void CalcAllocationStatInfo(StatInfo& outInfo) const = 0;
virtual void AddStatistics(Statistics& inoutStats) const = 0;
virtual void AddDetailedStatistics(DetailedStatistics& inoutStats) const = 0;
virtual void WriteAllocationInfoToJson(JsonWriter& json) const = 0;
protected:
@ -2742,6 +2773,7 @@ private:
D3D12MA_CLASS_NO_COPY(BlockMetadata);
};
#if 0
class BlockMetadata_Generic : public BlockMetadata
{
public:
@ -2773,7 +2805,8 @@ public:
void SetAllocationUserData(AllocHandle allocHandle, void* userData) override;
void CalcAllocationStatInfo(StatInfo& outInfo) const override;
void AddStatistics(Statistics& inoutStats) const override;
void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
void WriteAllocationInfoToJson(JsonWriter& json) const override;
private:
@ -2813,6 +2846,7 @@ private:
D3D12MA_CLASS_NO_COPY(BlockMetadata_Generic)
};
#endif // #if 0
class BlockMetadata_Linear : public BlockMetadata
{
@ -2845,7 +2879,8 @@ public:
void SetAllocationUserData(AllocHandle allocHandle, void* userData) override;
void CalcAllocationStatInfo(StatInfo& outInfo) const override;
void AddStatistics(Statistics& inoutStats) const override;
void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
void WriteAllocationInfoToJson(JsonWriter& json) const override;
private:
@ -2944,7 +2979,8 @@ public:
void SetAllocationUserData(AllocHandle allocHandle, void* userData) override;
void CalcAllocationStatInfo(StatInfo& outInfo) const override;
void AddStatistics(Statistics& inoutStats) const override;
void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
void WriteAllocationInfoToJson(JsonWriter& json) const override;
private:
@ -3136,7 +3172,8 @@ public:
D3D12_HEAP_TYPE GetHeapType() const { return m_HeapType; }
void CalculateStats(StatInfo& outStats);
void AddStatistics(Statistics& inoutStats);
void AddDetailedStatistics(DetailedStatistics& inoutStats);
// Writes JSON array with the list of allocations.
void BuildStatsString(JsonWriter& json);
@ -3220,8 +3257,8 @@ public:
void** ppvResource);
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
void AddStats(StatInfo& outStats);
void AddStats(Stats& outStats);
void AddStatistics(Statistics& inoutStats);
void AddDetailedStatistics(DetailedStatistics& inoutStats);
void WriteBlockInfoToJson(JsonWriter& json);
@ -3281,6 +3318,8 @@ static const UINT DEFAULT_POOL_MAX_COUNT = 9;
struct CurrentBudgetData
{
D3D12MA_ATOMIC_UINT32 m_BlockCount[HEAP_TYPE_COUNT];
D3D12MA_ATOMIC_UINT32 m_AllocationCount[HEAP_TYPE_COUNT];
D3D12MA_ATOMIC_UINT64 m_BlockBytes[HEAP_TYPE_COUNT];
D3D12MA_ATOMIC_UINT64 m_AllocationBytes[HEAP_TYPE_COUNT];
@ -3294,6 +3333,8 @@ struct CurrentBudgetData
{
for(UINT i = 0; i < HEAP_TYPE_COUNT; ++i)
{
m_BlockCount[i] = 0;
m_AllocationCount[i] = 0;
m_BlockBytes[i] = 0;
m_AllocationBytes[i] = 0;
m_BlockBytesAtBudgetFetch[i] = 0;
@ -3308,22 +3349,26 @@ struct CurrentBudgetData
void AddAllocation(UINT heapTypeIndex, UINT64 allocationSize)
{
++m_AllocationCount[heapTypeIndex];
m_AllocationBytes[heapTypeIndex] += allocationSize;
++m_OperationsSinceBudgetFetch;
}
void RemoveAllocation(UINT heapTypeIndex, UINT64 allocationSize)
{
m_AllocationBytes[heapTypeIndex] -= allocationSize;
--m_AllocationCount[heapTypeIndex];
++m_OperationsSinceBudgetFetch;
}
void AddCommittedAllocation(UINT heapTypeIndex, UINT64 allocationSize)
{
AddAllocation(heapTypeIndex, allocationSize);
++m_BlockCount[heapTypeIndex];
m_BlockBytes[heapTypeIndex] += allocationSize;
}
void RemoveCommittedAllocation(UINT heapTypeIndex, UINT64 allocationSize)
{
m_BlockBytes[heapTypeIndex] -= allocationSize;
--m_BlockCount[heapTypeIndex];
RemoveAllocation(heapTypeIndex, allocationSize);
}
};
@ -3342,8 +3387,9 @@ public:
BlockVector* GetBlockVector() { return m_BlockVector; }
CommittedAllocationList* GetCommittedAllocationList() { return SupportsCommittedAllocations() ? &m_CommittedAllocations : NULL; }
void CalculateStats(StatInfo& outStats);
void AddStats(Stats& inoutStats);
void GetStatistics(Statistics& outStats);
void CalculateStatistics(DetailedStatistics& outStats);
void AddDetailedStatistics(DetailedStatistics& inoutStats);
void SetName(LPCWSTR Name);
LPCWSTR GetName() const { return m_Name; }
@ -3457,7 +3503,7 @@ public:
UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
void CalculateStats(Stats& outStats);
void CalculateStatistics(TotalStatistics& outStats);
void GetBudget(Budget* outGpuBudget, Budget* outCpuBudget);
void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
@ -3663,6 +3709,7 @@ void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
json.EndObject();
}
#if 0
////////////////////////////////////////////////////////////////////////////////
// Private class BlockMetadata_Generic implementation
@ -4160,34 +4207,25 @@ void BlockMetadata_Generic::SetAllocationUserData(AllocHandle allocHandle, void*
suballoc.userData = userData;
}
void BlockMetadata_Generic::CalcAllocationStatInfo(StatInfo& outInfo) const
void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const
{
outInfo.BlockCount = 1;
inoutStats.BlockCount++;
inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount;
inoutStats.BlockBytes += GetSize();
inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
}
const UINT rangeCount = (UINT)m_Suballocations.size();
outInfo.AllocationCount = rangeCount - m_FreeCount;
outInfo.UnusedRangeCount = m_FreeCount;
outInfo.UsedBytes = GetSize() - m_SumFreeSize;
outInfo.UnusedBytes = m_SumFreeSize;
outInfo.AllocationSizeMin = UINT64_MAX;
outInfo.AllocationSizeMax = 0;
outInfo.UnusedRangeSizeMin = UINT64_MAX;
outInfo.UnusedRangeSizeMax = 0;
void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const
{
inoutStats.Stats.BlockCount++;
inoutStats.Stats.BlockBytes += GetSize();
for(const auto& suballoc : m_Suballocations)
{
if(suballoc.type == SUBALLOCATION_TYPE_FREE)
{
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(suballoc.size, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(suballoc.size, outInfo.UnusedRangeSizeMax);
}
AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size);
else
{
outInfo.AllocationSizeMin = D3D12MA_MIN(suballoc.size, outInfo.AllocationSizeMin);
outInfo.AllocationSizeMax = D3D12MA_MAX(suballoc.size, outInfo.AllocationSizeMax);
}
AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
}
}
@ -4203,6 +4241,7 @@ void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const
}
PrintDetailedMap_End(json);
}
#endif // #if 0
////////////////////////////////////////////////////////////////////////////////
// Private class BlockMetadata_Linear implementation
@ -4580,17 +4619,18 @@ void BlockMetadata_Linear::SetAllocationUserData(AllocHandle allocHandle, void*
suballoc.userData = userData;
}
void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
void BlockMetadata_Linear::AddStatistics(Statistics& inoutStats) const
{
outInfo.BlockCount = 1;
outInfo.AllocationCount = 0;
outInfo.UnusedRangeCount = 0;
outInfo.UsedBytes = 0;
inoutStats.BlockCount++;
inoutStats.AllocationCount += (UINT)GetAllocationCount();
inoutStats.BlockBytes += GetSize();
inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
}
outInfo.AllocationSizeMin = UINT64_MAX;
outInfo.AllocationSizeMax = 0;
outInfo.UnusedRangeSizeMin = UINT64_MAX;
outInfo.UnusedRangeSizeMax = 0;
void BlockMetadata_Linear::AddDetailedStatistics(DetailedStatistics& inoutStats) const
{
inoutStats.Stats.BlockCount++;
inoutStats.Stats.BlockBytes += GetSize();
const UINT64 size = GetSize();
const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
@ -4622,17 +4662,12 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
{
// There is free space from lastOffset to suballoc.offset.
const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size.
outInfo.UsedBytes += suballoc.size;
++outInfo.AllocationCount;
outInfo.AllocationSizeMin = D3D12MA_MIN(suballoc.size, outInfo.AllocationSizeMin);
outInfo.AllocationSizeMax = D3D12MA_MAX(suballoc.size, outInfo.AllocationSizeMax);
AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
// 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size;
@ -4645,9 +4680,7 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
if (lastOffset < freeSpace2ndTo1stEnd)
{
const UINT64 unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// End of loop.
@ -4678,17 +4711,12 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
{
// There is free space from lastOffset to suballoc.offset.
const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size.
outInfo.UsedBytes += suballoc.size;
++outInfo.AllocationCount;
outInfo.AllocationSizeMin = D3D12MA_MIN(suballoc.size, outInfo.AllocationSizeMin);
outInfo.AllocationSizeMax = D3D12MA_MAX(suballoc.size, outInfo.AllocationSizeMax);
AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
// 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size;
@ -4701,9 +4729,7 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
if (lastOffset < freeSpace1stTo2ndEnd)
{
const UINT64 unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// End of loop.
@ -4733,17 +4759,12 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
{
// There is free space from lastOffset to suballoc.offset.
const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size.
outInfo.UsedBytes += suballoc.size;
++outInfo.AllocationCount;
outInfo.AllocationSizeMin = D3D12MA_MIN(suballoc.size, outInfo.AllocationSizeMin);
outInfo.AllocationSizeMax = D3D12MA_MAX(suballoc.size, outInfo.AllocationSizeMax);
AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
// 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size;
@ -4756,9 +4777,7 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
if (lastOffset < size)
{
const UINT64 unusedRangeSize = size - lastOffset;
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(unusedRangeSize, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(unusedRangeSize, outInfo.UnusedRangeSizeMax);
AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
}
// End of loop.
@ -4766,7 +4785,6 @@ void BlockMetadata_Linear::CalcAllocationStatInfo(StatInfo& outInfo) const
}
}
}
outInfo.UnusedBytes = size - outInfo.UsedBytes;
}
void BlockMetadata_Linear::WriteAllocationInfoToJson(JsonWriter& json) const
@ -5765,40 +5783,29 @@ void BlockMetadata_TLSF::SetAllocationUserData(AllocHandle allocHandle, void* us
block->UserData() = userData;
}
void BlockMetadata_TLSF::CalcAllocationStatInfo(StatInfo& outInfo) const
void BlockMetadata_TLSF::AddStatistics(Statistics& inoutStats) const
{
outInfo.BlockCount = 1;
outInfo.AllocationCount = static_cast<UINT>(m_AllocCount);
outInfo.UnusedRangeCount = static_cast<UINT>(m_BlocksFreeCount);
inoutStats.BlockCount++;
inoutStats.AllocationCount += static_cast<UINT>(m_AllocCount);
inoutStats.BlockBytes += GetSize();
inoutStats.AllocationBytes += GetSize() - GetSumFreeSize();
}
outInfo.UnusedBytes = GetSumFreeSize();
outInfo.UsedBytes = GetSize() - outInfo.UnusedBytes;
outInfo.AllocationSizeMin = UINT64_MAX;
outInfo.AllocationSizeMax = 0;
outInfo.UnusedRangeSizeMin = UINT64_MAX;
outInfo.UnusedRangeSizeMax = 0;
void BlockMetadata_TLSF::AddDetailedStatistics(DetailedStatistics& inoutStats) const
{
inoutStats.Stats.BlockCount++;
inoutStats.Stats.BlockBytes += GetSize();
for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
{
if (block->IsFree())
{
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(block->size, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(block->size, outInfo.UnusedRangeSizeMax);
}
AddDetailedStatisticsUnusedRange(inoutStats, block->size);
else
{
outInfo.AllocationSizeMin = D3D12MA_MIN(block->size, outInfo.AllocationSizeMin);
outInfo.AllocationSizeMax = D3D12MA_MAX(block->size, outInfo.AllocationSizeMax);
}
AddDetailedStatisticsAllocation(inoutStats, block->size);
}
if (m_NullBlock->size > 0)
{
++outInfo.UnusedRangeCount;
outInfo.UnusedRangeSizeMin = D3D12MA_MIN(m_NullBlock->size, outInfo.UnusedRangeSizeMin);
outInfo.UnusedRangeSizeMax = D3D12MA_MAX(m_NullBlock->size, outInfo.UnusedRangeSizeMax);
}
AddDetailedStatisticsUnusedRange(inoutStats, m_NullBlock->size);
}
void BlockMetadata_TLSF::WriteAllocationInfoToJson(JsonWriter& json) const
@ -6023,16 +6030,13 @@ HRESULT NormalBlock::Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pPro
switch (algorithm)
{
case POOL_FLAG_ALGORITHM_TLSF:
m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
break;
case POOL_FLAG_ALGORITHM_LINEAR:
m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Linear)(&m_Allocator->GetAllocs(), false);
break;
default:
D3D12MA_ASSERT(0);
case 0:
m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Generic)(&m_Allocator->GetAllocs(), false);
m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
break;
}
m_pMetadata->Init(m_Size);
@ -6120,25 +6124,32 @@ CommittedAllocationList::~CommittedAllocationList()
}
}
void CommittedAllocationList::CalculateStats(StatInfo& outStats)
void CommittedAllocationList::AddStatistics(Statistics& inoutStats)
{
ZeroMemory(&outStats, sizeof(outStats));
outStats.AllocationSizeMin = UINT64_MAX;
outStats.UnusedRangeSizeMin = UINT64_MAX;
MutexLockRead lock(m_Mutex, m_UseMutex);
for(Allocation* alloc = m_AllocationList.Front();
alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
{
const UINT64 size = alloc->GetSize();
++outStats.BlockCount;
++outStats.AllocationCount;
outStats.UsedBytes += size;
if(size > outStats.AllocationSizeMax)
outStats.AllocationSizeMax = size;
if(size < outStats.AllocationSizeMin)
outStats.AllocationSizeMin = size;
inoutStats.BlockCount++;
inoutStats.AllocationCount++;
inoutStats.BlockBytes += size;
inoutStats.AllocationBytes += size;
}
}
void CommittedAllocationList::AddDetailedStatistics(DetailedStatistics& inoutStats)
{
MutexLockRead lock(m_Mutex, m_UseMutex);
for(Allocation* alloc = m_AllocationList.Front();
alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
{
const UINT64 size = alloc->GetSize();
inoutStats.Stats.BlockCount++;
inoutStats.Stats.BlockBytes += size;
AddDetailedStatisticsAllocation(inoutStats, size);
}
}
@ -6659,7 +6670,7 @@ HRESULT BlockVector::CreateBlock(
return hr;
}
void BlockVector::AddStats(StatInfo& outStats)
void BlockVector::AddStatistics(Statistics& inoutStats)
{
MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
@ -6668,17 +6679,12 @@ void BlockVector::AddStats(StatInfo& outStats)
const NormalBlock* const pBlock = m_Blocks[i];
D3D12MA_ASSERT(pBlock);
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
StatInfo blockStatInfo;
pBlock->m_pMetadata->CalcAllocationStatInfo(blockStatInfo);
AddStatInfo(outStats, blockStatInfo);
pBlock->m_pMetadata->AddStatistics(inoutStats);
}
}
void BlockVector::AddStats(Stats& outStats)
void BlockVector::AddDetailedStatistics(DetailedStatistics& inoutStats)
{
const UINT heapTypeIndex = HeapTypeToIndex(m_HeapProps.Type);
StatInfo* const pStatInfo = &outStats.HeapType[heapTypeIndex];
MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
for(size_t i = 0; i < m_Blocks.size(); ++i)
@ -6686,10 +6692,7 @@ void BlockVector::AddStats(Stats& outStats)
const NormalBlock* const pBlock = m_Blocks[i];
D3D12MA_ASSERT(pBlock);
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
StatInfo blockStatInfo;
pBlock->m_pMetadata->CalcAllocationStatInfo(blockStatInfo);
AddStatInfo(outStats.Total, blockStatInfo);
AddStatInfo(*pStatInfo, blockStatInfo);
pBlock->m_pMetadata->AddDetailedStatistics(inoutStats);
}
}
@ -6754,30 +6757,23 @@ PoolPimpl::~PoolPimpl()
D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
}
void PoolPimpl::CalculateStats(StatInfo& outStats)
void PoolPimpl::GetStatistics(Statistics& outStats)
{
ZeroMemory(&outStats, sizeof(outStats));
outStats.AllocationSizeMin = UINT64_MAX;
outStats.UnusedRangeSizeMin = UINT64_MAX;
m_BlockVector->AddStats(outStats);
{
StatInfo committedStatInfo; // Uninitialized.
m_CommittedAllocations.CalculateStats(committedStatInfo);
AddStatInfo(outStats, committedStatInfo);
}
PostProcessStatInfo(outStats);
ClearStatistics(outStats);
m_BlockVector->AddStatistics(outStats);
m_CommittedAllocations.AddStatistics(outStats);
}
void PoolPimpl::AddStats(Stats& inoutStats)
void PoolPimpl::CalculateStatistics(DetailedStatistics& outStats)
{
StatInfo poolStatInfo = {};
CalculateStats(poolStatInfo);
ClearDetailedStatistics(outStats);
AddDetailedStatistics(outStats);
}
AddStatInfo(inoutStats.Total, poolStatInfo);
AddStatInfo(inoutStats.HeapType[HeapTypeToIndex(m_Desc.HeapProperties.Type)], poolStatInfo);
void PoolPimpl::AddDetailedStatistics(DetailedStatistics& inoutStats)
{
m_BlockVector->AddDetailedStatistics(inoutStats);
m_CommittedAllocations.AddDetailedStatistics(inoutStats);
}
void PoolPimpl::SetName(LPCWSTR Name)
@ -6820,11 +6816,18 @@ POOL_DESC Pool::GetDesc() const
return m_Pimpl->GetDesc();
}
void Pool::CalculateStats(StatInfo* pStats)
void Pool::GetStatistics(Statistics* pStats)
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
m_Pimpl->CalculateStats(*pStats);
m_Pimpl->GetStatistics(*pStats);
}
void Pool::CalculateStatistics(DetailedStatistics* pStats)
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
m_Pimpl->CalculateStatistics(*pStats);
}
void Pool::SetName(LPCWSTR Name)
@ -7606,26 +7609,21 @@ void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
#endif
}
void AllocatorPimpl::CalculateStats(Stats& outStats)
void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats)
{
// Init stats
ZeroMemory(&outStats, sizeof(outStats));
outStats.Total.AllocationSizeMin = UINT64_MAX;
outStats.Total.UnusedRangeSizeMin = UINT64_MAX;
ClearDetailedStatistics(outStats.Total);
for(size_t i = 0; i < HEAP_TYPE_COUNT; i++)
{
outStats.HeapType[i].AllocationSizeMin = UINT64_MAX;
outStats.HeapType[i].UnusedRangeSizeMin = UINT64_MAX;
}
ClearDetailedStatistics(outStats.HeapType[i]);
// Process deafult pools.
// Process default pools.
if(SupportsResourceHeapTier2())
{
for(size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
{
BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex];
D3D12MA_ASSERT(pBlockVector);
pBlockVector->AddStats(outStats);
pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
}
}
else
@ -7636,7 +7634,7 @@ void AllocatorPimpl::CalculateStats(Stats& outStats)
{
BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex * 3 + heapSubType];
D3D12MA_ASSERT(pBlockVector);
pBlockVector->AddStats(outStats);
pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
}
}
}
@ -7648,23 +7646,17 @@ void AllocatorPimpl::CalculateStats(Stats& outStats)
PoolList& poolList = m_Pools[heapTypeIndex];
for(PoolPimpl* pool = poolList.Front(); pool != NULL; pool = poolList.GetNext(pool))
{
pool->AddStats(outStats);
pool->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
}
}
// Process committed allocations.
for(size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
{
StatInfo statInfo; // Uninitialized.
m_CommittedAllocations[heapTypeIndex].CalculateStats(statInfo);
AddStatInfo(outStats.Total, statInfo);
AddStatInfo(outStats.HeapType[heapTypeIndex], statInfo);
}
m_CommittedAllocations[heapTypeIndex].AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
// Post process
PostProcessStatInfo(outStats.Total);
// Postprocess
for(size_t i = 0; i < HEAP_TYPE_COUNT; ++i)
PostProcessStatInfo(outStats.HeapType[i]);
AddDetailedStatistics(outStats.Total, outStats.HeapType[i]);
}
void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
@ -7672,14 +7664,19 @@ void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
if(outGpuBudget)
{
// Taking DEFAULT.
outGpuBudget->BlockBytes = m_Budget.m_BlockBytes[0];
outGpuBudget->AllocationBytes = m_Budget.m_AllocationBytes[0];
outGpuBudget->Stats.BlockCount = m_Budget.m_BlockCount[0];
outGpuBudget->Stats.AllocationCount = m_Budget.m_AllocationCount[0];
outGpuBudget->Stats.BlockBytes = m_Budget.m_BlockBytes[0];
outGpuBudget->Stats.AllocationBytes = m_Budget.m_AllocationBytes[0];
}
if(outCpuBudget)
{
// Taking UPLOAD + READBACK.
outCpuBudget->BlockBytes = m_Budget.m_BlockBytes[1] + m_Budget.m_BlockBytes[2];
outCpuBudget->AllocationBytes = m_Budget.m_AllocationBytes[1] + m_Budget.m_AllocationBytes[2];
outCpuBudget->Stats.BlockCount = m_Budget.m_BlockCount[1] + m_Budget.m_BlockCount[2];
outCpuBudget->Stats.AllocationCount = m_Budget.m_AllocationCount[1] + m_Budget.m_AllocationCount[2];
outCpuBudget->Stats.BlockBytes = m_Budget.m_BlockBytes[1] + m_Budget.m_BlockBytes[2];
outCpuBudget->Stats.AllocationBytes = m_Budget.m_AllocationBytes[1] + m_Budget.m_AllocationBytes[2];
}
// TODO: What to do with CUSTOM?
@ -7692,10 +7689,10 @@ void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
if(outGpuBudget)
{
if(m_Budget.m_D3D12UsageLocal + outGpuBudget->BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[0])
if(m_Budget.m_D3D12UsageLocal + outGpuBudget->Stats.BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[0])
{
outGpuBudget->UsageBytes = m_Budget.m_D3D12UsageLocal +
outGpuBudget->BlockBytes - m_Budget.m_BlockBytesAtBudgetFetch[0];
outGpuBudget->Stats.BlockBytes - m_Budget.m_BlockBytesAtBudgetFetch[0];
}
else
{
@ -7705,10 +7702,10 @@ void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
}
if(outCpuBudget)
{
if(m_Budget.m_D3D12UsageNonLocal + outCpuBudget->BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2])
if(m_Budget.m_D3D12UsageNonLocal + outCpuBudget->Stats.BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2])
{
outCpuBudget->UsageBytes = m_Budget.m_D3D12UsageNonLocal +
outCpuBudget->BlockBytes - (m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2]);
outCpuBudget->Stats.BlockBytes - (m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2]);
}
else
{
@ -7729,13 +7726,13 @@ void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
if(outGpuBudget)
{
const UINT64 gpuMemorySize = m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.DedicatedSystemMemory; // TODO: Is this right?
outGpuBudget->UsageBytes = outGpuBudget->BlockBytes;
outGpuBudget->UsageBytes = outGpuBudget->Stats.BlockBytes;
outGpuBudget->BudgetBytes = gpuMemorySize * 8 / 10; // 80% heuristics.
}
if(outCpuBudget)
{
const UINT64 cpuMemorySize = m_AdapterDesc.SharedSystemMemory; // TODO: Is this right?
outCpuBudget->UsageBytes = outCpuBudget->BlockBytes;
outCpuBudget->UsageBytes = outCpuBudget->Stats.BlockBytes;
outCpuBudget->BudgetBytes = cpuMemorySize * 8 / 10; // 80% heuristics.
}
}
@ -7756,38 +7753,34 @@ void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE hea
}
}
static void AddStatInfoToJson(JsonWriter& json, const StatInfo& statInfo)
static void AddDetailedStatisticsInfoToJson(JsonWriter& json, const DetailedStatistics& stats)
{
json.BeginObject();
json.WriteString(L"Blocks");
json.WriteNumber(statInfo.BlockCount);
json.WriteString(L"Allocations");
json.WriteNumber(statInfo.AllocationCount);
json.WriteString(L"UnusedRanges");
json.WriteNumber(statInfo.UnusedRangeCount);
json.WriteString(L"UsedBytes");
json.WriteNumber(statInfo.UsedBytes);
json.WriteString(L"UnusedBytes");
json.WriteNumber(statInfo.UnusedBytes);
json.WriteString(L"BlockCount");
json.WriteNumber(stats.Stats.BlockCount);
json.WriteString(L"AllocationCount");
json.WriteNumber(stats.Stats.AllocationCount);
json.WriteString(L"UnusedRangeCount");
json.WriteNumber(stats.UnusedRangeCount);
json.WriteString(L"BlockBytes");
json.WriteNumber(stats.Stats.BlockBytes);
json.WriteString(L"AllocationBytes");
json.WriteNumber(stats.Stats.AllocationBytes);
json.WriteString(L"AllocationSize");
json.BeginObject(true);
json.WriteString(L"Min");
json.WriteNumber(statInfo.AllocationSizeMin);
json.WriteString(L"Avg");
json.WriteNumber(statInfo.AllocationSizeAvg);
json.WriteNumber(stats.AllocationSizeMin);
json.WriteString(L"Max");
json.WriteNumber(statInfo.AllocationSizeMax);
json.WriteNumber(stats.AllocationSizeMax);
json.EndObject();
json.WriteString(L"UnusedRangeSize");
json.BeginObject(true);
json.WriteString(L"Min");
json.WriteNumber(statInfo.UnusedRangeSizeMin);
json.WriteString(L"Avg");
json.WriteNumber(statInfo.UnusedRangeSizeAvg);
json.WriteNumber(stats.UnusedRangeSizeMin);
json.WriteString(L"Max");
json.WriteNumber(statInfo.UnusedRangeSizeMax);
json.WriteNumber(stats.UnusedRangeSizeMax);
json.EndObject();
json.EndObject();
@ -7802,17 +7795,17 @@ void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
Budget gpuBudget = {}, cpuBudget = {};
GetBudget(&gpuBudget, &cpuBudget);
Stats stats;
CalculateStats(stats);
TotalStatistics stats;
CalculateStatistics(stats);
json.BeginObject();
json.WriteString(L"Total");
AddStatInfoToJson(json, stats.Total);
AddDetailedStatisticsInfoToJson(json, stats.Total);
for (size_t heapType = 0; heapType < HEAP_TYPE_COUNT; ++heapType)
{
json.WriteString(HeapTypeNames[heapType]);
AddStatInfoToJson(json, stats.HeapType[heapType]);
AddDetailedStatisticsInfoToJson(json, stats.HeapType[heapType]);
}
json.WriteString(L"Budget");
@ -8057,10 +8050,14 @@ void AllocatorPimpl::WriteBudgetToJson(JsonWriter& json, const Budget& budget)
{
json.BeginObject();
{
json.WriteString(L"BlockCount");
json.WriteNumber(budget.Stats.BlockCount);
json.WriteString(L"AllocationCount");
json.WriteNumber(budget.Stats.AllocationCount);
json.WriteString(L"BlockBytes");
json.WriteNumber(budget.BlockBytes);
json.WriteNumber(budget.Stats.BlockBytes);
json.WriteString(L"AllocationBytes");
json.WriteNumber(budget.AllocationBytes);
json.WriteNumber(budget.Stats.AllocationBytes);
json.WriteString(L"UsageBytes");
json.WriteNumber(budget.UsageBytes);
json.WriteString(L"BudgetBytes");
@ -8452,11 +8449,11 @@ void Allocator::SetCurrentFrameIndex(UINT frameIndex)
m_Pimpl->SetCurrentFrameIndex(frameIndex);
}
void Allocator::CalculateStats(Stats* pStats)
void Allocator::CalculateStatistics(TotalStatistics* pStats)
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
m_Pimpl->CalculateStats(*pStats);
m_Pimpl->CalculateStatistics(*pStats);
}
void Allocator::GetBudget(Budget* pGpuBudget, Budget* pCpuBudget)
@ -8505,16 +8502,13 @@ VirtualBlockPimpl::VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallb
{
switch (desc.Flags & VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK)
{
case VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF:
m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
break;
case VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Linear)(&m_AllocationCallbacks, true);
break;
default:
D3D12MA_ASSERT(0);
case 0:
m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Generic)(&m_AllocationCallbacks, true);
m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
break;
}
m_Metadata->Init(m_Size);
@ -8627,14 +8621,22 @@ void VirtualBlock::SetAllocationUserData(VirtualAllocation allocation, void* pUs
m_Pimpl->m_Metadata->SetAllocationUserData(allocation.AllocHandle, pUserData);
}
void VirtualBlock::CalculateStats(StatInfo* pInfo) const
void VirtualBlock::GetStatistics(Statistics* pStats) const
{
D3D12MA_ASSERT(pInfo);
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
m_Pimpl->m_Metadata->CalcAllocationStatInfo(*pInfo);
ClearStatistics(*pStats);
m_Pimpl->m_Metadata->AddStatistics(*pStats);
}
void VirtualBlock::CalculateStatistics(DetailedStatistics* pStats) const
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
ClearDetailedStatistics(*pStats);
m_Pimpl->m_Metadata->AddDetailedStatistics(*pStats);
}
void VirtualBlock::BuildStatsString(WCHAR** ppStatsString) const

View File

@ -71,10 +71,8 @@ static const char* AlgorithmToStr(D3D12MA::POOL_FLAGS algorithm)
{
case D3D12MA::POOL_FLAG_ALGORITHM_LINEAR:
return "Linear";
case D3D12MA::POOL_FLAG_ALGORITHM_TLSF:
return "TLSF";
case 0:
return "Default";
return "TLSF";
default:
assert(0);
return "";
@ -87,10 +85,8 @@ static const char* VirtualAlgorithmToStr(D3D12MA::VIRTUAL_BLOCK_FLAGS algorithm)
{
case D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
return "Linear";
case D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF:
return "TLSF";
case 0:
return "Default";
return "TLSF";
default:
assert(0);
return "";
@ -199,13 +195,12 @@ static void TestDebugMargin(const TestContext& ctx)
POOL_DESC poolDesc = {};
poolDesc.HeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
for(size_t algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
for(size_t algorithmIndex = 0; algorithmIndex < 2; ++algorithmIndex)
{
switch(algorithmIndex)
{
case 0: poolDesc.Flags = POOL_FLAG_NONE; break;
case 1: poolDesc.Flags = POOL_FLAG_ALGORITHM_TLSF; break;
case 2: poolDesc.Flags = POOL_FLAG_ALGORITHM_LINEAR; break;
case 1: poolDesc.Flags = POOL_FLAG_ALGORITHM_LINEAR; break;
default: assert(0);
}
ComPtr<Pool> pool;
@ -263,15 +258,14 @@ static void TestDebugMarginNotInVirtualAllocator(const TestContext& ctx)
wprintf(L"Test D3D12MA_DEBUG_MARGIN not applied to virtual allocator\n");
using namespace D3D12MA;
constexpr size_t ALLOCATION_COUNT = 10;
for(size_t algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
for(size_t algorithmIndex = 0; algorithmIndex < 2; ++algorithmIndex)
{
VIRTUAL_BLOCK_DESC blockDesc = {};
blockDesc.Size = ALLOCATION_COUNT * MEGABYTE;
switch(algorithmIndex)
{
case 0: blockDesc.Flags = VIRTUAL_BLOCK_FLAG_NONE; break;
case 1: blockDesc.Flags = VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF; break;
case 2: blockDesc.Flags = VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR; break;
case 1: blockDesc.Flags = VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR; break;
default: assert(0);
}
@ -604,8 +598,8 @@ static void TestCustomPools(const TestContext& ctx)
// # Fetch global stats 1
D3D12MA::Stats globalStatsBeg = {};
ctx.allocator->CalculateStats(&globalStatsBeg);
D3D12MA::TotalStatistics globalStatsBeg = {};
ctx.allocator->CalculateStatistics(&globalStatsBeg);
// # Create pool, 1..2 blocks of 11 MB
@ -621,12 +615,13 @@ static void TestCustomPools(const TestContext& ctx)
// # Validate stats for empty pool
D3D12MA::StatInfo poolStats = {};
pool->CalculateStats(&poolStats);
CHECK_BOOL( poolStats.BlockCount == 1 );
CHECK_BOOL( poolStats.AllocationCount == 0 );
CHECK_BOOL( poolStats.UsedBytes == 0 );
CHECK_BOOL( poolStats.UnusedBytes == poolStats.BlockCount * poolDesc.BlockSize );
D3D12MA::DetailedStatistics poolStats = {};
pool->CalculateStatistics(&poolStats);
CHECK_BOOL( poolStats.Stats.BlockCount == 1 );
CHECK_BOOL( poolStats.Stats.AllocationCount == 0 );
CHECK_BOOL( poolStats.Stats.AllocationBytes == 0 );
CHECK_BOOL( poolStats.Stats.BlockBytes - poolStats.Stats.AllocationBytes ==
poolStats.Stats.BlockCount * poolDesc.BlockSize );
// # SetName and GetName
@ -657,20 +652,24 @@ static void TestCustomPools(const TestContext& ctx)
// # Validate pool stats now
pool->CalculateStats(&poolStats);
CHECK_BOOL( poolStats.BlockCount == 1 );
CHECK_BOOL( poolStats.AllocationCount == 2 );
CHECK_BOOL( poolStats.UsedBytes == 2 * BUFFER_SIZE );
CHECK_BOOL( poolStats.UnusedBytes == poolDesc.BlockSize - poolStats.UsedBytes );
pool->CalculateStatistics(&poolStats);
CHECK_BOOL( poolStats.Stats.BlockCount == 1 );
CHECK_BOOL( poolStats.Stats.AllocationCount == 2 );
CHECK_BOOL( poolStats.Stats.AllocationBytes == 2 * BUFFER_SIZE );
CHECK_BOOL( poolStats.Stats.BlockBytes - poolStats.Stats.AllocationBytes ==
poolDesc.BlockSize - poolStats.Stats.AllocationBytes );
// # Check that global stats are updated as well
D3D12MA::Stats globalStatsCurr = {};
ctx.allocator->CalculateStats(&globalStatsCurr);
D3D12MA::TotalStatistics globalStatsCurr = {};
ctx.allocator->CalculateStatistics(&globalStatsCurr);
CHECK_BOOL( globalStatsCurr.Total.AllocationCount == globalStatsBeg.Total.AllocationCount + poolStats.AllocationCount );
CHECK_BOOL( globalStatsCurr.Total.BlockCount == globalStatsBeg.Total.BlockCount + poolStats.BlockCount );
CHECK_BOOL( globalStatsCurr.Total.UsedBytes == globalStatsBeg.Total.UsedBytes + poolStats.UsedBytes );
CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationCount ==
globalStatsBeg.Total.Stats.AllocationCount + poolStats.Stats.AllocationCount );
CHECK_BOOL( globalStatsCurr.Total.Stats.BlockCount ==
globalStatsBeg.Total.Stats.BlockCount + poolStats.Stats.BlockCount );
CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationBytes ==
globalStatsBeg.Total.Stats.AllocationBytes + poolStats.Stats.AllocationBytes );
// # NEVER_ALLOCATE and COMMITTED should fail
// (Committed allocations not allowed in this pool because BlockSize != 0.)
@ -711,11 +710,12 @@ static void TestCustomPools(const TestContext& ctx)
}
}
pool->CalculateStats(&poolStats);
CHECK_BOOL( poolStats.BlockCount == 2 );
CHECK_BOOL( poolStats.AllocationCount == 4 );
CHECK_BOOL( poolStats.UsedBytes == 4 * BUFFER_SIZE );
CHECK_BOOL( poolStats.UnusedBytes == poolStats.BlockCount * poolDesc.BlockSize - poolStats.UsedBytes );
pool->CalculateStatistics(&poolStats);
CHECK_BOOL( poolStats.Stats.BlockCount == 2 );
CHECK_BOOL( poolStats.Stats.AllocationCount == 4 );
CHECK_BOOL( poolStats.Stats.AllocationBytes == 4 * BUFFER_SIZE );
CHECK_BOOL( poolStats.Stats.BlockBytes - poolStats.Stats.AllocationBytes ==
poolStats.Stats.BlockCount * poolDesc.BlockSize - poolStats.Stats.AllocationBytes );
// # Make room, AllocateMemory, CreateAliasingResource
@ -748,8 +748,8 @@ static void TestPoolsAndAllocationParameters(const TestContext& ctx)
D3D12MA::ALLOCATION_DESC allocDesc = {};
uint32_t totalNewAllocCount = 0, totalNewBlockCount = 0;
D3D12MA::Stats statsBeg, statsEnd;
ctx.allocator->CalculateStats(&statsBeg);
D3D12MA::TotalStatistics statsBeg, statsEnd;
ctx.allocator->CalculateStatistics(&statsBeg);
HRESULT hr;
ComPtr<D3D12MA::Allocation> alloc;
@ -842,22 +842,25 @@ static void TestPoolsAndAllocationParameters(const TestContext& ctx)
if(poolTypeI > 0)
{
D3D12MA::StatInfo poolStats = {};
(poolTypeI == 2 ? pool2 : pool1)->CalculateStats(&poolStats);
CHECK_BOOL(poolStats.AllocationCount == poolAllocCount);
CHECK_BOOL(poolStats.UsedBytes == poolAllocCount * MEGABYTE);
CHECK_BOOL(poolStats.BlockCount == poolBlockCount);
D3D12MA::DetailedStatistics poolStats = {};
(poolTypeI == 2 ? pool2 : pool1)->CalculateStatistics(&poolStats);
CHECK_BOOL(poolStats.Stats.AllocationCount == poolAllocCount);
CHECK_BOOL(poolStats.Stats.AllocationBytes == poolAllocCount * MEGABYTE);
CHECK_BOOL(poolStats.Stats.BlockCount == poolBlockCount);
}
totalNewAllocCount += poolAllocCount;
totalNewBlockCount += poolBlockCount;
}
ctx.allocator->CalculateStats(&statsEnd);
ctx.allocator->CalculateStatistics(&statsEnd);
CHECK_BOOL(statsEnd.Total.AllocationCount == statsBeg.Total.AllocationCount + totalNewAllocCount);
CHECK_BOOL(statsEnd.Total.BlockCount >= statsBeg.Total.BlockCount + totalNewBlockCount);
CHECK_BOOL(statsEnd.Total.UsedBytes == statsBeg.Total.UsedBytes + totalNewAllocCount * MEGABYTE);
CHECK_BOOL(statsEnd.Total.Stats.AllocationCount ==
statsBeg.Total.Stats.AllocationCount + totalNewAllocCount);
CHECK_BOOL(statsEnd.Total.Stats.BlockCount >=
statsBeg.Total.Stats.BlockCount + totalNewBlockCount);
CHECK_BOOL(statsEnd.Total.Stats.AllocationBytes ==
statsBeg.Total.Stats.AllocationBytes + totalNewAllocCount * MEGABYTE);
}
static void TestCustomPool_MinAllocationAlignment(const TestContext& ctx)
@ -927,8 +930,8 @@ static void TestCustomPool_Committed(const TestContext& ctx)
static HRESULT TestCustomHeap(const TestContext& ctx, const D3D12_HEAP_PROPERTIES& heapProps)
{
D3D12MA::Stats globalStatsBeg = {};
ctx.allocator->CalculateStats(&globalStatsBeg);
D3D12MA::TotalStatistics globalStatsBeg = {};
ctx.allocator->CalculateStatistics(&globalStatsBeg);
D3D12MA::POOL_DESC poolDesc = {};
poolDesc.HeapProperties = heapProps;
@ -957,19 +960,19 @@ static HRESULT TestCustomHeap(const TestContext& ctx, const D3D12_HEAP_PROPERTIE
&alloc,
__uuidof(ID3D12Resource), NULL) ); // riidResource, ppvResource
D3D12MA::Stats globalStatsCurr = {};
ctx.allocator->CalculateStats(&globalStatsCurr);
D3D12MA::TotalStatistics globalStatsCurr = {};
ctx.allocator->CalculateStatistics(&globalStatsCurr);
// Make sure it is accounted only in CUSTOM heap not any of the standard heaps.
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[0], &globalStatsBeg.HeapType[0], sizeof(D3D12MA::StatInfo)) == 0);
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[1], &globalStatsBeg.HeapType[1], sizeof(D3D12MA::StatInfo)) == 0);
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[2], &globalStatsBeg.HeapType[2], sizeof(D3D12MA::StatInfo)) == 0);
CHECK_BOOL( globalStatsCurr.HeapType[3].AllocationCount == globalStatsBeg.HeapType[3].AllocationCount + 1 );
CHECK_BOOL( globalStatsCurr.HeapType[3].BlockCount == globalStatsBeg.HeapType[3].BlockCount + 1 );
CHECK_BOOL( globalStatsCurr.HeapType[3].UsedBytes == globalStatsBeg.HeapType[3].UsedBytes + BUFFER_SIZE );
CHECK_BOOL( globalStatsCurr.Total.AllocationCount == globalStatsBeg.Total.AllocationCount + 1 );
CHECK_BOOL( globalStatsCurr.Total.BlockCount == globalStatsBeg.Total.BlockCount + 1 );
CHECK_BOOL( globalStatsCurr.Total.UsedBytes == globalStatsBeg.Total.UsedBytes + BUFFER_SIZE );
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[0], &globalStatsBeg.HeapType[0], sizeof(D3D12MA::DetailedStatistics)) == 0);
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[1], &globalStatsBeg.HeapType[1], sizeof(D3D12MA::DetailedStatistics)) == 0);
CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[2], &globalStatsBeg.HeapType[2], sizeof(D3D12MA::DetailedStatistics)) == 0);
CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.AllocationCount == globalStatsBeg.HeapType[3].Stats.AllocationCount + 1 );
CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.BlockCount == globalStatsBeg.HeapType[3].Stats.BlockCount + 1 );
CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.AllocationBytes == globalStatsBeg.HeapType[3].Stats.AllocationBytes + BUFFER_SIZE );
CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationCount == globalStatsBeg.Total.Stats.AllocationCount + 1 );
CHECK_BOOL( globalStatsCurr.Total.Stats.BlockCount == globalStatsBeg.Total.Stats.BlockCount + 1 );
CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationBytes == globalStatsBeg.Total.Stats.AllocationBytes + BUFFER_SIZE );
// Map and write some data.
if(heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE ||
@ -1020,10 +1023,10 @@ static void TestStandardCustomCommittedPlaced(const TestContext& ctx)
std::vector<ComPtr<D3D12MA::Allocation>> allocations;
D3D12MA::Stats statsBeg = {};
D3D12MA::StatInfo poolStatInfoBeg = {};
ctx.allocator->CalculateStats(&statsBeg);
pool->CalculateStats(&poolStatInfoBeg);
D3D12MA::TotalStatistics statsBeg = {};
D3D12MA::DetailedStatistics poolStatInfoBeg = {};
ctx.allocator->CalculateStatistics(&statsBeg);
pool->CalculateStatistics(&poolStatInfoBeg);
size_t poolAllocCount = 0;
@ -1074,17 +1077,17 @@ static void TestStandardCustomCommittedPlaced(const TestContext& ctx)
}
}
D3D12MA::Stats statsEnd = {};
D3D12MA::StatInfo poolStatInfoEnd = {};
ctx.allocator->CalculateStats(&statsEnd);
pool->CalculateStats(&poolStatInfoEnd);
D3D12MA::TotalStatistics statsEnd = {};
D3D12MA::DetailedStatistics poolStatInfoEnd = {};
ctx.allocator->CalculateStatistics(&statsEnd);
pool->CalculateStatistics(&poolStatInfoEnd);
CHECK_BOOL(statsEnd.Total.AllocationCount == statsBeg.Total.AllocationCount + allocations.size());
CHECK_BOOL(statsEnd.Total.UsedBytes >= statsBeg.Total.UsedBytes + allocations.size() * bufferSize);
CHECK_BOOL(statsEnd.HeapType[0].AllocationCount == statsBeg.HeapType[0].AllocationCount + allocations.size());
CHECK_BOOL(statsEnd.HeapType[0].UsedBytes >= statsBeg.HeapType[0].UsedBytes + allocations.size() * bufferSize);
CHECK_BOOL(poolStatInfoEnd.AllocationCount == poolStatInfoBeg.AllocationCount + poolAllocCount);
CHECK_BOOL(poolStatInfoEnd.UsedBytes >= poolStatInfoBeg.UsedBytes + poolAllocCount * bufferSize);
CHECK_BOOL(statsEnd.Total.Stats.AllocationCount == statsBeg.Total.Stats.AllocationCount + allocations.size());
CHECK_BOOL(statsEnd.Total.Stats.AllocationBytes >= statsBeg.Total.Stats.AllocationBytes + allocations.size() * bufferSize);
CHECK_BOOL(statsEnd.HeapType[0].Stats.AllocationCount == statsBeg.HeapType[0].Stats.AllocationCount + allocations.size());
CHECK_BOOL(statsEnd.HeapType[0].Stats.AllocationBytes >= statsBeg.HeapType[0].Stats.AllocationBytes + allocations.size() * bufferSize);
CHECK_BOOL(poolStatInfoEnd.Stats.AllocationCount == poolStatInfoBeg.Stats.AllocationCount + poolAllocCount);
CHECK_BOOL(poolStatInfoEnd.Stats.AllocationBytes >= poolStatInfoBeg.Stats.AllocationBytes + poolAllocCount * bufferSize);
}
static void TestAliasingMemory(const TestContext& ctx)
@ -1194,38 +1197,21 @@ static void TestMapping(const TestContext& ctx)
}
}
static inline bool StatInfoEqual(const D3D12MA::StatInfo& lhs, const D3D12MA::StatInfo& rhs)
static inline bool StatisticsEqual(const D3D12MA::DetailedStatistics& lhs, const D3D12MA::DetailedStatistics& rhs)
{
return lhs.BlockCount == rhs.BlockCount &&
lhs.AllocationCount == rhs.AllocationCount &&
lhs.UnusedRangeCount == rhs.UnusedRangeCount &&
lhs.UsedBytes == rhs.UsedBytes &&
lhs.UnusedBytes == rhs.UnusedBytes &&
lhs.AllocationSizeMin == rhs.AllocationSizeMin &&
lhs.AllocationSizeMax == rhs.AllocationSizeMax &&
lhs.AllocationSizeAvg == rhs.AllocationSizeAvg &&
lhs.UnusedRangeSizeMin == rhs.UnusedRangeSizeMin &&
lhs.UnusedRangeSizeMax == rhs.UnusedRangeSizeMax &&
lhs.UnusedRangeSizeAvg == rhs.UnusedRangeSizeAvg;
return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
static void CheckStatInfo(const D3D12MA::StatInfo& statInfo)
static void CheckStatistics(const D3D12MA::DetailedStatistics& stats)
{
if(statInfo.AllocationCount > 0)
if(stats.Stats.AllocationBytes > 0)
{
CHECK_BOOL(statInfo.AllocationSizeAvg >= statInfo.AllocationSizeMin &&
statInfo.AllocationSizeAvg <= statInfo.AllocationSizeMax);
CHECK_BOOL(stats.Stats.AllocationCount > 0);
}
if(statInfo.UsedBytes > 0)
if(stats.UnusedRangeCount > 0)
{
CHECK_BOOL(statInfo.AllocationCount > 0);
}
if(statInfo.UnusedRangeCount > 0)
{
CHECK_BOOL(statInfo.UnusedRangeSizeAvg >= statInfo.UnusedRangeSizeMin &&
statInfo.UnusedRangeSizeAvg <= statInfo.UnusedRangeSizeMax);
CHECK_BOOL(statInfo.UnusedRangeSizeMin > 0);
CHECK_BOOL(statInfo.UnusedRangeSizeMax > 0);
CHECK_BOOL(stats.UnusedRangeSizeMin > 0);
CHECK_BOOL(stats.UnusedRangeSizeMax > 0);
}
}
@ -1233,8 +1219,8 @@ static void TestStats(const TestContext& ctx)
{
wprintf(L"Test stats\n");
D3D12MA::Stats begStats = {};
ctx.allocator->CalculateStats(&begStats);
D3D12MA::TotalStatistics begStats = {};
ctx.allocator->CalculateStatistics(&begStats);
const UINT count = 10;
const UINT64 bufSize = 64ull * 1024;
@ -1259,40 +1245,40 @@ static void TestStats(const TestContext& ctx)
IID_PPV_ARGS(&resources[i].resource)) );
}
D3D12MA::Stats endStats = {};
ctx.allocator->CalculateStats(&endStats);
D3D12MA::TotalStatistics endStats = {};
ctx.allocator->CalculateStatistics(&endStats);
CHECK_BOOL(endStats.Total.BlockCount >= begStats.Total.BlockCount);
CHECK_BOOL(endStats.Total.AllocationCount == begStats.Total.AllocationCount + count);
CHECK_BOOL(endStats.Total.UsedBytes == begStats.Total.UsedBytes + count * bufSize);
CHECK_BOOL(endStats.Total.Stats.BlockCount >= begStats.Total.Stats.BlockCount);
CHECK_BOOL(endStats.Total.Stats.AllocationCount == begStats.Total.Stats.AllocationCount + count);
CHECK_BOOL(endStats.Total.Stats.AllocationBytes == begStats.Total.Stats.AllocationBytes + count * bufSize);
CHECK_BOOL(endStats.Total.AllocationSizeMin <= bufSize);
CHECK_BOOL(endStats.Total.AllocationSizeMax >= bufSize);
CHECK_BOOL(endStats.HeapType[1].BlockCount >= begStats.HeapType[1].BlockCount);
CHECK_BOOL(endStats.HeapType[1].AllocationCount >= begStats.HeapType[1].AllocationCount + count);
CHECK_BOOL(endStats.HeapType[1].UsedBytes >= begStats.HeapType[1].UsedBytes + count * bufSize);
CHECK_BOOL(endStats.HeapType[1].Stats.BlockCount >= begStats.HeapType[1].Stats.BlockCount);
CHECK_BOOL(endStats.HeapType[1].Stats.AllocationCount >= begStats.HeapType[1].Stats.AllocationCount + count);
CHECK_BOOL(endStats.HeapType[1].Stats.AllocationBytes >= begStats.HeapType[1].Stats.AllocationBytes + count * bufSize);
CHECK_BOOL(endStats.HeapType[1].AllocationSizeMin <= bufSize);
CHECK_BOOL(endStats.HeapType[1].AllocationSizeMax >= bufSize);
CHECK_BOOL(StatInfoEqual(begStats.HeapType[0], endStats.HeapType[0]));
CHECK_BOOL(StatInfoEqual(begStats.HeapType[2], endStats.HeapType[2]));
CHECK_BOOL(StatisticsEqual(begStats.HeapType[0], endStats.HeapType[0]));
CHECK_BOOL(StatisticsEqual(begStats.HeapType[2], endStats.HeapType[2]));
CheckStatInfo(endStats.Total);
CheckStatInfo(endStats.HeapType[0]);
CheckStatInfo(endStats.HeapType[1]);
CheckStatInfo(endStats.HeapType[2]);
CheckStatistics(endStats.Total);
CheckStatistics(endStats.HeapType[0]);
CheckStatistics(endStats.HeapType[1]);
CheckStatistics(endStats.HeapType[2]);
D3D12MA::Budget gpuBudget = {}, cpuBudget = {};
ctx.allocator->GetBudget(&gpuBudget, &cpuBudget);
CHECK_BOOL(gpuBudget.AllocationBytes <= gpuBudget.BlockBytes);
CHECK_BOOL(gpuBudget.AllocationBytes == endStats.HeapType[0].UsedBytes);
CHECK_BOOL(gpuBudget.BlockBytes == endStats.HeapType[0].UsedBytes + endStats.HeapType[0].UnusedBytes);
CHECK_BOOL(gpuBudget.Stats.AllocationBytes <= gpuBudget.Stats.BlockBytes);
CHECK_BOOL(gpuBudget.Stats.AllocationBytes == endStats.HeapType[0].Stats.AllocationBytes);
CHECK_BOOL(gpuBudget.Stats.BlockBytes == endStats.HeapType[0].Stats.BlockBytes);
CHECK_BOOL(cpuBudget.AllocationBytes <= cpuBudget.BlockBytes);
CHECK_BOOL(cpuBudget.AllocationBytes == endStats.HeapType[1].UsedBytes + endStats.HeapType[2].UsedBytes);
CHECK_BOOL(cpuBudget.BlockBytes == endStats.HeapType[1].UsedBytes + endStats.HeapType[1].UnusedBytes +
endStats.HeapType[2].UsedBytes + endStats.HeapType[2].UnusedBytes);
CHECK_BOOL(cpuBudget.Stats.AllocationBytes <= cpuBudget.Stats.BlockBytes);
CHECK_BOOL(cpuBudget.Stats.AllocationBytes == endStats.HeapType[1].Stats.AllocationBytes + endStats.HeapType[2].Stats.AllocationBytes);
CHECK_BOOL(cpuBudget.Stats.BlockBytes ==
endStats.HeapType[1].Stats.BlockBytes + endStats.HeapType[2].Stats.BlockBytes);
}
static void TestTransfer(const TestContext& ctx)
@ -1728,11 +1714,11 @@ static void TestLinearAllocator(const TestContext& ctx)
}
// Validate pool stats.
D3D12MA::StatInfo stats;
pool->CalculateStats(&stats);
CHECK_BOOL(stats.UnusedBytes == poolDesc.BlockSize - allocSumSize);
D3D12MA::DetailedStatistics stats;
pool->CalculateStatistics(&stats);
CHECK_BOOL(stats.Stats.BlockBytes - stats.Stats.AllocationBytes == poolDesc.BlockSize - allocSumSize);
CHECK_BOOL(allocSumSize >= bufSumSize);
CHECK_BOOL(stats.AllocationCount == buffInfo.size());
CHECK_BOOL(stats.Stats.AllocationCount == buffInfo.size());
// Destroy the buffers in random order.
while (!buffInfo.empty())
@ -2008,9 +1994,9 @@ static void TestLinearAllocatorMultiBlock(const TestContext& ctx)
CHECK_BOOL(buffInfo.size() > 2);
// Make sure that pool has now two blocks.
D3D12MA::StatInfo poolStats = {};
pool->CalculateStats(&poolStats);
CHECK_BOOL(poolStats.BlockCount == 2);
D3D12MA::DetailedStatistics poolStats = {};
pool->CalculateStatistics(&poolStats);
CHECK_BOOL(poolStats.Stats.BlockCount == 2);
// Destroy all the buffers in random order.
while (!buffInfo.empty())
@ -2020,8 +2006,8 @@ static void TestLinearAllocatorMultiBlock(const TestContext& ctx)
}
// Make sure that pool has now at most one block.
pool->CalculateStats(&poolStats);
CHECK_BOOL(poolStats.BlockCount <= 1);
pool->CalculateStatistics(&poolStats);
CHECK_BOOL(poolStats.Stats.BlockCount <= 1);
}
// Test stack.
@ -2053,9 +2039,9 @@ static void TestLinearAllocatorMultiBlock(const TestContext& ctx)
}
// Make sure that pool has now two blocks.
D3D12MA::StatInfo poolStats = {};
pool->CalculateStats(&poolStats);
CHECK_BOOL(poolStats.BlockCount == 2);
D3D12MA::DetailedStatistics poolStats = {};
pool->CalculateStatistics(&poolStats);
CHECK_BOOL(poolStats.Stats.BlockCount == 2);
// Delete half of buffers, LIFO.
for (size_t i = 0, countToDelete = buffInfo.size() / 2; i < countToDelete; ++i)
@ -2068,8 +2054,8 @@ static void TestLinearAllocatorMultiBlock(const TestContext& ctx)
buffInfo.push_back(std::move(newBuffInfo));
// Make sure that pool has now one block.
pool->CalculateStats(&poolStats);
CHECK_BOOL(poolStats.BlockCount == 1);
pool->CalculateStatistics(&poolStats);
CHECK_BOOL(poolStats.Stats.BlockCount == 1);
// Delete all the remaining buffers, LIFO.
while (!buffInfo.empty())
@ -2083,8 +2069,8 @@ static void ManuallyTestLinearAllocator(const TestContext& ctx)
RandomNumberGenerator rand{ 645332 };
D3D12MA::Stats origStats;
ctx.allocator->CalculateStats(&origStats);
D3D12MA::TotalStatistics origStats;
ctx.allocator->CalculateStatistics(&origStats);
D3D12MA::POOL_DESC poolDesc = {};
poolDesc.HeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
@ -2155,10 +2141,10 @@ static void ManuallyTestLinearAllocator(const TestContext& ctx)
nullptr, &newBuffInfo.Allocation, IID_PPV_ARGS(&newBuffInfo.Buffer)));
buffInfo.push_back(std::move(newBuffInfo));
D3D12MA::Stats currStats;
ctx.allocator->CalculateStats(&currStats);
D3D12MA::StatInfo poolStats;
pool->CalculateStats(&poolStats);
D3D12MA::TotalStatistics currStats;
ctx.allocator->CalculateStatistics(&currStats);
D3D12MA::DetailedStatistics poolStats;
pool->CalculateStatistics(&poolStats);
WCHAR* statsStr = nullptr;
ctx.allocator->BuildStatsString(&statsStr, FALSE);
@ -2323,7 +2309,7 @@ static void BenchmarkAlgorithms(const TestContext& ctx, FILE* file)
for (UINT32 emptyIndex = 0; emptyIndex < emptyCount; ++emptyIndex)
{
for (UINT32 algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
for (UINT32 algorithmIndex = 0; algorithmIndex < 2; ++algorithmIndex)
{
D3D12MA::POOL_FLAGS algorithm;
switch (algorithmIndex)
@ -2334,9 +2320,6 @@ static void BenchmarkAlgorithms(const TestContext& ctx, FILE* file)
case 1:
algorithm = D3D12MA::POOL_FLAG_ALGORITHM_LINEAR;
break;
case 2:
algorithm = D3D12MA::POOL_FLAG_ALGORITHM_TLSF;
break;
default:
assert(0);
}
@ -2537,12 +2520,12 @@ static void TestVirtualBlocks(const TestContext& ctx)
// # Calculate statistics
StatInfo statInfo = {};
block->CalculateStats(&statInfo);
CHECK_BOOL(statInfo.AllocationCount == 2);
CHECK_BOOL(statInfo.BlockCount == 1);
CHECK_BOOL(statInfo.UsedBytes == blockSize);
CHECK_BOOL(statInfo.UnusedBytes + statInfo.UsedBytes == blockSize);
DetailedStatistics statInfo = {};
block->CalculateStatistics(&statInfo);
CHECK_BOOL(statInfo.Stats.AllocationCount == 2);
CHECK_BOOL(statInfo.Stats.BlockCount == 1);
CHECK_BOOL(statInfo.Stats.AllocationBytes == blockSize);
CHECK_BOOL(statInfo.Stats.BlockBytes == blockSize);
// # Generate JSON dump
@ -2595,7 +2578,7 @@ static void TestVirtualBlocksAlgorithms(const TestContext& ctx)
RandomNumberGenerator rand{ 3454335 };
auto calcRandomAllocSize = [&rand]() -> UINT64 { return rand.Generate() % 20 + 5; };
for (size_t algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
for (size_t algorithmIndex = 0; algorithmIndex < 2; ++algorithmIndex)
{
// Create the block
D3D12MA::VIRTUAL_BLOCK_DESC blockDesc = {};
@ -2603,8 +2586,8 @@ static void TestVirtualBlocksAlgorithms(const TestContext& ctx)
blockDesc.Size = 10'000;
switch (algorithmIndex)
{
case 0: blockDesc.Flags = D3D12MA::VIRTUAL_BLOCK_FLAG_NONE; break;
case 1: blockDesc.Flags = D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR; break;
case 2: blockDesc.Flags = D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF; break;
}
ComPtr<D3D12MA::VirtualBlock> block;
CHECK_HR(D3D12MA::CreateVirtualBlock(&blockDesc, &block));
@ -2717,14 +2700,14 @@ static void TestVirtualBlocksAlgorithms(const TestContext& ctx)
actualAllocSizeSum += a.allocationSize;
});
D3D12MA::StatInfo statInfo = {};
block->CalculateStats(&statInfo);
CHECK_BOOL(statInfo.AllocationCount == allocations.size());
CHECK_BOOL(statInfo.BlockCount == 1);
CHECK_BOOL(statInfo.UsedBytes + statInfo.UnusedBytes == blockDesc.Size);
D3D12MA::DetailedStatistics statInfo = {};
block->CalculateStatistics(&statInfo);
CHECK_BOOL(statInfo.Stats.AllocationCount == allocations.size());
CHECK_BOOL(statInfo.Stats.BlockCount == 1);
CHECK_BOOL(statInfo.Stats.BlockBytes == blockDesc.Size);
CHECK_BOOL(statInfo.AllocationSizeMax == actualAllocSizeMax);
CHECK_BOOL(statInfo.AllocationSizeMin == actualAllocSizeMin);
CHECK_BOOL(statInfo.UsedBytes >= actualAllocSizeSum);
CHECK_BOOL(statInfo.Stats.AllocationBytes >= actualAllocSizeSum);
}
// Build JSON dump string
@ -2774,7 +2757,7 @@ static void TestVirtualBlocksAlgorithmsBenchmark(const TestContext& ctx)
}
printf(" Alignment=%llu\n", alignment);
for (UINT8 algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
for (UINT8 algorithmIndex = 0; algorithmIndex < 2; ++algorithmIndex)
{
switch (algorithmIndex)
{
@ -2784,9 +2767,6 @@ static void TestVirtualBlocksAlgorithmsBenchmark(const TestContext& ctx)
case 1:
blockDesc.Flags = D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR;
break;
case 2:
blockDesc.Flags = D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_TLSF;
break;
default:
assert(0);
}