⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 profiler.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++

Module Name:  

Abstract:  
 This file implements the NK kernel profiler support.

Functions:


Notes: 

--*/
#define C_ONLY
#include "kernel.h"
#include <profiler.h>

#define PROFILEMSG(cond,printf_exp)   \
   ((cond)?(NKDbgPrintfW printf_exp),1:0)

// Turning this zone on can break unbuffered mode, and can break buffered mode
// if the buffer overruns
#define ZONE_UNACCOUNTED 0

#ifdef KCALL_PROFILE
#include "kcall.h"
KPRF_t KPRFInfo[MAX_KCALL_PROFILE];

#ifdef NKPROF
#define KCALL_NextThread    10  // Next thread's entry in array
#endif
#endif // KCALL_PROFILE


int (*PProfileInterrupt)(void) = NULL;  // pointer to profiler ISR, 
                                        // set in platform profiler code

BOOL bProfileTimerRunning = FALSE;      // this variable is used in OEMIdle(), so must be defined even in a non-profiling kernel
const volatile DWORD dwProfileBufferMax = 0;  // Can be overwritten as a FIXUPVAR in config.bib

#ifdef NKPROF

// Used to track what mode the profiler is in
DWORD g_dwProfilerFlags;                // ObjCall, KCall, Buffer, CeLog

// Used for symbol lookup
DWORD g_dwNumROMModules;                // Number of modules in all XIP regions
DWORD g_dwFirstROMDLL;                  // First DLL address over all XIP regions
DWORD g_dwNKIndex;                      // Index (wrt first XIP region) of NK in PROFentry array


#if defined(x86)  // Callstack capture is only supported on x86 right now
// Temp buffer used to hold callstack during profiler hit; not threadsafe but
// all profiler hits should be serialized
#define PROFILER_MAX_STACK_FRAME        50
static BYTE g_ProfilerStackBuffer[PROFILER_MAX_STACK_FRAME*sizeof(CallSnapshot)];
static CONTEXT g_ProfilerContext;
#endif // defined(x86)


// Total number of profiler samples is g_ProfilerState_dwSamplesRecorded + g_ProfilerState_dwSamplesDropped + g_ProfilerState_dwSamplesInIdle
static DWORD g_ProfilerState_dwSamplesRecorded;    // Number of profiler hits that were recorded in the buffer or symbol list
static DWORD g_ProfilerState_dwSamplesDropped;     // Number of profiler hits that were not recorded due to buffer overrun

//------------------------------------------------------------------------------
// System state that is tracked while the profiler is running in Monte Carlo mode.

       DWORD g_ProfilerState_dwInterrupts;         // Number of interrupts that occurred while profiling, including profiler interrupt
       DWORD g_ProfilerState_dwProfilerIntsInTLB;  // Number of TLB misses that had profiler interrupts pending
static DWORD g_ProfilerState_dwSamplesInIdle;      // Number of profiler samples when no threads were scheduled
extern DWORD dwCeLogTLBMiss;                       // Number of TLB misses since boot (always running)
// System state counters that will run when profiling is paused are tracked by 
// recording start values while running and elapsed values during the pause.
static DWORD g_ProfilerState_dwTLBCount;           // Used to count TLB misses while profiling
static DWORD g_ProfilerState_dwTickCount;          // Used to count ticks while profiling

//------------------------------------------------------------------------------


extern void SC_DumpKCallProfile(DWORD bReset);
extern BOOL ProfilerAllocBuffer(void);
extern BOOL ProfilerFreeBuffer(void);


#define NUM_MODULES 200                 // max number of modules to display in report

                                        // 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 // PAGE_SIZE

#define PROF_ENTRY_MASK       ((1 << PROF_PAGE_SHIFT) - 1)

void ClearProfileHits(void);            // clear all profile counters

#define PROFILE_BUFFER_MAX   256*1024*1024  // Absolute max of 256 MB
#define PAGES_IN_MAX_BUFFER    PROFILE_BUFFER_MAX/PAGE_SIZE
#define BLOCKS_PER_SECTION  0x200
#define PAGES_PER_SECTION   BLOCKS_PER_SECTION * PAGES_PER_BLOCK

PPROFBUFENTRY g_pPBE[PAGES_IN_MAX_BUFFER];
HANDLE g_hProfileBuf;                   // Handle of memory-mapped file
PDWORD g_pdwProfileBufStart;            // Pointer to profile buffer (mmfile)
DWORD  g_dwProfileBufNumPages;          // Total number of pages in buffer
DWORD  g_dwProfileBufNumEntries;        // Total number of profiler hits that fit in buffer


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Look up the profiler symbol entry for the given module
PROFentry* GetProfEntryFromTOCEntry(
    TOCentry *tocexeptr
    )
{
    ROMChain_t *pROM = ROMChain;   // Chain of ROM XIP regions
    DWORD       dwModIndex;        // Index of module wrt first XIP region
    TOCentry   *tocptr;            // table of contents entry pointer

    // Look for the module in each successive XIP region, to find its index
    // in the profiler symbol table.
    dwModIndex = 0;
    while (pROM) {
        tocptr = (TOCentry *)(pROM->pTOC+1);  // tocptr-> first entry in ROM
        if ((tocexeptr >= tocptr)
            && (tocexeptr < tocptr + pROM->pTOC->nummods)) {
            // Found it
            dwModIndex += ((DWORD)tocexeptr - (DWORD)tocptr) / sizeof(TOCentry);
            return (PROFentry *)/*pROM->*/pTOC->ulProfileOffset + dwModIndex;  // All ROMs point to same profiler table
        }

        dwModIndex += pROM->pTOC->nummods;
        pROM = pROM->pNext;
    }
    
    // Not found in any XIP region
    return NULL;
}


