rsync で削除すると速い (?) 件

https://twitter.com/matsuu/statuses/340655491917152257
http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html

ちょっと気になったので試したけどそんな差がでなかった。もうちょい調べたいとこだが時間切れで途中までのメモ。
(追記: つづきを http://d.hatena.ne.jp/ichii386/20130602/1370112280 に書きました。)

環境

  • solaris11.1
  • zfs
  • rm: coreutils-8.21, ふつうに gcc-4.5 で ./configure && make しただけ
  • rsync: rsync-3.0.9, coreutils 同様
  • 空の zfs で ``mkdir aho && cd aho && seq 1000000 | xargs -n100 touch'' した状態

だいたい以下のような感じで実行した。

% sudo dtrace -s ~/aho.d -c 'ptime -m /home/ichii386/opt/bin/rm -rf a' 2>&1 | tee ~/rm-rf.out
@aho[pid, tid, probefunc] = sum(timestamp - self->start[pid, tid, probefunc]);

なお rsync はローカル間の rsync であっても、親から送信元/送信先用に 2 つ子プロセスを作ることに注意。なので pid が必要。 tid は不要だが入れただけ。

syscall

  • rm -rf
real     2:01.505976414
user        2.769709176
sys        55.723185817
trap        0.001915214
tflt        0.000000000
dflt        0.000000000
kflt        0.000000000
lock        0.000000000
slp      1:00.229405966
lat         2.781001128
stop        0.000432667
(中略)
    23225        1  openat64                                                      67380
    23225        1  brk                                                        34923152
    23225        1  fstatat64                                               26603970151
    23225        1  unlinkat                                                27208982573
    23225        1  getdents64                                              54917440620

(カラムは順に pid, tid, probefunc, sum)

real     1:36.321831952
user        2.637288864
sys      1:06.216847212
trap        0.000469720
tflt        0.000000000
dflt        0.000000000
kflt        0.000000000
lock        0.000000000
slp      3:39.204833186
lat         0.813593332
stop        0.000393367
(中略)
    23205        1  brk                                                         4543719
    23205        1  pollsys                                                    23666804
    23205        1  fstatat64                                               22882608802
    23205        1  getdents64                                              24778032557
    23205        1  unlinkat                                                35046337825
    23206        1  pollsys                                                 96253638085
    23204        1  pollsys                                                 96312023834

rm -rf に比べ 30sec ほど速いが、 getdents64 が 30sec ほどなので、それが原因ぽい。 (pid=23204, 23026 の pollsys はただ待ってるだけ)

getdents64 の分布

sum() を quantize() した結果:

  • rm -rf
           value  ------------- Distribution ------------- count
            4096 |                                         0
            8192 |                                         1
           16384 |                                         0
           32768 |                                         1
           65536 |                                         0
          131072 |                                         0
          262144 |                                         1
          524288 |                                         0
         1048576 |@@@@@@                                   568
         2097152 |@                                        111
         4194304 |@@@@@@@                                  689
         8388608 |@@@@@@@@@@@@@@@                          1463
        16777216 |@@@@@@@                                  699
        33554432 |@@                                       232
        67108864 |                                         39
       134217728 |                                         8
       268435456 |                                         4
       536870912 |                                         0
      1073741824 |                                         1
      2147483648 |                                         0
           value  ------------- Distribution ------------- count
            2048 |                                         0
            4096 |                                         1
            8192 |                                         0
           16384 |                                         1
           32768 |                                         0
           65536 |                                         0
          131072 |                                         0
          262144 |                                         0
          524288 |                                         2
         1048576 |@@@@@@@@@@@@@@@@@@@@@@@@                 2317
         2097152 |@@@@                                     364
         4194304 |@@@                                      270
         8388608 |@@@@@                                    463
        16777216 |@@@                                      265
        33554432 |@                                        121
        67108864 |                                         10
       134217728 |                                         1
       268435456 |                                         0
       536870912 |                                         1
      1073741824 |                                         0

感想

rsync は最初にファイルの一覧作ってから削除するだけだけど、 rm の場合は消しながら「ディレクトリが空になったか」を検査してるのかな?

...と思ったけど、だとすれば getdents の回数が変わるはずなんだけど、同じなんだよね。 rm のほうがバラついてるし、 とすると消してる間にディレクトリの中身が変わるから readdir にかかるコストが安定しないとか?