Skip to main content

IoUringConfiguration

Struct IoUringConfiguration 

Source
pub struct IoUringConfiguration {
    pub queue_len: u32,
    pub sqpoll_wake_interval: Option<u32>,
    pub per_numa_bounded_worker_count: Option<u32>,
    pub per_numa_unbounded_worker_count: Option<u32>,
    pub aggressive_poll: bool,
    pub iopoll_enabled: bool,
    pub recv_buffers: u16,
    pub recv_buffer_size: u32,
}
Expand description

The settings of every shard’s io_uring ring (Linux 6.1 or later).

The default is interrupt_driven with 2048 queue entries and the io-wq worker limits Some(256) and Some(512).

Fields§

§queue_len: u32

Entries in each ring’s submission queue (default 2048); the completion queue holds twice as many.

At least 64, the floor a ring is shrunk to when the system has no memory for more; a smaller value is refused as the configuration’s mistake when the first shard starts. The kernel rounds the count up to a power of two and clamps it to its own maximum (32768 on current kernels), so a larger value is accepted and gets what the kernel allows.

§sqpoll_wake_interval: Option<u32>

With Some(ms), a kernel thread polls the submission queue and sleeps after that many idle milliseconds: fewer system calls for more CPU (default None: no polling thread).

Before version 5.11 of the Linux kernel, to successfully use this feature, the application must register a set of files to be used for IO through io_uring_register(2) using the IORING_REGISTER_FILES opcode. Failure to do so will result in submitted IO being errored with EBADF. The presence of this feature can be detected by the IORING_FEAT_SQPOLL_NONFIXED feature flag. In version 5.11 and later, it is no longer necessary to register files to use this feature. 5.11 also allows using this as non-root, if the user has the CAP_SYS_NICE capability. In 5.13 this requirement was also relaxed, and no special privileges are needed for SQPOLL in newer kernels. Certain stable kernels older than 5.13 may also support unprivileged SQPOLL.

A shorter interval keeps the kernel thread awake more, for more CPU; a longer one lets it sleep, and a submission after it slept wakes it.

§per_numa_bounded_worker_count: Option<u32>

The most io_uring worker threads per NUMA node for IO bound in time, on regular files and block devices (default Some(256)).

Some(0) leaves the kernel’s limit as it is; with None the kernel limits them to the ring’s submission entries or four times the online CPUs, whichever is smaller.

§per_numa_unbounded_worker_count: Option<u32>

The most io_uring worker threads per NUMA node for IO that may never complete, such as on sockets (default Some(512)).

Some(0) leaves the kernel’s limit as it is; with None the process’s task limit (RLIMIT_NPROC) bounds them.

§aggressive_poll: bool

Has no effect, and is kept so code written against earlier versions builds (default false). Every shard already looks at its ring’s completions while it spins before it sleeps, and a kernel thread that polls the submission queue is sqpoll_wake_interval; no third kind of polling is left for this flag to turn on.

§iopoll_enabled: bool

Busy-waits for file completions instead of taking interrupts (default false): lower latency for more CPU, and only for files opened with O_DIRECT on file systems that support polling.

§recv_buffers: u16

Buffers in each shard’s group for multishot receives (default 256, or queue_len rounded up to a power of two when that is fewer): the kernel fills one as bytes arrive, so a stream’s receive stays armed for every arrival and a receive that waits holds no buffer of its own.

The buffers, with their descriptors, count against the shard’s io_buffer_cap for as long as the shard lives, and the shard’s own pool gets the rest; a group that leaves the pool less than 512 bytes is refused as the configuration’s mistake when the shard starts, and one the system has no memory for fails the shard’s start with OutOfMemory.

0 turns multishot receives off, and each read then takes a buffer of the shard’s own pool for its receive. Otherwise a power of two from 1 to 32768 and below twice queue_len, so the group never takes more than half the completion queue (twice queue_len, rounded up to a power of two); any other value is refused as the configuration’s mistake when the first shard starts. A ring the system could only make with fewer entries than queue_len (it had no memory for more) gets a group cut to the same rule.

A kernel that refuses provided buffer rings makes the default backend choice pick the poller; 0 keeps io_uring there. Ubuntu’s 6.8 kernels from 6.8.0-136 on refuse every valid registration: a backport inverted the check of its reserved words (https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2162843).

§recv_buffer_size: u32

The size in bytes of each of those buffers (default 16384); for UDP, one that holds the largest datagram expected.

From 512 (smaller buffers split a stream into chunks of a few packets each) to 1 GiB; a value outside is refused as the configuration’s mistake when the first shard starts. Not checked while recv_buffers is 0. recv_buffers buffers of this size count against the shard’s io_buffer_cap, as said there.

A receive is stopped once the bytes it handed out and its reader has not taken pass an eighth of the group (at least one buffer), and asked for again when its reader catches up. What the kernel took for it before the stop stays with it, so a reader with a long backlog may hold more until it reads; other receives take buffers of the shard’s own pool meanwhile.

Implementations§

Source§

impl IoUringConfiguration

Source

pub fn interrupt_driven(queue_len: u32) -> Self

No polling: a completion wakes its shard by interrupt. The one to pick when unsure.

Source

pub fn low_latency_driven(queue_len: u32) -> Self

A kernel thread polls the submission queue and sleeps after 2 idle milliseconds: lower latency under steady traffic, for more CPU.

Source

pub fn kernel_poll_only(queue_len: u32) -> Self

A kernel thread polls the submission queue and sleeps after 2 idle milliseconds, as low_latency_driven.

Source

pub fn io_poll(queue_len: u32) -> Self

Busy-waits for file completions (iopoll_enabled): low-latency IO on files opened with O_DIRECT.

Trait Implementations§

Source§

impl Clone for IoUringConfiguration

Source§

fn clone(&self) -> IoUringConfiguration

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for IoUringConfiguration

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for IoUringConfiguration

The interrupt-driven profile, with the io-wq worker limits nuclei sets on every ring.

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.