1 คะแนน โดย GN⁺ 2025-03-19 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • หากคอมไพล์แพ็กเกจซอร์สโค้ดของ jq ที่ Ubuntu จัดเตรียมไว้ด้วยตนเอง ประสิทธิภาพอาจดีขึ้นได้สูงสุด 90%
  • เพิ่มประสิทธิภาพสูงสุดด้วยการปรับปรุงคอมไพเลอร์ แฟล็กการออปติไมซ์ และตัวจัดสรรหน่วยความจำ

การตั้งค่า

  • jq ถูกใช้เพื่อประมวลผลไฟล์ GeoJSON ในรูปแบบ JSON
    • รันคิวรีเพื่อแสดงชื่อเมืองของ parcel ทั้งหมดที่มีค่ามากกว่าค่าที่กำหนดจากแผนที่ parcel ของ Alameda County Assessor ขนาด 500MB
  • บนระบบ Ryzen 9 9950X ใช้เวลาประมาณ 5 วินาที กับไฟล์ที่แคชไว้ จึงตัดสินใจลองปรับปรุงให้เร็วขึ้น

ขั้นตอนที่ 1: คอมไพล์แพ็กเกจใหม่

  • ดาวน์โหลดซอร์สโค้ด jq จาก Launchpad แล้วคอมไพล์ใหม่โดยไม่ใส่แฟล็กใด ๆ
  • ผลลัพธ์: ประสิทธิภาพดีขึ้น 2~4%
  • ผลการเบนช์มาร์ก
    • jq ที่คอมไพล์: เฉลี่ย 4.517 วินาที
    • แพ็กเกจมาตรฐานของ Ubuntu: เฉลี่ย 4.641 วินาที
    • ปรับปรุงประสิทธิภาพ: เร็วขึ้น 1.03 เท่า

ขั้นตอนที่ 2: ใช้ Clang และแฟล็กออปติไมซ์ขั้นสูง

  • คอมไพล์ด้วย Clang-18 และใช้ระดับการออปติไมซ์รวมถึง LTO
  • แฟล็กหลักที่ใช้:
    • -O3 → เพิ่มระดับการออปติไมซ์
    • -flto → ใช้ Link-Time Optimization
    • -DNDEBUG → ตัดโค้ดดีบักออก
  • ผลการเบนช์มาร์ก
    • jq ที่คอมไพล์: เฉลี่ย 3.853 วินาที
    • แพ็กเกจมาตรฐานของ Ubuntu: เฉลี่ย 4.631 วินาที
    • ปรับปรุงประสิทธิภาพ: เร็วขึ้น 1.20 เท่า

ขั้นตอนที่ 3: เพิ่ม TCMalloc

  • ใช้ TCMalloc แทน malloc เริ่มต้นของ GNU libc
  • เพิ่ม -L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal แล้วคอมไพล์
  • ผลการเบนช์มาร์ก
    • jq ที่คอมไพล์: เฉลี่ย 3.253 วินาที
    • แพ็กเกจมาตรฐานของ Ubuntu: เฉลี่ย 4.611 วินาที
    • ปรับปรุงประสิทธิภาพ: เร็วขึ้น 1.42 เท่า

ขั้นตอนที่ 4: ใช้ TCMalloc แบบ dynamic preload

  • ใช้ TCMalloc กับแพ็กเกจมาตรฐานของ Ubuntu ผ่าน dynamic preload
  • ผลการเบนช์มาร์ก
    • jq ปกติ: เฉลี่ย 4.601 วินาที
    • jq ที่ใช้ TCMalloc: เฉลี่ย 4.082 วินาที
    • ปรับปรุงประสิทธิภาพ: เร็วขึ้น 1.13 เท่า

ขั้นตอนที่ 5: ทดสอบ dynamic preload กับตัวจัดสรรอื่น

  • ทดสอบ jemalloc และ mimalloc ซึ่งเป็นตัวจัดสรรหน่วยความจำอื่นที่ Ubuntu มีให้
  • mimalloc ให้ประสิทธิภาพดีที่สุด
  • ผลการเบนช์มาร์ก
    • jq ปกติ: เฉลี่ย 4.123 วินาที
    • jq ที่ใช้ TCMalloc: เฉลี่ย 4.130 วินาที
    • jq ที่ใช้ Jemalloc: เฉลี่ย 3.510 วินาที
    • jq ที่ใช้ Mimalloc: เฉลี่ย 3.154 วินาที → ประสิทธิภาพดีขึ้น 1.31 เท่า

ขั้นตอนที่ 6: คอมไพล์ตรงกับ mimalloc

  • ลิงก์ mimalloc แบบสแตติกแทนการใช้ dynamic preload
  • ดันประสิทธิภาพได้สูงสุด
  • ผลการเบนช์มาร์ก
    • jq ที่คอมไพล์: เฉลี่ย 2.428 วินาที
    • แพ็กเกจมาตรฐานของ Ubuntu: เฉลี่ย 4.606 วินาที
    • ปรับปรุงประสิทธิภาพ: เร็วขึ้น 1.90 เท่า

🚀 ผลลัพธ์สุดท้าย

  • jq ที่คอมไพล์เองเร็วกว่าแพ็กเกจ Ubuntu 90%
  • ประสิทธิภาพในการประมวลผลไฟล์ JSON ขนาด 2.2GB จำนวน 13,000 ไฟล์:
    • jq ที่คอมไพล์: 0.755 วินาที
    • jq ปกติ: 1.424 วินาที
    • ปรับปรุงประสิทธิภาพ: ประมาณ 2 เท่า

