39 คะแนน โดย GN⁺ 2025-04-21 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • โปรเจกต์โอเพนซอร์สสำหรับเรียนรู้เทคนิคการเขียนโค้ด 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 ความคิดเห็น

 
GN⁺ 2025-04-21
ความคิดเห็นบน Hacker News
  • ตรีโกณมิติที่เร็วขึ้น 40 เท่า: สามารถเร่งฟังก์ชันไลบรารีมาตรฐานอย่าง std::sin ได้ด้วยโค้ด 3 บรรทัด

    • สามารถประมาณค่า sin(x) ได้โดยจำกัดการขยายให้เหลือเพียงไม่กี่พจน์
    • ต้นทุนการคำนวณลดลง แต่ความแม่นยำก็ลดลงด้วย
    • การบอกว่าความแม่นยำลดลงนั้นยังประเมินน้อยไปมาก สำหรับอินพุตที่อยู่นอกช่วง [-2, 2] จะไม่แม่นยำอย่างมาก
    • จัดการได้ไม่แม้แต่ช่วงคลื่นไซน์เดี่ยว และก็ไม่รองรับลักษณะการเกิดซ้ำ เป็น “การปรับแต่ง” ที่ไร้ประโยชน์
  • แชร์ประสบการณ์จากไมโครคอนโทรลเลอร์

    • กำลังทำงานกับระบบฝังตัว โดยมีฮีปราว 256 KiB และสแตกที่ใหญ่ที่สุด 4 KiB
    • ใช้ C++ สมัยใหม่เป็นหลัก แต่ไม่ใช่ว่าทุกเทคนิคจะเหมาะกับทุกสถานการณ์
    • CTRE ใช้ได้ตราบใดที่ยังหลีกเลี่ยง stack overflow ได้ เคยพยายามตรวจสอบสตริงของการตั้งค่า HTTP proxy แต่ระบบล่มเพราะ stack overflow
    • แทบไม่ได้ใช้ JSON ภายในเลย และเขียนไลบรารี BSON ของตัวเองขึ้นมา จึงไม่ต้องกังวลเรื่องการจัดสรรหน่วยความจำหรือ fragmentation
    • ใช้ picolibc แทน newlib และตัดโค้ด locale ของไลบรารีมาตรฐาน C/C++ ออก ทำให้ขนาดโปรแกรมเล็กลง
  • ความเห็นต่อการเลือกใช้ Abseil

    • ตอนออกมาใหม่ ๆ เป็นประเด็นใหญ่ แต่ตอนนี้มีทางเลือกหลายตัวที่แก้จุดอ่อนได้แล้ว
    • ช่วงไม่กี่ปีที่ผ่านมา มีเสียงบ่นเกี่ยวกับ Abseil มากขึ้น และมีผู้ดูแลไลบรารีหลักลาออกจาก Google
  • คำวิจารณ์ต่อการบิดเบือน C++ เพื่อแลกกับประสิทธิภาพ

    • แปลกใจที่ CTRE ให้ผลลัพธ์ที่ดี และอยากลงลึกมากขึ้น
    • อยากตรวจสอบเบนช์มาร์กของ thread pool ใน OpenMP และ TBB และดูว่าสามารถเพิ่ม thread pool ของ Boost::ASIO ได้หรือไม่
  • ความแตกต่างระหว่างการเขียนโค้ด FPGA กับ GPU และคำขอเกี่ยวกับ high-level synthesis, Verilog, VHDL

    • อยากเห็นคำขอในหัวข้อนี้เป็นลำดับต้น ๆ
  • ข้อมูลใหม่เกี่ยวกับ floating-point แบบ denormalized

    • บางครั้งสงสัยเรื่องนี้เวลาเอาเมทริกซ์ไปคูณกันบน GPU
  • ฟีดแบ็กเชิงบวกต่อโพสต์ Google Benchmark

    • ชอบการโฟกัสที่การทำ performance benchmarking และรีโพซิทอรีก็จัดระเบียบมาดี
  • ความคาดหวังต่อ “C, C++, assembly code ที่ช้าลดลง”

    • คิดว่าจะมีโค้ด C รวมอยู่ด้วย แต่มีแค่ .cpp กับ .S
    • less_slow.cpp ใช้ความสามารถของ C++ หลายอย่าง จึงควรเอา “C” ออกจากรายการหรือแก้ไขให้ถูกต้อง