Linux I/O Models and io_uring Performance Overview
Linux I/O models range from synchronous native operations to asynchronous kernel‑bypass techniques, with APIs such as open, read, write, mmap, sendfile and splice, while the modern io_uring interface—supporting interrupt, polling, and kernel‑polling modes via liburing—delivers superior performance, especially at high queue depths, compared to traditional libaio.
Linux I/O models are classified into native I/O, kernel bypass, etc. Native I/O includes synchronous and asynchronous operations. Synchronous I/O blocks the calling process until the operation completes, while asynchronous I/O allows the process to continue.
Blocking refers to the process state when a system call puts the process to sleep until the requested event occurs.
Common file operation APIs:
#include
#include
#include
#include
// 返回值:成功返回新分配的文件描述符,出错返回-1并设置errno
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
// 返回值:成功返回0,出错返回-1并设置errno
int close(int fd);
// 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0
ssize_t read(int fd, void *buf, size_t count);
// 返回值:成功返回写入的字节数,出错返回-1并设置errno
ssize_t write(int fd, const void *buf, size_t count);Typical open flags include O_CREAT, O_EXCL, O_TRUNC, O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_NONBLOCK, O_SYNC, O_DIRECT.
Mmap maps a file into the process address space, allowing direct memory access to file data.
// 成功执行时,mmap()返回被映射区的指针。失败时,mmap()返回MAP_FAILED[其值为(void *)-1]
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
// 成功执行时,munmap()返回0。失败时,munmap返回-1,error返回标志和mmap一致;
int munmap(void *addr, size_t len);
// 将内存中的修改同步到磁盘
int msync(void *addr, size_t len, int flags);Direct I/O (O_DIRECT) bypasses the kernel page cache, reducing data copies.
sendfile transfers data from a file descriptor to a socket without copying to user space.
splice connects two file descriptors, allowing data movement without user‑space copies; it is a superset of sendfile.
io_uring is a modern Linux asynchronous I/O interface that supports both storage and network I/O. It uses submission (SQ) and completion (CQ) queues.
Key io_uring system calls:
int io_uring_setup(u32 entries, struct io_uring_params *p);
int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args);
int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig);io_uring operates in three modes: interrupt‑driven (default), polling, and kernel‑polling. Polling reduces latency at the cost of CPU usage; kernel‑polling uses a kernel thread to submit and reap I/O without user‑space syscalls.
liburing provides a convenient wrapper around io_uring. Example initialization, submission, and completion handling are shown in the source code.
Performance comparisons show that io_uring outperforms traditional libaio in polling mode and approaches the performance of SPDK at high queue depths, while its advantage over libaio in non‑polling mode is modest.
Conclusion: io_uring offers a high‑performance, flexible I/O solution for Linux, though it requires recent kernel versions.
DeWu Technology
A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.