由于存储器的设计和语言的存储安排,一个具有良好局部性的程序往往可以更快的执行。——总结自《深入理解计算机系统》
- 局部性通常有两种不同的形式:时间局部性和空间局部性。在一个具有良好时间局部性的程序中,被引用过一次的存储器位置很可能在不远的将来再被多次引用。在一个具有良好空间局部性的程序中,如果一个存储器位置被引用了一次,那么程序很可能在不远的将来引用附近的一个存储器位置。
总之,编写高速缓存友好的代码涉及两个重要问题。
对局部变量的反复引用是好的,因为编译器能够将它们缓存在寄存器文件中(时间局部性)。
步长为1的引用模式是好的,因为存储器层次结构中所有层次上的缓存都是将数据存储为连续的块(空间局部性)。
按照上述思想结合 定时器,以及C语言关于数组的存储方式。我们实验比较按照列访问二维数组和按照行访问二维数组的效果差别。
sumarray.c
/*
csapp page 424
*/
#include <stdio.h>
#include "timer.h"
int sumarrayrows(int a[][150], int nrow, int ncol)
{
int i, j, sum = 0;
for (i = 0; i < nrow; i++ )
{
for (j = 0; j < ncol; j++)
{
sum += a[i][j];
}
}
return sum;
}
int sumarraycols(int a[][150], int nrow, int ncol)
{
int i, j, sum = 0;
for (j = 1; j < ncol; j++ )
{
for (i = 0; i < nrow; i++)
{
sum += a[i][j];
}
}
return sum;
}
int
main()
{
double timer1, timer2;
int i, j, sum;
int a[100][150];
for (i = 0; i < 100; i++ )
{
for (j = 0; j < 150; j++)
{
a[i][j] = 1;
}
}
timer_start(timer1);
sum = sumarrayrows(a, 100, 150);
timer_stop(timer1);
timer_start(timer2);
sum = sumarraycols(a, 100, 150);
timer_stop(timer2);
printf("time of summaryrow: %.2lfns\n", timer1);
printf("time of summarycol: %.2lfns\n", timer2);
return 0;
}
上述程序的输出结果如下:
从图中可以看出,对这个特定二维数组的访问,如果改变行列访问顺序,加速了7%左右。