-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-82088: Improve performance of PyLong_As*() for multi-digit ints #135585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Objects/longobject.c
Outdated
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1)); | ||
x = digits[i]; | ||
|
||
#if ((ULONG_MAX >> PyLong_SHIFT)) >= ((1UL << PyLong_SHIFT) - 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also unroll the second digit for the other methods. It gains a bit of performance at the cost of a bit of extra code. The unrolling can be factored out to a helper function (the loop itself is not so easy because there are small differences in how to handle the overflow)
Co-authored-by: Victor Stinner <vstinner@python.org>
I rewrote the benchmark using pyperf: import pyperf
from struct import Struct
N = 1000
runner = pyperf.Runner()
values = tuple(range(2**30, 2**30 + N))
for key in 'nNlL':
pack = Struct(key*N).pack
runner.bench_func(f'pack {key}', pack, *values) Result:
|
@@ -0,0 +1 @@ | |||
Improve performance of ``PyLongObject`` conversion method ``PyLong_AsLongAndOverflow``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should mention other modified functions:
Make the following functions 1.3x faster for integer larger than 2**30
:
- PyLong_AsLongAndOverflow(),
- PyLong_AsSsize_t(),
- PyLong_AsUnsignedLong(),
- PyLong_AsSize_t(),
- PyLong_AsUnsignedLongMask(),
- PyLong_AsUnsignedLongLongMask(),
- PyLong_AsLongLongAndOverflow().
Co-authored-by: Victor Stinner <vstinner@python.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I have two last minor suggestions.
@serhiy-storchaka: Would you mind to double check that the integer overflow checks are correct?
Replace:
prev = x;
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
if ((x >> PyLong_SHIFT) != prev) ...
with:
if (x > (ULONG_MAX >> PyLong_SHIFT)) ...
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-08-37-45.gh-issue-82088.TgPvLg.rst
Outdated
Show resolved
Hide resolved
Co-authored-by: Victor Stinner <vstinner@python.org>
This is a continuation of the work in #15363 by @sir-sigurd.
Performance is improved by
Performance: main
PR
Script:
(performance gain is similar to earlier reported improvements)