Repository navigation
implement per-opcode cache in ceval #70407
Copy link
Copy link
Closed
Labels
3.8 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagePerformance or resource usage
Description
| BPO | 26219 |
|---|---|
| Nosy | @gvanrossum, @brettcannon, @ncoghlan, @vstinner, @ned-deily, @methane, @markshannon, @ericsnowcurrently, @1st1, @jstasiak, @MojoVampire, @DimitrisJim, @dopplershift, @rowillia |
| PRs | |
| Dependencies | |
| Files |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/1st1'
closed_at = <Date 2019-06-04.15:15:23.302>
created_at = <Date 2016-01-27.17:11:27.004>
labels = ['interpreter-core', '3.8', 'performance']
title = 'implement per-opcode cache in ceval'
updated_at = <Date 2019-12-27.19:07:14.427>
user = 'https://github.com/1st1'bugs.python.org fields:
activity = <Date 2019-12-27.19:07:14.427>
actor = 'eric.snow'
assignee = 'yselivanov'
closed = True
closed_date = <Date 2019-06-04.15:15:23.302>
closer = 'vstinner'
components = ['Interpreter Core']
creation = <Date 2016-01-27.17:11:27.004>
creator = 'yselivanov'
dependencies = ['26058', '26110']
files = ['41729', '41776', '42658']
hgrepos = ['333']
issue_num = 26219
keywords = ['patch']
message_count = 42.0
messages = ['259040', '259042', '259051', '259052', '259060', '259064', '259065', '259344', '259371', '259410', '259522', '259523', '262623', '264528', '264532', '264533', '264534', '264658', '264660', '264664', '264671', '264674', '264676', '310845', '310956', '310960', '310961', '310965', '311028', '344418', '344419', '344421', '344470', '344587', '344591', '345300', '345315', '354089', '354090', '354091', '354122', '354181']
nosy_count = 15.0
nosy_names = ['gvanrossum', 'brett.cannon', 'ncoghlan', 'vstinner', 'ned.deily', 'methane', 'Mark.Shannon', 'eric.snow', 'francismb', 'yselivanov', 'jstasiak', 'josh.r', 'Jim Fasarakis-Hilliard', 'Ryan May', 'Roy Williams']
pr_nums = ['12884', '13775', '13809', '13997', '14000']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'performance'
url = 'https://bugs.python.org/issue26219'
versions = ['Python 3.8']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.8 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagePerformance or resource usage
Activity
brettcannon commentedon Jan 27, 2016
I assume there's going to be a patch or more of a description of what your idea is? :)
1st1 commentedon Jan 27, 2016
Yeah, I needed a URL of the issue for my email to python-dev ;)
Here's a link to the email, that explains a lot about this patch: https://mail.python.org/pipermail/python-dev/2016-January/142945.html
The patch is also attached (opcache1.patch).
1st1 commentedon Jan 27, 2016
BTW, there are a couple of unit-tests that fail. Both can be easily fixed.
To really move this thing forward, we need to profile the memory usage. First, it would be interesting to see how much additional memory is consumed if we optimize every code object. That will give us an idea of the overhead, and if it is significant, we can experiment with various heuristics to minimize it.
brettcannon commentedon Jan 27, 2016
If you run hg.python.org/benchmarks on Linux it has a flag to measure memory.
1st1 commentedon Jan 27, 2016
Great. I'll re-run the benchmarks. BTW, the latest results are here: https://gist.github.com/1st1/aed69d63a2ff4de4c7be
vstinner commentedon Jan 27, 2016
If I understand correctly, this change requires to wait until the PEP-509 is accepted, right? Well, I'm not really suprised, since global cache is mentioned as an use case of the PEP-509, and other global cache patches are mentioned in Prior Art.
1st1 commentedon Jan 27, 2016
Yes, this patch depends on PEP-509.
1st1 commentedon Feb 1, 2016
Attaching a new version of the patch. Issues bpo-26058 and bpo-26110 need to be merged before we can start reviewing it.
vstinner commentedon Feb 2, 2016
I'm concerned by the test_descr failure.
======================================================================
ERROR: test_vicious_descriptor_nonsense (test.test_descr.ClassPropertiesAndMethods)
----------------------------------------------------------------------
======================================================================
FAIL: test_objecttypes (test.test_sys.SizeofTest)
----------------------------------------------------------------------
======================================================================
FAIL: test_pycfunction (test.test_gdb.PyBtTests)
Verify that "py-bt" displays invocations of PyCFunction instances
----------------------------------------------------------------------
1st1 commentedon Feb 2, 2016
Victor,
Thanks for the initial review. I'll work on the patch sometime later next week.
As for test_vicious_descriptor_nonsense -- yeah, I saw that too. I know what's going on there and I know how to fix that. FWIW that test tests a very counter-intuitive and quirky CPython implementation detail.
francismb commentedon Feb 3, 2016
From the two checks on Python/compile.c:
+ expr_ty meth = e->v.Call.func;
[...]
+ /* Check [...] that
+ the call doesn't have keyword parameters. */
[...]
+ /* Check that there are no *varargs types of arguments. */
[...]
I just wonder how many times those kind of checks/guards are done
on the whole Cpython code base (the second one seems expensive).
(Naive Idea):
Wouldn't be some kind of fast function description (e.g. bit flags
or 'e->v.Call.func.desc') generally helpful? The function description
could have: 'has_keywords' or 'has_varargs', ...
Thanks in advance!
1st1 commentedon Feb 4, 2016
Stuff done in compile.c is cached in *.pyc files.
The for-loop you saw shouldn't take a lot of time - it iterates through function parameters, which an average function doesn't have more than 3-6.
18 remaining items
methane commentedon Jun 3, 2019
New changeset 91234a1 by Inada Naoki in branch 'master':
bpo-26219: per opcode cache for LOAD_GLOBAL (GH-12884)
91234a1
methane commentedon Jun 3, 2019
I committed cache only for LOAD_GLOBAL, which is much simpler than
LOAD_ATTR or LOAD_METHOD.
Caches for other instructions will be implemented 3.9 or later.
methane commentedon Jun 3, 2019
New changeset 395420e by Inada Naoki in branch 'master':
bpo-26219: remove unused code (GH-13775)
395420e
vstinner commentedon Jun 3, 2019
The opcode cache introduced an issue in reference leak hunting: see bpo-37146.
vstinner commentedon Jun 4, 2019
New changeset ea9f168 by Victor Stinner in branch 'master':
bpo-26219: Fix compiler warning in _PyCode_InitOpcache() (GH-13809)
ea9f168
vstinner commentedon Jun 4, 2019
I understand that the initial issue (add an opcode cache) has been implemented. Well done Yury and INADA-san!
Please open new issues for follow-up like the new optimization ideas ;-)
vstinner commentedon Jun 12, 2019
New changeset 376ce98 by Victor Stinner in branch 'master':
bpo-26219: Fix compiler warning in _PyCode_InitOpcache() (GH-13997)
376ce98
vstinner commentedon Jun 12, 2019
New changeset 996e526 by Victor Stinner (Miss Islington (bot)) in branch '3.8':
bpo-26219: Fix compiler warning in _PyCode_InitOpcache() (GH-13997) (GH-14000)
996e526
markshannon commentedon Oct 7, 2019
"What's new in Python 3.8" says that this change speeds up the LOAD_GLOBAL opcode by 40%.
That seems meaningless as a program cannot have LOAD_GLOBAL in isolation so any test would have other bytecodes as well.
What's the evidence for the claimed speedup?
What's the speedup on the benchmark suite?
vstinner commentedon Oct 7, 2019
#12884 (comment)
points to:
https://github.com/methane/sandbox/tree/master/2019/opcache_load_global#opcache-for-load_global
== Microbenchmark ==
== pyperformance ==
Faster (23):
Benchmark hidden because not significant (32): (...)
markshannon commentedon Oct 7, 2019
Given that
def foo(): int; str; bytes; float; int; str; bytes; float
can be trivially be rewritten as
def foo(): pass
I think that benchmark is meaningless.
I really don't think we should be making claims like "40% speedup" for such contrived examples.
It looks like the speedup is real, but only about 2% speedup overall.
The "what's new" should reflect that, IMO.
brettcannon commentedon Oct 7, 2019
I personally think it would be fine to change the wording to say "measurable speed-up" and not attribute a specific number.
methane commentedon Oct 8, 2019
On Mon, Oct 7, 2019 at 9:41 PM Mark Shannon <report@bugs.python.org> wrote:
Do you mean every microbenchmark measuring single feature is meaningless?
I think it is worth enough for readers who understand what
LOAD_GLOBALinstruction means.(e.g. People who using techniques like
int_ = intbefore a loop.)