Issue #20452: select and selectors round (again) timeout away from zero for

poll and epoll

Improve also debug info to analyze the issue
This commit is contained in:
Victor Stinner 2014-01-31 12:12:53 +01:00
parent 31f65044a9
commit dcd9740ad2
4 changed files with 26 additions and 26 deletions

View File

@ -627,16 +627,11 @@ class BaseEventLoop(events.AbstractEventLoop):
t1 = self.time() t1 = self.time()
# FIXME: remove these debug info (issue #20452) # FIXME: remove these debug info (issue #20452)
dt = t1-t0 dt = t1-t0
if timeout is not None: if timeout is not None and dt < timeout and not event_list:
if dt < timeout and not event_list: print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)"
print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" % (timeout, dt, dt-timeout), file=sys.__stdout__)
% (timeout, dt, dt-timeout), file=sys.__stdout__) print("WARNING: dt+%.20f > timeout? %s"
print("WARNING: dt+%.20f > timeout? %s" % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__)
% (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__)
else:
if not event_list:
print("WARNING: selector.select(timeout=%r) took dt=%.20f sec"
% (timeout, dt), file=sys.__stdout__)
if t1-t0 >= 1: if t1-t0 >= 1:
level = logging.INFO level = logging.INFO
else: else:

View File

@ -8,6 +8,7 @@ This module allows high-level and efficient I/O multiplexing, built upon the
from abc import ABCMeta, abstractmethod, abstractproperty from abc import ABCMeta, abstractmethod, abstractproperty
from collections import namedtuple, Mapping from collections import namedtuple, Mapping
import functools import functools
import math
import select import select
import sys import sys
@ -369,8 +370,9 @@ if hasattr(select, 'poll'):
elif timeout <= 0: elif timeout <= 0:
timeout = 0 timeout = 0
else: else:
# Round towards zero # poll() has a resolution of 1 millisecond, round away from
timeout = int(timeout * 1000) # zero to wait *at least* timeout seconds.
timeout = int(math.ceil(timeout * 1e3))
ready = [] ready = []
try: try:
fd_event_list = self._poll.poll(timeout) fd_event_list = self._poll.poll(timeout)
@ -430,6 +432,10 @@ if hasattr(select, 'epoll'):
timeout = -1 timeout = -1
elif timeout <= 0: elif timeout <= 0:
timeout = 0 timeout = 0
else:
# 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
max_ev = len(self._fd_to_key) max_ev = len(self._fd_to_key)
ready = [] ready = []
try: try:

View File

@ -28,6 +28,15 @@ from asyncio import events
from asyncio import selector_events from asyncio import selector_events
from asyncio import test_utils from asyncio import test_utils
# FIXME: remove these info, used for debug purpose (issue #20452)
print("time.monotonic() info: %r" % (time.get_clock_info('monotonic'),))
try:
SC_CLK_TCK = os.sysconf('SC_CLK_TCK')
print("os.sysconf('SC_CLK_TCK') = %s" % SC_CLK_TCK)
except Exception:
pass
# FIXME: remove these info, used for debug purpose (issue #20452)
def data_file(filename): def data_file(filename):
if hasattr(support, 'TEST_HOME_DIR'): if hasattr(support, 'TEST_HOME_DIR'):
@ -1157,11 +1166,6 @@ class EventLoopTestsMixin:
w.close() w.close()
def test_timeout_rounding(self): def test_timeout_rounding(self):
# FIXME: remove this imports, used for debug purpose (issue #20452)
import time
import platform
import os
def _run_once(): def _run_once():
self.loop._run_once_counter += 1 self.loop._run_once_counter += 1
orig_run_once() orig_run_once()
@ -1182,17 +1186,10 @@ class EventLoopTestsMixin:
self.loop.run_until_complete(wait()) self.loop.run_until_complete(wait())
calls.append(self.loop._run_once_counter) calls.append(self.loop._run_once_counter)
try:
SC_CLK_TCK = os.sysconf('SC_CLK_TCK')
except Exception:
SC_CLK_TCK = None
self.assertEqual(calls, [1, 3, 5, 6], self.assertEqual(calls, [1, 3, 5, 6],
# FIXME: remove these info, used for debug purpose (issue #20452) # FIXME: remove these info, used for debug purpose (issue #20452)
(self.loop._granularity, (self.loop._granularity,
self.loop._selector.resolution, self.loop._selector.resolution))
time.get_clock_info('monotonic'),
SC_CLK_TCK,
platform.platform()))
class SubprocessTestsMixin: class SubprocessTestsMixin:

View File

@ -1458,7 +1458,9 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
else { else {
timeout = (int)(dtimeout * 1000.0); /* epoll_wait() has a resolution of 1 millisecond, round away from zero
to wait *at least* dtimeout seconds. */
timeout = (int)ceil(dtimeout * 1000.0);
} }
if (maxevents == -1) { if (maxevents == -1) {