mirror of https://github.com/python/cpython
Issue6422 add autorange method to timeit.Timer
This commit is contained in:
parent
9171a8b4ce
commit
09f4f711b6
|
@ -100,8 +100,8 @@ The module defines three convenience functions and a public class:
|
||||||
can be controlled by passing a namespace to *globals*.
|
can be controlled by passing a namespace to *globals*.
|
||||||
|
|
||||||
To measure the execution time of the first statement, use the :meth:`.timeit`
|
To measure the execution time of the first statement, use the :meth:`.timeit`
|
||||||
method. The :meth:`.repeat` method is a convenience to call :meth:`.timeit`
|
method. The :meth:`.repeat` and :meth:`.autorange` methods are convenience
|
||||||
multiple times and return a list of results.
|
methods to call :meth:`.timeit` multiple times.
|
||||||
|
|
||||||
The execution time of *setup* is excluded from the overall timed execution run.
|
The execution time of *setup* is excluded from the overall timed execution run.
|
||||||
|
|
||||||
|
@ -134,6 +134,21 @@ The module defines three convenience functions and a public class:
|
||||||
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
|
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Timer.autorange(callback=None)
|
||||||
|
|
||||||
|
Automatically determine how many times to call :meth:`.timeit`.
|
||||||
|
|
||||||
|
This is a convenience function that calls :meth:`.timeit` repeatedly
|
||||||
|
so that the total time >= 0.2 second, returning the eventual
|
||||||
|
(number of loops, time taken for that number of loops). It calls
|
||||||
|
:meth:`.timeit` with *number* set to successive powers of ten (10,
|
||||||
|
100, 1000, ...) up to a maximum of one billion, until the time taken
|
||||||
|
is at least 0.2 second, or the maximum is reached.
|
||||||
|
|
||||||
|
If *callback* is given and is not *None*, it will be called after
|
||||||
|
each trial with two arguments: ``callback(number, time_taken)``.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Timer.repeat(repeat=3, number=1000000)
|
.. method:: Timer.repeat(repeat=3, number=1000000)
|
||||||
|
|
||||||
Call :meth:`.timeit` a few times.
|
Call :meth:`.timeit` a few times.
|
||||||
|
|
|
@ -354,6 +354,28 @@ 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):
|
||||||
|
timer = FakeTimer(seconds_per_increment=0.001)
|
||||||
|
t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)
|
||||||
|
return t.autorange(callback)
|
||||||
|
|
||||||
|
def test_autorange(self):
|
||||||
|
num_loops, time_taken = self.autorange()
|
||||||
|
self.assertEqual(num_loops, 1000)
|
||||||
|
self.assertEqual(time_taken, 1.0)
|
||||||
|
|
||||||
|
def test_autorange_with_callback(self):
|
||||||
|
def callback(a, b):
|
||||||
|
print("{} {:.3f}".format(a, b))
|
||||||
|
with captured_stdout() as s:
|
||||||
|
num_loops, time_taken = self.autorange(callback)
|
||||||
|
self.assertEqual(num_loops, 1000)
|
||||||
|
self.assertEqual(time_taken, 1.0)
|
||||||
|
expected = ('10 0.010\n'
|
||||||
|
'100 0.100\n'
|
||||||
|
'1000 1.000\n')
|
||||||
|
self.assertEqual(s.getvalue(), expected)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -207,6 +207,26 @@ class Timer:
|
||||||
r.append(t)
|
r.append(t)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
def autorange(self, callback=None):
|
||||||
|
"""Return the number of loops so that total time >= 0.2.
|
||||||
|
|
||||||
|
Calls the timeit method with *number* set to successive powers of
|
||||||
|
ten (10, 100, 1000, ...) up to a maximum of one billion, until
|
||||||
|
the time taken is at least 0.2 second, or the maximum is reached.
|
||||||
|
Returns ``(number, time_taken)``.
|
||||||
|
|
||||||
|
If *callback* is given and is not None, it will be called after
|
||||||
|
each trial with two arguments: ``callback(number, time_taken)``.
|
||||||
|
"""
|
||||||
|
for i in range(1, 10):
|
||||||
|
number = 10**i
|
||||||
|
time_taken = self.timeit(number)
|
||||||
|
if callback:
|
||||||
|
callback(number, time_taken)
|
||||||
|
if time_taken >= 0.2:
|
||||||
|
break
|
||||||
|
return (number, time_taken)
|
||||||
|
|
||||||
def timeit(stmt="pass", setup="pass", timer=default_timer,
|
def timeit(stmt="pass", setup="pass", timer=default_timer,
|
||||||
number=default_number, globals=None):
|
number=default_number, globals=None):
|
||||||
"""Convenience function to create Timer object and call timeit method."""
|
"""Convenience function to create Timer object and call timeit method."""
|
||||||
|
@ -295,17 +315,16 @@ def main(args=None, *, _wrap_timer=None):
|
||||||
t = Timer(stmt, setup, timer)
|
t = Timer(stmt, setup, timer)
|
||||||
if number == 0:
|
if number == 0:
|
||||||
# determine number so that 0.2 <= total time < 2.0
|
# determine number so that 0.2 <= total time < 2.0
|
||||||
for i in range(1, 10):
|
callback = None
|
||||||
number = 10**i
|
if verbose:
|
||||||
try:
|
def callback(number, time_taken):
|
||||||
x = t.timeit(number)
|
msg = "{num} loops -> {secs:.{prec}g} secs"
|
||||||
except:
|
print(msg.format(num=number, secs=time_taken, prec=precision))
|
||||||
t.print_exc()
|
try:
|
||||||
return 1
|
number, _ = t.autorange(callback)
|
||||||
if verbose:
|
except:
|
||||||
print("%d loops -> %.*g secs" % (number, precision, x))
|
t.print_exc()
|
||||||
if x >= 0.2:
|
return 1
|
||||||
break
|
|
||||||
try:
|
try:
|
||||||
r = t.repeat(repeat, number)
|
r = t.repeat(repeat, number)
|
||||||
except:
|
except:
|
||||||
|
|
Loading…
Reference in New Issue