Merge pull request #1 from Silveryard/master

Fixed compilation error in Vector::reserve
diff --git a/README.md b/README.md
index b403ae8..2213016 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,8 @@
 - Thread-safety: Library is designed to be used in multithreaded code.
 - Configuration: Fill optional members of `ALLOCATOR_DESC` structure to provide custom CPU memory allocator and other parameters.
 - Customization: Predefine appropriate macros to provide your own implementation of external facilities used by the library, like assert, mutex, and atomic.
+- Statistics: Obtain detailed statistics about the amount of memory used, unused, number of allocated blocks, number of allocations etc. - globally and per memory heap type.
+- Debug annotations: Associate string name with every allocation.
 
 # Prerequisites
 
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 4d3b04e..f0c5385 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -466,8 +466,6 @@
     }

 };

 

-static const UINT HEAP_TYPE_COUNT = 3;

-

 static UINT HeapTypeToIndex(D3D12_HEAP_TYPE type)

 {

     switch(type)

@@ -479,6 +477,29 @@
     }

 }

 

+// Stat helper functions

+

+static void AddStatInfo(StatInfo& dst, const StatInfo& src)

+{

+    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);

+}

+

+static void PostProcessStatInfo(StatInfo& statInfo)

+{

+    statInfo.AllocationSizeAvg = statInfo.AllocationCount ?

+        statInfo.UsedBytes / statInfo.AllocationCount : 0;

+    statInfo.UnusedRangeSizeAvg = statInfo.UnusedRangeCount ?

+        statInfo.UnusedBytes / statInfo.UnusedRangeCount : 0;

+}

+

 ////////////////////////////////////////////////////////////////////////////////

 // Private class Vector

 

@@ -1406,11 +1427,15 @@
     virtual void Free(const Allocation* allocation) = 0;

     virtual void FreeAtOffset(UINT64 offset) = 0;

 

+    virtual void CalcAllocationStatInfo(StatInfo& outInfo) const = 0;

+

 protected:

     const ALLOCATION_CALLBACKS* GetAllocs() const { return m_pAllocationCallbacks; }

 

 private:

     UINT64 m_Size;

+

+private:

     const ALLOCATION_CALLBACKS* m_pAllocationCallbacks;

 

     D3D12MA_CLASS_NO_COPY(BlockMetadata);

@@ -1442,6 +1467,8 @@
     virtual void Free(const Allocation* allocation);

     virtual void FreeAtOffset(UINT64 offset);

 

+    virtual void CalcAllocationStatInfo(StatInfo& outInfo) const;

+

 private:

     UINT m_FreeCount;

     UINT64 m_SumFreeSize;

@@ -1482,7 +1509,7 @@
 

 /*

 Represents a single block of device memory (heap) with all the data about its

-regions (aka suballocations, #Allocation), assigned and free.

+regions (aka suballocations, Allocation), assigned and free.

 

 Thread-safety: This class must be externally synchronized.

 */

@@ -1566,6 +1593,8 @@
     void Free(

         Allocation* hAllocation);

 

+    void AddStats(Stats& outpStats);

+

 private:

     static UINT64 HeapFlagsToAlignment(D3D12_HEAP_FLAGS flags);

 

@@ -1646,6 +1675,8 @@
     // Allocation object must be deleted externally afterwards.

     void FreePlacedMemory(Allocation* allocation);

 

+    void CalculateStats(Stats& outStats);

+

 private:

     friend class Allocator;

 

@@ -2183,6 +2214,40 @@
     //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());

 }

 

+void BlockMetadata_Generic::CalcAllocationStatInfo(StatInfo& outInfo) const

+{

+    outInfo.BlockCount = 1;

+

+    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;

+

+    for(SuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();

+        suballocItem != m_Suballocations.cend();

+        ++suballocItem)

+    {

+        const Suballocation& suballoc = *suballocItem;

+        if(suballoc.type == SUBALLOCATION_TYPE_FREE)

+        {

+            outInfo.UnusedRangeSizeMin = D3D12MA_MIN(suballoc.size, outInfo.UnusedRangeSizeMin);

+            outInfo.UnusedRangeSizeMax = D3D12MA_MAX(suballoc.size, outInfo.UnusedRangeSizeMax);

+        }

+        else

+        {

+            outInfo.AllocationSizeMin = D3D12MA_MIN(suballoc.size, outInfo.AllocationSizeMin);

+            outInfo.AllocationSizeMax = D3D12MA_MAX(suballoc.size, outInfo.AllocationSizeMax);

+        }

+    }

+}

+

 ////////////////////////////////////////////////////////////////////////////////

 // Private class DeviceMemoryBlock implementation

 

@@ -2624,6 +2689,25 @@
     return m_hAllocator->GetDevice()->CreateHeap(&heapDesc, IID_PPV_ARGS(&outHeap));

 }

 

+void BlockVector::AddStats(Stats& outStats)

+{

+    const UINT heapTypeIndex = HeapTypeToIndex(m_HeapType);

+    StatInfo* const pStatInfo = &outStats.HeapType[heapTypeIndex];

+

+    MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());

+

+    for(size_t i = 0; i < m_Blocks.size(); ++i)

+    {

+        const DeviceMemoryBlock* 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);

+    }

+}

+

 ////////////////////////////////////////////////////////////////////////////////

 // Private class AllocatorPimpl implementation

 

@@ -2935,6 +3019,57 @@
     blockVector->Free(allocation);

 }

 

+void AllocatorPimpl::CalculateStats(Stats& outStats)

+{

+    // Init stats

+    memset(&outStats, 0, sizeof(outStats));

+    outStats.Total.AllocationSizeMin = UINT64_MAX;

+    outStats.Total.UnusedRangeSizeMin = UINT64_MAX;

+    for(size_t i = 0; i < HEAP_TYPE_COUNT; i++)

+    {

+        outStats.HeapType[i].AllocationSizeMin = UINT64_MAX;

+        outStats.HeapType[i].UnusedRangeSizeMin = UINT64_MAX;

+    }

+

+    // Process deafult pools.

+    for(size_t i = 0; i < HEAP_TYPE_COUNT; ++i)

+    {

+        BlockVector* const pBlockVector = m_BlockVectors[i];

+        D3D12MA_ASSERT(pBlockVector);

+        pBlockVector->AddStats(outStats);

+    }

+

+    // Process committed allocations.

+    for(size_t i = 0; i < HEAP_TYPE_COUNT; ++i)

+    {

+        StatInfo& heapStatInfo = outStats.HeapType[i];

+        MutexLockRead lock(m_CommittedAllocationsMutex[i], m_UseMutex);

+        const AllocationVectorType* const allocationVector = m_pCommittedAllocations[i];

+        D3D12MA_ASSERT(allocationVector);

+        for(size_t j = 0, count = allocationVector->size(); j < count; ++j)

+        {

+            UINT64 size = (*allocationVector)[j]->GetSize();

+            StatInfo statInfo = {};

+            statInfo.BlockCount = 1;

+            statInfo.AllocationCount = 1;

+            statInfo.UnusedRangeCount = 0;

+            statInfo.UsedBytes = size;

+            statInfo.UnusedBytes = 0;

+            statInfo.AllocationSizeMin = size;

+            statInfo.AllocationSizeMax = size;

+            statInfo.UnusedRangeSizeMin = 0;

+            statInfo.UnusedRangeSizeMax = 0;

+            AddStatInfo(outStats.Total, statInfo);

+            AddStatInfo(heapStatInfo, statInfo);

+        }

+    }

+

+    // Post process

+    PostProcessStatInfo(outStats.Total);

+    for(size_t i = 0; i < HEAP_TYPE_COUNT; ++i)

+        PostProcessStatInfo(outStats.HeapType[i]);

+}

+

 

 ////////////////////////////////////////////////////////////////////////////////

 // Public class Allocation implementation

@@ -3095,6 +3230,13 @@
     return m_Pimpl->CreateResource(pAllocDesc, pResourceDesc, InitialResourceState, pOptimizedClearValue, ppAllocation, riidResource, ppvResource);

 }

 

+void Allocator::CalculateStats(Stats* pStats)

+{

+    D3D12MA_ASSERT(pStats);

+    D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK

+    m_Pimpl->CalculateStats(*pStats);

+}

+

 ////////////////////////////////////////////////////////////////////////////////

 // Public global functions

 

diff --git a/src/D3D12MemAlloc.h b/src/D3D12MemAlloc.h
index 8fdcdf6..610fcea 100644
--- a/src/D3D12MemAlloc.h
+++ b/src/D3D12MemAlloc.h
@@ -24,7 +24,7 @@
 

 /** \mainpage D3D12 Memory Allocator

 

-<b>Version 1.0.0</b> (2019-09-02)

+<b>Version 1.0.0-development</b> (2019-09-30)

 

 Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. \n

 License: MIT

@@ -295,8 +295,7 @@
 

 - Custom memory pools

 - Alternative allocation algorithms: linear allocator, buddy allocator

-- Statistics about memory usage, number of allocations, allocated blocks etc.,

-  along with JSON dump that can be visualized on a picture

+- JSON dump that can be visualized on a picture

 - Support for priorities using `ID3D12Device1::SetResidencyPriority`

 - Support for "lost" allocations

 

@@ -537,6 +536,48 @@
 };

 

 /**

+\brief Number of D3D12 memory heap types supported.

+*/

+const UINT HEAP_TYPE_COUNT = 3;

+

+/**

+\brief Calculated statistics of memory usage in entire allocator.

+*/

+struct StatInfo

+{

+    /// 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;

+    /// Total number of bytes occupied by all allocations.

+    UINT64 UsedBytes;

+    /// Total number of bytes occupied by unused ranges.

+    UINT64 UnusedBytes;

+    UINT64 AllocationSizeMin;

+    UINT64 AllocationSizeAvg;

+    UINT64 AllocationSizeMax;

+    UINT64 UnusedRangeSizeMin;

+    UINT64 UnusedRangeSizeAvg;

+    UINT64 UnusedRangeSizeMax;

+};

+

+/**

+\brief General statistics from the current state of the allocator.

+*/

+struct Stats

+{

+    /// Total statistics from all heap types.

+    StatInfo Total;

+    /**

+    One StatInfo for each type of heap located at the following indices:

+    0 - DEFAULT, 1 - UPLOAD, 2 - READBACK.

+    */

+    StatInfo HeapType[HEAP_TYPE_COUNT];

+};

+

+/**

 \brief Represents main object of this library initialized for particular `ID3D12Device`.

 

 Fill structure D3D12MA::ALLOCATOR_DESC and call function CreateAllocator() to create it.

@@ -577,6 +618,10 @@
         REFIID riidResource,

         void** ppvResource);

 

+    /** \brief Retrieves statistics from the current state of the allocator.

+    */

+    void CalculateStats(Stats* pStats);

+

 private:

     friend HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);

     template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);

diff --git a/src/Doxyfile b/src/Doxyfile
index 0b2b439..1bd8fae 100644
--- a/src/Doxyfile
+++ b/src/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.13

+# Doxyfile 1.8.16

 

 # This file describes the settings to be used by the documentation system

 # doxygen (www.doxygen.org) for a project.

@@ -17,11 +17,11 @@
 # Project related configuration options

 #---------------------------------------------------------------------------

 

-# This tag specifies the encoding used for all characters in the config file

-# that follow. The default is UTF-8 which is also the encoding used for all text

-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv

-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv

-# for the list of possible encodings.

+# This tag specifies the encoding used for all characters in the configuration

+# file that follow. The default is UTF-8 which is also the encoding used for all

+# text before the first occurrence of this tag. Doxygen uses libiconv (or the

+# iconv built into libc) for the transcoding. See

+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.

 # The default value is: UTF-8.

 

 DOXYFILE_ENCODING      = UTF-8

@@ -93,6 +93,14 @@
 

 OUTPUT_LANGUAGE        = English

 

+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all

+# documentation generated by doxygen is written. Doxygen will use this

+# information to generate all generated output in the proper direction.

+# Possible values are: None, LTR, RTL and Context.

+# The default value is: None.

+

+OUTPUT_TEXT_DIRECTION  = None

+

 # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member

 # descriptions after the members that are listed in the file and class

 # documentation (similar to Javadoc). Set to NO to disable this.

@@ -189,6 +197,16 @@
 

 JAVADOC_AUTOBRIEF      = NO

 

+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line

+# such as

+# /***************

+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the

+# Javadoc-style will behave just like regular comments and it will not be

+# interpreted by doxygen.

+# The default value is: NO.

+

+JAVADOC_BANNER         = NO

+

 # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first

 # line (until the first dot) of a Qt-style comment as the brief description. If

 # set to NO, the Qt-style will behave just like regular Qt-style comments (thus

@@ -236,7 +254,12 @@
 # will allow you to put the command \sideeffect (or @sideeffect) in the

 # documentation, which will result in a user-defined paragraph with heading

 # "Side Effects:". You can put \n's in the value part of an alias to insert

-# newlines.

+# newlines (in the resulting output). You can put ^^ in the value part of an

+# alias to insert a newline as if a physical newline was in the original file.

+# When you need a literal { or } or , in the value part of an alias you have to

+# escape them by means of a backslash (\), this can lead to conflicts with the

+# commands \{ and \} for these it is advised to use the version @{ and @} or use

+# a double escape (\\{ and \\})

 

 ALIASES                =

 

@@ -274,17 +297,26 @@
 

 OPTIMIZE_OUTPUT_VHDL   = NO

 

+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice

+# sources only. Doxygen will then generate output that is more tailored for that

+# language. For instance, namespaces will be presented as modules, types will be

+# separated into more groups, etc.

+# The default value is: NO.

+

+OPTIMIZE_OUTPUT_SLICE  = NO

+

 # Doxygen selects the parser to use depending on the extension of the files it

 # parses. With this tag you can assign which parser to use for a given

 # extension. Doxygen has a built-in mapping, but you can override or extend it

 # using this tag. The format is ext=language, where ext is a file extension, and

 # language is one of the parsers supported by doxygen: IDL, Java, Javascript,

-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:

-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:

-# Fortran. In the later case the parser tries to guess whether the code is fixed

-# or free formatted code, this is the default for Fortran type files), VHDL. For

-# instance to make doxygen treat .inc files as Fortran files (default is PHP),

-# and .f files as C (default is Fortran), use: inc=Fortran f=C.

+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,

+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:

+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser

+# tries to guess whether the code is fixed or free formatted code, this is the

+# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat

+# .inc files as Fortran files (default is PHP), and .f files as C (default is

+# Fortran), use: inc=Fortran f=C.

 #

 # Note: For files without extension you can use no_extension as a placeholder.

 #

@@ -295,7 +327,7 @@
 

 # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments

 # according to the Markdown format, which allows for more readable

-# documentation. See http://daringfireball.net/projects/markdown/ for details.

+# documentation. See https://daringfireball.net/projects/markdown/ for details.

 # The output of markdown processing is further processed by doxygen, so you can

 # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in

 # case of backward compatibilities issues.

@@ -307,7 +339,7 @@
 # to that level are automatically included in the table of contents, even if

 # they do not have an id attribute.

 # Note: This feature currently applies only to Markdown headings.

-# Minimum value: 0, maximum value: 99, default value: 0.

+# Minimum value: 0, maximum value: 99, default value: 5.

 # This tag requires that the tag MARKDOWN_SUPPORT is set to YES.

 

 TOC_INCLUDE_HEADINGS   = 0

@@ -337,7 +369,7 @@
 CPP_CLI_SUPPORT        = NO

 

 # Set the SIP_SUPPORT tag to YES if your project consists of sip (see:

-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen

+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen

 # will parse them like normal C++ but will assume all classes use public instead

 # of private inheritance when no explicit protection keyword is present.

 # The default value is: NO.

@@ -443,6 +475,12 @@
 

 EXTRACT_PRIVATE        = NO

 

+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual

+# methods of a class will be included in the documentation.

+# The default value is: NO.

+

+EXTRACT_PRIV_VIRTUAL   = NO

+

 # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal

 # scope will be included in the documentation.

 # The default value is: NO.

@@ -521,7 +559,7 @@
 # names in lower-case letters. If set to YES, upper-case letters are also

 # allowed. This is useful if you have classes or files whose names only differ

 # in case and if your file system supports case sensitive file names. Windows

