2017-03-04 48 views
1

我已决定传球的倍值和由在C基准++用下面的代码进行比较(克++ 5.4.0):定时使用变量通过引用,并通过在C++值传递的

#include <iostream> 
#include <sys/time.h> 
using namespace std; 

int fooVal(int a) { 
    for (size_t i = 0; i < 1000; ++i) { 
     ++a; 
     --a; 
    } 
    return a; 
} 
int fooRef(int & a) { 
    for (size_t i = 0; i < 1000; ++i) { 
     ++a; 
     --a; 
    } 
    return a; 
} 

int main() { 
    int a = 0; 
    struct timeval stop, start; 
    gettimeofday(&start, NULL); 
    for (size_t i = 0; i < 10000; ++i) { 
     fooVal(a); 
    } 
    gettimeofday(&stop, NULL); 
    printf("The loop has taken %lu microseconds\n", stop.tv_usec - start.tv_usec); 
    gettimeofday(&start, NULL); 
    for (size_t i = 0; i < 10000; ++i) { 
     fooRef(a); 
    } 
    gettimeofday(&stop, NULL); 
    printf("The loop has taken %lu microseconds\n", stop.tv_usec - start.tv_usec); 
    return 0; 
} 

它由于在执行fooRef内部的操作时在内存中“查找”了参考值,预计fooRef执行将花费比fooVal更多的时间。但事实证明,结果是出乎意料的对我说:

The loop has taken 18446744073708648210 microseconds 
The loop has taken 99967 microseconds 

,下一次我运行的代码可以生成类似

The loop has taken 97275 microseconds 
The loop has taken 99873 microseconds 

大多数时候产生的值都接近对方(以fooRef只是慢一点点),但有时会像第一次运行的输出一样发生爆发(对于fooReffooVal循环都是如此)。

你能解释一下这个奇怪的结果吗?

UPD:优化已关闭,O0级别。

+5

OMG!你真的等了18446744073708648210微秒吗? – WhiZTiM

+0

To @WhiZTiM 当然不是。它运行得非常快,因为它应该。但数据非常混乱。 –

+0

你打开了优化? –

回答

0

我不是这方面的专家,但我会倾向于认为两次有些相同的原因是由于cache memory

当你需要(在一个IA-32构建筑说,地址0xaabbc125)访问存储位置,则CPU将内存块(地址0xaabbc0000xaabbcfff)到您的高速缓存存储器。从内存中读取和写入内存很慢,但是一旦它被复制到缓存中,就可以非常快速地访问值。这很有用,因为程序通常需要一遍又一遍的相同地址范围。

由于您一遍又一遍地执行相同的代码,并且您的代码不需要太多内存,第一次执行该函数时,会将内存块(一次)复制到缓存中一次,这可能占用97000个时间单位中的大部分时间。随后对你的fooValfooRef函数的任何调用将需要已经在你的缓存中的地址,因此它们只需要几纳秒(我大概在10ns和1μs之间)。因此,取消引用指针(因为引用是作为指针实现的)与仅访问一个值相比,大约是时间的两倍,但无论如何,它是双重的。

更多的专家可能比我的更好或更完整的解释,但我认为这可以帮助你了解这里发生了什么。

一个小想法:在设置start并开始循环之前,尝试运行fooValfooRef函数几次(比如10次)。这样,(如果我的解释是正确的!)内存块将(应该)已经进入缓存,当你开始循环它们时,这意味着你不会在你的时代进行缓存。

关于你得到的超高价值,我无法解释。但价值显然是错误的。

这不是一个错误,它是一个功能!=)

+0

谢谢你的回复。缓存似乎真的可以平衡时间。不幸的是,在测量失败之前几次运行'fooVal'和'fooRef'的想法 - 结果与之前一样。 –

1

如果函数gettimeofday()函数依赖于操作系统的时钟,该时钟是不是真的设计用于与微秒以精确的方式处理。时钟通常会周期性地更新,并且频率足够高,以便为了处理日期/时间值而精确地显示秒数。在微秒级别采样可能不适用于您正在执行的基准测试。

您应该可以通过让您的测试时间更长来解决此限制;例如几秒钟。

同样,在其他的答案和评论,其影响的存储器类型被访问(寄存器,高速缓存,主等)和各种优化是否被施加,可以显着地影响结果提及。

与解决时间采样限制问题一样,您可以通过将测试数据设置得更大来有效解决内存类型和优化问题,从而有效绕过针对较小内存块的内存优化。

1

首先,您应该看看汇编语言,以查看引用传递和值传递之间是否存在差异。

其次,使相当于由恒定参考传递的功能。按值传递说,原始变量不会被改变。通过不断的引用保持相同的原则。

我的观点是这两种技术在汇编语言和性能上应该是等价的。 OMG!