diff --git a/IDE/src/ui/ProfilePanel.bf b/IDE/src/ui/ProfilePanel.bf index 033c553e..fab785f0 100644 --- a/IDE/src/ui/ProfilePanel.bf +++ b/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) diff --git a/IDEHelper/DebugTarget.cpp b/IDEHelper/DebugTarget.cpp index 335f99f4..978aa87e 100644 --- a/IDEHelper/DebugTarget.cpp +++ b/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() diff --git a/IDEHelper/DebugTarget.h b/IDEHelper/DebugTarget.h index 5adfdb6f..8716583a 100644 --- a/IDEHelper/DebugTarget.h +++ b/IDEHelper/DebugTarget.h @@ -42,6 +42,7 @@ public: DbgModule* mTargetBinary; Array mDbgModules; Dictionary mDbgModuleMap; + Dictionary mFindDbgModuleCache; // Addresses are all 64k multiples HashSet mPendingSrcFileRehup; // Waiting to remove old/invalid line info BumpAllocator mAlloc; diff --git a/IDEHelper/Profiler.cpp b/IDEHelper/Profiler.cpp index 85d43a3a..a5c3a8f6 100644 --- a/IDEHelper/Profiler.cpp +++ b/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(®isters); + 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(®isters, 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) + if (traceIsValid) { - insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1' - mPendingProfileEntries.Add(*insertedProfileEntry); - } - - for (int i = 0; i < curSampleCount; i++) - { - 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& 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& 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& 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& procEntries, if (!addedChild) { - if (entry.mStackIdx != -1) + if ((entry.mStackIdx != -1) && (entry.mStackIdx >= skipStackCount)) str += "-\n"; workQueue.pop_back(); } diff --git a/IDEHelper/Profiler.h b/IDEHelper/Profiler.h index e567962d..ef165e5c 100644 --- a/IDEHelper/Profiler.h +++ b/IDEHelper/Profiler.h @@ -134,6 +134,7 @@ public: BumpAllocator mAlloc; Dictionary mThreadInfo; Array mThreadIdList; + Dictionary mStackHeadCheckMap; ProfileAddrEntrySet mProfileAddrEntrySet; Array mProfileAddrEntries;