-# and Mac users are advised to set this option to NO.

+# (including Cygwin) ands Mac users are advised to set this option to NO.

 # The default value is: system dependent.

 

 CASE_SENSE_NAMES       = NO

@@ -708,7 +746,7 @@
 # The CITE_BIB_FILES tag can be used to specify one or more bib files containing

 # the reference definitions. This must be a list of .bib files. The .bib

 # extension is automatically appended if omitted. This requires the bibtex tool

-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.

+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.

 # For LaTeX the style of the bibliography can be controlled using

 # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the

 # search path. See also \cite for info how to create references.

@@ -753,7 +791,8 @@
 # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that

 # are documented, but have no documentation for their parameters or return

 # value. If set to NO, doxygen will only warn about wrong or incomplete

-# parameter documentation, but not about the absence of documentation.

+# parameter documentation, but not about the absence of documentation. If

+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.

 # The default value is: NO.

 

 WARN_NO_PARAMDOC       = NO

@@ -795,7 +834,7 @@
 # This tag can be used to specify the character encoding of the source files

 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

 # libiconv (or the iconv built into libc) for the transcoding. See the libiconv

-# documentation (see: http://www.gnu.org/software/libiconv) for the list of

+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of

 # possible encodings.

 # The default value is: UTF-8.

 

@@ -813,7 +852,7 @@
 # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,

 # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,

 # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,

-# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.

+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.

 

 FILE_PATTERNS          = *.c \

                          *.cc \

@@ -1011,7 +1050,7 @@
 STRIP_CODE_COMMENTS    = YES

 

 # If the REFERENCED_BY_RELATION tag is set to YES then for each documented

-# function all documented functions referencing it will be listed.

+# entity all documented functions referencing it will be listed.

 # The default value is: NO.

 

 REFERENCED_BY_RELATION = NO

@@ -1043,12 +1082,12 @@
 # If the USE_HTAGS tag is set to YES then the references to source code will

 # point to the HTML generated by the htags(1) tool instead of doxygen built-in

 # source browser. The htags tool is part of GNU's global source tagging system

-# (see http://www.gnu.org/software/global/global.html). You will need version

+# (see https://www.gnu.org/software/global/global.html). You will need version

 # 4.8.6 or higher.

 #

 # To use it do the following:

 # - Install the latest version of global

-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file

+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file

 # - Make sure the INPUT points to the root of the source tree

 # - Run doxygen as normal

 #

@@ -1076,7 +1115,7 @@
 # rich C++ code for which doxygen's built-in parser lacks the necessary type

 # information.

 # Note: The availability of this option depends on whether or not doxygen was

-# generated with the -Duse-libclang=ON option for CMake.

+# generated with the -Duse_libclang=ON option for CMake.

 # The default value is: NO.

 

 CLANG_ASSISTED_PARSING = NO

@@ -1089,6 +1128,16 @@
 

 CLANG_OPTIONS          =

 

+# If clang assisted parsing is enabled you can provide the clang parser with the

+# path to the compilation database (see:

+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files

+# were built. This is equivalent to specifying the "-p" option to a clang tool,

+# such as clang-check. These options will then be passed to the parser.

+# Note: The availability of this option depends on whether or not doxygen was

+# generated with the -Duse_libclang=ON option for CMake.

+

+CLANG_DATABASE_PATH    =

+

 #---------------------------------------------------------------------------

 # Configuration options related to the alphabetical class index

 #---------------------------------------------------------------------------

@@ -1207,7 +1256,7 @@
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen

 # will adjust the colors in the style sheet and background images according to

 # this color. Hue is specified as an angle on a colorwheel, see

-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value

+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value

 # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300

 # purple, and 360 is red again.

 # Minimum value: 0, maximum value: 359, default value: 220.

@@ -1243,6 +1292,17 @@
 

 HTML_TIMESTAMP         = NO

 

+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML

+# documentation will contain a main index with vertical navigation menus that

+# are dynamically created via Javascript. If disabled, the navigation index will

+# consists of multiple levels of tabs that are statically embedded in every HTML

+# page. Disable this option to support browsers that do not have Javascript,

