7

テストプログラムがあります。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
4

2 に答える 2

8

カーネル3.1。*は実際に同期を行っており、3.0.18はそれを偽造しています。あなたのコードは1,000回の同期書き込みを行います。ファイルを切り捨てるので、書き込むたびにファイルも拡大されます。つまり、実際には2,000回の書き込み操作があります。一般的なハードドライブの書き込み遅延は、I/Oあたり約20ミリ秒です。したがって、2,000 * 20=40,000ミリ秒または40秒です。したがって、一般的なハードドライブに書き込んでいると仮定すると、それはほぼ正しいように思われます。

基本的に、各書き込みの後に同期することにより、カーネルに書き込みを効率的にキャッシュまたはオーバーラップさせ、すべての操作で最悪の場合の動作を強制する機能を与えません。また、ハードドライブは、データが書き込まれる場所とメタデータが書き込まれる場所の間を行き来する必要があります。

于 2012-01-16T04:25:16.650 に答える
2

理由が見つかりました。Linux カーネル 3.1 (http://kernelnewbies.org/Linux_3.1) の ext3 では、ファイル システム バリアがデフォルトで有効になっています。バリアを無効にすると、はるかに高速になります。

于 2012-01-17T00:12:40.497 に答える