1GB x1個と1kB×1,000,000個のコピーの所要時間の差を実測してみた

[NSSOL Advent Calendar 2019(その2)](https://qiita.com/advent-calendar/2019/nssol2)の12/2の記事です。

 ファイル数が多いディレクトリで、うっかりlsを打つとやたらと応答がもっさりするということを経験したり見聞きしたりされる方は結構いらっしゃるのではないかと思います。ファイル数が多いというのはそれだけで数の暴力となり、色々な処理を重たくする要因になるといわれているわけですが、実際問題としてどれくらいの影響があるのかしら？という点をファイルコピーで実験してみようというのがこの記事の趣旨です。

# 目次
- 実験内容：同じ容量のデータをファイルサイズとファイル数を変えてコピーして所要時間を測定しました
- 実験環境：今回の実験に用いた環境について説明します
- 実験結果：測定結果をもとに、ファイル数等の要員に応じて所要時間がどのように変化したのかをまとめます
- まとめ：実験結果をまとめます
- Appendix1：実験手順
- Appendix2：測定結果データ
- Appendix3：もう少しやってみたいこと
- 注釈一覧

## 実験内容
　今回の実験では、基本的なファイル操作(の一つ)として、ファイルのコピーに要する時間を測定しました。転送するデータの総量(ファイルサイズ×ファイル数)を一定値(1GB)に固定して、ファイル数を変えてコピーに要する時間を測定しています。今回の実験に用意したデータは以下のパターンとなります。

| № |     ファイル数      |    ファイルサイズ   |
|:-:|:------------------:|:------------------:|
|①|          1         |        1GB         |
|②|          4         |       256MB        |
|③|         16         |        64MB        |
|④|         64         |        16MB        |
|⑤|        256         |         4MB        |
|⑥|       1024         |        1MB         |
|⑦|       4096         |       256kB        |
|⑧|       16384        |        64kB        |
|⑨|       65536        |        16kB        |
|⑩|       262144       |         4kB        |
|⑪|      1048576       |         1kB        |

　実験では、移行元のファイルシステムに①～⑪のデータセットを用意した上で、移行元と異なるデバイス上のファイルシステムにデータをコピーしています。また、移行先のファイルシステムの条件を変えつつ何回か試行していますが、移行先のファイルシステムは都度フォーマットするようにしています。

## 実験環境
　今回の実験に用いた環境は以下の通りです。

- OS：Windows 10
- 移行元ストレージ：SSD(※機種・スペックの確認を忘れていました。後ほどアップデートします)
- 移行元ファイルシステム：NTFS
- 移行先ストレージ：HDD(※機種・スペックの確認を忘れていました。後ほどアップデートします)
- 移行先ファイルシステム：
  - A:NTFS(クラスターサイズ　4kB)
  - B:NTFS(クラスターサイズ　16kB)
  - C:NTFS(クラスターサイズ　64kB)
  - D:exFAT(※)

※exFATはフラッシュドライブに最適化されたファイルシステムといわれている[^1]ため、HDD上に作成するファイルシステムとしては適切ではないかもしれません。が、ファイルシステムの差異で処理時間がどの程度違ってくるのかを体感的に理解するためにNTFS以外のファイルシステムで、すぐに用意できたexFATで測定を実施してみました。(ReFSでも試してみたかったのですが準備が間に合わず…)

## 実験結果
### NTFSへのコピー
アロケーションユニットサイズを変えた3パターンのNTFSへのコピーの結果が下記のグラフとなります。縦軸、横軸ともに対数表示としています。

![graph1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297527/601122c1-010f-a954-e27e-bea1248b145d.png)

　今回用意したデータセットはすべてデータ量が1GBになるようにファイルを作成していますが、ファイル数が多くなるにしたがって、転送時間が延びる傾向が見て取れると思います。特にファイルサイズが1万を超えている範囲では転送時間とファイル数の関係はほぼリニアになっているように見受けられます。転送先ファイルシステムのクラスターサイズは、4kB(デフォルト)、16KB、64KkBの3パターンで測定してみましたが、今回の実験の範囲では大きな差異は現れませんでした。
※クラスターサイズよりも小さいファイルを転送している場合、クラスターギャップによる影響により差異が出るかと思ったのですが…1GBというデータ量が少なすぎたのかもしれません。
　ちなみに、ファイル数と転送時間との関係がほぼリニアになっている1万以上のファイル転送の領域で、グラフの傾きを線形近似で評価してみたところ、傾きは約0.003という結果が得られました。ファイルサイズに関係なくファイル1個あたり0.003秒程度の処理時間はかかるということを示唆しています。ファイル数が少ない場合には、無視してもよいレベルかもしれませんが、塵も積もれば山となるわけで、(転送するデータ量に対して)ファイル数が増えてくるとその寄与が無視できない大きさになってきます。

## exFATへのコピー
　exFATはフラッシュディスクに最適化されたファイルシステムといわれているため、HDD上に作った場合は良い結果は得られないだろうとは思っていましたが、結果は以下のグラフのようになりました。NTFSの結果と比較できるよう、NTFSのデータと重ねてプロットしています。

![graph3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297527/e6f04a9c-485a-f2bc-07bf-ed9c2f50d8b6.png)


　ファイル数が1000のあたりでexFATのグラフはNTFSのグラフと交差し、それよりファイル数が大きい領域ではNTFSと比較して急激に処理時間が延びています。書き込み先のHDDとしてはNTFSと同じものを使っているので、媒体の性能よりもファイルシステムの特性が所要時間により強く影響したことを示唆していると考えられます。exFATは、32GB以上の領域に対するデフォルトのクラスターサイズが128kBとNTFSよりも大きい[^2]ため、クラスターギャップの影響である可能性もありますが、クラスターサイズが64kBのNTFSでの結果と比べてもかなり所要時間がかかっているといえそうです。
※1kBのファイルでの処理時間はあまりに長くかかりそうだったので打ち切ってしまいました。
　一方で、ファイル数が1000未満の比較的大きいサイズのファイル(4MB～)のコピーに対しては、わずかながらNTFSよりも処理時間が短くなっているようにも見えます。(exFATについては試行回数が1回なので、もう少し試行回数を重ねて検証する必要はありますが)

# まとめ
　データの総量を固定しつつ、ファイルサイズとファイル数の組み合わせを変えて、コピーに掛かる所要時間を測定しました。結果、ファイル数が多くなるほど所要時間は伸びる傾向があり、特にファイルサイズが100kB未満のファイルを1万個以上コピーする場合には、データ量よりもファイル数が処理時間により強く影響を与える傾向を見て取ることができました。ファイル数による処理時間への影響は、データを転送する媒体の性能よりもファイルシステムの特性に強く依存するようです。


# Appendix1:実験手順
　今回の実験の準備、操作に用いた手順について説明します。
### データの準備
 転送に用いたデータはfsutil.exeを用いて作成しました。

`fsutil file createnew <filename> <SizeBytes>` 

　ただし、fsutilで作成されたファイルを読み込む場合には、実際にはディスクを読みにいかずに0データ容量分返す動作をするとのことなので、読み出し元のデータとしては、fsutilで作成したファイルを必要数分コピーして準備しています。読み出し元のファイルは、サイズごとにフォルダを分けて用意しました。

### 書き込み先ファイルシステムの準備
　今回の実験では試行のたびにファイルシステムをフォーマットしています。ファイル数が多いと削除にも時間がかかるので、フォーマットの方が早かったということと、ファイルシステムのメタデータ含めクリーンな状態で試行を行いたかったというのが理由です。ファイルシステムのフォーマットには、Windowsのディスクの管理メニューを使っています。

### 転送＆所要時間測定
　ファイルの転送には普通にcopyコマンドを使っています。前後にdateコマンドを挟むことで、サイズごとのコピー所要時間を測定しています。ただし、デフォルトのdateコマンドでは秒より細かい精度での時刻出力が得られないので、-formatオプションで小数第二位までを出力するようにしています。※ファイル数が少ないケースでは2-3秒で終わってしまうこともあったためです。

`date -format "yyyy/MM/dd hh:mm:ss.ff"`

# Appendix2：測定結果データ
　グラフだけでは読み取りにくい部分もあるかもしれませんので、測定結果の数値データ(各パターンの測定結果平均値)もまとめておきます。

|ファイル数|サイズ|NFTS<br>(64kB)|NFTS<br>(16kB)|NFTS<br>(4kB)|exFAT|
|:-:|:-:|:-:|:-:|:-:|:-:|
|1|1G|2.39 |2.34 |2.42 |2.39 |
|4|256M|2.46 |2.58 |2.51 |2.31 |
|16|64M|3.65 |4.71 |4.37 |2.42 |
|64|16M|5.05 |5.31 |7.18 |2.63 |
|256|4M|5.57 |6.29 |6.12 |3.74 |
|1024|1M|6.88 |9.18 |10.19 |6.49 |
|4096|256k|16.93 |18.11 |17.99 |23.27 |
|16384|64k|50.89 |54.66 |52.34 |215.62 |
|65536|16k|186.94 |176.89 |171.07 |2331.99 |
|262144|4k|709.68 |695.47 |693.12 |34135.68 |
|1048576|1k|3052.06 |3053.88 |3160.83 |N/A|




# Appendix3：もう少しやってみたいこと
　今回は、小さいファイルをたくさん処理すると時間がかかるね。を実験してみただけで終わってしまいましたが「じゃあ、どうすれば短い時間で処理を終えられるの？」に対する回答を考えてみたいと思っています。なんとなくですが、Windowsの場合にはVHDファイル上にデータを格納して、VHDファイルレベルでコピーしてしまえば、ファイルサイズ・ファイル数の影響を受けずにコピーをすることができるのではないかと予想しているので、そちらの実験についても追試できたら結果を追記しようと思っています。また、exFatをちゃんとしたフラッシュディスク上に構成した場合の結果や、Linuxで同様のことを試した場合の結果についてもやってみたい…とは思うものの、こちらは手ごろな実験環境が用意出来たら試してみたいと思います。

# 注釈一覧
[^1]:https://ja.wikipedia.org/wiki/ExFAT
[^2]:https://support.microsoft.com/ja-jp/help/140365/default-cluster-size-for-ntfs-fat-and-exfat