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

Hai chuỗi "abc" viết ở hai hàm khác nhau lại cùng một địa chỉ — và vì sao đừng mừng vội

Tưởng mỗi literal là một vùng nhớ riêng? Tôi đo: compiler gộp các literal trùng thành một bản duy nhất trong .rodata, nên con trỏ tới chúng bằng nhau và binary nhẹ đi. Nhưng chuẩn C không hề bảo đảm điều đó — dựa vào == để so chuỗi là một bug chờ nổ, luôn dùng strcmp.

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

Đặt điều kiện rẻ trước để né phép đắt — mẹo kinh điển này lại là bản CHẬM NHẤT khi tôi đo

Ai cũng bảo đặt điều kiện rẻ, hay-sai lên trước để && dừng sớm né phép đắt thì nhanh hơn. Tôi đo và hiệu năng đi ngược: bản bitwise & không nhánh, tính cả hai mọi lần, lại nhanh nhất. Hóa ra giá trị thật của && không phải tốc độ, mà là ngữ nghĩa bảo vệ null — thứ mà đổi sang & là làm crash.

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

volatile không làm biến nhanh hơn — nó làm code chậm 5 lần, và tôi vẫn cần nó

Nhiều người tưởng volatile cho nhanh hoặc cho an toàn đa luồng. Tôi đo thì ngược hẳn: volatile chặn tối ưu nên chậm 5,1 lần, vì mỗi lần chạm biến là một chuyến bộ nhớ thật. Nó đúng cho MMIO, cờ ngắt, và biến sink khi đo — nhưng nó KHÔNG phải atomic và không hề an toàn đa luồng.

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

Rào bộ nhớ sinh 0 lệnh máy mà vẫn làm code chậm 5,8 lần — cái đắt nằm ở đâu?

Rào bộ nhớ là một lệnh CPU đắt tiền luôn có mặt? Tôi đo và bất ngờ: rào biên dịch sinh 0 lệnh máy mà vẫn chậm 5,8 lần vì nó chặn tối ưu, còn rào phần cứng có lệnh dmb thật lại nhanh hơn. Cái giá thật là tối ưu bị tước đi, không phải bản thân lệnh rào — và nó vô hình trong assembly.

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

Vòng chép byte tự viết của tôi chậm hơn memcpy 25 lần — thủ phạm là một chữ tôi quên

memcpy là lời gọi thư viện, và vòng chép byte tay nhanh ngang nó? Tôi đo và sai cả hai. memcpy kích thước hằng được inline thẳng thành lệnh vector, 0 lời gọi; còn vòng chép byte tay chậm 25 lần vì compiler sợ hai con trỏ trùng địa chỉ nên không dám tối ưu. Thêm restrict là nó nhanh bằng memcpy ngay.

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

gcc 'biết' hàm này luôn chia cho 7 — mà ở -O2 vẫn không thèm tối ưu, vì sao?

Tôi tưởng compiler tự chuyên biệt bất kỳ hàm nào gọi với hằng số. Đo lần đầu ở -O2 ra 1,0× — chẳng lợi gì. Hóa ra bản clone chuyên biệt chỉ bật ở -O3: khi đó hằng được nướng vào, phép chia hóa thành nhân ma thuật, nhanh 1,3 lần. Một tối ưu có trong compiler khác hẳn với nó đang chạy.