📄 profile.c
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
Module Name: profile.c
Abstract:
This file implements the NK kernel profiler support
Functions:
Notes:
--*/
#define C_ONLY
#include "kernel.h"
#include "romldr.h"
#include "xtime.h"
#define NUM_SYMBOLS 500 // max number of symbols to display in report
#define PROFILEMSG(cond,printf_exp) \
((cond)?(NKDbgPrintfW printf_exp),1:0)
extern BOOL bProfileBuffer; // profiling to buffer flag
// platform routine to disable profiler timer
extern void OEMProfileTimerDisable(void);
// platform routine to enable profiler timer
extern void OEMProfileTimerEnable(DWORD dwUSec);
typedef struct {
DWORD ra; // Interrupt program counter
TOCentry * pte;
} PROFBUFENTRY, *PPROFBUFENTRY;
#define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(PROFBUFENTRY))
//
// The number of bits to shift is a page shift - log2(sizeof(PROFBUFENTRY))
//
#if PAGE_SIZE == 4096
#define PROF_PAGE_SHIFT 9
#elif PAGE_SIZE == 2048
#define PROF_PAGE_SHIFT 8
#elif PAGE_SIZE == 1024
#define PROF_PAGE_SHIFT 7
#else
#error "Unsupported Page Size"
#endif
#define PROF_ENTRY_MASK ((2 << PROF_PAGE_SHIFT) - 1)
PDWORD g_pdwProfileBufStart; // platform profile buffer start
HANDLE g_hProfileBuf;
DWORD dwProfileCount; // total number of profiler calls
DWORD dwPerProcess; // per process profiling flag
void ClearProfileHits(void); // clear all profile counters
#define PROFILE_BUFFER_MAX 4096*1024
#define PAGES_IN_MAX_BUFFER PROFILE_BUFFER_MAX/PAGE_SIZE
PPROFBUFENTRY g_pPBE[PAGES_IN_MAX_BUFFER];
DWORD dwBufNumPages; // Total number of pages
DWORD dwBufNumEntries; // Total number of entries
DWORD dwBufRecDropped; // How many hits were not recorded?
/*
* ProfilerHit - record profiler interrupt call address
*
* Input: ra - interrupt return address
* tocexeptr - pCurProf.oe->tocexeptr at time of interrupt
*
* Attempts to find symbol address for the interrupt call address and increments
* hit counts for module and symbol if found.
*/
void ProfilerSymbolHit(unsigned int ra, TOCentry *tocexeptr) {
TOCentry *tocptr; // table of contents entry pointer
PROFentry *profptr=NULL; // profile entry pointer
SYMentry *symptr; // profiler symbol entry pointer
unsigned int iMod; // module enty in TOC
unsigned int iSym; // symbol counter
SYMentry *pClosestSym; // nearest symbol entry found
if (ra & 0x80000000) { // if high bit set, this is NK
ra&=0xdfffffff; // mask off uncached bit
// profptr-> first entry= NK
profptr= (PROFentry *)pTOC->ulProfileOffset;
// if ra >= pTOC->dllfirst, the hit
// is in a dll in the ROM
}else if ((unsigned int)ra >= (unsigned int)pTOC->dllfirst) {
profptr= (PROFentry *)pTOC->ulProfileOffset+1;
// skip exe's which start at 0x10000
// dll's are stored in descending addresses
while (profptr->ulStartAddr == 0 || profptr->ulStartAddr == 0x10000 || (unsigned int)ra<(unsigned int)profptr->ulStartAddr)
profptr++;
} else { // this is an exe in the ROM, something
// loaded in RAM or unknown
tocptr=(TOCentry *)(pTOC+1); // tocptr-> first entry in ROM
if (tocexeptr < tocptr) { // if tocexeptr at interrupt time < first entry
return; // we don't know what this is
}
// compute module number
iMod= ((DWORD)tocexeptr-(DWORD)tocptr)/sizeof(TOCentry);
if (!iMod) {
return;
}
if (iMod > pTOC->nummods) { // if module > number of modules in ROM
return; // this was loaded in RAM
}
// make profptr point to entry for this module
profptr= (PROFentry *)pTOC->ulProfileOffset;
profptr+=iMod;
}
profptr->ulHits++; // increment hits for this module
if (profptr->ulNumSym) {
// look up the symbol if module found
iSym= profptr->ulNumSym-1;
symptr=(SYMentry*)profptr->ulHitAddress;
pClosestSym = symptr;
// Scan the whole list of symbols, looking for the closest match.
while (iSym) {
// Keep track of the closest symbol found
if (((unsigned int)symptr->ulFuncAddress <= ra)
&& (symptr->ulFuncAddress > pClosestSym->ulFuncAddress)) {
pClosestSym = symptr;
}
iSym--;
symptr++;
}
pClosestSym->ulFuncHits++; // inc hit count for this symbol
}
return;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
ProfilerFreeBuffer(void)
{
DWORD dwMemSize;
BOOL fRet;
dwMemSize = dwBufNumPages * PAGE_SIZE;
fRet = SC_UnlockPages(g_pdwProfileBufStart, dwMemSize);
ASSERT(fRet);
fRet = UnmapViewOfFile(g_pdwProfileBufStart);
ASSERT(fRet);
fRet = CloseHandle(g_hProfileBuf);
ASSERT(fRet);
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
ProfilerAllocBuffer(void)
{
DWORD dwMemRequest;
BOOL fRet;
DWORD i;
//
// Determine half the free RAM.
//
dwMemRequest = (UserKInfo[KINX_PAGEFREE] * PAGE_SIZE) / 2;
//
// Make an upper limit.
//
if (dwMemRequest > PROFILE_BUFFER_MAX) {
dwMemRequest = PROFILE_BUFFER_MAX;
}
dwBufNumPages = dwMemRequest / PAGE_SIZE;
dwBufNumEntries = dwBufNumPages * ENTRIES_PER_PAGE;
//
// Create a shared memory-mapped object
//
g_hProfileBuf = CreateFileMapping((HANDLE) -1, NULL,
PAGE_READWRITE | SEC_COMMIT, 0,
dwMemRequest, NULL);
if (!g_hProfileBuf) {
goto EXIT_FALSE;
}
// Map in the object
g_pdwProfileBufStart = (PDWORD) MapViewOfFile(g_hProfileBuf, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (g_pdwProfileBufStart == NULL) {
CloseHandle(g_hProfileBuf);
goto EXIT_FALSE;
}
//
// Lock the pages and get the physical addresses.
//
fRet = SC_LockPages(g_pdwProfileBufStart, dwMemRequest, (PDWORD) g_pPBE, LOCKFLAG_READ | LOCKFLAG_WRITE);
//
// Convert the physical addresses to statically-mapped virtual addresses
//
for (i = 0; i < dwBufNumPages; i++) {
g_pPBE[i] = Phys2Virt((DWORD) g_pPBE[i]);
}
if (fRet == FALSE) {
UnmapViewOfFile(g_pdwProfileBufStart);
CloseHandle(g_hProfileBuf);
goto EXIT_FALSE;
}
PROFILEMSG(1, (TEXT("ProfileStart() : Allocated %d kB for Profiler Buffer (0x%08X)\r\n"), dwMemRequest >> 10, g_pdwProfileBufStart));
return TRUE;
EXIT_FALSE:
PROFILEMSG(1, (TEXT("ProfileStart() : Error allocating buffer... defaulting to symbol lookup in ISR.\r\n")));
return FALSE;
}
//------------------------------------------------------------------------------
//
// Takes a raw index and looks up the tiered entry pointer.
//
//------------------------------------------------------------------------------
PPROFBUFENTRY
GetEntryPointer(
DWORD dwIndex
)
{
DWORD dwPage, dwEntry;
dwPage = dwIndex >> PROF_PAGE_SHIFT;
dwEntry = dwIndex & PROF_ENTRY_MASK;
return (&(g_pPBE[dwPage][dwEntry]));
}
/*
* ProfilerHit - OEMProfilerISR calls this routine to record profile hit
*
* Input: ra - interrupt return address
*
* if buffer profiling, save ra and pCurProc->oe.tocptr in buffer
* else do symbol lookup in ISR
*/
void ProfilerHit(unsigned int ra) {
PPROFBUFENTRY pEntry;
if (bProfileBuffer) {
//
// If profiling to buffer and these is still room in the buffer
//
if (dwProfileCount < dwBufNumEntries) {
if (ra & 0x80000000) // if high bit set, this is NK
ra &= 0xdfffffff; // mask off uncached bit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -