Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Early work-in-progress io_uring support #1356

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dmantipov
Copy link
Contributor

@dmantipov dmantipov commented Oct 5, 2022

This code aims to provide an initial and very basic support for io_uring(7), a Linux-specific API for asynchronous I/O. Currently this work aims to provide an io_uring-based I/O for socket-based bufferevents. The most important issue of the whole thing is that bufferevent interface assumes the synchronous callbacks, somewhat similar to the convenient read() and write() system calls, but the whole io_uring subsystem is designed to be (mostly) asynchronous. Current approach is designed in attempt to avoid changing an external libevent API and basically works as follows:

  1. evbuffer_io_uring_submit_rwv() should get and SQE, prepare it to issue I/O request, submit to the ring, and call event_base_active_by_fd() to enforce the next iteration of (per-base) event processing loop.
  2. Being woken up to serve an event processing loop, event_process_active_single_queue() issues io_uring_wait_cqe_timeout() to fetch CQE and finally calls event_process_cqe() to complete an I/O.

I would strongly suggests everyone interested in this feature to try this code, run sample/bufferevent-benchmark test, share the numbers and maybe even an ideas on further improvements of this code, whatever.

Signed-off-by: Dmitry Antipov dantipov@cloudlinux.com

Fixes: #1019

@azat
Copy link
Member

azat commented Oct 6, 2022

Great!

An idea is that an event_base should auto-tune itself to match the workload.

Actually this is not that important, and maybe it is better to do it separately, since right now there is no such auto tunning.

That is, io_uring makes no sense if there are just a few in-flight evbuffers for the most of the time and so individual readv()/writev() calls are enough

Yes, but it will also not harm, right?
So maybe yo can go with a simpler implementation that we can merge first and then work in some auto-tuning algorithms.

@dmantipov
Copy link
Contributor Author

Is it possible to install liburing-2.2 on a few Linux systems running CI jobs? Although current io_uring quirks are not ready to pass all of the make verify tests, this may change in the near future :-).

@azat
Copy link
Member

azat commented Oct 7, 2022

Is it possible to install liburing-2.2 on a few Linux systems running CI jobs?

Sure, just modify:

@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch 2 times, most recently from 6a7036d to 7644b74 Compare October 10, 2022 10:50
@dmantipov
Copy link
Contributor Author

I've relaxed liburing requirements to >= 2.0, it should work as well.

@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch 3 times, most recently from 8facc5c to 626677e Compare October 13, 2022 15:10
@dmantipov
Copy link
Contributor Author

NOTE: in the last version of the patch, io_uring is turned off by default even if supported, and it's required to call event_base_new_with_config(cfg) with enabled event_config_set_flag(cfg, EVENT_BASE_FLAG_IO_URING) flag.

@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch 2 times, most recently from b1e531f to 0241dc3 Compare October 18, 2022 09:05
@azat
Copy link
Member

azat commented Oct 23, 2022

@dmantipov do you have some workload that can benefit from this?

@@ -73,7 +73,7 @@ jobs:
- name: Install Depends
run: |
sudo apt-get update
sudo apt-get install -y libmbedtls-dev
sudo apt-get install -y libmbedtls-dev liburing-dev
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, there is no liburing-dev in ubuntu 18.04, let's switch to ubuntu-22.04

#ifdef EVENT__HAVE_LIBURING
struct io_uring io_uring;
unsigned io_uring_sqe_count;
struct __kernel_timespec io_uring_cqe_timeout;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using plain timespec instead of private __kernel_timespec

base->io_uring_cqe_timeout.tv_nsec = 0;
}
if (io_uring_queue_init(queue_size, &base->io_uring, 0) == 0)
base->flags |= EVENT_BASE_FLAG_IO_URING;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error if it fails?

event.c Outdated
@@ -1769,6 +1841,14 @@ event_process_active_single_queue(struct event_base *base,
if (base->event_continue)
break;
}
#ifdef EVENT__HAVE_LIBURING
/* FIXME: handle unfinished I/O requests properly. */
if (base->io_uring_sqe_count > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is bad? It can be handled in another iteration

@@ -1755,6 +1817,16 @@ event_process_active_single_queue(struct event_base *base,
}
#endif

#ifdef EVENT__HAVE_LIBURING
if (base->io_uring_sqe_count) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, interface looks clumsy:

  • checking io_uring_sqe_count after each event looks odd, it should be checked in the event_base_loop, or it should be binded to specific event and processed only when the callback for that particular event is called (one way is to add new callback for event in case of uring, however a) this will bloat the structure and b) it will break ABI compatibility - even though it is highly not recommended to use event structure directly)
  • io_uring_sqe_count is set from the buffer.c, and checked here, how about adding some wrappers for this?
  • io_uring_buffers modified directly from the bufferevent code, how about adding some wrappers for this?

buffer.c Outdated
else {
/* Caller might want to check errno, which
is never used by liburing itself. */
n = -1, errno = -buf->io_uring_result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
n = -1, errno = -buf->io_uring_result;
n = -1;
errno = -buf->io_uring_result;

buffer.c Outdated
else {
/* Caller might want to check errno, which
is never used by liburing itself. */
n = -1, errno = -buffer->io_uring_result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
n = -1, errno = -buffer->io_uring_result;
n = -1;
errno = -buffer->io_uring_result;

buffer.c Outdated
buf->io_uring_status = IO_URING_NONE;
goto complete;
} else if (buf->io_uring_status == IO_URING_RUNNING) {
result = -1, errno = EINPROGRESS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
result = -1, errno = EINPROGRESS;
result = -1;
errno = EINPROGRESS;

buffer.c Outdated
buffer->io_uring_status = IO_URING_NONE;
goto complete;
} else if (buffer->io_uring_status == IO_URING_RUNNING) {
n = -1, errno = EINPROGRESS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
n = -1, errno = EINPROGRESS;
n = -1;
errno = EINPROGRESS;

@azat
Copy link
Member

azat commented Oct 23, 2022

I will mark it as draft for now.

@azat
Copy link
Member

azat commented Oct 24, 2022

CI failures:

/usr/bin/ld: lib/libevent_core-2.2.so.1.0.0: undefined reference to `io_uring_queue_init'
/usr/bin/ld: lib/libevent_core-2.2.so.1.0.0: undefined reference to `io_uring_submit'
/usr/bin/ld: lib/libevent_core-2.2.so.1.0.0: undefined reference to `io_uring_queue_exit'
/usr/bin/ld: lib/libevent_core-2.2.so.1.0.0: undefined reference to `io_uring_get_sqe'
/usr/bin/ld: lib/libevent_core-2.2.so.1.0.0: undefined reference to `io_uring_wait_cqe_timeout'

But by some reason one build with clang passed - https://github.com/libevent/libevent/actions/runs/3308507890/jobs/5460943018
Any clue?

@dmantipov dmantipov closed this Dec 8, 2022
@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch from a575de7 to d8ecb88 Compare December 8, 2022 16:27
@dmantipov dmantipov reopened this Dec 8, 2022
@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch from 97b88ad to bfe3f23 Compare December 9, 2022 08:58
@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch from bfe3f23 to ee65796 Compare December 20, 2022 09:43
@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch from ee65796 to 68d51a3 Compare December 30, 2022 09:52
Signed-off-by: Dmitry Antipov <dantipov@cloudlinux.com>
@dmantipov dmantipov force-pushed the early-work-in-progress-io-uring-support branch from 68d51a3 to b528661 Compare January 13, 2023 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

io_uring support for linux 5.1+
2 participants