1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Improved profiler - better filtering, show 'hot' paths

This commit is contained in:
Brian Fiete 2023-03-14 09:32:01 -07:00
parent 68bc8976b8
commit 398cb0c7ad
5 changed files with 147 additions and 45 deletions

View file

@ -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) public void Show(int32 threadId, StringView threadName)
{ {
mTickCreated = Utils.GetTickCount(); mTickCreated = Utils.GetTickCount();
@ -449,6 +462,8 @@ namespace IDE.ui
itemStack.Add(curItem); itemStack.Add(curItem);
curItem = newItem; curItem = newItem;
} }
OpenHot(mListView.GetRoot(), (.)(totalSamples * 0.05f));
} }
public void Add(DbgProfiler profiler) public void Add(DbgProfiler profiler)

View file

@ -273,6 +273,7 @@ String DebugTarget::UnloadDyn(addr_target imageBase)
} }
} }
mFindDbgModuleCache.Clear();
mDbgModules.RemoveAt(i); mDbgModules.RemoveAt(i);
bool success = mDbgModuleMap.Remove(dwarf->mId); bool success = mDbgModuleMap.Remove(dwarf->mId);
BF_ASSERT_REL(success); BF_ASSERT_REL(success);
@ -316,6 +317,7 @@ void DebugTarget::CleanupHotHeap()
DbgModule* dbgModule = mDbgModules[dwarfIdx]; DbgModule* dbgModule = mDbgModules[dwarfIdx];
if (dbgModule->mDeleting) if (dbgModule->mDeleting)
{ {
mFindDbgModuleCache.Clear();
mDbgModules.RemoveAt(dwarfIdx); mDbgModules.RemoveAt(dwarfIdx);
bool success = mDbgModuleMap.Remove(dbgModule->mId); bool success = mDbgModuleMap.Remove(dbgModule->mId);
BF_ASSERT_REL(success); BF_ASSERT_REL(success);
@ -932,6 +934,7 @@ void DebugTarget::GetCompilerSettings()
void DebugTarget::AddDbgModule(DbgModule* dbgModule) void DebugTarget::AddDbgModule(DbgModule* dbgModule)
{ {
dbgModule->mId = ++mCurModuleId; dbgModule->mId = ++mCurModuleId;
mFindDbgModuleCache.Clear();
mDbgModules.Add(dbgModule); mDbgModules.Add(dbgModule);
bool success = mDbgModuleMap.TryAdd(dbgModule->mId, dbgModule); bool success = mDbgModuleMap.TryAdd(dbgModule->mId, dbgModule);
BF_ASSERT_REL(success); 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) 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 dwarf->mOrigImageData->Read(address, data, size);
}
//return dbgModule->mOrigImageData + (address - dbgModule->mImageBase);
} }
return DbgMemoryFlags_None; return DbgMemoryFlags_None;
} }
bool DebugTarget::DecodeInstruction(addr_target address, CPUInst* inst) 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; return false;
} }
DbgBreakKind DebugTarget::GetDbgBreakKind(addr_target address, CPURegisters* registers, intptr_target* objAddr) 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; return DbgBreakKind_None;
} }
DbgModule* DebugTarget::FindDbgModuleForAddress(addr_target address) 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)) for (auto dwarf : mDbgModules)
return dwarf; {
if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize))
*valuePtr = dwarf;
}
} }
return NULL; return *valuePtr;
} }
DbgModule* DebugTarget::GetMainDbgModule() DbgModule* DebugTarget::GetMainDbgModule()

View file

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

View file

