Skip to content
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

GH-100982: Break up COMPARE_AND_BRANCH #102801

Merged
merged 15 commits into from
Mar 23, 2023

Conversation

brandtbucher
Copy link
Member

@brandtbucher brandtbucher commented Mar 17, 2023

COMPARE_AND_BRANCH (and its specializations) are a bit weird. It's basically an "adaptive superinstruction" that's present in co_code, and its semantics and lifecycle are different from that of any other instruction. Not only can it be harder to reason about, but it also makes changes (like quickening in the compiler) more awkward.

However, it appears to be only a small improvement over COMPARE_OP. This branch replaces the COMPARE_AND_BRANCH family with a "normal" COMPARE_OP one; here are some microbenchmarks for specializations with and without conditional jumps (non-debug, non-PGO):

main:

$ ./python -m timeit -s "x = 0.0" "x == x"
20000000 loops, best of 5: 12.7 nsec per loop
$ ./python -m timeit -s "x = 0" "x == x"
20000000 loops, best of 5: 11 nsec per loop
$ ./python -m timeit -s "x = '0'" "x == x"
20000000 loops, best of 5: 11.2 nsec per loop
$ ./python -m timeit -s "x = 0.0" "None if x == x else None"
20000000 loops, best of 5: 10.8 nsec per loop
$ ./python -m timeit -s "x = 0" "None if x == x else None"
20000000 loops, best of 5: 11.4 nsec per loop
$ ./python -m timeit -s "x = '0'" "None if x == x else None"
20000000 loops, best of 5: 11.3 nsec per loop

This branch:

$ ./python -m timeit -s "x = 0.0" "x == x"
50000000 loops, best of 5: 8.76 nsec per loop
$ ./python -m timeit -s "x = 0" "x == x"
50000000 loops, best of 5: 8.89 nsec per loop
$ ./python -m timeit -s "x = '0'" "x == x"
50000000 loops, best of 5: 8.83 nsec per loop
$ ./python -m timeit -s "x = 0.0" "None if x == x else None"
20000000 loops, best of 5: 11.6 nsec per loop
$ ./python -m timeit -s "x = 0" "None if x == x else None"
20000000 loops, best of 5: 11.8 nsec per loop
$ ./python -m timeit -s "x = '0'" "None if x == x else None"
20000000 loops, best of 5: 12 nsec per loop

So COMPARE_AND_BRANCH only gets us a <1ns improvement in the (common) branching case, and it costs us about 2-4ns in the (uncommon) non-branching case. Honestly, I don't think that's enough of a win.

(Benchmarks are slightly slower, but in the noise.)

Copy link
Member

@markshannon markshannon left a comment

Choose a reason for hiding this comment

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

Looks good.

@brandtbucher brandtbucher merged commit 0444ae2 into python:main Mar 23, 2023
Fidget-Spinner pushed a commit to Fidget-Spinner/cpython that referenced this pull request Mar 27, 2023
warsaw pushed a commit to warsaw/cpython that referenced this pull request Apr 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) performance Performance or resource usage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants