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

Mỗi luồng một biến riêng mà vẫn chậm gấp 2,6 lần?

Mỗi luồng ghi biến riêng của nó thì chạy song song thoải mái? Đo trên host ARM: tám luồng, mỗi luồng tăng một bộ đếm riêng, nhưng nếu tám bộ đếm nằm chung một dòng cache thì chậm gấp 2,6 lần so với khi mỗi bộ đếm được đệm ra dòng riêng — dù các biến hoàn toàn độc lập về logic. Đây là false sharing: dòng cache ping-pong giữa các lõi. Ghi thường không atomic vẫn trả giá.

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

Thêm phép tính vào vòng lặp mà không chậm hơn: vì sao?

Vòng lặp duyệt mảng lớn nhanh chậm do số phép tính? Đo trên host ARM bằng STREAM: copy (không phép tính), add, triad (nhân+cộng) đều đạt ~65-92 GB/s như nhau — nút cổ chai là băng thông bộ nhớ, không phải phép tính. Và một luồng đã đạt ~85% đỉnh, hai luồng bão hòa ~95 GB/s: trên lõi Apple này một core gần như dùng hết băng thông, khác hẳn server x86.

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.

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

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.