Skip to content

Commit 302dbc6

Browse files
committed
Issue #18983: Allow selection of output units in timeit.
This allows manual selection of a specific unit such as usecs rather than the use of a heuristic. This is intended to aid machine processing of timeit output. Patch by Serhiy Storchaka.
1 parent f024d26 commit 302dbc6

4 files changed

Lines changed: 55 additions & 10 deletions

File tree

Doc/library/timeit.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ Command-Line Interface
179179

180180
When called as a program from the command line, the following form is used::
181181

182-
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
182+
python -m timeit [-n N] [-r N] [-u U] [-s S] [-t] [-c] [-h] [statement ...]
183183

184184
Where the following options are understood:
185185

@@ -208,6 +208,12 @@ Where the following options are understood:
208208

209209
use :func:`time.time` (deprecated)
210210

211+
.. cmdoption:: -u, --unit=U
212+
213+
specify a time unit for timer output; can select usec, msec, or sec
214+
215+
.. versionadded:: 3.5
216+
211217
.. cmdoption:: -c, --clock
212218

213219
use :func:`time.clock` (deprecated)

Lib/test/test_timeit.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,26 @@ def test_main_very_verbose(self):
312312
10000 loops, best of 3: 50 usec per loop
313313
"""))
314314

315+
def test_main_with_time_unit(self):
316+
unit_sec = self.run_main(seconds_per_increment=0.002,
317+
switches=['-u', 'sec'])
318+
self.assertEqual(unit_sec,
319+
"1000 loops, best of 3: 0.002 sec per loop\n")
320+
unit_msec = self.run_main(seconds_per_increment=0.002,
321+
switches=['-u', 'msec'])
322+
self.assertEqual(unit_msec,
323+
"1000 loops, best of 3: 2 msec per loop\n")
324+
unit_usec = self.run_main(seconds_per_increment=0.002,
325+
switches=['-u', 'usec'])
326+
self.assertEqual(unit_usec,
327+
"1000 loops, best of 3: 2e+03 usec per loop\n")
328+
# Test invalid unit input
329+
with captured_stderr() as error_stringio:
330+
invalid = self.run_main(seconds_per_increment=0.002,
331+
switches=['-u', 'parsec'])
332+
self.assertEqual(error_stringio.getvalue(),
333+
"Unrecognized unit. Please select usec, msec, or sec.\n")
334+
315335
def test_main_exception(self):
316336
with captured_stderr() as error_stringio:
317337
s = self.run_main(switches=['1/0'])

Lib/timeit.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-t/--time: use time.time() (deprecated)
2020
-c/--clock: use time.clock() (deprecated)
2121
-v/--verbose: print raw timing results; repeat for more digits precision
22+
-u/--unit: set the output time unit (usec, msec, or sec)
2223
-h/--help: print this usage message and exit
2324
--: separate options from statement, use when statement starts with -
2425
statement: statement to be timed (default 'pass')
@@ -250,10 +251,10 @@ def main(args=None, *, _wrap_timer=None):
250251
args = sys.argv[1:]
251252
import getopt
252253
try:
253-
opts, args = getopt.getopt(args, "n:s:r:tcpvh",
254+
opts, args = getopt.getopt(args, "n:u:s:r:tcpvh",
254255
["number=", "setup=", "repeat=",
255256
"time", "clock", "process",
256-
"verbose", "help"])
257+
"verbose", "unit=", "help"])
257258
except getopt.error as err:
258259
print(err)
259260
print("use -h/--help for command line help")
@@ -264,12 +265,21 @@ def main(args=None, *, _wrap_timer=None):
264265
setup = []
265266
repeat = default_repeat
266267
verbose = 0
268+
time_unit = None
269+
units = {"usec": 1, "msec": 1e3, "sec": 1e6}
267270
precision = 3
268271
for o, a in opts:
269272
if o in ("-n", "--number"):
270273
number = int(a)
271274
if o in ("-s", "--setup"):
272275
setup.append(a)
276+
if o in ("-u", "--unit"):
277+
if a in units:
278+
time_unit = a
279+
else:
280+
print("Unrecognized unit. Please select usec, msec, or sec.",
281+
file=sys.stderr)
282+
return 2
273283
if o in ("-r", "--repeat"):
274284
repeat = int(a)
275285
if repeat <= 0:
@@ -319,15 +329,21 @@ def main(args=None, *, _wrap_timer=None):
319329
print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
320330
print("%d loops," % number, end=' ')
321331
usec = best * 1e6 / number
322-
if usec < 1000:
323-
print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
332+
if time_unit is not None:
333+
print("best of %d: %.*g %s per loop" % (repeat, precision,
334+
usec/units[time_unit], time_unit))
324335
else:
325-
msec = usec / 1000
326-
if msec < 1000:
327-
print("best of %d: %.*g msec per loop" % (repeat, precision, msec))
336+
if usec < 1000:
337+
print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
328338
else:
329-
sec = msec / 1000
330-
print("best of %d: %.*g sec per loop" % (repeat, precision, sec))
339+
msec = usec / 1000
340+
if msec < 1000:
341+
print("best of %d: %.*g msec per loop" % (repeat,
342+
precision, msec))
343+
else:
344+
sec = msec / 1000
345+
print("best of %d: %.*g sec per loop" % (repeat,
346+
precision, sec))
331347
return None
332348

333349
if __name__ == "__main__":

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Core and Builtins
1818
Library
1919
-------
2020

21+
- Issue #18983: Allow selection of output units in timeit.
22+
Patch by Serhiy Storchaka.
23+
2124
- Issue #23631: Fix traceback.format_list when a traceback has been mutated.
2225

2326
- Issue #23568: Add rdivmod support to MagicMock() objects.

0 commit comments

Comments
 (0)