+# like the Qt help browser.

+# The default value is: YES.

+# This tag requires that the tag GENERATE_HTML is set to YES.

+

+HTML_DYNAMIC_MENUS     = YES

+

 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML

 # documentation will contain sections that can be hidden and shown after the

 # page has loaded.

@@ -1266,13 +1326,13 @@
 

 # If the GENERATE_DOCSET tag is set to YES, additional index files will be

 # generated that can be used as input for Apple's Xcode 3 integrated development

-# environment (see: http://developer.apple.com/tools/xcode/), introduced with

-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a

+# environment (see: https://developer.apple.com/xcode/), introduced with OSX

+# 10.5 (Leopard). To create a documentation set, doxygen will generate a

 # Makefile in the HTML output directory. Running make will produce the docset in

 # that directory and running make install will install the docset in

 # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at

-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html

-# for more information.

+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy

+# genXcode/_index.html for more information.

 # The default value is: NO.

 # This tag requires that the tag GENERATE_HTML is set to YES.

 

@@ -1311,7 +1371,7 @@
 # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three

 # additional HTML index files: index.hhp, index.hhc, and index.hhk. The

 # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop

-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on

+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on

 # Windows.

 #

 # The HTML Help Workshop contains a compiler that can convert all HTML output

@@ -1387,7 +1447,7 @@
 

 # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help

 # Project output. For more information please see Qt Help Project / Namespace

-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).

+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).

 # The default value is: org.doxygen.Project.

 # This tag requires that the tag GENERATE_QHP is set to YES.

 

@@ -1395,7 +1455,7 @@
 

 # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt

 # Help Project output. For more information please see Qt Help Project / Virtual

-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-

+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-

 # folders).

 # The default value is: doc.

 # This tag requires that the tag GENERATE_QHP is set to YES.

@@ -1404,7 +1464,7 @@
 

 # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom

 # filter to add. For more information please see Qt Help Project / Custom

-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-

+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-

 # filters).

 # This tag requires that the tag GENERATE_QHP is set to YES.

 

@@ -1412,7 +1472,7 @@
 

 # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the

 # custom filter to add. For more information please see Qt Help Project / Custom

-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-

+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-

 # filters).

 # This tag requires that the tag GENERATE_QHP is set to YES.

 

@@ -1420,7 +1480,7 @@
 

 # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this

 # project's filter section matches. Qt Help Project / Filter Attributes (see:

-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).

+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).

 # This tag requires that the tag GENERATE_QHP is set to YES.

 

 QHP_SECT_FILTER_ATTRS  =

@@ -1513,7 +1573,7 @@
 

 FORMULA_FONTSIZE       = 10

 

-# Use the FORMULA_TRANPARENT tag to determine whether or not the images

+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images

 # generated for formulas are transparent PNGs. Transparent PNGs are not

 # supported properly for IE 6.0, but are supported on all modern browsers.

 #

@@ -1525,7 +1585,7 @@
 FORMULA_TRANSPARENT    = YES

 

 # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see

-# http://www.mathjax.org) which uses client side Javascript for the rendering

+# https://www.mathjax.org) which uses client side Javascript for the rendering

 # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX

 # installed or if you want to formulas look prettier in the HTML output. When

 # enabled you may also need to install MathJax separately and configure the path

@@ -1552,8 +1612,8 @@
 # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax

 # Content Delivery Network so you can quickly see the result without installing

 # MathJax. However, it is strongly recommended to install a local copy of

-# MathJax from http://www.mathjax.org before deployment.

-# The default value is: http://cdn.mathjax.org/mathjax/latest.

+# MathJax from https://www.mathjax.org before deployment.

+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.

 # This tag requires that the tag USE_MATHJAX is set to YES.

 

 MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest

@@ -1614,7 +1674,7 @@
 #

 # Doxygen ships with an example indexer (doxyindexer) and search engine

 # (doxysearch.cgi) which are based on the open source search engine library

-# Xapian (see: http://xapian.org/).

+# Xapian (see: https://xapian.org/).

 #

 # See the section "External Indexing and Searching" for details.

 # The default value is: NO.

