在完成一个算法的改进后, 除了人工估算时间复杂度外, 我们可能还希望直观地检测改进效果, 现有的性能分析工具比如Intel® VTune™ Amplifier自然满足需求, 然而有时候使用第三方工具的成本却可能超出我们的所需(也许我们仅仅需要大概地对比便能得到结果), 或者我们希望能在代码中控制测试流程, 这时写一个Benchmark便是首选了.
本文实现了一个简单的通用型Benchmark框架, 因为简单, 它所能得到的信息也十分有限, 不过这已经足够了.(如果你需要更为强健的framework, 推荐使用Celero, C++ Benchmark Authoring Library/Framework)
//compiled with /UNICODE #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <RLib_Import.h> #if _DEBUG #pragma comment(lib, "RLib_d.lib") #else #pragma comment(lib, "RLib.lib") #endif // _DEBUG using namespace System; //------------------------------------------------------------------------- static Timer timer; //Timer是对高精度计时API QueryPerformanceCounter 的简单封装 //------------------------------------------------------------------------- static void show_benchmark_result(double interval, const String &prefix = Nothing) { GlobalizeString u_prefix(prefix + _T("运行耗时:") + String().Format(_T("%f"), interval * 1000) + _T("ms") RLIB_NEWLINE); printf(u_prefix.toGBK()); } //------------------------------------------------------------------------- #define SAMPLE_COUNT 1024 //采样次数 void test1() { } //------------------------------------------------------------------------- void test_wrapper(RLIB_TYPE(test1) *test_t, const String &test_name) { printf(RLIB_NEWLINEA); double intervals[SAMPLE_COUNT]; for (int i = 0; i < RLIB_COUNTOF(intervals); ++i) { timer.BeginTimer(); test_t(); timer.EndTimer(); intervals[i] = timer.GetDoubleTimeSpan(); //show_benchmark_result(intervals[i]); } //for double imin = intervals[0], imax = intervals[0]; for (int i = 1; i < RLIB_COUNTOF(intervals); ++i) { intervals[0] += intervals[i]; imax = max(imax, intervals[i]); imin = min(imin, intervals[i]); } show_benchmark_result(imin, _T("最小")); show_benchmark_result(imax, _T("最大")); show_benchmark_result((intervals[0] - imax - imin) / (RLIB_COUNTOF(intervals) - 2), test_name + _T(" 平均")); } //------------------------------------------------------------------------- int _tmain(int argc, _TCHAR* argv[]) { test_wrapper(test1, _T("测试例名")); printf(RLIB_NEWLINEA); system("pause"); return argc; }
此外, 如果调用API不是很方便, 还可以借助rdtsc指令获取大概的CPU时钟周期进行估计.