summaryrefslogtreecommitdiff
path: root/Lib/timeit.py
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2017-02-04 16:46:53 -0800
committerSteve Dower <steve.dower@microsoft.com>2017-02-04 16:46:53 -0800
commitb1a1742796fce8078f9f1f3d5e3161122fae3b0a (patch)
tree89c863764481b7c7fbe645be42b16e1d35e92751 /Lib/timeit.py
parent391ed6c73cb1964b57d0b538370a76d03d30511b (diff)
parentcf1f5444eb42a8dc252b295d3863288309996a5d (diff)
downloadcpython-b1a1742796fce8078f9f1f3d5e3161122fae3b0a.tar.gz
Merge from 3.6
Diffstat (limited to 'Lib/timeit.py')
-rw-r--r--Lib/timeit.py110
1 files changed, 61 insertions, 49 deletions
diff --git a/Lib/timeit.py b/Lib/timeit.py
index 2770efa35a..38c2b1f061 100644
--- a/Lib/timeit.py
+++ b/Lib/timeit.py
@@ -9,7 +9,7 @@ the Python Cookbook, published by O'Reilly.
Library usage: see the Timer class.
Command line usage:
- python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-p] [-h] [--] [statement]
+ python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement]
Options:
-n/--number N: how many times to execute 'statement' (default: see below)
@@ -17,10 +17,8 @@ Options:
-s/--setup S: statement to be executed once initially (default 'pass').
Execution time of this setup statement is NOT timed.
-p/--process: use time.process_time() (default is time.perf_counter())
- -t/--time: use time.time() (deprecated)
- -c/--clock: use time.clock() (deprecated)
-v/--verbose: print raw timing results; repeat for more digits precision
- -u/--unit: set the output time unit (usec, msec, or sec)
+ -u/--unit: set the output time unit (nsec, usec, msec, or sec)
-h/--help: print this usage message and exit
--: separate options from statement, use when statement starts with -
statement: statement to be timed (default 'pass')
@@ -59,7 +57,7 @@ __all__ = ["Timer", "timeit", "repeat", "default_timer"]
dummy_src_name = "<timeit-src>"
default_number = 1000000
-default_repeat = 3
+default_repeat = 5
default_timer = time.perf_counter
_globals = globals
@@ -210,22 +208,23 @@ class Timer:
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)``.
+ Calls the timeit method with increasing numbers from the sequence
+ 1, 2, 5, 10, 20, 50, ... until the time taken is at least 0.2
+ second. 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)
+ i = 1
+ while True:
+ for j in 1, 2, 5:
+ number = i * j
+ time_taken = self.timeit(number)
+ if callback:
+ callback(number, time_taken)
+ if time_taken >= 0.2:
+ return (number, time_taken)
+ i *= 10
def timeit(stmt="pass", setup="pass", timer=default_timer,
number=default_number, globals=None):
@@ -266,6 +265,7 @@ def main(args=None, *, _wrap_timer=None):
print(err)
print("use -h/--help for command line help")
return 2
+
timer = default_timer
stmt = "\n".join(args) or "pass"
number = 0 # auto-determine
@@ -273,7 +273,7 @@ def main(args=None, *, _wrap_timer=None):
repeat = default_repeat
verbose = 0
time_unit = None
- units = {"usec": 1, "msec": 1e3, "sec": 1e6}
+ units = {"nsec": 1e-9, "usec": 1e-6, "msec": 1e-3, "sec": 1.0}
precision = 3
for o, a in opts:
if o in ("-n", "--number"):
@@ -284,17 +284,13 @@ def main(args=None, *, _wrap_timer=None):
if a in units:
time_unit = a
else:
- print("Unrecognized unit. Please select usec, msec, or sec.",
+ print("Unrecognized unit. Please select nsec, usec, msec, or sec.",
file=sys.stderr)
return 2
if o in ("-r", "--repeat"):
repeat = int(a)
if repeat <= 0:
repeat = 1
- if o in ("-t", "--time"):
- timer = time.time
- if o in ("-c", "--clock"):
- timer = time.clock
if o in ("-p", "--process"):
timer = time.process_time
if o in ("-v", "--verbose"):
@@ -305,6 +301,7 @@ def main(args=None, *, _wrap_timer=None):
print(__doc__, end=' ')
return 0
setup = "\n".join(setup) or "pass"
+
# Include the current directory, so that local imports work (sys.path
# contains the directory of this script, rather than the current
# directory)
@@ -312,50 +309,65 @@ def main(args=None, *, _wrap_timer=None):
sys.path.insert(0, os.curdir)
if _wrap_timer is not None:
timer = _wrap_timer(timer)
+
t = Timer(stmt, setup, timer)
if number == 0:
# determine number so that 0.2 <= total time < 2.0
callback = None
if verbose:
def callback(number, time_taken):
- msg = "{num} loops -> {secs:.{prec}g} secs"
- print(msg.format(num=number, secs=time_taken, prec=precision))
+ msg = "{num} loop{s} -> {secs:.{prec}g} secs"
+ plural = (number != 1)
+ print(msg.format(num=number, s='s' if plural else '',
+ secs=time_taken, prec=precision))
try:
number, _ = t.autorange(callback)
except:
t.print_exc()
return 1
+
+ if verbose:
+ print()
+
try:
- r = t.repeat(repeat, number)
+ raw_timings = t.repeat(repeat, number)
except:
t.print_exc()
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:
- print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
- print("%d loops," % number, end=' ')
- usec = best * 1e6 / number
- if time_unit is not None:
- scale = units[time_unit]
- else:
- scales = [(scale, unit) for unit, scale in units.items()]
- scales.sort(reverse=True)
- for scale, time_unit in scales:
- if usec >= scale:
- break
- print("best of %d: %.*g %s per loop" % (repeat, precision,
- usec/scale, time_unit))
- best = min(r)
- usec = best * 1e6 / number
- worst = max(r)
+ print("raw times: %s" % ", ".join(map(format_time, raw_timings)))
+ print()
+ timings = [dt / number for dt in raw_timings]
+
+ best = min(timings)
+ print("%d loop%s, best of %d: %s per loop"
+ % (number, 's' if number != 1 else '',
+ repeat, format_time(best)))
+
+ best = min(timings)
+ worst = max(timings)
if worst >= best * 4:
- usec = worst * 1e6 / number
import warnings
- warnings.warn_explicit(
- "The test results are likely unreliable. The worst\n"
- "time (%.*g %s) was more than four times slower than the best time." %
- (precision, usec/scale, time_unit),
- UserWarning, '', 0)
+ warnings.warn_explicit("The test results are likely unreliable. "
+ "The worst time (%s) was more than four times "
+ "slower than the best time (%s)."
+ % (format_time(worst), format_time(best)),
+ UserWarning, '', 0)
return None
if __name__ == "__main__":