我知道硬盘(注意,我说的是磁盘,而不是SSD)有内部磁盘RAM缓存。这些通常约为64MB。我试图了解这些缓存的典型读缓冲策略。
天真地,我假设最新的读取被缓存。我尝试在辅助磁盘,Seagate ST32000645NS硬盘上进行简单的测试,使用fio以及我编写的一小段代码。该磁盘甚至没有安装,因此不应该干扰这些测试。两者都反复从小范围的扇区(几MB)中读取,这些扇区很好地包含在磁盘缓冲区大小中。两个测试都使用O_DIRECT,以消除主机OS缓冲区的影响。由于现代磁盘接口具有Gb / s吞吐量,并且除磁盘初始读取之外的所有内容都应缓存在磁盘缓冲区上,因此我预计吞吐量将达到100s MB / s。然而,我得到了大约1MB / s的可测量结果,表明没有在磁盘上进行读取缓存。我甚至试图一遍又一遍地反复阅读相同的4KB,但仍然有类似的不良结果。
我查看了dmesg,其中说" sd 1:0:0:0:[sdb]写入缓存:启用,读取缓存:已启用,不支持DPO或FUA"。所以这里似乎没有配置问题。任何人都可以了解这里的磁盘读取缓存可能存在的问题吗?也许驱动程序中的一些基础默认配置告诉设备忽略读缓存?
已编辑 - 以下是相关的代码段。
我连续多次运行的fio脚本代码:
[global]
bs=4k
rw=randread
random_generator=lfsr
direct=1
ioengine=libaio
iodepth=1
direct=1
[device]
filename=/dev/sdb
filesize=64M
size=64M
我的代码:
char name[20] = "/dev/sdb";
int fd = open(name, O_RDWR | O_DIRECT);
if (fd < 0){
printf("failed openning %s. errno %d\n", name, errno);
return -1;
}
int pagesize=getpagesize();
printf("pagesize %d\n", pagesize);
char* realbuff=malloc(4096+pagesize);
char* buf=((((int unsigned)realbuff+pagesize-1)/pagesize)*pagesize);
int res, off, total_reads = 100000;
for (i=0; i<total_reads;i++){
off = 0;
res = lseek(fd, off, SEEK_SET);
if (res != off){
printf("seek res %d, expected %d\n. i %d errno %d", res, off, i, errno);
close(fd);
return -1;
}
res = read(fd, buf, pagesize);
if (res != pagesize){
printf("read only %d bytes, expected %d\n. i %d errno %d", res, pagesize, i, errno);
close(fd);
return -1;
}
}
答案 0 :(得分:0)
通常,在小I / O大小上使用O_DIRECT
表现不佳,因此如果要查看效果读缓存,请尝试发出大I / O.分享fio
测试脚本或您的微基准代码以帮助您将会很有帮助。
并且,您可以尝试在hdparam
中设置预读选项,this link
----更新----
由于可以将直接I / O视为同步I / O,因此必须在处理传入I / O之前完成I / O.而且,小I / O会花费大量时间进行上下文切换和为DMA操作设置寄存器。
下图显示了直接I / O测试fio脚本的带宽。我使用提供的fio脚本将I / O大小从4KB更改为8MB。因为它表明使用直接I / O发出小I / O大小表现出非常差的性能,并且随着I / O大小的增加,性能也会提高。
由于主机页面缓存由于直接I / O而无法正常工作,因此系统无法利用预读功能,并且必须从磁盘表面或设备上的磁盘缓存中获取数据,从而导致缓慢且繁琐的上下文切换。
答案 1 :(得分:0)
增加深度,顺序执行I / O并改变大小(更小和更大)会有所不同吗? Wikipedia suggests the hard disk's cache is only used for readahead/readbehind and write caching。如果是这样的话,即使您正在重新读取相同的区域,您也无法在任何给定时间从磁盘缓存中获取一个随机I / O的好处。