Почему gzip работает медленно, несмотря на то, что производительность процессора и жесткого диска не доведена до максимума?

14

У меня есть несколько файлов JSON по 20 ГБ каждый, которые я хочу сжать gzip:

gzip file1.json

Это занимает одно полное ядро ​​процессора, все хорошо.

Он обрабатывает около 25 МБ / с (проверено atop), мой жесткий диск может считывать 125 МБ / с, и у меня есть 3 свободных процессорных ядра, поэтому я ожидаю ускорения при сжатии нескольких файлов параллельно. Итак, я бегу в других терминалах:

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

Удивительно, но моя пропускная способность не увеличивается; Процессор составляет около 25% на каждое ядро, а мой HD все еще читает только со скоростью 25 МБ / с.

Почему и как это решить?

NH2
источник

Ответы:

17

Я узнал это:

Причина заключается в том, что gzipработает (с точки зрения скорости процессора и скорости поиска HD в наши дни) очень низкие размеры буфера .

Он считывает несколько килобайт из входного файла, сжимает его и сбрасывает в выходной файл. Принимая во внимание тот факт, что для этого требуется поиск по жесткому диску, в секунду можно выполнить всего несколько операций.

Причина, по которой мое выступление не масштабировалось, в том, что он уже gzipискал как сумасшедший.


Я работал с этим с помощью bufferутилиты Unix :

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

Буферизуя большую часть ввода перед отправкой в ​​gzip, количество маленьких запросов может быть значительно уменьшено. Варианты:

  • -sи -mдолжны указать размер буфера (я считаю, что это в КБ, но не уверен)
  • -p 100 гарантирует, что данные передаются в gzip только после заполнения буфера на 100%

Запустив четыре из них параллельно, я мог получить пропускную способность 4 * 25 МБ / с, как и ожидалось.


Мне все еще интересно, почему gzip не позволяет увеличивать размер буфера - таким образом, это довольно бесполезно, если он запускается на вращающемся диске.

РЕДАКТИРОВАТЬ : я опробовал еще несколько программ сжатия поведения:

  • bzip2 обрабатывает только 2 МБ / с благодаря более сильному / более интенсивному сжатию ресурсов процессора
  • lzop Похоже, что он позволяет увеличивать буферы: 70 МБ / с на ядро, а 2 ядра могут максимально использовать мой HD без чрезмерного поиска
NH2
источник
Можно ddсделать то же самое?
Симон Куанг
@ SimonKuang Я подозреваю, что ddможет сделать то же самое с его bs=опцией, да.
nh2
Звучит как интересное совпадение, что для одного файла размер блока в полной мере использовал как одно ядро ​​процессора, так и IOPS диска.
Дейв Л.
3

Посмотрев первые пять или около того лекций в MIT OpenCourseware для 6.172: «Разработка производительности программных систем», я запустил анализатор производительности Linux «perf» на умеренно большом тестовом файле. Результат, по-видимому, показывает конвейерные остановки, где одна инструкция должна ждать результата предыдущей.

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

Вторая последняя инструкция копируется в, %ecxа последняя должна ждать (останавливая конвейер), пока %cxрегистр не получит данные, готовые к использованию. Этот трубопроводный конвейер удерживает вмещающую петлю.

Это результат какого-то действительно неясного стиля программирования на языке С.

user1295785
источник
1

Совет, который может привести его к еще одному уровню скорости на многоядерном / гиперпоточном процессоре:
(при условии Ubuntu)

sudo apt-get установить moreutils

Moreutils содержит, помимо прочего, «gnurallel» - в нем много опций, помогающих использовать больше вашего процессора.

Ханну
источник