You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Improve performance for switch in ceval.c when using MSVC #91719
We've received reports of MSVC not generating optimal code, e.g. gh-89279.
One possible improvement would be to get the big switch statement in ceval.c to generate better code. It's been rumored that MSVC will generate essentially a computed goto if all cases are filled.
[3.12] REPORT: Efficient switch(opcode) seems to require 182 or more effective cases. Starting from e48ac9c with 179 opcodes, the switch loads indexed memory twice, not once. I expect next alpha to have a sufficient number of opcodes.
Thanks for the detailed and clear report. It sounds like in the long term we would be okay without depending on the EXTRA_CASES macro, though we might want to add a check somewhere that we have at least 182 cases. (It would be better if we could directly test for the extra memory indirection but that seems beyond our current tooling. :-)
As for performance advantage over loading memory twice, the examples above has little for me. Each of the following was faster on PGO:
Avoid falling through in EXTRA_CASES, giving each an exclusive body without default.
Use something better than Py_FatalError().
Make default case unreachable.
I'm not sure how come any of those would make a difference given that we never execute the default case. Or am I not following you?
I'm not sure why either(EDIT: improved by #94364), so I tried making a small reproducer. After trimming the cases in eval loop, INSTRUCTION_START() macro remained loading memory twice, which is not implemented in 3.10. I'd like to look into after new opcodes are introduced into 3.12.
Activity
GH-91719: Make MSVC generate somewhat faster switch code (#91718)
gvanrossum commentedon Apr 23, 2022
Fixed by #91718.
gh-91719: Add pycore_opcode.h internal header file (#91906)
gh-91719: Mark pycore_opcode.h as generated in .gitattributes (#91976)
neonene commentedon May 22, 2022
[3.12] REPORT: Efficient
switch(opcode)seems to require 182 or more effective cases. Starting from e48ac9c with 179 opcodes, the switch loads indexed memory twice, not once. I expect next alpha to have a sufficient number of opcodes.Details of the switch in e48ac9c (release build)
Example changes of
EXTRA_CASESin pycore_opcode.h:As for performance advantage over loading memory twice, the examples above has little for me. Each of the following was faster on PGO:
EXTRA_CASES, giving each an exclusive body withoutdefault.Py_FatalError().defaultcase unreachable.gvanrossum commentedon May 25, 2022
Thanks for the detailed and clear report. It sounds like in the long term we would be okay without depending on the
EXTRA_CASESmacro, though we might want to add a check somewhere that we have at least 182 cases. (It would be better if we could directly test for the extra memory indirection but that seems beyond our current tooling. :-)I'm not sure how come any of those would make a difference given that we never execute the default case. Or am I not following you?
neonene commentedon May 27, 2022
I'm not sure why either(EDIT: improved by #94364), so I tried making a small reproducer. After trimming the cases in eval loop,INSTRUCTION_START()macro remained loading memory twice, which is not implemented in3.10. I'd like to look into after new opcodes are introduced into3.12.Current jump behaviors using
case 255:Equivalent to if-else with 6 cases
Single memory load with 7 to 63 cases
Double memory load with 64 to 181 cases
Single memory load with 182 or more cases
Another behavior without
case 255MSVC seems to check whether existing cases are continuous or not, rather than their count. The following shows an extra memory load:
Details
erlend-aasland commentedon May 27, 2022
Do you want to reopen this, or create a new issue?
neonene commentedon May 27, 2022
The faster-cpython site would be better for more information.
gh-91719: Reload opcode on unknown error so that C can optimize the d…
pythongh-91719: Reload opcode on unknown error so that C can optimize…
gh-91719: Reload opcode on unknown error so that C can optimize the d…
pythongh-91719: Reload opcode on unknown error so that C can optimize…