Skip to content

Commit 8f0c124

Browse files
committed
Merge branch 'iowait'
* iowait: Add suppport for toggling iowait
2 parents 0c96306 + 937d486 commit 8f0c124

8 files changed

Lines changed: 160 additions & 1 deletion

File tree

src/include/liburing.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ int __io_uring_get_cqe(struct io_uring *ring,
320320
struct io_uring_cqe **cqe_ptr, unsigned submit,
321321
unsigned wait_nr, sigset_t *sigmask);
322322

323+
/*
324+
* Enable/disable setting of iowait by the kernel.
325+
*/
326+
int io_uring_set_iowait(struct io_uring *ring, bool enable_iowait);
327+
323328
#define LIBURING_UDATA_TIMEOUT ((__u64) -1)
324329

325330
/*

src/include/liburing/io_uring.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ struct io_cqring_offsets {
527527
#define IORING_ENTER_REGISTERED_RING (1U << 4)
528528
#define IORING_ENTER_ABS_TIMER (1U << 5)
529529
#define IORING_ENTER_EXT_ARG_REG (1U << 6)
530+
#define IORING_ENTER_NO_IOWAIT (1U << 7)
530531

531532
/*
532533
* Passed in for io_uring_setup(2). Copied back with updated info on success
@@ -564,6 +565,7 @@ struct io_uring_params {
564565
#define IORING_FEAT_RECVSEND_BUNDLE (1U << 14)
565566
#define IORING_FEAT_MIN_TIMEOUT (1U << 15)
566567
#define IORING_FEAT_RW_ATTR (1U << 16)
568+
#define IORING_FEAT_NO_IOWAIT (1U << 17)
567569

568570
/*
569571
* io_uring_register(2) opcodes and arguments

src/int_flags.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
#ifndef LIBURING_INT_FLAGS
33
#define LIBURING_INT_FLAGS
44

5-
#define INT_FLAGS_MASK (IORING_ENTER_REGISTERED_RING)
5+
#define INT_FLAGS_MASK (IORING_ENTER_REGISTERED_RING | \
6+
IORING_ENTER_NO_IOWAIT)
67

78
enum {
89
INT_FLAG_REG_RING = IORING_ENTER_REGISTERED_RING,
10+
INT_FLAG_NO_IOWAIT = IORING_ENTER_NO_IOWAIT,
911
INT_FLAG_REG_REG_RING = 1,
1012
INT_FLAG_APP_MEM = 2,
1113
INT_FLAG_CQ_ENTER = 4,

src/liburing-ffi.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,5 @@ LIBURING_2.10 {
233233
io_uring_prep_writev_fixed;
234234
io_uring_prep_readv_fixed;
235235
io_uring_prep_sendmsg_zc_fixed;
236+
io_uring_set_iowait;
236237
} LIBURING_2.9;

src/liburing.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,5 @@ LIBURING_2.9 {
115115
LIBURING_2.10 {
116116
global:
117117
io_uring_register_ifq;
118+
io_uring_set_iowait;
118119
} LIBURING_2.9;

src/register.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,3 +482,14 @@ int io_uring_register_region(struct io_uring *ring,
482482
{
483483
return do_register(ring, IORING_REGISTER_MEM_REGION, reg, 1);
484484
}
485+
486+
int io_uring_set_iowait(struct io_uring *ring, bool enable_iowait)
487+
{
488+
if (!(ring->features & IORING_FEAT_NO_IOWAIT))
489+
return -EOPNOTSUPP;
490+
if (enable_iowait)
491+
ring->int_flags &= ~INT_FLAG_NO_IOWAIT;
492+
else
493+
ring->int_flags |= INT_FLAG_NO_IOWAIT;
494+
return 0;
495+
}

test/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ test_srcs := \
122122
io_uring_passthrough.c \
123123
io_uring_register.c \
124124
io_uring_setup.c \
125+
iowait.c \
125126
kallsyms.c \
126127
lfs-openat.c \
127128
lfs-openat-write.c \

test/iowait.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
#include <string.h>
5+
6+
#include "liburing.h"
7+
#include "helpers.h"
8+
9+
static int get_iowait(int cpu)
10+
{
11+
char cpu_buf[32], this_cpu[32];
12+
int user, nice, system, idle, iowait, ret;
13+
FILE *file;
14+
15+
file = fopen("/proc/stat", "r");
16+
if (!file) {
17+
perror("fopen stat");
18+
return 0;
19+
}
20+
21+
sprintf(this_cpu, "cpu%d", cpu);
22+
ret = 0;
23+
do {
24+
int r;
25+
r = fscanf(file, "%s %d %d %d %d %d", cpu_buf, &user, &nice,
26+
&system, &idle, &iowait);
27+
if (r != 6)
28+
continue;
29+
if (strncmp(cpu_buf, this_cpu, strlen(this_cpu)))
30+
continue;
31+
ret = iowait;
32+
break;
33+
} while (1);
34+
35+
fclose(file);
36+
return ret;
37+
}
38+
39+
static int test(struct io_uring *ring, int with_iowait, int cpu)
40+
{
41+
struct io_uring_sqe *sqe;
42+
struct io_uring_cqe *cqe;
43+
int iowait_pre, iowait_post;
44+
struct __kernel_timespec ts;
45+
int ret, fds[2], diff;
46+
char buf[32];
47+
48+
if (!(ring->features & IORING_FEAT_NO_IOWAIT))
49+
return T_EXIT_SKIP;
50+
51+
if (pipe(fds) < 0) {
52+
perror("pipe");
53+
return T_EXIT_FAIL;
54+
}
55+
56+
ret = io_uring_set_iowait(ring, with_iowait);
57+
if (ret) {
58+
fprintf(stderr, "set_iowait=%d\n", ret);
59+
return T_EXIT_FAIL;
60+
}
61+
62+
sqe = io_uring_get_sqe(ring);
63+
io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
64+
io_uring_submit(ring);
65+
66+
ts.tv_sec = 1;
67+
ts.tv_nsec = 0;
68+
iowait_pre = get_iowait(cpu);
69+
ret = io_uring_wait_cqe_timeout(ring, &cqe, &ts);
70+
if (ret != -ETIME) {
71+
fprintf(stderr, "Unexpected wait ret: %d\n", ret);
72+
return T_EXIT_FAIL;
73+
}
74+
iowait_post = get_iowait(cpu);
75+
diff = iowait_post - iowait_pre;
76+
77+
close(fds[0]);
78+
close(fds[1]);
79+
80+
ret = io_uring_wait_cqe(ring, &cqe);
81+
if (ret) {
82+
fprintf(stderr, "Unexpected wait ret: %d\n", ret);
83+
return T_EXIT_FAIL;
84+
}
85+
io_uring_cqe_seen(ring, cqe);
86+
87+
if (with_iowait) {
88+
if (diff < 90) {
89+
fprintf(stderr, "iowait diff too small: %d\n", diff);
90+
return T_EXIT_FAIL;
91+
}
92+
} else {
93+
if (diff > 10) {
94+
fprintf(stderr, "iowait diff too large: %d\n", diff);
95+
return T_EXIT_FAIL;
96+
}
97+
}
98+
return T_EXIT_PASS;
99+
}
100+
101+
int main(int argc, char *argv[])
102+
{
103+
struct io_uring ring;
104+
cpu_set_t cpuset;
105+
int ret;
106+
107+
CPU_ZERO(&cpuset);
108+
CPU_SET(0, &cpuset);
109+
if (sched_setaffinity(0, sizeof(cpuset), &cpuset))
110+
return T_EXIT_SKIP;
111+
112+
ret = t_create_ring(64, &ring, 0);
113+
if (ret == T_SETUP_SKIP)
114+
return T_EXIT_SKIP;
115+
else if (ret != T_SETUP_OK)
116+
return T_EXIT_FAIL;
117+
118+
ret = test(&ring, 0, 0);
119+
if (ret == T_EXIT_SKIP) {
120+
return T_EXIT_SKIP;
121+
} else if (ret == T_EXIT_FAIL) {
122+
fprintf(stderr, "test 0 failed\n");
123+
return T_EXIT_FAIL;
124+
}
125+
126+
ret = test(&ring, 1, 0);
127+
if (ret == T_EXIT_SKIP) {
128+
return T_EXIT_SKIP;
129+
} else if (ret == T_EXIT_FAIL) {
130+
fprintf(stderr, "test 1 failed\n");
131+
return T_EXIT_FAIL;
132+
}
133+
134+
io_uring_queue_exit(&ring);
135+
return 0;
136+
}

0 commit comments

Comments
 (0)