@@ -1627,7 +1687,7 @@
 #

 # Doxygen ships with an example indexer (doxyindexer) and search engine

 # (doxysearch.cgi) which are based on the open source search engine library

-# Xapian (see: http://xapian.org/). See the section "External Indexing and

+# Xapian (see: https://xapian.org/). See the section "External Indexing and

 # Searching" for details.

 # This tag requires that the tag SEARCHENGINE is set to YES.

 

@@ -1679,21 +1739,35 @@
 # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be

 # invoked.

 #

-# Note that when enabling USE_PDFLATEX this option is only used for generating

-# bitmaps for formulas in the HTML output, but not in the Makefile that is

-# written to the output directory.

-# The default file is: latex.

+# Note that when not enabling USE_PDFLATEX the default is latex when enabling

+# USE_PDFLATEX the default is pdflatex and when in the later case latex is

+# chosen this is overwritten by pdflatex. For specific output languages the

+# default can have been set differently, this depends on the implementation of

+# the output language.

 # This tag requires that the tag GENERATE_LATEX is set to YES.

 

 LATEX_CMD_NAME         = latex

 

 # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate

 # index for LaTeX.

+# Note: This tag is used in the Makefile / make.bat.

+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file

+# (.tex).

 # The default file is: makeindex.

 # This tag requires that the tag GENERATE_LATEX is set to YES.

 

 MAKEINDEX_CMD_NAME     = makeindex

 

+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to

+# generate index for LaTeX. In case there is no backslash (\) as first character

+# it will be automatically added in the LaTeX code.

+# Note: This tag is used in the generated output file (.tex).

+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.

+# The default value is: makeindex.

+# This tag requires that the tag GENERATE_LATEX is set to YES.

+

+LATEX_MAKEINDEX_CMD    = makeindex

+

 # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX

 # documents. This may be useful for small projects and may help to save some

 # trees in general.

@@ -1814,7 +1888,7 @@
 

 # The LATEX_BIB_STYLE tag can be used to specify the style to use for the

 # bibliography, e.g. plainnat, or ieeetr. See

-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.

+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.

 # The default value is: plain.

 # This tag requires that the tag GENERATE_LATEX is set to YES.

 

@@ -1828,6 +1902,14 @@
 

 LATEX_TIMESTAMP        = NO

 

+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)

+# path from which the emoji images will be read. If a relative path is entered,

+# it will be relative to the LATEX_OUTPUT directory. If left blank the

+# LATEX_OUTPUT directory will be used.

+# This tag requires that the tag GENERATE_LATEX is set to YES.

+

+LATEX_EMOJI_DIRECTORY  =

+

 #---------------------------------------------------------------------------

 # Configuration options related to the RTF output

 #---------------------------------------------------------------------------

@@ -1867,9 +1949,9 @@
 

 RTF_HYPERLINKS         = NO

 

-# Load stylesheet definitions from file. Syntax is similar to doxygen's config

-# file, i.e. a series of assignments. You only have to provide replacements,

-# missing definitions are set to their default value.

+# Load stylesheet definitions from file. Syntax is similar to doxygen's

+# configuration file, i.e. a series of assignments. You only have to provide

+# replacements, missing definitions are set to their default value.

 #

 # See also section "Doxygen usage" for information on how to generate the

 # default style sheet that doxygen normally uses.

@@ -1878,8 +1960,8 @@
 RTF_STYLESHEET_FILE    =

 

 # Set optional variables used in the generation of an RTF document. Syntax is

-# similar to doxygen's config file. A template extensions file can be generated

-# using doxygen -e rtf extensionFile.

+# similar to doxygen's configuration file. A template extensions file can be

+# generated using doxygen -e rtf extensionFile.

 # This tag requires that the tag GENERATE_RTF is set to YES.

 

 RTF_EXTENSIONS_FILE    =

@@ -1965,6 +2047,13 @@
 

 XML_PROGRAMLISTING     = YES

 

+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include

+# namespace members in file scope as well, matching the HTML output.

+# The default value is: NO.

+# This tag requires that the tag GENERATE_XML is set to YES.

+

+XML_NS_MEMB_FILE_SCOPE = NO

