📄 profiler.c
字号:
g_dwProfilerFlags |= PROFILE_CELOG;
#if defined(x86) // Callstack capture is only supported on x86 right now
// CALLSTACK flag can only be used with CeLog & Monte Carlo right now
if ((pControl->dwOptions & PROFILE_CALLSTACK)
&& !(pControl->dwOptions & (PROFILE_OBJCALL | PROFILE_KCALL))) {
g_dwProfilerFlags |= PROFILE_CALLSTACK;
// INPROC flag modifies the callstack flag
if (pControl->dwOptions & PROFILE_CALLSTACK_INPROC) {
g_dwProfilerFlags |= PROFILE_CALLSTACK_INPROC;
}
}
#endif // defined(x86)
} else if (pControl->dwOptions & PROFILE_BUFFER) {
// Attempt to alloc the buffer; skip buffering if the alloc fails
if (ProfilerAllocBuffer()) {
g_dwProfilerFlags |= PROFILE_BUFFER;
}
}
// Determine which type of data is being gathered
if (pControl->dwOptions & PROFILE_OEMDEFINED) {
// OEM-specific profiler
if ((pControl->dwOptions & (PROFILE_OBJCALL | PROFILE_KCALL))
|| !OEMIoControl(IOCTL_HAL_OEM_PROFILER,
(ProfilerControl*) pControl, // non-const
sizeof(ProfilerControl) + pControl->OEM.dwControlSize,
NULL, 0, NULL)) {
PROFILEMSG(1, (TEXT("Kernel Profiler: OEM Profiler start failed!\r\n")));
SetLastError(ERROR_NOT_SUPPORTED);
// Restore CeLog state
if (IsCeLogStatus(CELOGSTATUS_ENABLED_ANY)) {
SC_CeLogSetZones(dwCeLogZoneUser, dwCeLogZoneCE, dwCeLogZoneProcess);
CeLogEnableStatus(CELOGSTATUS_ENABLED_GENERAL);
}
g_dwProfilerFlags = 0;
bStart = FALSE;
return;
}
g_dwProfilerFlags |= PROFILE_OEMDEFINED;
} else if (pControl->dwOptions & PROFILE_OBJCALL) {
// Object call profiling
g_dwProfilerFlags |= PROFILE_OBJCALL;
} else if (pControl->dwOptions & PROFILE_KCALL) {
// Kernel call profiling
g_dwProfilerFlags |= PROFILE_KCALL;
} else {
// Monte Carlo profiling
// Initialize the system state counters that will not run
// whenever profiling is paused
g_ProfilerState_dwInterrupts = 0;
g_ProfilerState_dwProfilerIntsInTLB = 0;
if (pControl->dwOptions & PROFILE_STARTPAUSED) {
--scPauseContinueCalls;
// Set elapsed values for system counters that will
// continue to run whenever profiling is paused
// (paused now)
g_ProfilerState_dwTLBCount = 0;
g_ProfilerState_dwTickCount = 0;
} else {
// Set start values for system counters that will
// continue to run whenever profiling is paused
// (running now)
g_ProfilerState_dwTLBCount = dwCeLogTLBMiss;
g_ProfilerState_dwTickCount = GetTickCount();
// Start profiler timer
OEMProfileTimerEnable(pControl->Kernel.dwUSecInterval);
bProfileTimerRunning = TRUE;
}
}
}
} else if (pControl->dwOptions & PROFILE_STOP) {
// ProfileStop()
if (bProfileTimerRunning) {
OEMProfileTimerDisable(); // disable profiler timer
bProfileTimerRunning = FALSE;
// Set system state counters to paused (elapsed) values
g_ProfilerState_dwTLBCount = dwCeLogTLBMiss - g_ProfilerState_dwTLBCount;
g_ProfilerState_dwTickCount = GetTickCount() - g_ProfilerState_dwTickCount;
} else if (g_dwProfilerFlags & PROFILE_OEMDEFINED) {
// OEM-specific profiler
ProfilerControl control;
control.dwVersion = 1;
control.dwOptions = PROFILE_STOP | PROFILE_OEMDEFINED;
control.dwReserved = 0;
control.OEM.dwControlSize = 0; // no OEM struct passed to stop profiler
control.OEM.dwProcessorType = 0; OEMIoControl(IOCTL_HAL_OEM_PROFILER, &control,
sizeof(ProfilerControl), NULL, 0, NULL);
g_dwProfilerFlags &= ~PROFILE_OEMDEFINED;
}
scPauseContinueCalls = 0;
if (g_dwProfilerFlags & PROFILE_CELOG) {
// Resume general logging
if (IsCeLogStatus(CELOGSTATUS_ENABLED_ANY)) {
// Log the stop event
g_pfnCeLogData(TRUE, CELID_PROFILER_STOP, NULL, 0, 0,
CELZONE_PROFILER, 0, FALSE);
// Restore the original zone settings
SC_CeLogSetZones(dwCeLogZoneUser, dwCeLogZoneCE, dwCeLogZoneProcess);
// Restore CeLog general logging
CeLogEnableStatus(CELOGSTATUS_ENABLED_GENERAL);
}
g_dwProfilerFlags &= ~(PROFILE_CELOG | PROFILE_CALLSTACK | PROFILE_CALLSTACK_INPROC);
// The Monte Carlo report header can still be printed, though
// the full report must be generated by desktop tools that parse
// the log
PROFILEMSG(1, (TEXT("Profiler data written to CeLog.\r\n")));
if (!(g_dwProfilerFlags & PROFILE_OBJCALL)) {
ProfilerReportHeader();
PROFILEMSG(1, (TEXT("\r\nMODULES: Written to CeLog\r\n")));
PROFILEMSG(1, (TEXT("\r\nSYMBOLS: Written to CeLog\r\n")));
}
} else if (g_dwProfilerFlags & PROFILE_KCALL) {
// Dump the KCall profile data
SC_DumpKCallProfile(TRUE);
g_dwProfilerFlags &= ~PROFILE_KCALL;
} else {
// Display profile hit report
ProfilerReport();
}
if (g_dwProfilerFlags & PROFILE_BUFFER) {
ProfilerFreeBuffer();
g_dwProfilerFlags &= ~PROFILE_BUFFER;
}
g_dwProfilerFlags = 0;
bStart = FALSE;
} else if (pControl->dwOptions & PROFILE_OEM_QUERY) {
// ProfileCaptureStatus()
// Insert the current state of the OEM-defined profiler into the
// CeLog data stream
BYTE Buf[1024]; DWORD dwBufSize = 1024;
DWORD dwBufUsed;
// Only supported via CeLog for now
if ((g_dwProfilerFlags & PROFILE_OEMDEFINED)
&& (g_dwProfilerFlags & PROFILE_CELOG)
&& IsCeLogStatus(CELOGSTATUS_ENABLED_PROFILE)) {
ProfilerControl control;
control.dwVersion = 1;
control.dwOptions = PROFILE_OEM_QUERY | PROFILE_OEMDEFINED;
control.dwReserved = 0;
control.OEM.dwControlSize = 0; // no OEM struct being passed here
control.OEM.dwProcessorType = 0; if (OEMIoControl(IOCTL_HAL_OEM_PROFILER, &control,
sizeof(ProfilerControl), Buf, dwBufSize,
&dwBufUsed)) {
// Clear the RA since it does not apply when the data is just being queried
((OEMProfilerData*)Buf)->ra = 0;
// Now that we have the data, send it to CeLog
g_pfnCeLogData(FALSE, CELID_OEMPROFILER_HIT, Buf, dwBufUsed, 0,
CELZONE_PROFILER, 0, FALSE);
}
}
}
}
#endif // NKPROF
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
SC_TurnOnProfiling(void)
{
DEBUGMSG(ZONE_ENTRY,(L"SC_TurnOnProfiling entry\r\n"));
SET_PROFILE(pCurThread);
#if SHx
ProfileFlag = 1; // profile status
#endif
DEBUGMSG(ZONE_ENTRY,(L"SC_TurnOnProfiling exit\r\n"));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
SC_TurnOffProfiling(void)
{
DEBUGMSG(ZONE_ENTRY,(L"SC_TurnOffProfiling entry\r\n"));
CLEAR_PROFILE(pCurThread);
#if SHx
ProfileFlag = 0; // profile status
#endif
DEBUGMSG(ZONE_ENTRY,(L"SC_TurnOffProfiling exit\r\n"));
}
#ifdef KCALL_PROFILE
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
GetKCallProfile(
KPRF_t *pkprf,
int loop,
BOOL bReset
)
{
KCALLPROFON(26);
memcpy(pkprf,&KPRFInfo[loop],sizeof(KPRF_t));
if (bReset && (loop != 26))
memset(&KPRFInfo[loop],0,sizeof(KPRF_t));
KCALLPROFOFF(26);
if (bReset && (loop == 26))
memset(&KPRFInfo[loop],0,sizeof(KPRF_t));
}
#endif // KCALL_PROFILE
//
// Convert the number of ticks to microseconds.
//
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static DWORD
local_ScaleDown(
DWORD dwIn
)
{
LARGE_INTEGER liFreq;
SC_QueryPerformanceFrequency(&liFreq);
return ((DWORD) (((__int64) dwIn * 1000000) / liFreq.LowPart));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
SC_DumpKCallProfile(
DWORD bReset
)
{
#ifdef KCALL_PROFILE
extern DWORD local_ScaleDown(DWORD);
int loop;
KPRF_t kprf;
DWORD min = 0xffffffff, max = 0, total = 0, calls = 0;
TRUSTED_API_VOID (L"SC_DumpKCallProfile");
#ifdef NKPROF
calls = local_ScaleDown(1000);
PROFILEMSG(1, (L"Resolution: %d.%3.3d usec per tick\r\n", calls / 1000, calls % 1000));
KCall((PKFN)GetKCallProfile, &kprf, KCALL_NextThread, bReset);
PROFILEMSG(1, (L"NextThread: Calls=%u Min=%u Max=%u Ave=%u\r\n",
kprf.hits, local_ScaleDown(kprf.min),
local_ScaleDown(kprf.max), kprf.hits ? local_ScaleDown(kprf.total) / kprf.hits : 0));
for (loop = 0; loop < MAX_KCALL_PROFILE; loop++) {
if (loop != KCALL_NextThread) {
KCall((PKFN)GetKCallProfile, &kprf, loop, bReset);
if (kprf.max > max)
max = kprf.max;
total += kprf.total;
calls += kprf.hits;
}
}
PROFILEMSG(1, (L"Other Kernel calls: Max=%u Avg=%u\r\n", max, calls ? local_ScaleDown(total) / calls : 0));
#else // NKPROF
calls = local_ScaleDown(1000);
PROFILEMSG(1, (L"Resolution: %d.%3.3d usec per tick\r\n", calls / 1000, calls % 1000));
PROFILEMSG(1, (L"Index Entrypoint Calls uSecs Min Max Ave\r\n"));
for (loop = 0; loop < MAX_KCALL_PROFILE; loop++) {
KCall((PKFN)GetKCallProfile, &kprf, loop, bReset);
PROFILEMSG(1, (L"%5d %-30s %8d %10d %6d %6d %6d\r\n",
loop, pKCallName[loop], kprf.hits, local_ScaleDown(kprf.total), local_ScaleDown(kprf.min),
local_ScaleDown(kprf.max), kprf.hits ? local_ScaleDown(kprf.total) / kprf.hits : 0));
if (kprf.min && (kprf.min < min))
min = kprf.min;
if (kprf.max > max)
max = kprf.max;
calls += kprf.hits;
total += kprf.total;
}
PROFILEMSG(1, (L"\r\n"));
PROFILEMSG(1, (L" %-30s %8d %10d %6d %6d %6d\r\n",
L"Summary", calls, local_ScaleDown(total), local_ScaleDown(min), local_ScaleDown(max),calls ? local_ScaleDown(total) / calls : 0));
#endif // NKPROF
#endif // KCALL_PROFILE
}
#ifdef NKPROF // TOC info available only in profiling builds
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//
// Functions used to look up symbol information included in the TOC in
// profiling builds.
//
// GetT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -