Saya bertanya-tanya apakah mungkin untuk melakukan sesuatu yang lebih efisien daripada mendekompresi dari awal file sampai ke titik. Tampaknya jawabannya adalah tidak. Namun, pada beberapa CPU (Skylake) zcat | tail
tidak meningkatkan CPU hingga kecepatan jam penuh. Lihat di bawah. Decoder kustom dapat menghindari masalah itu dan menghemat panggilan sistem penulisan pipa, dan mungkin ~ 10% lebih cepat. (Atau ~ 60% lebih cepat di Skylake jika Anda tidak mengubah pengaturan manajemen daya).
Yang terbaik yang dapat Anda lakukan dengan zlib yang disesuaikan dengan a skipbytes
fungsi adalah mengurai simbol dalam blok kompresi untuk sampai ke akhir tanpa melakukan pekerjaan merekonstruksi blok dekompresi. Ini bisa lebih cepat secara signifikan (mungkin setidaknya 2x) daripada memanggil fungsi decode reguler zlib untuk menimpa buffer yang sama dan bergerak maju dalam file. Tapi saya tidak tahu apakah ada yang menulis fungsi seperti itu. (Dan saya pikir ini tidak benar-benar berfungsi kecuali file itu ditulis khusus untuk memungkinkan decoder untuk memulai kembali pada blok tertentu).
Saya berharap ada cara untuk melewati blok Deflate tanpa memecahkan kode mereka, karena itu akan jauh lebih cepat. Pohon Huffman dikirim pada awal setiap blok, sehingga Anda dapat memecahkan kode dari awal setiap blok (saya pikir). Oh, saya pikir negara decoder lebih dari pohon Huffman, itu juga 32kiB data yang diterjemahkan sebelumnya, dan ini tidak diatur ulang / dilupakan melintasi batas blok secara default. Byte yang sama dapat terus dirujuk berulang kali, jadi mungkin hanya muncul sekali dalam satu file terkompresi raksasa. (mis. dalam file log, nama host mungkin tetap "panas" dalam kamus kompresi sepanjang waktu, dan setiap contoh merujuk pada yang sebelumnya, bukan yang pertama).
The zlib
pengguna mengatakan Anda harus menggunakan Z_FULL_FLUSH
saat memanggil deflate
jika Anda ingin aliran dikompresi menjadi seekable ke titik itu. Ini "me-reset kondisi kompresi", jadi saya pikir tanpa itu, referensi mundur dapat masuk ke blok sebelumnya. Jadi kecuali file zip Anda ditulis dengan blok full-flush sesekali (seperti setiap 1G atau sesuatu akan memiliki dampak yang dapat diabaikan pada kompresi), saya pikir Anda harus melakukan lebih banyak pekerjaan pengodean ulang ke titik yang Anda inginkan daripada yang saya awalnya berpikir. Saya kira Anda mungkin tidak dapat memulai di awal blok apa pun.
Sisa dari ini ditulis ketika saya berpikir mungkin untuk menemukan awal dari blok yang berisi byte pertama yang Anda inginkan, dan decode dari sana.
Namun sayangnya, awal blok Deflate tidak menunjukkan berapa lama , untuk blok terkompresi. Data yang tidak dapat dikompres dapat dikodekan dengan tipe blok terkompresi yang memiliki ukuran 16-bit dalam byte di depan, tetapi blok terkompresi tidak: RFC 1951 menggambarkan format yang cukup mudah dibaca . Blok dengan pengkodean Huffman dinamis memiliki pohon di bagian depan blok (sehingga decompressor tidak harus mencari dalam aliran), sehingga kompresor harus menyimpan seluruh (terkompresi) blok dalam memori sebelum menulisnya.
Jarak referensi mundur maksimum hanya 32kiB, sehingga kompresor tidak perlu menyimpan banyak data yang tidak terkompresi dalam memori, tetapi itu tidak membatasi ukuran blok. Panjang blok bisa beberapa megabyte. (Ini cukup besar untuk disk mencari nilai bahkan pada drive magnetik, vs. membaca sekuensial ke dalam memori dan hanya melewatkan data dalam RAM, jika mungkin untuk menemukan akhir dari blok saat ini tanpa menguraikannya).
zlib membuat blok selama mungkin:
Menurut Marc Adler , zlib hanya memulai blok baru ketika buffer simbol terisi, yang dengan pengaturan default adalah 16.383 simbol (literal atau korek api)
Saya gzip output seq
(yang sangat berlebihan dan dengan demikian mungkin bukan tes yang bagus), tetapi pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -c
hanya berjalan pada ~ 62 MiB / s data terkompresi pada Skylake i7-6700k di 3,9GHz, dengan DDR4-2666 RAM. Itu 246MiB / s dari data yang terkompresi, yang merupakan perubahan besar dibandingkan dengan memcpy
kecepatan ~ 12 GiB / s untuk ukuran blok yang terlalu besar untuk disimpan dalam cache.
(Dengan energy_performance_preference
set ke default balance_power
sebagai gantinya balance_performance
, gubernur CPU internal Skylake memutuskan untuk hanya berjalan pada 2.7GHz, ~ 43 MiB / s data terkompresi. Saya gunakan sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'
untuk mengubah itu. Mungkin panggilan sistem yang sering seperti itu tidak terlihat seperti terikat CPU nyata bekerja ke unit manajemen daya.)
TL: DR: zcat | tail -c
adalah CPU yang terikat bahkan pada CPU yang cepat, kecuali jika Anda memiliki disk yang sangat lambat. gzip menggunakan 100% CPU yang digunakannya (dan menjalankan 1,81 instruksi per jam, menurut perf
), dan tail
menggunakan 0,162 CPU yang digunakannya (0,58 IPC). Sistem itu sebagian besar menganggur.
Saya menggunakan Linux 4.14.11-1-ARCH, yang memiliki KPTI diaktifkan secara default untuk bekerja di sekitar Meltdown, jadi semua write
panggilan sistem di gzip
lebih mahal daripada sebelumnya: /
Memiliki pencarian bawaan untuk unzip
atau zcat
(tetapi masih menggunakan zlib
fungsi decode biasa ) akan menyimpan semua pipa tersebut, dan akan membuat CPU Skylake berjalan pada kecepatan jam penuh. (Ini downclocking untuk beberapa jenis beban adalah unik untuk Intel Skylake dan kemudian, yang memiliki beban pengambilan keputusan frekuensi CPU dari OS, karena mereka memiliki lebih banyak data tentang apa yang CPU lakukan, dan dapat meningkatkan / menurunkan lebih cepat. Ini adalah biasanya baik, tetapi di sini mengarah ke Skylake yang tidak mencapai kecepatan penuh dengan pengaturan gubernur yang lebih konservatif).
Tidak ada panggilan sistem, hanya menulis ulang buffer yang sesuai dengan cache L2 sampai Anda mencapai posisi byte awal yang Anda inginkan, mungkin akan membuat perbedaan setidaknya beberapa%. Mungkin bahkan 10%, tapi saya hanya membuat angka di sini. Saya belum memprofilkan zlib
detail untuk melihat seberapa besar jejak cache yang dimilikinya, dan seberapa banyak TLB flush (dan dengan demikian uop-cache flush) pada setiap panggilan sistem sakit dengan KPTI diaktifkan.
Ada beberapa proyek perangkat lunak yang menambahkan indeks pencarian ke format file gzip . Ini tidak membantu Anda jika Anda tidak dapat membuat siapa pun menghasilkan file terkompresi yang dapat dicari untuk Anda, tetapi pembaca lain di masa mendatang mungkin mendapat manfaat.
Agaknya tak satu pun dari proyek-proyek ini memiliki fungsi decode yang tahu bagaimana untuk melewati melalui aliran Deflate tanpa indeks, karena mereka hanya dirancang untuk bekerja ketika indeks adalah tersedia.