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

📄 profiler.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File:  profiler.c
//
//  This file contains implementation of profiler module suitable for MIPS
//  CPU/SoC with count/compare CP0 timer. It probably can be used on most 
//  if not all MIPS platforms for kernel profiling.
//
#include <windows.h>
#include <nkintr.h>
#include <oal.h>
#include <oal_intr_mips.h>

//------------------------------------------------------------------------------
// Local Variables 

static struct {
    BOOL enabled;                               // is profiler active?
    UINT32 countsPerHit;                        // counts per profiler interrupt
    UINT32 counts;                              // counts in system tick
    UINT32 maxPeriodMSec;                       // saved maximal timer period
    VOID (*pUpdateRescheduleTime)(DWORD);       // saved function pointer
} g_profiler;

//------------------------------------------------------------------------------
// Local Functions 

VOID OALProfileIntrUpdateRescheduleTime(DWORD time);
    
//------------------------------------------------------------------------------
//
//  Function:  OEMProfileTimerEnable
//
//  This function is called by kernel to start kernel profiling timer.
//
VOID OEMProfileTimerEnable(DWORD interval)
{
    BOOL enabled;
    
    OALMSG(TRUE, (L"+OEMProfileTimerEnable(%d)\r\n", interval));
    
    // We can't enable timer second time
    if (g_profiler.enabled) return;
   
    // How many hi-res ticks per profiler hit
    g_profiler.countsPerHit = (g_oalTimer.countsPerMSec * interval)/1000;

    // Make sure that value isn't too small
    if (g_profiler.countsPerHit < 8 * g_oalTimer.countsMargin) {
        g_profiler.countsPerHit = 8 * g_oalTimer.countsMargin;
    }

    // Following code should not be interrupted
    enabled = INTERRUPTS_ENABLE(FALSE);

    // Action depends if system run with fixed or variable system tick
    if (pOEMUpdateRescheduleTime == NULL) {
        // Avoid idle longer than system tick, so set value to one system tick
        g_profiler.maxPeriodMSec = g_oalTimer.maxPeriodMSec;
        g_oalTimer.maxPeriodMSec = g_oalTimer.msecPerSysTick;
    } else {
        // Replace update reschedule function with profile aware version
        g_profiler.pUpdateRescheduleTime = pOEMUpdateRescheduleTime;
        pOEMUpdateRescheduleTime = OALProfileIntrUpdateRescheduleTime;
    }            

    // Change actual period
    g_profiler.counts = OALTimerUpdate(
        g_profiler.countsPerHit, g_oalTimer.countsMargin
    ) * g_profiler.countsPerHit;
    g_oalTimer.curCounts += g_profiler.counts;

    // Hook profiler interrupt service routing
    UnhookInterrupt(5, OALTimerIntrHandler);
    HookInterrupt(5, OALProfileIntrHandler);

    // Enable interrupts
    INTERRUPTS_ENABLE(enabled);

    // Set flag
    g_profiler.enabled = TRUE;

    OALMSG(TRUE, (L"-OEMProfileTimerEnable\r\n"));
}

//------------------------------------------------------------------------------
//
//  Function:  OEMProfileTimerEnable
//
//  This function is called by kernel to stop kernel profiling timer.
//

VOID OEMProfileTimerDisable() 
{
    BOOL enabled;

    OALMSG(TRUE, (L"+OEMProfileTimerDisable()\r\n"));

    // No disable without enable
    if (!g_profiler.enabled) goto cleanUp;

    // Following code should not be interrupted
    enabled = INTERRUPTS_ENABLE(FALSE);

    // Action depends if system run with fixed or variable system tick
    if (pOEMUpdateRescheduleTime == NULL) {
        // Restore maximal idle
        g_oalTimer.maxPeriodMSec = g_profiler.maxPeriodMSec;
    } else {
        // Restore original update reschedule function
        pOEMUpdateRescheduleTime = g_profiler.pUpdateRescheduleTime;
    }

    // Restore original system tick period
    OALTimerUpdate(
        g_oalTimer.countsPerSysTick - g_profiler.counts, 
        g_oalTimer.countsMargin
    );

    // Hook original timer interrupt service routine
    UnhookInterrupt(5, OALProfileIntrHandler);
    HookInterrupt(5, OALTimerIntrHandler);

    // Enable interrupts
    INTERRUPTS_ENABLE(enabled);

    // Reset flag
    g_profiler.enabled = FALSE;

cleanUp:
    OALMSG(TRUE, (L"-OEMProfileTimerDisable\r\n"));
}

