精确测量代码的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

你可能感兴趣的:(timer,优化,struct,测试,profiling,branch)