瀏覽代碼

Improved profiler - better filtering, show 'hot' paths

Brian Fiete 2 年之前
父節點
當前提交
398cb0c7ad
共有 5 個文件被更改,包括 147 次插入45 次删除
  1. 15 0
      IDE/src/ui/ProfilePanel.bf
  2. 22 24
      IDEHelper/DebugTarget.cpp
  3. 1 0
      IDEHelper/DebugTarget.h
  4. 108 21
      IDEHelper/Profiler.cpp
  5. 1 0
      IDEHelper/Profiler.h

+ 15 - 0
IDE/src/ui/ProfilePanel.bf

@@ -351,6 +351,19 @@ namespace IDE.ui
 			}
 		}
 
+		void OpenHot(ListViewItem lvi, int32 minSamples)
+		{
+			lvi.WithItems(scope (childItem) =>
+				{
+					var profileListViewItem = childItem as ProfileListViewItem;
+					if ((profileListViewItem.mSelfSamples + profileListViewItem.mChildSamples >= minSamples) && (profileListViewItem.IsParent))
+					{
+						profileListViewItem.Open(true, true);
+						OpenHot(childItem, minSamples);
+					}
+				});
+		}
+
 		public void Show(int32 threadId, StringView threadName)
 		{
 			mTickCreated = Utils.GetTickCount();
@@ -449,6 +462,8 @@ namespace IDE.ui
 				itemStack.Add(curItem);
 				curItem = newItem;
 			}
+
+			OpenHot(mListView.GetRoot(), (.)(totalSamples * 0.05f));
 		}
 
 		public void Add(DbgProfiler profiler)

+ 22 - 24
IDEHelper/DebugTarget.cpp

@@ -273,6 +273,7 @@ String DebugTarget::UnloadDyn(addr_target imageBase)
 				}
 			}
 
+			mFindDbgModuleCache.Clear();
 			mDbgModules.RemoveAt(i);
 			bool success = mDbgModuleMap.Remove(dwarf->mId);
 			BF_ASSERT_REL(success);
@@ -316,6 +317,7 @@ void DebugTarget::CleanupHotHeap()
 			DbgModule* dbgModule = mDbgModules[dwarfIdx];
 			if (dbgModule->mDeleting)
 			{
+				mFindDbgModuleCache.Clear();
 				mDbgModules.RemoveAt(dwarfIdx);
 				bool success = mDbgModuleMap.Remove(dbgModule->mId);
 				BF_ASSERT_REL(success);
@@ -932,6 +934,7 @@ void DebugTarget::GetCompilerSettings()
 void DebugTarget::AddDbgModule(DbgModule* dbgModule)
 {
 	dbgModule->mId = ++mCurModuleId;
+	mFindDbgModuleCache.Clear();
 	mDbgModules.Add(dbgModule);
 	bool success = mDbgModuleMap.TryAdd(dbgModule->mId, dbgModule);
 	BF_ASSERT_REL(success);
@@ -2446,54 +2449,49 @@ bool DebugTarget::GetValueByNameInBlock(DbgSubprogram* dwSubprogram, DbgBlock* d
 
 const DbgMemoryFlags DebugTarget::ReadOrigImageData(addr_target address, uint8* data, int size)
 {
-	for (auto dwarf : mDbgModules)
+	auto dwarf = FindDbgModuleForAddress(address);
+	if ((dwarf != NULL) && (dwarf->mOrigImageData != NULL))
 	{
-		if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize) && (dwarf->mOrigImageData != NULL))
-		{
-			return dwarf->mOrigImageData->Read(address, data, size);
-		}
-		//return dbgModule->mOrigImageData + (address - dbgModule->mImageBase);
+		return dwarf->mOrigImageData->Read(address, data, size);
 	}
-
 	return DbgMemoryFlags_None;
 }
 
 bool DebugTarget::DecodeInstruction(addr_target address, CPUInst* inst)
 {
-	for (auto dwarf : mDbgModules)
+	auto dwarf = FindDbgModuleForAddress(address);
+	if ((dwarf != NULL) && (dwarf->mOrigImageData != NULL))
 	{
-		if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize) && (dwarf->mOrigImageData != NULL))
-		{
-			return mDebugger->mCPU->Decode(address, dwarf->mOrigImageData, inst);
-		}
+		return mDebugger->mCPU->Decode(address, dwarf->mOrigImageData, inst);
 	}
