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:
parent
68bc8976b8
commit
398cb0c7ad
5 changed files with 147 additions and 45 deletions
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(®isters);
|
mDebugger->PopulateRegisters(®isters);
|
||||||
|
|
||||||
|
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(®isters, stackIdx == 0))
|
if (!mDebugger->RollBackStackFrame(®isters, 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue