高速缓存(也称为 L1、L2 或 L3 高速缓存)是靠近 CPU 的 SRAM,有助于改善 DRAM 数据访问。另一方面,页面高速缓存(或磁盘高速缓存)是对源自诸如硬盘驱动器等辅助存储设备的页面的透明高速缓存。此外,linux 操作系统使用未使用的 DRAM 内存来构建页面缓存。
我发现许多代码可以在 SRAM 上产生缓存未命中(即 L1、L2 或 L3),我对在页面缓存级别生成缓存未命中的 C 代码感兴趣(或者说页面错误更好?)。
我的理解是这样的代码要处理读写等文件系统操作。所以我设计了一个代码来从带有 O_DIRECT 标志的文件中读取数据,这个想法是每个读取操作都会请求访问磁盘,因此会导致页面缓存中的缓存未命中。下面是代码,其中 /tmp/data 是一个 4 KB(一页大小)的文件,其中充满了 0,使用以下命令创建dd if=/dev/zero of=/tmp/data count=4K
:
#include <stdio.h>
#include <time.h>
#define DATA_SIZE 10000
int main(){
char page_data[DATA_SIZE];
clock_t begin, end;
double time_spent;
int lap;
int fd;
fd = open("/tmp/data", "O_DIRECT", "r");
for(lap=0; lap < 10; lap++){
begin = clock();
read(fd, page_data, DATA_SIZE);
end = clock();
time_spent = (double) (end - begin); // / CLOCKS_PER_SEC;
printf("lap %d : time spent : %f data : %s \n", lap, time_spent, page_data);
lseek(fd, 0, SEEK_SET);
}
close(fd);
return 0;
}
这是代码的输出,其中包含 perf-tool 提供的附加信息
perf stat -B -e cpu-clock,task-clock,task-clock,cycles,context-swtiches,cpu-mogrations,page-faults,cache-references,cache-misses ./read_a_file
lap 0 : time spent : 1.000000 data :
lap 1 : time spent : 1.000000 data :
lap 2 : time spent : 1.000000 data :
lap 3 : time spent : 0.000000 data :
lap 4 : time spent : 0.000000 data :
lap 5 : time spent : 0.000000 data :
lap 6 : time spent : 1.000000 data :
lap 7 : time spent : 0.000000 data :
lap 8 : time spent : 0.000000 data :
lap 9 : time spent : 1.000000 data :
Performance counter stats for './read_a_file':
0,282623 cpu-clock (msec)
0,282361 task-clock (msec) # 0,024 CPUs utilized
0 cycles # 0,000 GHz
3 context-switches # 0,011 M/sec
0 cpu-migrations # 0,000 K/sec
54 page-faults # 0,191 M/sec
0 cache-references # 0,000 K/sec
0 cache-misses # 0,000 K/sec
0,011596405 seconds time elapsed
问题是 perf 表明在代码期间没有发生缓存未命中,即使我无法解释原因,我也感到惊讶。否则会发生 54 个页面错误,我也觉得很奇怪,因为我的代码只要求 1 个文件(其大小是页面大小)仅 10 次(不是 54 次)。
所以我的问题是如何设计一个更好的代码来系统地生成页面缓存(或页面错误)上的缓存未命中?
欢迎任何评论