io-ag凯发k8国际
io_uring设计理念及使用方式总结
- overview
- 设计目标
- io_uring系统调用
- io_uring_setup
- 特性
- io_uring_enter
- io_uring_register
- liburing
- op code
- feature
- io interfaces 比较
- spdk io_uring
- 参考链接
overview
io_uring通过使用先进的io特性,以及内核支持下的各种免拷贝、免context switch特性,成为kernel下一代高性能异步io接口,不同于libaio,io_uring支持direct和非direct io。
fundamentally, io_uring is just ring based communication channel. ---- jens
io请求通过submission queue sq下发到内核中,内核完成io之后通过completion queue cq放回io result。两个队列在用户态和内核态之间通过共享内存的方式沟通,从而免拷贝,每个sqe(submission queue entry)的大小为64byte,正好容纳近一个cache line。内核通过memory ordering、fense等技巧保证整个io链路是不出错且高效的。
设计目标
作者jens在文章中明确列出了io_uring的设计目标:
io_uring系统调用
io_uring_setup
创建并配置io_uring
#include通过io_uring_params设置申请uring的参数:
struct io_uring_params {__u32 sq_entries; // 指定分配多少个sqe__u32 cq_entries; // 指定分配多少个cqe__u32 flags; // io_uring各种参数,包括ioring_setup_iopoll设置用户态polling,ioring_setup_sqpoll设置内核态polling,ioring_setup_sq_aff设置内核态polling的绑核等等__u32 sq_thread_cpu; // 内核态绑核__u32 sq_thread_idle; // 内核态polling 如果idle超过sq_thread_idle milliseconds会进入休眠,进入休眠后用户态进程必须通过调用io_uring_enter设置ioring_sq_need_wakeup 来唤醒内核polling线程__u32 features; // 由内核填写,表明内核支持那些io_uring特性__u32 wq_fd; // 可以指定一个已经存在的io_uring,而不重新创建__u32 resv[3];struct io_sqring_offsets sq_off; // 指定sq的一些特性struct io_cqring_offsets cq_off; };ring创建好之后是以fd的形式呈现的,用户可以通过mmap的方式访问特定的ring
#define ioring_off_sq_ring 0ull #define ioring_off_cq_ring 0x8000000ull #define io_ring_off_sqes 0x10000000ull // 通过以上三个flag来mmap对应的三片ioring的区域 // 下面举例:sq->ring_ptr = mmap(0, sq->ring_sz, prot_read | prot_write,map_shared | map_populate, fd, ioring_off_sq_ring); if (sq->ring_ptr == map_failed)return -errno;sq->khead = sq->ring_ptr p->sq_off.head; // p就是之前设置的io_uring_params sq->ktail = sq->ring_ptr p->sq_off.tail;// sq配置好之后,用户态进程作为生产者在sq tail追加sqe,kernel作为消费者从head获取待处理的sqe上述讲解的是io_uring系统调用的方法,我们也可以使用上层封装liburinginclude/liburing.h中的函数进行初始化和下发io
特性
我们可以通过io_uring_params配置io_uring不同的特性
io_uring_enter
int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t sig);在程序向sq,即请求队列中插入了io请求后(可以通过io_uring_get_sqe插入),需要通知内核开始处理,这时就需要调用io_uring_enter。参数中的fd是io_uring的fd,to_submit是提交的io请求数。
min_complete可以用来阻塞等待内核完成特定数量的请求,前提是flags中设置ioring_enter_getevents。这个功能可以单独调用来等待内核处理完成。需要注意的是由于采用共享内存队列的方式来同步请求完成情况,因此程序也可以不使用这个接口而是直接判断cqring的状态来获取io完成情况并处理cqring中的完成事件(使用liburing中的io_uring_peek_cqe)。
io_uring_register
int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args);这个syscall用于支持一些高级的优化用法,主要有两种模式,opcode分别为:
liburing
op code
io entry中不同的opcode可指示kernel做不同的事情:
feature
使用io_uring_get_sqe获取一个新的sqe之后,可以通过sqe->flages设置特性,一些比较重要的特性列述如下:
io interfaces 比较
sw overheadsynchronous i/olibaioio_uringsystem calls | at least 1 per i/o | 2 per i/o batch | 1 per patch, zero when using sq submission thread |
memory copy | yes | yes - sqe & ceq | zero-copy for sqe&cqe |
context switches | yes | yes | minimal context switching polling |
interrupts | interupt driven | interupt driven | supports both interrupts and polling i/o |
blocking i/o | synchronous | asynchronous | asynchronous |
buffer i/o | yes | no | yes |
spdk io_uring
目前spdk已经支持了io_uring,具体代码可见pdk/module/bdev/uring/bdev_uring.c,由于目前有一些远程挂载设备不支持ioring_setup_iopoll特性,spdk为了维护模块的通用性,目前的spdk实现也没有启用ioring_setup_iopoll特性,当然定制添加的工作量并不大。
使用如下命令可以在spdk中测试io_uring
./scripts/rpc.py -s /var/tmp/spdk.sock bdev_uring_create /dev/nvme0n1 nvme0n1 512 # 创建uring_bdev ld_preload=/root/spdk_bdev ./fio ./example_config.fio # 使用fio_plugin测试io_uring,需要更改对应的bdev参数配置。参考链接
总结
以上是ag凯发k8国际为你收集整理的io_uring设计理念及使用方式总结的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇:
- 下一篇: