Live data from Hacker News

Epoll vs. io_uring in Linux

sibexi.co

41–50 of 79 posts

Re: Epoll vs. io_uring in Linux

#41

I've not yet tested the shared buffers for my io uring based web server, but that's because instead of reading from a file and writing, i send directly from a mmaped region. But really, I want to sendfile with io_uring, but that's not supported yet. My writeup, with extra buzzwords like Rust and kTLS: https://blog.habets.se/2025/04/io-uring-ktls-and-rust-for-ze... It was on HN too: https://news.ycombinator.com/item?i…

FYI you can use sendfile ish with uring, since splice(2) is implemented. Not as user friendly as sendfile, but should work fairly similarly.

[deleted]

Re: Epoll vs. io_uring in Linux

#42

I've not yet tested the shared buffers for my io uring based web server, but that's because instead of reading from a file and writing, i send directly from a mmaped region. But really, I want to sendfile with io_uring, but that's not supported yet. My writeup, with extra buzzwords like Rust and kTLS: https://blog.habets.se/2025/04/io-uring-ktls-and-rust-for-ze... It was on HN too: https://news.ycombinator.com/item?i…

FYI you can use sendfile ish with uring, since splice(2) is implemented. Not as user friendly as sendfile, but should work fairly similarly.

On the Linux side sendfile is implemented via splice. So it is a more generic API that covers the sendfile case.

Re: Epoll vs. io_uring in Linux

#43
Such a great article!

This sent me through a rabbit hole of uring, kernel development and C. I've been a rust and c++ dev for quite a few years now, but there's such a simplicity and even artistic feel to small(ish) C programs.

Re: Epoll vs. io_uring in Linux

#44
post #31
post #3

Yes, io_uring is significantly faster than epoll (I think I had like 20% faster req/s with io_uring.) The catch is that its kernel opt-in and disabled just about everywhere for security reasons. I think that it has direct memory sharing between the kernel and user-land which is kind of yikes. There's been multiple exploits that hit io_uring in recent times. It's because of this that even engineering projects that try…

The main reason why it gets disabled is fixed now, the latest RC got cBPF support and as such you can restrict what OPs can be run now instead of just fully disabling it.

Well the reason it's disabled now is the recent history of pretty bad vulnerabilities. It probably needs to go a while without new vulnerabilities before it makes sense to enable by default. It's pretty complex completely unsafe C code, after all.

Re: Epoll vs. io_uring in Linux

#45
If you write one with DPDK, it'll be infinitely more complex but you'll have the opportunity to blow away nginx in performance.

If you make one run on an FPGA you it'll be even more complex.

The lesson is that cutting through abstraction like a hot knife through butter is a necessary mindset for performance but also makes things more difficult. Sockets and thread-per-connection were good approaches when networks were very slow relative to CPUs, and they're still often the simplest approach today.

Re: Epoll vs. io_uring in Linux

#46
post #32

Earlier quoted context omitted.

It's still seccomp'd off in most environments because io-uring is still a seccomp bypass that doesn't play well with kernel security systems (audit subsystem), even if it weren't also like the #1 or #2 exploit vector for privesc.

That’s solved as of last week, you can use cBPF now to disable functionality.

How solved? AFAIK it's not meaningfully shipped but happy to hear otherwise.

Re: Epoll vs. io_uring in Linux

#47

Earlier quoted context omitted.

FYI you can use sendfile ish with uring, since splice(2) is implemented. Not as user friendly as sendfile, but should work fairly similarly.

On the Linux side sendfile is implemented via splice. So it is a more generic API that covers the sendfile case.

Yes, my understanding is that I should be able to emulate sendfile via splice. The problem with that is that splice requires one end to be a pipe.

So I think this means two extra file descriptors per connection (one per side of the pipe). And per connection this adds 5 slots in the submit/completion queue, with a LINK dependency. Maybe the trade off is worth it. I've not done concrete experiments with it, but I'm guessing it would be if the saved copy_from_user is large enough.

So for optimal performance this may mean using write() for short files, and a pipe(), a pair of splice() calls, and a pair of close() calls, for larger files.

Edit: I guess I could save some ops by reusing pipes, but then I'd have to make sure to flush them. Would add some complexity.

Re: Epoll vs. io_uring in Linux

#48

I've not yet tested the shared buffers for my io uring based web server, but that's because instead of reading from a file and writing, i send directly from a mmaped region. But really, I want to sendfile with io_uring, but that's not supported yet. My writeup, with extra buzzwords like Rust and kTLS: https://blog.habets.se/2025/04/io-uring-ktls-and-rust-for-ze... It was on HN too: https://news.ycombinator.com/item?i…

FYI you can use sendfile ish with uring, since splice(2) is implemented. Not as user friendly as sendfile, but should work fairly similarly.

Oops, I actually replied to the wrong comment. I replied here: https://news.ycombinator.com/item?id=48617774

But it's a relevant reply to both comments, so copied here:

Yes, my understanding is that I should be able to emulate sendfile via splice. The problem with that is that splice requires one end to be a pipe. So I think this means two extra file descriptors per connection (one per side of the pipe). And per connection this adds 5 slots in the submit/completion queue, with a LINK dependency. Maybe the trade off is worth it. I've not done concrete experiments with it, but I'm guessing it would be if the saved copy_from_user is large enough.

So for optimal performance this may mean using write() for short files, and a pipe(), a pair of splice() calls, and a pair of close() calls, for larger files.

Re: Epoll vs. io_uring in Linux

#50
In the context of a proxy one should mention epoll_wait busy poll. I've recently dived into this when reviewing low-latency options, and found that it's almost possible to do user space busy polling just for simple sockets, no DPDK/VMA/io_uring needed, and Fastly contributed to this and uses it.

It's too low level, I cannot even tell that I understand everything, only the concept, so I will just share some links. It works only per NAPI epoll context, and one cannot easily control NAPI ID, but if an entire machine is dedicated for a proxy one can do a simple trick of assinging sockets by NAPI ID to dedicated pollers.

In my use case, it was not a proxy, but N socket polling on a machine that then processes received data. It does not look feasible for such case, maybe round-robin polling of NAPI contexts from a single thread may work. What I would really want to have one day from the kernel is that I can easily tell it: trust me, I will poll this single socket eventually, never ever use IRQ path for it.

Previous HN discussion of the kernel feature: https://news.ycombinator.com/item?id=43749271 Nice presentation by the Fastly contributor, with nice diagrams making the big picture much easier to understand: https://netdevconf.info/0x18/docs/netdev-0x18-paper10-talk-s... LWN articles: https://lwn.net/Articles/1008399/, https://lwn.net/Articles/997491/, https://lwn.net/Articles/959462/ Kernel docs: https://docs.kernel.org/networking/napi.html#irq-mitigation

Post reply on HN