|
6 | 6 |
|
7 | 7 | Library usage: see the Timer class. |
8 | 8 |
|
9 | | -Command line usage: |
10 | | - python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [-t T] [--] [statement] |
11 | | -
|
12 | | -Options: |
13 | | - -n/--number N: how many times to execute 'statement' (default: see below) |
14 | | - -r/--repeat N: how many times to repeat the timer (default 5) |
15 | | - -s/--setup S: statement to be executed once initially (default 'pass'). |
16 | | - Execution time of this setup statement is NOT timed. |
17 | | - -p/--process: use time.process_time() (default is time.perf_counter()) |
18 | | - -v/--verbose: print raw timing results; repeat for more digits precision |
19 | | - -u/--unit: set the output time unit (nsec, usec, msec, or sec) |
20 | | - -t/--target-time T: if --number is 0 the code will run until it |
21 | | - takes *at least* this many seconds |
22 | | - (default: 0.2) |
23 | | - -h/--help: print this usage message and exit |
24 | | - --: separate options from statement, use when statement starts with - |
25 | | - statement: statement to be timed (default 'pass') |
26 | | -
|
27 | | -A multi-line statement may be given by specifying each line as a |
28 | | -separate argument; indented lines are possible by enclosing an |
29 | | -argument in quotes and using leading spaces. Multiple -s options are |
30 | | -treated similarly. |
31 | | -
|
32 | | -If -n is not given, a suitable number of loops is calculated by trying |
33 | | -increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the |
34 | | -total time is at least --target-time seconds. |
35 | | -
|
36 | | -Note: there is a certain baseline overhead associated with executing a |
37 | | -pass statement. It differs between versions. The code here doesn't try |
38 | | -to hide it, but you should be aware of it. The baseline overhead can be |
39 | | -measured by invoking the program without arguments. |
40 | | -
|
41 | 9 | Classes: |
42 | 10 |
|
43 | 11 | Timer |
@@ -268,62 +236,114 @@ def main(args=None, *, _wrap_timer=None): |
268 | 236 | is not None, it must be a callable that accepts a timer function |
269 | 237 | and returns another timer function (used for unit testing). |
270 | 238 | """ |
271 | | - import getopt |
| 239 | + import argparse |
272 | 240 | if args is None: |
273 | 241 | args = sys.argv[1:] |
274 | 242 | import _colorize |
275 | 243 | colorize = _colorize.can_colorize() |
276 | 244 | theme = _colorize.get_theme(force_color=colorize).timeit |
277 | 245 | reset = theme.reset |
278 | 246 |
|
| 247 | + epilog = """\ |
| 248 | +A multi-line statement may be given by specifying each line as a |
| 249 | +separate argument; indented lines are possible by enclosing an |
| 250 | +argument in quotes and using leading spaces. Multiple `-s` options are |
| 251 | +treated similarly. |
| 252 | +
|
| 253 | +If `-n` is not given, a suitable number of loops is calculated by trying |
| 254 | +increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the |
| 255 | +total time is at least `--target-time` seconds. |
| 256 | +
|
| 257 | +Note: there is a certain baseline overhead associated with executing a |
| 258 | +pass statement. It differs between versions. The code here doesn't try |
| 259 | +to hide it, but you should be aware of it. The baseline overhead can be |
| 260 | +measured by invoking the program without arguments.""" |
| 261 | + |
| 262 | + parser = argparse.ArgumentParser( |
| 263 | + prog="python -m timeit", |
| 264 | + description="""\ |
| 265 | +Tool for measuring execution time of small code snippets. |
| 266 | +
|
| 267 | +This module avoids a number of common traps for measuring execution |
| 268 | +times. See also Tim Peters' introduction to the Algorithms chapter in |
| 269 | +the Python Cookbook, published by O'Reilly. |
| 270 | +
|
| 271 | +Library usage: see the Timer class.""", |
| 272 | + epilog=epilog, |
| 273 | + formatter_class=argparse.RawDescriptionHelpFormatter, |
| 274 | + ) |
| 275 | + parser.add_argument( |
| 276 | + "-n", |
| 277 | + "--number", |
| 278 | + type=int, |
| 279 | + default=0, |
| 280 | + help="how many times to execute 'statement' (default: see below)", |
| 281 | + ) |
| 282 | + parser.add_argument( |
| 283 | + "-r", |
| 284 | + "--repeat", |
| 285 | + type=int, |
| 286 | + default=default_repeat, |
| 287 | + help="how many times to repeat the timer (default %(default)s)", |
| 288 | + ) |
| 289 | + parser.add_argument( |
| 290 | + "-s", |
| 291 | + "--setup", |
| 292 | + action="append", |
| 293 | + default=[], |
| 294 | + help="statement to be executed once initially " |
| 295 | + "(default 'pass'). Execution time of this " |
| 296 | + "setup statement is NOT timed.", |
| 297 | + ) |
| 298 | + parser.add_argument( |
| 299 | + "-p", |
| 300 | + "--process", |
| 301 | + action="store_true", |
| 302 | + help="use time.process_time() (default is time.perf_counter())", |
| 303 | + ) |
| 304 | + parser.add_argument( |
| 305 | + "-t", |
| 306 | + "--target-time", |
| 307 | + type=float, |
| 308 | + default=default_target_time, |
| 309 | + help="if --number is 0 the code will run until it takes " |
| 310 | + "at least this many seconds (default %(default)s)", |
| 311 | + ) |
| 312 | + parser.add_argument( |
| 313 | + "-v", |
| 314 | + "--verbose", |
| 315 | + action="count", |
| 316 | + default=0, |
| 317 | + help="print raw timing results; repeat for more digits precision", |
| 318 | + ) |
| 319 | + parser.add_argument( |
| 320 | + "-u", |
| 321 | + "--unit", |
| 322 | + default=None, |
| 323 | + choices=["nsec", "usec", "msec", "sec"], |
| 324 | + help="set the output time unit", |
| 325 | + ) |
| 326 | + parser.add_argument( |
| 327 | + "statement", |
| 328 | + nargs="*", |
| 329 | + default=["pass"], |
| 330 | + help="statement to be timed (default 'pass')", |
| 331 | + ) |
279 | 332 | try: |
280 | | - opts, args = getopt.getopt(args, "n:u:s:r:pt:vh", |
281 | | - ["number=", "setup=", "repeat=", |
282 | | - "process", "target-time=", |
283 | | - "verbose", "unit=", "help"]) |
284 | | - except getopt.error as err: |
285 | | - print(err) |
286 | | - print("use -h/--help for command line help") |
287 | | - return 2 |
288 | | - |
289 | | - timer = default_timer |
290 | | - stmt = "\n".join(args) or "pass" |
291 | | - number = 0 # auto-determine |
292 | | - target_time = default_target_time |
293 | | - setup = [] |
294 | | - repeat = default_repeat |
295 | | - verbose = 0 |
296 | | - time_unit = None |
| 333 | + ns = parser.parse_args(args) |
| 334 | + except SystemExit as e: |
| 335 | + return e.code |
| 336 | + |
| 337 | + timer = time.process_time if ns.process else default_timer |
| 338 | + stmt = "\n".join(ns.statement) or "pass" |
| 339 | + number = ns.number |
| 340 | + target_time = ns.target_time |
| 341 | + setup = "\n".join(ns.setup) or "pass" |
| 342 | + repeat = max(ns.repeat, 1) |
| 343 | + verbose = ns.verbose |
| 344 | + time_unit = ns.unit |
297 | 345 | units = {"nsec": 1e-9, "usec": 1e-6, "msec": 1e-3, "sec": 1.0} |
298 | | - precision = 3 |
299 | | - for o, a in opts: |
300 | | - if o in ("-n", "--number"): |
301 | | - number = int(a) |
302 | | - if o in ("-s", "--setup"): |
303 | | - setup.append(a) |
304 | | - if o in ("-u", "--unit"): |
305 | | - if a in units: |
306 | | - time_unit = a |
307 | | - else: |
308 | | - print("Unrecognized unit. Please select nsec, usec, msec, or sec.", |
309 | | - file=sys.stderr) |
310 | | - return 2 |
311 | | - if o in ("-r", "--repeat"): |
312 | | - repeat = int(a) |
313 | | - if repeat <= 0: |
314 | | - repeat = 1 |
315 | | - if o in ("-p", "--process"): |
316 | | - timer = time.process_time |
317 | | - if o in ("-t", "--target-time"): |
318 | | - target_time = float(a) |
319 | | - if o in ("-v", "--verbose"): |
320 | | - if verbose: |
321 | | - precision += 1 |
322 | | - verbose += 1 |
323 | | - if o in ("-h", "--help"): |
324 | | - print(__doc__, end="") |
325 | | - return 0 |
326 | | - setup = "\n".join(setup) or "pass" |
| 346 | + precision = 3 + max(verbose - 1, 0) |
327 | 347 |
|
328 | 348 | # Include the current directory, so that local imports work (sys.path |
329 | 349 | # contains the directory of this script, rather than the current |
|
0 commit comments