@ -343,10 +343,6 @@ void DbgProfiler::ThreadProc()
bool isThreadIdle = idleThreadSet.Contains(thread->mThreadId); bool isThreadIdle = idleThreadSet.Contains(thread->mThreadId);
profileThreadInfo->mTotalSamples += curSampleCount;
if (isThreadIdle)
profileThreadInfo->mTotalIdleSamples += curSampleCount;
mDebugger->mActiveThread = thread; mDebugger->mActiveThread = thread;
::SuspendThread(thread->mHThread); ::SuspendThread(thread->mHThread);
@ -354,14 +350,38 @@ void DbgProfiler::ThreadProc()
CPURegisters registers; CPURegisters registers;
mDebugger->PopulateRegisters(&registers); mDebugger->PopulateRegisters(&registers);
addr_target prevPC = 0;
bool traceIsValid = true;
int stackSize = 0; int stackSize = 0;
for (int stackIdx = 0; stackIdx < maxStackTrace; stackIdx++) for (int stackIdx = 0; stackIdx < maxStackTrace; stackIdx++)
{ {
auto pc = registers.GetPC(); 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; break;
} }
prevPC = pc;
auto lastDbgModule = mDebugger->mDebugTarget->FindDbgModuleForAddress(pc);
if (lastDbgModule == NULL)
{
traceIsValid = false;
break;
}
stackTrace[stackSize++] = pc; stackTrace[stackSize++] = pc;
auto prevSP = registers.GetSP(); auto prevSP = registers.GetSP();
if (!mDebugger->RollBackStackFrame(&registers, stackIdx == 0)) if (!mDebugger->RollBackStackFrame(&registers, stackIdx == 0))
@ -369,30 +389,38 @@ void DbgProfiler::ThreadProc()
if (registers.GetSP() <= prevSP) if (registers.GetSP() <= prevSP)
{ {
// SP went the wrong direction, stop rolling back // SP went the wrong direction, stop rolling back
traceIsValid = false;
break; break;
} }
} }
ProfileAddrEntry* insertedProfileEntry = AddToSet(mProfileAddrEntrySet, stackTrace, stackSize); if (traceIsValid)
if (insertedProfileEntry->mEntryIdx == -1)
{ {
insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1' profileThreadInfo->mTotalSamples += curSampleCount;
mPendingProfileEntries.Add(*insertedProfileEntry);
}
for (int i = 0; i < curSampleCount; i++)
{
int entryIdx = insertedProfileEntry->mEntryIdx;
if (isThreadIdle) if (isThreadIdle)
entryIdx = -entryIdx; profileThreadInfo->mTotalIdleSamples += curSampleCount;
profileThreadInfo->mProfileAddrEntries.push_back(entryIdx);
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); ::ResumeThread(thread->mHThread);
int elapsedTime = timeGetTime() - startTick;
mTotalActiveSamplingMS += elapsedTime;
mDebugger->mActiveThread = NULL; mDebugger->mActiveThread = NULL;
threadIdx++; threadIdx++;
@ -479,6 +507,7 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
int mStackIdx; int mStackIdx;
}; };
Array<_QueuedEntry> workQueue; Array<_QueuedEntry> workQueue;
int skipStackCount = 0;
auto _AddEntries = [&](int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc) 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; int childSampleCount = 0;
// First arrange list so we only contain items that match 'findProc' // First arrange list so we only contain items that match 'findProc'
if (stackIdx != -1) if (stackIdx >= skipStackCount)
{ {
for (int idx = rangeStart; idx < rangeEnd; idx++) for (int idx = rangeStart; idx < rangeEnd; idx++)
{ {
@ -551,6 +580,64 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
}; };
_AddEntries(rangeStart, rangeEnd, stackIdx, findProc); _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()) while (!workQueue.IsEmpty())
{ {
auto& entry = workQueue.back(); auto& entry = workQueue.back();
@ -574,7 +661,7 @@ void DbgProfiler::AddEntries(String& str, Array<ProfileProcEntry*>& procEntries,
if (!addedChild) if (!addedChild)
{ {
if (entry.mStackIdx != -1) if ((entry.mStackIdx != -1) && (entry.mStackIdx >= skipStackCount))
str += "-\n"; str += "-\n";
workQueue.pop_back(); workQueue.pop_back();
} }

View file

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