1 điểm bởi GN⁺ 2025-03-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • Khi xây dựng lại cùng mã nguồn jq và thay đổi allocator, thời gian xử lý GeoJSON 500MB giảm từ 4,606 giây xuống 2,428 giây, nhanh hơn 1,90 lần so với binary của Ubuntu
  • Benchmark được thực hiện trên Ryzen 9 9950X với parcel map của Alameda County Assessor, bằng cách trích xuất SitusCity theo điều kiện TotalNetValue < 193000
  • Chỉ riêng việc rebuild đơn giản cũng cải thiện 2~4%, còn tổ hợp clang-18, -O3, -flto, -DNDEBUG đạt hiệu năng 1,20 lần so với gói Ubuntu
  • Profile cho thấy chi phí cấp phát bộ nhớ rất lớn, nên đã so sánh TCMalloc, jemalloc, mimalloc; trong thử nghiệm LD_PRELOAD, mimalloc nhanh nhất
  • Bản build cuối cùng liên kết với mimalloc cũng ghi nhận 0,755 giây so với 1,424 giây trong một trường hợp xử lý JSON 2,2GB riêng, cho thấy tùy workload có thể có chênh lệch lớn so với bản build mặc định của distro

Workload chuẩn và cách đo

  • Đối tượng thử nghiệm là công cụ xử lý JSON jq, dữ liệu đầu vào là tệp GeoJSON 500MB chứa parcel map của Alameda County Assessor
  • Truy vấn được chạy sẽ in ra SitusCity của các mục trong danh sách parcel thỏa điều kiện TotalNetValue < 193000
    • .features[] | select(.properties.TotalNetValue < 193000) | .properties.SitusCity
  • /usr/bin/jq mặc định của Ubuntu mất khoảng 5 giây khi tệp đã được cache, và benchmark chi tiết được đo lặp lại bằng hyperfine
  • Để giảm biến động khi chạy, tiến trình được cố định vào CPU logic 2 bằng taskset -c 2
    • Đây là thiết lập nhằm tránh ảnh hưởng từ interrupt hệ thống chạy trên CPU 0 và việc migrate CPU

Rebuild đơn giản từ cùng mã nguồn

  • Tải mã nguồn jq mà Ubuntu sử dụng, rồi chạy configure và build mà không thêm flag riêng
  • Chỉ với bản rebuild đơn giản này, tốc độ đã nhanh hơn gói binary của Ubuntu khoảng 2~4%
    • Binary rebuild: trung bình 4,517 giây
    • Ubuntu /usr/bin/jq: trung bình 4,641 giây
    • Kết quả là hiệu năng khoảng 1,03 lần

Áp dụng clang và các flag tối ưu hóa

  • Ở bước tiếp theo, clang-18, mức tối ưu hóa cao hơn, LTO, cùng các flag liên quan đến debug/profiling được áp dụng cùng lúc
  • Các flag chính ảnh hưởng đến hiệu năng là -O3, -flto, -DNDEBUG
    • -O3 dùng mức tối ưu hóa cao hơn -O2
    • -flto bật tối ưu hóa ở thời điểm liên kết
    • -DNDEBUG giảm chi phí assertion vốn hiện lên đáng kể trong profile
  • Ví dụ configure đã áp dụng như sau
    • CC=clang-18
    • LDFLAGS="-flto -g -Wl,--emit-relocs -Wl,-z,now -Wl,--gc-sections -fuse-ld=lld"
    • CFLAGS="-flto -DNDEBUG -fno-omit-frame-pointer -gmlt -march=native -O3 -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections"
  • Bản build này nhanh hơn binary Ubuntu 1,20 lần
    • Rebuild tối ưu hóa: trung bình 3,853 giây
    • Ubuntu /usr/bin/jq: trung bình 4,631 giây

