io_uring, io_uring_cmd, and libaio record issue_time inside the ioengine code when their commit functions are called. So we don't need to record issue_time again for these ioengines in td_io_queue. If we do fill issue_time twice, then mean(slat) + mean(clat) != mean(lat): user@ubuntu:~/fio-dev$ fio-canonical/fio --name=test --ioengine=io_uring --number_ios=1 --rw=randread --size=1M test: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=io_uring, iodepth=1 fio-3.30-48-g26fa Starting 1 process test: (groupid=0, jobs=1): err= 0: pid=172145: Mon Jun 6 16:12:42 2022 read: IOPS=1000, BW=4000KiB/s (4096kB/s)(4096B/1msec) slat (nsec): min=61424, max=61424, avg=61424.00, stdev= 0.00 clat (nsec): min=242709, max=242709, avg=242709.00, stdev= 0.00 lat (nsec): min=308346, max=308346, avg=308346.00, stdev= 0.00 61424 + 242709 = 304133 != 308346 If we fill issue_time only once, then the equality will hold (as it should): user@ubuntu:~/fio-dev$ fio-latency/fio --name=test --ioengine=io_uring --number_ios=1 --rw=randread --size=1M test: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=io_uring, iodepth=1 fio-3.30-48-g26fa-dirty Starting 1 process test: (groupid=0, jobs=1): err= 0: pid=172220: Mon Jun 6 16:12:47 2022 read: IOPS=1000, BW=4000KiB/s (4096kB/s)(4096B/1msec) slat (nsec): min=53701, max=53701, avg=53701.00, stdev= 0.00 clat (nsec): min=259566, max=259566, avg=259566.00, stdev= 0.00 lat (nsec): min=313267, max=313267, avg=313267.00, stdev= 0.00 53701 + 259566 = 313267 Signed-off-by: Vincent Fu <vincent.fu@xxxxxxxxxxx> --- engines/io_uring.c | 7 +++++-- engines/libaio.c | 3 ++- ioengines.c | 3 ++- ioengines.h | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/engines/io_uring.c b/engines/io_uring.c index cceafe69..474d215c 100644 --- a/engines/io_uring.c +++ b/engines/io_uring.c @@ -1191,7 +1191,8 @@ static int fio_ioring_cmd_get_max_open_zones(struct thread_data *td, static struct ioengine_ops ioengine_uring = { .name = "io_uring", .version = FIO_IOOPS_VERSION, - .flags = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD, + .flags = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD | + FIO_ASYNCIO_SETS_ISSUE_TIME, .init = fio_ioring_init, .post_init = fio_ioring_post_init, .io_u_init = fio_ioring_io_u_init, @@ -1211,7 +1212,9 @@ static struct ioengine_ops ioengine_uring = { static struct ioengine_ops ioengine_uring_cmd = { .name = "io_uring_cmd", .version = FIO_IOOPS_VERSION, - .flags = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD | FIO_MEMALIGN | FIO_RAWIO, + .flags = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD | + FIO_MEMALIGN | FIO_RAWIO | + FIO_ASYNCIO_SETS_ISSUE_TIME, .init = fio_ioring_init, .post_init = fio_ioring_cmd_post_init, .io_u_init = fio_ioring_io_u_init, diff --git a/engines/libaio.c b/engines/libaio.c index 9c278d06..da5279f4 100644 --- a/engines/libaio.c +++ b/engines/libaio.c @@ -511,7 +511,8 @@ static int fio_libaio_init(struct thread_data *td) FIO_STATIC struct ioengine_ops ioengine = { .name = "libaio", .version = FIO_IOOPS_VERSION, - .flags = FIO_ASYNCIO_SYNC_TRIM, + .flags = FIO_ASYNCIO_SYNC_TRIM | + FIO_ASYNCIO_SETS_ISSUE_TIME, .init = fio_libaio_init, .post_init = fio_libaio_post_init, .prep = fio_libaio_prep, diff --git a/ioengines.c b/ioengines.c index 280da3c8..e4ad698c 100644 --- a/ioengines.c +++ b/ioengines.c @@ -442,7 +442,8 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u) if (!td_ioengine_flagged(td, FIO_SYNCIO) && !async_ioengine_sync_trim(td, io_u)) { - if (fio_fill_issue_time(td)) + if (fio_fill_issue_time(td) && + !td_ioengine_flagged(td, FIO_ASYNCIO_SETS_ISSUE_TIME)) fio_gettime(&io_u->issue_time, NULL); /* diff --git a/ioengines.h b/ioengines.h index acdb0071..fafa1e48 100644 --- a/ioengines.h +++ b/ioengines.h @@ -83,6 +83,8 @@ enum fio_ioengine_flags { FIO_ASYNCIO_SYNC_TRIM = 1 << 14, /* io engine has async ->queue except for trim */ FIO_NO_OFFLOAD = 1 << 15, /* no async offload */ + FIO_ASYNCIO_SETS_ISSUE_TIME + = 1 << 16, /* async ioengine with commit function that sets issue_time */ }; /* -- 2.25.1