Skip to content

Commit 2df4a88

Browse files
authored
io_uring cascading engine supports for I/O (alibaba#848)
1 parent 9694d2b commit 2df4a88

5 files changed

Lines changed: 162 additions & 166 deletions

File tree

fs/cache/test/cache_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ limitations under the License.
1515
*/
1616

1717

18-
#include <gtest/gtest.h>
18+
#include "../../../test/gtest.h"
1919

2020
#include <fcntl.h>
2121
#include <sys/types.h>
@@ -455,7 +455,7 @@ void* worker(void* arg) {
455455
auto f = fs->open("/huge", O_RDONLY);
456456
DEFER(delete f);
457457
for (int i=0;i<4;i++) {
458-
std::random_shuffle(offset.begin(), offset.end());
458+
shuffle(offset.begin(), offset.end());
459459
for (const auto &x : offset) {
460460
EXPECT_EQ((ssize_t)(1UL<<20), ::pread(fd, buffersrc, 1024*1024, x));
461461
f->pread(buffer, 1024*1024, x);

io/fd-events.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct iouring_args {
145145
bool setup_sqpoll = false;
146146
bool setup_sq_aff = false;
147147
bool setup_iopoll = false;
148+
bool eager_submit = false;
148149
uint32_t sq_thread_cpu;
149150
uint32_t sq_thread_idle_ms = 1000; // by default polls for 1s
150151
};

io/iouring-wrapper.cpp

Lines changed: 115 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
241241
io_uring_sqe_set_data(sqe, &timer_ctx);
242242
}
243243

244+
if (try_submit() < 0) return -1;
245+
244246
SCOPED_PAUSE_WORK_STEALING;
245247
photon::thread_sleep(-1);
246248

@@ -268,6 +270,15 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
268270
}
269271
}
270272

273+
int try_submit() {
274+
if (m_args.eager_submit) {
275+
int ret = io_uring_submit(m_ring);
276+
if (ret < 0)
277+
LOG_ERROR_RETURN(-ret, -1, "iouring: failed to io_uring_submit(), ", ERRNO(-ret));
278+
}
279+
return 0;
280+
}
281+
271282
int wait_for_fd(int fd, uint32_t interests, Timeout timeout) override {
272283
if (unlikely(interests == 0))
273284
return 0;
@@ -289,9 +300,8 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
289300

290301
bool one_shot = e.interests & ONE_SHOT;
291302
fdInterest fd_interest{e.fd, (uint32_t)evmap.translate_bitwisely(e.interests)};
292-
ioCtx io_ctx(false, true);
293-
eventCtx event_ctx{e, one_shot, io_ctx};
294-
auto pair = m_event_contexts.insert({fd_interest, event_ctx});
303+
eventCtx event_ctx{e, one_shot, {false, true}};
304+
auto pair = m_event_contexts.emplace(fd_interest, event_ctx);
295305
if (!pair.second) {
296306
LOG_ERROR_RETURN(0, -1, "iouring: event has already been added");
297307
}
@@ -302,10 +312,7 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
302312
io_uring_prep_poll_multishot(sqe, fd_interest.fd, fd_interest.interest);
303313
}
304314
io_uring_sqe_set_data(sqe, &pair.first->second.io_ctx);
305-
int ret = io_uring_submit(m_ring);
306-
if (ret < 0)
307-
LOG_ERROR_RETURN(-ret, -1, "iouring: fail to submit when adding interest, ", ERRNO(-ret));
308-
return 0;
315+
return try_submit();
309316
}
310317

311318
int rm_interest(Event e) override {
@@ -321,74 +328,29 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
321328

322329
io_uring_prep_poll_remove(sqe, (__u64) &iter->second.io_ctx);
323330
io_uring_sqe_set_data(sqe, nullptr);
324-
int ret = io_uring_submit(m_ring);
325-
if (ret < 0)
326-
LOG_ERROR_RETURN(-ret, -1, "iouring: fail to submit when removing interest, ", ERRNO(-ret));
327-
return 0;
331+
return try_submit();
328332
}
329333

330334
ssize_t wait_for_events(void** data, size_t count, Timeout timeout) override {
335+
if (!(m_ring->flags & IORING_SETUP_SQPOLL) &&
336+
m_ring->sq.sqe_tail != *m_ring->sq.khead)
337+
io_uring_submit(m_ring);
338+
331339
// Use master engine to wait for self event fd
332340
int ret = ::photon::wait_for_fd_readable(m_eventfd, timeout);
333341
if (ret < 0) {
334342
return errno == ETIMEDOUT ? 0 : -1;
335343
}
336344
uint64_t value;
337345
eventfd_read(m_eventfd, &value);
338-
339-
// Reap events
340-
size_t num = 0;
341-
io_uring_cqe* cqe = nullptr;
342-
uint32_t head = 0;
343-
unsigned i = 0;
344-
io_uring_for_each_cqe(m_ring, head, cqe) {
345-
++i;
346-
auto ctx = (ioCtx*) io_uring_cqe_get_data(cqe);
347-
if (!ctx) {
348-
// rm_interest didn't set user data
349-
continue;
350-
}
351-
ctx->res = cqe->res;
352-
if (cqe->flags & IORING_CQE_F_MORE && cqe->res & POLLERR) {
353-
LOG_ERROR_RETURN(0, -1, "iouring: multi-shot poll got POLLERR");
354-
}
355-
if (!ctx->is_event) {
356-
LOG_ERROR_RETURN(0, -1, "iouring: cascading engine only needs to handle event. Must be a bug...")
357-
}
358-
eventCtx* event_ctx = container_of(ctx, eventCtx, io_ctx);
359-
fdInterest fd_interest{event_ctx->event.fd, (uint32_t)evmap.translate_bitwisely(event_ctx->event.interests)};
360-
if (ctx->res == -ECANCELED) {
361-
m_event_contexts.erase(fd_interest);
362-
} else if (event_ctx->one_shot) {
363-
data[num++] = event_ctx->event.data;
364-
m_event_contexts.erase(fd_interest);
365-
} else {
366-
data[num++] = event_ctx->event.data;
367-
}
368-
if (num >= count) {
369-
break;
370-
}
371-
}
372-
io_uring_cq_advance(m_ring, i);
373-
return num;
346+
return reap_events(data, count);
374347
}
375-
376-
ssize_t wait_and_fire_events(uint64_t timeout) override {
377-
// Prepare own timeout
378-
if (timeout > (uint64_t) std::numeric_limits<int64_t>::max()) {
379-
timeout = std::numeric_limits<int64_t>::max();
380-
}
381-
382-
auto ts = usec_to_timespec(timeout);
383-
if (m_submit_wait_func(m_ring, &ts) != 0) {
384-
return -1;
385-
}
386-
387-
uint32_t head = 0;
388-
unsigned i = 0;
348+
ssize_t reap_events(void** data = 0, size_t count = 0) {
389349
io_uring_cqe* cqe;
350+
uint32_t head = 0, num = 0, n = 0;
351+
DEFER( io_uring_cq_advance(m_ring, n) );
390352
io_uring_for_each_cqe(m_ring, head, cqe) {
391-
i++;
353+
n++;
392354
auto ctx = (ioCtx*) io_uring_cqe_get_data(cqe);
393355
if (!ctx) {
394356
// Own timeout doesn't have user data
@@ -406,31 +368,65 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
406368
// The cqe for notify, corresponding to IORING_CQE_F_MORE
407369
if (unlikely(cqe->res != 0))
408370
LOG_WARN("iouring: send_zc fall back to copying");
371+
assert(!ctx->is_event);
409372
photon::thread_interrupt(ctx->th_id, EOK);
410373
continue;
411374
}
412375

413376
ctx->res = cqe->res;
414-
if (!ctx->is_canceller && ctx->res == -ECANCELED) {
415-
// An I/O was canceled because of:
416-
// 1. IORING_OP_LINK_TIMEOUT. Leave the interrupt job to the linked timer later.
417-
// 2. IORING_OP_POLL_REMOVE. The I/O is actually a polling.
418-
// 3. IORING_OP_ASYNC_CANCEL. This OP is the superset of case 2.
419-
ctx->res = -ETIMEDOUT;
420-
continue;
421-
} else if (ctx->is_canceller && ctx->res == -ECANCELED) {
422-
// The linked timer itself is also a canceller. The reasons it got cancelled could be:
423-
// 1. I/O finished in time
424-
// 2. I/O was cancelled by IORING_OP_ASYNC_CANCEL
425-
continue;
426-
} else if (cqe->flags & IORING_CQE_F_MORE) {
427-
continue;
377+
if (cqe->flags & IORING_CQE_F_MORE) {
378+
if (cqe->res & POLLERR) {
379+
assert(ctx->is_event);
380+
assert(num == 0);
381+
LOG_ERROR_RETURN(0, -1, "iouring: multi-shot poll got POLLERR");
382+
} else { continue; }
383+
}
384+
if (!ctx->is_event) {
385+
if (!ctx->is_canceller && ctx->res == -ECANCELED) {
386+
// An I/O was canceled because of:
387+
// 1. IORING_OP_LINK_TIMEOUT. Leave the interrupt job to the linked timer later.
388+
// 2. IORING_OP_POLL_REMOVE. The I/O is actually a polling.
389+
// 3. IORING_OP_ASYNC_CANCEL. This OP is the superset of case 2.
390+
ctx->res = -ETIMEDOUT;
391+
continue;
392+
} else if (ctx->is_canceller && ctx->res == -ECANCELED) {
393+
// The linked timer itself is also a canceller. The reasons it got cancelled could be:
394+
// 1. I/O finished in time
395+
// 2. I/O was cancelled by IORING_OP_ASYNC_CANCEL
396+
continue;
397+
}
398+
photon::thread_interrupt(ctx->th_id, EOK);
399+
400+
} else /* if (ctx->is_event) */ {
401+
402+
if (num >= count) { --n; break; }
403+
eventCtx* event_ctx = container_of(ctx, eventCtx, io_ctx);
404+
fdInterest fd_interest{event_ctx->event.fd, (uint32_t)evmap.translate_bitwisely(event_ctx->event.interests)};
405+
if (ctx->res == -ECANCELED) {
406+
m_event_contexts.erase(fd_interest);
407+
} else if (event_ctx->one_shot) {
408+
data[num++] = event_ctx->event.data;
409+
m_event_contexts.erase(fd_interest);
410+
} else {
411+
data[num++] = event_ctx->event.data;
412+
}
428413
}
414+
}
415+
return num;
416+
}
417+
418+
ssize_t wait_and_fire_events(uint64_t timeout) override {
419+
// Prepare own timeout
420+
if (timeout > (uint64_t) std::numeric_limits<int64_t>::max()) {
421+
timeout = std::numeric_limits<int64_t>::max();
422+
}
429423

430-
photon::thread_interrupt(ctx->th_id, EOK);
424+
auto ts = usec_to_timespec(timeout);
425+
if (m_submit_wait_func(m_ring, &ts) != 0) {
426+
return -1;
431427
}
432428

433-
io_uring_cq_advance(m_ring, i);
429+
reap_events();
434430
return 0;
435431
}
436432

@@ -594,108 +590,105 @@ int iouringEngine::m_cooperative_task_flag = -1;
594590

595591
iouringEngine::SubmitWaitFunc iouringEngine::m_submit_wait_func = nullptr;
596592

597-
template<typename...Ts>
598-
inline size_t do_async_io(Ts...xs) {
599-
auto mee = (iouringEngine*) get_vcpu()->master_event_engine;
600-
return mee->async_io(xs...);
593+
inline iouringEngine* get_ring(CascadingEventEngine* cee) {
594+
return cee ? static_cast<iouringEngine*>(cee) :
595+
static_cast<iouringEngine*>(get_vcpu()->master_event_engine);
601596
}
602597

603-
ssize_t iouring_pread(int fd, void* buf, size_t count, off_t offset, uint64_t flags, Timeout timeout) {
598+
ssize_t iouring_pread(int fd, void* buf, size_t count, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
604599
uint32_t ring_flags = flags >> 32;
605-
return do_async_io(&io_uring_prep_read, timeout, ring_flags, fd, buf, count, offset);
600+
return get_ring(cee)->async_io(&io_uring_prep_read, timeout, ring_flags, fd, buf, count, offset);
606601
}
607602

608-
ssize_t iouring_pwrite(int fd, const void* buf, size_t count, off_t offset, uint64_t flags, Timeout timeout) {
603+
ssize_t iouring_pwrite(int fd, const void* buf, size_t count, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
609604
uint32_t ring_flags = flags >> 32;
610-
return do_async_io(&io_uring_prep_write, timeout, ring_flags, fd, buf, count, offset);
605+
return get_ring(cee)->async_io(&io_uring_prep_write, timeout, ring_flags, fd, buf, count, offset);
611606
}
612607

613-
ssize_t iouring_preadv(int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout) {
608+
ssize_t iouring_preadv(int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
614609
uint32_t ring_flags = flags >> 32;
615-
return do_async_io(&io_uring_prep_readv, timeout, ring_flags, fd, iov, iovcnt, offset);
610+
return get_ring(cee)->async_io(&io_uring_prep_readv, timeout, ring_flags, fd, iov, iovcnt, offset);
616611
}
617612

618-
ssize_t iouring_pwritev(int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout) {
613+
ssize_t iouring_pwritev(int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
619614
uint32_t ring_flags = flags >> 32;
620-
return do_async_io(&io_uring_prep_writev, timeout, ring_flags, fd, iov, iovcnt, offset);
615+
return get_ring(cee)->async_io(&io_uring_prep_writev, timeout, ring_flags, fd, iov, iovcnt, offset);
621616
}
622617

623-
ssize_t iouring_send(int fd, const void* buf, size_t len, uint64_t flags, Timeout timeout) {
618+
ssize_t iouring_send(int fd, const void* buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
624619
uint32_t io_flags = flags & 0xffffffff;
625620
uint32_t ring_flags = flags >> 32;
626-
return do_async_io(&io_uring_prep_send, timeout, ring_flags, fd, buf, len, io_flags);
621+
return get_ring(cee)->async_io(&io_uring_prep_send, timeout, ring_flags, fd, buf, len, io_flags);
627622
}
628623

629-
ssize_t iouring_send_zc(int fd, const void* buf, size_t len, uint64_t flags, Timeout timeout) {
624+
ssize_t iouring_send_zc(int fd, const void* buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
630625
uint32_t io_flags = flags & 0xffffffff;
631626
uint32_t ring_flags = flags >> 32;
632-
return do_async_io(&io_uring_prep_send_zc, timeout, ring_flags, fd, buf, len, io_flags, 0);
627+
return get_ring(cee)->async_io(&io_uring_prep_send_zc, timeout, ring_flags, fd, buf, len, io_flags, 0);
633628
}
634629

635-
ssize_t iouring_sendmsg(int fd, const msghdr* msg, uint64_t flags, Timeout timeout) {
630+
ssize_t iouring_sendmsg(int fd, const msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
636631
uint32_t io_flags = flags & 0xffffffff;
637632
uint32_t ring_flags = flags >> 32;
638-
return do_async_io(&io_uring_prep_sendmsg, timeout, ring_flags, fd, msg, io_flags);
633+
return get_ring(cee)->async_io(&io_uring_prep_sendmsg, timeout, ring_flags, fd, msg, io_flags);
639634
}
640635

641-
ssize_t iouring_sendmsg_zc(int fd, const msghdr* msg, uint64_t flags, Timeout timeout) {
636+
ssize_t iouring_sendmsg_zc(int fd, const msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
642637
uint32_t io_flags = flags & 0xffffffff;
643638
uint32_t ring_flags = flags >> 32;
644-
return do_async_io(&io_uring_prep_sendmsg_zc, timeout, ring_flags, fd, msg, io_flags);
639+
return get_ring(cee)->async_io(&io_uring_prep_sendmsg_zc, timeout, ring_flags, fd, msg, io_flags);
645640
}
646641

647-
ssize_t iouring_recv(int fd, void* buf, size_t len, uint64_t flags, Timeout timeout) {
642+
ssize_t iouring_recv(int fd, void* buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
648643
uint32_t io_flags = flags & 0xffffffff;
649644
uint32_t ring_flags = flags >> 32;
650-
return do_async_io(&io_uring_prep_recv, timeout, ring_flags, fd, buf, len, io_flags);
645+
return get_ring(cee)->async_io(&io_uring_prep_recv, timeout, ring_flags, fd, buf, len, io_flags);
651646
}
652647

653-
ssize_t iouring_recvmsg(int fd, msghdr* msg, uint64_t flags, Timeout timeout) {
648+
ssize_t iouring_recvmsg(int fd, msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee) {
654649
uint32_t io_flags = flags & 0xffffffff;
655650
uint32_t ring_flags = flags >> 32;
656-
return do_async_io(&io_uring_prep_recvmsg, timeout, ring_flags, fd, msg, io_flags);
651+
return get_ring(cee)->async_io(&io_uring_prep_recvmsg, timeout, ring_flags, fd, msg, io_flags);
657652
}
658653

659-
int iouring_connect(int fd, const sockaddr* addr, socklen_t addrlen, Timeout timeout) {
660-
return do_async_io(&io_uring_prep_connect, timeout, 0, fd, addr, addrlen);
654+
int iouring_connect(int fd, const sockaddr* addr, socklen_t addrlen, Timeout timeout, CascadingEventEngine* cee) {
655+
return get_ring(cee)->async_io(&io_uring_prep_connect, timeout, 0, fd, addr, addrlen);
661656
}
662657

663-
int iouring_accept(int fd, sockaddr* addr, socklen_t* addrlen, Timeout timeout) {
664-
return do_async_io(&io_uring_prep_accept, timeout, 0, fd, addr, addrlen, 0);
658+
int iouring_accept(int fd, sockaddr* addr, socklen_t* addrlen, Timeout timeout, CascadingEventEngine* cee) {
659+
return get_ring(cee)->async_io(&io_uring_prep_accept, timeout, 0, fd, addr, addrlen, 0);
665660
}
666661

667-
int iouring_fsync(int fd) {
668-
return do_async_io(&io_uring_prep_fsync, -1, 0, fd, 0);
662+
int iouring_fsync(int fd, Timeout timeout, CascadingEventEngine* cee) {
663+
return get_ring(cee)->async_io(&io_uring_prep_fsync, timeout, 0, fd, 0);
669664
}
670665

671-
int iouring_fdatasync(int fd) {
672-
return do_async_io(&io_uring_prep_fsync, -1, 0, fd, IORING_FSYNC_DATASYNC);
666+
int iouring_fdatasync(int fd, Timeout timeout, CascadingEventEngine* cee) {
667+
return get_ring(cee)->async_io(&io_uring_prep_fsync, timeout, 0, fd, IORING_FSYNC_DATASYNC);
673668
}
674669

675-
int iouring_open(const char* path, int flags, mode_t mode) {
676-
return do_async_io(&io_uring_prep_openat, -1, 0, AT_FDCWD, path, flags, mode);
670+
int iouring_open(const char* path, int flags, mode_t mode, Timeout timeout, CascadingEventEngine* cee) {
671+
return get_ring(cee)->async_io(&io_uring_prep_openat, timeout, 0, AT_FDCWD, path, flags, mode);
677672
}
678673

679-
int iouring_mkdir(const char* path, mode_t mode) {
680-
return do_async_io(&io_uring_prep_mkdirat, -1, 0, AT_FDCWD, path, mode);
674+
int iouring_mkdir(const char* path, mode_t mode, Timeout timeout, CascadingEventEngine* cee) {
675+
return get_ring(cee)->async_io(&io_uring_prep_mkdirat, timeout, 0, AT_FDCWD, path, mode);
681676
}
682677

683-
int iouring_close(int fd) {
684-
return do_async_io(&io_uring_prep_close, -1, 0, fd);
678+
int iouring_close(int fd, Timeout timeout, CascadingEventEngine* cee) {
679+
return get_ring(cee)->async_io(&io_uring_prep_close, timeout, 0, fd);
685680
}
686681

687682
bool iouring_register_files_enabled() {
688683
return iouringEngine::register_files_enabled();
689684
}
690685

691-
int iouring_register_files(int fd) {
692-
auto ee = (iouringEngine*) get_vcpu()->master_event_engine;
693-
return ee->register_unregister_files(fd, true);
686+
int iouring_register_files(int fd, CascadingEventEngine* cee) {
687+
return get_ring(cee)->register_unregister_files(fd, true);
694688
}
695689

696-
int iouring_unregister_files(int fd) {
697-
auto ee = (iouringEngine*) get_vcpu()->master_event_engine;
698-
return ee->register_unregister_files(fd, false);
690+
int iouring_unregister_files(int fd, CascadingEventEngine* cee) {
691+
return get_ring(cee)->register_unregister_files(fd, false);
699692
}
700693

701694
void* new_iouring_event_engine(iouring_args args) {

0 commit comments

Comments
 (0)