-
 	return false;
 }
 
 DbgBreakKind DebugTarget::GetDbgBreakKind(addr_target address, CPURegisters* registers, intptr_target* objAddr)
 {
-	for (auto dwarf : mDbgModules)
+	auto dwarf = FindDbgModuleForAddress(address);
+	if ((dwarf != NULL) && (dwarf->mOrigImageData != NULL))
 	{
-		if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize) && (dwarf->mOrigImageData != NULL))
-		{
-			auto result = mDebugger->mCPU->GetDbgBreakKind(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
-			return result;
-		}
+		auto result = mDebugger->mCPU->GetDbgBreakKind(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
+		return result;
 	}
-
 	return DbgBreakKind_None;
 }
 
 DbgModule* DebugTarget::FindDbgModuleForAddress(addr_target address)
 {
-	for (auto dwarf : mDbgModules)
+	addr_target checkAddr = address & ~0xFFFF;
+	DbgModule** valuePtr = NULL;
+	if (mFindDbgModuleCache.TryAdd(checkAddr, NULL, &valuePtr))
 	{
-		if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize))
-			return dwarf;
+		for (auto dwarf : mDbgModules)
+		{
+			if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize))
+				*valuePtr = dwarf;
+		}
 	}
 
-	return NULL;
+	return *valuePtr;
 }
 
 DbgModule* DebugTarget::GetMainDbgModule()

+ 1 - 0
IDEHelper/DebugTarget.h

@@ -42,6 +42,7 @@ public:
 	DbgModule* mTargetBinary;
 	Array<DbgModule*> mDbgModules;
 	Dictionary<int, DbgModule*> mDbgModuleMap;
+	Dictionary<addr_target, DbgModule*> mFindDbgModuleCache; // Addresses are all 64k multiples
 	HashSet<DbgSrcFile*> mPendingSrcFileRehup; // Waiting to remove old/invalid line info
 
 	BumpAllocator mAlloc;

+ 108 - 21
IDEHelper/Profiler.cpp

@@ -343,10 +343,6 @@ void DbgProfiler::ThreadProc()
 
 			bool isThreadIdle = idleThreadSet.Contains(thread->mThreadId);
 
-			profileThreadInfo->mTotalSamples += curSampleCount;
-			if (isThreadIdle)
-				profileThreadInfo->mTotalIdleSamples += curSampleCount;
-
 			mDebugger->mActiveThread = thread;
 
 			::SuspendThread(thread->mHThread);
@@ -354,14 +350,38 @@ void DbgProfiler::ThreadProc()
 			CPURegisters registers;
 			mDebugger->PopulateRegisters(&registers);
 
+			addr_target prevPC = 0;
+			bool traceIsValid = true;
 			int stackSize = 0;
 			for (int stackIdx = 0; stackIdx < maxStackTrace; stackIdx++)
 			{
 				auto pc = registers.GetPC();
-				if (pc <= 0xFFFF)
+				if (pc == 0)
+				{
+					bool* valuePtr = NULL;
+					if (mStackHeadCheckMap.TryAdd(prevPC, NULL, &valuePtr))
+					{
+						addr_target symbolOffset = 0;
+						String symbolName;
+						mDebugger->mDebugTarget->FindSymbolAt(prevPC, &symbolName, &symbolOffset, NULL, false);
+						*valuePtr = (symbolName == "RtlUserThreadStart");
+					}
+
+					if (!*valuePtr)
+						traceIsValid = false;
+
+					// Done - success (?). Check lastDbgModule.
+					break;
+				}
+
+				prevPC = pc;
+				auto lastDbgModule = mDebugger->mDebugTarget->FindDbgModuleForAddress(pc);
+				if (lastDbgModule == NULL)
 				{
+					traceIsValid = false;
 					break;
 				}
+
 				stackTrace[stackSize++] = pc;
 				auto prevSP = registers.GetSP();
 				if (!mDebugger->RollBackStackFrame(&registers, stackIdx == 0))
@@ -369,30 +389,38 @@ void DbgProfiler::ThreadProc()
 				if (registers.GetSP() <= prevSP)
 				{
 					// SP went the wrong direction, stop rolling back
+					traceIsValid = false;
 					break;
 				}
 			}
 
