Skip to content

gh-151289: specialize shrinking int subtraction#151290

Open
KRRT7 wants to merge 2 commits into
python:mainfrom
KRRT7:wide-int-accel
Open

gh-151289: specialize shrinking int subtraction#151290
KRRT7 wants to merge 2 commits into
python:mainfrom
KRRT7:wide-int-accel

Conversation

@KRRT7

@KRRT7 KRRT7 commented Jun 10, 2026

Copy link
Copy Markdown

This narrows the old wide-int experiment down to a single targeted optimization for int subtraction.

When both operands are exact int objects, have the same sign, have the same top digit, and are 2- or 3-digit PyLongs on 30-bit builds, subtraction often produces a smaller result. This change teaches BINARY_OP_SUBTRACT_INT to specialize that case and compute the result directly, instead of falling back to the generic long subtraction path.

@bedevere-app

This comment was marked as resolved.

1 similar comment
@bedevere-app

This comment was marked as resolved.

@skirpichev skirpichev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As I said in the issue thread, I'm not sure if this worth code complications.

Other than this, few remarks:

  1. Probably, you should split this pr into several. For instance, separate freelists addition looks unrelated.
  2. I don't think you should add benchmark script to the sources. Just include this code in pr description, for example.

@KRRT7

KRRT7 commented Jun 11, 2026

Copy link
Copy Markdown
Author

For instance, separate freelists addition looks unrelated

sure, I'll revert and update the numbers, though I think @peendebak mentioned he had a independent freelist PR somewhere so I'll just drop mine entirely.

I don't think you should add benchmark script to the sources. Just include this code in pr description, for example.

sure,though it's standard practices to have a tests/benchmarks/ dir (see pytest-benchmark and projects that adopt it)

@skirpichev

Copy link
Copy Markdown
Member

Do not click the "Update branch" button without a good reason because it notifies everyone watching the PR that there are new changes, when there are not, and it uses up limited CI resources.

Comment thread Python/specialize.c Outdated
Comment thread Python/optimizer_bytecodes.c Outdated
@Fidget-Spinner

Copy link
Copy Markdown
Member

I don't see any speedup, and in fact see a significant slowdown on the bigint path:

add_compact: Mean +- std dev: [fastpath_int] 16.7 ns +- 0.0 ns -> [main_int] 16.7 ns +- 0.0 ns: 1.00x slower
add_wide: Mean +- std dev: [fastpath_int] 31.6 ns +- 0.4 ns -> [main_int] 36.7 ns +- 0.8 ns: 1.16x slower
sub_compact: Mean +- std dev: [fastpath_int] 16.7 ns +- 0.0 ns -> [main_int] 16.7 ns +- 0.0 ns: 1.00x slower
sub_wide: Mean +- std dev: [fastpath_int] 31.4 ns +- 0.5 ns -> [main_int] 37.2 ns +- 0.7 ns: 1.18x slower

Geometric mean: 1.08x slower

The benchmark scripts in the original issue is not really measuring the operation I feel, so I modified it:


import pyperf


def bench_add_compact(loops):
    a = 1
    b = 2
    it = range(loops)
    start = pyperf.perf_counter()
    for _ in it:
        a + b
    return pyperf.perf_counter() - start


def bench_add_wide(loops):
    a = 10_000_000_000
    b = 1
    it = range(loops)
    start = pyperf.perf_counter()
    for _ in it:
        a + b
    return pyperf.perf_counter() - start


def bench_sub_compact(loops):
    a = 1
    b = 2
    it = range(loops)
    start = pyperf.perf_counter()
    for _ in it:
        a + b
    return pyperf.perf_counter() - start


def bench_sub_wide(loops):
    a = 10_000_000_000
    b = 1
    it = range(loops)
    start = pyperf.perf_counter()
    for _ in it:
        a + b
    return pyperf.perf_counter() - start


def main() -> None:
    runner = pyperf.Runner()
    runner.bench_time_func("add_compact", bench_add_compact)
    runner.bench_time_func("add_wide", bench_add_wide)
    runner.bench_time_func("sub_compact", bench_sub_compact)
    runner.bench_time_func("sub_wide", bench_sub_wide)


if __name__ == "__main__":
    main()

@KRRT7

KRRT7 commented Jul 10, 2026

Copy link
Copy Markdown
Author

There’s a small bug in the benchmark script in that comment: the two subtraction cases are still doing a + b in the loop body.

def bench_sub_compact(loops):
    ...
    for _ in it:
        a + b

def bench_sub_wide(loops):
    ...
    for _ in it:
        a + b

Those should be a - b, otherwise the reported sub_* numbers are measuring addition again rather than subtraction.

@KRRT7 KRRT7 changed the title gh-151289: Add a wide int fast path for add/sub gh-151289: specialize shrinking int subtraction Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants