精確測量代碼的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
目前有不少商業軟件可以完成類似的測試,比如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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.