Hi, async programmers. Linux 4.5 released in last month intorduces EPOLLEXCLUSIVE. http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
It can address epoll thundering herd problem. http://uwsgi-docs.readthedocs.org/en/latest/articles/SerializingAccept.html#select-poll-kqueue-epoll I tried it on AWS EC2 c4.xlarge (4core). * simple "hello world" wsgi app * Use uWSGI and meinheld with 8 workers * ab -n10000 -c4 EPOLLEXCLUSIVE improve performance from 15k req/sec to 22k req/sec. And I confirm it reduces number of `accept4()` call significantly. ubuntu:~/app$ strace -f ~/.local/bin/uwsgi --master --workers=8 --http-socket :8080 --wsgi hello 2>trace.log ubuntu:~$ ab -c1 -n1000 http://localhost:8080/ ubuntu:~/app$ grep -c '] accept4' trace.log # w/o EPOLLEXCLUSIVE6884 ubuntu:~/app$ grep -c '] accept4' trace.log # w/ EPOLLEXCLUSIVE1557 And I confirm Linux ~4.4 ignores EPOLLEXCLUSIVE (1 << 28). So I can use it safely without compile time nor runtime check. I want to add EPOLLEXCLUSIVE support to asyncio. Current selector's API is: abstractmethod register(fileobj, events, data=None) https://docs.python.org/3/library/selectors.html#selectors.BaseSelector.register How can I cange the API? Maybe: abstractmethod register(fileobj, events, data=None, **flags) ... poller.register(listenfd, selectors.EVENT_READ, data, exclusive=True) # only EpollSelector supports exclusive. others ignore unknown flags. Or: poller.register(listenfd, selectors.EVENT_READ_EXCLUSIVE, data) # Add EVENT_READ_EXCLUSIVE and EVENT_READ_EXCLUSIVE. Thanks. --- pache for meinheld: diff --git a/meinheld/server/picoev_epoll.c b/meinheld/server/picoev_epoll.c index 06e1dbb..773cf3c 100644--- a/meinheld/server/picoev_epoll.c+++ b/meinheld/server/picoev_epoll.c@@ -115,6 +115,7 @@ int picoev_update_events_internal(picoev_loop* _loop, int fd, int events) SET(EPOLL_CTL_MOD, 0); if (epoll_ret != 0) { assert(errno == ENOENT);+ ev.events |= (1 << 28); // EPOLLEXCLUSIVE (from linux 4.5) SET(EPOLL_CTL_ADD, 1); } }@@ -124,7 +125,12 @@ int picoev_update_events_internal(picoev_loop* _loop, int fd, int events) if ((events & PICOEV_READWRITE) == 0) { SET(EPOLL_CTL_DEL, 1); } else {- SET(target->events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, 1);+ if (target->events == 0) {+ ev.events |= (1 << 28); // EPOLLEXCLUSIVE (from linux 4.5)+ SET(EPOLL_CTL_ADD, 1);+ } else {+ SET(EPOLL_CTL_MOD, 1);+ } } #endif pache for uWSGI: diff --git a/core/event.c b/core/event.c index 36751a6..32a1934 100644--- a/core/event.c+++ b/core/event.c@@ -514,7 +514,7 @@ int event_queue_add_fd_read(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event));- ee.events = EPOLLIN;+ ee.events = EPOLLIN | (1 << 28); ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
