Por que o gzip é lento, apesar de o desempenho da CPU e do disco rígido não estar no máximo?


14

Eu tenho alguns arquivos JSON, 20 GB cada, com os quais desejo compactar gzip:

gzip file1.json

Isso ocupa um núcleo completo da CPU, tudo bem.

Ele processa cerca de 25 MB / s (com check-in atop), meu disco rígido pode ler 125 MB / se eu tenho 3 núcleos de processador gratuitos, portanto, espero acelerar quando comprimir vários arquivos em paralelo. Então eu corro em outros terminais:

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

Surpreendentemente, minha taxa de transferência não aumenta; A CPU é de cerca de 25% em cada núcleo, e meu HD ainda lê apenas 25 MB / s.

Por que e como lidar com isso?

Respostas:


17

Eu descobri:

O motivo é que gzipopera (em termos de velocidade da CPU versus velocidade de busca HD hoje em dia) tamanhos de buffer extremamente baixos .

Ele lê alguns KB do arquivo de entrada, o compacta e libera para o arquivo de saída. Dado que isso requer uma busca no disco rígido, apenas algumas operações podem ser realizadas por segundo.

A razão pela qual meu desempenho não foi dimensionado é porque já se gzipestava procurando como um louco.


Eu trabalhei em torno disso usando o bufferutilitário unix :

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

Armazenando em buffer muita entrada antes de enviá-la para o gzip, o número de pequenas buscas pode ser reduzido drasticamente. As opções:

  • -se -mdeve especificar o tamanho do buffer ( acredito que seja em KB, mas não tenho certeza)
  • -p 100 garante que os dados sejam passados ​​para o gzip apenas quando o buffer estiver 100% preenchido

Executando quatro deles em paralelo, eu poderia obter uma taxa de transferência de 4 * 25 MB / s, conforme o esperado.


Ainda me pergunto por que o gzip não permite aumentar o tamanho do buffer - dessa forma, é bastante inútil se for executado em um disco giratório.

EDIT : Tentei mais alguns comportamentos de programas de compactação:

  • bzip2 processa apenas 2 MB / s devido à sua compressão mais forte / intensiva da CPU
  • lzop parece permitir buffers maiores: 70 MB / s por núcleo e 2 núcleos podem maximizar meu HD sem procurar demais

Pode ddfazer o mesmo?
Simon Kuang

@SimonKuang Suspeito que ddpossa fazer o mesmo com sua bs=opção, sim.
Nh2 30/05

Parece uma coincidência interessante que, para um único arquivo, o tamanho do bloco utilizasse totalmente um único núcleo da CPU e as IOPS de uma unidade.
Dave L.

3

Depois de examinar as cinco primeiras palestras do MIT OpenCourseware para 6.172: "Engenharia de desempenho de sistemas de software", executei o analisador de desempenho Linux 'perf' em um arquivo de teste moderadamente grande. O resultado parece mostrar paradas no pipeline em que uma instrução precisa aguardar o resultado da anterior.

       │         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.  

A segunda última instrução está sendo copiada %ecxe a última precisa aguardar (paralisando o pipeline) até que o %cxregistro tenha dados prontos para uso. Essa parada do pipeline sustenta o loop de contenção.

Isso é resultado de algum estilo de programação C realmente "obscuro".


1

Uma dica que pode levar a outro nível de velocidade em uma CPU multi-core / hyperthreading:
(assumindo o Ubuntu)

sudo apt-get install moreutils

O moreutils contém, entre outras coisas, "gnu paralelo" - que tem muitas opções para ajudar a usar mais sua CPU.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.