【问题标题】:Why fsync() takes much more time on Linux kernel 3.1.* than kernel 3.0为什么 fsync() 在 Linux 内核 3.1.* 上比内核 3.0 花费更多时间
【发布时间】:2012-01-16 04:16:18
【问题描述】:

我有一个测试程序。在 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

【问题讨论】:

  • 你怎么知道是 fsync() 导致了减速?也可能是 open() 调用。
  • 您在相关文件系统上使用了哪些mount 选项? (顺便说一句,在我的 Ubuntu 的 2.6.38-12-generic 内核上大约需要 1.5 秒;ext3 文件系统,rw,errors=remount-ro,commit=0。)
  • strace -c ./a.out 会汇总不同系统调用的执行时间。

标签: linux-kernel fsync


【解决方案1】:

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

基本上,通过在每次写入后进行同步,您使内核无法有效地缓存或重叠写入,并在每个操作上强制执行最坏情况的行为。此外,硬盘驱动器最终不得不在每次写入数据的位置和写入元数据的位置之间来回寻找。

【讨论】:

    【解决方案2】:

    找到原因了。 Linux 内核 3.1 (http://kernelnewbies.org/Linux_3.1) 在 ext3 中默认启用文件系统屏障。禁用障碍后,它变得更快。

    【讨论】:

    • 您的测试的异常 I/O 模式也可能导致性能问题。例如,尝试 1000 个不同的文件,这些文件可能穿插着读取。如果您实际上正在寻找更安全的数据保留(因为没有更好的术语),我不确定禁用 fs 屏障是一个好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2017-04-08
    • 2013-04-10
    • 2011-11-05
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 1970-01-01
    相关资源
    最近更新 更多