2014-10-31 45 views
8

我正在运行一个内存访问实验,其中使用了一个2D矩阵,每行都是内存页面的大小。实验包括使用行/列主要读取每个元素,然后使用行/列主要写入每个元素。被访问的矩阵被声明为全局范围,以减轻编程需求。是否比读取其他值更快地从内存读取“零”?

这个问题的关键在于,在静态声明测试矩阵的情况下,编译器将这些值初始化为零,我发现结果非常有趣。当我第一次读取操作时,即

rowMajor_read(); 
colMajor_read(); 
rowMajor_write(); 
colMajor_write(); 

然后我的colMajor_read操作很快完成。 enter image description here

但是,如果我读之前做的写操作,我们有:

rowMajor_write(); 
colMajor_write(); 
rowMajor_read(); 
colMajor_read(); 

enter image description here

与列主要读取操作增加幅度近一个数量级。

我认为它必须与编译器如何优化代码有关。由于全局矩阵对于每个元素都是相同的零,编译器是否完全删除了读操作?或者是从某种方式“更容易”从内存中读取同样为零的值?

我没有通过任何关于优化的特殊编译器命令,但我确实以这种方式声明了我的函数。

inline void colMajor_read(){ 
    register int row, col; 
    register volatile char temp __attribute__((unused)); 
    for(col = 0; col < COL_COUNT; col++) 
     for(row = 0; row < ROW_COUNT; row++) 
      temp = testArray[row][col]; 
} 

因为我是运行到编译器在其中完全除去从上述函数的temp变量,因为从来没有正在使用的问题。我认为同时拥有volatile__attribute__((unused))是多余的,但我仍然包括它。我的印象是没有对易变变量实施优化。

任何想法?


我看着生成的程序集,colMajor_read函数的结果是一样的。 (汇编)非内联版本:http://pastebin.com/C8062fYB

+5

我的猜测是系统缓存和预测。 – Nit 2014-10-31 17:24:25

+1

我同意@Nit。缓存局部性很可能是方差的来源。缓存可以轻松地提高访问时间10倍。如果您真的怀疑编译器优化了远离操作(不太可能跨功能,但不是绝对不可能),请获取C函数的汇编程序输出以检查。 – 2014-10-31 17:32:02

+2

挂在家伙身上。我不认为这一切都很复杂。因为这些方法是内联的,这意味着所有这些函数都在同一个编译单元中,所以编译器可以做很棒的事情。主要的是,它可以告诉你是否已经改变了自读写之后的变量,因此可以很容易地将代码重新解释为'temp = 0;',通过比较它会快得疯狂。你可以发布程序集吗? – IdeaHat 2014-10-31 17:50:03

回答

7

在向矩阵写出值之前和之后检查进程的内存使用情况。例如,如果它存储在Linux上的.bss节中,则归零页面将映射到具有写入时复制语义的单个只读页面。所以,即使你正在阅读一堆地址,你可能会一遍又一遍地读同一页的物理内存。

此页http://madalanarayana.wordpress.com/2014/01/22/bss-segment/有一个很好的解释。

如果是这样的话,再次将矩阵归零并重新运行读取测试,它不应该再那么快。

+0

+1当我注意到我迟到了16个小时后才准备发布。 – Mehrdad 2014-11-01 10:34:01