Thử nghiệm thay allocator

  • jq là một chương trình C phức tạp, và profile cho thấy cấp phát bộ nhớ là chi phí lớn nhất
  • Trước tiên, build lại bằng cách liên kết với TCMalloc do Ubuntu đóng gói
    • Thêm -L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimal vào LDFLAGS
    • Binary rebuild: trung bình 3,253 giây
    • Ubuntu /usr/bin/jq: trung bình 4,611 giây
    • Kết quả nhanh hơn 1,42 lần so với binary Ubuntu
  • Ngay cả khi chỉ đổi allocator bằng LD_PRELOAD trên binary Ubuntu mặc định, vẫn có thể cải thiện phần nào
    • Mặc định: trung bình 4,601 giây
    • Preload TCMalloc: trung bình 4,082 giây
    • Nhanh hơn 1,13 lần so với mặc định

Preload động và thiết lập THP

  • So sánh jemalloc, mimalloc, TCMalloc do Ubuntu cung cấp bằng LD_PRELOAD
  • So sánh này thu được sau khi thiết lập các biến môi trường sau
    • MIMALLOC_LARGE_OS_PAGES=1
    • MALLOC_CONF="thp:always,metadata_thp:always"
    • GLIBC_TUNABLES=glibc.malloc.hugetlb=1
  • Kết quả là mimalloc nhanh nhất
    • glibc mặc định: trung bình 4,123 giây
    • Preload TCMalloc: trung bình 4,130 giây
    • Preload jemalloc: trung bình 3,510 giây
    • Preload mimalloc: trung bình 3,154 giây
  • Bật THP mang lại lợi ích cho cả glibc allocator, jemalloc và mimalloc
  • THP + mimalloc nhanh hơn 31% so với THP + glibc, và nhanh hơn 48% so với giá trị mặc định của glibc

Kết quả cuối cùng của bản build liên kết mimalloc

  • Do preload động được xem là không lý tưởng về mặt hiệu năng, ở bước cuối cùng jq được build lại bằng cách liên kết với mimalloc
  • Bản build cuối cùng nhanh hơn gói binary Ubuntu 1,90 lần
    • Rebuild với mimalloc: trung bình 2,428 giây
    • Ubuntu /usr/bin/jq: trung bình 4,606 giây
    • Mỗi benchmark dựa trên 10 lần chạy
  • Cùng bản build cũng được dùng cho một ứng dụng khác
    • Xử lý JSON 2,2GB nằm trong 13.000 tệp
    • Dùng rush để song song hóa
    • jq rebuild với mimalloc: 0,755 giây
    • jq trong gói Ubuntu: 1,424 giây
  • Trong trường hợp riêng này, mức tăng tốc cũng gần 2 lần

