ฉันสงสัยว่ามันเป็นไปได้หรือไม่ที่จะทำสิ่งใดให้มีประสิทธิภาพมากกว่าการคลายการบีบอัดจากจุดเริ่มต้นของไฟล์จนถึงจุด ปรากฏว่าคำตอบคือไม่ อย่างไรก็ตามในบางซีพียู (Skylake) zcat | tail
ไม่ได้เพิ่มความเร็วของนาฬิกาจนเต็ม ดูด้านล่าง ตัวถอดรหัสที่กำหนดเองสามารถหลีกเลี่ยงปัญหานั้นและบันทึกการเรียกใช้การเขียนไปป์ของระบบและอาจเร็วกว่า ~ 10% (หรือเร็วกว่า ~ ~ ~ ~ ~ ~ ~ ~ 60% สำหรับ Skylake หากคุณไม่ได้ปรับแต่งการตั้งค่าการจัดการพลังงาน)
สิ่งที่ดีที่สุดที่คุณสามารถทำได้ด้วย zlib ที่กำหนดเองด้วยskipbytes
ฟังก์ชั่นคือการแยกสัญลักษณ์ในบล็อกการบีบอัดเพื่อไปยังจุดสิ้นสุดโดยไม่ต้องทำงานเพื่อสร้างบล็อกที่คลายการบีบอัดใหม่ นี่อาจจะเร็วกว่าอย่างมาก (อาจเป็นอย่างน้อย 2x) กว่าการเรียกฟังก์ชันถอดรหัสปกติของ zlib เพื่อเขียนทับบัฟเฟอร์เดิมและเลื่อนไปข้างหน้าในไฟล์ แต่ฉันไม่รู้ว่ามีใครเขียนฟังก์ชันดังกล่าวหรือไม่ (และฉันคิดว่ามันใช้งานไม่ได้จริงยกเว้นว่าไฟล์นั้นถูกเขียนขึ้นเป็นพิเศษเพื่อให้ตัวถอดรหัสสามารถเริ่มการทำงานใหม่ได้ที่บล็อกบางอัน)
ผมก็หวังว่าไม่มีทางที่จะข้ามผ่านบล็อกยุบโดยไม่ต้องถอดรหัสพวกเขาเพราะที่จะมากได้เร็วขึ้น ต้นไม้ Huffman ถูกส่งไปที่จุดเริ่มต้นของแต่ละบล็อกเพื่อให้คุณสามารถถอดรหัสจากจุดเริ่มต้นของบล็อกใด ๆ (ฉันคิดว่า) โอ้ฉันคิดว่าสถานะถอดรหัสเป็นมากกว่าต้นไม้ Huffman แต่ก็เป็นข้อมูลถอดรหัสที่ 32kiB ก่อนหน้าและนี่ไม่ได้ถูกรีเซ็ต / ลืมข้ามขอบเขตบล็อกโดยค่าเริ่มต้น ไบต์เดียวกันสามารถถูกอ้างอิงซ้ำ ๆ ได้ดังนั้นอาจปรากฏเพียงครั้งเดียวในไฟล์บีบอัดขนาดยักษ์ (เช่นในไฟล์บันทึกชื่อโฮสต์อาจยังคง "ร้อน" ในพจนานุกรมการบีบอัดตลอดเวลาและทุกอินสแตนซ์ของมันอ้างอิงหนึ่งก่อนหน้านี้ไม่ใช่ชื่อแรก)
zlib
คู่มือบอกว่าคุณต้องใช้Z_FULL_FLUSH
เมื่อโทรdeflate
ถ้าคุณต้องการกระแสบีบอัดที่จะ seekable ไปยังจุดที่ มัน "รีเซ็ตสถานะการบีบอัด" ดังนั้นฉันคิดว่าไม่มีการอ้างอิงย้อนหลังสามารถเข้าไปในบล็อกก่อนหน้า ดังนั้นหากไฟล์ zip ของคุณถูกเขียนด้วยบล็อกเต็มเปี่ยมเป็นครั้งคราว (เช่นทุก 1G หรือบางสิ่งบางอย่างอาจส่งผลกระทบต่อการบีบอัดข้อมูลเล็กน้อย) ฉันคิดว่าคุณจะต้องทำงานถอดรหัสให้มากขึ้นกว่าที่คุณต้องการในตอนแรก ความคิด ฉันเดาว่าคุณคงไม่สามารถเริ่มต้นเมื่อเริ่มต้นบล็อกใดก็ได้
ส่วนที่เหลือถูกเขียนในขณะที่ฉันคิดว่ามันจะเป็นไปได้ที่จะหาจุดเริ่มต้นของบล็อกที่มีไบต์แรกที่คุณต้องการและถอดรหัสจากที่นั่น
แต่น่าเสียดายที่การเริ่มต้นบล็อก Deflate ไม่ได้ระบุระยะเวลาของบล็อกบีบอัด ข้อมูลที่ไม่สามารถบีบอัดสามารถเข้ารหัสด้วยประเภทบล็อกที่ไม่บีบอัดที่มีขนาด 16 บิตเป็นไบต์ที่ด้านหน้า แต่บล็อกที่บีบอัดไม่ได้: RFC 1951 อธิบายรูปแบบที่อ่านได้ง่าย บล็อกที่มีการเข้ารหัส Huffman แบบไดนามิกมีต้นไม้ที่ด้านหน้าของบล็อก (ดังนั้นตัวขยายการบีบอัดไม่จำเป็นต้องค้นหาในสตรีม) ดังนั้นคอมเพรสเซอร์จะต้องเก็บบล็อกทั้งหมด (บีบอัด) ไว้ในหน่วยความจำก่อนที่จะเขียน
ระยะอ้างอิงย้อนหลังสูงสุดเพียง 32kiB ดังนั้นคอมเพรสเซอร์จึงไม่จำเป็นต้องเก็บข้อมูลที่ไม่ได้บีบอัดไว้ในหน่วยความจำมากนัก แต่นั่นไม่ได้ จำกัด ขนาดบล็อก บล็อกสามารถมีความยาวหลายเมกะไบต์ (นี่มีขนาดใหญ่พอสำหรับดิสก์ที่ค้นหาว่ามีค่าแม้จะอยู่บนไดรฟ์แบบแม่เหล็กเทียบกับการอ่านตามลำดับลงในหน่วยความจำและเพียงข้ามข้อมูลใน RAM ถ้าเป็นไปได้ที่จะหาจุดสิ้นสุดของบล็อกปัจจุบันโดยไม่ต้องแยกวิเคราะห์)
zlib สร้างบล็อกให้นานที่สุด:
ตามที่ Marc Adler , zlib จะเริ่มบล็อกใหม่เมื่อบัฟเฟอร์สัญลักษณ์เต็มขึ้นซึ่งการตั้งค่าเริ่มต้นคือสัญลักษณ์ 16,383 (ตัวอักษรหรือไม้ขีดไฟ)
ฉันส่งเอาต์พุตของseq
(ซึ่งซ้ำซ้อนอย่างมากและอาจไม่ใช่การทดสอบที่ยอดเยี่ยม) แต่มีการpv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -c
ทำงานที่เพียง 62 62 MiB / s ของข้อมูลที่ถูกบีบอัดบน Skylake i7-6700k ที่ 3.9GHz พร้อม DDR4-2666 RAM นั่นคือ 246MiB / s ของข้อมูลที่ถูกแตกซึ่งเป็นการเปลี่ยนแปลงของก้อนเมื่อเทียบกับmemcpy
ความเร็วของ ~ 12 GiB / s สำหรับขนาดบล็อกที่ใหญ่เกินไปที่จะใส่ในแคช
(ด้วยการenergy_performance_preference
ตั้งค่าเป็นค่าเริ่มต้นbalance_power
แทนที่จะbalance_performance
เป็นผู้ว่าราชการซีพียูภายในของ Skylake ตัดสินใจที่จะทำงานที่ 2.7GHz เท่านั้น ~ 43 MiB / s ของข้อมูลที่ถูกบีบอัดฉันใช้sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'
เพื่อปรับแต่งมันการโทรระบบบ่อยเช่นนั้นอาจไม่เหมือน CPU จริง ๆ ทำงานกับหน่วยจัดการพลังงาน)
TL: DR: zcat | tail -c
ถูกผูกไว้กับ CPU แม้กระทั่งบน CPU ที่เร็วเว้นแต่คุณจะมีดิสก์ที่ช้ามาก gzip ใช้ CPU 100% ที่รันบน (และรัน 1.81 คำสั่งต่อนาฬิกาอ้างอิงจากperf
) และtail
ใช้ 0.162 ของ CPU ที่รันบน (0.58 IPC) ระบบไม่ได้ใช้งานเป็นส่วนใหญ่
ฉันใช้ Linux 4.14.11-1-ARCH ซึ่งเปิดใช้งาน KPTI เป็นค่าเริ่มต้นเพื่อแก้ไข Meltdown ดังนั้นการwrite
เรียกใช้ระบบเหล่านั้นทั้งหมดจึงgzip
มีราคาแพงกว่าที่เคยเป็น: /
การมีการค้นหาในตัวunzip
หรือzcat
(แต่ยังคงใช้zlib
ฟังก์ชั่นถอดรหัสปกติ)จะช่วยประหยัดการเขียนไปป์ทั้งหมดและจะทำให้ซีพียู Skylake ทำงานที่ความเร็วสัญญาณนาฬิกาเต็ม (การดาวน์โหลดสำหรับการโหลดบางประเภทนั้นไม่เหมือนกันสำหรับ Intel Skylake และใหม่กว่าซึ่งมีการลดความถี่การตัดสินใจของ CPU ที่ทำจากระบบปฏิบัติการเนื่องจากพวกเขามีข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ CPU กำลังทำอยู่และสามารถเพิ่ม / ลดความเร็วได้เร็วขึ้น ปกติดี แต่ที่นี่นำไปสู่การ Skylake ไม่เร่งความเร็วเต็มที่กับการตั้งค่าผู้ว่าการอนุรักษ์มากขึ้น)
ไม่มีการเรียกระบบเพียงแค่เขียนบัฟเฟอร์ที่เหมาะกับแคช L2 จนกว่าคุณจะไปถึงตำแหน่งไบต์เริ่มต้นที่คุณต้องการอาจสร้างความแตกต่าง% อย่างน้อย อาจจะเป็น 10% แต่ฉันแค่คิดเลขตรงนี้ ฉันยังไม่ได้ทำโปรไฟล์zlib
ในรายละเอียดใด ๆ เพื่อดูว่ามีแคชของรอยเท้าขนาดใหญ่เท่าใดและ TLB flush (และ uop-cache flush) ในการโทรของระบบทุกครั้งที่เปิดใช้งาน KPTI
มีโครงการซอฟต์แวร์ไม่กี่รายที่จะเพิ่มแสวงหาดัชนีรูปแบบไฟล์ gzip มี นี่ไม่ได้ช่วยอะไรคุณถ้าคุณไม่สามารถให้ใครสร้างไฟล์บีบอัดที่หาได้ให้คุณ แต่ผู้อ่านคนอื่น ๆ ในอนาคตอาจได้รับประโยชน์
สันนิษฐานว่าค่าของโครงการเหล่านี้มีฟังก์ชั่นการถอดรหัสที่รู้วิธีการข้ามผ่านกระแสยุบโดยไม่ต้องดัชนีเพราะพวกเขากำลังออกแบบเฉพาะเพื่อการทำงานเมื่อดัชนีเป็นใช้ได้