39 điểm bởi GN⁺ 2025-04-21 | 1 bình luận | Chia sẻ qua WhatsApp
  • Dự án mã nguồn mở giúp học các kỹ thuật lập trình C/C++ và assembly hiệu năng cao qua các ví dụ thực chiến
  • Bao gồm ví dụ sử dụng thư viện được tối ưu hóa thay cho STL và nhiều kỹ thuật tối ưu hóa phần cứng khác nhau
  • Giải thích nhiều mẹo hiệu năng như chi phí tạo đầu vào, xấp xỉ hàm toán học, dự đoán nhánh CPU, song song hóa đa lõi
  • Bao quát rộng từ kỹ thuật tối ưu hóa theo từng nền tảng như CUDA, PTX, ASM, FPGA, xử lý JSON cho đến cách đo benchmark
  • Cung cấp tính năng tự động hóa chạy benchmark và xử lý thống kê dựa trên Google Benchmark

Cách viết mã C/C++ và assembly hướng hiệu năng

  • Dự án này là một bộ mã benchmark giúp hình thành trực giác và tư duy cần thiết cho thiết kế phần mềm hiệu năng cao
  • Tập trung vào các ví dụ lập trình thực chiến để tránh bug, vấn đề bảo mật, nút thắt hiệu năng thường gặp trong mã hiện đại
  • Giới thiệu có hệ thống các kỹ thuật hướng hiệu năng trong thực tế mà môn học đại học hay bootcamp khó bao quát
  • Phần lớn mã chạy trên môi trường Linux dùng GCC, Clang, nhưng cũng hỗ trợ một phần cho Windows và macOS
  • Đồng thời giới thiệu thuật toán song song, coroutine, đa hình để hiện thực mã hiệu năng cao

Các mục chính

  • Đầu vào ngẫu nhiên rẻ hơn tới 100 lần?! Việc tạo đầu vào đôi khi còn chậm hơn cả thuật toán
  • Sai số 1%, chi phí chỉ còn 1/40: thử xấp xỉ các hàm lượng giác STL như std::sin chỉ bằng 3 dòng mã
  • Logic trì hoãn lại nhanh hơn 4 lần? Hiện thực sự lười tối đa với std::ranges tùy biến và iterator
  • Tối ưu hóa compiler vượt cả -O3: có thể đẩy hiệu năng lên gấp đôi bằng các cờ ẩn và mẹo khác
  • Nhân ma trận mới là vấn đề? Dù ít phép tính hơn 60%, GEMM 3x3x3 vẫn có thể chậm hơn 4x4x4 tới 70%
  • Sự thật về scaling AI? Tự đo khoảng cách giữa thông lượng ALU lý thuyết và hiệu năng BLAS thực tế
  • Bao nhiêu câu lệnh điều kiện thì là quá nhiều? Thử nghiệm giới hạn của bộ dự đoán nhánh CPU chỉ với 10 dòng mã
  • Đệ quy tốt hơn à? Hãy tự đo độ sâu stack để xem nó văng SEGFAULT ở đâu
  • Vì sao nên tránh exception? Thử các lựa chọn thay thế như std::error_code hay std::variant
  • Muốn mở rộng đa lõi? Cách dùng OpenMP, Intel oneTBB hoặc thread pool tự viết
  • Cách xử lý JSON mà không cấp phát bộ nhớ? C++20 tốt hơn hay công cụ C99 kiểu cũ lại đơn giản hơn?
  • Muốn dùng đúng các associative container của STL thì khai thác custom key và transparent comparator như thế nào?
  • Nếu có cách nhanh hơn parser tự viết? So tài trực diện với regex engine dựa trên consteval
  • Kích thước con trỏ có thật sự là 64-bit? Hãy thử tận dụng pointer tagging
  • UDP sẽ làm rơi bao nhiêu packet? Thử cả việc xử lý web request từ user space bằng io_uring
  • Hiện thực phép toán bộ nhớ không liên tục được vector hóa nhanh hơn 50% với Scatter-Gather
  • Intel oneAPI vs Nvidia CCCL? <thrust><cub> có gì đặc biệt?
  • CUDA C++, PTX, SASS khác gì so với mã CPU?
  • Với mã nhạy cảm về hiệu năng? So sánh nên chọn intrinsic, inline asm, hay file .S
  • Tensor Core và cấu trúc bộ nhớ — CPU và GPU Volta, Ampere, Hopper, Blackwell khác nhau ra sao?
  • Lập trình FPGA khác gì GPU? Khác biệt giữa high-level synthesis (HLS), Verilog, VHDL là gì? 🔜 #36
  • Encrypted Enclave là gì? So sánh độ trễ của Intel SGX, AMD SEV, ARM Realm 🔜 #31

