• C++简单的函数计时方法


       这里提供一个简单的函数计时方法,利用QueryPerformanceFrequency和QueryPerformanceCount函数进行精确计时,这是最精确的计时方法。
       原理是在函数被调用时记录时间,结束时利用局部对象的析构函数再记录一次时间,将这个时间差累积到对应的函数的统计数据中。当程序退出时,全局对象释放,将所有函数的数据输出到调试窗口。使用时,需要再函数开头位置插入一条宏:_PF。需要计时的函数内都插入一条这样的宏。为了方便,宏被定义的比较短。


      FunctionName   ActiveTime    Average  Clled
             WinMain     
    5.480105    5.480105     1
        
             MsgProc     
    0.975687    0.015245    64
        
             InitD3D     
    0.222094    0.222094     1
        
        InitGeometry     
    0.004631    0.004631     1
        
              Render     
    4.876714    0.021771   224
        
       SetupMatrices     
    0.001405    0.000006   224
        
             Cleanup     
    0.209167    0.209167     1 



    #define PERFDATA_INIT_SIZE 32
    #define PERFDATA_INC_SIZE  32
    class PerformanceDaemon 
    {
    private
    :
        typedef 
    struct
     _PERF_DATA
        
    {
            DWORD  nID;
            LPSTR pstrName;
            DWORD TotolCalled;
            LONGLONG TotolTime;
            
    //LARGE_INTEGER FuncBeginTime;


        }
    PERF_DATA,*LPPERF_DATA;


        LPPERF_DATA m_pDatas;
        DWORD m_dwUsed;
        DWORD m_dwSize;

        LARGE_INTEGER m_TickNow;
        LARGE_INTEGER m_Freq;
        
    void
     SetSize(DWORD dwSize)
        
    {
            assert(dwSize
    >
    m_dwUsed);
            LPPERF_DATA pData
    =new
     PERF_DATA[dwSize];
            memcpy(pData,m_pDatas,m_dwUsed
    *sizeof
    (PERF_DATA));
            memset(pData
    +m_dwUsed,0,(dwSize-m_dwUsed)*sizeof
    (PERF_DATA));
            delete []m_pDatas;
            m_pDatas
    =
    pData;
            m_dwSize
    =
    dwSize;
        }

    public:

        PerformanceDaemon ()
        
    {
            m_pDatas
    =0
    ;
            m_dwUsed
    =0
    ;
            m_dwSize
    =0
    ;
            
            SetSize(PERFDATA_INIT_SIZE);

            QueryPerformanceFrequency(
    &
    m_Freq); 
            QueryPerformanceCounter(
    &
    m_TickNow);

        }




        
    void FuncStart(LPSTR pstrName,DWORD &nID)
        
    {
            
    if(nID>=m_dwUsed && nID!=0xFFFFreturn
    ;
            
    if(nID==0xFFFF)    //add new function record;

            {
            

                PERF_DATA data;
                SIZE_T nLenght;
                nLenght
    =
    strlen(pstrName);
                memset(
    &data,0,sizeof
    (data));
                data.pstrName
    =new CHAR[nLenght+1
    ];
                strcpy(data.pstrName,pstrName);

                
    if(m_dwUsed >=
     m_dwSize) 
                    SetSize(m_dwSize
    +
    PERFDATA_INC_SIZE);
                
                nID
    =m_dwUsed++
    ;
                
                

                m_pDatas[nID]
    =
    data;

            }

            QueryPerformanceCounter(
    &m_TickNow);
        }

        
    void GetTime(LONGLONG *pTime)
        
    {
            
    *pTime=
    m_TickNow.QuadPart;
        }


        
    void FuncEnd(DWORD nID,LONGLONG *pTime)
        
    {
            LARGE_INTEGER TickNow;
            QueryPerformanceCounter(
    &
    TickNow);
        
            
    if(nID>=m_dwUsed && nID!=0xFFFFreturn
    ;
            m_pDatas[nID].TotolTime
    += TickNow.QuadPart-*
    pTime;
            m_pDatas[nID].TotolCalled
    ++
    ;
            m_TickNow
    =
    TickNow;    
        
        }


        
    void DumpFunctionPerfmance()
        
    {
            CHAR strBuffer[
    256
    ];

            OutputDebugString(
    "FunctionName\t\tActiveTime\tAverage\t  Clled\n"
    ); 
            
    for(DWORD i=0;i<m_dwUsed;i++
    )
            
    {
                
    double
     t;
                DWORD n
    =
    m_pDatas[i].TotolCalled;

                t
    =m_pDatas[i].TotolTime/double
    (m_Freq.QuadPart); 
                sprintf(strBuffer,
    "%16s %12f\t%8f%6u\t\n",m_pDatas[i].pstrName,t,t/
    n,n);
                OutputDebugString(strBuffer);
            }

        
        }



        
    ~PerformanceDaemon ()
        
    {
            DumpFunctionPerfmance();
            
    for(DWORD i=0;i<m_dwUsed;i++
    )
            
    {
                delete []m_pDatas[i].pstrName;
            
            }

            

            delete []m_pDatas;
        
        
        }


    }
    ;
    PerformanceDaemon  Perf;
    class
     PerformanceWatcher
    {
        DWORD dwID;    
        LONGLONG StartTime;        
    //为了解决嵌套调用问题


    public:
        
    //just for convinience 

        PerformanceWatcher(LPSTR pstrFunName,DWORD &nID)
        
    {
            Perf.FuncStart(pstrFunName,nID);
            dwID
    =
    nID;
            Perf.GetTime(
    &
    StartTime);
            
        }

        
    ~PerformanceWatcher()
        
    {
            Perf.FuncEnd(dwID,
    &
    StartTime);
        }


    }
    ;

    #ifdef _DEBUG
    #define _PF  \

        
    static DWORD __PerfCounter=0xFFFF;\
        PerformanceWatcher __PerfWatcher(__FUNCTION__,__PerfCounter);
    #else

    #define _PF
    #endif 



    VOID Cleanup()
    {
        _PF
        
    if( g_pTexture !=
     NULL )
            g_pTexture
    ->
    Release();

        
    if( g_pVB !=
     NULL )
            g_pVB
    ->
    Release();

        
    if( g_pd3dDevice !=
     NULL )
            g_pd3dDevice
    ->
    Release();

        
    if( g_pD3D !=
     NULL )
            g_pD3D
    ->
    Release();
    }


    据MSDN上的资料,VC6以后的版本上的确支持Profile,但个人感觉没有VC6那么方便了。
    VC6 Function Profiling 参考:
    http://msdn.microsoft.com/en-us/library/aa269759(VS.60).aspx

    另外有一个/callcap的编译宏,这个宏允许函数开始执行和结束时调用两个自定义的函数,参考:
    http://msdn.microsoft.com/en-us/library/ms404386.aspx

    // File: callcaphooks.c

    #include 
    <stdio.h>
    int main();

    void _CAP_Enter_Function(void *p) 
    {
        
    if (p != main) 
            printf(
    "Enter function   (at address %p) at %d\n"
                p, GetTickCount());
            
    return;
    }

    void _CAP_Exit_Function(void *p) 
    {
        
    if (p != main) 
            printf(
    "Leaving function (at address %p) at %d\n"
                p, GetTickCount());
        
    return;
    }




  • 相关阅读:
    函数中this指向问题及函数不同方式的调用
    拷贝继承
    组合继承
    借用构造函数
    继承
    UVA-11054(扫描法)
    hihocoder-1347 小h的树上的朋友(lca+线段树)
    UVA-10391(字符串检索)
    UVA-10125(中途相遇法)
    UVA-10827(前缀和降维)
  • 原文地址:https://www.cnblogs.com/Tue/p/1244757.html
Copyright © 2020-2023  润新知