程序设计原则——局部性原理

存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构:CPU寄存器-》高速缓冲存储器-》主存储器-》磁盘-》通过网络连接的其他存储设备。

SRAM静态,一般作为高速缓冲存储器。

DRAM动态,一般作为大容量的主存储器

每次CPU和主存之间的数据传送都是通过一些列的步骤完成的,这些步骤称为总线事务。读事务从主存传送数据到CPU,写事务从CPU传送数据到主存。

局部性:一般较好的程序都有较好的局部性,也就是说,它们倾向于引用的数据项邻近于其他最近引用过的数据项,或者邻近于最近自我引用过的数据项。对应的就是空间局部性和时间局部性。

局部性小结:

1、重复引用同一变量的程序有较好的时间局部性。

2、对于具有步长为k的引用模式的程序,步长越小,空间局部性就越好。具有步长为1的引用模式的程序有很好的空间局部性。在存储器中以大步跳来跳去的程序的空间局部性就很差。

3、对于取指令来说,循环有很好的空间和时间局部性。循环体越小,循环迭代次数越多,局部性越好。

编写高速缓存友好的代码

编写高速缓冲友好的代码的基本方法:

1、让最常见的情况运行得快。程序通常把大部分时间都花在少量的核心函数上,而这些函数通常把大部分时间都花在了少量的循环上。所以要把注意力集中在核心函数的循环上,而忽略其他部分。

2、在每个循环内部使缓存不命中数量最小。在其他条件,例如加载和存储的总次数相同的情况下,不命中率低的程序运行得更快。

注意:编译器将局部变量存储到寄存器中,因此循环内对局部变量的引用不需要任何加载或存储指令。

高速缓存对程序性能的影响:

1、通过重新排列循环以提高空间局部性:降低高速缓冲的不命中率。例子(求两个矩阵的乘积)

2、使用分块来提高时间局部性。

分块的大致思想是将一个程序中的数据结构组织成称为块(block)的组块(chunk)。这里的“块”指的是一个应用级的块,不是高速缓冲块。这样构造程序,使得能够将一个块加载到L1高速缓存中,并在这个块中进行所需的所有的读和写,然后丢掉这个块,加载下一个块,以此类推。

但是分块可能带来的负面影响就是会降低程序的可读性。

在程序中利用局部性:

为了编写更有效的程序,不论具体的存储结构是怎样的。推荐以下技术:

1、将注意力集中在内部循环上,大部分计算和存储器访问都发生在这里。

2、通过按照数据对象存储在存储器中的顺序来读取数据,从而使程序的空间局部性最大。

3、一旦从存储器中读入了一个数据对象,就尽可能多的使用它,从而使得程序的时间局部性最大。

4、记住,不命中率只是确定代码性能的一个因素(虽然是重要的)。存储器访问数量也扮演中重要的角色,有时需要在两者之间做一个折中。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·

这里在补充一些有关高速缓冲存储器的内容:

对于一个计算机系统,如果每个存储器的地址有m位,可形成M=2m个不同的地址。而高速缓存一般被组织成一个S=2s个高速缓存组(cache set)的数组。每个组包含E个高速缓存行(cache line)。每一行由B=2b字节的数据块(block)组成。一个有效位(valid bit)指明这个行包含的数据是否有效,还有t=m-(b+s)个标记位(tag bit)(是当前块的存储器地址的位子集),它们唯一的标示存储在这个高速缓存行中的块。

高速缓存的大小指的是所有块的大小的和(不包括有效位和标记位在内)。因此C=S*E*B。

高速缓存主要分为:直接映射高速缓存(每一组只有一行),组相联高速缓存(每一组有两行以上),全相联高速缓存(只有一个组,这个组包含了所有的行)。

注意:高速缓存加载数据时是以每一行的块大小来加载数据的,所以正是基于这一点,我们才能利用高速缓存来提高程序性能。

小技巧:当数组的大小是2的幂时,直接映射高速缓存中通常很容易发生冲突不命中,一般可以通过在数组尾部进行填充来完成“抖动”现象(即,数据反复在高速缓存中发生不命中,而频繁的换进换出)。

但是我看了一下,现在的计算机一般在d-cache、i-cache、二级缓存使用的都是组相联或全相联形式。

注意:高速缓存利用的是地址位的中间位作为缓存的索引,所以这样做相对于使用地址高位作为索引的好处是,主存相邻的块总是映射到不同的高速缓存行。这一点又是我们可以利用在程序性能提高上的原理所在。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/*
 * 高速缓冲实验
 * 发现:
 * 1、如果在内层循环中,存储器加载和存储次数相同的情况下,高速缓冲命中率的高低
 * 反映在程序执行时间上要相差大约200~300ms
 * 2、高速缓冲命中率只是一个因素,循环中存储器的加载次数和存储次数也是会起到很大的
 * 影响,第一个测试程序就比第二个测试程序运行效率更高,虽然它命中率没有另一个高
 * 3、这种高速缓冲的效果一般在较大数据集上,才有明显的差异,所以如果在数据集比较小的情况下,不用在这个高速缓冲上花心思

猜你喜欢

转载自blog.csdn.net/qq_36387683/article/details/81162679
今日推荐