From 5ad3d6331147e2c24d64aa2b5e7f097b15196498 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 14 Jul 2023 10:23:35 -1000 Subject: [PATCH 1/7] Optimize EpollSelector performance --- Lib/selectors.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py index 6d82935445d4b1..e7241878edd0f6 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -430,6 +430,9 @@ class PollSelector(_PollLikeSelector): if hasattr(select, 'epoll'): + NOT_EPOLLIN = ~select.EPOLLIN + NOT_EPOLLOUT = ~select.EPOLLOUT + class EpollSelector(_PollLikeSelector): """Epoll-based selector.""" _selector_cls = select.epoll @@ -448,27 +451,31 @@ def select(self, timeout=None): # epoll_wait() has a resolution of 1 millisecond, round away # from zero to wait *at least* timeout seconds. timeout = math.ceil(timeout * 1e3) * 1e-3 - # epoll_wait() expects `maxevents` to be greater than zero; # we want to make sure that `select()` can be called when no # FD is registered. - max_ev = max(len(self._fd_to_key), 1) + max_ev = len(self._fd_to_key) or 1 ready = [] try: fd_event_list = self._selector.poll(timeout, max_ev) except InterruptedError: return ready - for fd, event in fd_event_list: - events = 0 - if event & ~select.EPOLLIN: - events |= EVENT_WRITE - if event & ~select.EPOLLOUT: - events |= EVENT_READ - key = self._fd_to_key.get(fd) + fd_to_key = self._fd_to_key + for fd, event in fd_event_list: + key = fd_to_key.get(fd) if key: - ready.append((key, events & key.events)) + ready.append( + ( + key, + ( + (event & NOT_EPOLLIN and EVENT_WRITE) + | (event & NOT_EPOLLOUT and EVENT_READ) + ) + & key.events + ) + ) return ready def close(self): From 0986a6491d70439a1859f0d644ac3276ffbb4e0e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 14 Jul 2023 10:26:37 -1000 Subject: [PATCH 2/7] tweak lines --- Lib/selectors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/selectors.py b/Lib/selectors.py index e7241878edd0f6..3bce9c23ea4484 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -451,6 +451,7 @@ def select(self, timeout=None): # epoll_wait() has a resolution of 1 millisecond, round away # from zero to wait *at least* timeout seconds. timeout = math.ceil(timeout * 1e3) * 1e-3 + # epoll_wait() expects `maxevents` to be greater than zero; # we want to make sure that `select()` can be called when no # FD is registered. From 4a64471f82ae4d9314383ad1fdda8eec8cd6254e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:31:11 +0000 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst new file mode 100644 index 00000000000000..ae2f466062aa5f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst @@ -0,0 +1 @@ +:mod:`selectors`: Reduce EpollSelector overhead by moving code outside of the loop and avoiding a call to ``max()``. From 83d46be50a4650865c5c14553d27148fe437f59a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 14 Jul 2023 12:15:14 -1000 Subject: [PATCH 4/7] Update Lib/selectors.py Co-authored-by: Pieter Eendebak --- Lib/selectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/selectors.py b/Lib/selectors.py index 3bce9c23ea4484..376d27be226324 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -430,7 +430,7 @@ class PollSelector(_PollLikeSelector): if hasattr(select, 'epoll'): - NOT_EPOLLIN = ~select.EPOLLIN + _NOT_EPOLLIN = ~select.EPOLLIN NOT_EPOLLOUT = ~select.EPOLLOUT class EpollSelector(_PollLikeSelector): From 298b04c38f0493d3fa41cef5107f7dcec554512d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 14 Jul 2023 12:15:47 -1000 Subject: [PATCH 5/7] Apply suggestions from code review --- Lib/selectors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py index 376d27be226324..ba7f465c26a1d6 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -431,7 +431,7 @@ class PollSelector(_PollLikeSelector): if hasattr(select, 'epoll'): _NOT_EPOLLIN = ~select.EPOLLIN - NOT_EPOLLOUT = ~select.EPOLLOUT + _NOT_EPOLLOUT = ~select.EPOLLOUT class EpollSelector(_PollLikeSelector): """Epoll-based selector.""" @@ -471,8 +471,8 @@ def select(self, timeout=None): ( key, ( - (event & NOT_EPOLLIN and EVENT_WRITE) - | (event & NOT_EPOLLOUT and EVENT_READ) + (event & _NOT_EPOLLIN and EVENT_WRITE) + | (event & _NOT_EPOLLOUT and EVENT_READ) ) & key.events ) From ee3b0573251d81601ca77a832f23ffd66fb408f3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 17 Jul 2023 18:45:02 -1000 Subject: [PATCH 6/7] Update Lib/selectors.py Co-authored-by: Inada Naoki --- Lib/selectors.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py index ba7f465c26a1d6..a42d1563406417 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -467,16 +467,9 @@ def select(self, timeout=None): for fd, event in fd_event_list: key = fd_to_key.get(fd) if key: - ready.append( - ( - key, - ( - (event & _NOT_EPOLLIN and EVENT_WRITE) - | (event & _NOT_EPOLLOUT and EVENT_READ) - ) - & key.events - ) - ) + events = ((event & _NOT_EPOLLIN and EVENT_WRITE) + | (event & _NOT_EPOLLOUT and EVENT_READ)) + ready.append((key, events & key.events)) return ready def close(self): From bd137ec8b170267bcc2846e90d56919851899672 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 18 Jul 2023 18:35:33 +0900 Subject: [PATCH 7/7] Update 2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst --- .../next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst index ae2f466062aa5f..486b1f9bbd0a97 100644 --- a/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst +++ b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst @@ -1 +1 @@ -:mod:`selectors`: Reduce EpollSelector overhead by moving code outside of the loop and avoiding a call to ``max()``. +:mod:`selectors`: Optimize ``EpollSelector.select()`` code by moving some code outside of the loop.