Browse Source

Added memory allocation profiling
Optimized text generation a bit

Marko Pintera 12 years ago
parent
commit
1c195fdbde

+ 8 - 12
BansheeEngine/Include/BsProfilerOverlay.h

@@ -19,13 +19,12 @@ namespace BansheeEngine
 			CM::HString name;
 			CM::HString pctOfParent;
 			CM::HString numCalls;
+			CM::HString numAllocs;
+			CM::HString numFrees;
 			CM::HString avgTime;
 			CM::HString totalTime;
-			CM::HString maxTime;
 			CM::HString avgTimeSelf;
 			CM::HString totalTimeSelf;
-			CM::HString estOverhead;
-			CM::HString estOverheadSelf;
 		};
 
 		struct PreciseRow
@@ -38,13 +37,12 @@ namespace BansheeEngine
 			CM::HString name;
 			CM::HString pctOfParent;
 			CM::HString numCalls;
+			CM::HString numAllocs;
+			CM::HString numFrees;
 			CM::HString avgCycles;
 			CM::HString totalCycles;
-			CM::HString maxCycles;
 			CM::HString avgCyclesSelf;
 			CM::HString totalCyclesSelf;
-			CM::HString estOverhead;
-			CM::HString estOverheadSelf;
 		};
 
 	public:
@@ -80,24 +78,22 @@ namespace BansheeEngine
 		GUIElement* mTitleBasicName;
 		GUIElement* mTitleBasicPctOfParent;
 		GUIElement* mTitleBasicNumCalls;
+		GUIElement* mTitleBasicNumAllocs;
+		GUIElement* mTitleBasicNumFrees;
 		GUIElement* mTitleBasicAvgTime;
 		GUIElement* mTitleBasicTotalTime;
-		GUIElement* mTitleBasicMaxTime;
 		GUIElement* mTitleBasicAvgTitleSelf;
 		GUIElement* mTitleBasicTotalTimeSelf;
-		GUIElement* mTitleBasicEstOverhead;
-		GUIElement* mTitleBasicEstOverheadSelf;
 
 		GUIElement* mTitlePreciseName;
 		GUIElement* mTitlePrecisePctOfParent;
 		GUIElement* mTitlePreciseNumCalls;
+		GUIElement* mTitlePreciseNumAllocs;
+		GUIElement* mTitlePreciseNumFrees;
 		GUIElement* mTitlePreciseAvgCycles;
 		GUIElement* mTitlePreciseTotalCycles;
-		GUIElement* mTitlePreciseMaxCycles;
 		GUIElement* mTitlePreciseAvgCyclesSelf;
 		GUIElement* mTitlePreciseTotalCyclesSelf;
-		GUIElement* mTitlePreciseEstOverhead;
-		GUIElement* mTitlePreciseEstOverheadSelf;
 
 		CM::Vector<BasicRow>::type mBasicRows;
 		CM::Vector<PreciseRow>::type mPreciseRows;

+ 42 - 56
BansheeEngine/Source/BsProfilerOverlay.cpp

@@ -44,8 +44,8 @@ namespace BansheeEngine
 			rows.resize(curIdx);
 		}
 
-		void addData(UINT32 depth, const String& name, float pctOfParent, UINT32 numCalls, double avgTime, double totalTime, 
-			double maxTime, double avgSelfTime, double totalSelfTime, double estOverhead, double estOverheadSelf)
+		void addData(UINT32 depth, const String& name, float pctOfParent, UINT32 numCalls, UINT64 numAllocs, 
+			UINT64 numFrees, double avgTime, double totalTime, double avgSelfTime, double totalSelfTime)
 		{
 			if(curIdx >= rows.size())
 			{
@@ -56,13 +56,12 @@ namespace BansheeEngine
 				newRow.name = HString(L"{0}");
 				newRow.pctOfParent = HString(L"{0} %");
 				newRow.numCalls = HString(L"{0}");
+				newRow.numAllocs = HString(L"{0}");
+				newRow.numFrees = HString(L"{0}");
 				newRow.avgTime = HString(L"{0}");
 				newRow.totalTime = HString(L"{0}");
-				newRow.maxTime = HString(L"{0}");
 				newRow.avgTimeSelf = HString(L"{0}");
 				newRow.totalTimeSelf = HString(L"{0}");
-				newRow.estOverhead = HString(L"{0}");
-				newRow.estOverheadSelf = HString(L"{0}");
 
 				newRow.labelLayout = &labelLayout.insertLayoutX(labelLayout.getNumChildren() - 1); // Insert before flexible space
 				newRow.contentLayout = &contentLayout.insertLayoutX(contentLayout.getNumChildren() - 1); // Insert before flexible space
@@ -70,37 +69,34 @@ namespace BansheeEngine
 				GUILabel* name = GUILabel::create(widget, newRow.name, GUIOptions(GUIOption::fixedWidth(200)));
 				GUILabel* pctOfParent = GUILabel::create(widget, newRow.pctOfParent, GUIOptions(GUIOption::fixedWidth(50)));
 				GUILabel* numCalls = GUILabel::create(widget, newRow.numCalls, GUIOptions(GUIOption::fixedWidth(50)));
+				GUILabel* numAllocs = GUILabel::create(widget, newRow.numAllocs, GUIOptions(GUIOption::fixedWidth(50)));
+				GUILabel* numFrees = GUILabel::create(widget, newRow.numFrees, GUIOptions(GUIOption::fixedWidth(50)));
 				GUILabel* avgTime = GUILabel::create(widget, newRow.avgTime, GUIOptions(GUIOption::fixedWidth(60)));
 				GUILabel* totalTime = GUILabel::create(widget, newRow.totalTime, GUIOptions(GUIOption::fixedWidth(60)));
-				GUILabel* maxTime = GUILabel::create(widget, newRow.maxTime, GUIOptions(GUIOption::fixedWidth(60)));
 				GUILabel* avgTimeSelf = GUILabel::create(widget, newRow.avgTimeSelf, GUIOptions(GUIOption::fixedWidth(100)));
 				GUILabel* totalTimeSelf = GUILabel::create(widget, newRow.totalTimeSelf, GUIOptions(GUIOption::fixedWidth(100)));
-				GUILabel* estOverhead = GUILabel::create(widget, newRow.estOverhead, GUIOptions(GUIOption::fixedWidth(100)));
-				GUILabel* estOverheadSelf = GUILabel::create(widget, newRow.estOverheadSelf, GUIOptions(GUIOption::fixedWidth(100)));
 
 				newRow.labelLayout->addSpace(0);
 				newRow.labelLayout->addElement(name);
 
 				newRow.contentLayout->addElement(pctOfParent);
 				newRow.contentLayout->addElement(numCalls);
+				newRow.contentLayout->addElement(numAllocs);
+				newRow.contentLayout->addElement(numFrees);
 				newRow.contentLayout->addElement(avgTime);
 				newRow.contentLayout->addElement(totalTime);
-				newRow.contentLayout->addElement(maxTime);
 				newRow.contentLayout->addElement(avgTimeSelf);
 				newRow.contentLayout->addElement(totalTimeSelf);
-				newRow.contentLayout->addElement(estOverhead);
-				newRow.contentLayout->addElement(estOverheadSelf);
 
 				newRow.elements.push_back(name);
 				newRow.elements.push_back(pctOfParent);
 				newRow.elements.push_back(numCalls);
+				newRow.elements.push_back(numAllocs);
+				newRow.elements.push_back(numFrees);
 				newRow.elements.push_back(avgTime);
 				newRow.elements.push_back(totalTime);
-				newRow.elements.push_back(maxTime);
 				newRow.elements.push_back(avgTimeSelf);
 				newRow.elements.push_back(totalTimeSelf);
-				newRow.elements.push_back(estOverhead);
-				newRow.elements.push_back(estOverheadSelf);
 			}
 			
 			ProfilerOverlay::BasicRow& row = rows[curIdx];
@@ -111,13 +107,12 @@ namespace BansheeEngine
 			row.name.setParameter(0, toWString(name));
 			row.pctOfParent.setParameter(0, toWString(pctOfParent * 100.0f, 2, 0, ' ', std::ios::fixed));
 			row.numCalls.setParameter(0, toWString(numCalls));
+			row.numAllocs.setParameter(0, toWString(numAllocs));
+			row.numFrees.setParameter(0, toWString(numFrees));
 			row.avgTime.setParameter(0, toWString(avgTime, 2, 0, ' ', std::ios::fixed));
 			row.totalTime.setParameter(0, toWString(totalTime, 2, 0, ' ', std::ios::fixed));
-			row.maxTime.setParameter(0, toWString(maxTime, 2, 0, ' ', std::ios::fixed));
 			row.avgTimeSelf.setParameter(0, toWString(avgSelfTime, 2, 0, ' ', std::ios::fixed));
 			row.totalTimeSelf.setParameter(0, toWString(totalSelfTime, 2, 0, ' ', std::ios::fixed));
-			row.estOverhead.setParameter(0, toWString(estOverhead, 2, 0, ' ', std::ios::fixed));
-			row.estOverheadSelf.setParameter(0, toWString(estOverheadSelf, 2, 0, ' ', std::ios::fixed));
 
 			curIdx++;
 		}
@@ -153,8 +148,8 @@ namespace BansheeEngine
 			rows.resize(curIdx);
 		}
 
-		void addData(UINT32 depth, const String& name, float pctOfParent, UINT32 numCalls, UINT64 avgCycles, UINT64 totalCycles, 
-			UINT64 maxCycles, UINT64 avgSelfCycles, UINT64 totalSelfCycles, UINT64 estOverhead, UINT64 estOverheadSelf)
+		void addData(UINT32 depth, const String& name, float pctOfParent, UINT32 numCalls, UINT64 numAllocs, 
+			UINT64 numFrees, UINT64 avgCycles, UINT64 totalCycles, UINT64 avgSelfCycles, UINT64 totalSelfCycles)
 		{
 			if(curIdx >= rows.size())
 			{
@@ -165,13 +160,12 @@ namespace BansheeEngine
 				newRow.name = HString(L"{0}");
 				newRow.pctOfParent = HString(L"{0}");
 				newRow.numCalls = HString(L"{0}");
+				newRow.numAllocs = HString(L"{0}");
+				newRow.numFrees = HString(L"{0}");
 				newRow.avgCycles = HString(L"{0}");
 				newRow.totalCycles = HString(L"{0}");
-				newRow.maxCycles = HString(L"{0}");
 				newRow.avgCyclesSelf = HString(L"{0}");
 				newRow.totalCyclesSelf = HString(L"{0}");
-				newRow.estOverhead = HString(L"{0}");
-				newRow.estOverheadSelf = HString(L"{0}");
 
 				newRow.labelLayout = &labelLayout.insertLayoutX(labelLayout.getNumChildren() - 1); // Insert before flexible space
 				newRow.contentLayout = &contentLayout.insertLayoutX(contentLayout.getNumChildren() - 1); // Insert before flexible space
@@ -179,37 +173,34 @@ namespace BansheeEngine
 				GUILabel* name = GUILabel::create(widget, newRow.name, GUIOptions(GUIOption::fixedWidth(200)));
 				GUILabel* pctOfParent = GUILabel::create(widget, newRow.pctOfParent, GUIOptions(GUIOption::fixedWidth(50)));
 				GUILabel* numCalls = GUILabel::create(widget, newRow.numCalls, GUIOptions(GUIOption::fixedWidth(50)));
+				GUILabel* numAllocs = GUILabel::create(widget, newRow.numAllocs, GUIOptions(GUIOption::fixedWidth(50)));
+				GUILabel* numFrees = GUILabel::create(widget, newRow.numFrees, GUIOptions(GUIOption::fixedWidth(50)));
 				GUILabel* avgCycles = GUILabel::create(widget, newRow.avgCycles,GUIOptions(GUIOption::fixedWidth(60)));
 				GUILabel* totalCycles = GUILabel::create(widget, newRow.totalCycles, GUIOptions(GUIOption::fixedWidth(60)));
-				GUILabel* maxCycles = GUILabel::create(widget, newRow.maxCycles, GUIOptions(GUIOption::fixedWidth(60)));
 				GUILabel* avgCyclesSelf = GUILabel::create(widget, newRow.avgCyclesSelf, GUIOptions(GUIOption::fixedWidth(100)));
 				GUILabel* totalCyclesSelf = GUILabel::create(widget, newRow.totalCyclesSelf, GUIOptions(GUIOption::fixedWidth(100)));
-				GUILabel* estOverhead = GUILabel::create(widget, newRow.estOverhead, GUIOptions(GUIOption::fixedWidth(100)));
-				GUILabel* estOverheadSelf = GUILabel::create(widget, newRow.estOverheadSelf, GUIOptions(GUIOption::fixedWidth(100)));
 
 				newRow.labelLayout->addSpace(0);
 				newRow.labelLayout->addElement(name);
 
 				newRow.contentLayout->addElement(pctOfParent);
 				newRow.contentLayout->addElement(numCalls);
+				newRow.contentLayout->addElement(numAllocs);
+				newRow.contentLayout->addElement(numFrees);
 				newRow.contentLayout->addElement(avgCycles);
 				newRow.contentLayout->addElement(totalCycles);
-				newRow.contentLayout->addElement(maxCycles);
 				newRow.contentLayout->addElement(avgCyclesSelf);
 				newRow.contentLayout->addElement(totalCyclesSelf);
-				newRow.contentLayout->addElement(estOverhead);
-				newRow.contentLayout->addElement(estOverheadSelf);
 
 				newRow.elements.push_back(name);
 				newRow.elements.push_back(pctOfParent);
 				newRow.elements.push_back(numCalls);
+				newRow.elements.push_back(numAllocs);
+				newRow.elements.push_back(numFrees);
 				newRow.elements.push_back(avgCycles);
 				newRow.elements.push_back(totalCycles);
-				newRow.elements.push_back(maxCycles);
 				newRow.elements.push_back(avgCyclesSelf);
 				newRow.elements.push_back(totalCyclesSelf);
-				newRow.elements.push_back(estOverhead);
-				newRow.elements.push_back(estOverheadSelf);
 			}
 
 			ProfilerOverlay::PreciseRow& row = rows[curIdx];
@@ -220,28 +211,27 @@ namespace BansheeEngine
 			row.name.setParameter(0, toWString(name));
 			row.pctOfParent.setParameter(0, toWString(pctOfParent * 100.0f, 2, 0, ' ', std::ios::fixed));
 			row.numCalls.setParameter(0, toWString(numCalls));
+			row.numAllocs.setParameter(0, toWString(numAllocs));
+			row.numFrees.setParameter(0, toWString(numFrees));
 			row.avgCycles.setParameter(0, toWString(avgCycles));
 			row.totalCycles.setParameter(0, toWString(totalCycles));
-			row.maxCycles.setParameter(0, toWString(maxCycles));
 			row.avgCyclesSelf.setParameter(0, toWString(avgSelfCycles));
 			row.totalCyclesSelf.setParameter(0, toWString(totalSelfCycles));
-			row.estOverhead.setParameter(0, toWString(estOverhead));
-			row.estOverheadSelf.setParameter(0, toWString(estOverheadSelf));
 
 			curIdx++;
 		}
 	};
 
-	const UINT32 ProfilerOverlay::MAX_DEPTH = 2;
+	const UINT32 ProfilerOverlay::MAX_DEPTH = 4;
 
 	ProfilerOverlay::ProfilerOverlay(const CM::ViewportPtr& target)
 		:mIsShown(false), mBasicAreaLabels(nullptr), mPreciseAreaLabels(nullptr), mBasicAreaContents(nullptr), mPreciseAreaContents(nullptr),
 		mBasicLayoutLabels(nullptr), mPreciseLayoutLabels(nullptr), mBasicLayoutContents(nullptr), mPreciseLayoutContents(nullptr),
-		mTitleBasicName(nullptr), mTitleBasicPctOfParent(nullptr), mTitleBasicNumCalls(nullptr), mTitleBasicAvgTime(nullptr), 
-		mTitleBasicTotalTime(nullptr), mTitleBasicMaxTime(nullptr), mTitleBasicAvgTitleSelf(nullptr), mTitleBasicTotalTimeSelf(nullptr), 
-		mTitleBasicEstOverhead(nullptr), mTitleBasicEstOverheadSelf(nullptr), mTitlePreciseName(nullptr), mTitlePrecisePctOfParent(nullptr), 
-		mTitlePreciseNumCalls(nullptr), mTitlePreciseAvgCycles(nullptr), mTitlePreciseTotalCycles(nullptr), mTitlePreciseMaxCycles(nullptr), 
-		mTitlePreciseAvgCyclesSelf(nullptr), mTitlePreciseTotalCyclesSelf(nullptr), mTitlePreciseEstOverhead(nullptr), mTitlePreciseEstOverheadSelf(nullptr)
+		mTitleBasicName(nullptr), mTitleBasicPctOfParent(nullptr), mTitleBasicNumCalls(nullptr), mTitleBasicNumAllocs(nullptr), mTitleBasicNumFrees(nullptr),
+		mTitleBasicAvgTime(nullptr), mTitleBasicTotalTime(nullptr), mTitleBasicAvgTitleSelf(nullptr), mTitleBasicTotalTimeSelf(nullptr), 
+		mTitlePreciseName(nullptr), mTitlePrecisePctOfParent(nullptr), mTitlePreciseNumCalls(nullptr), mTitlePreciseNumAllocs(nullptr), 
+		mTitlePreciseNumFrees(nullptr), mTitlePreciseAvgCycles(nullptr), mTitlePreciseTotalCycles(nullptr), mTitlePreciseAvgCyclesSelf(nullptr), 
+		mTitlePreciseTotalCyclesSelf(nullptr)
 	{
 		setTarget(target);
 	}
@@ -289,24 +279,22 @@ namespace BansheeEngine
 		mTitleBasicName = GUILabel::create(*mWidget, HString(L"Name"), GUIOptions(GUIOption::fixedWidth(200)));
 		mTitleBasicPctOfParent = GUILabel::create(*mWidget, HString(L"% parent"), GUIOptions(GUIOption::fixedWidth(50)));
 		mTitleBasicNumCalls = GUILabel::create(*mWidget, HString(L"# calls"), GUIOptions(GUIOption::fixedWidth(50)));
+		mTitleBasicNumAllocs = GUILabel::create(*mWidget, HString(L"# allocs"), GUIOptions(GUIOption::fixedWidth(50)));
+		mTitleBasicNumFrees = GUILabel::create(*mWidget, HString(L"# frees"), GUIOptions(GUIOption::fixedWidth(50)));
 		mTitleBasicAvgTime = GUILabel::create(*mWidget, HString(L"Avg. time"), GUIOptions(GUIOption::fixedWidth(60)));
 		mTitleBasicTotalTime = GUILabel::create(*mWidget, HString(L"Total time"), GUIOptions(GUIOption::fixedWidth(60)));
-		mTitleBasicMaxTime = GUILabel::create(*mWidget, HString(L"Max time"), GUIOptions(GUIOption::fixedWidth(60)));
 		mTitleBasicAvgTitleSelf = GUILabel::create(*mWidget, HString(L"Avg. self time"), GUIOptions(GUIOption::fixedWidth(100)));
 		mTitleBasicTotalTimeSelf = GUILabel::create(*mWidget, HString(L"Total self time"), GUIOptions(GUIOption::fixedWidth(100)));
-		mTitleBasicEstOverhead = GUILabel::create(*mWidget, HString(L"Est. overhead"), GUIOptions(GUIOption::fixedWidth(100)));
-		mTitleBasicEstOverheadSelf = GUILabel::create(*mWidget, HString(L"Est. self overhead"), GUIOptions(GUIOption::fixedWidth(100)));
 
 		mTitlePreciseName = GUILabel::create(*mWidget, HString(L"Name"), GUIOptions(GUIOption::fixedWidth(200)));
 		mTitlePrecisePctOfParent = GUILabel::create(*mWidget, HString(L"% parent"), GUIOptions(GUIOption::fixedWidth(50)));
 		mTitlePreciseNumCalls = GUILabel::create(*mWidget, HString(L"# calls"), GUIOptions(GUIOption::fixedWidth(50)));
+		mTitlePreciseNumAllocs = GUILabel::create(*mWidget, HString(L"# allocs"), GUIOptions(GUIOption::fixedWidth(50)));
+		mTitlePreciseNumFrees = GUILabel::create(*mWidget, HString(L"# frees"), GUIOptions(GUIOption::fixedWidth(50)));
 		mTitlePreciseAvgCycles = GUILabel::create(*mWidget, HString(L"Avg. cycles"), GUIOptions(GUIOption::fixedWidth(60)));
 		mTitlePreciseTotalCycles = GUILabel::create(*mWidget, HString(L"Total cycles"), GUIOptions(GUIOption::fixedWidth(60)));
-		mTitlePreciseMaxCycles = GUILabel::create(*mWidget, HString(L"Max cycles"), GUIOptions(GUIOption::fixedWidth(60)));
 		mTitlePreciseAvgCyclesSelf = GUILabel::create(*mWidget, HString(L"Avg. self cycles"), GUIOptions(GUIOption::fixedWidth(100)));
 		mTitlePreciseTotalCyclesSelf = GUILabel::create(*mWidget, HString(L"Total self cycles"), GUIOptions(GUIOption::fixedWidth(100)));
-		mTitlePreciseEstOverhead = GUILabel::create(*mWidget, HString(L"Est. overhead"), GUIOptions(GUIOption::fixedWidth(100)));
-		mTitlePreciseEstOverheadSelf = GUILabel::create(*mWidget, HString(L"Est. self overhead"), GUIOptions(GUIOption::fixedWidth(100)));
 
 		GUILayout& basicTitleLabelLayout = mBasicLayoutLabels->addLayoutX();
 		GUILayout& preciseTitleLabelLayout = mPreciseLayoutLabels->addLayoutX();
@@ -316,24 +304,22 @@ namespace BansheeEngine
 		basicTitleLabelLayout.addElement(mTitleBasicName);
 		basicTitleContentLayout.addElement(mTitleBasicPctOfParent);
 		basicTitleContentLayout.addElement(mTitleBasicNumCalls);
+		basicTitleContentLayout.addElement(mTitleBasicNumAllocs);
+		basicTitleContentLayout.addElement(mTitleBasicNumFrees);
 		basicTitleContentLayout.addElement(mTitleBasicAvgTime);
 		basicTitleContentLayout.addElement(mTitleBasicTotalTime);
-		basicTitleContentLayout.addElement(mTitleBasicMaxTime);
 		basicTitleContentLayout.addElement(mTitleBasicAvgTitleSelf);
 		basicTitleContentLayout.addElement(mTitleBasicTotalTimeSelf);
-		basicTitleContentLayout.addElement(mTitleBasicEstOverhead);
-		basicTitleContentLayout.addElement(mTitleBasicEstOverheadSelf);
 
 		preciseTitleLabelLayout.addElement(mTitlePreciseName);
 		preciseTitleContentLayout.addElement(mTitlePrecisePctOfParent);
 		preciseTitleContentLayout.addElement(mTitlePreciseNumCalls);
+		preciseTitleContentLayout.addElement(mTitlePreciseNumAllocs);
+		preciseTitleContentLayout.addElement(mTitlePreciseNumFrees);
 		preciseTitleContentLayout.addElement(mTitlePreciseAvgCycles);
 		preciseTitleContentLayout.addElement(mTitlePreciseTotalCycles);
-		preciseTitleContentLayout.addElement(mTitlePreciseMaxCycles);
 		preciseTitleContentLayout.addElement(mTitlePreciseAvgCyclesSelf);
 		preciseTitleContentLayout.addElement(mTitlePreciseTotalCyclesSelf);
-		preciseTitleContentLayout.addElement(mTitlePreciseEstOverhead);
-		preciseTitleContentLayout.addElement(mTitlePreciseEstOverheadSelf);
 
 		mBasicLayoutLabels->addFlexibleSpace();
 		mPreciseLayoutLabels->addFlexibleSpace();
@@ -451,8 +437,8 @@ namespace BansheeEngine
 				todoBasic.pop();
 
 				const CPUProfilerBasicSamplingEntry::Data& data = curEntry.entry.data;