-			ProfileAddrEntry* insertedProfileEntry = AddToSet(mProfileAddrEntrySet, stackTrace, stackSize);
-			if (insertedProfileEntry->mEntryIdx == -1)
-			{
-				insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1'
-				mPendingProfileEntries.Add(*insertedProfileEntry);
-			}
-
-			for (int i = 0; i < curSampleCount; i++)
+			if (traceIsValid)
 			{
-				int entryIdx = insertedProfileEntry->mEntryIdx;
+				profileThreadInfo->mTotalSamples += curSampleCount;
 				if (isThreadIdle)
-					entryIdx = -entryIdx;
-				profileThreadInfo->mProfileAddrEntries.push_back(entryIdx);
+					profileThreadInfo->mTotalIdleSamples += curSampleCount;
+
+				ProfileAddrEntry* insertedProfileEntry = AddToSet(mProfileAddrEntrySet, stackTrace, stackSize);
+				if (insertedProfileEntry->mEntryIdx == -1)
+				{
+					insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1'
+					mPendingProfileEntries.Add(*insertedProfileEntry);
+				}
+
+				for (int i = 0; i < curSampleCount; i++)
+				{
+					int entryIdx = insertedProfileEntry->mEntryIdx;
+					if (isThreadIdle)
+						entryIdx = -entryIdx;
+					profileThreadInfo->mProfileAddrEntries.push_back(entryIdx);
+				}
+
+				int elapsedTime = timeGetTime() - startTick;
+				mTotalActiveSamplingMS += elapsedTime;
 			}
 
 			::ResumeThread(thread->mHThread);
 
-			int elapsedTime = timeGetTime() - startTick;
-			mTotalActiveSamplingMS += elapsedTime;
-
 			mDebugger->mActiveThread = NULL;
 
 			threadIdx++;
@@ -479,6 +507,7 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
 		int mStackIdx;
 	};
 	Array<_QueuedEntry> workQueue;
+	int skipStackCount = 0;
 
 	auto _AddEntries = [&](int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc)
 	{
@@ -486,7 +515,7 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
 		int childSampleCount = 0;
 
 		// First arrange list so we only contain items that match 'findProc'
-		if (stackIdx != -1)
+		if (stackIdx >= skipStackCount)
 		{
 			for (int idx = rangeStart; idx < rangeEnd; idx++)
 			{
@@ -551,6 +580,64 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
 	};
 	_AddEntries(rangeStart, rangeEnd, stackIdx, findProc);
 
+	while (skipStackCount < 6)
+	{
+		bool isSkipValid = true;
+
+		for (int idx = rangeStart; idx < rangeEnd; idx++)
+		{
+			auto procEntry = procEntries[idx];
+			if (procEntry->mUsed)
+				continue;
+
+			int stackIdx = procEntry->mSize - 1 - skipStackCount;
+			if (stackIdx < 0)
+			{
+				isSkipValid = false;
+				break;
+			}
+
+			auto checkProc = procEntry->mData[procEntry->mSize - 1 - skipStackCount];
+
+			switch (skipStackCount)
+			{
+			case 0:
+				if (checkProc->mProcName != "RtlUserThreadStart")
+					isSkipValid = false;
+				break;
+			case 1:
+				if (checkProc->mProcName != "BaseThreadInitThunk")
+					isSkipValid = false;
+				break;
+			case 2:
+				if ((checkProc->mProcName != "__scrt_common_main_seh()") && (checkProc->mProcName != "mainCRTStartup()"))
+					isSkipValid = false;
+				break;
+			case 3:
+				if ((checkProc->mProcName != "invoke_main()") && (checkProc->mProcName != "main"))
+					isSkipValid = false;
+				break;
+			case 4:
+				if (checkProc->mProcName != "main")
+					isSkipValid = false;
+				break;
+			case 5:
+				if (checkProc->mProcName != "BeefStartProgram")
+					isSkipValid = false;
+				break;
+			default:
+				isSkipValid = false;
+			}
+
+			if (!isSkipValid)
+				break;
+		}
+
+		if (!isSkipValid)
+			break;
+		skipStackCount++;
+	}
+
 	while (!workQueue.IsEmpty())
 	{
 		auto& entry = workQueue.back();
@@ -574,7 +661,7 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
 
 		if (!addedChild)
 		{
-			if (entry.mStackIdx != -1)
+			if ((entry.mStackIdx != -1) && (entry.mStackIdx >= skipStackCount))
 				str += "-\n";
 			workQueue.pop_back();
 		}

+ 1 - 0
IDEHelper/Profiler.h

@@ -134,6 +134,7 @@ public:
 	BumpAllocator mAlloc;
 	Dictionary<uint, ProfileThreadInfo*> mThreadInfo;
 	Array<uint> mThreadIdList;
+	Dictionary<addr_target, bool> mStackHeadCheckMap;
 
 	ProfileAddrEntrySet mProfileAddrEntrySet;
 	Array<ProfileAddrEntry*> mProfileAddrEntries;