精確測量代碼的CPU運行週期

工欲善其事,必先利其器。爲了優化代碼,我們需要準確的獲取代碼在運行期間的相關數據,比如最重要的運行時間。這裏介紹若干種測量方法。

目前有不少商業軟件可以完成類似的測試,比如Intel VTune,AMD CodeAnalyst等等。VS2005的Professional版本中也有相應的Profiling功能。不過,對於輕量級的代碼優化而言,殺雞未必要用牛刀。

首先,對於簡單的計時需求,可以使用boost的timer類,它內部使用clock函數。如果覺得精度仍然不夠的話,可以使用下面的CTimingLight類

#include <windows.h>

enum TimerType {e_TimerType_Accurate};

template<TimerType Type>
struct TimerTimeFormat {};

template<>
struct TimerTimeFormat<e_TimerType_Accurate> {
    typedef LARGE_INTEGER TimeFormat;
    TimeFormat StartTime;
    const double Frequency;

    TimerTimeFormat():Frequency(GetFrequency().LowPart) {}
    void SetStartTime() {StartTime=GetCurTime();}
    double GetSpan() const {
        return (GetCurTime().QuadPart-StartTime.QuadPart)/Frequency;
    }
private:
    static TimeFormat GetCurTime() {
        LARGE_INTEGER t;
        ::QueryPerformanceCounter(&t);
        return t;
    }
    static TimeFormat GetFrequency() {
        LARGE_INTEGER t;
        ::QueryPerformanceFrequency(&t);
        return t;
    }
};

template<TimerType Type>
class CTimingLight
{
public:
    CTimingLight() {Restart();}
    void Restart() {m_Timer.SetStartTime();}
    double GetTime() const {return m_Timer.GetSpan();}
private:
    TimerTimeFormat<Type> m_Timer;
private:
    CTimingLight(const CTimingLight&);
    CTimingLight& operator=(const CTimingLight&);
};

如果你希望獲取更豐富的信息,譬如CPU Clock,Cache Miss,Branch MisPredict,那麼可以使用Agner Fog編寫的testp庫(http://www.agner.org/optimize/testp.zip
這個庫需要你把測試代碼嵌入到它的源文件中,不過利用類派生簡單擴展一下以後就可以很方便使用了。大致的調用代碼如下:

#include "Timing/CPUTiming.h"

int Setup()
{
    return 1;
}
int UnSetup()
{
    return 1;
}

struct TestFunOpT:public TestFunOp {
    virtual void TestFun() const;
    virtual int GetRepNum() const {return 20;}
};

void TestFunOpT::TestFun() const
{
    // your code here
}

void Test()
{
    // create CCounters instance and interpret CounterTypesDesired list
    CCounters MSRCounters;

    MSRCounters.OutputStart();
    // start MSR counters
    MSRCounters.StartCounters();
    // run the test code
    int repetitions = TestFunOpT().TestLoop();
    // stop MSR counters
    MSRCounters.StopCounters();
    MSRCounters.OutputEnd(repetitions);
}

int main()
{
    if (!Setup()) return 0;
    Test();
    UnSetup();
    return 0;
}

運行之後就可以在控制檯看到詳細的統計信息了。

不過有一點需要注意的是,testp運行的時候會掛起整個操作系統,所以不要在TestFun中測試可能會運行很長時間的代碼。如果你不幸在TestFun裏寫了個死循環,那麼你就只能按機箱上的reset了 :P
另外一點是,在vista上使用testp庫時需要提升到管理員權限,因爲testp的統計工作需要藉助Driver程序MSRDriver32.sys中提供的Service
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章