Cách chạy và thiết lập môi trường

  • Khuyến nghị môi trường Linux + GCC, cũng có thể dùng WSL hoặc Clang trên Mac (bản phân phối không mặc định)
  • Cần cài CMake, liburing, OpenBLAS, g++, build-essential
  • Sau khi build file thực thi less_slow, chạy nó để benchmark tự động được thực hiện
git clone https://github.com/ashvardanian/less_slow.cpp.git  
cd less_slow.cpp  
pip install cmake --upgrade  
sudo apt install -y build-essential g++ liburing-dev libopenblas-base  
cmake -B build_release -D CMAKE_BUILD_TYPE=Release  
cmake --build build_release --config Release  
build_release/less_slow  
  • Có thể chọn có dùng CUDA và Intel TBB hay không (dùng cờ như -D USE_INTEL_TBB=OFF)
  • Khi chạy có thể chỉ chọn một benchmark cụ thể, lưu JSON hoặc chỉ định định dạng đầu ra
build_release/less_slow --benchmark_filter=std_sort  
build_release/less_slow --benchmark_out=results.json --benchmark_format=json  

Mẹo cải thiện việc đo hiệu năng

  • Tắt SMT, dùng random interleaving để giảm thiểu nhiễu
  • Có thể đo hardware performance counter bằng tùy chọn --benchmark_perf_counters của Google Benchmark
sudo build_release/less_slow --benchmark_perf_counters="CYCLES,INSTRUCTIONS"  
  • Hoặc đo benchmark bằng công cụ Linux perf
sudo perf stat taskset 0xEFFFEFFFEFFFEFFFEFFFEFFFEFFFEFFF build_release/less_slow --benchmark_filter=super_sort  

Cấu trúc file của dự án

  • Mã nguồn chính: less_slow.cpp (tập trung vào mã benchmark CPU)
  • Bao gồm các file tối ưu hóa theo từng nền tảng: ASM cho x86/ARM, mã CUDA .cu, mã PTX .ptx
├── less_slow.cpp           # Mã benchmark chính  
├── less_slow_amd64.S       # Assembly x86  
├── less_slow_aarch64.S     # Assembly ARM  
├── less_slow.cu            # CUDA C++  
├── less_slow_sm70.ptx      # PTX IR (Volta)  
├── less_slow_sm90a.ptx     # PTX IR (Hopper)  

Sử dụng thư viện bên ngoài

  • Google Benchmark: đo hiệu năng
  • Intel oneTBB: backend STL song song
  • Meta libunifex: mô hình thực thi bất đồng bộ
  • range-v3: thay thế std::ranges
  • fmt: thay thế std::format
  • StringZilla: thay thế std::string
  • CTRE: thay thế std::regex
  • nlohmann/json, yyjson: parser JSON
  • Abseil: container hiệu năng cao
  • cppcoro: hiện thực coroutine
  • liburing: I/O bỏ qua lớp trung gian kernel Linux
  • ASIO: networking bất đồng bộ
  • Nvidia CCCL, CUTLASS: thuật toán GPU và phép toán ma trận

