- 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> và <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
Ý 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::sinchỉ với 3 dòng mãsin(x)bằng cách giới hạn khai triển ở một vài hạng tửChia sẻ kinh nghiệm trên vi điều khiển
Ý kiến về lựa chọn Abseil
Phê phán sự bóp méo vì hiệu năng trong C++
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
Thông tin mới về số thực dấu phẩy động phi chuẩn hóa
Phản hồi tích cực về bài viết Google Benchmark
Kỳ vọng về "mã C, C++, assembly ít chậm hơn"