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字节:

 

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