我有以下程序,我在stackoverflow的其他人的帮助下写了解了高速缓存行和CPU缓存。我有下面发布的计算结果。
1 450.0 440.0
2 420.0 230.0
4 400.0 110.0
8 390.0 60.0
16 380.0 30.0
32 320.0 10.0
64 180.0 10.0
128 60.0 0.0
256 40.0 10.0
512 10.0 0.0
1024 10.0 0.0
我使用gnuplot绘制了一个图表,该图表发布在下面。
我有以下问题。
是我的时间计算,以毫秒为准? 440毫秒似乎 很多时间?
从图表cache_access_1(redline)我们可以得出结论 高速缓存行的大小是32位(而不是64位?)
在代码中的for循环之间清除它是个好主意 缓存?如果是,我该如何以编程方式执行此操作?
正如您所看到的,我在上面的结果中有一些0.0
值。
这表明了什么?也是测量的粒度
粗?
请回复。
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX_SIZE (512*1024*1024)
int main()
{
clock_t start, end;
double cpu_time;
int i = 0;
int k = 0;
int count = 0;
/*
* MAX_SIZE array is too big for stack.This is an unfortunate rough edge of the way the stack works.
* It lives in a fixed-size buffer, set by the program executable's configuration according to the
* operating system, but its actual size is seldom checked against the available space.
*/
/*int arr[MAX_SIZE];*/
int *arr = (int*)malloc(MAX_SIZE * sizeof(int));
/*cpu clock ticks count start*/
for(k = 0; k < 3; k++)
{
start = clock();
count = 0;
for (i = 0; i < MAX_SIZE; i++)
{
arr[i] += 3;
/*count++;*/
}
/*cpu clock ticks count stop*/
end = clock();
cpu_time = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("cpu time for loop 1 (k : %4d) %.1f ms.\n",k,(cpu_time*1000));
}
printf("\n");
for (k = 1 ; k <= 1024 ; k <<= 1)
{
/*cpu clock ticks count start*/
start = clock();
count = 0;
for (i = 0; i < MAX_SIZE; i += k)
{
/*count++;*/
arr[i] += 3;
}
/*cpu clock ticks count stop*/
end = clock();
cpu_time = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("cpu time for loop 2 (k : %4d) %.1f ms.\n",k,(cpu_time*1000));
}
printf("\n");
/* Third loop, performing the same operations as loop 2,
but only touching 16KB of memory
*/
for (k = 1 ; k <= 1024 ; k <<= 1)
{
/*cpu clock ticks count start*/
start = clock();
count = 0;
for (i = 0; i < MAX_SIZE; i += k)
{
count++;
arr[i & 0xfff] += 3;
}
/*cpu clock ticks count stop*/
end = clock();
cpu_time = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("cpu time for loop 3 (k : %4d) %.1f ms.\n",k,(cpu_time*1000));
}
return 0;
}
答案 0 :(得分:5)
由于您使用的是Linux,我将从这个角度回答。我还会考虑使用英特尔(即x86-64)架构。
更多警告:一致步幅(如2的幂)的问题在于处理器喜欢通过预取来隐藏缓存未命中惩罚。您可以在BIOS中的许多计算机上禁用预取程序(请参阅"Changing the Prefetcher for Intel Processors")。
页面错误也可能会影响您的结果。您正在分配500M整数或大约2GB的存储空间。循环1尝试触摸内存,以便操作系统分配页面,但如果您没有这么多可用内存(不仅仅是总数,因为操作系统等占用了一些空间),那么您的结果将会出现偏差。此外,操作系统可能会开始回收一些空间,以便在您的某些访问中始终存在页面错误。
与之前相关,TLB也会对结果产生一些影响。硬件在转换后备缓冲区(TLB)中保留从虚拟地址到物理地址的映射的小缓存。每页内存(英特尔上4KB)都需要TLB条目。所以你的实验需要2GB / 4KB =&gt; ~500,000个条目。大多数TLB只能容纳1000个条目,因此测量结果也会因此错过而产生偏差。幸运的是,每4KB或1024个整数只有一次。 malloc可能会为您分配“大”或“大”页面,以获取更多详细信息 - Huge Pages in Linux。
另一个实验是重复第三个循环,但更改正在使用的掩码,以便您可以观察每个缓存级别的大小(L1,L2,可能是L3,很少是L4)。您可能还会发现不同的缓存级别使用不同的缓存行大小。