+

 #---------------------------------------------------------------------------

 # Configuration options related to the DOCBOOK output

 #---------------------------------------------------------------------------

@@ -1997,9 +2086,9 @@
 #---------------------------------------------------------------------------

 

 # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an

-# AutoGen Definitions (see http://autogen.sf.net) file that captures the

-# structure of the code including all documentation. Note that this feature is

-# still experimental and incomplete at the moment.

+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures

+# the structure of the code including all documentation. Note that this feature

+# is still experimental and incomplete at the moment.

 # The default value is: NO.

 

 GENERATE_AUTOGEN_DEF   = NO

@@ -2166,12 +2255,6 @@
 

 EXTERNAL_PAGES         = YES

 

-# The PERL_PATH should be the absolute path and name of the perl script

-# interpreter (i.e. the result of 'which perl').

-# The default file (with absolute path) is: /usr/bin/perl.

-

-PERL_PATH              = /usr/bin/perl

-

 #---------------------------------------------------------------------------

 # Configuration options related to the dot tool

 #---------------------------------------------------------------------------

@@ -2185,15 +2268,6 @@
 

 CLASS_DIAGRAMS         = YES

 

-# You can define message sequence charts within doxygen comments using the \msc

-# command. Doxygen will then run the mscgen tool (see:

-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the

-# documentation. The MSCGEN_PATH tag allows you to specify the directory where

-# the mscgen tool resides. If left empty the tool is assumed to be found in the

-# default search path.

-

-MSCGEN_PATH            =

-

 # You can include diagrams made with dia in doxygen documentation. Doxygen will

 # then run dia to produce the diagram and insert it in the documentation. The

 # DIA_PATH tag allows you to specify the directory where the dia binary resides.

diff --git a/src/Tests.cpp b/src/Tests.cpp
index 0f22d35..45c32c8 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -281,6 +281,95 @@
     }

 }

 

+static inline bool StatInfoEqual(const D3D12MA::StatInfo& lhs, const D3D12MA::StatInfo& 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;

+}

+

+static void CheckStatInfo(const D3D12MA::StatInfo& statInfo)

+{

+    if(statInfo.AllocationCount > 0)

+    {

+        CHECK_BOOL(statInfo.AllocationSizeAvg >= statInfo.AllocationSizeMin &&

+            statInfo.AllocationSizeAvg <= statInfo.AllocationSizeMax);

+    }

+    if(statInfo.UsedBytes > 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);

+    }

+}

+

+static void TestStats(const TestContext& ctx)

+{

+    wprintf(L"Test stats\n");

+

+    D3D12MA::Stats begStats = {};

+    ctx.allocator->CalculateStats(&begStats);

+

+    const UINT count = 10;

+    const UINT64 bufSize = 64ull * 1024;

+    ResourceWithAllocation resources[count];

+

+    D3D12MA::ALLOCATION_DESC allocDesc = {};

+    allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;

+

+    D3D12_RESOURCE_DESC resourceDesc;

+    FillResourceDescForBuffer(resourceDesc, bufSize);

+

+    for(UINT i = 0; i < count; ++i)

+    {

+        D3D12MA::Allocation* alloc = nullptr;

+        CHECK_HR( ctx.allocator->CreateResource(

+            &allocDesc,

+            &resourceDesc,

+            D3D12_RESOURCE_STATE_GENERIC_READ,

+            NULL,

+            &alloc,

+            IID_PPV_ARGS(&resources[i].resource)) );

+        resources[i].allocation.reset(alloc);

+    }

+

+    D3D12MA::Stats endStats = {};

+    ctx.allocator->CalculateStats(&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.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].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]));

+

+    CheckStatInfo(endStats.Total);

+    CheckStatInfo(endStats.HeapType[0]);

+    CheckStatInfo(endStats.HeapType[1]);

+    CheckStatInfo(endStats.HeapType[2]);

+}

+

 static void TestTransfer(const TestContext& ctx)

 {

     wprintf(L"Test mapping\n");

@@ -527,6 +616,7 @@
     TestCommittedResources(ctx);

     TestPlacedResources(ctx);

     TestMapping(ctx);

+    TestStats(ctx);

     TestTransfer(ctx);

     TestMultithreading(ctx);

 }