Vista のファイルコピーが遅い件について

id:NyaRuRu:20070731:p1 で紹介した KB938979 絡みでついでに書いておきます.
Windows Vista 環境で大量のファイルコピーが遅くなる問題については,単一の現象ではなく,いくつかの同じような結果を引き起こす複数の原因があって,それらの重ね合わせではないかと個人的には思っています.もし自分の環境で似たような問題が発生した場合は,ある程度下調べをしてから対策をとった方が良いでしょう.もちろん,基本は KB938979 の登場を待つで OK でしょうけど.

Bufferd I/O VS Unbufferd I/O

まず 1 つ目のポイントですが,TechNet blog の以下の記事では,巨大なファイルをネットワーク越しに転送する場合,CopyFile や CopyFileEx といった Buffered I/O よりも,Unbufferd I/O の方が好ましいと述べられています.

Unbuffered I/O (or a raw file copy) is preferred when attempting to copy a large file from one location to another when we do not intend to access the source file after the copy is complete. This will avoid the file system cache overhead and prevent the file system cache from being effectively flushed by the large file data. Many applications accomplish this by calling CreateFile() to create an empty destination file, then using the ReadFile() and WriteFile() functions to transfer the data.

なお,Process Monitor でモニタリングするときには,CopyFile や CopyFileEx というオペレーションが存在しないことには注意しておきましょう.CopyFile や CopyFileEx も内部では ReadFile や WriteFile を使うことがあるため,ログの結果に ReadFile や WriteFile が出てくるかを見るだけでは十分な調査とは言えません.ネットワーク越しの巨大ファイルコピーでは,これらの API を「Unbufferd の形で使っているか」がポイントになるようです.

TCP 受信ウィンドウ自動チューニング

この他に考えられる要因ですが,Vista で導入された「TCP 受信ウィンドウ自動チューニング」の影響で,ネットワーク層での転送帯域が影響を受けているという可能性があります.「TCP 受信ウィンドウ自動チューニング」については,TechNet Magazine の記事がおすすめです.

Microsoft Live OneCare の可能性?

もうひとつの可能性,というかこれは実際に手元の環境で何度も見ている現象です.
以前 Vista でファイル操作が遅いことがあるなぁと不審に思って,Process Monitor で調べてみたことがあるのですが,そのときはなんと,CreateFile が呼び出された瞬間から,実際の結果が戻るまでに,分単位の遅延が発生していました.
この場面でアプリケーションを責めるのはちょっと気の毒です.さすがに,ローカル HDD 上のファイルに対する CreateFile が,分単位のブロックというのは,普通想像しないよなぁと*1
んで,リソースモニタを見ると,この現象が起きるときは MsMpEng.exe が同じファイルへのアクセスを行っていたことから,どうも Live OneCare のウィルス検査の副作用という可能性が高いんじゃなかろうかと.もしそうであれば,濫用された AOP の悲劇にも見えますね.分単位で必要な処理は,CreateFile といった基本的な処理に単純に割り込ませられるものではなく,もっと抜本的に処理フローを検討し直すべき要求でしょう.これはいずれもっとちゃんと原因を調べたいと思います.OneCare のせいであれば,別に Vista 固有の問題というわけでもないかもしれません.

Vista Multimedia Playback によるネットワークパケット数制限

(追記)
Vista Multimedia Playback and Network Throughput』で Mark Russinovich 氏が解説されているように,MMCSS*2 の Multimedia Playback に属するプロセスが存在するときに,ネットワークドライバが受け取るパケット数が 10,000 パケット/秒に制限されるそうです.
イーサネットの標準的なパケットサイズは 1500 bytes なので,100 Mbps のイーサネット環境では,少なくとも 12 MB/sec の速度は得られるはずです.
なお,バグにより,2 つのネットワークアダプタが存在すると (ひとつのアダプタの?) 制限値が 8,000 パケット/秒に,3 つのネットワークアダプタが存在すると (ひとつのアダプタの?) 制限値が 6,000 パケット/秒にそれぞれ低下するとのことです.

まとめ

ひとつ言えるのは,あなたが開発者であれば,自分の作っている製品がこの問題に遭遇する可能性があったかもしれない,ということです.その点に限っていえば,これは単なる「イライラする現象」では済まされないものがあります.
私といえば,もちろんイライラはするのですが,一方でこういった有名 OS での不具合の裏話も大好きで,自分が普段行っているプログラミングの内容とはあまり関係がなくても,見つけるとついつい読みふけってしまいます.トラブルシュート系 MS blog で,おすすめをいくつか挙げておきますので,興味がある方はぜひ空いた時間にでも読み漁ってみてください.

  • Mark's Blog』言わずとしれた Mark Russinovich 氏の blog です.
  • Microsoft Advanced Windows Debugging and Troubleshooting』 Inside Windows 級の超大エントリが続くため,私は読み始める前にコーヒーとお菓子を用意しています.
  • Mike Stall's .NET Debugging BlogCLR の特徴のひとつが,豊富なデバッグ基盤技術なのですが,Visual Studio から使える以上の機能が実際には眠っていることは,案外と知られていません.まああんまり過ぎたデバッグ知識を持っていても,幸せになれるかどうかはまた別問題なのですが,それが身を救うこともあると思えばこの blog もぜひチェックしておきましょう.
  • Ask the Performance Team』先ほどもでてきた,TechNet blog のひとつです.身近な問題が多く取り上げられているので,助けられる度は案外高いかもしれません.

*1:とはいえ,「ブラウザ内のアプリケーションよりも,デスクトップアプリケーションの方がよりリッチなユーザーエクスペリエンスを……」と主張するのであれば,当然こういう細かい同期アクセスも気を配って,ひとつひとつ潰していくべきでしょうが……

*2:id:NyaRuRu:20060910