2012-01-16 5 views
7

私はテストプログラムを持っています。 Linuxカーネル3.1。*では約37秒かかりますが、カーネル3.0.18では約1秒しかかかりません(以前と同じマシンでカーネルを置き換えています)。カーネル3.1の改善方法を教えてください。ありがとう!fsync()がカーネル3.0よりもLinuxカーネル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 
+0

減速の原因となるfsync()はどのようにわかりますか? open()呼び出しであってもかまいません。 –

+0

問題のファイルシステムで使用している 'mount'オプションは何ですか? (ちなみに、私の2.6.38-12ジェネリックカーネル、Ubuntuでは 'ext3'ファイルシステム、' rw、errors = remount-ro、commit = 0'で約1.5秒かかります) – sarnold

+0

'strace -c ./a。システムコールの実行時間を要約する。 – sarnold

答えて

8

カーネル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でデフォルトで有効になっているファイルシステムのバリア。障壁を無効にしたら、はるかに速くなります。

+0

テストの珍しいI/Oパターンのため、パフォーマンスの問題が発生している可能性もあります。例えば1000個の異なるファイルを試してみてください。実際にデータのより安全な保持(より良い用語が不足している)を探しているなら、fsの障壁を無効にすることは良い解決策であるかどうかはわかりません。 – ergosys

関連する問題