web-dev-qa-db-ja.com

CPUとハードドライブのパフォーマンスが限界に達していないにもかかわらず、gzipが遅いのはなぜですか?

gzipで圧縮したいJSONファイルがそれぞれ20 GBあります。

gzip file1.json

これには、1つの完全なCPUコアが必要です。

約25 MB /秒(atopでチェック)を処理し、私のハードドライブは125 MB /秒を読み取ることができ、3つの空きプロセッサコアを持っているため、複数のファイルを並列に圧縮するときにスピードアップが見込まれます。だから私は他の端末で実行します:

gzip file2.json
gzip file3.json
gzip file4.json

驚いたことに、私のスループットは向上しません。 CPUは各コアで約25%であり、私のHDはまだ25 MB /秒でしか読み取れません。

なぜ、どのように対処するのですか?

14
nh2

私はそれを見つけました:

その理由は、gzipが(最近のCPU速度とHDシーク速度の観点から)動作する非常に小さいバッファーサイズであるためです。

入力ファイルから数KBを読み取り、圧縮して、出力ファイルにフラッシュします。これにはハードドライブシークが必要なため、1秒あたりの操作数はわずかです。

私のパフォーマンスがスケーリングしなかった理由は、すでに1つのgzipが狂ったように求めていたためです。


私はunix buffer ユーティリティを使用してこれを回避しました:

buffer -s 100000 -m 10000000 -p 100 < file1.json | gzip > file1.json.gz

大量の入力をgzipに送信する前にバッファリングすることにより、小さなシークの数を劇的に減らすことができます。オプション:

  • -sおよび-mは、バッファのサイズを指定することです(I信じますKBですが、わかりません)
  • -p 100は、バッファが100%満たされたときにのみ、データがgzipに渡されることを確認します

これらのうち4つを並行して実行すると、期待どおりに4 * 25 MB/sのスループットが得られます。


なぜgzipではバッファーサイズを増やすことができないのでしょうか。この方法では、回転しているディスクで実行しても、ほとんど役に立ちません。

[〜#〜] edit [〜#〜]:さらにいくつかの圧縮プログラムの動作を試しました:

  • bzip2より強力な/より多くのCPU集中圧縮のため、2 MB /秒のみを処理します
  • lzopはより大きなバッファーを許可しているようです:コアあたり70 MB /秒、2つのコアで過剰シークなしにHDを最大化できます
17
nh2

MIT 6.172のOpenCourseware:ソフトウェアシステムのパフォーマンスエンジニアリング "の最初の5つほどの講義を見て、中程度の大きさのテストファイルでLinuxパフォーマンスアナライザー「perf」を実行しました。結果は、1つの命令が前の命令の結果を待たなければならないパイプラインストールを示しているように見えます。

       │         while (lookahead != 0) {                                                                
       │             /* Insert the string window[strstart .. strstart+2] in the                          
       │              * dictionary, and set hash_head to the head of the hash chain:                     
       │              */                                                                                 
       │             INSERT_STRING(strstart, hash_head);                                                 
  2.07 │       movzbl 0x8096d82(%edx),%eax                                                               
  3.99 │       mov    %edx,%ebp                                                                          
       │       shl    $0x5,%ecx                                                                          
  0.03 │       and    $0x7fff,%ebp                                                                       
  1.94 │       xor    %ecx,%eax                                                                          
  1.43 │       and    $0x7fff,%eax                                                                       
  2.01 │       mov    %eax,0x805e588                                                                     
  2.40 │       add    $0x8000,%eax                                                                      
  0.88 │       movzwl 0x8062140(%eax,%eax,1),%ecx                                                        
 23.79 │       movzwl %cx,%edi                                                                           
       │             /* Find the longest match, discarding those <= prev_length.  

最後から2番目の命令は%ecxへのコピーであり、最後の命令は%cxレジスタで使用できるデータが得られるまで待機する(パイプラインを停止する)必要があります。このパイプラインストールは、包含ループを保持します。

これは、いくつかの本当にあいまいな「古い」Cプログラミングスタイルの結果です。

3
user1295785

マルチコア/ハイパースレッディングCPUでさらに別のレベルの速度に引き上げるヒント:
(Ubuntuを想定)

Sudo apt-get install moreutils

moreutilsには、とりわけ「gnuパラレル」が含まれています。これには、CPUをより多く使用するのに役立つ多くのオプションがあります。

1
Hannu