- โปรเจกต์โอเพนซอร์สสำหรับเรียนรู้เทคนิคการเขียนโค้ด C/C++ และแอสเซมบลีประสิทธิภาพสูงผ่านตัวอย่างใช้งานจริง
- มีตัวอย่างการใช้ไลบรารีที่ปรับแต่งมาเพื่อประสิทธิภาพและเทคนิคการเพิ่มประสิทธิภาพฮาร์ดแวร์หลากหลายแบบแทน STL
- อธิบายกลเม็ดด้านประสิทธิภาพหลากหลาย เช่น ต้นทุนการสร้างอินพุต, การประมาณค่าฟังก์ชันคณิตศาสตร์, การทำนายการแตกแขนงของ CPU, การทำงานขนานหลายคอร์
- ครอบคลุมทั้งเทคนิคการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์มและวิธีวัดผลเบนช์มาร์กอย่างกว้างขวาง ไม่ว่าจะเป็น CUDA, PTX, ASM, FPGA, การประมวลผล JSON ฯลฯ
- มีฟังก์ชันรันเบนช์มาร์กและทำสถิติอัตโนมัติบนพื้นฐานของ Google Benchmark
วิธีเขียนโค้ด C/C++ และแอสเซมบลีที่เน้นประสิทธิภาพ
- โปรเจกต์นี้เป็นชุดโค้ดเบนช์มาร์กที่ช่วยสร้างสัญชาตญาณและกรอบความคิดที่จำเป็นต่อการออกแบบซอฟต์แวร์ประสิทธิภาพสูง
- นำเสนอตัวอย่างการเขียนโค้ดใช้งานจริงเพื่อหลีกเลี่ยงบั๊ก ปัญหาความปลอดภัย และคอขวดด้านประสิทธิภาพที่พบบ่อยในโค้ดยุคใหม่
- แนะนำเทคนิคเชิงประสิทธิภาพสำหรับงานจริงอย่างเป็นระบบ ซึ่งหาเจอได้ยากในวิชาเรียนมหาวิทยาลัยหรือบูตแคมป์
- โค้ดส่วนใหญ่ทำงานบน Linux ที่ใช้ GCC, Clang แต่ก็รองรับ Windows และ macOS บางส่วนด้วย
- ยังแนะนำเรื่อง อัลกอริทึมขนาน, คอร์รูทีน, พหุสัณฐาน สำหรับการสร้างโค้ดประสิทธิภาพสูงด้วย
หัวข้อสำคัญ
- สุ่มอินพุตให้ถูกลงได้ถึง 100 เท่า?! ความจริงที่ว่าการสร้างอินพุตอาจช้ากว่าอัลกอริทึมเองก็ได้
- ยอมคลาดเคลื่อน 1% แต่ต้นทุนเหลือ 1/40: ลองประมาณค่าฟังก์ชันตรีโกณมิติ STL อย่าง
std::sin ด้วยโค้ดแค่ 3 บรรทัด
- ตรรกะแบบหน่วงกลับเร็วกว่า 4 เท่า? ใช้
std::ranges แบบคัสตอมและ iterator เพื่อความ lazy ขั้นสุด
- การเพิ่มประสิทธิภาพคอมไพเลอร์ที่เหนือกว่า
-O3: มีแฟลกและทริกซ่อนอยู่ที่ดันประสิทธิภาพเพิ่มได้อีก 2 เท่า
- คิดว่าเมทริกซ์คูณคือปัญหา? แม้จำนวนการคำนวณจะน้อยลง 60% แต่ 3x3x3 GEMM อาจช้ากว่า 4x4x4 ถึง 70%
- ความจริงของการสเกล AI? ลองวัดช่องว่างระหว่าง throughput ตามทฤษฎีของ ALU กับประสิทธิภาพ BLAS จริง
- ต้องมี
if กี่อันถึงจะถือว่าเยอะ? ทดลองขีดจำกัดของตัวทำนายการแตกแขนงของ CPU ด้วยโค้ดเพียง 10 บรรทัด
- รีเคอร์ชันดีกว่าจริงไหม? มาวัดความลึกของสแตกด้วยตัวเองว่าตรงไหนจะเจอ
SEGFAULT
- ทำไมควรหลีกเลี่ยง exception? ลองใช้ทางเลือกอย่าง
std::error_code หรือ std::variant
- อยากสเกลหลายคอร์? เรียนรู้การใช้ OpenMP, Intel oneTBB หรือ thread pool ที่เขียนเอง
- จัดการ JSON โดยไม่จองหน่วยความจำทำอย่างไร? C++20 ดีกว่า หรือเครื่องมือ C99 แบบคลาสสิกจะง่ายกว่า?
- ถ้าอยากใช้ associative container ของ STL ให้ถูกต้อง จะใช้ custom key และ transparent comparator อย่างไรดี
- ถ้ามีวิธีที่เร็วกว่า parser เขียนมือ? ปะทะตรง ๆ ด้วย regex engine ที่ใช้
consteval
- ขนาดพอยน์เตอร์เป็น 64 บิตจริงหรือ? มาลองใช้ pointer tagging กัน
- UDP จะดรอปแพ็กเก็ตได้มากแค่ไหน? ไปจนถึงการจัดการเว็บรีเควสต์จาก user space ด้วย
io_uring
- ใช้ Scatter-Gather เพื่อทำงานเวกเตอร์กับหน่วยความจำไม่ต่อเนื่องให้เร็วขึ้น 50%
- Intel oneAPI vs Nvidia CCCL? อะไรทำให้
<thrust> กับ <cub> พิเศษ?
- CUDA C++, PTX, SASS ต่างจากโค้ดฝั่ง CPU อย่างไร?
- ถ้าเป็นโค้ดที่ไวต่อประสิทธิภาพ? เปรียบเทียบว่าจะเลือก intrinsic, inline
asm หรือไฟล์ .S แบบไหน
- Tensor Core และโครงสร้างหน่วยความจำ — CPU กับ GPU Volta, Ampere, Hopper, Blackwell ต่างกันอย่างไร?
- การเขียนโค้ด FPGA ต่างจาก GPU อย่างไร? HLS, Verilog, VHDL ต่างกันแบบไหน? 🔜 #36
- Encrypted Enclave คืออะไร? เปรียบเทียบ latency ของ Intel SGX, AMD SEV, ARM Realm 🔜 #31
วิธีรันและการตั้งค่าสภาพแวดล้อม
- แนะนำ Linux + GCC, ใช้ WSL หรือ Clang บน Mac (ดิสโทรที่ไม่ใช่ค่าเริ่มต้น) ก็ได้
- ต้องติดตั้ง
CMake, liburing, OpenBLAS, g++, build-essential
- หลัง build ไฟล์รัน
less_slow แล้วเรียกใช้งาน ระบบจะรันเบนช์มาร์กอัตโนมัติ
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
- เลือกได้ว่าจะใช้ CUDA และ Intel TBB หรือไม่ (
-D USE_INTEL_TBB=OFF เป็นต้น)
- ตอนรันสามารถเลือกให้รันเฉพาะบางเบนช์มาร์ก บันทึกเป็น JSON หรือกำหนดรูปแบบเอาต์พุตได้
build_release/less_slow --benchmark_filter=std_sort
build_release/less_slow --benchmark_out=results.json --benchmark_format=json
เคล็ดลับเพื่อให้การวัดประสิทธิภาพดีขึ้น
- ปิด SMT และใช้ random interleaving เพื่อลด noise ให้เหลือน้อยที่สุด
- ใช้ตัวเลือก
--benchmark_perf_counters ของ Google Benchmark เพื่อวัด hardware performance counter ได้
sudo build_release/less_slow --benchmark_perf_counters="CYCLES,INSTRUCTIONS"
- หรือจะใช้เครื่องมือ
perf ของ Linux เพื่อวัดเบนช์มาร์กก็ได้
sudo perf stat taskset 0xEFFFEFFFEFFFEFFFEFFFEFFFEFFFEFFF build_release/less_slow --benchmark_filter=super_sort
โครงสร้างไฟล์ของโปรเจกต์
- ซอร์สหลัก:
less_slow.cpp (เน้นโค้ดเบนช์มาร์กฝั่ง CPU)
- มีไฟล์สำหรับการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์ม: รวมโค้ด ASM สำหรับ x86/ARM, CUDA
.cu, PTX .ptx
├── less_slow.cpp # โค้ดเบนช์มาร์กหลัก
├── less_slow_amd64.S # แอสเซมบลี x86
├── less_slow_aarch64.S # แอสเซมบลี ARM
├── less_slow.cu # CUDA C++
├── less_slow_sm70.ptx # PTX IR (Volta)
├── less_slow_sm90a.ptx # PTX IR (Hopper)
การใช้ไลบรารีภายนอก
- Google Benchmark: วัดประสิทธิภาพ
- Intel oneTBB: แบ็กเอนด์ STL แบบขนาน
- Meta libunifex: โมเดลการรันแบบอะซิงก์
- range-v3: ใช้แทน
std::ranges
- fmt: ใช้แทน
std::format
- StringZilla: ใช้แทน
std::string
- CTRE: ใช้แทน
std::regex
- nlohmann/json, yyjson: ตัวแยกวิเคราะห์ JSON
- Abseil: คอนเทนเนอร์ประสิทธิภาพสูง
- cppcoro: การทำคอร์รูทีน
- liburing: I/O แบบข้ามเคอร์เนลลินุกซ์
- ASIO: เครือข่ายแบบอะซิงก์
- Nvidia CCCL, CUTLASS: อัลกอริทึม GPU และการคำนวณเมทริกซ์
สรุปเคล็ดลับการใช้ Google Benchmark
- ลงทะเบียนเบนช์มาร์กด้วย
BENCHMARK() และส่งพารามิเตอร์ด้วย ->Args({x,y})
- ควบคุมการเพิ่มประสิทธิภาพของคอมไพเลอร์ด้วย
DoNotOptimize(), ClobberMemory()
- ควบคุมจำนวนรอบและเวลาเบนช์มาร์กด้วย
->Iterations(n), ->MinTime(n)
- ระบุ time complexity ด้วย
->Complexity(...), ->SetComplexityN(n)
- ควบคุมช่วงเวลาที่จะจับด้วยตัวเองผ่าน
state.PauseTiming(), ResumeTiming()
- ลงทะเบียนเคาน์เตอร์แบบกำหนดเองได้ด้วย
state.counters[...]
มีมและองค์ประกอบแนวขำขัน
- แทรกภาพมีมสายเทคนิคในสื่อการสอนเพื่อเพิ่มความน่าสนใจ
- นำเสนอความขัดแย้งระหว่างประสิทธิภาพกับ abstraction รวมถึง floating point แบบ IEEE 754 ในโทนขำ ๆ
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ตรีโกณมิติที่เร็วขึ้น 40 เท่า: สามารถเร่งฟังก์ชันไลบรารีมาตรฐานอย่าง
std::sinได้ด้วยโค้ด 3 บรรทัดsin(x)ได้โดยจำกัดการขยายให้เหลือเพียงไม่กี่พจน์แชร์ประสบการณ์จากไมโครคอนโทรลเลอร์
ความเห็นต่อการเลือกใช้ Abseil
คำวิจารณ์ต่อการบิดเบือน C++ เพื่อแลกกับประสิทธิภาพ
ความแตกต่างระหว่างการเขียนโค้ด FPGA กับ GPU และคำขอเกี่ยวกับ high-level synthesis, Verilog, VHDL
ข้อมูลใหม่เกี่ยวกับ floating-point แบบ denormalized
ฟีดแบ็กเชิงบวกต่อโพสต์ Google Benchmark
ความคาดหวังต่อ “C, C++, assembly code ที่ช้าลดลง”