web-dev-qa-db-ja.com

最後にgunzip to ddパイプラインが遅くなるのはなぜですか?

私のコマンド:

gunzip -c serial2udp.image.gz |
Sudo dd of=/dev/mmcblk0 conv=fsync,notrunc status=progress bs=4M

私の出力:

15930949632 bytes (16 GB, 15 GiB) copied, 1049 s, 15.2 MB/s    

0+331128 records in
0+331128 records out
15931539456 bytes (16 GB, 15 GiB) copied, 1995.2 s, 8.0 MB/s

カード:最大30MB/sのSanDisk Ultra 32GB MicroSDHC Class 10 UHSメモリカード
配布:16.0.4 xenial with xfce
カーネルバージョン:4.13.0.37-generic

私が読んだことから、17分かかるのは妥当だと思います。ブロックサイズで遊んでも実際には大きな違いはないようです(bs = 100Mでも同様のタイムスタンプでこの動作を示します)。更新がハングし、さらに16分間の完成したレポートが生成されないのはなぜですか?

iotopは、mmcqd/0がこの時点で(99%IOで)バックグラウンドでまだ実行中であることを教えてくれるので、最後の5MBを保持しているキャッシュがどこかにあると思いますが、fsyncはそれが起こらないようにする必要があると思いましたこの時点では、iotopはddのトラフィックの交差を示していません。 ctrl-cはほとんど役に立たず、書き込み後にドライブを破損したくありません。

5
cts

最後の5MBを保持しているキャッシュがどこかにあると思いますが、fsyncはそれが起こらないようにする必要があると思いました

_conv=fsync_は、fsyncがすべてのデータを書き込んだ後、ddを呼び出してキャッシュを書き戻すことを意味します。最後にぶら下がることはまさにそれがすることです。

出力ファイルが入力ファイルより遅い場合、ddによって書き込まれたデータがキャッシュに蓄積される可能性があります。カーネルキャッシュは、システムRAMのかなりの部分を占めることがあります。これは、非常に誤解を招く進行情報になります。あなたの「最終的な5MB」は、ddがどのように進捗状況を示しているかの単なる人工物でした。

システムが実際に約8 GBをキャッシュしていた場合(つまり、16 GBの書き込みデータの半分)、約32 GBのRAMが必要か、特定のカーネルオプションをいじっていたと思います。以下のlwn.netリンクを参照してください。 15分間進行状況情報を取得しないことはかなりイライラすることに同意します。

使用できる代替のddコマンドがあります。 ddでより正確な進行状況を表示したい場合は、より複雑なものを受け入れる必要があるかもしれません。現実には私以外の考えがあるかもしれませんが、以下はあなたのパフォーマンスを低下させることなく機能すると思います。

_gunzip -c serial2udp.image.gz |
dd iflag=fullblock bs=4M |
Sudo dd iflag=fullblock oflag=direct conv=fsync status=progress bs=4M of=/dev/mmcblk0
_
  • _oflag=direct iflag=fullblock_は、完全にバイパスするため、カーネルキャッシュの蓄積を回避します。
  • そのようなコマンドAFAIKでは_iflag=fullblock_が必要です(たとえば、パイプから読み取り、直接IOを使用して書き込むため)。 fullblockがないことによる影響は、ddのもう1つの残念な複雑さです。このサイトの一部の投稿では、これを使用して、常に別のコマンドを使用することを優先する必要があると主張しています。 IOただし、直接または同期する別の方法を見つけるのは難しいです。
  • deviceキャッシュを書き戻すには、_conv=fsync_を引き続き使用する必要があります。
  • ddの後に追加のgunzipを追加して、解凍された出力をディスクの書き込みと並行してバッファリングしました。これは、_oflag=direct_または_oflag=sync_でのパフォーマンスを少し複雑にする問題の1つです。通常IO(non-direct、non-sync)は、カーネルキャッシュによって既にバッファーされているため、これを必要とすることは想定されていません。 4Mのライトバックキャッシュを備えたハードドライブですが、SDカードにそれほど多くの容量があるとは思いません。

あるいは、_oflag=direct,sync_を使用することもできます(_conv=fsync_は必要ありません)。 数百メガバイトのキャッシュ を備えた奇妙な出力デバイスがある場合、これは良い進行状況の情報に役立ちます。しかし、通常、私は_oflag=sync_をパフォーマンスへの潜在的な障壁と考えています。

2013年の記事があります https://lwn.net/Articles/572911/ は、あなたのような1分間の遅延について述べています。多くの人は、分単位のライトバックデータをキャッシュするこの機能を望ましくないと考えています。問題は、キャッシュサイズの制限が高速デバイスと低速デバイスの両方に無差別に適用されることでした。カーネルがデバイスの速度を測定することは、データの場所によって異なるため、重要ではないことに注意してください。例えば。キャッシュされた書き込みがランダムな場所に分散している場合、ハードドライブは書き込みヘッドを繰り返し移動するのに時間がかかります。

更新がハングする理由

fsync()は、すべての範囲に適用される単一のシステムコールです。 ファイル 端末。完了する前に、ステータスの更新は返されません。

14
sourcejedi

fullblockを使用したい。 notruncはデバイスファイルには影響しません。

dd of=/dev/mmcblk0 iflag=fullblock status=progress bs=4M
0
RalfFriedl

そのようなものとしての答えではなく、より多くの診断です。パイプビューutil pv を使用して、パイプフローのそれぞれの速度がどのようになっているかを確認します

pv -c -N raw serial2udp.image.gz |
gunzip |
pv -c -N uncompressed |
Sudo dd of=/dev/mmcblk0 conv=fsync,notrunc status=progress bs=4M

仮説:

  1. 最後に速度が低下する場合は、.gzファイルは最後に最も圧縮されているか、そうでなければgunzipに追加の作業を与えています。
  2. 別の可能性としては、書き込みメディア自体が一部の部分で遅くなっている可能性があります。これは、おそらくデザインの特殊性や、不良ブロックや限界ブロックが原因である可能性があります。非破壊的な読み取り/書き込みテストはbadblocks -nv /dev/mmcblk0
0
agc