summaryrefslogtreecommitdiffstats
path: root/src/system/Qt3DSMemoryStatistics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/system/Qt3DSMemoryStatistics.cpp')
-rw-r--r--src/system/Qt3DSMemoryStatistics.cpp647
1 files changed, 647 insertions, 0 deletions
diff --git a/src/system/Qt3DSMemoryStatistics.cpp b/src/system/Qt3DSMemoryStatistics.cpp
new file mode 100644
index 0000000..2f5eba0
--- /dev/null
+++ b/src/system/Qt3DSMemoryStatistics.cpp
@@ -0,0 +1,647 @@
+/****************************************************************************
+**
+** Copyright (C) 1993-2009 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "SystemPrefix.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSIStream.h"
+#include "Qt3DSMemoryStatistics.h"
+#include "Qt3DSMemoryTracker.h"
+#include "Qt3DSMemoryHeap.h"
+#include "foundation/Qt3DSLogging.h"
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+// Static Fields
+//==============================================================================
+INT32 CMemoryStatistics::s_Overhead = 0;
+CMemoryManager *CMemoryStatistics::s_PoolManagers[MANAGERCOUNT] = { NULL };
+
+//==============================================================================
+// REGISTRATION
+//==============================================================================
+
+//==============================================================================
+/**
+ * Add the manager from the static list done automatically on manager construction.
+ * @param inManager the manager we are beginning to track
+ */
+void CMemoryStatistics::AddManager(CMemoryManager *inManager)
+{
+ INT32 theIndex = 0;
+ while (s_PoolManagers[theIndex] && theIndex < MANAGERCOUNT - 1)
+ ++theIndex;
+
+ if (!s_PoolManagers[theIndex]) {
+ s_PoolManagers[theIndex] = inManager;
+ } else {
+ qCWarning(qt3ds::TRACE_INFO)
+ << "Could not add memory manager tracker. Limit: " << MANAGERCOUNT;
+ }
+}
+
+//==============================================================================
+/**
+ * Remove the manager from the static list done automatically on manager deletion.
+ * @param inManager the manager we are ceasing to track
+ */
+void CMemoryStatistics::RemoveManager(CMemoryManager *inManager)
+{
+ INT32 theIndex = 0;
+ while (inManager != s_PoolManagers[theIndex] && theIndex < MANAGERCOUNT - 1)
+ ++theIndex;
+
+ if (inManager == s_PoolManagers[theIndex])
+ s_PoolManagers[theIndex] = NULL;
+}
+
+//==============================================================================
+/**
+ * Read/write access to the static tracking field that keeps tab on how
+ * much memory we are spending _tracking_ memory.
+ * @return reference to the field tracking the overhead in bytes
+ */
+INT32 &CMemoryStatistics::Overhead()
+{
+ return s_Overhead;
+}
+
+//==============================================================================
+// OPERATION
+//==============================================================================
+
+//==============================================================================
+/**
+ * Reset all memory probes
+ */
+void CMemoryStatistics::Reset()
+{
+ qCInfo(qt3ds::TRACE_INFO) << "Resetting Memory Statistics";
+ CMemoryHeap::GetProbe().Reset();
+
+ for (INT32 theIndex = 0; theIndex < MANAGERCOUNT; ++theIndex)
+ if (s_PoolManagers[theIndex])
+ s_PoolManagers[theIndex]->Reset();
+}
+
+//==============================================================================
+// ACCESS
+//==============================================================================
+
+//==============================================================================
+/**
+ * Quick access to memory usage of the first memory manager.
+ * @param inPeak is true if you want the peak, false if you want the current state
+ * @return the current explict usage in bytes
+ */
+INT32 CMemoryStatistics::GetRequestedBytes(BOOL inPeak /*=false*/)
+{
+ Q3DStudio_ASSERT(s_PoolManagers[0]);
+
+ EMemoryValue theValue = inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT;
+ CMemoryManager::SPoolData &theUsageData = s_PoolManagers[0]->GetManagerData();
+
+ return theUsageData.m_Aligned.GetBytes(MEMSCOPE_RESET, theValue)
+ + theUsageData.m_Overflow.GetBytes(MEMSCOPE_RESET, theValue);
+}
+
+//==============================================================================
+/**
+ * Quick access to heap usage.
+ * @param inPeak is true if you want the peak, false if you want the current state
+ * @return the current heap usage in bytes
+ */
+INT32 CMemoryStatistics::GetHeapBytes(BOOL inPeak /*=false*/)
+{
+ return Q3DStudio::CMemoryHeap::GetProbe().GetBytes(MEMSCOPE_RESET,
+ inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT);
+}
+
+//==============================================================================
+/**
+ * Fill out a SFactSheet with memory statistics.
+ * @param outFacts is filled out with factoids showing the system state
+ * @param inPeak is true if you want the peak, false if you want the current state
+ * @param inGlobal is true if you want values since process start, false since last reset
+ */
+void CMemoryStatistics::GetFacts(SFactSheet &outFacts, BOOL inPeak /*= true*/,
+ BOOL inGlobal /*= true*/)
+{
+ INT32 thePresentationBytes = 0;
+ Q3DStudio_UNREFERENCED_PARAMETER(thePresentationBytes);
+ Q3DStudio_memset(&outFacts, 0, sizeof(SFactSheet));
+
+ // Translate flags to enumerations
+ EMemoryScope theScope = inGlobal ? MEMSCOPE_GLOBAL : MEMSCOPE_RESET;
+ EMemoryValue theValue = inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT;
+
+ // Capture heap state
+ outFacts.m_HeapState.m_Bytes = CMemoryHeap::GetProbe().GetBytes(theScope, theValue);
+ outFacts.m_HeapState.m_Calls = CMemoryHeap::GetProbe().GetCalls(theScope, theValue);
+
+#if Q3DStudio_MEMORY_POOLTRACKING
+ INT32 theTotalChunks = 0;
+ INT32 theTotalBytes = 0;
+
+ // Scan all registered pool managers
+ Q3DStudio_sprintf(outFacts.m_ManagerState.m_Name, 32, "All Managers");
+ for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex) {
+ CMemoryManager *theManager = s_PoolManagers[theManagerIndex];
+ SFactoid &theManagerFact = outFacts.m_Manager[theManagerIndex];
+ INT32 theManagerChunks = 0;
+ INT32 theManagerBytes = 0;
+
+ // Ignore empty managers
+ if (!theManager)
+ break;
+
+ // Scan each pool in the manager
+ Q3DStudio_sprintf(theManagerFact.m_Name, 32, " %s", theManager->GetName());
+ for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) {
+ CMemoryPool &thePool = theManager->GetPool(thePoolIndex);
+ CMemoryManager::SPoolData *thePoolData = theManager->GetPoolData(thePoolIndex);
+ Q3DStudio_ASSERT(thePoolData);
+
+ SFactoid &thePoolFact = outFacts.m_Pool[theManagerIndex][thePoolIndex];
+ INT32 theUsed = thePool.GetProbe().GetCalls(theScope, theValue);
+ INT32 theAlign = thePoolData->m_Aligned.GetBytes(theScope, theValue);
+
+ // Ignore empty pools
+ if (thePool.GetChunkCount() == 0)
+ break;
+
+ // Extract all the factoids
+ Q3DStudio_sprintf(thePoolFact.m_Name, 32, " %d: %4db x %4d", thePoolIndex,
+ thePool.GetChunkSize(), thePool.GetChunkCount());
+ thePoolFact.m_Bytes = thePool.GetChunkSize() * thePool.GetChunkCount();
+ thePoolFact.m_Calls = thePool.GetProbe().GetCalls(theScope, theValue);
+ thePoolFact.m_Used = 100 * theUsed / thePool.GetChunkCount();
+
+ thePoolFact.m_Align = 100;
+ if (theUsed > 0)
+ thePoolFact.m_Align = 100 * theAlign / (theUsed * thePool.GetChunkSize());
+ thePoolFact.m_Miss = thePoolData->m_Overflow.GetCalls(theScope, theValue);
+
+ thePresentationBytes += theAlign + thePoolData->m_Overflow.GetBytes(theScope, theValue);
+
+ theManagerFact.m_Bytes += thePoolFact.m_Bytes;
+ theManagerFact.m_Calls += thePoolFact.m_Calls;
+ theManagerFact.m_Used += theUsed;
+ theManagerFact.m_Align += theAlign;
+ theManagerFact.m_Miss += thePoolFact.m_Miss;
+
+ outFacts.m_ManagerState.m_Bytes += thePoolFact.m_Bytes;
+ outFacts.m_ManagerState.m_Calls += thePoolFact.m_Calls;
+ outFacts.m_ManagerState.m_Used += theUsed;
+ outFacts.m_ManagerState.m_Align += theAlign;
+ outFacts.m_ManagerState.m_Miss += thePoolFact.m_Miss;
+
+ theManagerChunks += thePool.GetChunkCount();
+ theManagerBytes += theUsed * thePool.GetChunkSize();
+ }
+
+ thePresentationBytes +=
+ theManager->GetManagerData().m_Overflow.GetBytes(theScope, theValue);
+
+ // Both the manager sub-total and grand-total need to track bytes separately
+ // since the percentages can't just be added or averaged. Those totals
+ // are instead weighted and this is the tracking math that does it.
+ theTotalChunks += theManagerChunks;
+ theTotalBytes += theManagerBytes;
+
+ theManagerFact.m_Used = 0;
+ if (theManagerChunks > 0)
+ theManagerFact.m_Used = 100 * theManagerFact.m_Used / theManagerChunks;
+
+ theManagerFact.m_Align = 100;
+ if (theManagerBytes > 0)
+ theManagerFact.m_Align = 100 * theManagerFact.m_Align / theManagerBytes;
+
+ CullHistogram(theManager->GetHistogram(), theValue, outFacts.m_Histogram[theManagerIndex]);
+ }
+
+ // Again this is the grand-total separate percentage computation that has
+ // to be done in the end when all sums have been added.
+ outFacts.m_ManagerState.m_Used = 0;
+ if (theTotalChunks > 0)
+ outFacts.m_ManagerState.m_Used = 100 * outFacts.m_ManagerState.m_Used / theTotalChunks;
+
+ outFacts.m_ManagerState.m_Align = 100;
+ if (theTotalBytes > 0)
+ outFacts.m_ManagerState.m_Align = 100 * outFacts.m_ManagerState.m_Align / theTotalBytes;
+
+#endif // Q3DStudio_MEMORY_POOLTRACKING
+
+ // return thePresentationBytes;
+}
+
+//==============================================================================
+/**
+ * Find the HISTOGRAMLIMIT highest performers in the histogram.
+ * @param inHistogram array of CMemoryManager::HISTOGRAMCOUNT values
+ * each showing the number of allocation of that bytesize
+ * @param outResults collects the highest points of the histogram
+ */
+void CMemoryStatistics::CullHistogram(const CMemoryProbe::SValue *inHistogram,
+ const EMemoryValue inValue,
+ SHistogramScore outResults[HISTOGRAMCOUNT])
+{
+ // Always clear even if there is no data
+ Q3DStudio_memset(outResults, 0, sizeof(SHistogramScore));
+
+ // Return quickly when no data
+ if (!inHistogram)
+ return;
+
+ // Scan full histogram
+ INT32 theLowestIndex = 0;
+ for (UINT16 theSize = 0; theSize < 512; ++theSize) {
+ // Is this count higher than the lowest recorded count?
+ if (inHistogram[theSize].m_Value[inValue] > outResults[theLowestIndex].m_Count) {
+ outResults[theLowestIndex].m_Count = inHistogram[theSize].m_Value[inValue];
+ outResults[theLowestIndex].m_Size = theSize;
+
+ // Find new low in high score
+ theLowestIndex = 0;
+ for (UINT16 theResult = 1; theResult < HISTOGRAMCOUNT; ++theResult)
+ if (outResults[theResult].m_Count < outResults[theLowestIndex].m_Count)
+ theLowestIndex = theResult;
+ }
+ }
+
+ // Sort histogram - brute force for now so don't call this all the time
+ ::qsort(outResults, 10, sizeof(SHistogramScore), CompareHistogram);
+}
+
+//==============================================================================
+/**
+ * Helper comparison function for CullHistogram
+ */
+int CMemoryStatistics::CompareHistogram(const void *arg1, const void *arg2)
+{
+ return reinterpret_cast<const SHistogramScore *>(arg2)->m_Count
+ - reinterpret_cast<const SHistogramScore *>(arg1)->m_Count;
+}
+
+//==============================================================================
+/**
+ * Helper comparison function for CMemoryStatistics::HeapReport
+ */
+int CMemoryStatistics::CompareHeap(const void *inEntry1, const void *inEntry2)
+{
+ return reinterpret_cast<const CMemoryHeap::SReportEntry *>(inEntry1)->m_Size
+ - reinterpret_cast<const CMemoryHeap::SReportEntry *>(inEntry2)->m_Size;
+}
+
+//==============================================================================
+// REPORTING
+//==============================================================================
+
+//==============================================================================
+/**
+ * Simple memory usage report covering both bytes allocated and call count.
+ * @param inStream the stream we are sending the report or NULL to use logger
+ */
+void CMemoryStatistics::SimpleReport(IStream *inStream /*=NULL*/)
+{
+ CHAR theReportBuffer[REPORTSIZE];
+ CMemoryProbe theProbe;
+
+ // Basic info is always available
+ Report(inStream, "\n --- RUNTIME SIMPLE MEMORY REPORT ---\n");
+
+ // Only the first manager is reported for now
+ Q3DStudio_ASSERT(s_PoolManagers[0]);
+ theProbe = s_PoolManagers[0]->GetManagerData().m_Aligned;
+ theProbe.Combine(s_PoolManagers[0]->GetManagerData().m_Overflow);
+ Report(inStream, "PRESENTATION: Current Peak Alloc Free\n");
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer),
+ "Global:%12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n",
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_PEAK) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_PEAK),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_ADDS) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_ADDS),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_DELETES) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_DELETES));
+ Report(inStream, theReportBuffer);
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer),
+ "Reset: %12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n",
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_CURRENT) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_CURRENT),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_PEAK) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_PEAK),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_ADDS) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_ADDS),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_DELETES) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_DELETES));
+ Report(inStream, theReportBuffer);
+
+ // Overflow is memory not serviced by memory pools - removed to make the simple report...
+ // simpler
+ /* theProbe = s_PoolManagers[0]->GetManagerData( ).m_Overflow;
+ Report( inStream, "OVERFLOW:\n" );
+ Q3DStudio_sprintf( theReportBuffer, sizeof( theReportBuffer ),
+ "Global:%12ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)\n",
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_PEAK )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_PEAK ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_ADDS )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_ADDS ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_DELETES )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_DELETES ) );
+ Report( inStream, theReportBuffer );
+ Q3DStudio_sprintf( theReportBuffer, sizeof( theReportBuffer ), "Reset:
+ %12ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)\n",
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_PEAK )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_PEAK ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_ADDS )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_ADDS ),
+ theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_DELETES )/1024,
+ theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_DELETES ) );
+ Report( inStream, theReportBuffer );*/
+
+ // All managers share the same heap
+ theProbe = CMemoryHeap::GetProbe();
+ Report(inStream, "HEAP:\n");
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer),
+ "Global:%12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n",
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_PEAK) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_PEAK),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_ADDS) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_ADDS),
+ theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_DELETES) / 1024,
+ theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_DELETES));
+ Report(inStream, theReportBuffer);
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer),
+ "Reset: %12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n",
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_CURRENT) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_CURRENT),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_PEAK) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_PEAK),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_ADDS) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_ADDS),
+ theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_DELETES) / 1024,
+ theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_DELETES));
+ Report(inStream, theReportBuffer);
+
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), "Tracking overhead: %dk\n",
+#if Q3DStudio_MEMORY_HEAPTRACKING
+ (s_Overhead + sizeof(CMemoryHeap::TMemoryReport)) / 1024);
+#else
+ s_Overhead / 1024);
+#endif // Q3DStudio_MEMORY_HEAPTRACKING
+
+ Report(inStream, theReportBuffer);
+}
+
+//==============================================================================
+/**
+ * Output the memory report log.
+ *
+ * The is always watched by a CMemoryProbe that records all activity. Most
+ * individual allocations will not be recorded though since they are handled
+ * by memory pools.
+ *
+ * A probe records three axis of information (value, scope and call/bytes).
+ *
+ * # Value (current,peak,add,del) tracks the current value along with its
+ * peak value, and also separately tracks adds(allocations) and deletes(frees)
+ * such that current = add - del.
+ * # Scope (local,global) tracks values since last reset or dawn of heap.
+ * # Call/Bytes tracks separately bytes and calls so you can distinguish between
+ * many small allocations and a few large.
+ *
+ * @param inStream the stream we are sending the report or NULL to use logger
+ */
+void CMemoryStatistics::HeapReport(IStream *inStream /*=NULL*/)
+{
+ Report(inStream, "\n --- RUNTIME HEAP MEMORY REPORT ---\n");
+
+#if Q3DStudio_MEMORY_HEAPTRACKING
+ // Detailed info needs Q3DStudio_MEMORY_HEAPTRACKING defined
+ INT32 theCount = CMemoryHeap::GetReport()->GetCount();
+ ::qsort(&CMemoryHeap::GetReport()[0], static_cast<size_t>(theCount),
+ sizeof(CMemoryHeap::SReportEntry), CompareHeap);
+
+ CHAR theReportBuffer[REPORTSIZE];
+ for (INT32 theIndex = 0; theIndex < theCount; ++theIndex) {
+ CMemoryHeap::SReportEntry &theEntry = CMemoryHeap::GetReport()->operator[](theIndex);
+ Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer),
+ "%3d. %8d bytes - \"%s\" - %s (%d)\n", theIndex, theEntry.m_Size,
+ theEntry.m_Description, theEntry.m_File, theEntry.m_Line);
+ Report(inStream, theReportBuffer);
+ }
+#else
+ Report(inStream, " Unavailable: Q3DStudio_MEMORY_HEAPTRACKING not defined in this build\n");
+#endif
+}
+
+/* Example output of CMemoryStatistics::Report
+
+=POOL= HEAP CALLS USED ALIGN MISSES
+---------------------------------------------------------------
+All Managers 722k 38 72% 19%
+
+ Global 482k
+ 0: 16b x 1024 16k 2182 3% 13%
+ 1: 32b x 2048 64k 4123 96% 9% 38
+ 2: 48b x 512 24k 212 72% 21%
+ 3: 64b x 512 32k 454 11% 3%
+ .
+ 8: 512b x 128 64k 68 64% 22%
+*/
+
+//==============================================================================
+/**
+ * Return a text buffer describing the state of the memory system.
+ */
+void CMemoryStatistics::PoolReport(BOOL inPeak /*= true*/, BOOL inGlobal /*= true*/,
+ IStream *inStream /*=NULL*/)
+{
+ CHAR theLine[256] = { 0 };
+ SFactSheet theFacts;
+
+ GetFacts(theFacts, inPeak, inGlobal);
+
+ Report(inStream, "\n --- RUNTIME POOL MEMORY REPORT ---\n");
+ Q3DStudio_sprintf(theLine, 256,
+ "Mode: %s %s\nTotal Heap: %7dk(%d)\nPresentation: %7dk\n",
+ inGlobal ? "GLOBAL" : "RESET", inPeak ? "PEAK" : "CURRENT",
+ theFacts.m_HeapState.m_Bytes / 1024, theFacts.m_HeapState.m_Calls,
+ GetRequestedBytes(inPeak) / 1024);
+ Report(inStream, theLine);
+
+#if Q3DStudio_MEMORY_POOLTRACKING
+ Report(inStream, "=POOLS= HEAP HITS USED ALIGN MISS"
+ "\n");
+ Report(inStream, "-----------------------------------------------------------------"
+ "\n");
+ Q3DStudio_sprintf(theLine, 256, "All Managers %7dk %8d %5d%% %5d%% %6d"
+ "\n\n",
+ theFacts.m_ManagerState.m_Bytes / 1024, theFacts.m_ManagerState.m_Calls,
+ theFacts.m_ManagerState.m_Used, theFacts.m_ManagerState.m_Align,
+ theFacts.m_ManagerState.m_Miss);
+ Report(inStream, theLine);
+
+ for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex) {
+ SFactoid &theManagerFact = theFacts.m_Manager[theManagerIndex];
+ if (theManagerFact.m_Bytes > 0) {
+ Q3DStudio_sprintf(theLine, 256, "%-20s %7dk %8d %5d%% %5d%% %6d\n",
+ theManagerFact.m_Name, theManagerFact.m_Bytes / 1024,
+ theManagerFact.m_Calls, theManagerFact.m_Used, theManagerFact.m_Align,
+ theManagerFact.m_Miss);
+ Report(inStream, theLine);
+
+ for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT;
+ ++thePoolIndex) {
+ SFactoid &thePoolFact = theFacts.m_Pool[theManagerIndex][thePoolIndex];
+ if (theManagerFact.m_Bytes > 0) {
+ Q3DStudio_sprintf(theLine, 256, "%-20s %7dk %8d %5d%% %5d%% %6d\n",
+ thePoolFact.m_Name, thePoolFact.m_Bytes / 1024,
+ thePoolFact.m_Calls, thePoolFact.m_Used, thePoolFact.m_Align,
+ thePoolFact.m_Miss);
+ Report(inStream, theLine);
+ }
+ }
+
+ // Histogram only valid for Current-Reset
+ if (inGlobal) {
+ Report(inStream, " Histogram: Only available in RESET mode\n");
+ } else {
+ Q3DStudio_sprintf(
+ theLine, 256,
+ " Histogram: 1:%3db(%3d) 2:%3db(%3d) 3:%3db(%3d) 4:%3db(%3d) 5:%3db(%3d)\n",
+ theFacts.m_Histogram[theManagerIndex][0].m_Size,
+ theFacts.m_Histogram[theManagerIndex][0].m_Count,
+ theFacts.m_Histogram[theManagerIndex][1].m_Size,
+ theFacts.m_Histogram[theManagerIndex][1].m_Count,
+ theFacts.m_Histogram[theManagerIndex][2].m_Size,
+ theFacts.m_Histogram[theManagerIndex][2].m_Count,
+ theFacts.m_Histogram[theManagerIndex][3].m_Size,
+ theFacts.m_Histogram[theManagerIndex][3].m_Count,
+ theFacts.m_Histogram[theManagerIndex][4].m_Size,
+ theFacts.m_Histogram[theManagerIndex][4].m_Count);
+ Report(inStream, theLine);
+ Q3DStudio_sprintf(
+ theLine, 256,
+ " 6:%3db(%3d) 7:%3db(%3d) 8:%3db(%3d) 9:%3db(%3d) 10:%3db(%3d)\n",
+ theFacts.m_Histogram[theManagerIndex][5].m_Size,
+ theFacts.m_Histogram[theManagerIndex][5].m_Count,
+ theFacts.m_Histogram[theManagerIndex][6].m_Size,
+ theFacts.m_Histogram[theManagerIndex][6].m_Count,
+ theFacts.m_Histogram[theManagerIndex][7].m_Size,
+ theFacts.m_Histogram[theManagerIndex][7].m_Count,
+ theFacts.m_Histogram[theManagerIndex][8].m_Size,
+ theFacts.m_Histogram[theManagerIndex][8].m_Count,
+ theFacts.m_Histogram[theManagerIndex][9].m_Size,
+ theFacts.m_Histogram[theManagerIndex][9].m_Count);
+ Report(inStream, theLine);
+ }
+ }
+ }
+#else
+ Report(inStream, " Unavailable: Q3DStudio_MEMORY_POOLTRACKING not defined in this build\n");
+#endif
+}
+
+//==============================================================================
+/**
+ * Dump the low-level memory list stored in each manager's hash bin.
+ *
+ * @note Q3DStudio_MEMORY_LINETRACKING has to be set to 1 in AKMemorySettings.h or
+ * the compiler for this method to save out any data.
+ *
+ * @param inStream the stream we are sending the report or NULL to use logger
+ */
+void CMemoryStatistics::LineReport(IStream *inStream /*=NULL*/)
+{
+ Report(inStream, "\n--- RUNTIME LINE MEMORY REPORT ---\n");
+#if Q3DStudio_MEMORY_LINETRACKING
+ Report(inStream, "ADDR, SIZE, TYPE, LINE, FILE, \n");
+
+ INT32 theTotalBytes = 0;
+ for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex)
+ if (s_PoolManagers[theManagerIndex] && s_PoolManagers[theManagerIndex]->GetLineTracker())
+ theTotalBytes += s_PoolManagers[theManagerIndex]->GetLineTracker()->Report(inStream);
+
+ CHAR theTotal[64];
+ theTotal[0] = '\0';
+
+ Q3DStudio_sprintf(theTotal, sizeof(theTotal), "TOTAL: , %8d\n", theTotalBytes);
+ Report(inStream, theTotal);
+#else
+ Report(inStream, " Unavailable: Q3DStudio_MEMORY_LINETRACKING not defined in this build\n");
+#endif // Q3DStudio_MEMORY_LINETRACKING
+}
+
+//==============================================================================
+/**
+ * Output to log or stream if available.
+ * @param inMessage string to be reported
+ * @param inStream stream to be used or output to log if NULL
+ */
+void CMemoryStatistics::Report(IStream *inStream, const CHAR *inMessage)
+{
+ if (inStream)
+ inStream->WriteRaw(inMessage, (INT32)::strlen(inMessage));
+ else
+ qCInfo(qt3ds::TRACE_INFO) << inMessage;
+}
+
+//==============================================================================
+/**
+ * Output full memory report to log or stream if available.
+ * @param inStream stream to be used or output to log if NULL
+ */
+void CMemoryStatistics::FullReport(IStream *inStream /*=NULL*/)
+{
+ SimpleReport(inStream);
+ HeapReport(inStream);
+ LineReport(inStream);
+ PoolReport(false, false, inStream);
+ PoolReport(true, false, inStream);
+ PoolReport(false, true, inStream);
+ PoolReport(true, true, inStream);
+}
+
+} // namespace Q3DStudio