1. DMA
DMA(Direct Memory Access,存儲器直接訪問)
DMA是一種高速的數據傳輸操作,允許在外部設備和存儲器之間直接讀寫數據,DMA數據傳輸操作在DMA控制器(DMAC)的控制下進行的。
CPU除了在數據傳輸開始和結束時候做中斷處理,在數據傳輸過程中CPU可以進行其他的工作。這樣,在大部分時間裏,CPU和輸入輸出都處於並行操作。因此,使整個計算機系統的效率大大提高。
DMA傳送方式是讓存儲器與外設、外設與外設之間直接交換數據,不需要經過CPU中轉,減少了這個中間環節,並且內存地址的修改、數據傳送完畢都是由硬件電路實現的,因此很大程度上提高了數據傳輸效率。
當沒有DMA的時候,數據讀取流程:
- 用戶程序執行read系統調用
- 操作系統爲該用戶進程分配CPU
- CPU向IO控制器發送IO請求
- 用戶進程讓出CPU,等待IO完成
- 操作系統調度CPU執行其他任務
- 數據寫入至IO控制器的緩衝寄存器
- 緩衝寄存器滿了向CPU發出中斷信號
- CPU讀取數據至內存
有DMA的時候,數據讀取流程:
- 用戶程序執行read系統調用
- 操作系統爲該用戶進程分配CPU
- CPU向DMA發送IO請求
- 用戶進程讓出CPU,等待IO完成
- 操作系統調度CPU執行其他任務
- 數據寫入至IO控制器的緩衝寄存器
- DMA不斷獲取緩衝寄存器中的數據傳輸至內存
- 數據獲取完畢後向CPU發出中斷信號
簡單點說就是DMA操作,能夠減少IO操作的CPU佔用和中斷,讓CPU有機會做更多的其他操作,而不是處理緩慢的IO操作。
2. read與write
這種模式會發生3次拷貝,4次上下文切換。
- 用戶程序執行read系統調用,操作系統OS從用戶空間切換到內核空間(第一次上下文切換)
- 通過DMA將數據讀取到內核空間緩衝區(第一次拷貝,DMA)
- 操作系統將系統緩衝區數據複製到用戶空間緩衝區(第二次拷貝,CPU)
- read系統調用返回,系統從內核空間切回到用戶空間的(第二次上下文切換)
- 用戶程序執行write系統調用,操作系統從用戶模式切換到內核模式(第三次上下文切換)
- 將用戶空間緩衝區數據複製到內核空間的Socket緩衝區(第三次拷貝,CPU)
- write系統調用返回,操作系統從內核空間切回到用戶空間(第四次上下文切換)
- 操作系統將內核空間Socket緩衝區的數據通過DMA寫到網卡(第四次拷貝,DMA)
3. mmap
mmap大概是memory map的縮寫,核心的思想就是通過內存映射實現內核緩衝區與應用程序共享。
用戶程序調用mmap,數據通過DMA被拷貝的內核緩衝區,操作系統把這段內核緩衝區與用戶程序共享,這樣就不需要把內核緩衝區的內容往用戶空間拷貝。
mmap比read很明顯減少了一次拷貝,在執行大文件拷貝時效率更高。
mmap問題是,當map了一個文件,但是當這個文件被另一個進程截斷了, write系統調用會因爲訪問非法地址而被sigbus信號終止,sigbus信號默認會殺死進程。
- 用戶程序執行mmap系統調用,操作系統從用戶空間切換到內核空間(第一次上下文切換)
- 通過DMA將磁盤文件中的內容拷貝到內核空間緩衝區中(第一次拷貝,DMA)
- mmap系統調用返回,操作系統從內核空間切回到用戶空間(第二次上下文切換)
- 用戶程序執行write系統調用,從用戶空間切換到內核空間(第三次上下文切換)
- 數據從內核空間緩衝區拷貝到內核空間Socket緩衝區(第二次拷貝,CPU)
- write系統調用返回,操作系統從內核空間切回到用戶空間(第四次上下文切換)
- DMA將內核空間Socket緩衝區中的數據拷貝到網卡(第三次拷貝,DMA)
第4步,因爲用戶空間和內核空間共享這個緩衝區,不用拷貝從內核空間數據到用戶空間。
可以看出mmap與直接read相比,減少了一次從內核緩衝區到用戶緩衝區的CPU拷貝。
4. sendfile
Linux在2.1加入引入sendfile系統調用,它在輸入的描述符in_fd和輸出的描述符out_fd之間傳送數據。
描述符out_fd必須指向一個套接字,in_fd指向的文件必須是可以mmap的,sendfile只能將數據從文件傳遞到套接字上,反之則不行。
4.1 不支持收集拷貝DMA的sendfile
- 用戶程序執行sendfile系統調用,操作系統從用戶空間切換到內核空間(第一次上下文切換)
- 通過DMA將磁盤文件中的數據拷貝到內核空間緩衝區(第一次拷貝,DMA)
- 直接將內核緩衝區數據拷貝到內核中Socket緩衝區(第二次拷貝,CPU)
- sendfile系統調用返回,操作系統從內核空間切回到用戶空間(第二次上下文切換)
- 通過DMA將內核空間Socket緩衝區中的數據拷貝到網卡(第三次拷貝,DMA)
通過不帶有收集拷貝功能的DMA,sendfile只用2次用戶空間與內核空間的上下文切換,以及3次數據的拷貝。
4.2 支持收集拷貝DMA的sendfile
- 用戶程序執行sendfile系統調用,操作系統從用戶空間切到內核空間(第一次上下文切換)
- 通過DMA將磁盤文件數據拷貝到內核空間緩衝區中(第一次拷貝,DMA)
- 將系統緩衝區的內存地址和偏移量信息拷貝到Socket緩衝區
- sendfile系統調用返回,操作系統從內核空間切回到用戶空間(第二次上下文切換)
- DMA根據Socket緩衝區中系統緩衝區位置和偏移量信息直接將內核空間緩衝區中的數據拷貝到網卡(第二次拷貝,DMA)
通過帶有收集拷貝功能的DMA,調用sendfile只用2次用戶空間與內核空間的上下文切換,以及2次數據的拷貝,而且這2次的數據拷貝都是DMA拷貝,從而實現真正的零拷貝。
5. splice
Linux在2.6.17加入splice系統調用,爲了解決sendfile只適用於將數據從文件拷貝到套接字上的問題。
splice可以用於在兩個文件描述符中移動數據,splice調用在兩個文件描述符之間移動數據,而不需要數據在內核空間和用戶空間來回拷貝。
6. 小結
零拷貝主要是避免CPU數據拷貝和操作系統在用戶空間和內核空間切換來提升性能。
數據拷貝又分通過CPU數據拷貝,和通過DMA進行數據拷貝,儘量讓DMA來執行IO操作。
數據在用戶空間和內核空間拷貝時,系統通常應用用寫時複製(COW,copy on write)來減少系統開銷。簡單的來說就是多個用戶程序共享數據塊的時候,先不執行拷貝操作,當有修改操作的時候再執行拷貝操作。