From 3b78ef2a402af30a4887fb3d8d282e985ef6ae58 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:06:56 +0200 Subject: 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. --- Lib/timeit.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 2770efa35a..0040efd1d6 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -218,7 +218,7 @@ class Timer: 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): + for i in range(0, 10): number = 10**i time_taken = self.timeit(number) if callback: @@ -318,8 +318,10 @@ def main(args=None, *, _wrap_timer=None): 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: @@ -333,7 +335,7 @@ def main(args=None, *, _wrap_timer=None): best = min(r) if verbose: 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 if time_unit is not None: scale = units[time_unit] -- cgit v1.2.1 From b9f2189bd33cf6daeafb8f6ec30f64db1f1f58f0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:13:22 +0200 Subject: timeit: change default repeat to 5, instead of 3 Issue #28240: timeit now repeats the benchmarks 5 times instead of only 3 to make benchmarks more reliable. --- Lib/timeit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 0040efd1d6..d40998c77d 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -59,7 +59,7 @@ __all__ = ["Timer", "timeit", "repeat", "default_timer"] dummy_src_name = "" default_number = 1000000 -default_repeat = 3 +default_repeat = 5 default_timer = time.perf_counter _globals = globals -- cgit v1.2.1 From 707a52a156851c7d8f6ebaedb6c98ef52a756186 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:18:21 +0200 Subject: timeit: remove --clock and --time options Issue #28240: timeit: remove -c/--clock and -t/--time command line options which were deprecated since Python 3.3. --- Lib/timeit.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index d40998c77d..3395b36071 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,8 +17,6 @@ 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) -h/--help: print this usage message and exit @@ -291,10 +289,6 @@ def main(args=None, *, _wrap_timer=None): 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"): -- cgit v1.2.1 From 4dcc8647b23d484724821c14be42aa8a3c82ad7b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:56:42 +0200 Subject: timeit: enhance format of raw timings (in verbose mode) Issue #28240. --- Lib/timeit.py | 63 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 3395b36071..8bc6a9eb2d 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -264,6 +264,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 @@ -271,7 +272,7 @@ def main(args=None, *, _wrap_timer=None): repeat = default_repeat verbose = 0 time_unit = None - units = {"usec": 1, "msec": 1e3, "sec": 1e6} + units = {"usec": 1e-6, "msec": 1e-3, "sec": 1.0} precision = 3 for o, a in opts: if o in ("-n", "--number"): @@ -299,6 +300,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) @@ -306,6 +308,7 @@ 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 @@ -321,37 +324,47 @@ def main(args=None, *, _wrap_timer=None): except: t.print_exc() return 1 + 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 loop%s," % (number, 's' if number != 1 else ''), 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))) + + 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)." + % (precision, + format_time(worst), format_time(best)), + UserWarning, '', 0) return None if __name__ == "__main__": -- cgit v1.2.1 From 29560e62d585e46739ddf27f630337b1f5dc8198 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:42:48 +0200 Subject: timeit: add nsec (nanosecond) unit for format timings Issue #28240. --- Lib/timeit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 8bc6a9eb2d..23bdd02161 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -18,7 +18,7 @@ Options: Execution time of this setup statement is NOT timed. -p/--process: use time.process_time() (default is time.perf_counter()) -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') @@ -272,7 +272,7 @@ def main(args=None, *, _wrap_timer=None): repeat = default_repeat verbose = 0 time_unit = None - units = {"usec": 1e-6, "msec": 1e-3, "sec": 1.0} + 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"): @@ -283,7 +283,7 @@ 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"): -- cgit v1.2.1 From b9d91733a5faaae5acf8729175e70fd8440f546b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Oct 2016 17:55:18 +0200 Subject: timeit: add newlines to output for readability Issue #28240. --- Lib/timeit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 23bdd02161..d8112944bd 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -325,6 +325,9 @@ def main(args=None, *, _wrap_timer=None): t.print_exc() return 1 + if verbose: + print() + try: raw_timings = t.repeat(repeat, number) except: @@ -347,7 +350,7 @@ def main(args=None, *, _wrap_timer=None): if verbose: print("raw times: %s" % ", ".join(map(format_time, raw_timings))) - + print() timings = [dt / number for dt in raw_timings] best = min(timings) -- cgit v1.2.1 From 0fd3d3987c7230e5cb6079c18e9809f82174b11b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 19 Oct 2016 15:48:23 +0200 Subject: Issue #28240: Fix formatting of the warning. --- Lib/timeit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index d8112944bd..0b5061f480 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -365,8 +365,7 @@ def main(args=None, *, _wrap_timer=None): warnings.warn_explicit("The test results are likely unreliable. " "The worst time (%s) was more than four times " "slower than the best time (%s)." - % (precision, - format_time(worst), format_time(best)), + % (format_time(worst), format_time(best)), UserWarning, '', 0) return None -- cgit v1.2.1 From f1796723da117f8ffff0882333777e26fc0acb53 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Oct 2016 15:17:05 +0300 Subject: Issue #28469: timeit now uses the sequence 1, 2, 5, 10, 20, 50,... instead of 1, 10, 100,... for autoranging. --- Lib/timeit.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'Lib/timeit.py') diff --git a/Lib/timeit.py b/Lib/timeit.py index 0b5061f480..38c2b1f061 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -208,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(0, 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): -- cgit v1.2.1