gh-149800: Generate the perf trampoline .eh_frame from the compiled assembly - #157246
gh-149800: Generate the perf trampoline .eh_frame from the compiled assembly#157246stratakis wants to merge 6 commits into
Conversation
Documentation build overview
23 files changed ·
|
|
Undrafting, this should be ready. The failed CI jobs must be flakiness as they passed on the previous commit, the last one just skips a specific test on BOLT builds. Did some extra verification here: A Fedora Rawhide RPM build of python3.15 with this on top of the split and the macOS fix (so basically a 3.15 backport), which contains the multitude of Fedora compiler flags. Tested on aarch64 and x86_64 the main, debug, free-threading and free-threading-debug interpreters . On all eight the trampoline is enabled, the jitdumps written by Also I've tested with adding ppc64le support and deployed it on the ppc64le Rawhide buildbot (source build not RPM). Granted the non-fp path is not exercised on ppc64le but nontheless it works if I add this patch on top: ppc64le patchbuilds, tests pass, perf back-chain and DWARF mode both unwind through the trampolines. Did also a s390x compilation (with the relevant code added similarly as the ppc64le one) on RHEL10 (no access to Fedora s390x for now), builds with and without So if that approach seems sound, it should be fairly easy to add s390x, ppc64le, RISC-V support. |
|
Thanks for the change, this is great. Two point of discussions, although very low priority:
The first skim of the PR looks OK to me, I might need a second look to it. Also please fix the errors in the CI. |
I would prefer to not depend on llvm for non-optional parts of CPython at least for now |
|
Will review this soon :) |
Re reading my message I realised that I didn't express well what I meant. I meant that we could reuse the work in this PR to drop the llvm-dwarfdump when building the JIT. |
Let the assembler emit an .eh_frame for the trampoline, matching the frame layout jit_unwind.c describes.
…iled assembly Extract the .eh_frame the assembler emits for the trampoline object at build time into trampoline_ehframe.h and patch only the FDE address fields at runtime. Building with the perf trampoline now needs a host Python, and configure disables the trampoline with a warning when none is usable.
Check the FDEs in jitdump files against their code load records, cover the generator's parsers, and validate the header structure from C.
99dbd73 to
0f6b805
Compare
|
Force pushed the get the latest changes from main, the commits are the same, I don't see how the CI could be failing so it might need something else, couldn't reproduce it. |
I'll take a jab on that, it certainly sounds like a better design. I could send another PR with it as alternative or do a followup, whatever works best.
Sharing would mean adding a CFA program interpreter in Python, which sounds great if it's gonna start reducing the llvm dependency area of the JIT. I'd be happy to take a look at it but since I deal with the JIT as adjacent to these Perf issues I don't have the best overview of the possible impact. |
|
The CI on Mac fails on the llvm installation phase |
| TRAMPOLINE_EHFRAME_H = $(if @PERF_TRAMPOLINE_OBJ@,trampoline_ehframe.h) | ||
|
|
||
| trampoline_ehframe.h: @PERF_TRAMPOLINE_OBJ@ $(srcdir)/Tools/jit/_trampoline_ehframe.py | ||
| $(PYTHON_FOR_REGEN) $(srcdir)/Tools/jit/_trampoline_ehframe.py \ |
There was a problem hiding this comment.
JIT_DEPS includes $(srcdir)/Tools/jit/*.py, so touching this script invalidates .jit-stamp and regenerates every JIT stencil, which has nothing to do with the perf trampoline. This is not JIT tooling; can we move it to Tools/build/?
There was a problem hiding this comment.
Damn, yeap you are correct here, it needs to be moved.
| * field offsets Python/jit_unwind.c patches. Raises instead of assert() | ||
| * so the checks also run in release builds. */ | ||
| static PyObject * | ||
| test_trampoline_ehframe(PyObject *self, PyObject *Py_UNUSED(args)) |
There was a problem hiding this comment.
parse_ehframe() already rejects a bad CIE version, a non-zR augmentation, an unsupported FDE encoding, more than one FDE and a non-zero FDE augmentation length at generation time, and test_generated_header_is_current diffs the header exactly against a fresh run. So what does this add? I am not sure ~120 lines of C plus a new _testinternalcapi entry point buy us anything here.
There was a problem hiding this comment.
Fair, gonna drop this.
| dnl time needs a Python interpreter, 3.7 or newer (Tools/jit/_trampoline_ehframe.py). | ||
| perf_trampoline_missing_python=no | ||
| AS_VAR_IF([perf_trampoline], [yes], [ | ||
| AS_IF([$PYTHON_FOR_REGEN -c 'import sys; sys.exit(sys.version_info < (3, 7))' >/dev/null 2>&1], |
There was a problem hiding this comment.
Why 3.7? AC_CHECK_PROGS above only probes python3.10 and newer (plus a bare python3/python), and Tools/jit/mypy.ini type-checks this script at 3.11, so 3.7 is never exercised. I would use the same floor as the rest of the build tooling so we are not claiming support we never test.
There was a problem hiding this comment.
The floor is for the bare python3 fallback , which is 3.9.6 on a stock Mac and I tested that there end to end. Started with 3.10, trampoline disabled on Mac, 3.9 works. I've put 3.7 not for any premise there, but because it was compatible code wise and I've thought that maaaybe someone might try to build on something older. I think raising to 3.9 would be reasonable?
A branch with some extra commits on top of this PR implementing that to see if it makes sense: main...stratakis:cpython:trampoline_bootstrap However it's mostly Fable generated with a small review by gpt6, haven't checked the code much or done any rigorous testing apart from a simple build and tests. If it makes sense I can expand on this. I'll check out the review comments the next days (or feel free to amend as you see fit :) ) |
|
I pushed a commit with some small cleanup for the main file to parse the debug info |
The trampoline's unwind information has been a hand-maintained DWARF block per architecture in
Python/jit_unwind.c.Now all of this can be changed :)
The perf trampoline's unwind information is now produced by the assembler from
.cfidirectives in the trampoline assembly and extracted into a header at build time, so no architecture needs hand-written DWARF anymore.Building the perf trampoline now needs a host Python (
PYTHON_FOR_REGEN, 3.7 or newer. Wanted 3.9 for the stock Mac interpreter but 3.7 was compatible so why not). Without one,configuredisables the trampoline.Tested on Linux x86_64 (gcc, clang, CET, JIT, tail-call interpreter, free-threaded, LTO, PGO, BOLT, shared, debug, no frame pointers, out-of-tree)
Linux aarch64 (default, PAC, shared, debug, no frame pointers)
macOS arm64 (native, framework, universal2 on both slices), end to end with perf (fp and DWARF call graphs) and samply.
Plus the test suite ofc which was passing for me (let's see what the CI says though).
This can also be backported into 3.15 together with #149894 and #150364 if needed.
Fixes: #149800
THe PR and testing has been assisted by various frontier models, mainly by Fable 5.1 but also each each iteration reviewed in addition by the gpt 6 astra model.
Making it a draft for now, I believe it's ready but I'd also like to test an rpm build first, plus adding another architecture such as s390x or ppc64le to verify things work as intended.