1 ความคิดเห็น

 
GN⁺ 2025-03-19
ความคิดเห็นบน Hacker News
  • หัวข้อ "ทำให้แพ็กเกจ Ubuntu เร็วขึ้น 90% ด้วยการบิลด์ใหม่และเปลี่ยนตัวจัดสรรหน่วยความจำ" ดูเหมือนคลิกเบต

    • เป็นเรื่องของแพ็กเกจเดียวเท่านั้น และการเพิ่มประสิทธิภาพบางส่วนก็ไม่ได้เกิดจากการคอมไพล์ใหม่
    • เคยมีประสบการณ์พรีโหลด jemalloc เพื่อสลับ implementation ของ malloc และได้ผลลัพธ์เชิงบวกในการทำให้การใช้หน่วยความจำเสถียรขึ้น
    • สิ่งนี้แก้ปัญหา memory leak ได้ และมีความเป็นไปได้สูงว่านั่นไม่ใช่ปัญหาของตัวแอปพลิเคชันเอง แต่เป็นปัญหา memory fragmentation
  • วิศวกรรมคือศิลปะแห่งการประนีประนอม

    • บทความอธิบายว่าได้ประสิทธิภาพที่เพิ่มขึ้นส่วนใหญ่จากการปรับตัวจัดสรรหน่วยความจำให้เฉพาะทาง
    • ในโปรเจ็กต์แบบมัลติเธรด การเลือกตัวจัดสรรมีความสำคัญ และการเพิ่มความเร็วในโปรเจ็กต์หนึ่งอาจทำให้เกิดการแครชในอีกโปรเจ็กต์หนึ่งได้
    • ควรพิจารณากลยุทธ์การจัดสรรซ้ำด้วย และจำเป็นต้องเลือกระหว่างเสถียรภาพระยะยาวกับความเร็วระยะสั้น
    • ระหว่างพัฒนาวิดีโอเอดิเตอร์ เคยทดลองใช้ตัวจัดสรรหลายแบบ และพบว่าตัวจัดสรรของ glibc ให้เสถียรภาพในระยะยาว
  • Gentoo Linux เป็นระบบปฏิบัติการที่ออกแบบมาเพื่อให้ปรับแต่งให้เหมาะกับการใช้งานเฉพาะของผู้ใช้ได้

    • หลังตั้งค่าเริ่มต้นแล้วก็ใช้งานได้ไม่ยาก และยังจำได้ว่าเคยได้เพื่อนมากมายในช่อง Gentoo Linux
    • ChromeOS ยุคแรก ๆ โดยพื้นฐานแล้วเป็นการติดตั้ง Gentoo Linux แบบคัสตอม
  • หากติดตั้งแพ็กเกจอย่าง jq ด้วยตนเอง ก็อาจหลุดจากการอัปเดตด้านความปลอดภัย

    • ตัวอย่างเช่น เคยมีการอัปเดตความปลอดภัยของ onigurama และถ้าสถานการณ์แบบนี้เกิดขึ้นอีกก็อาจมีช่องโหว่ได้
    • มีกรณีที่มีการแก้ไขช่องโหว่หลายรายการ เช่น CVE-2017-9224
  • การใช้ malloc ที่ไม่เป็นทางการอาจทำให้เกิดบั๊กแปลก ๆ ได้

    • หากใช้งานเกินกว่าธงที่นักพัฒนาใช้กันอยู่ ก็มีโอกาสสูงที่จะเกิดปัญหา
  • เมื่ออ่านว่าการเปลี่ยนแปลงเล็กน้อยให้ผลด้านความเร็วอย่างมาก ก็อยากบอกเรื่องนี้กับผู้พัฒนา jq

    • ดูเหมือนบทความจะไม่ได้พิจารณาตัวเลือกนี้ และในคอมเมนต์ก็ไม่ได้พูดถึงเช่นกัน
  • การคอมไพล์แพ็กเกจจากซอร์สหรือดาวน์โหลดไบนารีทางการอาจมีประโยชน์

    • การตรวจสอบอัปเดตของแพ็กเกจที่ติดตั้งด้วยตนเองและคอมไพล์จากซอร์สนั้นทำได้ยาก แต่เคยพัฒนาเครื่องมือเพื่อแก้ปัญหานี้
  • ฟีเจอร์ cargo install ของ Rust มีประโยชน์เพราะช่วยให้ปรับแต่งให้เหมาะกับแพลตฟอร์มเฉพาะได้

    • jaq และ yq เป็นตัวเลือกที่มักใช้บ่อยเพื่อเพิ่มประสิทธิภาพเมื่อใช้งาน jq
  • หลังจากเปลี่ยนตัวจัดสรรหน่วยความจำแล้ว ก็สามารถบิลด์แพ็กเกจ Ubuntu ใหม่ให้เร็วขึ้น 90% ได้

    • มีความเป็นไปได้ว่าจะใช้ได้กับ Debian และ RedHat เช่นกัน
    • ตอนแรกนึกว่าเป็นบทความเกี่ยวกับการเปลี่ยน Ubuntu ให้เป็น Linux From Scratch