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

Bỏ if cho nhanh: mẹo hay hay giáo điều?

Code không nhánh (branchless) luôn nhanh hơn if? Đo trên host ARM: khi nhánh khó đoán (dữ liệu ngẫu nhiên), branchless nhanh gấp 3 lần vì né được dự đoán sai. Nhưng khi nhánh dễ đoán và thân điều kiện rất đắt (8 phép chia, hiếm khi chạy), bản có if lại thắng vì bỏ qua được việc đắt. Và nhiều khi trình biên dịch đã tự bỏ nhánh giúp bạn rồi mà không hay.

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

Lệnh không nhánh có luôn thắng if? Còn tùy đồng xu

Lệnh chọn không nhánh (cmov/csel) luôn tốt hơn một if? Đo trên host ARM, quét theo xác suất điều kiện đúng: chi phí của nhánh là một đường cong hình chuông — gần như miễn phí khi điều kiện luôn đúng hoặc luôn sai (dễ đoán), nhưng đỉnh 0,58 ns khi 50/50 (khó đoán nhất). Còn branchless thì phẳng lì ~0,37 ns. Hai đường giao nhau quanh 15% và 85% — và đó mới là chỗ quyết định.

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

Cái 'bộ đếm chu kỳ' của bạn không đếm chu kỳ đâu

Đọc bộ đếm chu kỳ của CPU là đếm được số chu kỳ? Đo trên host ARM: bộ đếm timer cntvct chạy tần số cố định 24 MHz, còn CPU chạy ~4,44 GHz — nên một tick bằng 41,67 ns, tức khoảng 185 chu kỳ CPU chứ không phải một. Và mỗi lần gọi steady_clock::now() tốn ~13 ns; đo đoạn ngắn hơn thế thì kết quả toàn là rác. Đây là cách đo cho đúng.

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

Đổi int64 thành int8, vòng lặp nhanh gấp 10 lần

Kiểu số nào cũng 'một phép tính' nên tốc độ như nhau? Đo trên host ARM: cùng một phép trên mảng, khi vector hóa thì int8 nhanh gấp 10 lần int64 — thanh ghi NEON 128-bit gói 16 số int8 nhưng chỉ 2 số int64 mỗi lệnh. Dữ liệu lớn (memory-bound) kiểu hẹp cũng thắng ~9 lần vì ít byte. Nhưng ở chế độ vô hướng mọi kiểu int lại y hệt, và kiểu nhỏ dễ tràn — nên quy tắc là hẹp nhất đủ dùng.

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

Một dòng trộn int với float, và 19 chu kỳ bốc hơi

Gán số nguyên cho biến float trông như miễn phí — 'đều là số' mà. Đo trên host ARM: một phép cộng int tốn ~1 chu kỳ, nhưng vòng chuyển khứ hồi (int)((float)v+1) trên chuỗi phụ thuộc tốn 4,3 ns — khoảng 19 chu kỳ, gấp 19 lần. int và float là hai thế giới riêng trong CPU, và các phép ép kiểu ngầm trong biểu thức trộn kích hoạt lệnh chuyển đổi mà bạn không hề viết ra.

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

Đổi chỗ hai dòng for, code chạy chậm đi 18 lần

Duyệt ma trận theo hàng hay theo cột — cùng số phần tử, cùng phép cộng, chỉ khác thứ tự — thì như nhau chứ? Đo trên host ARM: ma trận 64MB duyệt theo hàng 0,211 ns mỗi phần tử, theo cột 3,79 ns — chậm gần 18 lần. Mỗi lần chạm cột rơi vào một dòng cache riêng, CPU nạp 128 byte nhưng chỉ dùng 4, phí 31/32 dòng và cộng cả lỗi TLB. Thứ quyết định không phải số phần tử, mà số byte dòng cache phải kéo.