io_uring相對libaio的優勢

1,libaio只支持direct_io,即旁路內核緩存,且用戶態參數buffer、size、offset也要對齊;
2,libaio每完成一個IO event至少需要兩個系統調用,用戶態提交IO:io_submit; 用戶態收割IO:io_getevents;
而io_uring由於用戶態與內核態共享IO提交隊列與完成隊列,用戶態可以不通過系統系統調用提交IO event

前提是:
用戶態在調用 io_uring_setup 時設置IORING_SETUP_SQPOLL 的 flag,這樣內核會啓動一個內核線程,即SQ線程。這個內核線程可以運行在某個指定的 core 上(通過 sq_thread_cpu 配置)。這個內核線程會不停的 Poll SQ,除非在一段時間內沒有 poll 到任何請求(通過 sq_thread_idle 配置),纔會掛起,用戶態程序只需要向IO提交隊列中寫入IO event即可;
如果沒有設置IORING_SETUP_SQPOLL,io_uring提交IO event時,也是需要一次系統調用的;
對於IO event的收割:
    1) 如果設置了IORING_SETUP_SQPOLL,IO收割也不需要系統調用,內核將在SQ線程中兼顧收割完成IO event並更新IO完成隊列(SQ線程同時也在polling SQ,即IO提交隊列,這是其主要工作),用戶態程序只需要遍歷IO完成隊列(完成隊列的head到tail的區間)就可以知道有沒有完成的IO event;
    2) 如果調用io_uring_setup 時設置了IORING_SETUP_IOPOLL,內核採用 polling 的模式收割完成IO。當沒有使用 SQ 線程時,io_uring_enter 函數會主動的 poll,以檢查提交的IO請求是否已經完成;
3,libaio在每次調用io_submit時,在內核態需要調用get_user_pages_fast來獲取用戶態buffer虛擬地址所映射的物理pages,然後用這些pages組織bio進而提交;
例如在塊設備提交IO的函數__blkdev_direct_IO中,需要先獲取用戶態buffer對應的物理pages:

而io_uring機制,如果設置了IORING_REGISTER_BUFFERS,內核會提前調用get_user_pages來獲得用戶態buffer虛擬地址對應的物理pages,這樣在開始提交IO的時候,內核發現如果提交的用戶態buffer虛擬地址曾經被註冊過,那麼就免去了虛擬地址到 pages的轉換,這樣就節省了在提交IO時再轉換pages的開銷;
4,libaio內存copy的開銷如下,而io_uring沒有此開銷(使用內存映射機制,用戶態與內核態共享一塊內存);
libaio詳細內存copy開銷如下,
1)對於libaio,用戶態調用io_submit每提交一個aio event時內核從用戶態copy內存的開銷是64+8字節:


2)對於libaio,用戶態調用io_getevents每收割一個aio event時內核向用戶態copy內存的開銷是32字節:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章