//------------------------------------------------------------------------------
//
//  Function:  OALProfileIntrHandler
//
//  This is timer interrupt handler which replace default handler in time when
//  kernel profiling is active. It calls original interrupt handler in
//  appropriate times.
//
UINT32 OALProfileIntrHandler()
{
    UINT32 sysIntr;

    // First call profiler
    ProfilerHit(GetEPC());

    // Get new counts value
    g_profiler.counts += g_profiler.countsPerHit;
    
    // If offset is bigger or equal to system tick then call original timer ISR
    if (g_profiler.counts >= g_oalTimer.actualCountsPerSysTick) {
        // Fix high resolution counter (it will be updated by original ISR)
        g_oalTimer.curCounts -= g_profiler.counts - g_profiler.countsPerHit;
        // Update offset counter 
        g_profiler.counts -= g_oalTimer.actualCountsPerSysTick;
        // Call standard handler
        sysIntr = OALTimerIntrHandler();
        // Timer handler recharged timer to full period, so we must change it
        OALTimerUpdate(g_profiler.countsPerHit, g_oalTimer.countsMargin);
    } else {
        // Update counter/compare for next interrupt
        OALTimerRecharge(g_profiler.countsPerHit, g_oalTimer.countsMargin);
        // Update high resolution counter
        g_oalTimer.curCounts += g_profiler.countsPerHit;
        // No other action
        sysIntr = SYSINTR_NOP;
    }        
    return sysIntr;                                     
}

//------------------------------------------------------------------------------
//
//  Function: OALProfileIntrUpdateRescheduleTime
//
//  This function is used to update reschedule time when profiler is running.
//  It is mostly same as OALIntrUpdateRescheduleTime it only doesn't call
//  OALTimerExtendSysTick.
//
VOID OALProfileIntrUpdateRescheduleTime(DWORD time)
{
    UINT32 baseMSec, diffMSec, diffCounts;                                
    INT32 counts;
    
    // Get current system timer counter
    baseMSec = CurMSec;

    // Return if we are already setup correctly
    if (time == (baseMSec + g_oalTimer.actualMSecPerSysTick)) return;

    // How far we are from next tick
    counts = g_oalTimer.actualCountsPerSysTick - OALTimerCountsSinceSysTick();

    // If timer interrupts occurs, or we are within 1 ms of the scheduled
    // interrupt, just return - timer ISR will take care of it.
    if (baseMSec != CurMSec || counts < (INT32)g_oalTimer.countsPerMSec) return;
    
    // Calculate the distance between the new time and the last timer interrupt
    diffMSec = time - baseMSec;

    // Trying to set reschedule time prior or equal to CurMSec - this could
    // happen if a thread is on its way to sleep while preempted before
    // getting into the Sleep Queue
    if (diffMSec <= 0) diffMSec = 0;

    // Account for hardware limitation
    if (diffMSec > g_oalTimer.maxPeriodMSec) {
        diffMSec = g_oalTimer.maxPeriodMSec;
    }        

    // Calculate count difference
    diffCounts = diffMSec * g_oalTimer.countsPerMSec;

    // Actual values to be used by interrupt handler (it is safe to do
    // modification without any type of guard as long as we know we are
    // at least 1 ms before timer interrupt).
    g_oalTimer.actualMSecPerSysTick = diffMSec;
    g_oalTimer.actualCountsPerSysTick = diffCounts;

    // Tick shift is not enough if there was interrupt from timer
    // which increased CurMSec -> increase g_oalTimer.countsMargin to fix.
    DEBUGCHK(baseMSec == CurMSec);
}

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

⌨️ 快捷键说明

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