https://github.com/python/cpython/commit/f3b74d62698d5f0ee7dd905b8a7b9189e6ef9fce
commit: f3b74d62698d5f0ee7dd905b8a7b9189e6ef9fce
branch: main
author: Miikka Koskinen <[email protected]>
committer: hugovk <[email protected]>
date: 2026-04-03T06:47:21Z
summary:

gh-80642: timeit - make target time of autorange configurable (#140283)

Co-authored-by: Alessandro Cucci <[email protected]>
Co-authored-by: blurb-it[bot] <blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>
Co-authored-by: Bénédikt Tran <[email protected]>

files:
A Misc/NEWS.d/next/Library/2019-04-25-21-11-37.bpo-36461.TO5YyP.rst
M Doc/library/timeit.rst
M Doc/whatsnew/3.15.rst
M Lib/test/test_timeit.py
M Lib/timeit.py

diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst
index bc12061a2aeb2d..aed7e7556f6666 100644
--- a/Doc/library/timeit.rst
+++ b/Doc/library/timeit.rst
@@ -143,21 +143,24 @@ The module defines three convenience functions and a 
public class:
             timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
 
 
-   .. method:: Timer.autorange(callback=None)
+   .. method:: Timer.autorange(callback=None, target_time=None)
 
       Automatically determine how many times to call :meth:`.timeit`.
 
       This is a convenience function that calls :meth:`.timeit` repeatedly
-      so that the total time >= 0.2 second, returning the eventual
+      so that the total time >= *Timer.target_time* seconds, returning the 
eventual
       (number of loops, time taken for that number of loops). It calls
       :meth:`.timeit` with increasing numbers from the sequence 1, 2, 5,
-      10, 20, 50, ... until the time taken is at least 0.2 seconds.
+      10, 20, 50, ... until the time taken is at least *target_time* seconds.
 
       If *callback* is given and is not ``None``, it will be called after
       each trial with two arguments: ``callback(number, time_taken)``.
 
       .. versionadded:: 3.6
 
+      .. versionchanged:: next
+         The optional *target_time* parameter was added.
+
 
    .. method:: Timer.repeat(repeat=5, number=1000000)
 
@@ -239,6 +242,13 @@ Where the following options are understood:
 
    .. versionadded:: 3.5
 
+.. option:: -t, --target-time=T
+
+   if :option:`--number` is 0, the code will run until it takes at
+   least this many seconds (default: 0.2)
+
+   .. versionadded:: next
+
 .. option:: -v, --verbose
 
    print raw timing results; repeat for more digits precision
@@ -254,7 +264,7 @@ similarly.
 
 If :option:`-n` is not given, a suitable number of loops is calculated by 
trying
 increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the total
-time is at least 0.2 seconds.
+time is at least :option:`--target-time` seconds (default: 0.2).
 
 :func:`default_timer` measurements can be affected by other programs running on
 the same machine, so the best thing to do when accurate timing is necessary is
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 2a5f9c939e7280..287109035f1ee6 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -1090,6 +1090,11 @@ timeit
   :ref:`environment variables <using-on-controlling-color>`.
   (Contributed by Yi Hong in :gh:`139374`.)
 
+* Make the target time of :meth:`timeit.Timer.autorange` configurable
+  and add ``--target-time`` option to the command-line interface.
+  (Contributed by Alessandro Cucci and Miikka Koskinen in :gh:`140283`.)
+
+
 tkinter
 -------
 
diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py
index f8bc306b455a5d..8837e88ba638cf 100644
--- a/Lib/test/test_timeit.py
+++ b/Lib/test/test_timeit.py
@@ -364,10 +364,10 @@ def test_main_exception_fixed_reps(self):
             s = self.run_main(switches=['-n1', '1/0'])
         self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
 
-    def autorange(self, seconds_per_increment=1/1024, callback=None):
+    def autorange(self, seconds_per_increment=1/1024, callback=None, 
target_time=0.2):
         timer = FakeTimer(seconds_per_increment=seconds_per_increment)
         t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, 
timer=timer)
-        return t.autorange(callback)
+        return t.autorange(callback, target_time=target_time)
 
     def test_autorange(self):
         num_loops, time_taken = self.autorange()
@@ -379,6 +379,11 @@ def test_autorange_second(self):
         self.assertEqual(num_loops, 1)
         self.assertEqual(time_taken, 1.0)
 
+    def test_autorange_with_target_time(self):
+        num_loops, time_taken = self.autorange(target_time=1.0)
+        self.assertEqual(num_loops, 2000)
+        self.assertEqual(time_taken, 2000/1024)
+
     def test_autorange_with_callback(self):
         def callback(a, b):
             print("{} {:.3f}".format(a, b))
diff --git a/Lib/timeit.py b/Lib/timeit.py
index 80791acdeca23f..f900da6ffe7d67 100644
--- a/Lib/timeit.py
+++ b/Lib/timeit.py
@@ -7,7 +7,7 @@
 Library usage: see the Timer class.
 
 Command line usage:
-    python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement]
+    python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [-t T] [--] [statement]
 
 Options:
   -n/--number N: how many times to execute 'statement' (default: see below)
@@ -17,6 +17,9 @@
   -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 (nsec, usec, msec, or sec)
+  -t/--target-time T: if --number is 0 the code will run until it
+                      takes *at least* this many seconds
+                      (default: 0.2)
   -h/--help: print this usage message and exit
   --: separate options from statement, use when statement starts with -
   statement: statement to be timed (default 'pass')
@@ -28,7 +31,7 @@
 
 If -n is not given, a suitable number of loops is calculated by trying
 increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
-total time is at least 0.2 seconds.
+total time is at least --target-time seconds.
 
 Note: there is a certain baseline overhead associated with executing a
 pass statement.  It differs between versions.  The code here doesn't try
@@ -57,6 +60,7 @@
 default_number = 1000000
 default_repeat = 5
 default_timer = time.perf_counter
+default_target_time = 0.2
 
 _globals = globals
 
@@ -212,12 +216,13 @@ def repeat(self, repeat=default_repeat, 
number=default_number):
             r.append(t)
         return r
 
-    def autorange(self, callback=None):
-        """Return the number of loops and time taken so that total time >= 0.2.
+    def autorange(self, callback=None, target_time=default_target_time):
+        """Return the number of loops and time taken so that
+        total time >= target_time (default is 0.2 seconds).
 
         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).
+        1, 2, 5, 10, 20, 50, ... until the target time is reached.
+        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)``.
@@ -229,7 +234,7 @@ def autorange(self, callback=None):
                 time_taken = self.timeit(number)
                 if callback:
                     callback(number, time_taken)
-                if time_taken >= 0.2:
+                if time_taken >= target_time:
                     return (number, time_taken)
             i *= 10
 
@@ -270,9 +275,10 @@ def main(args=None, *, _wrap_timer=None):
     colorize = _colorize.can_colorize()
 
     try:
-        opts, args = getopt.getopt(args, "n:u:s:r:pvh",
+        opts, args = getopt.getopt(args, "n:u:s:r:pt:vh",
                                    ["number=", "setup=", "repeat=",
-                                    "process", "verbose", "unit=", "help"])
+                                    "process", "target-time=",
+                                    "verbose", "unit=", "help"])
     except getopt.error as err:
         print(err)
         print("use -h/--help for command line help")
@@ -281,6 +287,7 @@ def main(args=None, *, _wrap_timer=None):
     timer = default_timer
     stmt = "\n".join(args) or "pass"
     number = 0  # auto-determine
+    target_time = default_target_time
     setup = []
     repeat = default_repeat
     verbose = 0
@@ -305,6 +312,8 @@ def main(args=None, *, _wrap_timer=None):
                 repeat = 1
         if o in ("-p", "--process"):
             timer = time.process_time
+        if o in ("-t", "--target-time"):
+            target_time = float(a)
         if o in ("-v", "--verbose"):
             if verbose:
                 precision += 1
@@ -324,7 +333,7 @@ def main(args=None, *, _wrap_timer=None):
 
     t = Timer(stmt, setup, timer)
     if number == 0:
-        # determine number so that 0.2 <= total time < 2.0
+        # determine number so that total time >= target_time
         callback = None
         if verbose:
             def callback(number, time_taken):
@@ -333,7 +342,7 @@ def callback(number, time_taken):
                 print(msg.format(num=number, s='s' if plural else '',
                                  secs=time_taken, prec=precision))
         try:
-            number, _ = t.autorange(callback)
+            number, _ = t.autorange(callback, target_time)
         except:
             t.print_exc(colorize=colorize)
             return 1
diff --git a/Misc/NEWS.d/next/Library/2019-04-25-21-11-37.bpo-36461.TO5YyP.rst 
b/Misc/NEWS.d/next/Library/2019-04-25-21-11-37.bpo-36461.TO5YyP.rst
new file mode 100644
index 00000000000000..e78f66018077c2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-25-21-11-37.bpo-36461.TO5YyP.rst
@@ -0,0 +1,3 @@
+Make the target time of :meth:`timeit.Timer.autorange` configurable
+and add ``--target-time`` option to the command-line interface of
+:mod:`timeit`.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to