下面是我使用的代码:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <malloc.h>
int main (int argc, char* argv[]) {
int fd;
int alignment = 4096;
int bufsize = 4096 * 4096;
char* buf = (char*) memalign(alignment, bufsize);
int i, n, result=0;
const char* fname = "1GB.txt";
if ((fd = open(fname, O_RDONLY|O_DIRECT)) < 0) {
printf("%s: cannot open %s\n", fname);
exit(2);
}
while ( (n = read(fd,buf,bufsize)) > 0 )
for (i=0; i<n; ++i)
result += buf[i];
printf("Result: %d\n", result);
return 0;
}
下面是我运行的命令:
echo 1 > /proc/sys/vm/drop_caches
time ./a.out 1GB.txt
如果不使用O_DIRECT,在刷新页面缓存后,只需要1.1秒,而使用O_DIRECT则需要2.5秒。
我试着改变对齐和bufsize。将bufsize增加到4096 * 4096 * 4
将运行时间减少到1.79秒。将bufsize增加到4096 * 4096 * 64
将运行时间减少到1.75秒。将对齐减少到512将运行时间减少到1.72秒。我不知道还能做什么。
我不明白为什么使用O_DIRECT会使代码变慢。可能是因为我使用了磁盘加密吗?
Debian 12 kernel 6.1.0-9-amd64
1条答案
按热度按时间quhf5bfb1#
我认为Linus在this old mailing list thread中很好地总结了
O_DIRECT
,其中有人遇到了与您相同的问题:2002年5月10日星期五,林肯Dale写道:
所以2.4.18中的O_DIRECT仍然显示为55%的性能命中,而没有O_DIRECT。有人有线索吗
是的
O_DIRECT不执行任何预读。
要使O_DIRECT成功,您需要使其异步。
关于O_DIRECT,一直困扰我的是,整个界面都很愚蠢,可能是由一只精神错乱的猴子在一些严重的精神控制物质上设计的。
它不是很漂亮,而且由于糟糕的接口(读/写的同步性是其中的一部分,但固有的页表遍历是另一个问题),它的性能也不是很好。
我敢打赌,通过合理地划分实际的IO生成和“用户空间Map”,您可以更干净地获得 * 更好 * 的性能。
因此,由于没有执行预读或缓存,所以读操作速度变慢,这是没有
O_DIRECT
的正常行为。除非你想请求阅读一个更大的大小,如果你做分块读取,你真的只能受益于
O_DIRECT
,如果你正在实现异步操作,例如使用io_uring
。Linus在上面链接的邮件列表线程中也提出了其他有趣的解决方案。