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-91053: Add an optional callback that is invoked whenever a function is modified #98175
Conversation
JIT compilers may need to invalidate compiled code when a function is modified (e.g. if its code object is modified). This adds the ability to set a callback that, when set, is called each time a function is modified.
|
pyperformance results are perf-neutral. I also wrote a microbenchmark that attempts to measure the overhead on function creation when no callbacks are present. Happy to use a different benchmark and/or do this a bit more rigorously if there is concern. Results on the microbenchmark are perf-neutral as well: This PR with no function watchers set: Upstream: All benchmarks were run on a bare metal machine in AWS that was configured using |
|
The failing test appears unrelated to this diff. Is there a way that I can re-run the test without adding additional commits? |
You can merge in |
Or any core dev (and probably triager) can trigger a rerun, which I did already and it's now passed. |
Looks good. I added a bunch of PEP 7 comments because we should (almost) always strive to follow the style guide, both for new code and (in most cases) when modifying existing code. I also added some comments regarding docs, inconsistent naming of the constants, and some C API suggestions.
Questions:
PyFunction_SetDefaultsshould emit aPyFunction_EVENT_MODIFY_DEFAULTSevent, no?PyFunction_SetKwDefaultsshould emit aPyFunction_EVENT_MODIFY_KWDEFAULTSevent, no?- Why no events for
func_closureandfunc_annotationsmodifications?
Also, please add the Python test code to Lib/test/test_capi.py instead of adding a new Lib/test/test_func_events.py, like the dict watchers did.
Yep, good catch!
Sure thing, will do. |
- Imperative mood - Semantic line breaks
|
I don't like having watchers for function creation and destruction. Having those watchers adds overhead for every creation of a comprehension or nested function, which could be an issue for performance for two reasons:
|
|
Discussed offline with @markshannon and reached these conclusions (Mark please let me know if any of this doesn't match your understanding):
We also discussed a possible alternative design where code objects have a vectorcall pointer and function objects just copy it from the code object; then we wouldn't need func-created hook. But this also adds an extra read to function creation, as well as making code objects bigger, so it's not clear this is really a better approach. |
A bit is set in the bit vector iff there is a watcher set at the corresponding offset in the watcher array. Only notify watchers if at least one bit is set.
|
LGTM, thanks! I'll wait for @markshannon's thumbs up before merging. |
JIT compilers may need to invalidate compiled code when a function is modified (e.g. if its code object is modified). This adds the ability to set a callback that, when set, is called each time a function is modified.