/*
 *  ProfilerSymbolHit - Lookup profiler interrupt call address and record hit count
 *
 *  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
    )
{
    PROFentry  *profptr;               // profile entry pointer

    if (IsKernelVa(ra)) {
        // The hit is inside NK
        ra &= 0xdfffffff;              // mask off uncached bit
        profptr = (PROFentry *)pTOC->ulProfileOffset + g_dwNKIndex;
    
    } else if (ZeroPtr(ra) >= g_dwFirstROMDLL) {
        // The hit is in a dll in the ROM
        profptr = (PROFentry *)pTOC->ulProfileOffset+1;
        while (!((ZeroPtr(ra) >= ZeroPtr(profptr->ulStartAddr)) && (ZeroPtr(ra) <= ZeroPtr(profptr->ulEndAddr)))) {
            //
            // This is not the module/section for this hit.
            //
            profptr++;
            if (profptr >= (PROFentry *)pTOC->ulProfileOffset + g_dwNumROMModules) {
                PROFILEMSG(ZONE_UNACCOUNTED, (TEXT("Hit dropped (ROM DLL not found), ra=0x%08x tocexeptr=0x%08x\r\n"), ra, tocexeptr));
                return;
            }
        }

    } else {
        // This is an exe in the ROM, something loaded in RAM or unknown
        profptr = GetProfEntryFromTOCEntry(tocexeptr);
        if (!profptr) {
            // Not found in any XIP region
            PROFILEMSG(ZONE_UNACCOUNTED, (TEXT("Hit dropped (module not found), ra=0x%08x tocexeptr=0x%08x\r\n"), ra, tocexeptr));
            return;
        }
    }


    // 
    // We've picked a particular module and section (profptr), now verify the
    // hit is really in bounds.
    //
    if ((ra < profptr->ulStartAddr) || (ra > profptr->ulEndAddr)) {
        // Most likely a 0xDFFFnnnn hit inside PSL entry
        PROFILEMSG(ZONE_UNACCOUNTED, (TEXT("Hit dropped (out of bounds), ra=0x%08x tocexeptr=0x%08x (0x%08x 0x%08x 0x%08x)\r\n"),
                   ra, tocexeptr, profptr, profptr->ulStartAddr, profptr->ulEndAddr));
        return;
    }
    
    profptr->ulHits++;                  // increment hits for this module
    if (profptr->ulNumSym) {
        SYMentry    *symptr;            // profiler symbol entry pointer
        unsigned int iSym;              // symbol counter
        SYMentry    *pClosestSym;       // nearest symbol entry found

        // 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;
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static VOID
DoFreeBuffer(void)
{
    BOOL fRet;
    CALLBACKINFO cbi;

    // Need to use callbacks because the kernel owns the map instead of the app
    
    if (g_pdwProfileBufStart) {
        // UnmapViewOfFile(g_pdwProfileBufStart);
        cbi.hProc = ProcArray[0].hProc;
        cbi.pfn = (FARPROC)UnmapViewOfFile;
        cbi.pvArg0 = g_pdwProfileBufStart;
        fRet = (BOOL)PerformCallBack(&cbi);
        ASSERT(fRet);

        g_pdwProfileBufStart = NULL;
    }
    
    if (g_hProfileBuf) {
        // CloseHandle(g_hProfileBuf);
        cbi.hProc = ProcArray[0].hProc;
        cbi.pfn = (FARPROC)CloseHandle;
        cbi.pvArg0 = g_hProfileBuf;
        fRet = (BOOL)PerformCallBack(&cbi);
        ASSERT(fRet);

        g_hProfileBuf = NULL;
    }
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
ProfilerFreeBuffer(void)
{
    DWORD dwMemSize;
    BOOL  fRet;
    
    if (g_pdwProfileBufStart) {
        dwMemSize = g_dwProfileBufNumPages * PAGE_SIZE;
        fRet = SC_UnlockPages(g_pdwProfileBufStart, dwMemSize);
        ASSERT(fRet);
    }
    
    DoFreeBuffer();

    return TRUE;
}


#define SECTION_SIZE (1 << VA_SECTION)

//------------------------------------------------------------------------------
// Lock a large block with iterative calls to LockPages
//------------------------------------------------------------------------------
BOOL 
ProfLockPages(
    LPVOID lpvAddress,
    DWORD cbSize,
    PDWORD pPFNs,
    int fOptions
    ) 
{
    BOOL fRet = FALSE;
    DWORD section;
    DWORD dwNumSections = (cbSize + SECTION_SIZE - 1) >> VA_SECTION;

    for (section = 0; section < dwNumSections; section++) {
        fRet = SC_LockPages(lpvAddress, cbSize < SECTION_SIZE ? cbSize : SECTION_SIZE, pPFNs, fOptions);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -