1 điểm bởi GN⁺ 2025-03-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • Tự biên dịch gói mã nguồn jq do Ubuntu cung cấp có thể cải thiện hiệu năng lên tới 90%
  • Tối đa hóa hiệu năng bằng cách cải thiện trình biên dịch, cờ tối ưu hóa và bộ cấp phát bộ nhớ

Thiết lập

  • jq được dùng để xử lý các tệp GeoJSON ở định dạng JSON
    • Chạy truy vấn để in ra tên thành phố của mọi parcel có giá trị từ một ngưỡng nhất định trở lên trong bản đồ parcel của Alameda County Assessor dung lượng 500MB
  • Trên hệ thống Ryzen 9 9950X, mất khoảng 5 giây với tệp đã được cache, nên đã thử cải thiện điều này

Bước 1: Biên dịch lại gói

  • Tải mã nguồn jq từ Launchpad rồi biên dịch lại mà không dùng cờ nào
  • Kết quả: cải thiện hiệu năng 2~4%
  • Kết quả benchmark
    • jq đã biên dịch: trung bình 4.517 giây
    • gói mặc định của Ubuntu: trung bình 4.641 giây
    • Cải thiện hiệu năng: nhanh hơn 1,03 lần

Bước 2: Dùng Clang và cờ tối ưu hóa nâng cao

  • Biên dịch bằng Clang-18 và dùng mức tối ưu hóa cùng LTO
  • Các cờ chính đã dùng:
    • -O3 → tăng mức tối ưu hóa
    • -flto → áp dụng Link-Time Optimization
    • -DNDEBUG → loại bỏ mã debug
  • Kết quả benchmark
    • jq đã biên dịch: trung bình 3.853 giây
    • gói mặc định của Ubuntu: trung bình 4.631 giây
    • Cải thiện hiệu năng: nhanh hơn 1,20 lần

Bước 3: Thêm TCMalloc

  • Dùng TCMalloc thay cho malloc mặc định của GNU libc
  • Thêm -L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal rồi biên dịch
  • Kết quả benchmark
    • jq đã biên dịch: trung bình 3.253 giây
    • gói mặc định của Ubuntu: trung bình 4.611 giây
    • Cải thiện hiệu năng: nhanh hơn 1,42 lần

Bước 4: Áp dụng preload động cho TCMalloc

  • Dùng TCMalloc bằng preload động với gói mặc định của Ubuntu
  • Kết quả benchmark
    • jq mặc định: trung bình 4.601 giây
    • jq có áp dụng TCMalloc: trung bình 4.082 giây
    • Cải thiện hiệu năng: nhanh hơn 1,13 lần

Bước 5: Thử preload động với các bộ cấp phát khác

  • Thử jemallocmimalloc, các bộ cấp phát bộ nhớ khác có trong Ubuntu
  • mimalloc cho hiệu năng tốt nhất
  • Kết quả benchmark
    • jq mặc định: trung bình 4.123 giây
    • jq có áp dụng TCMalloc: trung bình 4.130 giây
    • jq có áp dụng Jemalloc: trung bình 3.510 giây
    • jq có áp dụng Mimalloc: trung bình 3.154 giây → hiệu năng tăng 1,31 lần

Bước 6: Biên dịch trực tiếp với mimalloc

  • Liên kết tĩnh với mimalloc thay vì dùng preload động
  • Tối đa hóa hiệu năng
  • Kết quả benchmark
    • jq đã biên dịch: trung bình 2.428 giây
    • gói mặc định của Ubuntu: trung bình 4.606 giây
    • Cải thiện hiệu năng: nhanh hơn 1,90 lần

🚀 Kết quả cuối cùng

  • jq tự biên dịch nhanh hơn 90% so với gói Ubuntu
  • Hiệu năng xử lý 13.000 tệp JSON tổng dung lượng 2,2GB:
    • jq đã biên dịch: 0.755 giây
    • jq mặc định: 1.424 giây
    • Cải thiện hiệu năng: gần 2 lần