-				basicRowFiller.addData(curEntry.depth, data.name, data.pctOfParent, data.numCalls, data.avgTimeMs, data.totalTimeMs, 
-					data.maxTimeMs, data.avgSelfTimeMs, data.totalSelfTimeMs, data.estimatedOverheadMs, data.estimatedSelfOverheadMs);
+				basicRowFiller.addData(curEntry.depth, data.name, data.pctOfParent, data.numCalls, data.memAllocs, data.memFrees, 
+					data.avgTimeMs, data.totalTimeMs, data.avgSelfTimeMs, data.totalSelfTimeMs);
 
 				if(curEntry.depth <= MAX_DEPTH)
 				{
@@ -481,8 +467,8 @@ namespace BansheeEngine
 				todoPrecise.pop();
 
 				const CPUProfilerPreciseSamplingEntry::Data& data = curEntry.entry.data;
-				preciseRowFiller.addData(curEntry.depth, data.name, data.pctOfParent, data.numCalls, data.avgCycles, data.totalCycles, 
-					data.maxCycles, data.avgSelfCycles, data.totalSelfCycles, data.estimatedOverhead, data.estimatedSelfOverhead);
+				preciseRowFiller.addData(curEntry.depth, data.name, data.pctOfParent, data.numCalls, data.memAllocs, data.memFrees, 
+					data.avgCycles, data.totalCycles, data.avgSelfCycles, data.totalSelfCycles);
 
 				if(curEntry.depth <= MAX_DEPTH)
 				{

+ 20 - 4
CamelotCore/Include/CmCPUProfiler.h

@@ -48,20 +48,24 @@ namespace CamelotFramework
 
 		struct ProfileSample
 		{
-			ProfileSample(double _time)
-				:time(_time)
+			ProfileSample(double _time, UINT64 _numAllocs, UINT64 _numFrees)
+				:time(_time), numAllocs(_numAllocs), numFrees(_numFrees)
 			{ }
 
 			double time;
+			UINT64 numAllocs;
+			UINT64 numFrees;
 		};
 
 		struct PreciseProfileSample
 		{
-			PreciseProfileSample(UINT64 _cycles)
-				:cycles(_cycles)
+			PreciseProfileSample(UINT64 _cycles, UINT64 _numAllocs, UINT64 _numFrees)
+				:cycles(_cycles), numAllocs(_numAllocs), numFrees(_numFrees)
 			{ }
 
 			UINT64 cycles;
+			UINT64 numAllocs;
+			UINT64 numFrees;
 		};
 
 		struct ProfileData
@@ -69,6 +73,9 @@ namespace CamelotFramework
 			Vector<ProfileSample>::type samples;
 			Timer timer;
 
+			UINT64 memAllocs;
+			UINT64 memFrees;
+
 			void beginSample();
 			void endSample();
 			void resumeLastSample();
@@ -79,6 +86,9 @@ namespace CamelotFramework
 			Vector<PreciseProfileSample>::type samples;
 			TimerPrecise timer;
 
+			UINT64 memAllocs;
+			UINT64 memFrees;
+
 			void beginSample();
 			void endSample();
 			void resumeLastSample();
@@ -235,6 +245,9 @@ namespace CamelotFramework
 			String name;
 			UINT32 numCalls;
 
+			UINT64 memAllocs;
+			UINT64 memFrees;
+
 			double avgTimeMs;
 			double maxTimeMs;
 			double totalTimeMs;
@@ -260,6 +273,9 @@ namespace CamelotFramework
 			String name;
 			UINT32 numCalls;
 
+			UINT64 memAllocs;
+			UINT64 memFrees;
+
 			UINT64 avgCycles;
 			UINT64 maxCycles;
 			UINT64 totalCycles;

+ 0 - 1
CamelotCore/Include/CmPrerequisites.h

@@ -4,7 +4,6 @@
 
 #define CM_MAX_MULTIPLE_RENDER_TARGETS 8
 #define CM_FORCE_SINGLETHREADED_RENDERING 0
-#define CM_PROFILING_ENABLED 1
 
 //----------------------------------------------------------------------------
 // Windows Settings

+ 1 - 5
CamelotCore/Include/CmTextUtility.h

@@ -14,11 +14,9 @@ namespace CamelotFramework
 		public:
 			TextWord(bool spacer);
 
-			void addChar(const CHAR_DESC& desc);
+			UINT32 addChar(const CHAR_DESC& desc);
 			void addSpace(UINT32 spaceWidth);
 
-			void removeLastChar();
-
 			UINT32 getWidth() const { return mWidth; }
 			UINT32 getHeight() const { return mHeight; }
 			bool isSpacer() const { return mSpacer; }
@@ -31,8 +29,6 @@ namespace CamelotFramework
 			UINT32 mHeight;
 			bool mSpacer;
 			UINT32 mSpaceWidth;
-
-			void calculateWidth();
 		};
 
 	public:

+ 24 - 2
CamelotCore/Source/CmCPUProfiler.cpp

@@ -66,6 +66,9 @@ namespace CamelotFramework
 
 	void CPUProfiler::ProfileData::beginSample()
 	{
+		memAllocs = MemoryCounter::Allocs.load();
+		memFrees = MemoryCounter::Frees.load();
+
 		timer.reset();
 		timer.start();
 	}
@@ -73,7 +76,11 @@ namespace CamelotFramework
 	void CPUProfiler::ProfileData::endSample()
 	{
 		timer.stop();
-		samples.push_back(ProfileSample(timer.time));
+
+		UINT64 numAllocs = MemoryCounter::Allocs.load() - memAllocs;
+		UINT64 numFrees = MemoryCounter::Frees.load() - memFrees;
+
+		samples.push_back(ProfileSample(timer.time, numAllocs, numFrees));
 	}
 
 	void CPUProfiler::ProfileData::resumeLastSample()
@@ -84,6 +91,9 @@ namespace CamelotFramework
 
 	void CPUProfiler::PreciseProfileData::beginSample()
 	{
+		memAllocs = MemoryCounter::Allocs.load();
+		memFrees = MemoryCounter::Frees.load();
+
 		timer.reset();
 		timer.start();
 	}
@@ -91,7 +101,11 @@ namespace CamelotFramework
 	void CPUProfiler::PreciseProfileData::endSample()
 	{
 		timer.stop();
-		samples.push_back(PreciseProfileSample(timer.cycles));
+
+		UINT64 numAllocs = MemoryCounter::Allocs.load() - memAllocs;
+		UINT64 numFrees = MemoryCounter::Frees.load() - memFrees;
+
+		samples.push_back(PreciseProfileSample(timer.cycles, numAllocs, numFrees));
 	}
 
 	void CPUProfiler::PreciseProfileData::resumeLastSample()
@@ -460,12 +474,16 @@ namespace CamelotFramework
 			// Calculate basic data
 			entryBasic->data.name = curBlock->name;
 
+			entryBasic->data.memAllocs = 0;
+			entryBasic->data.memFrees = 0;
 			entryBasic->data.totalTimeMs = 0.0;
 			entryBasic->data.maxTimeMs = 0.0;
 			for(auto& sample : curBlock->basic.samples)
 			{
 				entryBasic->data.totalTimeMs += sample.time;
 				entryBasic->data.maxTimeMs = std::max(entryBasic->data.maxTimeMs, sample.time);
+				entryBasic->data.memAllocs += sample.numAllocs;
+				entryBasic->data.memFrees += sample.numFrees;
 			}
 
 			entryBasic->data.numCalls = (UINT32)curBlock->basic.samples.size();
@@ -496,12 +514,16 @@ namespace CamelotFramework
 			// Calculate precise data
 			entryPrecise->data.name = curBlock->name;
 
+			entryPrecise->data.memAllocs = 0;
+			entryPrecise->data.memFrees = 0;
 			entryPrecise->data.totalCycles = 0;
 			entryPrecise->data.maxCycles = 0;
 			for(auto& sample : curBlock->precise.samples)
 			{
 				entryPrecise->data.totalCycles += sample.cycles;
 				entryPrecise->data.maxCycles = std::max(entryPrecise->data.maxCycles, sample.cycles);
+				entryPrecise->data.memAllocs += sample.numAllocs;
+				entryPrecise->data.memFrees += sample.numFrees;
 			}
 
 			entryPrecise->data.numCalls = (UINT32)curBlock->precise.samples.size();

+ 31 - 55
CamelotCore/Source/CmTextUtility.cpp

@@ -11,65 +11,38 @@ namespace CamelotFramework
 		:mWidth(0), mHeight(0), mSpacer(spacer), mSpaceWidth(0)
 	{ }
 
-	void TextUtility::TextWord::addChar(const CHAR_DESC& desc)
-	{
-		mChars.push_back(desc);
-
-		calculateWidth();
-	}
-
-	void TextUtility::TextWord::addSpace(UINT32 spaceWidth)
-	{
-		mSpaceWidth += spaceWidth;
-
-		calculateWidth();
-	}
-
-	void TextUtility::TextWord::removeLastChar()
+	UINT32 TextUtility::TextWord::addChar(const CHAR_DESC& desc)
 	{
+		UINT32 charWidth = desc.xAdvance;
 		if(mChars.size() > 0)
 		{
-			mChars.erase(mChars.end() - 1);
-			calculateWidth();
-		}
-	}
-
-	void TextUtility::TextWord::calculateWidth()
-	{
-		if(isSpacer())
-		{
-			mWidth = mSpaceWidth;
-			mHeight = 0;
-			return;
-		}
-
-		if(mChars.size() == 0)
-		{
-			mWidth = 0;
-			mHeight = 0;
-			return;
-		}
-
-		mWidth = 0;
-		mHeight = 0;
-		UINT32 kerning = 0;
-		for(size_t i = 0; i < mChars.size() - 1; i++)
-		{
-			mWidth += mChars[i].xAdvance + kerning;
-			mHeight = std::max(mHeight, mChars[i].height);
-
-			kerning = 0;
-			for(size_t j = 0; j < mChars[i].kerningPairs.size(); j++)
+			UINT32 kerning = 0;
+			CHAR_DESC& prevChar = mChars.back();
+			for(size_t j = 0; j < prevChar.kerningPairs.size(); j++)
 			{
-				if(mChars[i].kerningPairs[j].otherCharId == mChars[i + 1].charId)
+				if(prevChar.kerningPairs[j].otherCharId == desc.charId)
 				{
-					kerning = mChars[i].kerningPairs[j].amount;
+					kerning = prevChar.kerningPairs[j].amount;
 					break;
 				}
 			}
+
+			charWidth += kerning;
 		}
 
-		mWidth += mChars[mChars.size() - 1].xAdvance + kerning;
+		mWidth += charWidth;
+		mHeight = std::max(mHeight, desc.height);
+
+		mChars.push_back(desc);
+
+		return charWidth;
+	}
+
+	void TextUtility::TextWord::addSpace(UINT32 spaceWidth)
+	{
+		mSpaceWidth += spaceWidth;
+		mWidth = mSpaceWidth;
+		mHeight = 0;
 	}
 
 	TextUtility::TextLine::TextLine(UINT32 baselineOffset, UINT32 lineHeight, UINT32 spaceWidth)
@@ -90,12 +63,13 @@ namespace CamelotFramework
 
 	void TextUtility::TextLine::add(const CHAR_DESC& charDesc)
 	{
+		UINT32 charWidth = 0;
 		if(mLastWord == nullptr)
 		{
 			mWords.push_back(TextWord(false));
 			mLastWord = &mWords.back();
 
-			mLastWord->addChar(charDesc);
+			charWidth = mLastWord->addChar(charDesc);
 		}
 		else
 		{
@@ -105,10 +79,11 @@ namespace CamelotFramework
 				mLastWord = &mWords.back();
 			}
 
-			mLastWord->addChar(charDesc);
+			charWidth = mLastWord->addChar(charDesc);
 		}
 
-		calculateBounds();
+		mWidth += charWidth;
+		mHeight = std::max(mHeight, mLastWord->getHeight());
 	}
 
 	void TextUtility::TextLine::addSpace()
