65.9K
CodeProject 正在变化。 阅读更多。
Home

处理器基准测试实用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.09/5 (9投票s)

2008年5月29日

CPOL

4分钟阅读

viewsIcon

39659

downloadIcon

774

测量处理器性能

引言

本文讨论了一个处理器基准测试工具。结果令人惊讶。就像如今的万事万物都会打破我们的固有观念一样,处理器也不例外。

就在前几天,我收到了一封关于21世纪被打破的固有观念的电子邮件。内容大致是这样的:“……最高的篮球运动员是中国人……最受欢迎的说唱歌手是白人,而最好的高尔夫球员是……”。所以,看到一个打破固有观念的处理器基准测试,也就不足为奇了。

背景

我一直很好奇新一代处理器性能如何。它们有多快?不仅仅是一个代表处理器整体的数字,而是一个真实的值,代表在给定时间内处理器可以执行多少给定类型的操作。例如,每秒执行多少次整数加法。每秒执行多少次双精度除法?……

debugbench_s.jpg

Using the Code

代码的开发是为了使用宏作为简化的手段。这样,宏参数就可以表示任何所需的基准测试操作。宏 `TIMEDOP`(定时操作)接受两个参数

  1. 要生成的函数名称
  2. 在定时循环中执行的代码
//
// The timing loop generation macros. You may roll your own by changing the second
// argument to the macro to a piece of code. 
// If you use variables in the code snippet, make sure you declare them first.
//
// Here is an example of tinkering between add and increment:
//
//    TIMEDOP(do_int,        count2++   );
//    TIMEDOP(do_int,        count2 +=3 );
//
// Note the missing (or optional) semicolon (;) at the end of the snippets.

TIMEDOP(do_int,        count2++);
TIMEDOP(do_mul,        count *= 33);    // I chose the constants randomly
TIMEDOP(do_div,        count /= 13);    // they have no influence on the timing
TIMEDOP(do_sub,        count -= 10);
TIMEDOP(do_mod,        count %= 13);
TIMEDOP(do_str,        memcpy(str, str2, 1024));
TIMEDOP(do_str2,       memcpy(str, str2, 1));
TIMEDOP(do_dbladd,     dop2 += dop1; dop1+=3);
TIMEDOP(do_dbladd3,    dop2 = dop1 + dop3; dop1+= 2);
TIMEDOP(do_dbldiv,     dop2 /= 103);
TIMEDOP(do_dblsin,     dop2 = sin(dop1); );
TIMEDOP(do_func,       noop(count2));
TIMEDOP(do_cos,        cos(dop1););
TIMEDOP(do_tan,        tan(dop1););
TIMEDOP(do_sqrt,       sqrt(dop1););

// After declaring, one may call the function as follows:

int count = do_int();  // count receives the count of instructions / 100

// To make sure the time elapsed is accurate, the performance counter is 
// queried twice, as to measure how long it takes to query the performance counter.

QueryPerformanceCounter(&PerformanceCount);\
double dd = largeuint2double(PerformanceCount);\

QueryPerformanceCounter(&PerformanceCount3);\
double skew = largeuint2double(PerformanceCount3) - dd;\
         
// Then, in the main loop, every time the performance counter is
// queried, the code extends the expected time by the time it 
// took the performance counter to respond

... in the while loop ...

timeforonesec += skew;  /* Compensate for skew */
if(currentcount - startcount > timeforonesec)  
    break;

测量精度

自然,有很多进程在竞争处理器资源。因此,测得的基准结果会有很大的波动。为了弥补这一点,该工具会保持一个运行平均值。

为了测试代码的准确性,并证明补偿技巧是否按预期工作,我陷入了一个两难的境地。老的海森堡不确定性原理显现出来,我无法观察处理器速度,因为观察进程干扰了结果。换句话说,我尝试对处理器做的任何事情都会干扰测量。

最后,为了测试补偿代码,我在一个测试中执行了基准测试代码片段(来自一个宏)一百次,在另一个测试中执行了五十次。如果补偿代码工作正常,第二个测试的结果应该是第一个测试的两倍。它奏效了!太棒了!

我想到了测量处理器速度涉及到与量子力学相关的理论。太酷了。这难道不是编程的全部意义吗?

描述的基准测试项目

以下是基准测试屏幕上各项的简要说明

函数名 代码 描述 注释
do_int, count2++ 简单的整数加法和/或增量 增量和加法速度相同
do_mul, count *= 33 简单的整数乘法 速度几乎与加法一样快
do_div count /= 13
简单的整数除法
比双精度加法慢
do_mod count %= 13 简单的整数取模 速度与除法相同
do_str memcpy(str, str2, 1024) 复制1k字符串 涉及内存。这是一个很好的测试,看看DDR 400升级是否有效。
do_str2 memcpy(str, str2, 1) 复制1字节字符串 库函数调用开销
do_dbladd dop2 += dop1; dop1+=3 加两个双精度数 优化器知道第二个变量没有改变,所以我们对其进行了填充。
do_dbladd3 dop2 = dop1 + dop3; dop1+= 2 加两个双精度数,并赋值 也进行了填充
do_dbldiv dop2 /= 103 双精度除法 比整数运算快
do_dblsin dop2 = sin(dop1) 三角函数 比预期慢
do_func noop(count2) 调用一个空函数 调试版本慢很多
do_cos cos(dop1) 三角函数 所有三角函数执行速度相似
do_tan tan(dop1) 三角函数
do_sqrt sqrt(dop1) 平方根 处理器在这里工作很努力

调试版本

调试版本与发布版本的性能相似。唯一显著的区别在于函数调用。这(可能)是由于调试器跟踪函数调用堆栈的开销造成的。

发布版本

我们不得不禁用优化,因为它(自然)会破坏代码。优化器知道我们在无缘无故地进行重复计算和重复调用,所以它会将其优化掉。

关注点

我用这个工具测试了几种处理器(Core2、Sempron、AMD_64)。令我惊讶的是,我发现过去学到的许多格言都被打破了。例如,在学习C或C++时,你会发现建议:“`variable++`”比“`variable += 1`”更快。根据基准测试,`var1 += var2`和`var1++;`的速度相同。

另一个常识是,处理双精度数比处理整数慢。根据基准测试结果并非如此。在我的Athlon 64上,`int`除法每秒45000次,而`double`除法每秒153000次。

整数乘法和加法一样快。这也是一个意想不到的结果。

如果所有这些听起来难以置信,那么请务必自己测试一下。尝试运行代码,如果代码有错误,我希望收到反馈。

反馈

请将您处理器的截图发送给我(peterglen@verizon.net)。

历史

  • 2008年5月29日:初始版本
© . All rights reserved.