فهرست منبع

Profiler now uses a special memory allocator so it doesn't skew memory alloc profiling results

Marko Pintera 12 سال پیش
والد
کامیت
b2dd1e7508

+ 10 - 8
CamelotCore/Include/CmCPUProfiler.h

@@ -6,6 +6,8 @@ namespace CamelotFramework
 {
 	class CPUProfilerReport;
 
+	typedef std::basic_string<char, std::char_traits<char>, StdAlloc<char, ProfilerAlloc>> ProfilerString; 
+
 	/**
 	 * @brief	Provides various performance measuring methods
 	 * 			
@@ -102,14 +104,14 @@ namespace CamelotFramework
 			ProfiledBlock();
 			~ProfiledBlock();
 
-			String name;
+			ProfilerString name;
 			
 			ProfileData basic;
 			PreciseProfileData precise;
 
 			Vector<ProfiledBlock*>::type children;
 
-			ProfiledBlock* findChild(const String& name) const;
+			ProfiledBlock* findChild(const ProfilerString& name) const;
 		};
 
 		enum class ActiveSamplingType
@@ -144,7 +146,7 @@ namespace CamelotFramework
 			Stack<ActiveBlock>::type activeBlocks;
 			ActiveBlock activeBlock;
 
-			void begin(const String& _name);
+			void begin(const ProfilerString& _name);
 			void end();
 			void reset();
 
@@ -162,7 +164,7 @@ namespace CamelotFramework
 		 *
 		 * @param	name	Name that will allow you to more easily identify the thread.
 		 */
-		void beginThread(const String& name);
+		void beginThread(const ProfilerString& name);
 
 		/**
 		 * @brief	Ends sampling for the current thread. No beginSample*\endSample* calls after this point.
@@ -174,7 +176,7 @@ namespace CamelotFramework
 		 *
 		 * @param	name	Unique name for the sample you can later use to find the sampling data.
 		 */
-		void beginSample(const String& name);
+		void beginSample(const ProfilerString& name);
 
 		/**
 		 * @brief	Ends sample measurement and returns measured data.
@@ -184,7 +186,7 @@ namespace CamelotFramework
 		 * @note	Unique name is primarily needed to more easily identify mismatched
 		 * 			begin/end sample pairs. Otherwise the name in beginSample would be enough.
 		 */
-		void endSample(const String& name);
+		void endSample(const ProfilerString& name);
 
 		/**
 		 * @brief	Begins sample measurement. Must be followed by endSample. 
@@ -196,7 +198,7 @@ namespace CamelotFramework
 		 * 			not use this method for larger parts of code. It does not consider context switches so if the OS
 		 * 			decides to switch context between measurements you will get invalid data.
 		 */
-		void beginSamplePrecise(const String& name);
+		void beginSamplePrecise(const ProfilerString& name);
 
 		/**
 		 * @brief	Ends precise sample measurement and returns measured data.
@@ -206,7 +208,7 @@ namespace CamelotFramework
 		 * @note	Unique name is primarily needed to more easily identify mismatched
 		 * 			begin/end sample pairs. Otherwise the name in beginSamplePrecise would be enough.
 		 */
-		void endSamplePrecise(const String& name);
+		void endSamplePrecise(const ProfilerString& name);
 
 		/**
 		 * @brief	Clears all sampling data, and ends any unfinished sampling blocks.

+ 5 - 5
CamelotCore/Include/CmProfiler.h

@@ -31,7 +31,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc CPUProfiler::beginThread
 		 */
-		void beginThread(const String& name) 
+		void beginThread(const ProfilerString& name) 
 		{ 
 #if CM_PROFILING_ENABLED
 			mCPUProfiler->beginThread(name); 
@@ -51,7 +51,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc CPUProfiler::beginSample
 		 */
-		void beginSample(const String& name) 
+		void beginSample(const ProfilerString& name) 
 		{ 
 #if CM_PROFILING_ENABLED
 			mCPUProfiler->beginSample(name); 
@@ -61,7 +61,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc CPUProfiler::endSample
 		 */
-		void endSample(const String& name) 
+		void endSample(const ProfilerString& name) 
 		{ 
 #if CM_PROFILING_ENABLED
 			mCPUProfiler->endSample(name); 
@@ -71,7 +71,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc CPUProfiler::beginSamplePrecise
 		 */
-		void beginSamplePrecise(const String& name) 
+		void beginSamplePrecise(const ProfilerString& name) 
 		{ 
 #if CM_PROFILING_ENABLED
 			mCPUProfiler->beginSamplePrecise(name); 
@@ -81,7 +81,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc CPUProfiler::endSamplePrecise
 		 */
-		void endSamplePrecise(const String& name) 
+		void endSamplePrecise(const ProfilerString& name) 
 		{ 
 #if CM_PROFILING_ENABLED
 			mCPUProfiler->endSamplePrecise(name); 

+ 25 - 23
CamelotCore/Source/CmCPUProfiler.cpp

@@ -122,7 +122,7 @@ namespace CamelotFramework
 
 	}
 
-	void CPUProfiler::ThreadInfo::begin(const String& _name)
+	void CPUProfiler::ThreadInfo::begin(const ProfilerString& _name)
 	{
 		if(isActive)
 		{
@@ -189,12 +189,12 @@ namespace CamelotFramework
 	{
 		// TODO - Pool this, if possible using the memory allocator stuff
 		// TODO - Also consider moving all samples in ThreadInfo, and also pool them (otherwise I can't pool ProfiledBlock since it will be variable size)
-		return cm_new<ProfiledBlock>();
+		return cm_new<ProfiledBlock, ProfilerAlloc>();
 	}
 
 	void CPUProfiler::ThreadInfo::releaseBlock(CPUProfiler::ProfiledBlock* block)
 	{
-		cm_delete(block);
+		cm_delete<ProfilerAlloc>(block);
 	}
 
 	CPUProfiler::ProfiledBlock::ProfiledBlock()
@@ -210,7 +210,7 @@ namespace CamelotFramework
 		children.clear();
 	}
 
-	CPUProfiler::ProfiledBlock* CPUProfiler::ProfiledBlock::findChild(const String& name) const
+	CPUProfiler::ProfiledBlock* CPUProfiler::ProfiledBlock::findChild(const ProfilerString& name) const
 	{
 		for(auto& child : children)
 		{
@@ -237,15 +237,15 @@ namespace CamelotFramework
 		CM_LOCK_MUTEX(mThreadSync);
 
 		for(auto& threadInfo : mActiveThreads)
-			cm_delete(threadInfo);
+			cm_delete<ProfilerAlloc>(threadInfo);
 	}
 
-	void CPUProfiler::beginThread(const String& name)
+	void CPUProfiler::beginThread(const ProfilerString& name)
 	{
 		ThreadInfo* thread = ThreadInfo::activeThread;
 		if(thread == nullptr)
 		{
-			ThreadInfo::activeThread = cm_new<ThreadInfo>();
+			ThreadInfo::activeThread = cm_new<ThreadInfo, ProfilerAlloc>();
 			thread = ThreadInfo::activeThread;
 
 			{
@@ -264,7 +264,7 @@ namespace CamelotFramework
 		ThreadInfo::activeThread->end();
 	}
 
-	void CPUProfiler::beginSample(const String& name)
+	void CPUProfiler::beginSample(const ProfilerString& name)
 	{
 		ThreadInfo* thread = ThreadInfo::activeThread;
 		if(thread == nullptr || !thread->isActive)
@@ -293,7 +293,7 @@ namespace CamelotFramework
 		block->basic.beginSample();
 	}
 
-	void CPUProfiler::endSample(const String& name)
+	void CPUProfiler::endSample(const ProfilerString& name)
 	{
 		ThreadInfo* thread = ThreadInfo::activeThread;
 		ProfiledBlock* block = thread->activeBlock.block;
@@ -313,7 +313,8 @@ namespace CamelotFramework
 
 		if(block->name != name)
 		{
-			LOGWRN("Mismatched CPUProfiler::endSample. Was expecting \"" + block->name + "\" but got \"" + name + "\". Sampling data will not be valid.");
+			LOGWRN("Mismatched CPUProfiler::endSample. Was expecting \"" + String(block->name.c_str()) + 
+				"\" but got \"" + String(name.c_str()) + "\". Sampling data will not be valid.");
 			return;
 		}
 #endif
@@ -328,7 +329,7 @@ namespace CamelotFramework
 			thread->activeBlock = ActiveBlock();
 	}
 
-	void CPUProfiler::beginSamplePrecise(const String& name)
+	void CPUProfiler::beginSamplePrecise(const ProfilerString& name)
 	{
 		// Note: There is a (small) possibility a context switch will happen during this measurement in which case result will be skewed. 
 		// Increasing thread priority might help. This is generally only a problem with code that executes a long time (10-15+ ms - depending on OS quant length)
@@ -360,7 +361,7 @@ namespace CamelotFramework
 		block->precise.beginSample();
 	}
 
-	void CPUProfiler::endSamplePrecise(const String& name)
+	void CPUProfiler::endSamplePrecise(const ProfilerString& name)
 	{
 		ThreadInfo* thread = ThreadInfo::activeThread;
 		ProfiledBlock* block = thread->activeBlock.block;
@@ -380,7 +381,8 @@ namespace CamelotFramework
 
 		if(block->name != name)
 		{
-			LOGWRN("Mismatched Profiler::endSamplePrecise. Was expecting \"" + block->name + "\" but got \"" + name + "\". Sampling data will not be valid.");
+			LOGWRN("Mismatched Profiler::endSamplePrecise. Was expecting \"" + String(block->name.c_str()) + 
+				"\" but got \"" + String(name.c_str()) + "\". Sampling data will not be valid.");
 			return;
 		}
 #endif
@@ -472,7 +474,7 @@ namespace CamelotFramework
 			CPUProfilerPreciseSamplingEntry* entryPrecise = &preciseEntries[curData.entryIdx];
 
 			// Calculate basic data
-			entryBasic->data.name = curBlock->name;
+			entryBasic->data.name = String(curBlock->name.c_str());
 
 			entryBasic->data.memAllocs = 0;
 			entryBasic->data.memFrees = 0;
@@ -512,7 +514,7 @@ namespace CamelotFramework
 			entryBasic->data.estimatedSelfOverheadMs = mBasicTimerOverhead;
 
 			// Calculate precise data
-			entryPrecise->data.name = curBlock->name;
+			entryPrecise->data.name = String(curBlock->name.c_str());
 
 			entryPrecise->data.memAllocs = 0;
 			entryPrecise->data.memFrees = 0;
@@ -778,8 +780,8 @@ namespace CamelotFramework
 
 			for (UINT32 i = 0; i < sampleReps * 5; i++) 
 			{
-				beginSample("TestAvg#" + toString(i));
-				endSample("TestAvg#" + toString(i));
+				beginSample("TestAvg#" + ProfilerString(toString(i).c_str()));
+				endSample("TestAvg#" + ProfilerString(toString(i).c_str()));
 			}
 
 			endThread();
@@ -829,8 +831,8 @@ namespace CamelotFramework
 
 			for (UINT32 i = 0; i < sampleReps * 5; i++) 
 			{
-				beginSample("TestAvg#" + toString(i));
-				endSample("TestAvg#" + toString(i));
+				beginSample("TestAvg#" + ProfilerString(toString(i).c_str()));
+				endSample("TestAvg#" + ProfilerString(toString(i).c_str()));
 			}
 
 			endThread();
@@ -878,8 +880,8 @@ namespace CamelotFramework
 
 			for (UINT32 i = 0; i < sampleReps * 5; i++) 
 			{
-				beginSamplePrecise("TestAvg#" + toString(i));
-				endSamplePrecise("TestAvg#" + toString(i));
+				beginSamplePrecise("TestAvg#" + ProfilerString(toString(i).c_str()));
+				endSamplePrecise("TestAvg#" + ProfilerString(toString(i).c_str()));
 			}
 
 			endThread();
@@ -927,8 +929,8 @@ namespace CamelotFramework
 
 			for (UINT32 i = 0; i < sampleReps * 5; i++) 
 			{
-				beginSamplePrecise("TestAvg#" + toString(i));
-				endSamplePrecise("TestAvg#" + toString(i));
+				beginSamplePrecise("TestAvg#" + ProfilerString(toString(i).c_str()));
+				endSamplePrecise("TestAvg#" + ProfilerString(toString(i).c_str()));
 			}
 
 			endThread();

+ 6 - 6
CamelotCore/Source/CmProfiler.cpp

@@ -10,23 +10,23 @@ namespace CamelotFramework
 		mSavedCoreReports(nullptr), mNextCoreReportIdx(0)
 	{
 #if CM_PROFILING_ENABLED
-		mCPUProfiler = cm_new<CPUProfiler>();
+		mCPUProfiler = cm_new<CPUProfiler, ProfilerAlloc>();
 #endif
 
-		mSavedSimReports = cm_newN<ProfilerReport>(NUM_SAVED_FRAMES);
-		mSavedCoreReports = cm_newN<ProfilerReport>(NUM_SAVED_FRAMES);
+		mSavedSimReports = cm_newN<ProfilerReport, ProfilerAlloc>(NUM_SAVED_FRAMES);
+		mSavedCoreReports = cm_newN<ProfilerReport, ProfilerAlloc>(NUM_SAVED_FRAMES);
 	}
 
 	Profiler::~Profiler()
 	{
 		if(mCPUProfiler != nullptr)
-			cm_delete(mCPUProfiler);
+			cm_delete<ProfilerAlloc>(mCPUProfiler);
 
 		if(mSavedSimReports != nullptr)
-			cm_deleteN(mSavedSimReports, NUM_SAVED_FRAMES);
+			cm_deleteN<ProfilerAlloc>(mSavedSimReports, NUM_SAVED_FRAMES);
 
 		if(mSavedCoreReports != nullptr)
-			cm_deleteN(mSavedCoreReports, NUM_SAVED_FRAMES);
+			cm_deleteN<ProfilerAlloc>(mSavedCoreReports, NUM_SAVED_FRAMES);
 	}
 
 	void Profiler::update()

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -278,6 +278,7 @@
     <ClInclude Include="Include\CmManagedDataBlock.h" />
     <ClInclude Include="Include\CmMathAsm.h" />
     <ClInclude Include="Include\CmMemoryAllocator.h" />
+    <ClInclude Include="Include\CmMemAllocProfiler.h" />
     <ClInclude Include="Include\CmModule.h" />
     <ClInclude Include="Include\CmPath.h" />
     <ClInclude Include="Include\CmRect.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -228,6 +228,9 @@
     <ClInclude Include="Include\CmStringTable.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmMemAllocProfiler.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmMath.cpp">

+ 39 - 0
CamelotUtility/Include/CmMemAllocProfiler.h

@@ -0,0 +1,39 @@
+#pragma once
+
+namespace CamelotFramework
+{
+	/**
+	 * @brief	Specialized allocator for profiler so we can avoid tracking internal profiler memory allocations
+	 */
+	class ProfilerAlloc
+	{};
+
+	/**
+	 * @brief	Memory allocator providing a generic implementation. 
+	 * 			Specialize for specific categories as needed.
+	 */
+	template<>
+	class MemoryAllocator<ProfilerAlloc> : public MemoryAllocatorBase
+	{
+	public:
+		static inline void* allocate(UINT32 bytes)
+		{
+			return malloc(bytes);
+		}
+
+		static inline void* allocateArray(UINT32 bytes, UINT32 count)
+		{
+			return malloc(bytes * count);
+		}
+
+		static inline void free(void* ptr)
+		{
+			::free(ptr);
+		}
+
+		static inline void freeArray(void* ptr, UINT32 count)
+		{
+			::free(ptr);
+		}
+	};
+}

+ 3 - 1
CamelotUtility/Include/CmMemoryAllocator.h

@@ -107,6 +107,7 @@ namespace CamelotFramework
 	class PoolAlloc
 	{ };
 
+
 	/**
 	 * @brief	Allocates the specified number of bytes.
 	 */
@@ -398,4 +399,5 @@ namespace CamelotFramework
    }
 }
 
-#include "CmMemStack.h"
+#include "CmMemStack.h"
+#include "CmMemAllocProfiler.h"