Tóm tắt mẹo dùng Google Benchmark

  • Đăng ký benchmark bằng BENCHMARK(), truyền tham số bằng ->Args({x,y})
  • Điều khiển tối ưu hóa compiler bằng DoNotOptimize(), ClobberMemory()
  • Điều khiển số vòng lặp và thời gian benchmark bằng ->Iterations(n), ->MinTime(n)
  • Chỉ định độ phức tạp thời gian bằng ->Complexity(...), ->SetComplexityN(n)
  • Tự điều khiển đoạn timing bằng state.PauseTiming(), ResumeTiming()
  • Có thể đăng ký custom counter bằng state.counters[...]

Yếu tố meme và hài hước

  • Chèn ảnh meme kỹ thuật vào tài liệu học để tăng hứng thú
  • Thể hiện một cách hài hước sự đối đầu giữa hiệu năng và tính trừu tượng, cùng chủ đề số thực dấu phẩy động IEEE 754

1 bình luận

 
GN⁺ 2025-04-21
Ý kiến trên Hacker News
  • Lượng giác nhanh hơn 40 lần: có thể tăng tốc các hàm thư viện chuẩn như std::sin chỉ với 3 dòng mã

    • Có thể xấp xỉ sin(x) bằng cách giới hạn khai triển ở một vài hạng tử
    • Chi phí tính toán giảm nhưng độ chính xác cũng giảm
    • Mức suy giảm độ chính xác còn bị đánh giá thấp. Với đầu vào nằm ngoài khoảng [-2, 2] thì kết quả rất thiếu chính xác
    • Thậm chí không xử lý nổi một chu kỳ sóng sin đơn lẻ và cũng không thể xử lý tính tuần hoàn. Đây là một kiểu "tối ưu hóa" vô dụng
  • Chia sẻ kinh nghiệm trên vi điều khiển

    • Đang làm việc với hệ thống nhúng, heap khoảng 256 KiB, stack lớn nhất là 4 KiB
    • Chủ yếu dùng C++ hiện đại, nhưng không phải mọi mẹo đều phù hợp với mọi tình huống
    • CTRE vẫn ổn miễn là tránh được tràn stack. Đã thử xác thực chuỗi trong cấu hình proxy HTTP nhưng hệ thống bị crash do tràn stack
    • Hầu như không dùng JSON nội bộ mà tự viết thư viện BSON riêng. Không cần lo về cấp phát bộ nhớ hay phân mảnh
    • Dùng picolibc thay cho newlib và loại bỏ mã locale của thư viện chuẩn C/C++. Điều đó giúp giảm kích thước chương trình
  • Ý kiến về lựa chọn Abseil

    • Khi mới xuất hiện thì đây là vấn đề lớn, nhưng giờ đã có nhiều lựa chọn thay thế khắc phục được các điểm yếu của nó
    • Những năm gần đây, sự bất mãn với Abseil ngày càng tăng. Tại Google đã có sự rời đi của các maintainer thư viện cốt lõi
  • Phê phán sự bóp méo vì hiệu năng trong C++

    • Ngạc nhiên khi CTRE cho kết quả tốt. Cần đào sâu thêm
    • Muốn xem xét benchmark thread pool của OpenMP và TBB, đồng thời kiểm tra xem có thể thêm thread pool của Boost::ASIO hay không
  • Khác biệt giữa lập trình FPGA và GPU, cùng yêu cầu về tổng hợp mức cao, Verilog, VHDL

    • Muốn có thêm các yêu cầu ưu tiên về chủ đề này
  • Thông tin mới về số thực dấu phẩy động phi chuẩn hóa

    • Thỉnh thoảng tự hỏi về điều này khi nhân ma trận trên GPU
  • Phản hồi tích cực về bài viết Google Benchmark

    • Tập trung vào benchmark hiệu năng là rất tốt. Kho mã được tổ chức gọn gàng
  • Kỳ vọng về "mã C, C++, assembly ít chậm hơn"

    • Tưởng rằng sẽ có cả mã C, nhưng chỉ có .cpp và .S
    • less_slow.cpp dùng rất nhiều đặc tính của C++. Cần bỏ "C" khỏi danh sách hoặc chỉnh sửa lại