1 bình luận

 
GN⁺ 2025-03-19
Ý kiến trên Hacker News
  • Tiêu đề "Làm gói Ubuntu nhanh hơn 90% bằng cách biên dịch lại và thay đổi trình cấp phát bộ nhớ" có vẻ như câu kéo nhấp chuột

    • Đây chỉ là câu chuyện về một gói duy nhất, và một phần cải thiện hiệu năng không đến từ việc biên dịch lại
    • Tôi từng preload jemalloc để thay thế triển khai malloc, và đã nhận được kết quả tích cực trong việc ổn định mức sử dụng bộ nhớ
    • Điều này đã giải quyết vấn đề rò rỉ bộ nhớ, và rất có thể đó là vấn đề phân mảnh bộ nhớ chứ không phải lỗi của chính ứng dụng
  • Kỹ thuật là nghệ thuật của sự đánh đổi

    • Bài viết giải thích rằng phần lớn cải thiện hiệu năng đến từ việc chuyên biệt hóa trình cấp phát bộ nhớ
    • Trong các dự án đa luồng, việc chọn trình cấp phát là quan trọng, và mức tăng tốc ở một dự án có thể gây crash ở dự án khác
    • Cũng cần cân nhắc chiến lược tái cấp phát, và phải lựa chọn giữa độ ổn định dài hạn và tốc độ ngắn hạn
    • Trong quá trình phát triển một trình biên tập video, tôi đã thử nhiều trình cấp phát khác nhau và nhận ra trình cấp phát của glibc mang lại độ ổn định dài hạn
  • Gentoo Linux là hệ điều hành được thiết kế để có thể tối ưu hóa cho từng mục đích sử dụng cụ thể của người dùng

    • Sau khi thiết lập ban đầu thì việc sử dụng khá đơn giản, và tôi nhớ mình đã kết bạn với nhiều người trên kênh Gentoo Linux
    • ChromeOS thời kỳ đầu về cơ bản là một bản cài đặt Gentoo Linux tùy biến
  • Nếu cài thủ công các gói như jq thì có thể bị bỏ lỡ các bản cập nhật bảo mật

    • Ví dụ đã từng có bản cập nhật bảo mật cho onigurama, và nếu tình huống tương tự lặp lại thì có thể trở nên dễ bị tấn công
    • Đã có nhiều lỗ hổng bảo mật được vá, bao gồm CVE-2017-9224
  • Dùng malloc không chính thức có thể gây ra những lỗi kỳ lạ

    • Nếu vượt ra ngoài các cờ mà nhà phát triển sử dụng, khả năng phát sinh vấn đề sẽ cao
  • Đọc thấy chỉ với thay đổi đơn giản mà có thể tăng tốc lớn như vậy khiến tôi muốn báo cho tác giả jq

    • Có vẻ bài viết chưa cân nhắc tùy chọn này, và trong phần bình luận cũng không nhắc đến
  • Việc biên dịch gói từ mã nguồn hoặc tải binary chính thức có thể mang lại lợi ích

    • Trước đây việc kiểm tra cập nhật cho các gói cài thủ công và biên dịch từ mã nguồn khá khó, nhưng tôi đã phát triển một công cụ để giải quyết việc đó
  • Tính năng cargo install của Rust rất hữu ích vì cho phép tối ưu hóa cho từng nền tảng cụ thể

    • jaqyq là những lựa chọn tôi thường dùng để cải thiện hiệu năng khi dùng jq
  • Sau khi thay đổi trình cấp phát bộ nhớ, có thể biên dịch lại gói Ubuntu để làm nó nhanh hơn 90%

    • Có khả năng điều này cũng hoạt động trên Debian và RedHat
    • Ban đầu tôi tưởng đây là bài viết về việc biến Ubuntu thành Linux From Scratch