Skip to content

Commit c0d63f6

Browse files
Merge branch 'main' of https://github.com/python/cpython into jit-inline-funcptr
2 parents e10de14 + 3908593 commit c0d63f6

File tree

8 files changed

+61
-25
lines changed

8 files changed

+61
-25
lines changed

Doc/library/timeit.rst

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,24 @@ The module defines three convenience functions and a public class:
143143
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
144144

145145

146-
.. method:: Timer.autorange(callback=None)
146+
.. method:: Timer.autorange(callback=None, target_time=None)
147147

148148
Automatically determine how many times to call :meth:`.timeit`.
149149

150150
This is a convenience function that calls :meth:`.timeit` repeatedly
151-
so that the total time >= 0.2 second, returning the eventual
151+
so that the total time >= *Timer.target_time* seconds, returning the eventual
152152
(number of loops, time taken for that number of loops). It calls
153153
:meth:`.timeit` with increasing numbers from the sequence 1, 2, 5,
154-
10, 20, 50, ... until the time taken is at least 0.2 seconds.
154+
10, 20, 50, ... until the time taken is at least *target_time* seconds.
155155

156156
If *callback* is given and is not ``None``, it will be called after
157157
each trial with two arguments: ``callback(number, time_taken)``.
158158

159159
.. versionadded:: 3.6
160160

161+
.. versionchanged:: next
162+
The optional *target_time* parameter was added.
163+
161164

162165
.. method:: Timer.repeat(repeat=5, number=1000000)
163166

@@ -239,6 +242,13 @@ Where the following options are understood:
239242

240243
.. versionadded:: 3.5
241244

245+
.. option:: -t, --target-time=T
246+
247+
if :option:`--number` is 0, the code will run until it takes at
248+
least this many seconds (default: 0.2)
249+
250+
.. versionadded:: next
251+
242252
.. option:: -v, --verbose
243253

244254
print raw timing results; repeat for more digits precision
@@ -254,7 +264,7 @@ similarly.
254264

255265
If :option:`-n` is not given, a suitable number of loops is calculated by trying
256266
increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the total
257-
time is at least 0.2 seconds.
267+
time is at least :option:`--target-time` seconds (default: 0.2).
258268

259269
:func:`default_timer` measurements can be affected by other programs running on
260270
the same machine, so the best thing to do when accurate timing is necessary is

Doc/whatsnew/3.15.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,11 @@ timeit
10901090
:ref:`environment variables <using-on-controlling-color>`.
10911091
(Contributed by Yi Hong in :gh:`139374`.)
10921092

1093+
* Make the target time of :meth:`timeit.Timer.autorange` configurable
1094+
and add ``--target-time`` option to the command-line interface.
1095+
(Contributed by Alessandro Cucci and Miikka Koskinen in :gh:`140283`.)
1096+
1097+
10931098
tkinter
10941099
-------
10951100

Lib/test/test_pathlib/test_pathlib.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from test.support import infinite_recursion
2222
from test.support import os_helper
2323
from test.support import requires_root_user
24+
from test.support import requires_non_root_user
2425
from test.support.os_helper import TESTFN, FS_NONASCII, FakePath
2526
try:
2627
import fcntl
@@ -1550,7 +1551,7 @@ def raiser(*args, **kwargs):
15501551
self.assertRaises(FileNotFoundError, source.copy, target)
15511552

15521553
@unittest.skipIf(sys.platform == "win32" or sys.platform == "wasi", "directories are always readable on Windows and WASI")
1553-
@requires_root_user
1554+
@requires_non_root_user
15541555
def test_copy_dir_no_read_permission(self):
15551556
base = self.cls(self.base)
15561557
source = base / 'dirE'

Lib/test/test_timeit.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,10 @@ def test_main_exception_fixed_reps(self):
364364
s = self.run_main(switches=['-n1', '1/0'])
365365
self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
366366

367-
def autorange(self, seconds_per_increment=1/1024, callback=None):
367+
def autorange(self, seconds_per_increment=1/1024, callback=None, target_time=0.2):
368368
timer = FakeTimer(seconds_per_increment=seconds_per_increment)
369369
t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)
370-
return t.autorange(callback)
370+
return t.autorange(callback, target_time=target_time)
371371

372372
def test_autorange(self):
373373
num_loops, time_taken = self.autorange()
@@ -379,6 +379,11 @@ def test_autorange_second(self):
379379
self.assertEqual(num_loops, 1)
380380
self.assertEqual(time_taken, 1.0)
381381

382+
def test_autorange_with_target_time(self):
383+
num_loops, time_taken = self.autorange(target_time=1.0)
384+
self.assertEqual(num_loops, 2000)
385+
self.assertEqual(time_taken, 2000/1024)
386+
382387
def test_autorange_with_callback(self):
383388
def callback(a, b):
384389
print("{} {:.3f}".format(a, b))

