2008-10-20 67 views
9

今天当我在计算机组织课上时,老师谈到了一些有趣的事情。说到为什么高速缓存有效,他说:缓存如何工作?

for (i=0; i<M; i++) 
    for(j=0; j<N; j++) 
     X[i][j] = X[i][j] + K; //X is double(8 bytes) 

用第二行改变第一行并不好。你对此有何看法?为什么它是这样的?

+1

这是我在过去几天看到的第三个基本家庭作业类型的问题。如果你挣扎,你可能想聘请一名导师。 – tvanfosson 2008-10-20 11:45:37

+0

嘿,伙计!这不是功课......我在课堂上偶然发现了这个!因为老师用中文讲,我真的不明白他在说什么。这就是为什么我想问你们所有的...... – israkir 2008-10-20 11:55:03

+2

但是,如果是作业,我可以自己放置'家庭作业'标签;就像我之前对我最近的一些问题所说的那样...... – israkir 2008-10-20 11:56:07

回答

9

参考的地点。因为数据是按行存储的,所以对于每一行j列都在相邻的存储器地址中。操作系统通常会将整个页面从内存加载到缓存中,并且相邻的地址引用可能会引用同一页面。如果通过内部循环中的行索引进行递增,则这些行可能会位于不同的页面上(因为它们之间每隔j个双重分隔),并且缓存可能必须不断引入并丢弃内存页面数据。这被称为颠簸,对性能不利。

在实践中,对于更大,更现代的缓存,行/列的大小需要相当大才能发挥作用,但这仍然是一个好习惯。

[编辑]上面的答案是特定于C,可能会有所不同其他语言。我知道的唯一不同的是FORTRAN。 FORTRAN以列主要顺序存储事物(以上是主行),并且更改FORTRAN中语句的顺序是正确的。如果你想/需要效率,了解你的语言如何实现数据存储很重要。

7

这就像是因为缓存像地方一样。被访问的内存数量相同,但间隔更远,会触及不同的“缓存行”,甚至可能完全错过缓存。因此,只要有选择,组织数据以便可能及时接近彼此的访问在太空中也是如此。这增加了缓存命中的机会,并为您提供更多性能。

当然有关于此主题的丰富信息可用,请参阅this wikipedia entry on locality of reference。或者,我猜,你自己的课程教科书。 :)

+0

感谢您的信息。良好的资源;) – israkir 2008-10-20 11:56:42

2

在C中,n维矩阵是主要行,意味着矩阵的最后一个索引表示存储器中的相邻空间。这与其他一些语言不同,例如FORTRAN,它们是列主要的。在FORTRAN,它的效率更高,通过二维矩阵像这样的迭代:

do jj = 1,N 
    do ii = 1,M 
    x(ii,jj) = x(ii,jj) + K; 
    enddo 
enddo 
1

高速缓存是非常快和非常昂贵的内存,坐在靠近CPU。 CPU不是每次从RAM中取一小块数据,而是获取一块数据并将其存储在缓存中。打赌是,如果你只读了一个字节,那么你读的下一个字节可能就在它之后。如果是这种情况,那么它可能来自缓存。

通过按照您的循环布置循环,您可以按照它们存储在内存中的顺序读取这些字节。这意味着它们在高速缓存中,并且可以由CPU快速读取。如果在第1行和第2行之间交换,那么每次在循环中读取每个“N”个字节。您正在读取的字节在内存中不再连续,因此它们可能不在缓存中。 CPU必须从(较慢的)RAM中取出它们,所以你的性能会下降。

12

Red Hat的Ulrich Drepper和glibc的名气很好,What Every Programmer Should Know About Memory。一节详细讨论了缓存。例如,在SMP系统中存在高速缓存效应,其中CPU可能最终颠倒所修改的高速缓存行的所有权,从而极大地损害了性能。