我想研究缓存大小对代码的影响。对于在大型阵列上运行的程序,如果阵列适合缓存,则可能会有显着的加速。
我怎样才能确定这一点?
我试图运行这个c程序:
#define L1_CACHE_SIZE 32 // Kbytes 8192 integers
#define L2_CACHE_SIZE 256 // Kbytes 65536 integers
#define L3_CACHE_SIZE 4096 // Kbytes
#define ARRAYSIZE 32000
#define ITERATIONS 250
int arr[ARRAYSIZE];
/*************** TIME MEASSUREMENTS ***************/
double microsecs() {
struct timeval t;
if (gettimeofday(&t, NULL) < 0 )
return 0.0;
return (t.tv_usec + t.tv_sec * 1000000.0);
}
void init_array() {
int i;
for (i = 0; i < ARRAYSIZE; i++) {
arr[i] = (rand() % 100);
}
}
int operation() {
int i, j;
int sum = 0;
for (j = 0; j < ITERATIONS; j++) {
for (i = 0; i < ARRAYSIZE; i++) {
sum =+ arr[i];
}
}
return sum;
}
void main() {
init_array();
double t1 = microsecs();
int result = operation();
double t2 = microsecs();
double t = t2 - t1;
printf("CPU time %f milliseconds\n", t/1000);
printf("Result: %d\n", result);
}
获取ARRAYSIZE和ITERATIONS的值(保持产品,因此指令数量不变),以检查程序是否运行得更快,如果阵列适合缓存,但我总是获得相同的CPU时间。 / p>
谁能说我做错了什么?
答案 0 :(得分:1)
你真正想做的是建立一座“记忆山”。内存山可以帮助您直观地了解内存访问如何影响程序性能。具体而言,它测量读取吞吐量与空间局部性和时间局部性。良好的空间局部性意味着连续的存储器访问彼此接近,良好的时间局部性意味着在短的程序时间内多次访问某个存储器位置。这里是a link,简要提到缓存性能和内存山。该链接中提到的第3版教科书是一个非常好的参考,特别是第6章,用于了解内存和缓存性能。 (事实上,当我回答这个问题时,我目前正在使用该部分作为参考。)
另一个link显示了一个可用于衡量缓存性能的测试函数,我在此处复制了这些函数:
void test(int elems, int stride)
{
int i, result = 0;
volatile int sink;
for (i = 0; i < elems; i+=stride)
result += data[i];
sink = result;
}
Stride是时间局部性 - 内存访问距离多远。 这个想法是这个函数会估计它运行的周期数。要获得吞吐量,您需要采用(大小/步幅)/(周期/ MHz),其中size是以字节为单位的数组大小,cycle是此函数的结果,MHz是处理器的时钟速度。在进行任何测量以“预热”缓存之前,您需要调用一次。然后,运行循环并进行测量。
我找到了一个GitHub repository,可用于在自己的机器上构建3D内存山。我鼓励您在具有不同处理器的多台计算机上进行尝试并比较差异。
答案 1 :(得分:0)
您的代码中存在拼写错误。 = +而不是+ =。
答案 2 :(得分:0)
arr
数组已链接到BSS
[未初始化]部分。此部分中变量的默认值为零。本节中的所有页面最初都将R / O映射到单 zero page
。这是以Linux / Unix为中心的,但可能适用于大多数现代操作系统
因此,无论数组大小如何,您只能从单个页面获取,这将被缓存,这就是您获得相同结果的原因。
您需要打破&#34;零页面映射&#34;在做测试之前,通过向所有arr
写一些内容。也就是说,首先执行memset
之类的操作。这将导致操作系统使用其COW(写时复制)机制为arr
创建线性页面映射。