高速缓存可的对你的应用程序的性能产生戏剧性的影响. 在深刻理解高速缓存的工作原理后, 你可对代码结构进行安排, 最大限度地发挥高速缓存性能. 有关高速缓存结构的内容. 参见(原书 2.2节).
当对一个可高速缓冲的数据访问时, 若该数据不在数据高速缓存中, 将使整个高速缓存线从外部内存带入高速缓存, 这就称之为线读入. 对于奔腾或动态执行(P6-系列)处理器, 这些数据按下列成组顺序以4个8字节段组成的成组读入.
第一个地址 | 第二个地址 | 第三个地址 | 第四个地址 |
---|---|---|---|
0H | 8H | 10H | 18H |
8H | 0H | 18H | 10H |
10H | 18H | 0H | 8H |
18H | 10H | 8H | 0H |
数据可以按它们到达的顺序有效地使用. 如果一个数据组按串行顺序读出, 那么可按串行顺序进行访问. 因此, 每个数据项可在它从内存到达时即被使用.
大小为32字节倍数的数组应在高速缓存线的起始位置. 以32字节边界对齐, 将充分发挥按序线读入的优势, 并匹配高速缓存线大小. 大小非32字节倍数的数组应以32或16字节边界开始 (在高速缓存线的开始或中间). 为了按32或16边界对齐, 需要对数据进行填充. 如果必要, 尽量按填充后的空间来定位数据(变量或常量).
动态执行(P6-系列)处理器有一个"按读分配写"的高速缓存, 对应于奔腾处理器的"无写分配, 通过写失败而写"的高速缓存.
在动态执行(P6-系列)处理器中, 写操作发生但被写部分不在高速缓存时, 整个32字节高速缓存线被读入.在奔腾处理器中,当被写部分不在高速缓存时, 仅简单地写到内存中去.
由于连序存贮操作被合并为突发写, 且将数据保存在高速缓存中可为后继的读取操作使用, 使写分配通常是有利的. 这就是动态执行(P6-系列) 处理器采用这种写策略的原因, 也是一些奔腾处理器的系统在设计 L2 Cache时实现这种方式的原因.
在以下情况下, 写分配有如下缺点:
当在一个应用程序中有大量的写操作, 如下面例子所示, 跨距大于32字节高速缓存线且数组为大数组时, 对动态执行 (P6-系列)处理器的每个写操作将使整个高速缓存线被读取.另外, 这种读取将替换掉一条(有时两条)不用或很少用的高速缓存线.
这样将导致每次存贮时增加一次对高速缓存线的读取, 并降低程序的执行速度. 当一个程序中有大量的写操作时, 将使性能降低。厄拉多塞筛选程序是一个说明这种高速缓冲效果的简单例子. 在这个例子中, 一个大数组不断地按增大的步长将其特定的值赋0.
注意这仅为一个表现高速缓存效果的简单例子. 在代码中可使用很多其它的优化方法.
厄拉多塞筛选例子:
boolean array [2..max] for (i=2; i<max; i++) { array:=1; } for (i=2; i<max; i++) { if (array[i]) { for(j=2; j<max; j+= i) { array[j]:=0; /* 这里我们对内存赋0产生了 j循环内对高速缓存线的读取*/ } } }
对这个特定的例子来说, 有两种有效的优化方法. 第一种是通过改用位数组来减少数组大小, 目的是降低 Cache线的读取次数. 每二种是通过检查前一次写的值, 降低对内存的读写次数(波动较大高速缓存线).
在上面的程序中,"Boolean" 是一个字符型数组.在某些程序中, 更好的方法是把"boolean" 数组变成位数组, 这样可以执行读 一一修改一一写操作(因为高速缓存规程将每个读操作变成 读一一修改一一写). 但在本例中, 由于大多数的步长大于256比特 (一个高速缓存线的位数). 故不能有效地提高性能.
另一种优化方法是在写前检查该值是否已经是0.
boolean array[2..max] for(i=2; i<max;i++) { array:=1; } for(i=2; i<max; i++) { if(array[i]) { for (j=2; j<max; j+=i) { if(array[j]!=0) { /* 检测该值是否已为0 */ array[j]:=0; } } } }
由于在大多数时候筛选程序的数据已经是0, 所以可以把对外部总线的驱动次数降低一半.
通过预先检查, 可以仅使用一个猝发总线周期读数据, 并为每个不需要再写的缓存线节省一个猝发总线周期. 由于对已修改的高速缓存线不再需要回写, 可节省下额外的时钟周期.
注意 本操作仅对 P6-系列的处理器有意义, 不能增加奔腾处理器的性能. 因此, 本操作不具备通用性. 由于顺序存贮被合并为猝发写, 高速缓存中的数据为下一次读取而保留, 所以写分配在大多数系统中是一种通用的改善性能的方法, 这也是为什么 P6系列处理使用该策略, 而一些基于奔腾处理器的系统在 L2高速缓存中实现它的原因.