在实际CPU从内存中取数时很多时候从cache中存取,在这个实验中使用C语言编成估计cache的大小。
当一个数组的大小超过cache的大小时,随机读取数组的元素会发生cache的替换现象。如果要存取的数据经常不在cache中(被替换出去/没有载入),CPU需要多次从内存中读取数据。
从内存中读取数据的时间远大与从cache中读取的时间,因此从如果数组大于cache size那么多次随即读取的时间会增加。当随即读取时间出现显著增加时,数组的大小即为cache size的估计量。
代码本身比较简单。注释也都比较详细,直接上代码。
#include
#include
#include
#include
#define READ_TIMES 999999999
#define TEST_RANGE 24
int main()
{
int i;
// 每次要测试的内存块大小
int *block_size = (int *)calloc(TEST_RANGE, sizeof(int));
for (i = 0; i < TEST_RANGE; ++i)
block_size[i] = pow(2, i);
srand(time(NULL));
// 每次循环测试大小为block_size[i]的数组随即读取的时间
for (i = 0; i < TEST_RANGE; ++i)
{
// 用size代替block_size[i]减少代码量
int size = block_size[i];
// 创建大小为block_size[i]的数组
int *block = (int *)calloc(size, sizeof(int));
int j, temp;
clock_t start = clock(), total_time;
// 开始随即读取
for(j = 0; j < READ_TIMES; ++j)
temp += block[rand() % size];
total_time = clock() - start;
// 由于数组是int类型,因此最终大小要乘 sizeof(int)
printf("At size: %ldB, we need %lf sec\n", size * sizeof(int),\
(double)total_time / CLOCKS_PER_SEC);
}
return 0;
}
得到的运行结果如下
At size: 4B, we need 8.686316 sec
At size: 8B, we need 8.830951 sec
At size: 16B, we need 8.271359 sec
At size: 32B, we need 8.633918 sec
At size: 64B, we need 8.209328 sec
At size: 128B, we need 8.174642 sec
At size: 256B, we need 8.257708 sec
At size: 512B, we need 8.429885 sec
At size: 1024B, we need 8.398997 sec
At size: 2048B, we need 8.389903 sec
At size: 4096B, we need 8.349263 sec
At size: 8192B, we need 8.603128 sec
At size: 16384B, we need 8.294702 sec
At size: 32768B, we need 8.382414 sec
At size: 65536B, we need 8.452870 sec
At size: 131072B, we need 8.577709 sec
At size: 262144B, we need 8.493697 sec
At size: 524288B, we need 8.535531 sec
At size: 1048576B, we need 8.457926 sec
At size: 2097152B, we need 8.466891 sec
At size: 4194304B, we need 8.602997 sec
At size: 8388608B, we need 8.984190 sec
At size: 16777216B, we need 9.560884 sec
At size: 33554432B, we need 10.243553 sec
可以看到在数组大小为8388608 Byte时随机读取的时间发生了比较大的增长。因此可以估计cache的大小为4184304 Byte。
为了验证实验的结果,使用命令
getconf -a | grep CACHE
来获得机器的硬件信息。得到的输出如下:
LEVEL1_ICACHE_SIZE 65536
LEVEL1_ICACHE_ASSOC 4
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_ASSOC 8
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 524288
LEVEL2_CACHE_ASSOC 8
LEVEL2_CACHE_LINESIZE 64
LEVEL3_CACHE_SIZE 4194304
LEVEL3_CACHE_ASSOC 16
LEVEL3_CACHE_LINESIZE 64
LEVEL4_CACHE_SIZE 0
LEVEL4_CACHE_ASSOC 0
LEVEL4_CACHE_LINESIZE 0
可以看到L3-cache的大小为4194304 Byte。因此上面估计的cache大小可以接受。
实际上可以看到数组大小到达4194304 Byte时随即读取的总时间也比较大,这可能是cache替换时出现抖动引起的。
在没有超过cache size时,随机读取时间也有一定的波动,可能有如下原因:
(1)电脑上其他程序占用了一定的资源,并且每时每刻占用的资源大小不一样;
(2)在数组比较小的时,存取时间可能受到指令的局部性的影响。