timeit: start autorange with 1 iteration, not 10
Issue #28240: timeit autorange now uses a single loop iteration if the benchmark takes less than 10 seconds, instead of 10 iterations. "python3 -m timeit -s 'import time' 'time.sleep(1)'" now takes 4 seconds instead of 40 seconds.
This commit is contained in:
parent
bf9655854b
commit
f8fb82cd25
@ -226,7 +226,7 @@ class TestTimeit(unittest.TestCase):
|
|||||||
t.print_exc(s)
|
t.print_exc(s)
|
||||||
self.assert_exc_string(s.getvalue(), 'ZeroDivisionError')
|
self.assert_exc_string(s.getvalue(), 'ZeroDivisionError')
|
||||||
|
|
||||||
MAIN_DEFAULT_OUTPUT = "10 loops, best of 3: 1 sec per loop\n"
|
MAIN_DEFAULT_OUTPUT = "1 loop, best of 3: 1 sec per loop\n"
|
||||||
|
|
||||||
def run_main(self, seconds_per_increment=1.0, switches=None, timer=None):
|
def run_main(self, seconds_per_increment=1.0, switches=None, timer=None):
|
||||||
if timer is None:
|
if timer is None:
|
||||||
@ -252,7 +252,7 @@ class TestTimeit(unittest.TestCase):
|
|||||||
|
|
||||||
def test_main_seconds(self):
|
def test_main_seconds(self):
|
||||||
s = self.run_main(seconds_per_increment=5.5)
|
s = self.run_main(seconds_per_increment=5.5)
|
||||||
self.assertEqual(s, "10 loops, best of 3: 5.5 sec per loop\n")
|
self.assertEqual(s, "1 loop, best of 3: 5.5 sec per loop\n")
|
||||||
|
|
||||||
def test_main_milliseconds(self):
|
def test_main_milliseconds(self):
|
||||||
s = self.run_main(seconds_per_increment=0.0055)
|
s = self.run_main(seconds_per_increment=0.0055)
|
||||||
@ -280,11 +280,11 @@ class TestTimeit(unittest.TestCase):
|
|||||||
|
|
||||||
def test_main_fixed_reps(self):
|
def test_main_fixed_reps(self):
|
||||||
s = self.run_main(seconds_per_increment=60.0, switches=['-r9'])
|
s = self.run_main(seconds_per_increment=60.0, switches=['-r9'])
|
||||||
self.assertEqual(s, "10 loops, best of 9: 60 sec per loop\n")
|
self.assertEqual(s, "1 loop, best of 9: 60 sec per loop\n")
|
||||||
|
|
||||||
def test_main_negative_reps(self):
|
def test_main_negative_reps(self):
|
||||||
s = self.run_main(seconds_per_increment=60.0, switches=['-r-5'])
|
s = self.run_main(seconds_per_increment=60.0, switches=['-r-5'])
|
||||||
self.assertEqual(s, "10 loops, best of 1: 60 sec per loop\n")
|
self.assertEqual(s, "1 loop, best of 1: 60 sec per loop\n")
|
||||||
|
|
||||||
@unittest.skipIf(sys.flags.optimize >= 2, "need __doc__")
|
@unittest.skipIf(sys.flags.optimize >= 2, "need __doc__")
|
||||||
def test_main_help(self):
|
def test_main_help(self):
|
||||||
@ -308,14 +308,15 @@ class TestTimeit(unittest.TestCase):
|
|||||||
def test_main_verbose(self):
|
def test_main_verbose(self):
|
||||||
s = self.run_main(switches=['-v'])
|
s = self.run_main(switches=['-v'])
|
||||||
self.assertEqual(s, dedent("""\
|
self.assertEqual(s, dedent("""\
|
||||||
10 loops -> 10 secs
|
1 loop -> 1 secs
|
||||||
raw times: 10 10 10
|
raw times: 1 1 1
|
||||||
10 loops, best of 3: 1 sec per loop
|
1 loop, best of 3: 1 sec per loop
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
def test_main_very_verbose(self):
|
def test_main_very_verbose(self):
|
||||||
s = self.run_main(seconds_per_increment=0.000050, switches=['-vv'])
|
s = self.run_main(seconds_per_increment=0.000050, switches=['-vv'])
|
||||||
self.assertEqual(s, dedent("""\
|
self.assertEqual(s, dedent("""\
|
||||||
|
1 loop -> 5e-05 secs
|
||||||
10 loops -> 0.0005 secs
|
10 loops -> 0.0005 secs
|
||||||
100 loops -> 0.005 secs
|
100 loops -> 0.005 secs
|
||||||
1000 loops -> 0.05 secs
|
1000 loops -> 0.05 secs
|
||||||
@ -328,15 +329,15 @@ class TestTimeit(unittest.TestCase):
|
|||||||
unit_sec = self.run_main(seconds_per_increment=0.002,
|
unit_sec = self.run_main(seconds_per_increment=0.002,
|
||||||
switches=['-u', 'sec'])
|
switches=['-u', 'sec'])
|
||||||
self.assertEqual(unit_sec,
|
self.assertEqual(unit_sec,
|
||||||
"1000 loops, best of 3: 0.002 sec per loop\n")
|
"100 loops, best of 3: 0.002 sec per loop\n")
|
||||||
unit_msec = self.run_main(seconds_per_increment=0.002,
|
unit_msec = self.run_main(seconds_per_increment=0.002,
|
||||||
switches=['-u', 'msec'])
|
switches=['-u', 'msec'])
|
||||||
self.assertEqual(unit_msec,
|
self.assertEqual(unit_msec,
|
||||||
"1000 loops, best of 3: 2 msec per loop\n")
|
"100 loops, best of 3: 2 msec per loop\n")
|
||||||
unit_usec = self.run_main(seconds_per_increment=0.002,
|
unit_usec = self.run_main(seconds_per_increment=0.002,
|
||||||
switches=['-u', 'usec'])
|
switches=['-u', 'usec'])
|
||||||
self.assertEqual(unit_usec,
|
self.assertEqual(unit_usec,
|
||||||
"1000 loops, best of 3: 2e+03 usec per loop\n")
|
"100 loops, best of 3: 2e+03 usec per loop\n")
|
||||||
# Test invalid unit input
|
# Test invalid unit input
|
||||||
with captured_stderr() as error_stringio:
|
with captured_stderr() as error_stringio:
|
||||||
invalid = self.run_main(seconds_per_increment=0.002,
|
invalid = self.run_main(seconds_per_increment=0.002,
|
||||||
@ -354,8 +355,8 @@ class TestTimeit(unittest.TestCase):
|
|||||||
s = self.run_main(switches=['-n1', '1/0'])
|
s = self.run_main(switches=['-n1', '1/0'])
|
||||||
self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
|
self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
|
||||||
|
|
||||||
def autorange(self, callback=None):
|
def autorange(self, seconds_per_increment=0.001, callback=None):
|
||||||
timer = FakeTimer(seconds_per_increment=0.001)
|
timer = FakeTimer(seconds_per_increment=seconds_per_increment)
|
||||||
t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)
|
t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)
|
||||||
return t.autorange(callback)
|
return t.autorange(callback)
|
||||||
|
|
||||||
@ -364,14 +365,20 @@ class TestTimeit(unittest.TestCase):
|
|||||||
self.assertEqual(num_loops, 1000)
|
self.assertEqual(num_loops, 1000)
|
||||||
self.assertEqual(time_taken, 1.0)
|
self.assertEqual(time_taken, 1.0)
|
||||||
|
|
||||||
|
def test_autorange_second(self):
|
||||||
|
num_loops, time_taken = self.autorange(seconds_per_increment=1.0)
|
||||||
|
self.assertEqual(num_loops, 1)
|
||||||
|
self.assertEqual(time_taken, 1.0)
|
||||||
|
|
||||||
def test_autorange_with_callback(self):
|
def test_autorange_with_callback(self):
|
||||||
def callback(a, b):
|
def callback(a, b):
|
||||||
print("{} {:.3f}".format(a, b))
|
print("{} {:.3f}".format(a, b))
|
||||||
with captured_stdout() as s:
|
with captured_stdout() as s:
|
||||||
num_loops, time_taken = self.autorange(callback)
|
num_loops, time_taken = self.autorange(callback=callback)
|
||||||
self.assertEqual(num_loops, 1000)
|
self.assertEqual(num_loops, 1000)
|
||||||
self.assertEqual(time_taken, 1.0)
|
self.assertEqual(time_taken, 1.0)
|
||||||
expected = ('10 0.010\n'
|
expected = ('1 0.001\n'
|
||||||
|
'10 0.010\n'
|
||||||
'100 0.100\n'
|
'100 0.100\n'
|
||||||
'1000 1.000\n')
|
'1000 1.000\n')
|
||||||
self.assertEqual(s.getvalue(), expected)
|
self.assertEqual(s.getvalue(), expected)
|
||||||
|
@ -218,7 +218,7 @@ class Timer:
|
|||||||
If *callback* is given and is not None, it will be called after
|
If *callback* is given and is not None, it will be called after
|
||||||
each trial with two arguments: ``callback(number, time_taken)``.
|
each trial with two arguments: ``callback(number, time_taken)``.
|
||||||
"""
|
"""
|
||||||
for i in range(1, 10):
|
for i in range(0, 10):
|
||||||
number = 10**i
|
number = 10**i
|
||||||
time_taken = self.timeit(number)
|
time_taken = self.timeit(number)
|
||||||
if callback:
|
if callback:
|
||||||
@ -318,8 +318,10 @@ def main(args=None, *, _wrap_timer=None):
|
|||||||
callback = None
|
callback = None
|
||||||
if verbose:
|
if verbose:
|
||||||
def callback(number, time_taken):
|
def callback(number, time_taken):
|
||||||
msg = "{num} loops -> {secs:.{prec}g} secs"
|
msg = "{num} loop{s} -> {secs:.{prec}g} secs"
|
||||||
print(msg.format(num=number, secs=time_taken, prec=precision))
|
plural = (number != 1)
|
||||||
|
print(msg.format(num=number, s='s' if plural else '',
|
||||||
|
secs=time_taken, prec=precision))
|
||||||
try:
|
try:
|
||||||
number, _ = t.autorange(callback)
|
number, _ = t.autorange(callback)
|
||||||
except:
|
except:
|
||||||
@ -333,7 +335,7 @@ def main(args=None, *, _wrap_timer=None):
|
|||||||
best = min(r)
|
best = min(r)
|
||||||
if verbose:
|
if verbose:
|
||||||
print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
|
print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
|
||||||
print("%d loops," % number, end=' ')
|
print("%d loop%s," % (number, 's' if number != 1 else ''), end=' ')
|
||||||
usec = best * 1e6 / number
|
usec = best * 1e6 / number
|
||||||
if time_unit is not None:
|
if time_unit is not None:
|
||||||
scale = units[time_unit]
|
scale = units[time_unit]
|
||||||
|
@ -88,6 +88,11 @@ Core and Builtins
|
|||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #28240: timeit autorange now uses a single loop iteration if the
|
||||||
|
benchmark takes less than 10 seconds, instead of 10 iterations.
|
||||||
|
"python3 -m timeit -s 'import time' 'time.sleep(1)'" now takes 4 seconds
|
||||||
|
instead of 40 seconds.
|
||||||
|
|
||||||
- Distutils.sdist now looks for README and setup.py files with case
|
- Distutils.sdist now looks for README and setup.py files with case
|
||||||
sensitivity. This behavior matches that found in Setuptools 6.0 and
|
sensitivity. This behavior matches that found in Setuptools 6.0 and
|
||||||
later. See `setuptools 100
|
later. See `setuptools 100
|
||||||
|
Loading…
x
Reference in New Issue
Block a user