Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bf88016
Add fast path for single-argument range
eendebakpt Mar 7, 2024
f4d1162
Merge branch 'main' into fast_range_v2
eendebakpt Mar 7, 2024
8973518
📜🤖 Added by blurb_it.
blurb-it[bot] Mar 7, 2024
24d9b9a
Update Misc/NEWS.d/next/Core and Builtins/2024-03-07-22-38-07.gh-issu…
eendebakpt Mar 8, 2024
cbbf211
whitespace
eendebakpt Mar 8, 2024
b59002c
Merge branch 'main' into fast_range_v2
eendebakpt Mar 8, 2024
b26893b
Update Objects/rangeobject.c
eendebakpt Mar 8, 2024
a110276
Apply suggestions from code review
eendebakpt Mar 8, 2024
602501b
Merge branch 'main' into fast_range_v2
eendebakpt Mar 9, 2024
1014c0f
Merge branch 'main' into fast_range_v2
eendebakpt Mar 18, 2024
cbf8cab
Merge branch 'main' into fast_range_v2
eendebakpt Mar 18, 2024
7462d77
Update Objects/rangeobject.c
eendebakpt Apr 4, 2024
70f6f74
Merge branch 'main' into fast_range_v2
eendebakpt Apr 4, 2024
05780ea
Merge branch 'main' into fast_range_v2
eendebakpt Apr 20, 2024
2c2ae84
Merge branch 'main' into fast_range_v2
eendebakpt May 16, 2024
f1f9bd6
Update Objects/rangeobject.c
eendebakpt May 23, 2024
48da228
Merge branch 'main' into fast_range_v2
eendebakpt May 26, 2024
73eed5d
Merge branch 'main' into fast_range_v2
eendebakpt May 28, 2024
f389fb4
Merge branch 'main' into fast_range_v2
eendebakpt Jun 10, 2024
a28e2dc
Merge branch 'main' into fast_range_v2
eendebakpt Jul 11, 2024
903c7ab
revert iter optimization
eendebakpt Jun 10, 2024
732a90b
update news entry
eendebakpt Jul 11, 2024
7696583
Merge branch 'main' into fast_range_v2
eendebakpt Aug 16, 2024
f619889
Merge branch 'main' into fast_range_v2
eendebakpt Jan 8, 2025
565d1d8
Merge branch 'main' into fast_range_v2
eendebakpt Feb 10, 2025
7b1e6f9
lint
eendebakpt Feb 11, 2025
7d2428e
Merge branch 'main' into fast_range_v2
eendebakpt Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Speed up the :class:`range` object constructor and the :class:`!range`
iterator constructor in the case of a single argument.
22 changes: 18 additions & 4 deletions Objects/rangeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ compute_range_length(PyObject *start, PyObject *stop, PyObject *step)
assert(PyLong_Check(stop));
assert(PyLong_Check(step));

/* fast path for one argument case of range */
if (start == zero && step == one) {
if (_PyLong_IsPositive((const PyLongObject *)stop)) {
return Py_NewRef(stop);
}
return zero;
}

/* fast path when all arguments fit into a long integer */
long len = compute_range_length_long(start, stop, step);
if (len >= 0) {
Expand Down Expand Up @@ -1135,13 +1143,19 @@ range_iter(PyObject *seq)

/* If all three fields and the length convert to long, use the int
* version */
lstart = PyLong_AsLong(r->start);
if (lstart == -1 && PyErr_Occurred()) {
lstop = PyLong_AsLong(r->stop);
if (lstop == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
lstop = PyLong_AsLong(r->stop);
if (lstop == -1 && PyErr_Occurred()) {

if (r->start == _PyLong_GetZero() && r->step == _PyLong_GetOne() ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How large is overhead of two PyLong_AsLong() calls for 0 and 1? Is it noticeable?

Run something like:

./python -m timeit -s 'r = range(10)' 'for i in r: break'

AFAIK it is the fastest code that is affected by the iterator creation time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overhead for the two PyLong_AsLong calls (plus some bits and pieces) are from the first benchmark above:

range(1): Mean +- std dev: [main_pgo] 44.4 ns +- 1.0 ns -> [pr_pgo] 34.7 ns +- 4.0 ns: 1.28x faster

So about 10 ns.

The last benchmark from the first comment:

for loop: Mean +- std dev: [main_pgo] 295 ns +- 9 ns -> [pr_pgo] 267 ns +- 5 ns: 1.10x faster

executes:

def g():
    x=0
    for ii in range(10):
        x += 1

So a small for loop with minimal work becomes 10% faster. (timings may vary, my system is noisy)

/* fast path for one argument range */
return fast_range_iter(0, lstop, 1, Py_MAX(0, lstop));
}

lstart = PyLong_AsLong(r->start);
if (lstart == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
Expand Down