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
Use io_uring to batch handle clients pending writes to reduce SYSCALL count. #13139
base: unstable
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
io_uring is very cool, but I don't understand it well enough yet. I commented on some things related to conditional compilation.
I think we can mark it as draft, because there are problems in CI that needs to be solved.
src/Makefile
Outdated
ifneq ($(USE_IO_URING),no) | ||
FINAL_CFLAGS+= -DUSE_IO_URING | ||
FINAL_LIBS+= -luring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will always be true. USE_IO_URING is not set to "no" anywhere. Why not ifeq ($(USE_IO_URING),yes)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, my original intention is to turn on io_uring by default unless the user manually turns off io_uring by make USE_IO_URING=no
. ): It works on Linux, but for other platform, we should disable io_uring default.
Sure, I will change to ifeq ($(USE_IO_URING),yes)
as you suggested. Thanks.
src/server.h
Outdated
@@ -3725,6 +3732,14 @@ void quitCommand(client *c); | |||
void resetCommand(client *c); | |||
void failoverCommand(client *c); | |||
|
|||
/* io_uring.c -- io_uring related operations */ | |||
#include <liburing.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't include this on platforms that don't have it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right, maybe we can solve this by ifeq ($(USE_IO_URING),yes)
. And use USE_IO_URING to protect it.
@zuiderkwast Thanks for your comments.
Yes, io_uring is very cool, really excited to see io_uring can help Redis on this scenario and gain perf. The scenario is very straightforward, appreciate that the community can help on this.
For the CI build failure, it is caused by the liburing is not exist in CI environment, I am thinking how to add the liburing dependency for Redis: manually copy liburing to deps/ folder or refer to the method of ssl. What's your suggestion? |
I think we can auto-detect it like we do for C11 atomics here: https://github.com/redis/redis/blob/7.2.4/src/Makefile#L46. It creates a small file and tries to compile it. |
The approach still need user manually install liburing even kernel has io_uring support, and sometimes the build env is not total same with runtime env, can we include https://github.com/axboe/liburing/ in deps module like jemalloc if license compliance? |
Ok, now I understand. I think we can include it under deps if it is small. What's the total size of it? The core team needs to make the final decision. An idea is to introduce it in two steps. First, as a beta feature, we can we require the user to manually install liburing. We can modify one of the CI jobs to install and use it in tests. Later, when it's found to work well, it can be enabled by default and included under deps. |
With liburing, the total size of redis-server binary changed from 21279160 to 21451704.
Agree, I just upload the liburing-2.5 to deps to check if the CI could success, this is a temporary solution. The final solution need core team make decision. |
|
||
for (i = 0; i < qd; i++) { | ||
sqe = io_uring_get_sqe(&ring); | ||
int roff = (off + i) % table_size; |
Check failure
Code scanning / CodeQL
Uncontrolled data in arithmetic expression High
uncontrolled value
if (ret == -1) | ||
t_error(1, errno, "recv"); | ||
if (ret != cfg_payload_len) | ||
t_error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); |
Check failure
Code scanning / CodeQL
Wrong type of arguments to formatting function High
Update: The patch makes below 4 unit tests hang, the others passed, I am trying to fix it, if any help will be appreciated. :)
BTW, @madolson @oranagra @zuiderkwast @enjoy-binbin do you think this make sense for Redis to adopt io_uring from this scenario? |
@lipzhu can you save me some time and improve the top comment describing the change in the flow. additionally, i see the benchmark mentions the reducing of cycles per commands, but not any improvement in throughput or latency, can we add one? how will it be affected by adding a pipeline ( |
Description
This patch try to benefit the io_uring batching feature to reduce the SYSCALL count for Redis when handleClientsWithPendingWrites.
With this patch, we can observe more than 4% perf gain for SET/GET, and didn't see an obvious performance regression.
NOTE
Test Result
Test Env
Test Steps
taskset -c 0-3 ~/src/redis-server /tmp/redis_1.conf
with below config.taskset -c 16-19 ~/src/redis-benchmark -p 9001 -t set -d 100 -r 1000000 -n 5000000 -c 50 --threads 4
to ensure redis-server CPU utilized is 1(fully utilized).Test Result
With this patch, the QPS can increase 4.3%.
And both the cycles for each query and SYSCALL count are reduced as expected.
perf stat -p `pidof redis-server` sleep 10
Table is the normalized cycles/ins for each query.
bcc/syscount -p `pidof redis-server` -d 10
In this patch,
io_uring_enter
is the replacement ofwrite
.From above data, the SYSCALL is expensive, by reducing the SYSCALL related instructions, IPC improves.