1 bình luận

 
GN⁺ 2025-03-19
Ý kiến trên Hacker News
  • Kiểu tiêu đề câu view như “build lại một gói Ubuntu và đổi trình cấp phát bộ nhớ để nhanh hơn 90%” làm tôi chỉ muốn đấm cho một cú qua TCP/IP. Thực ra chỉ là một gói thôi, và một phần cải thiện thậm chí cũng không nhờ biên dịch lại
    Dù vậy, tôi từng thử chèn jemalloc vào một chương trình bằng LD_PRELOAD để thay implementation malloc, và kết quả khá tốt. Tôi không đo hiệu năng, nhưng mức dùng bộ nhớ của ứng dụng đó ổn định hơn và vấn đề trông giống rò rỉ bộ nhớ cũng biến mất. Trên thực tế, rất có thể đó không phải lỗi của chính ứng dụng mà là do phân mảnh bộ nhớ của malloc tiêu chuẩn

    • Tôi đã tìm hiểu trình cấp phát bộ nhớ của glibc, và hóa ra đây không phải phân mảnh bộ nhớ mà là cache theo từng luồng không bao giờ được trả lại cho kernel. Ngay cả khi gọi free(), bộ nhớ cũng không thực sự được giải phóng ra bên ngoài trừ những trường hợp ngoại lệ
      Càng nhiều luồng và càng nhiều lõi CPU thì vấn đề này càng nghiêm trọng. Một cách khắc phục đơn giản là đặt biến môi trường “ma thuật” MALLOC_ARENA_MAX=2 để giới hạn số lượng cache. Cách khác là để ứng dụng gọi malloc_trim() định kỳ nhằm dọn cache, nhưng cách này cần sửa mã nguồn
      https://www.joyfulbikeshedding.com/blog/2019-03-14-what-caus...
    • Đúng vậy, tôi cũng suýt tin trong chốc lát. Nhưng cũng rất dễ đổ lỗi cho Ubuntu là nguyên nhân gây ra lỗi. Cá nhân tôi thấy Ubuntu đóng gói khá tốt, và thực tế còn bật cả tùy chọn bảo vệ stack khi biên dịch
      Ngược lại, may là họ không biên dịch bằng -O3, vốn có thể tiềm ẩn lỗi. Nó có thể tốt cho một số thứ mà hiệu năng là quan trọng, nhưng tôi không muốn toàn bộ hệ thống được biên dịch với -O3
    • Không thể nào đạt được kiểu cải thiện đó trên diện rộng chỉ với lời giải thích trong một bài viết duy nhất, nên rõ ràng đây là phóng đại. Nhanh hơn 90% là con số của microbenchmark
    • Tôi tự hỏi có bao nhiêu bản phân phối nhị phân được đóng gói sẵn đang được build bằng các tùy chọn an toàn nhất cho hệ điều hành và phần cứng, và vì thế không đạt hiệu năng cao nhất có thể. Thành thật mà nói, có lẽ là đa số
      Từ lâu tôi đã bắt đầu tự build Mozilla và kernel Linux của mình theo ý thích, và thường thu được mức cải thiện hiệu năng tương đối. Xét cho cùng, toàn bộ mục đích của bản phân phối Gentoo Linux, chẳng hạn, là mức tăng hiệu năng có được nhờ biên dịch tối ưu mọi thứ từ mã nguồn
    • Tiêu đề là câu view, nhưng việc khuyến khích các nhà phát triển ứng dụng thử build lại vẫn là điều tốt. Đặc biệt là khi CPU là nút thắt cổ chai với một số tiện ích phổ biến như jq, grep, ffmpeg, ocrmypdf, và các tiện ích Unix phổ biến như vậy thường được build cho mục đích dùng chung chứ không phải cho một ứng dụng cụ thể
  • Kỹ thuật là sự đánh đổi. Trong bài viết, phần lớn lợi ích đến từ việc chuyên biệt hóa bộ cấp phát bộ nhớ. Cần nhớ rằng có những dự án đa luồng, nơi một luồng cấp phát, luồng khác ghi dữ liệu và luồng thứ ba giải phóng nó
    Bộ cấp phát phải xử lý được việc này, nên việc tăng tốc cho một dự án có thể lại gây xung đột ở dự án khác. Chiến lược tái cấp phát cũng là một vấn đề. Có chương trình cấp phát trước rồi không bao giờ đụng tới malloc nữa, nhưng cũng có chương trình cứ liên tục giải phóng rồi cấp lại. Khả năng xử lý phân mảnh tốt đến đâu, thời gian chạy là 10 giây hay 10 năm, tất cả đều quan trọng. Đôi khi việc chọn bộ cấp phát là khác biệt giữa độ ổn định dài hạn và tốc độ ngắn hạn
    Khi làm trình biên tập video để thử video 4K và cache các khung hình, tôi đã thử nhiều bộ cấp phát khác nhau. 32MB mỗi khung, 60fps tức gần 2GB mỗi giây cho một track. Rất nhanh sẽ chạm trần giới hạn của bộ cấp phát, và tôi nhận ra ít nhất thì bộ cấp phát mặc định của glibc cho độ ổn định dài hạn tốt nhất. Nhưng trong benchmark ngắn thì nó chậm nhất

  • Mimalloc là bộ cấp phát đa dụng giống JEMalloc / TCMalloc. glibc được biết đến là một bộ cấp phát khá tệ, còn MIMalloc hay TCMalloc mới hơn, tức các bản không phải bản mặc định đi kèm Ubuntu, thì vượt glibc rất xa
    Dĩ nhiên mức tăng tốc có thể khác nhau, nhưng benchmark nhìn chung cho thấy cải thiện tổng thể. Việc điều đó có ý nghĩa với một ứng dụng cụ thể hay không lại là chuyện hoàn toàn khác. Về crash cũng vậy, đây đều là các bộ cấp phát đa dụng đa luồng nên không vận hành khác glibc, và bug thì glibc cũng có thể gặp y hệt

  • Tôi cũng xử lý khung hình video 8K lớn [1]. Nếu nói về chính các khung hình, thì cấp phát 60 lần mỗi giây chẳng là gì cả. glibc chậm chỉ vì một lý do. Mỗi lần cấp phát đều vượt DEFAULT_MMAP_THRESHOLD_MAX, mà trên nền tảng 64-bit giá trị này là 32MiB, nên không thể thuyết phục glibc cache chúng như đã được mô tả trong tài liệu mallopt
    Mỗi lần nó đều gọi mmap để xin bộ nhớ trực tiếp từ kernel rồi trả lại bằng munmap. Các system call này hơi chậm, và trong trường hợp của tôi, chi phí page fault trên từng trang bộ nhớ ở lần truy cập đầu tiên đủ chậm để không đạt được mục tiêu hiệu năng. Cách giải quyết thật ra rất đơn giản. Chỉ riêng với các khung hình video, hãy dùng bộ cấp phát riêng hoặc danh sách rỗi tự viết trên mmap. Vì các lần cấp phát cùng đúng một kích thước lặp lại rất ổn định nên cách này hoạt động tốt
    [1] Ở định dạng UYVY thì nhỏ hơn một chút so với 64MiB, còn ở định dạng I420 thì nhỏ hơn một chút so với 48MiB

  • Tôi thấy hơi khó hiểu bình luận này. Tôi không rành về C hay trình biên dịch C, nhưng tôi đã đọc toàn bộ gist, học được khá nhiều và thấy nó có giá trị
    Nhưng rồi đọc bình luận top này khiến tôi lo là mình đã hiểu sai hoàn toàn bài viết. Giọng điệu của nó nghe như thể những gì gist nói tuyệt đối không bao giờ nên làm, và đó là một đề xuất tồi vì đã bỏ qua toàn bộ sự phức tạp này. Có ai có thể giúp tôi hiểu gist ban đầu có phải là một bài viết hay không, có điểm nào hợp lý không, hay hoàn toàn vô giá trị? Trước khi thấy bình luận này tôi nghĩ nó có ích, nhưng giờ tôi nhận ra mình không đủ hiểu biết để tự phân biệt

  • Đó là lý do dùng một bộ cấp phát duy nhất cho mọi thứ trên đời là một ý tưởng tệ. Thật khủng khiếp khi mọi ứng dụng đơn luồng, thậm chí cả ứng dụng đa luồng quản lý tài nguyên rất chặt, đều phải trả chi phí cho tính an toàn luồng

  • Đây là nỗi khổ rất quen thuộc. Nếu bạn dùng đúng ngôn ngữ cho dự án, người ta vẫn sẽ bảo bạn lẽ ra nên dùng ngôn ngữ khác vì đủ thứ lý do
    Nếu bạn dùng đúng thuật toán nén cho dữ liệu, người ta vẫn sẽ giải thích vì sao bạn ngu ngốc và lẽ ra nên dùng thuật toán khác. Gần đây tôi phải nén một chuỗi JSON dài cụ thể để đưa vào Dynamo, và sau khi kiểm thử kỹ toàn bộ các thuật toán phổ biến thì Brotli vượt lên hẳn. Nhưng điều đó vẫn không ngăn được người đi ngang qua nào cũng bảo zlib tốt hơn. Đôi khi thật sự rất mệt mỏi

  • Gentoo Linux về cơ bản là một bản phân phối được tạo ra cho kiểu người như vậy, để họ có thể tối ưu hóa chiếc máy Linux của mình đúng theo nhu cầu sử dụng
    Sau khi thiết lập ban đầu xong thì nó khá đơn giản và dễ dùng. Tôi nhớ mình đã kết được nhiều bạn trong kênh Gentoo Linux trên Matrix, đó là một thời vui vẻ
    https://www.gentoo.org/
    Một điều thú vị là ChromeOS thời kỳ đầu về cơ bản là một bản cài đặt Gentoo Linux tùy biến. Tôi không biết bây giờ nội bộ họ còn dùng Gentoo Linux hay không

    • Đúng, nhưng cũng đáng nói là tối ưu hóa ở đây không nhất thiết có nghĩa là hiệu năng
      Tôi đã dùng Gentoo suốt 20 năm nhưng chưa bao giờ dùng nó vì lý do hiệu năng. Gentoo rất tuyệt khi bạn biết mình muốn hệ thống hoạt động theo cách nào, và nó giúp bạn đạt tới điều đó
    • Đây là lần đầu tôi thấy meme kiểu HN “install gentoo”. Quả thật là tinh tế hơn
      Mục tiêu của Gentoo là có một hệ điều hành trong đó mọi chương trình đều được build từ mã nguồn thay vì dùng các gói nhị phân dựng sẵn. Điều này cho phép tăng tốc ở mức nâng cao và tùy biến sâu, nhưng cũng đồng nghĩa ngay cả các thành phần cơ bản nhất như kernel cũng phải được biên dịch từ mã nguồn. Trong cộng đồng Linux, nó nổi tiếng là một hệ điều hành rất phức tạp vì quy trình cài đặt nặng nề. Một bản cài Gentoo cơ bản sẽ khởi động thẳng vào dấu nhắc lệnh, và người dùng phải tự chia phân vùng đĩa, tải xuống rồi giải nén một gói gọi là “Stage 3 tarball”, cài gói thủ công và tự dựng hệ thống. Người dùng mới hoặc ít kinh nghiệm thường không biết phải làm gì khi vào trình cài đặt mà không có màn hình đồ họa. Thành viên /g/ thường hay phóng đại giá trị của Gentoo để lừa người mới thử cài nó
    • Tôi đã dùng Gentoo liên tục từ năm 2003, rồi mới chuyển sang thử Void Linux vào cuối năm 2024. Trên Void, việc để người dùng cuối build từ mã nguồn không phải là mục tiêu được tuyên bố hay một tính năng kiến trúc, nhưng khả năng làm cho nó hoạt động được trên thực tế là khá cao
      Có thể sẽ trục trặc một hai lần, nhưng nếu bạn có đủ kinh nghiệm Linux tổng thể thì nhiều khả năng bạn sẽ vào recipe build để sửa, làm cho nó chạy theo nhu cầu, và đóng góp bản sửa ngược lên upstream. Đây là kết quả của việc tập trung ám ảnh vào chủ nghĩa tối giản và tránh mọi kiểu overengineering. Đó cũng là điều tôi đã nhớ suốt thời gian dùng Gentoo. Trong Gentoo, tôi luôn phải vọc USE flags và package masks theo những cách hầu như chẳng giúp ích gì cho người dùng khác. Hệ thống build quá phức tạp, đến mức suốt nhiều năm trời việc thật sự nắm vững nó và sửa vấn đề tận gốc để đóng góp lên upstream là quá khó. Void có thể là nền tảng lý tưởng cả khi bạn không muốn build toàn bộ hệ thống từ mã nguồn, nhưng vẫn muốn dùng lẫn giữa các gói nhị phân do bản phân phối cung cấp và các gói tự build từ source
    • Tôi từng dùng Gentoo một thời gian, nhưng cuối cùng lại thường tự làm hỏng hệ thống vì cám dỗ muốn chỉnh sửa mọi thứ không ngừng. Không phải lỗi của Gentoo mà là lỗi của tôi
      Sau đó tôi chuyển sang ArchLinux, và nhìn chung nó khá ổn với tôi. Nếu bạn đang dùng một bộ xử lý khá tiêu chuẩn thì có lẽ Gentoo cũng không mang lại lợi thế lớn đến vậy
    • Theo như tôi biết thì ChromeOS dựa trên Gentoo đang dần được thay bằng Android
  • Làm vậy cũng có nghĩa bạn sẽ bỏ lỡ các bản cập nhật bảo mật không chỉ cho jq mà còn cho onigurama, thứ phụ thuộc để parse bằng regex. Trước đây đã từng có cập nhật bảo mật cho onigurama, và nếu chuyện như vậy lặp lại thì có thể sẽ dễ bị tấn công. jq thường được dùng để parse JSON không đáng tin cậy
    Nội dung khi đó là “Cập nhật bảo mật: sửa nhiều lỗi dereference con trỏ sai, hỏng bộ nhớ do ghi ngoài phạm vi, tràn bộ đệm ngăn xếp”, và vụ đó liên quan đến CVE-2017-9224, CVE-2017-9226, CVE-2017-9227, CVE-2017-9228, CVE-2017-9229

    • Nếu dùng một trình quản lý gói không gian người dùng như Gentoo Prefix thì bạn vẫn có thể cài bản build tùy biến này mà tiếp tục nhận cập nhật bảo mật
    • Tuy vậy, chẳng phải đây là một ý tưởng kiểu hạt giống cho một hệ thống quản lý gói có thể quyết định thông minh việc có nên build hay không tùy theo nền tảng sao? Mức tăng hiệu năng có vẻ khá lớn để mà bỏ qua
    • Nói chung là đúng, nhưng trong trường hợp này thì không đúng. Bản build được mô tả trong gist vẫn đang liên kết động với onigurama. onigurama nằm trong một gói khác là libonig5, và gói đó vẫn sẽ được cập nhật bình thường
    • Tôi tự hỏi những CVE kiểu này thực tế thường áp dụng được đến mức nào. Nó giống như nói rằng nếu dùng cửa trước trong nhà thì bạn sẽ bỏ lỡ mức bảo mật mà cửa két sắt mang lại. Không sai, nhưng cũng có lý do khiến không phải mọi cánh cửa trong ngân hàng đều là cửa két
      Tôi không cố hạ thấp giá trị của hệ thống CVE, nhưng cũng khó phủ nhận là tác động thực tế giữa các phát hiện có khác biệt rất lớn
    • Chắc chắn là vậy. Ngoài ra, nếu thay allocator và đổi compiler flags thì bạn cũng có thể vô tình trở nên miễn nhiễm với các cuộc tấn công phụ thuộc vào bố cục bộ nhớ cụ thể
  • Tôi đã xử lý mấy việc kiểu này từ khá lâu rồi, và theo trí nhớ của tôi thì ngay khi bạn đi vượt ra ngoài các flags mà upstream developer dùng, bạn sẽ dễ gặp những lỗi kỳ quặc, và khi lỗi xảy ra thì cũng nhận lại một mức độ thờ ơ khổng lồ. Ở đây tôi đang nói về upstream developer, chứ không phải người đóng gói của bản phân phối
    Tôi chưa từng dùng malloc nào ngoài libc, nhưng có vẻ nguyên lý vẫn giống nhau

    • Có hai điều đối lập cùng đúng một lúc. Nếu một cá nhân cố không khác biệt dù chỉ một chút, thì họ đang đi trên con đường giống nhiều người nhất và trong ngắn hạn có khả năng thành công cao nhất
      Nhưng nếu ai cũng làm vậy thì sẽ thành đơn văn hóa, mà đơn văn hóa thì mong manh và tệ hại. Mã nguồn chỉ trở nên dù là hơi vững chắc hơn khi được build trong các bối cảnh khác nhau, tức trên các nền tảng, compiler, tùy chọn, thư viện khác nhau. Một lỗi mà nền tảng hay build flags chỉ tình cờ lướt ngay sát cái bẫy nên phần lớn thời gian không chạm phải thì vẫn là lỗi, và phát hiện rồi sửa nó sẽ tốt hơn cho mã nguồn. Với tư cách cá nhân, tất cả chúng ta đều được lợi khi mã nguồn nói chung trở nên vững chắc thay vì mong manh
    • Tôi đã tự build emacs của mình suốt nhiều năm và vẫn chưa gặp lỗi kỳ lạ nào. Tôi nghĩ miễn là tránh các tối ưu hóa không an toàn thì vẫn ổn
      Tất nhiên, tôi cũng từng nghĩ -march=native là cải thiện chủ yếu mà mình thấy, nhưng bài này cho thấy không hẳn vậy. Có vẻ các ứng dụng dùng số thực dấu phẩy động có thể có nhiều góc cạnh hơn
    • Ngược lại, nếu một tối ưu hóa nào đó giúp ích nhất quán trên nhiều nền tảng, thì có thể thuyết phục upstream developer tự triển khai nó. Không nhất thiết phải là trên mọi nền tảng; chỉ cần mức tăng hiệu năng đủ lớn trên một kiến trúc duy nhất thôi cũng có thể là lý do để điều chỉnh cấu hình cho bản build đó
  • Điều này gần với việc biên dịch lại bằng một allocator khác cho kết quả benchmark tốt hơn trong một quy trình công việc cụ thể

    • Gần như bất cứ thứ gì cũng có thể tốt hơn glibc malloc. Việc các bản phân phối vẫn tiếp tục dùng glibc malloc thay vì mimalloc hay jemalloc về cơ bản là thiếu trách nhiệm trong công việc
    • Thực ra có ai biết glibc malloc phù hợp với loại tải công việc nào không?
  • Tò mò không biết hiệu năng so với bản clone jq viết bằng Rust này như thế nào
    cargo install --locked jaq
    Nếu muốn bật tối ưu hóa cho một họ CPU cụ thể, cũng có thể thêm RUSTFLAGS="-C target-cpu=native". cargo install là một tính năng bị đánh giá thấp của Rust, rất hợp với kiểu mục đích được mô tả trong bài. Nó biên dịch công cụ từ mã nguồn, nên có thể chọn các tính năng hay tập lệnh theo nền tảng mà bình thường không có trong binary để giữ tương thích với CPU cũ. Cũng không cần phải clone kho mã hay tự tìm cách build, vì mọi thứ đi kèm sẵn
    jaq[1] và yq[2] là lựa chọn tôi thường dùng mỗi khi đang dùng jq mà cần cải thiện hiệu năng nhanh và dễ
    [1] https://github.com/01mf02/jaq
    [2] https://github.com/mikefarah/yq

    • Thỉnh thoảng tôi có so sánh jaq với jqgojq, dùng lời giải jq của tôi cho AoC 2022 day 13 để thử nghiệm
      https://gist.github.com/oguz-ismail/8d0957dfeecc4f816ffee79d...
      Hiện tại nó vẫn chậm hơn cả hai
    • Một lợi ích thêm mà có thể nhiều người chưa biết là khi muốn dùng trực tiếp một kho mã, cargo install còn có cờ --git để chỉ định URL kho mã. Có thể dùng khi không có gói công khai hoặc khi muốn lấy commit mới nhất chưa phát hành
      Tôi đã dùng cách này nhiều lần trước đây, đặc biệt hữu ích như một cách dễ dàng để nhanh chóng cài các công cụ cá nhân viết gấp sau khi đẩy lên kho mã, mà không cần thiết lập quy trình phát hành hay tự chép binary sang các máy riêng và theo dõi chính xác commit đã dùng để build
  • Nếu thực sự định làm vậy thì chỉ cần tải đúng gói mã nguồn mà Ubuntu muốn dùng. Trong trường hợp này là apt-get source jq
    Sau đó vào trong gói và biên dịch lại tùy ý. Cũng có thể đóng gói lại để phân phối hoặc lưu trữ. Làm vậy sẽ cho kết quả gần với Ubuntu upstream hơn rất nhiều, thay vì nhận về hàng loạt lỗi lạ và sự không nhất quán

  • Tiêu đề gây hiểu nhầm. Ý là thời gian giảm đi 90% so với trước, còn trên thực tế là nhanh hơn khoảng 45%
    Nếu quan tâm tới cách chúng ta dùng ngôn ngữ thì điều này hơi thú vị. Người ta cũng có thể nói làm được nhiều việc hơn 90% trong cùng một khoảng thời gian, và cách nói đó phù hợp với những đơn vị tốc độ khác mà ta hay dùng như dặm mỗi giờ, từ mỗi phút, hay bit mỗi giây. Nhưng trong hiệu năng máy tính, thông lệ là đo thời gian cần cho một khối lượng công việc cố định. Có lẽ vì khối lượng công việc thường là cố định, còn thứ thay đổi là thời gian phải chờ. Trường hợp bài blog này cũng đúng hệt như vậy nên thời gian nằm ở tử số. Bản thân bài viết rất thú vị và được viết tốt, nhưng không phải là nhanh hơn 90%

    • Điều còn dễ gây hiểu nhầm hơn là sắc thái như thể có thể làm mọi gói đều nhanh hơn 90%. Trong khi đây chỉ là một gói cụ thể
    • Ở đây có lẽ dùng “90% faster” theo nghĩa đơn vị thông lượng sẽ hợp lý hơn là đơn vị thời gian
      Thêm nữa, nếu dùng đơn vị thời gian thì tôi sẽ không dùng từ “faster”. “45% less time” và “45% faster” là hai khẳng định rất khác nhau, và cả hai đều có ý nghĩa cả trong lẫn ngoài lập trình
    • Bài liên quan: https://randomascii.wordpress.com/2018/02/04/what-we-talk-ab...
    • Nghĩ thêm thì tôi đoán ra vì sao nó gây hiểu nhầm. Đó là vì đang diễn đạt sự thay đổi của một giá trị lớn hơn dưới dạng phần trăm của giá trị nhỏ hơn
      Khi nói “đã giảm N% một thứ gì đó”, người ta thường mặc định N% đó là của chính thứ bị giảm, chứ không phải của một giá trị khác
    • Nghe có vẻ đúng. Có thể nói gói đó, tức phần mã, nhanh hơn 45%, hoặc nói thông lượng phân tích cú pháp tăng 90%. Nhưng trộn hai cách nói lại thì rất dễ gây rối
  • Khi đọc rằng chỉ với một thay đổi đơn giản như vậy mà có thể đạt được mức tăng tốc lớn, điều đầu tiên tôi nghĩ tới là nên báo cho các tác giả jq biết. Có thể có những cạm bẫy cần lưu ý, hoặc sau khi kiểm thử họ có thể làm cho mọi người đều chạy nhanh hơn
    Dù kết quả ra sao thì việc báo cho họ biết có vẻ vẫn hữu ích. Nhưng bài viết dường như thậm chí còn không cân nhắc lựa chọn đó, và trong phần bình luận ở đây tôi cũng không thấy. Có phải tôi đang bỏ sót điều gì không?

    • Tò mò không biết Clear Linux của Intel có đạt được lợi ích tương tự nhờ dùng mã thao tác của tập lệnh mới hơn hay không
      Tôi cũng không biết ở đó glibc allocator có phải mặc định hay không
      https://en.m.wikipedia.org/wiki/Clear_Linux_OS