Ngắt (Interrupt) và DMA (Direct Memory Access)
1. Tổng quan
Ngắt (Interrupt) là một cơ chế chuyển điều khiển bất đồng bộ, trong đó khi CPU đang thực thi chương trình một cách tuần tự mà phát sinh một sự kiện cần xử lý ngay lập tức—hoàn tất I/O, ngoại lệ, tín hiệu bên ngoài—thì CPU tạm ngưng luồng thực thi hiện tại, trao quyền điều khiển cho trình phục vụ ngắt (ISR), rồi quay về vị trí ban đầu. DMA (Direct Memory Access) là một kỹ thuật I/O trong đó một bộ điều khiển chuyên dụng truyền dữ liệu I/O khối lượng lớn trực tiếp giữa thiết bị I/O và bộ nhớ chính mà không đi qua CPU, giải phóng CPU khỏi công việc giá trị thấp là sao chép dữ liệu.
Bối cảnh ra đời của ngắt và DMA nằm ở sự mất cân bằng tốc độ (speed gap) giữa CPU và các thiết bị I/O. CPU xử lý lệnh ở đơn vị nano giây, nhưng các thiết bị ngoại vi như đĩa, mạng, bàn phím hoạt động ở đơn vị mili giây đến micro giây, nên giữa hai bên tồn tại chênh lệch tốc độ hàng nghìn đến hàng triệu lần. I/O điều khiển bằng chương trình (Programmed I/O) mà máy tính thời kỳ đầu sử dụng là phương thức thăm dò (polling) trong đó CPU đọc lặp đi lặp lại thanh ghi trạng thái thiết bị để chờ hoàn tất; trong trường hợp này CPU không làm được việc gì có ích cho đến khi thiết bị chậm sẵn sàng và lãng phí hàng trăm triệu chu kỳ vào chờ bận (busy waiting). Mặc dù CPU có thể xử lý hàng triệu lệnh khác trong vài mili giây đọc một khối đĩa, nó lại vứt bỏ tất cả.
Ngắt giải quyết sự lãng phí này bằng phương thức hướng sự kiện (event-driven) là "hãy báo cho CPU khi thiết bị sẵn sàng". CPU yêu cầu I/O rồi ngay lập tức chuyển sang công việc khác, và khi thiết bị hoàn tất nó gửi tín hiệu ngắt để thu hút sự chú ý của CPU. Nhờ đó loại bỏ được lãng phí chu kỳ CPU và đặt nền móng cho đa nhiệm và đáp ứng thời gian thực. Tuy nhiên chỉ ngắt thôi là chưa đủ, vì bản thân việc truyền dữ liệu (di chuyển byte giữa bộ nhớ và bộ đệm thiết bị) vẫn phải do CPU thực hiện. Để truyền 1KB cần phát sinh một ngắt cho mỗi byte (hoặc word) hoặc CPU phải chạy vòng lặp, nên trong truyền tốc độ cao, khối lượng lớn, chính chi phí xử lý ngắt trở thành nút cổ chai.
Ở đây cần đính chính một hiểu lầm thường gặp. Ngắt không phải là kỹ thuật giảm lượng dữ liệu truyền mà là kỹ thuật loại bỏ thời gian CPU phải chờ, còn DMA là kỹ thuật loại bỏ công sức CPU dành cho việc truyền. Nếu chỉ dùng ngắt, CPU không chờ nhưng phải thức dậy ở mỗi đơn vị truyền để tự mình vận chuyển byte. Nếu chỉ dùng DMA mà kiểm tra hoàn tất bằng thăm dò thì không có công sức truyền nhưng CPU lại bị trói buộc vì phải chờ hoàn tất. Chỉ khi kết hợp hai kỹ thuật mới hoàn thiện được I/O lý tưởng trong đó CPU "không chờ cũng không vận chuyển". Trên tiền đề về tính bổ sung này, ta xem xét từng cơ chế dưới đây.
DMA bổ sung đúng điểm này. CPU chỉ can thiệp vào "bắt đầu truyền" và "hoàn tất truyền", còn việc di chuyển byte thực tế ở giữa do bộ điều khiển DMA (DMAC) đảm nhiệm hoàn toàn. Kết quả là ngắt "giải phóng CPU khỏi việc chờ" còn DMA "giải phóng CPU khỏi việc sao chép dữ liệu". Hai kỹ thuật không ở quan hệ cạnh tranh mà ở quan hệ bổ sung lẫn nhau, và mọi đường I/O hiệu năng cao hiện đại (NVMe SSD, NIC 100GbE, GPU) đều vận hành bằng tổ hợp "truyền trọn một khối bằng DMA, và khi truyền xong thì báo cho CPU bằng một ngắt". Dưới đây ta xử lý hoạt động nội bộ và tương tác của từng cơ chế ở mức chuyên sâu.
2. Cơ chế xử lý ngắt
Khi ngắt phát sinh, CPU đi vào chu kỳ ngắt ngay sau khi hoàn tất thực thi lệnh hiện tại (ranh giới lệnh). Cốt lõi là yêu cầu về tính trong suốt (transparency) rằng "phải có thể quay về chính xác điểm bị gián đoạn", và vì thế nhất thiết kèm theo quá trình lưu rồi khôi phục ngữ cảnh (context) hiện tại. Nếu quá trình này sai lệch, ngắt trở thành lỗi làm hỏng chương trình, nên phần cứng và hệ điều hành phối hợp một cách tinh vi.
Trách nhiệm bảo đảm tính trong suốt này được chia cho phần cứng và phần mềm. Phần cứng (CPU) đảm nhận đến việc nhận diện ranh giới lệnh, tự động lưu PC và PSW, và rẽ nhánh qua bảng vector, còn phần mềm (ISR) đảm nhận việc lưu và khôi phục các thanh ghi đa dụng mà nó sẽ làm hỏng cùng việc xử lý sự kiện thực tế. Nếu sự phân chia này mơ hồ, ISR sẽ ghi đè lên các thanh ghi mà mã thông thường đang dùng và chương trình hoạt động sai sau khi quay về. Do đó trình biên dịch và hệ điều hành áp dụng cho ISR các quy tắc đặc biệt khác với quy ước gọi (calling convention) (lưu toàn bộ thanh ghi được dùng, chỉ dùng trạng thái cục bộ để có thể tái nhập), và ngay cả trong ngôn ngữ C hàm ISR cũng được biên dịch riêng biệt bằng thuộc tính interrupt hoặc phần mở đầu/kết thúc riêng.
Trình tự xử lý ngắt điển hình như sau. Thứ nhất, thiết bị gửi tín hiệu yêu cầu ngắt (IRQ) đến bộ điều khiển ngắt (ví dụ APIC trên x86). Thứ hai, bộ điều khiển phán định ưu tiên và kích hoạt chân INTR của CPU. Thứ ba, sau khi hoàn tất lệnh hiện tại, CPU kiểm tra có chấp nhận ngắt hay không (có bị che hay không). Thứ tư, nếu chấp nhận thì lưu bộ đếm chương trình (PC) và thanh ghi trạng thái (PSW) hiện tại lên ngăn xếp, và lưu thêm các thanh ghi đa dụng (một phần do ISR lưu). Thứ năm, từ bảng vector ngắt đọc địa chỉ ISR tương ứng với số ngắt đó và nạp vào PC. Thứ sáu, ISR được thực thi, kiểm tra trạng thái thiết bị và thực hiện xử lý cần thiết, rồi thông báo hoàn tất cho bộ điều khiển (EOI, End Of Interrupt). Thứ bảy, khôi phục ngữ cảnh đã lưu và quay về điểm gián đoạn bằng lệnh IRET.
flowchart TB
START["Thực thi chương trình bình thường"] --> CHK{"Kiểm tra ngắt tại ranh giới lệnh"}
CHK -->|"Không có yêu cầu"| START
CHK -->|"Có yêu cầu"| MASK{"Ngắt đang được bật?"}
MASK -->|"Bị che"| START
MASK -->|"Cho phép"| SAVE["Lưu ngữ cảnh(PC·PSW·thanh ghi)"]
SAVE --> VEC["Lấy địa chỉ ISR từ bảng vector"]
VEC --> ISR["Chạy ISR(xử lý thiết bị·thông báo EOI)"]
ISR --> REST["Khôi phục ngữ cảnh"]
REST --> IRET["Quay về điểm gián đoạn bằng IRET"]
IRET --> START
Ở đây vai trò của ngắt có vector (vectored interrupt) là quan trọng. Phương thức thời kỳ đầu có một ISR duy nhất thăm dò (polling) lần lượt mọi thiết bị để tìm nguyên nhân, nhưng điều này làm độ trễ tăng tỷ lệ với số thiết bị. Phương thức có vector cho thiết bị cung cấp số nhận dạng (vector) của nó cùng với ngắt, để CPU rẽ nhánh thẳng đến ISR tương ứng từ bảng vector. Ví dụ x86 có 256 vector (0–255), trong đó 0–31 là ngoại lệ CPU và từ 32 trở lên được gán cho thiết bị bên ngoài. Nhờ cấu trúc này, độ trễ ngắt (interrupt latency) được giữ ổn định ngay cả khi có hàng trăm thiết bị.
Khi thiết kế hệ thống thời gian thực, phải quản lý độ trễ ngắt bằng cách phân rã thành các thành phần. Độ trễ được chia thành ① độ trễ do ngắt bị tắt là chờ cho khoảng ngắt bị tắt kết thúc, ② độ trễ phần cứng là phần cứng truyền tín hiệu và CPU đạt đến ranh giới lệnh, ③ độ trễ điều phối dành cho việc lưu ngữ cảnh và rẽ nhánh vector, ④ độ trễ xử lý cho đến khi ISR hoàn tất việc xử lý thực tế. Trong các lĩnh vực như ô tô, hàng không nơi độ trễ xấu nhất (worst-case) gắn trực tiếp với an toàn, để giữ ① ngắn người ta giới hạn khoảng tắt ngắt trong vùng tới hạn trong vòng vài chục chu kỳ, và thiết kế ISR chỉ thực hiện xử lý tối thiểu cần thiết rồi chuyển phần còn lại sang nửa dưới (bottom-half). Tóm lại, câu "ngắt thì nhanh" phải được đọc không phải là mức trung bình mà là sự bảo đảm cận trên của từng thành phần đã phân rã.
Ngoài ra, ngắt lồng nhau (nested interrupt) và ưu tiên chi phối tính thời gian thực. Nếu trong khi ISR đang chạy mà có ngắt ưu tiên cao hơn vào thì phải gián đoạn ISR hiện tại lần nữa và xử lý ISR cấp cao hơn trước, nên để làm vậy mức che được điều chỉnh tại điểm vào ISR sao cho chỉ cho phép các ngắt cấp cao hơn. Ví dụ, trong bộ điều khiển động cơ công nghiệp, "phát hiện mất điện" được đặt làm ngắt không che được ưu tiên cao nhất (NMI) để trong mọi tình huống đều thực thi dừng an toàn ngay lập tức. Ngược lại, ngắt cần xử lý dài thì giảm thiểu ISR và chuyển phần còn lại sang xử lý trì hoãn (softirq·tasklet·workqueue của Linux, tức tách top-half/bottom-half), giữ khoảng tắt ngắt ngắn để bảo đảm khả năng đáp ứng của các thiết bị khác.
3. Các loại ngắt
Ngắt được phân loại theo nhiều trục tùy nguyên nhân phát sinh, và mỗi loại khác nhau về phương thức xử lý và ưu tiên. Chỉ khi phân biệt chính xác các loại mới không nhầm lẫn ngoại lệ (exception) với ngắt bên ngoài và mới thiết kế đúng việc xử lý bẫy và xử lý thiết bị của hệ điều hành. Đặc biệt, phân biệt "đồng bộ/bất đồng bộ" và "bên trong/bên ngoài" là quan trọng về mặt thực tiễn trong gỡ lỗi và thiết kế thời gian thực.
Cái phát sinh bên trong và đồng bộ với sự thực thi của CPU là ngoại lệ (trap/exception). Chia cho không, lỗi trang, vi phạm quyền, lời gọi hệ thống (ngắt phần mềm) v.v. thuộc về đây; vì nguyên nhân là sự thực thi của một lệnh cụ thể nên chúng tái lập được và phát sinh một cách xác định tại điểm lệnh đó. Ngược lại, ngắt phần cứng đi vào một cách bất đồng bộ từ thiết bị bên ngoài không liên quan đến sự thực thi của CPU, với các ví dụ tiêu biểu là hoàn tất đĩa, gói mạng đến, nhịp định thời. Vì bất đồng bộ nên không thể dự đoán khi nào nó đến, do đó phát sinh vấn đề đồng thời (tranh chấp giữa ngắt và mã thông thường) khi truy cập cấu trúc dữ liệu dùng chung, và để ngăn điều này người ta tắt ngắt trong một khoảng ngắn hoặc dùng spinlock.
Trong các ngoại lệ, lỗi trang là ví dụ cho thấy sự tinh vi của thiết kế hệ điều hành. Nếu trang được truy cập trong bộ nhớ ảo không có trong bộ nhớ vật lý thì CPU phát sinh ngoại lệ lỗi trang, hệ điều hành nạp trang đó từ đĩa rồi thực thi lại "đúng lệnh đã gây lỗi". Nghĩa là ngoại lệ được dùng không chỉ cho việc xử lý lỗi mà còn như phương tiện hiện thực các chức năng bình thường như phân trang theo yêu cầu (demand paging) và sao chép khi ghi (copy-on-write). Mặt khác, lời gọi hệ thống là ngắt phần mềm (bẫy) do chương trình ứng dụng cố ý phát sinh, là cổng duy nhất để đi vào chế độ nhân một cách an toàn từ chế độ người dùng. Hiểu rằng "ngoại lệ/bẫy" như vậy không phải là tai nạn đơn thuần mà là sự chuyển điều khiển chủ động nâng đỡ việc bảo vệ và ảo hóa mới giải thích đúng được cách hệ điều hành hoạt động.
| Trục phân loại | Loại | Ví dụ | Đặc điểm |
|---|---|---|---|
| Vị trí phát sinh | Bên ngoài (phần cứng) | đĩa·NIC·định thời | Bất đồng bộ, thông báo hoàn tất I/O |
| Bên trong (ngoại lệ/bẫy) | chia-cho-không·lỗi trang·lời gọi hệ thống | Đồng bộ, do thực thi lệnh gây ra | |
| Che | Che được (IRQ) | ngắt thiết bị thông thường | Phần mềm có thể chặn tạm thời |
| Không che được (NMI) | bất thường nguồn·hỏng phần cứng | Không chặn được, xử lý ưu tiên cao nhất | |
| Phương thức tín hiệu | Kích mức | đường dùng chung của nhiều thiết bị | Duy trì trong khi tín hiệu được giữ |
| Kích cạnh | sự kiện một lần | Chỉ phát hiện tại khoảnh khắc thay đổi trạng thái |
Trong các phân biệt ở bảng, sự khác biệt giữa che được và không che được là mang tính quyết định trong thiết kế an toàn. Ngắt thiết bị thông thường có thể chặn tạm thời để bảo vệ vùng tới hạn, nhưng các sự kiện chí mạng như bất thường nguồn hay lỗi chẵn lẻ bộ nhớ thì không được chặn, nên được phân loại là NMI để trong mọi trường hợp đều được xử lý ngay. Ngoài ra, lựa chọn kích cạnh so với kích mức ảnh hưởng đến việc dùng chung ngắt và phòng chống mất mát. Kích mức có ưu điểm là khi nhiều thiết bị dùng chung một đường thì tín hiệu được giữ nên không bị bỏ sót, nhưng cần thăm dò để nhận diện thiết bị gây ra; kích cạnh chỉ phát hiện khoảnh khắc thay đổi nên nhanh, nhưng nếu ISR không xóa tín hiệu kịp thời thì có thể mất các ngắt kế tiếp. Một ví dụ tiêu biểu là sự cố thực tế trong nhân Linux trong đó ngắt PCI dùng chung làm thiết bị dừng dưới dạng "lost interrupt", bắt nguồn từ chính sự khác biệt cơ chế này.
4. Nguyên lý hoạt động và các chế độ truyền của DMA
Nhận thức cốt lõi của DMA là "việc di chuyển dữ liệu không nhất thiết phải đi qua thanh ghi của CPU". Vì bộ nhớ và bộ đệm thiết bị đều được nối với bus hệ thống, nên bất kỳ thiết bị nào có thể đảm nhận vai trò chủ bus (bus master) đều có thể đọc và ghi trực tiếp vào bộ nhớ. Bộ điều khiển DMA (DMAC) chính là phần cứng chuyên dụng thực hiện chức năng chủ bus này; một khi nhận từ CPU chỉ lệnh truyền "từ đâu (thiết bị), đến đâu (địa chỉ bắt đầu bộ nhớ), bao nhiêu byte", nó tự xử lý phần còn lại.
Để DMA hoạt động, nhất thiết phải xử lý vấn đề nhất quán bộ nhớ đệm (cache coherence). Vì CPU đọc ghi bộ nhớ thông qua bộ nhớ đệm, nên khi DMA cập nhật bộ nhớ trực tiếp sẽ phát sinh bất nhất với giá trị cũ còn lại trong bộ nhớ đệm CPU. Do đó, trước khi DMA nhận (thiết bị→bộ nhớ) phải vô hiệu hóa (invalidate) bộ nhớ đệm của vùng đó, và trước khi DMA gửi (bộ nhớ→thiết bị) phải xả (flush) bộ nhớ đệm về bộ nhớ để giá trị mới nhất được phản ánh. x86 hiện đại bảo đảm nhất quán DMA tự động bằng phần cứng (coherent DMA), nhưng trên hệ nhúng ARM v.v. trình điều khiển phải quản lý bộ nhớ đệm một cách tường minh hoặc cấp phát bộ đệm DMA không đệm (non-cacheable), và bỏ sót điều này trở thành lỗi khó truy vết "dữ liệu hỏng ngắt quãng".
Trình tự truyền như sau. CPU thiết lập vào thanh ghi của DMAC hướng truyền, địa chỉ bắt đầu bộ nhớ, và độ dài truyền (đếm), chỉ thị truyền rồi ngay lập tức chuyển sang công việc khác. Khi thiết bị đã chuẩn bị xong dữ liệu, DMAC giành quyền sử dụng bus (bus grant) từ CPU, ghi byte trực tiếp vào bộ nhớ và giảm số đếm, và khi số đếm về 0 thì phát sinh một ngắt hoàn tất truyền cho CPU. Như vậy CPU chỉ can thiệp hai lần—ở lúc đầu và lúc cuối—cho toàn bộ việc truyền hàng nghìn đến hàng triệu byte.
sequenceDiagram
participant CPU
participant DMAC as "Bộ điều khiển DMA"
participant DEV as "Thiết bị I/O"
participant MEM as "Bộ nhớ chính"
CPU->>DMAC: "Thiết lập truyền(địa chỉ·độ dài·hướng)"
Note over CPU: "Làm việc khác(không bị chặn)"
DEV->>DMAC: "Dữ liệu sẵn sàng(DREQ)"
DMAC->>CPU: "Yêu cầu quyền dùng bus(HOLD)"
CPU-->>DMAC: "Nhường bus(HLDA)"
loop "Truyền khối"
DEV->>DMAC: "Dữ liệu"
DMAC->>MEM: "Ghi trực tiếp vào bộ nhớ"
DMAC->>DMAC: "Giảm số đếm"
end
DMAC->>CPU: "Ngắt hoàn tất truyền"
CPU->>CPU: "Xử lý hoàn tất trong ISR"
Tùy theo cách DMAC chia sẻ bus với CPU, có ba chế độ truyền. Thứ nhất, đánh cắp chu kỳ (cycle stealing) truyền mỗi lần một word bằng cách "đánh cắp" các chu kỳ rảnh mà CPU không dùng bus; nó hầu như không ảnh hưởng đến hiệu năng CPU nhưng truyền chậm. Thứ hai, chế độ bùng nổ (burst/block mode) có DMAC độc chiếm bus để truyền trọn một khối trong một lần; việc truyền nhanh nhất, nhưng trong thời gian đó CPU có thể bị dừng vì không truy cập được bộ nhớ. Thứ ba, chế độ trong suốt (transparent mode) chỉ truyền trong các khoảng mà CPU rõ ràng không dùng bus, nên hoàn toàn không ảnh hưởng đến CPU nhưng chậm nhất. Ví dụ, phát luồng âm thanh quan trọng về thời gian thực chọn đánh cắp chu kỳ, còn sao lưu đĩa khối lượng lớn chọn chế độ bùng nổ, chọn chế độ khớp với đặc tính của ứng dụng.
Trong hệ thống hiện đại, vượt khỏi DMAC đơn giản, DMA làm chủ bus (bus-mastering DMA)—trong đó mỗi thiết bị tự trở thành chủ bus—là tiêu chuẩn, và các thiết bị PCIe (NVMe SSD, GPU, NIC) đều tích hợp bộ máy DMA riêng. Đặc biệt, DMA phân tán-gom (scatter-gather) DMA dựa trên descriptor xử lý nhiều vùng bộ nhớ nằm rải rác về mặt vật lý gộp thành một lệnh truyền, nên có thể truyền một lần cả bộ đệm người dùng không liền kề do bộ nhớ ảo. Đây là nền tảng phần cứng của mạng zero-copy và lưu trữ hiệu năng cao.
Các thiết bị tốc độ cao có CPU và bộ máy DMA phối hợp bất đồng bộ qua vòng descriptor (descriptor ring) trong bộ nhớ dùng chung. CPU (trình điều khiển) nhồi vào vòng các descriptor chứa địa chỉ và độ dài của bộ đệm cần truyền và tiến "chỉ số nhà sản xuất", còn bộ máy DMA của thiết bị đi theo "chỉ số nhà tiêu dùng", đọc descriptor, thực hiện truyền rồi ghi ngược lại cờ hoàn tất. Nhờ cấu trúc này, CPU và thiết bị có thể chồng lấn hàng nghìn lần truyền như một đường ống mà không chờ nhau, và vòng thu phát (TX/RX ring) của NIC cùng hàng đợi nộp/hoàn tất (SQ/CQ) của NVMe đều tuân theo nguyên lý này. Rốt cuộc, "DMA nhanh" phải được hiểu không phải là một lần truyền nhanh mà là có thể tiến hành nhiều lần truyền đồng thời (outstanding I/O) mà không chờ hoàn tất.
5. So sánh các phương thức I/O
Ba phương thức I/O—điều khiển bằng chương trình (thăm dò), hướng ngắt, và DMA—phải được hiểu là một quá trình tiến hóa đã giải phóng CPU một cách tiệm tiến theo trục "CPU can thiệp bao nhiêu". Hàm ý thực tiễn không đơn thuần là "DMA là tốt nhất" mà là phương thức phù hợp khác nhau tùy theo đánh đổi về kích thước dữ liệu, tính thời gian thực, và độ phức tạp hiện thực.
| Phân loại | Điều khiển bằng chương trình (thăm dò) | Hướng ngắt | DMA |
|---|---|---|---|
| Mức CPU can thiệp | Toàn quá trình (chờ bận) | Mỗi đơn vị dữ liệu | Chỉ 2 lần: bắt đầu·hoàn tất |
| Chủ thể di chuyển dữ liệu | CPU | CPU | Bộ điều khiển DMA |
| Hiệu suất CPU | Rất thấp | Trung bình | Rất cao |
| Độ trễ đáp ứng | Phụ thuộc chu kỳ thăm dò | Mức độ trễ ngắt | Thấp (theo khối) |
| Tình huống phù hợp | Siêu nhanh·lượng nhỏ, thiết bị đơn giản | Tốc độ thấp-trung·sự kiện không định kỳ | Truyền khối tốc độ cao·khối lượng lớn |
| Nguồn chi phí phụ | Chờ bận | Lưu/khôi phục ngữ cảnh | Tranh chấp bus·chi phí thiết lập |
Lựa chọn giữa ba phương thức có thể tóm lại là được quyết định bởi tổ hợp hai biến "tốc độ thiết bị" và "kích thước đơn vị truyền". Thiết bị đơn giản tốc độ thấp, lượng nhỏ nhưng cần tức thời (đọc một byte từ cảm biến nhiệt độ) thì thăm dò không có chi phí thiết lập là gọn gàng; thiết bị tốc độ thấp-trung với sự kiện thưa thớt (bàn phím·chuột) thì ngắt phù hợp; còn truyền khối tốc độ cao, khối lượng lớn (đĩa·mạng·GPU) thì DMA là lựa chọn thực tế duy nhất. Điều quan trọng là ranh giới này không ngừng dịch chuyển theo sự phát triển phần cứng—một ví dụ là cách 1GbE, vốn ngắt từng đủ, tăng tốc lên 100GbE và chuyển trở lại tổ hợp DMA và thăm dò (NAPI). Thay vì ghi nhớ một phương thức cụ thể như đáp án đúng, kỹ sư chuyên nghiệp phải có tư duy phán định đánh đổi trên các trục tốc độ và đơn vị truyền.
Thăm dò phần lớn kém hiệu quả, nhưng lại có thể có lợi trong các lần truyền rất ngắn, tức thời. Ngắt tốn hàng trăm đến hàng nghìn chu kỳ cho lưu/khôi phục ngữ cảnh và rẽ nhánh vector, nên nếu dữ liệu cần truyền chỉ một hai byte thì chi phí phụ này vượt cả bản thân việc truyền. Nghịch lý là trên mạng tốc độ cao 10GbE·100GbE, khi gói đổ về quá nhanh khiến ngắt phát sinh hàng triệu lần mỗi giây thì phát sinh bão ngắt (interrupt storm) trong đó CPU bão hòa chỉ với việc xử lý ISR. Để ngăn điều này, Linux NAPI một khi nhận một ngắt thì sau đó chuyển sang thăm dò để xử lý gộp nhiều gói, còn DPDK thì quay về phương thức tắt hẳn ngắt và để một lõi chuyên dụng liên tục thăm dò. Nghĩa là "thăm dò → ngắt → DMA" không phải là sự thay thế đơn thuần mà là một phổ cùng tồn tại và quay lại tùy tình huống.
Nhìn bằng con số cụ thể, khi đọc một khối 4KB từ đĩa, phương thức thăm dò có CPU kiểm tra trạng thái suốt vài mili giây và vứt bỏ hàng triệu chu kỳ, trong khi DMA chỉ cần CPU thiết lập truyền trong vài chục chu kỳ rồi xử lý một ngắt hoàn tất duy nhất (vài nghìn chu kỳ). NVMe SSD đạt hàng triệu IOPS mỗi giây là vì, ngoài tổ hợp DMA + ngắt hoàn tất này, hàng đợi lệnh sâu (tối đa 64K hàng đợi × độ sâu 64K) tiến hành nhiều lần truyền đồng thời.
Một trường hợp áp dụng cụ thể có thể kể đến broker của Apache Kafka. Khi Kafka truyền một phân đoạn log trên đĩa đến người tiêu dùng, nó dùng lời gọi hệ thống sendfile, lời gọi này giao dữ liệu đã đưa lên bộ nhớ đệm trang bằng DMA đĩa thẳng đến NIC qua DMA phân tán-gom mà không đi qua không gian người dùng. Trong suốt quá trình truyền, việc CPU làm chỉ là thiết lập truyền và xử lý ngắt hoàn tất, nên một broker đơn lẻ chuyển tiếp hàng trăm nghìn thông điệp mỗi giây mà vẫn giữ mức sử dụng CPU thấp. Đây là cấu trúc điển hình trong đó ngắt (thông báo hoàn tất) và DMA (di chuyển thực tế) kết hợp để nâng thông lượng.
6. Chuyên sâu: Sự tiến hóa của ngắt và DMA trong hệ thống hiện đại
Trong điện toán hiệu năng cao hiện đại, ngắt và DMA đã tiến hóa mạnh mẽ để đáp ứng các yêu cầu đa lõi, ảo hóa, và bảo mật. Đó là vì các cấu trúc PIC đơn (8259) và DMAC đơn (8237) cũ không thể gánh được hàng chục lõi và hàng triệu IOPS. Mục này nêu bật các phát triển then chốt chi phối hiệu năng và bảo mật trong thực tiễn.
Thứ nhất, MSI/MSI-X (Message Signaled Interrupt) là phương thức trong đó, thay cho chân ngắt vật lý, thiết bị truyền ngắt bằng cách ghi một giá trị cụ thể vào một địa chỉ bộ nhớ đã thỏa thuận. Phương thức dựa trên chân có các vấn đề thăm dò nhận diện do đường dùng chung và thiếu đường, nhưng MSI-X hỗ trợ tối đa 2.048 vector độc lập cho mỗi thiết bị, cho phép NIC đa hàng đợi và NVMe có hàng đợi ngắt chuyên dụng cho mỗi lõi. Ví dụ, NIC 100GbE trong máy chủ 64 lõi nối từng hàng đợi trong 64 hàng đợi nhận của nó với vector MSI-X của một lõi khác (RSS, Receive Side Scaling), phân tán việc xử lý ngắt ra toàn bộ các lõi và nâng cao tính cục bộ của bộ nhớ đệm.
Thứ hai, IOMMU (Input-Output MMU, Intel VT-d·AMD-Vi) giải quyết các vấn đề bảo mật và ảo hóa của DMA. DMA truyền thống truy cập trực tiếp địa chỉ vật lý, nên khả thi một tấn công DMA trong đó thiết bị độc hại hoặc lỗi ghi đè lên bộ nhớ tùy ý (ví dụ cướp DMA qua Thunderbolt). IOMMU dịch địa chỉ ảo I/O mà thiết bị dùng thành địa chỉ vật lý thực và giới hạn phạm vi truy cập, cô lập thiết bị sao cho chỉ truy cập vùng được phép. Đây là công nghệ then chốt bảo vệ bộ nhớ giữa các VM trong khi gán một thiết bị vật lý trực tiếp cho một máy ảo (PCI passthrough), và trở thành nền tảng của ảo hóa mạng dựa trên SR-IOV của đám mây.
Thứ ba, gộp ngắt (interrupt coalescing) và thăm dò lai là các giải pháp thực tiễn cho vấn đề bão ngắt. Bằng cách để thiết bị gom nhiều sự kiện và phát một ngắt (coalescing), hoặc thăm dò trong một khoảng thời gian nhất định rồi chuyển sang ngắt, chúng cân bằng giữa thông lượng và độ trễ. Thăm dò lai của trình điều khiển NVMe tắt ngắt hoàn tất và thăm dò ngắn trong các tình huống IOPS cao, giảm đồng thời cả chi phí ngắt lẫn độ trễ. Tính đến năm 2024, io_uring của nhân Linux là một trường hợp tiêu biểu kết hợp thăm dò hoàn tất (IOPOLL) như vậy với DMA để đạt hàng triệu IOPS trong không gian người dùng.
Thứ tư, việc phân phối ngắt trong môi trường ảo hóa chi phối hiệu năng. Khi một ngắt vật lý phát sinh trong máy ảo, theo truyền thống bộ giám sát máy ảo (hypervisor) chặn lại và tiêm (inject) vào khách, và việc vào/ra VM (VM-exit) này là một chi phí lớn. Hỗ trợ phần cứng ngắt ảo như Intel APICv và AMD AVIC cùng ngắt đã đăng (posted interrupt) loại bỏ chi phí này bằng cách phân phối ngắt trực tiếp đến vCPU của khách mà không cần hypervisor can thiệp. Tổ hợp gán chức năng ảo (VF) của một NIC vật lý trực tiếp cho một VM qua SR-IOV, cô lập DMA của VF đó bằng IOMMU, và phân phối ngắt trực tiếp bằng ngắt đã đăng chính là đường tiêu chuẩn của mạng hiệu năng cao trên đám mây ngày nay.
7. Điểm cân nhắc và hàm ý
Ngắt và DMA là các khái niệm nền tảng hơn nửa thế kỷ, nhưng từ góc nhìn của kỹ sư chuyên nghiệp thiết kế các hệ thống hiệu năng cao, thời gian thực, và bảo mật thì chúng vẫn là nguồn gốc của các đánh đổi then chốt. Phải cân nhắc toàn diện các mục sau.
Cân bằng giữa độ trễ ngắt và thông lượng: Điều khiển thời gian thực (robot·ô tô) sống còn nhờ độ trễ ngắt xác định (worst-case latency), nên phải giữ ISR cực ngắn và bảo đảm ưu tiên cao hơn. Ngược lại, máy chủ thông lượng cao hưởng lợi từ việc giảm số lần ngắt bằng gộp ngắt·NAPI·thăm dò. Khi một hệ thống có cả hai yêu cầu (ví dụ ECU lái tự hành) thì phải đồng thời tách ưu tiên và cô lập lõi (core isolation).
Bảo mật DMA và ranh giới tin cậy: Vì DMA về bản chất là truy cập bộ nhớ trực tiếp nên nó có thể phá vỡ ranh giới tin cậy. Với các cổng bên ngoài (Thunderbolt·USB4) và các thiết bị passthrough của đám mây nhất thiết phải bật IOMMU, và trong môi trường điện toán cơ mật phải áp dụng mã hóa và kiểm chứng đối với DMA của thiết bị (ví dụ PCIe IDE/TDISP). Thói quen "tắt IOMMU để lấy hiệu năng" trở thành kẽ hở cho sự cố bảo mật, nên phải phán định thận trọng.
Khả năng mở rộng đa lõi và tính ái lực ngắt (affinity): Nếu ngắt dồn vào một lõi duy nhất thì chỉ lõi đó bão hòa và hiệu năng tổng thể bị giới hạn. Phân tán tải bằng nhiều vector MSI-X và thiết lập ái lực ngắt, đồng thời khớp lõi xử lý ngắt với lõi tiêu thụ dữ liệu (tính cục bộ bộ nhớ đệm) để tối thiểu hóa truy cập bộ nhớ từ xa trong môi trường NUMA.
Góc nhìn công suất và năng lượng: Vì thăm dò giữ CPU luôn thức và tiêu thụ điện, nên trong IoT·nhúng chạy bằng pin, thiết kế dựa trên ngắt đặt CPU vào trạng thái ngủ công suất thấp và chỉ đánh thức khi có sự kiện là thiết yếu. Ngược lại, tải nhạy độ trễ của trung tâm dữ liệu chấp nhận chi phí điện và chọn thăm dò. Công suất và hiệu năng là hai đầu của cùng một trục, và đặc tính tải quyết định lựa chọn.
Thiết kế tích hợp với các công nghệ liên đới: DMA mở rộng sang I/O zero-copy, RDMA (DMA từ xa), GPU Direct, và SmartNIC·DPU. Đặc biệt, trong trung tâm dữ liệu AI, GPUDirect RDMA để NIC DMA trực tiếp vào bộ nhớ GPU mà không đi qua CPU hay bộ nhớ hệ thống, loại bỏ nút cổ chai truyền thông của huấn luyện phân tán. Kỹ sư chuyên nghiệp phải có khả năng tối ưu toàn bộ đường dữ liệu từ góc nhìn DMA giữa các nút (RDMA), vượt khỏi DMA một nút.
Tài liệu tham khảo
- Intel, "Intel 64 and IA-32 Architectures Software Developer's Manual, Vol.3 (System Programming): Interrupt and Exception Handling, I/O" — https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
- The Linux Kernel Documentation, "Interrupt Handling / MSI / DMA-API / IOMMU" — https://docs.kernel.org/core-api/dma-api.html
- PCI-SIG, "PCI Express Base Specification (MSI-X, Address Translation Services)" — https://pcisig.com/specifications
- Thunderclap, "DMA attacks and the IOMMU" (NDSS 2019) — https://www.ndss-symposium.org/ndss-paper/thunderclap/
Tóm tắt một câu: Ngắt là sự chuyển điều khiển hướng sự kiện giải phóng CPU khỏi việc chờ các thiết bị chậm, còn DMA là kỹ thuật giao việc di chuyển dữ liệu cho một bộ điều khiển chuyên dụng để giải phóng CPU khỏi công việc sao chép; I/O hiệu năng cao hiện đại mở rộng, trên nền tổ hợp "truyền một khối bằng DMA và một ngắt khi hoàn tất", với MSI-X·IOMMU·sự quay lại thăm dò.