Add opcode cache for LOAD_ATTR #86259
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
assignee = 'https://github.com/pablogsal' closed_at = <Date 2020-10-20.05:27:36.232> created_at = <Date 2020-10-20.03:18:36.160> labels = ['interpreter-core', '3.10'] title = 'Add opcode cache for LOAD_ATTR' updated_at = <Date 2021-02-21.11:02:18.003> user = 'https://github.com/pablogsal'
activity = <Date 2021-02-21.11:02:18.003> actor = 'vstinner' assignee = 'pablogsal' closed = True closed_date = <Date 2020-10-20.05:27:36.232> closer = 'pablogsal' components = ['Interpreter Core'] creation = <Date 2020-10-20.03:18:36.160> creator = 'pablogsal' dependencies =  files =  hgrepos =  issue_num = 42093 keywords = ['patch'] message_count = 9.0 messages = ['379083', '379087', '383859', '384087', '384254', '384354', '384364', '384366', '387451'] nosy_count = 5.0 nosy_names = ['gvanrossum', 'vstinner', 'yselivanov', 'Guido.van.Rossum', 'pablogsal'] pr_nums = ['22803', '24070', '24582'] priority = 'normal' resolution = 'fixed' stage = 'resolved' status = 'closed' superseder = None type = None url = 'https://bugs.python.org/issue42093' versions = ['Python 3.10']
The text was updated successfully, but these errors were encountered:
From the creators of "opcode cache for LOAD_GLOBAL" (https://bugs.python.org/issue26219) now it's time for "opcode cache for LOAD_ATTR: the revenge". This issue/PR builds on top of Yury's original patch in the same way https://bugs.python.org/issue26219 did for LOAD_GLOBAL.
These are the benchmark results for the pyperformance test suite with PGO/LTO/CPU ISOLATION in a tuned system with pyperf:
Not significant (35): chameleon; django_template; dulwich_log; fannkuch; float; json_dumps; json_loads; logging_format; mako; nqueens; pathlib; pickle; pickle_dict; pickle_list; pidigits; python_startup; python_startup_no_site; regex_compile; scimark_fft; spectral_norm; sqlalchemy_declarative; sqlalchemy_imperative; sqlite_synth; sympy_expand; sympy_sum; sympy_str; telco; tornado_http; unpack_sequence; unpickle; unpickle_list; xml_etree_parse; xml_etree_iterparse; xml_etree_generate; xml_etree_process; sympy_integrate
Not only that: is even faster than the highly-tuned namedtuple access descriptors that used to be the faster access to an attribute:
Now this is the faster way to get an attribute:
Good idea!. I will prepare a PR complementing the current paragraph.
Yeah, we are experimenting with some ideas here: https://bugs.python.org/issue42115.
I think we can do it as long as we can detect easily if a given descriptor is immutable. The problem of mutability is this code:
class Descriptor: pass class C: def __init__(self): self.x = 1 x = Descriptor() def f(o): return o.x o = C() for i in range(10000): assert f(o) == 1 Descriptor.__get__ = lambda self, instance, value: 2 Descriptor.__set__ = lambda *args: None print(f(o))
In this case, if we do not skip the cache for mutable descriptors, the code will not reflect the new result (2 instead of 1). __slots__ are immutable descriptors so we should be good as long as we can detect them.