本文介绍了io_uring
的percpu sqthread
使用方法及常见故障码的处理。
背景介绍
io_uring
是Linux内核中的一种高性能异步I/O接口,通过一对共享内存缓冲区(ring buffer)实现应用程序与内核之间的高效通信,从而提升性能和效率。sqpoll
是io_uring
的一个特性,它将启用一个单独的内核线程来处理提交队列(SQ)中的任务,该线程称为sqthread
。
如果在同一个进程内创建多个io_uring
并开启了sqpoll
,可能会出现所有的sqthread
都运行在同一个核上的情况——每个io_uring
都会开启一个单独的sqthread
线程,导致单一核上同时运行多个sqthread
线程。这种情况下,sqthread
上下文切换将带来较多不必要的开销。为实现高效的sqpoll
功能并降低使用难度,Alibaba Cloud Linux 3提供了io_uring
的percpu sqthread
特性,允许您在创建sqthread
时指定其所在的核。此外,在同一个核上只存在一个sqthread
,该sqthread
会轮询处理绑定自己的所有io_uring
的请求。
使用限制
操作系统:Alibaba Cloud Linux 3。
内核:5.10.112-11
及以上版本。
使用percpu sqthread特性
启用 percpu sqthread
在初始化io_uring
时,需要设置IORING_SETUP_SQPOLL
标志来启用sqpoll
模式。此外,为了使能percpu sqthread
特性,还需要配置IORING_SETUP_SQPOLL_PERCPU
和IORING_SETUP_SQ_AFF
。同时,需要通过sq_thread_cpu
指定绑定到sqthread
所在的CPU序号。具体示例如下所示:
struct io_uring ring;
struct io_uring_params params = {};
params.flags = IORING_SETUP_SQPOLL|IORING_SETUP_SQPOLL_PERCPU|IORING_SETUP_SQ_AFF;
params.sq_thread_cpu = 1;
ret = io_uring_queue_init_params(ENTRIES, &ring, ¶ms);
if (ret < 0) {
perror("io_uring_queue_init_params");
exit(EXIT_FAILURE);
}
提交和处理I/O请求
使用
io_uring_sqe
结构体准备I/O请求。struct io_uring_sqe *sqe = io_uring_get_sqe(&ring); if (!sqe) { fprintf(stderr, "get sqe failed\n"); return -1; } io_uring_prep_read(sqe, fd, buf, len, offset); sqe->user_data = (uint64_t)buf;
使用
io_uring_submit
函数将请求提交到SQ。ret = io_uring_submit(&ring); if (ret < 0) { perror("io_uring_submit"); return -1; }
使用
io_uring_wait_cqe
或io_uring_peek_cqe
函数从CQ中获取完成的I/O请求。struct io_uring_cqe *cqe; ret = io_uring_wait_cqe(&ring, &cqe); if (ret < 0) { perror("io_uring_wait_cqe"); return -1; } if (cqe->res < 0) { fprintf(stderr, "read error: %s\n", strerror(-cqe->res)); } else { printf("read %d bytes\n", cqe->res); } io_uring_cqe_seen(&ring, cqe);