Lib/timeit.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Library usage: see the Timer class.
88
99
Command line usage:
10-
python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement]
10+
python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [-t T] [--] [statement]
1111
1212
Options:
1313
-n/--number N: how many times to execute 'statement' (default: see below)
@@ -17,6 +17,9 @@
1717
-p/--process: use time.process_time() (default is time.perf_counter())
1818
-v/--verbose: print raw timing results; repeat for more digits precision
1919
-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)
2023
-h/--help: print this usage message and exit
2124
--: separate options from statement, use when statement starts with -
2225
statement: statement to be timed (default 'pass')
@@ -28,7 +31,7 @@
2831
2932
If -n is not given, a suitable number of loops is calculated by trying
3033
increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
31-
total time is at least 0.2 seconds.
34+
total time is at least --target-time seconds.
3235
3336
Note: there is a certain baseline overhead associated with executing a
3437
pass statement. It differs between versions. The code here doesn't try
@@ -57,6 +60,7 @@
5760
default_number = 1000000
5861
default_repeat = 5
5962
default_timer = time.perf_counter
63+
default_target_time = 0.2
6064

6165
_globals = globals
6266

@@ -212,12 +216,13 @@ def repeat(self, repeat=default_repeat, number=default_number):
212216
r.append(t)
213217
return r
214218

215-
def autorange(self, callback=None):
216-
"""Return the number of loops and time taken so that total time >= 0.2.
219+
def autorange(self, callback=None, target_time=default_target_time):
220+
"""Return the number of loops and time taken so that
221+
total time >= target_time (default is 0.2 seconds).
217222
218223
Calls the timeit method with increasing numbers from the sequence
219-
1, 2, 5, 10, 20, 50, ... until the time taken is at least 0.2
220-
second. Returns (number, time_taken).
224+
1, 2, 5, 10, 20, 50, ... until the target time is reached.
225+
Returns (number, time_taken).
221226
222227
If *callback* is given and is not None, it will be called after
223228
each trial with two arguments: ``callback(number, time_taken)``.
@@ -229,7 +234,7 @@ def autorange(self, callback=None):
229234
time_taken = self.timeit(number)
230235
if callback:
231236
callback(number, time_taken)
232-
if time_taken >= 0.2:
237+
if time_taken >= target_time:
233238
return (number, time_taken)
234239
i *= 10
235240

@@ -270,9 +275,10 @@ def main(args=None, *, _wrap_timer=None):
270275
colorize = _colorize.can_colorize()
271276

272277
try:
273-
opts, args = getopt.getopt(args, "n:u:s:r:pvh",
278+
opts, args = getopt.getopt(args, "n:u:s:r:pt:vh",
274279
["number=", "setup=", "repeat=",
275-
"process", "verbose", "unit=", "help"])
280+
"process", "target-time=",
281+
"verbose", "unit=", "help"])
276282
except getopt.error as err:
277283
print(err)
278284
print("use -h/--help for command line help")
@@ -281,6 +287,7 @@ def main(args=None, *, _wrap_timer=None):
281287
timer = default_timer
282288
stmt = "\n".join(args) or "pass"
283289
number = 0 # auto-determine
290+
target_time = default_target_time
284291
setup = []
285292
repeat = default_repeat
286293
verbose = 0
@@ -305,6 +312,8 @@ def main(args=None, *, _wrap_timer=None):
305312
repeat = 1
306313
if o in ("-p", "--process"):
307314
timer = time.process_time
315+
if o in ("-t", "--target-time"):
316+
target_time = float(a)
308317
if o in ("-v", "--verbose"):
309318
if verbose:
310319
precision += 1
@@ -324,7 +333,7 @@ def main(args=None, *, _wrap_timer=None):
324333

325334
t = Timer(stmt, setup, timer)
326335
if number == 0:
327-
# determine number so that 0.2 <= total time < 2.0
336+
# determine number so that total time >= target_time
328337
callback = None
329338
if verbose:
330339
def callback(number, time_taken):
@@ -333,7 +342,7 @@ def callback(number, time_taken):
333342
print(msg.format(num=number, s='s' if plural else '',
334343
secs=time_taken, prec=precision))
335344
try:
336-
number, _ = t.autorange(callback)
345+
number, _ = t.autorange(callback, target_time)
337346
except:
338347
t.print_exc(colorize=colorize)
339348
return 1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Make :c:func:`PySet_Contains` attempt a lock-free lookup, similar to
2+
:meth:`!set.__contains__`. This avoids acquiring the set object mutex in the
3+
normal case.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Make the target time of :meth:`timeit.Timer.autorange` configurable
2+
and add ``--target-time`` option to the command-line interface of
3+
:mod:`timeit`.

Objects/setobject.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,14 +3023,14 @@ PySet_Contains(PyObject *anyset, PyObject *key)
30233023
PyErr_BadInternalCall();
30243024
return -1;
30253025
}
3026-
if (PyFrozenSet_CheckExact(anyset)) {
3027-
return set_contains_key((PySetObject *)anyset, key);
3026+
3027+
PySetObject *so = (PySetObject *)anyset;
3028+
Py_hash_t hash = _PyObject_HashFast(key);
3029+
if (hash == -1) {
3030+
set_unhashable_type(key);
3031+
return -1;
30283032
}
3029-
int rv;
3030-
Py_BEGIN_CRITICAL_SECTION(anyset);
3031-
rv = set_contains_key((PySetObject *)anyset, key);
3032-
Py_END_CRITICAL_SECTION();
3033-
return rv;
3033+
return set_contains_entry(so, key, hash);
30343034
}
30353035

30363036
int

0 commit comments

Comments
 (0)