为什么O_DIRECT比正常读取慢?

qij5mzcb  于 2023-06-28  发布在  其他
关注(0)|答案(1)|浏览(126)

下面是我使用的代码:

#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

quhf5bfb

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在上面链接的邮件列表线程中也提出了其他有趣的解决方案。

相关问题