Restartable Sequences: Vũ khí bí mật giúp tối ưu hóa hiệu năng trên CPU đa nhân

Công nghệ31 tháng 5, 2026·5 phút đọc

Restartable Sequences (rseq) là một tính năng ít người biết đến trên Linux 4.18+, cho phép tạo cấu trúc dữ liệu an toàn luồng mà không cần khóa hay atomic. Công nghệ này mang lại hiệu suất vượt trội trên các hệ thống có hàng trăm nhân CPU, thay thế hoàn toàn các phương pháp truyền thống.

Restartable Sequences: Vũ khí bí mật giúp tối ưu hóa hiệu năng trên CPU đa nhân

Trong thế giới lập trình hệ thống hiện nay, một trong những bí mật được giữ kín nhất nằm ở khái niệm Restartable Sequences (hay rseq), được giới thiệu trong Linux phiên bản 4.18 vào khoảng năm 2018. Đây là công nghệ cho phép các nhà phát triển tạo ra các cấu trúc dữ liệu an toàn luồng (thread-safe) mà không cần đến khóa (locks) hay các thao tác atomic, đồng thời khả năng mở rộng cực tốt trên các vi xử lý đa nhân.

Hiện tại, việc sử dụng rseq trên Linux đòi hỏi phải viết mã Assembly thủ công. Tuy nhiên, tôi tin rằng trong tương lai, tất cả các hệ điều hành sẽ được cập nhật để hỗ trợ rseq(), mọi ngôn ngữ lập trình hệ thống sẽ được thiết kế lại để biểu diễn các chuỗi có thể khởi động lại, và các thư viện cấu trúc dữ liệu sẽ được viết lại để tận dụng tính năng này.

Sơ đồ minh họa Restartable SequencesSơ đồ minh họa Restartable Sequences

Kỷ nguyên của CPU đa nhân

Cho đến nay, chỉ có một số ít phần mềm sử dụng rseq như tcmalloc, jemalloc, glibc và Cosmopolitan. Tuy nhiên, tình hình sắp thay đổi khi các vi xử lý sở hữu 128 hoặc thậm chí 192 nhân đang trở nên dễ tiếp cận hơn về mặt chi phí.

Các lập trình viên hệ thống nếu không sở hữu một trạm làm việc mạnh mẽ sẽ bị bỏ lại phía sau, bỏ lỡ cơ hội tối ưu hóa hiệu năng gấp 10 lần. Ví dụ, tôi đã không thể đạt được sự tăng tốc đáng kể cho phép nhân ma trận năm ngoái nếu không đầu tư vào một CPU 96 nhân. Mặc dù việc này khiến tôi "cháy túi" trong vài tháng, nhưng nó hoàn toàn xứng đáng khi công việc của tôi được cộng đồng AI chú ý và giúp dự án được 32% các tổ chức áp dụng.

AMD Ryzen Threadripper Pro 7995WXAMD Ryzen Threadripper Pro 7995WX

Vấn đề của Mutex và Atomic

Nếu bạn sử dụng Global Interpreter Lock (GIL) hoặc mutex để bảo vệ cấu trúc dữ liệu, hiệu suất sẽ bị chậm lại trên các hệ thống có hàng chục nhân vì chỉ một luồng có thể giữ khóa tại một thời điểm. Bạn có thể nghĩ đến việc sử dụng danh sách không khóa (lockless list) với atomic, nhưng vấn đề nằm ở việc chia sẻ cùng một vùng nhớ 64 byte (cacheline) giữa nhiều nhân. Điều này khiến CPU về cơ bản phải sử dụng một mutex nội bộ, và khả năng cao mutex của CPU không tốt bằng những gì bạn triển khai trong không gian người dùng (userspace).

Một cách tiếp cận thông minh hơn là phân mảnh (sharding) cấu trúc dữ liệu để mỗi CPU có vùng riêng. Tuy nhiên, cách tiếp cận này vẫn gặp vấn đề: chúng ta vẫn cần mutex vì hệ điều hành có thể tạm ngắt (preempt) và di chuyển luồng của bạn sang một CPU khác ngay giữa lúc tải số CPU và thực hiện thay đổi dữ liệu.

Cơ chế hoạt động của rseq

Đây là lúc Linux cung cấp giải pháp rseq(). Với restartable sequences, bạn có thể loại bỏ cả mutex và atomic, trong khi hệ điều hành vẫn tiếp tục quản lý việc lập lịch hoàn toàn.

Cách hoạt động như sau: Cosmopolitan C runtime sẽ cấp phát cho nhân (kernel) 32 byte bộ nhớ TLS khi tạo một luồng. Trong suốt vòng đời của luồng đó, kernel sẽ cập nhật bộ nhớ TLS này với số CPU bất cứ khi nào luồng được lập lịch lại. Điều này giúp cải thiện đáng kể hàm sched_getcpu(), giảm thời gian lấy số CPU từ 1 microsecond xuống chỉ còn 1 nanosecond.

System76 Thelio Astra với Ampere CPUSystem76 Thelio Astra với Ampere CPU

Tuy nhiên, điểm mấu chốt nằm ở trường thứ hai trong bộ nhớ TLS của rseq, cho phép luồng gửi thông tin ngược lại kernel. Thông thường trường rseq_cs là NULL, nhưng nó có thể được cập nhật bằng một con trỏ chỉ định một chuỗi lệnh Assembly trong chương trình của bạn.

Khi kernel tạm ngắt luồng của bạn và cố gắng di chuyển nó sang một CPU khác, nó sẽ nhận thấy rseq_cs không phải NULL và kiểm tra bộ đếm chương trình (program counter). Nếu nó nằm trong khoảng được chỉ định, kernel sẽ buộc luồng nhảy đến một trình xử lý hủy bỏ (abort handler) do bạn quy định. Trình xử lý này có thể thực hiện các thao tác như nhảy lại về đầu hàm để thử lại thao tác.

Hiệu suất vượt trội

Khi so sánh rseq với phiên bản di động của malloc() đã được tối ưu hóa heavily, tôi thấy mã nguồn chạy nhanh hơn 34 đến 43 lần. Nhưng nếu so sánh với một giải pháp ngây thơ sử dụng mutex của glibc để bảo vệ thao tác tăng giá trị, rseq thực sự có thể làm mọi thứ nhanh hơn một triệu lần xét về mức tiêu thụ CPU.

Trên các hệ thống như System76 Thelio Astra với CPU Ampere 128 nhân, hiệu năng của rseq càng thể hiện rõ rệt. Đây là minh chứng cho thấy kiến trúc ARM đã thực hiện được giấc mơ của RISC: nhiều nhân hơn với giá rẻ hơn và khả năng vượt trội so với các chip x86 đắt tiền hơn trong một số bài kiểm tra cụ thể.

Kết luận

Restartable sequences là một trong những kỹ thuật quan trọng nhất để khai thác sức mạnh của các vi xử lý đa nhân hiện đại. Bằng cách loại bỏ sự tranh giành (contention) và sử dụng bộ nhớ chia sẻ hiệu quả, rseq mở ra cánh cửa mới cho việc tối ưu hóa hiệu năng ở cấp độ thấp. Nếu bạn đang làm việc với hệ thống lớn hoặc AI, đây là công cụ bạn không thể bỏ qua.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