@@ -128,7 +103,7 @@ namespace CamelotFramework
 			mLastWord->addSpace(mSpaceWidth);
 		}
 
-		calculateBounds();
+		mWidth += mSpaceWidth;
 	}
 
 	void TextUtility::TextLine::addWord(const TextWord& word)
@@ -136,7 +111,8 @@ namespace CamelotFramework
 		mWords.push_back(word);
 		mLastWord = &mWords.back();
 
-		calculateBounds();
+		mWidth += word.getWidth();
+		mHeight = std::max(mHeight, word.getHeight());
 	}
 
 	TextUtility::TextWord TextUtility::TextLine::removeLastWord()
@@ -391,7 +367,7 @@ namespace CamelotFramework
 				{
 					TextWord lastWord = curLine->removeLastWord();
 
-					if(lastWord.getWidth() <= width) // If the world fits, attempt to add it to a new line
+					if(lastWord.getWidth() <= width) // If the word fits, attempt to add it to a new line
 					{
 						curLine->finalize(false);
 						textData->mLines.push_back(TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth));

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -250,6 +250,7 @@
     <ClCompile Include="Source\CmFRect.cpp" />
     <ClCompile Include="Source\CmInt2.cpp" />
     <ClCompile Include="Source\CmManagedDataBlock.cpp" />
+    <ClCompile Include="Source\CmMemoryAllocator.cpp" />
     <ClCompile Include="Source\CmMemStack.cpp" />
     <ClCompile Include="Source\CmRect.cpp" />
     <ClCompile Include="Source\CmStringTable.cpp" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -344,5 +344,8 @@
     <ClCompile Include="Source\CmStringTable.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmMemoryAllocator.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 24 - 0
CamelotUtility/Include/CmMemoryAllocator.h

@@ -4,9 +4,17 @@
 #undef max
 
 #include <boost/preprocessor.hpp>
+#include <atomic>
 
 namespace CamelotFramework
 {
+	class CM_UTILITY_EXPORT MemoryCounter
+	{
+	public:
+		static std::atomic_uint64_t Allocs;
+		static std::atomic_uint64_t Frees;
+	};
+
 	/**
 	 * @brief	Memory allocator providing a generic implementation. 
 	 * 			Specialize for specific categories as needed.
@@ -17,21 +25,37 @@ namespace CamelotFramework
 	public:
 		static inline void* allocate(UINT32 bytes)
 		{
+#if CM_PROFILING_ENABLED
+			MemoryCounter::Allocs++;
+#endif
+
 			return malloc(bytes);
 		}
 
 		static inline void* allocateArray(UINT32 bytes, UINT32 count)
 		{
+#if CM_PROFILING_ENABLED
+			MemoryCounter::Allocs++;
+#endif
+
 			return malloc(bytes * count);
 		}
 
 		static inline void free(void* ptr)
 		{
+#if CM_PROFILING_ENABLED
+			MemoryCounter::Frees++;
+#endif
+
 			::free(ptr);
 		}
 
 		static inline void freeArray(void* ptr, UINT32 count)
 		{
+#if CM_PROFILING_ENABLED
+			MemoryCounter::Frees++;
+#endif
+
 			::free(ptr);
 		}
 	};

+ 2 - 0
CamelotUtility/Include/CmPrerequisitesUtil.h

@@ -32,6 +32,8 @@ THE SOFTWARE
 // 2 - Thread support but render system can only be accessed from main thread
 #define CM_THREAD_SUPPORT 2
 
+#define CM_PROFILING_ENABLED 1
+
 // Platform-specific stuff
 #include "CmPlatformDefines.h"