Tại sao gzip chậm mặc dù CPU và hiệu năng ổ cứng không được tối đa hóa?


14

Tôi có một số tệp JSON, mỗi tệp 20 GB mà tôi muốn nén bằng gzip:

gzip file1.json

Điều này chiếm một lõi CPU đầy đủ, tất cả đều tốt.

Nó xử lý khoảng 25 MB / s (đã đăng ký atop), ổ cứng của tôi có thể đọc 125 MB / s và tôi có 3 lõi bộ xử lý miễn phí, vì vậy tôi hy vọng sẽ tăng tốc khi nén song song nhiều tệp. Vì vậy, tôi chạy trong các thiết bị đầu cuối khác:

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

Đáng ngạc nhiên, thông lượng của tôi không tăng; CPU là khoảng 25% trên mỗi lõi và HD của tôi vẫn chỉ đọc ở tốc độ 25 MB / s.

Tại sao và làm thế nào để giải quyết nó?

Câu trả lời:


17

Tôi tìm thấy nó:

Lý do là gziphoạt động trên (về tốc độ CPU so với tốc độ tìm kiếm HD hiện nay) kích thước bộ đệm cực thấp .

Nó đọc một vài KB từ tệp đầu vào, nén nó và xóa nó sang tệp đầu ra. Với thực tế là điều này đòi hỏi phải tìm kiếm ổ cứng, chỉ một vài thao tác có thể được thực hiện mỗi giây.

Lý do hiệu suất của tôi không mở rộng là vì đã có người gziptìm kiếm như điên.


Tôi đã giải quyết vấn đề này bằng cách sử dụng buffertiện ích unix :

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

Bằng cách đệm rất nhiều đầu vào trước khi gửi nó đến gzip, số lượng tìm kiếm nhỏ có thể giảm đáng kể. Các tùy chọn:

  • -s-mphải chỉ định kích thước của bộ đệm (tôi tin rằng nó được tính bằng KB, nhưng không chắc chắn)
  • -p 100 đảm bảo rằng dữ liệu chỉ được chuyển đến gzip sau khi bộ đệm được lấp đầy 100%

Chạy song song bốn trong số này, tôi có thể nhận được thông lượng 4 * 25 MB / s, như mong đợi.


Tôi vẫn tự hỏi tại sao gzip không cho phép tăng kích thước bộ đệm - theo cách này, nó khá vô dụng nếu chạy trên đĩa quay.

EDIT : Tôi đã thử một vài hành vi chương trình nén:

  • bzip2 chỉ xử lý 2 MB / s do nén mạnh hơn / nhiều CPU hơn
  • lzop dường như cho phép bộ đệm lớn hơn: 70 MB / s mỗi lõi và 2 lõi có thể tối đa hóa HD của tôi mà không cần tìm kiếm quá nhiều

Có thể ddlàm như vậy?
Simon Kuang

@SimonKuang Tôi nghi ngờ rằng ddcó thể làm tương tự với bs=tùy chọn của nó , vâng.
nh2

Nghe có vẻ như một sự trùng hợp thú vị rằng đối với một tệp duy nhất, kích thước khối đã sử dụng hoàn toàn cả lõi CPU đơn và IOPS của ổ đĩa.
Dave L.

3

Sau khi xem năm bài giảng đầu tiên trong MIT OpenC thảo luận cho 6.172: "Kỹ thuật hiệu suất của các hệ thống phần mềm", tôi đã chạy bộ phân tích hiệu suất Linux 'perf' trên một tệp thử nghiệm lớn vừa phải. Kết quả xuất hiện để hiển thị các quầy hàng đường ống trong đó một lệnh phải chờ kết quả của một lệnh trước đó.

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

Lệnh cuối cùng thứ hai là sao chép %ecxvà lệnh cuối cùng phải chờ (tạm dừng đường ống) cho đến khi thanh %cxghi có dữ liệu sẵn sàng để sử dụng. Gian hàng đường ống này giữ vòng lặp chứa.

Đây là kết quả của một số phong cách lập trình C 'trường học cũ' tối nghĩa.


1

Một mẹo có thể đưa nó đến một mức tốc độ khác trên CPU đa lõi / siêu phân luồng:
(giả sử Ubuntu)

sudo apt-get cài đặt thêmututils

moreutils chứa trong số những thứ khác "gnu song song" - có rất nhiều tùy chọn để giúp sử dụng nhiều CPU của bạn hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.