timeit: enhance format of raw timings (in verbose mode)

Issue #28240.
This commit is contained in:
Victor Stinner 2016-10-18 17:56:42 +02:00
parent 3d7feb9ac2
commit 61de57f175
2 changed files with 40 additions and 27 deletions

View file

@ -297,7 +297,7 @@ class TestTimeit(unittest.TestCase):
s = self.run_main(switches=['-v']) s = self.run_main(switches=['-v'])
self.assertEqual(s, dedent("""\ self.assertEqual(s, dedent("""\
1 loop -> 1 secs 1 loop -> 1 secs
raw times: 1 1 1 1 1 raw times: 1 sec, 1 sec, 1 sec, 1 sec, 1 sec
1 loop, best of 5: 1 sec per loop 1 loop, best of 5: 1 sec per loop
""")) """))
@ -309,7 +309,7 @@ class TestTimeit(unittest.TestCase):
100 loops -> 0.005 secs 100 loops -> 0.005 secs
1000 loops -> 0.05 secs 1000 loops -> 0.05 secs
10000 loops -> 0.5 secs 10000 loops -> 0.5 secs
raw times: 0.5 0.5 0.5 0.5 0.5 raw times: 500 msec, 500 msec, 500 msec, 500 msec, 500 msec
10000 loops, best of 5: 50 usec per loop 10000 loops, best of 5: 50 usec per loop
""")) """))

View file

@ -264,6 +264,7 @@ def main(args=None, *, _wrap_timer=None):
print(err) print(err)
print("use -h/--help for command line help") print("use -h/--help for command line help")
return 2 return 2
timer = default_timer timer = default_timer
stmt = "\n".join(args) or "pass" stmt = "\n".join(args) or "pass"
number = 0 # auto-determine number = 0 # auto-determine
@ -271,7 +272,7 @@ def main(args=None, *, _wrap_timer=None):
repeat = default_repeat repeat = default_repeat
verbose = 0 verbose = 0
time_unit = None time_unit = None
units = {"usec": 1, "msec": 1e3, "sec": 1e6} units = {"usec": 1e-6, "msec": 1e-3, "sec": 1.0}
precision = 3 precision = 3
for o, a in opts: for o, a in opts:
if o in ("-n", "--number"): if o in ("-n", "--number"):
@ -299,6 +300,7 @@ def main(args=None, *, _wrap_timer=None):
print(__doc__, end=' ') print(__doc__, end=' ')
return 0 return 0
setup = "\n".join(setup) or "pass" setup = "\n".join(setup) or "pass"
# Include the current directory, so that local imports work (sys.path # Include the current directory, so that local imports work (sys.path
# contains the directory of this script, rather than the current # contains the directory of this script, rather than the current
# directory) # directory)
@ -306,6 +308,7 @@ def main(args=None, *, _wrap_timer=None):
sys.path.insert(0, os.curdir) sys.path.insert(0, os.curdir)
if _wrap_timer is not None: if _wrap_timer is not None:
timer = _wrap_timer(timer) timer = _wrap_timer(timer)
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
@ -321,37 +324,47 @@ def main(args=None, *, _wrap_timer=None):
except: except:
t.print_exc() t.print_exc()
return 1 return 1
try: try:
r = t.repeat(repeat, number) raw_timings = t.repeat(repeat, number)
except: except:
t.print_exc() t.print_exc()
return 1 return 1
best = min(r)
def format_time(dt):
unit = time_unit
if unit is not None:
scale = units[unit]
else:
scales = [(scale, unit) for unit, scale in units.items()]
scales.sort(reverse=True)
for scale, unit in scales:
if dt >= scale:
break
return "%.*g %s" % (precision, dt / scale, unit)
if verbose: if verbose:
print("raw times:", " ".join(["%.*g" % (precision, x) for x in r])) print("raw times: %s" % ", ".join(map(format_time, raw_timings)))
print("%d loop%s," % (number, 's' if number != 1 else ''), end=' ')
usec = best * 1e6 / number timings = [dt / number for dt in raw_timings]
if time_unit is not None:
scale = units[time_unit] best = min(timings)
else: print("%d loop%s, best of %d: %s per loop"
scales = [(scale, unit) for unit, scale in units.items()] % (number, 's' if number != 1 else '',
scales.sort(reverse=True) repeat, format_time(best)))
for scale, time_unit in scales:
if usec >= scale: best = min(timings)
break worst = max(timings)
print("best of %d: %.*g %s per loop" % (repeat, precision,
usec/scale, time_unit))
best = min(r)
usec = best * 1e6 / number
worst = max(r)
if worst >= best * 4: if worst >= best * 4:
usec = worst * 1e6 / number
import warnings import warnings
warnings.warn_explicit( warnings.warn_explicit("The test results are likely unreliable. "
"The test results are likely unreliable. The worst\n" "The worst time (%s) was more than four times "
"time (%.*g %s) was more than four times slower than the best time." % "slower than the best time (%s)."
(precision, usec/scale, time_unit), % (precision,
UserWarning, '', 0) format_time(worst), format_time(best)),
UserWarning, '', 0)
return None return None
if __name__ == "__main__": if __name__ == "__main__":