Trình biên dịch 03/09/2026 8 phút

clang thắng ba vòng lặp, tôi định khoe — rồi đọc assembly thấy mình sai cả lý do

Đo sáu vòng lặp bằng gcc và clang: clang nhanh hơn 2-4 lần ở vài vòng, hòa ở số khác. Tôi định kết 'clang nhanh hơn' và giải thích nó thắng popcount nhờ lệnh cnt. Đọc mã máy ra ngược hẳn — gcc mới dùng cnt mà vẫn chậm. Bài cuối sê-ri, và cái bẫy tôi rơi vào cả hai chân.

Giải thuật 03/09/2026 8 phút

-O0 chậm hơn -O2 gần 5 lần, còn -O3 gần như không hơn -O2 — cả hai điều tôi tưởng đều sai

Cùng một code C, -O0 chậm 4,6 lần -O2 — không phải vì làm nhiều phép tính hơn, mà vì giữ mọi biến trên ngăn xếp (72 lệnh load/store so với 26 khi lên -O1). Cú nhảy tốc độ lớn nhất nằm ở -O0 → -O1; còn -O2 và -O3 cho mã gần như y hệt. Số cao hơn không đảm bảo nhanh hơn.

Giải thuật 03/09/2026 8 phút

Inline để bỏ lệnh gọi hàm ư? Tôi đo: bỏ call chỉ được 0,15 ns — lợi thật gấp mười lần thế, ở chỗ khác

Ai cũng bảo inline để khỏi tốn chi phí gọi hàm. Tôi đo và thấy bỏ một lệnh call chỉ tiết kiệm 0,15 ns — call trên CPU hiện đại gần như miễn phí. Lợi thật là tối ưu xuyên biên: gọi g(x,0) hằng số, inline giúp gấp hằng và khử nhánh chết, nhanh 1,8 lần. Nhưng inline hàm lớn vào 24 chỗ làm mã phình gấp đôi.

Giải thuật 03/09/2026 8 phút

Vòng lặp 2 tỉ phép tính của tôi đo ra đúng 0 nano giây — vì gcc xóa sạch nó, và đó là bài học nền

Một vòng 2 tỉ phép tính mà kết quả không ai dùng đo ra đúng 0,00 ns — gcc -O2 xóa cả vòng, hàm chỉ còn ret. Thêm một volatile sink là số nhảy lên 1,37 ns thật. Khử mã chết còn xóa dead store và mã sau return, và đây chính là lý do mọi benchmark cần 'quan sát' kết quả.