Linux kernel 为什么fsync()在Linux内核3.1.*上花费的时间比内核3.0多得多

Linux kernel 为什么fsync()在Linux内核3.1.*上花费的时间比内核3.0多得多,linux-kernel,fsync,Linux Kernel,Fsync,我有一个测试程序。在Linux内核3.1.*上大约需要37秒,但在内核3.0.18上只需要大约1秒(我只是在与以前相同的机器上更换内核)。请告诉我如何在内核3.1上改进它。谢谢 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>

我有一个测试程序。在Linux内核3.1.*上大约需要37秒,但在内核3.0.18上只需要大约1秒(我只是在与以前相同的机器上更换内核)。请告诉我如何在内核3.1上改进它。谢谢

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int my_fsync(int fd)
{
    // return fdatasync(fd);
    return fsync(fd);
}


int main(int argc, char **argv)
{
    int rc = 0;
    int count;
    int i;
    char oldpath[1024];
    char newpath[1024];
    char *writebuffer = calloc(1024, 1);

    snprintf(oldpath, sizeof(oldpath), "./%s", "foo");
    snprintf(newpath, sizeof(newpath), "./%s", "foo.new");

    for (count = 0; count < 1000; ++count) {
    int fd = open(newpath, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
    if (fd == -1) {
        fprintf(stderr, "open error! path: %s\n", newpath);
        exit(1);
    }

    for (i = 0; i < 10; i++) {
        rc = write(fd, writebuffer, 1024);
        if (rc != 1024) {
        fprintf(stderr, "underwrite!\n");
        exit(1);
        }
    }

    if (my_fsync(fd)) {
        perror("fsync failed!\n");
        exit(1);
    }

    if (close(fd)) {
        perror("close failed!\n");
        exit(1);
    }

    if (rename(newpath, oldpath)) {
        perror("rename failed!\n");
        exit(1);
    }

    }

    return 0;
}


# strace -c ./testfsync
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.58    0.068004          68      1000           fsync
  0.84    0.000577           0     10001           write
  0.40    0.000275           0      1000           rename
  0.19    0.000129           0      1003           open
  0.00    0.000000           0         1           read
  0.00    0.000000           0      1003           close
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         2           setitimer
  0.00    0.000000           0        68           sigreturn
  0.00    0.000000           0         1           uname
  0.00    0.000000           0         1           mprotect
  0.00    0.000000           0         2           writev
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         6           mmap2
  0.00    0.000000           0         2           fstat64
  0.00    0.000000           0         1           set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00    0.068985                 14099         1 total
#包括
#包括
#包括
#包括
#包括
#包括
int my_fsync(int fd)
{
//返回fdatasync(fd);
返回fsync(fd);
}
int main(int argc,字符**argv)
{
int rc=0;
整数计数;
int i;
charoldpath[1024];
char newpath[1024];
char*writebuffer=calloc(1024,1);
snprintf(oldpath,sizeof(oldpath),“/%s”,“foo”);
snprintf(newpath,sizeof(newpath),“/%s”,“foo.new”);
用于(计数=0;计数<1000;++计数){
int fd=开放(新建路径、创建路径、创建路径、仅创建路径、创建路径);
如果(fd==-1){
fprintf(stderr,“打开错误!路径:%s\n”,newpath);
出口(1);
}
对于(i=0;i<10;i++){
rc=写入(fd,writebuffer,1024);
如果(rc!=1024){
fprintf(标准“承保!\n”);
出口(1);
}
}
if(my_fsync(fd)){
perror(“fsync失败!\n”);
出口(1);
}
如果(关闭(fd)){
perror(“关闭失败!\n”);
出口(1);
}
如果(重命名(新路径、旧路径)){
perror(“重命名失败!\n”);
出口(1);
}
}
返回0;
}
#strace-c./testfsync
%时间秒usecs/调用错误syscall
------ ----------- ----------- --------- --------- ----------------
98.58 0.068004 68 1000 fsync
0.84 0.000577 0 10001写入
0.40 0.000275 0 1000重命名
0.19 0.000129 0 1003打开
0.00 0.0000000 1读取
0.00 0.000000 0 1003收盘
0.00 0.0000000 1执行
0.00 0.0000000 1 1访问权限
0.00 0.0000000 3 brk
0.00 0.0000000 1孟马普
0.00 0.0000000 2设定值
0.00 0.0000000.68 sigreturn
0.00 0.0000000 1联塞
0.00 0.0000000 1 M保护
0.00 0.0000000 2写入
0.00 0.0000000 2 rt\u信号动作
0.00 0.0000000 6 mmap2
0.00 0.0000000 2 fstat64
0.00 0.0000000 1套螺纹区域
------ ----------- ----------- --------- --------- ----------------
100.00 0.068985 14099 1总计

内核3.1.*实际上是在进行同步,而3.0.18是在伪造。您的代码执行1000次同步写入。由于截断了文件,每次写入也会放大文件。实际上有2000个写操作。典型的硬盘驱动器写入延迟约为每个I/O 20毫秒。因此2000*20=40000毫秒或40秒。因此,假设您正在向一个典型的硬盘驱动器写入数据,这似乎是正确的


基本上,通过在每次写操作后进行同步,内核无法高效缓存或重叠写操作,也无法强制执行每个操作的最坏情况。此外,硬盘驱动器必须在数据写入位置和元数据写入位置之间来回搜索,每次写入一次。

找到了原因。Linux内核3.1的ext3中默认启用的文件系统屏障(http://kernelnewbies.org/Linux_3.1). 禁用屏障后,速度会快得多

你怎么知道是fsync()导致了减速?也可以是open()调用。您在所讨论的文件系统上使用了哪些
mount
选项?(顺便说一句,在我的Ubuntu 2.6.38-12-generic内核上大约需要1.5秒;
ext3
文件系统,
rw,errors=remount ro,commit=0
strace-c./a.out
将总结不同系统调用的执行时间。由于测试的不寻常I/O模式,可能还会导致性能问题。例如,尝试1000个不同的文件,这些文件可能夹杂着读取。如果您实际上在寻找更安全的数据保留(因为缺少更好的术语),我不确定禁用fs屏障是否是一个好的解决方案。