📄 profiler.c
字号:
ProfilerSymbolHit(pEntry->ra, pEntry->pte);
}
PROFILEMSG(1, (TEXT("\r\n")));
}
//
// Report header contains lots of interesting goodies
//
ProfilerReportHeader();
// Don't print anything else if the only recorded samples were in idle.
if (!g_ProfilerState_dwSamplesRecorded) {
return;
}
//
// Display hits by module and count number of symbols hit
//
dwModCount = 0;
dwSymCount = 0;
// Insert the modules with nonzero hits into the list
dwModIndex = 0;
pROM = ROMChain;
pProf = (PROFentry *)/*pROM->*/pTOC->ulProfileOffset; // All ROMs point to same profiler table
while (pROM) {
dwNumModules = pROM->pTOC->nummods;
for (loop = 0; loop < dwNumModules; loop++) {
if (pProf->ulHits) {
if (dwModCount < NUM_MODULES-1) { // -1 to leave room for idle
dwHits[dwModCount] = pProf->ulHits;
dwMods[dwModCount] = dwModIndex + loop; // index wrt first XIP region
dwModCount++;
} else {
PROFILEMSG(ZONE_UNACCOUNTED, (TEXT("Module %u dropped, not all modules with hits will be printed!\r\n"), dwModIndex + loop));
}
}
pProf++;
}
dwModIndex += dwNumModules;
pROM = pROM->pNext;
}
// dwModCount is now the count of modules with nonzero hits
// Count idle as a "module"
if (g_ProfilerState_dwSamplesInIdle) {
dwHits[dwModCount] = g_ProfilerState_dwSamplesInIdle;
dwMods[dwModCount] = IDLE_SIGNATURE;
dwModCount++;
}
// Sort the list into decreasing order (bubble sort)
for (loop = 1; loop < dwModCount; loop++) {
for (loop2 = dwModCount-1; loop2 >= loop; loop2--) {
if (dwHits[loop2-1] < dwHits[loop2]) {
dwTemp = dwHits[loop2-1];
dwHits[loop2-1] = dwHits[loop2];
dwHits[loop2] = dwTemp;
dwTemp = dwMods[loop2-1];
dwMods[loop2-1] = dwMods[loop2];
dwMods[loop2] = dwTemp;
}
}
}
PROFILEMSG(1, (TEXT("\r\nMODULES: (Does not include dropped samples!)\r\n\r\n")));
PROFILEMSG(1, (TEXT("Module Hits Percent\r\n")));
PROFILEMSG(1, (TEXT("------------ ---------- -------\r\n")));
// Print the sorted list
dwModIndex = 0; // index wrt current XIP region
dwCount = 0; // # of symbol hits that were successfully attributed to a module
for (loop = 0; loop < dwModCount; loop++) {
dwModIndex = dwMods[loop];
if (dwModIndex != IDLE_SIGNATURE) {
// Figure out which XIP region the module was in
pROM = ROMChain;
while ((dwModIndex >= pROM->pTOC->nummods) && pROM) {
dwModIndex -= pROM->pTOC->nummods;
pROM = pROM->pNext;
}
DEBUGCHK(pROM);
if (pROM) {
tocptr = ((TOCentry *)(pROM->pTOC+1)) + dwModIndex;
pProf = ((PROFentry *)/*pROM->*/pTOC->ulProfileOffset) + dwMods[loop]; // All ROMs point to same profiler table
DEBUGCHK(pProf->ulHits && (pProf->ulHits == dwHits[loop]));
if (pProf->ulHits) {
// Display module name, hits, percentage
ulPercent = pProf->ulHits;
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("%-12a %10lu %5lu.%1d\r\n"),
tocptr->lpszFileName, pProf->ulHits, ulPercent / 10, ulPercent % 10));
dwCount += pProf->ulHits;
pSym = (SYMentry *)pProf->ulHitAddress;
// While we're here walking the TOC, count the nonzero symbols
for (loop2 = 0; loop2 < pProf->ulNumSym; loop2++) {
if (pSym->ulFuncHits) {
dwSymCount++;
}
pSym++;
}
}
}
} else {
// False "module" representing idle
ulPercent = dwHits[loop];
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("IDLE %10lu %5lu.%1d\r\n"),
dwHits[loop], ulPercent / 10, ulPercent % 10));
}
}
// dwSymCount is now the count of symbols with nonzero hits
if (g_ProfilerState_dwSamplesRecorded - dwCount) {
ulPercent = g_ProfilerState_dwSamplesRecorded - dwCount;
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("%-12a %10lu %5lu.%1d\r\n"),
"UNKNOWN", g_ProfilerState_dwSamplesRecorded - dwCount, ulPercent/10, ulPercent%10));
}
//
// Display hits by symbol
//
if (!dwSymCount) {
PROFILEMSG(1, (TEXT("No symbols found.\r\n")));
goto profile_exit;
}
// Allocate memory for sorting
pHits = (SortSYMentry *)VirtualAlloc(NULL, (dwSymCount+1)*sizeof(SortSYMentry), // +1 to hold idle count
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pHits == NULL) {
PROFILEMSG(1, (TEXT("ProfileStop: Sort memory allocation size %u failed.\r\n"), (dwSymCount+1)*sizeof(SYMentry)));
goto profile_exit;
}
// Insert the symbols with nonzero hits into the list
dwCount = dwSymCount; // Temp holder to make sure we don't exceed this number
dwSymCount = 0;
dwModIndex = 0;
pROM = ROMChain;
pProf = (PROFentry *)/*pROM->*/pTOC->ulProfileOffset; // All ROMs point to same profiler table
while (pROM) {
dwNumModules = pROM->pTOC->nummods;
for (loop = 0; loop < dwNumModules; loop++) {
if (pProf->ulHits) {
pSym = (SYMentry *)pProf->ulHitAddress;
for (loop2 = 0; loop2 < pProf->ulNumSym; loop2++) {
if (pSym->ulFuncHits && (dwSymCount < dwCount)) {
pHits[dwSymCount].ulFuncAddress = pSym->ulFuncAddress;
pHits[dwSymCount].ulFuncHits = pSym->ulFuncHits;
pHits[dwSymCount].ulModuleIndex = dwModIndex + loop; // index wrt first XIP region
dwSymCount++;
}
pSym++;
}
}
pProf++;
}
dwModIndex += dwNumModules;
pROM = pROM->pNext;
}
// dwSymCount is now the count of symbols with nonzero hits
// Count idle as a "symbol"
if (g_ProfilerState_dwSamplesInIdle) {
pHits[dwSymCount].ulFuncAddress = 0;
pHits[dwSymCount].ulFuncHits = g_ProfilerState_dwSamplesInIdle;
pHits[dwSymCount].ulModuleIndex = IDLE_SIGNATURE;
dwSymCount++;
}
// Sort the list into decreasing order (bubble sort)
for (loop = 1; loop < dwSymCount; loop++) {
for (loop2 = dwSymCount-1; loop2 >= loop; loop2--) {
if ((unsigned int)pHits[loop2-1].ulFuncHits < (unsigned int)pHits[loop2].ulFuncHits) {
symTemp.ulFuncHits = pHits[loop2-1].ulFuncHits;
symTemp.ulFuncAddress = pHits[loop2-1].ulFuncAddress;
symTemp.ulModuleIndex = pHits[loop2-1].ulModuleIndex;
pHits[loop2-1].ulFuncHits = pHits[loop2].ulFuncHits;
pHits[loop2-1].ulFuncAddress = pHits[loop2].ulFuncAddress;
pHits[loop2-1].ulModuleIndex = pHits[loop2].ulModuleIndex;
pHits[loop2].ulFuncHits = symTemp.ulFuncHits;
pHits[loop2].ulFuncAddress = symTemp.ulFuncAddress;
pHits[loop2].ulModuleIndex = symTemp.ulModuleIndex;
}
}
}
PROFILEMSG(1, (TEXT("\r\nSYMBOLS: (Does not include dropped samples!)\r\n\r\n")));
PROFILEMSG(1, (TEXT("Hits Percent Address Module Routine\r\n")));
PROFILEMSG(1, (TEXT("---------- ------- -------- ------------:---------------------\r\n")));
// Print the sorted list
dwCount = 0; // # of hits that were successfully attributed to a symbol
for (loop = 0; loop < dwSymCount; loop++) {
dwModIndex = pHits[loop].ulModuleIndex;
if (dwModIndex != IDLE_SIGNATURE) {
// Figure out which XIP region and module the symbol was in
pROM = ROMChain;
while ((dwModIndex >= pROM->pTOC->nummods) && pROM) {
dwModIndex -= pROM->pTOC->nummods;
pROM = pROM->pNext;
}
DEBUGCHK(pROM);
if (pROM) {
pProf = (PROFentry *)/*pROM->*/pTOC->ulProfileOffset + pHits[loop].ulModuleIndex; // All ROMs point to same profiler table
tocptr = (TOCentry *)(pROM->pTOC+1) + dwModIndex;
DEBUGCHK(pProf->ulHits);
// Find profile entry for this symbol
pSym = (SYMentry *)pProf->ulHitAddress;
for (loop2 = 0; loop2 < pProf->ulNumSym; loop2++) {
if ((pSym->ulFuncAddress == pHits[loop].ulFuncAddress)
&& (pSym->ulFuncHits == pHits[loop].ulFuncHits)) {
ulPercent = pHits[loop].ulFuncHits;
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("%10d %5d.%1d %8.8lx %-12a:%a\r\n"), pHits[loop].ulFuncHits,
ulPercent / 10, ulPercent % 10, pHits[loop].ulFuncAddress, tocptr->lpszFileName,
GetSymbol((LPBYTE)pProf->ulSymAddress, loop2)));
dwCount += pHits[loop].ulFuncHits;
goto next_sym;
}
pSym++;
}
}
next_sym:
;
} else {
// False "symbol" representing idle
ulPercent = pHits[loop].ulFuncHits;
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("%10d %5d.%1d -------- ------------:IDLE\r\n"),
pHits[loop].ulFuncHits, ulPercent / 10, ulPercent % 10));
}
}
// Print hits in unlisted symbols. These unlisted hits are hits in modules
// that are not in ROM.
if (dwCount != g_ProfilerState_dwSamplesRecorded) {
ulPercent = g_ProfilerState_dwSamplesRecorded - dwCount;
ulPercent *= 1000;
ulPercent /= dwRecordedSamples;
PROFILEMSG(1, (TEXT("%10d %5d.%1d :<UNACCOUNTED FOR>\r\n"),
g_ProfilerState_dwSamplesRecorded - dwCount, ulPercent / 10, ulPercent % 10));
}
profile_exit:
if (pHits)
VirtualFree(pHits, 0, MEM_DECOMMIT | MEM_FREE);
return;
}
//------------------------------------------------------------------------------
// This is a dummy function for the profiler
//------------------------------------------------------------------------------
void IDLE_STATE()
{
//
// Force the function to be non-empty so the hit engine can find it.
//
static volatile DWORD dwVal;
dwVal++;
}
#if defined(x86) // Callstack capture is only supported on x86 right now
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Called by ProfilerHitEx when the profiler is using PROFILE_CELOG and
// PROFILE_CALLSTACK. Logs the call stack of the interrupted thread to CeLog.
static BOOL LogCallStack()
{
DWORD dwLastError;
DWORD dwNumFrames, dwSkip, dwFlags;
// NKGetThreadCallStack may overwrite thread LastError
dwLastError = KGetLastError(pCurThread);
KSetLastError(pCurThread, 0);
// Get context for the thread that was interrupted
g_ProfilerContext.Ebp = pCurThread->ctx.TcxEbp;
g_ProfilerContext.Eip = pCurThread->ctx.TcxEip;
if (g_dwProfilerFlags & PROFILE_CALLSTACK_INPROC) {
dwFlags = (STACKSNAP_INPROC_ONLY | STACKSNAP_FAIL_IF_INCOMPLETE);
} else {
dwFlags = STACKSNAP_FAIL_IF_INCOMPLETE;
}
// Iterate if the buffer is not large enough to hold the whole stack
dwSkip = 0;
do {
// Use the context to get the callstack
dwNumFrames = NKGetThreadCallStack(pCurThread, PROFILER_MAX_STACK_FRAME,
g_ProfilerStackBuffer, dwFlags,
dwSkip, &g_ProfilerContext);
// Log the callstack to CeLog
if (dwNumFrames) {
g_pfnCeLogData(FALSE, CELID_CALLSTACK, g_ProfilerStackBuffer,
dwNumFrames * sizeof(CallSnapshot),
0, CELZONE_PROFILER, 0, FALSE);
dwSkip += dwNumFrames;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -