Skip to content

Commit 99eea02

Browse files
committed
Add posixaio_wait=aio_waitcomplete.
Provide an option to use FreeBSD's aio_waitcomplete() function to wait for completions, instead of aio_suspend(). Not enabled by default. Signed-off-by: Thomas Munro <[email protected]>
1 parent 6e556e9 commit 99eea02

File tree

3 files changed

+145
-4
lines changed

3 files changed

+145
-4
lines changed

HOWTO

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,6 +2650,14 @@ with the caveat that when used on the command line, they must come after the
26502650
false, effectively behaving as though
26512651
:option:`iodepth_batch_complete_max` has the same value as
26522652
:option:`iodepth`.
2653+
Only applies to wait=aio_suspend, as other options already
2654+
respect :option:`iodepth_batch_complete_max`.
2655+
2656+
.. options:: posixaio_wait=str : [posixaio]
2657+
2658+
Selects the mechanism used for waiting for I/Os to complete.
2659+
Default is aio_suspend. On FreeBSD, aio_waitcomplete may be used.
2660+
26532661

26542662
I/O depth
26552663
~~~~~~~~~

configure

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,26 @@ EOF
737737
fi
738738
print_config "POSIX AIO fsync" "$posix_aio_fsync"
739739

740+
##########################################
741+
# aio_waitcomplete probe
742+
if test "have_aio_waitcomplete" != "yes" ; then
743+
have_aio_waitcomplete="no"
744+
fi
745+
cat > $TMPC <<EOF
746+
#include <aio.h>
747+
#include <stdlib.h>
748+
int main(void)
749+
{
750+
struct aiocb *cb;
751+
aio_waitcomplete(&cb, NULL);
752+
return 0;
753+
}
754+
EOF
755+
if compile_prog "" "" "aio_waitcomplete" ; then
756+
have_aio_waitcomplete="yes"
757+
fi
758+
print_config "aio_waitcomplete()" "$have_aio_waitcomplete"
759+
740760
##########################################
741761
# POSIX pshared attribute probe
742762
if test "$posix_pshared" != "yes" ; then
@@ -2858,6 +2878,9 @@ fi
28582878
if test "$posix_aio_fsync" = "yes" ; then
28592879
output_sym "CONFIG_POSIXAIO_FSYNC"
28602880
fi
2881+
if test "$have_aio_waitcomplete" = "yes" ; then
2882+
output_sym "CONFIG_HAVE_AIO_WAITCOMPLETE"
2883+
fi
28612884
if test "$posix_pshared" = "yes" ; then
28622885
output_sym "CONFIG_PSHARED"
28632886
fi

engines/posixaio.c

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,56 @@
1313
#include "../fio.h"
1414
#include "../optgroup.h"
1515

16+
enum {
17+
FIO_POSIXAIO_SUSPEND,
18+
FIO_POSIXAIO_WAITCOMPLETE,
19+
};
20+
1621
struct posixaio_data {
1722
struct io_u **aio_events;
1823
unsigned int queued;
24+
int (*getevents)(struct thread_data *, unsigned int, unsigned int, const struct timespec *);
1925
};
2026

2127
struct posixaio_options {
2228
void *pad;
2329
unsigned int respect_iodepth_batch_complete_max;
30+
unsigned int wait;
2431
};
2532

2633
static struct fio_option options[] = {
2734
{
2835
.name = "posixaio_respect_iodepth_batch_complete_max",
29-
.lname = "Respect iodepth_batch_complete_max",
36+
.lname = "Respect iodepth_batch_complete_max for wait=aio_suspend",
3037
.type = FIO_OPT_BOOL,
3138
.off1 = offsetof(struct posixaio_options, respect_iodepth_batch_complete_max),
32-
.help = "Whether to cap batch completion",
39+
.help = "Whether to cap batch completion for wait=aio_suspend",
3340
.def = "0",
3441
.category = FIO_OPT_C_ENGINE,
3542
.group = FIO_OPT_G_POSIXAIO,
3643
},
44+
{
45+
.name = "posixaio_wait",
46+
.lname = "POSIX AIO wait mechanism",
47+
.type = FIO_OPT_STR,
48+
.off1 = offsetof(struct posixaio_options, wait),
49+
.help = "Select mechanism for waiting for I/O completion",
50+
.def = "aio_suspend",
51+
.posval = {
52+
{ .ival = "aio_suspend",
53+
.oval = FIO_POSIXAIO_SUSPEND,
54+
.help = "Use aio_suspend()",
55+
},
56+
#ifdef CONFIG_HAVE_AIO_WAITCOMPLETE
57+
{ .ival = "aio_waitcomplete",
58+
.oval = FIO_POSIXAIO_WAITCOMPLETE,
59+
.help = "Use aio_waitcomplete()",
60+
},
61+
#endif
62+
},
63+
.category = FIO_OPT_C_ENGINE,
64+
.group = FIO_OPT_G_POSIXAIO,
65+
},
3766
{
3867
.name = NULL,
3968
},
@@ -77,10 +106,65 @@ static int fio_posixaio_prep(struct thread_data fio_unused *td,
77106
return 0;
78107
}
79108

109+
#ifdef CONFIG_HAVE_AIO_WAITCOMPLETE
110+
111+
static int fio_posixaio_getevents_waitcomplete(struct thread_data *td,
112+
unsigned int min,
113+
unsigned int max,
114+
const struct timespec *t)
115+
{
116+
struct posixaio_data *pd = td->io_ops_data;
117+
struct aiocb *aiocb;
118+
struct io_u *io_u;
119+
ssize_t retval;
120+
unsigned int events = 0;
121+
struct timespec zero_timeout = {0};
122+
struct timespec *timeout;
123+
124+
do
125+
{
126+
if (events < min) {
127+
/* Wait until the minimum is satisfied. */
128+
timeout = (struct timespec *)t;
129+
} else {
130+
/* Consume as many more as we can without waiting. */
131+
timeout = &zero_timeout;
132+
}
133+
134+
retval = aio_waitcomplete(&aiocb, timeout);
135+
if (retval < 0) {
136+
if (errno == EINTR)
137+
continue;
138+
if (errno == EAGAIN)
139+
break;
140+
td_verror(td, errno, "aio_waitcomplete");
141+
break;
142+
}
143+
144+
io_u = container_of(aiocb, struct io_u, aiocb);
145+
pd->queued--;
146+
pd->aio_events[events++] = io_u;
147+
148+
if (retval >= 0)
149+
io_u->resid = io_u->xfer_buflen - retval;
150+
else if (errno == ECANCELED)
151+
io_u->resid = io_u->xfer_buflen;
152+
else
153+
io_u->error = errno;
154+
155+
} while (events < max && pd->queued > 0);
156+
157+
return events;
158+
}
159+
160+
#endif
161+
80162
#define SUSPEND_ENTRIES 8
81163

82-
static int fio_posixaio_getevents(struct thread_data *td, unsigned int min,
83-
unsigned int max, const struct timespec *t)
164+
static int fio_posixaio_getevents_suspend(struct thread_data *td,
165+
unsigned int min,
166+
unsigned int max,
167+
const struct timespec *t)
84168
{
85169
struct posixaio_data *pd = td->io_ops_data;
86170
struct posixaio_options *o = td->eo;
@@ -152,6 +236,16 @@ static int fio_posixaio_getevents(struct thread_data *td, unsigned int min,
152236
goto restart;
153237
}
154238

239+
static int fio_posixaio_getevents(struct thread_data *td,
240+
unsigned int min,
241+
unsigned int max,
242+
const struct timespec *t)
243+
{
244+
struct posixaio_data *pd = td->io_ops_data;
245+
246+
return pd->getevents(td, min, max, t);
247+
}
248+
155249
static struct io_u *fio_posixaio_event(struct thread_data *td, int event)
156250
{
157251
struct posixaio_data *pd = td->io_ops_data;
@@ -223,13 +317,29 @@ static void fio_posixaio_cleanup(struct thread_data *td)
223317

224318
static int fio_posixaio_init(struct thread_data *td)
225319
{
320+
struct posixaio_options *o = td->eo;
226321
struct posixaio_data *pd = malloc(sizeof(*pd));
227322

228323
memset(pd, 0, sizeof(*pd));
229324
pd->aio_events = malloc(td->o.iodepth * sizeof(struct io_u *));
230325
memset(pd->aio_events, 0, td->o.iodepth * sizeof(struct io_u *));
231326

327+
switch (o->wait) {
328+
case FIO_POSIXAIO_SUSPEND:
329+
pd->getevents = fio_posixaio_getevents_suspend;
330+
break;
331+
#ifdef CONFIG_HAVE_AIO_WAITCOMPLETE
332+
case FIO_POSIXAIO_WAITCOMPLETE:
333+
pd->getevents = fio_posixaio_getevents_waitcomplete;
334+
break;
335+
#endif
336+
default:
337+
free(pd);
338+
return -1;
339+
}
340+
232341
td->io_ops_data = pd;
342+
233343
return 0;
234344
}
235345

0 commit comments

Comments
 (0)