Support handling TCP I/O in simple separate io_uring-based I/O threads

Required mainly for clients, allows to scale parallel client I/O with TCP
from 100-150k iops to ~400k iops and from 2-3 GB/s to at least 7-8 GB/s
with 4 I/O threads, at the same time increasing Q=1 latency by 2x thread
switching delay, which is ~10 us when CPU powersaving is disabled and may
be as high as 200 us when it's enabled.
This commit is contained in:
Vitaliy Filippov
2024-07-04 13:29:20 +03:00
parent 21d1171ba4
commit abbba6ade4
14 changed files with 331 additions and 19 deletions
+27 -1
View File
@@ -10,8 +10,9 @@
#include "ringloop.h"
ring_loop_t::ring_loop_t(int qd)
ring_loop_t::ring_loop_t(int qd, bool multithreaded)
{
mt = multithreaded;
int ret = io_uring_queue_init(qd, &ring, 0);
if (ret < 0)
{
@@ -64,6 +65,25 @@ void ring_loop_t::unregister_consumer(ring_consumer_t *consumer)
}
}
io_uring_sqe* ring_loop_t::get_sqe()
{
if (mt)
mu.lock();
if (free_ring_data_ptr == 0)
{
if (mt)
mu.unlock();
return NULL;
}
struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
assert(sqe);
*sqe = { 0 };
io_uring_sqe_set_data(sqe, ring_datas + free_ring_data[--free_ring_data_ptr]);
if (mt)
mu.unlock();
return sqe;
}
void ring_loop_t::loop()
{
if (ring_eventfd >= 0)
@@ -79,6 +99,8 @@ void ring_loop_t::loop()
struct io_uring_cqe *cqe;
while (!io_uring_peek_cqe(&ring, &cqe))
{
if (mt)
mu.lock();
struct ring_data_t *d = (struct ring_data_t*)cqe->user_data;
if (d->callback)
{
@@ -90,12 +112,16 @@ void ring_loop_t::loop()
dl.res = cqe->res;
dl.callback.swap(d->callback);
free_ring_data[free_ring_data_ptr++] = d - ring_datas;
if (mt)
mu.unlock();
dl.callback(&dl);
}
else
{
fprintf(stderr, "Warning: empty callback in SQE\n");
free_ring_data[free_ring_data_ptr++] = d - ring_datas;
if (mt)
mu.unlock();
}
io_uring_cqe_seen(&ring, cqe);
}