New submission from Vladimir Matveev <desco...@gmail.com>:

Calling methods and lookup up attributes when receiver is `super()` has extra 
cost comparing to regular attribute lookup. It mainly comes from the need to 
allocate and initialize the instance of the `super` which for zero argument 
case also include peeking into frame/code object for the `__class__` cell and 
first argument. In addition because `PySuper_Type` has custom implementation of 
tp_getattro - `_PyObject_GetMethod` would always return bound method. 
```
import timeit

setup = """
class A:
    def f(self): pass
class B(A):
    def f(self): super().f()
    def g(self): A.f(self)
b = B()
"""
print(timeit.timeit("b.f()", setup=setup, number=20000000))
print(timeit.timeit("b.g()", setup=setup, number=20000000))

7.329449548968114
3.892987059080042
```
 
One option to improve it could be to make compiler/interpreter aware of super 
calls so they can be treated specially. Attached patch introduces two new 
opcodes LOAD_METHOD_SUPER and LOAD_ATTR_SUPER that are intended to be 
counterparts for LOAD_METHOD and LOAD_ATTR for cases when receiver is super 
with either zero or two arguments.

Immediate argument for both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER is a pair 
that consist of:
 0: index of method/attribute in co_names
 1: Py_True if super was originally called with 0 arguments and Py_False 
otherwise.

Both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER expect 3 elements on the stack:
TOS3: global_super
TOS2: type
TOS1: self/cls

Result of LOAD_METHOD_SUPER is the same as LOAD_METHOD.
Result of LOAD_ATTR_SUPER is the same as LOAD_ATTR

In runtime both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER will check if 
`global_super` is `PySuper_Type` to handle situations when `super` is patched. 
If `global_super` is `PySuper_Type` then it can use dedicated routine to 
perform the lookup for provided `__class__` and `cls/self` without allocating 
new `super` instance. If `global_super` is different from `PySuper_Type` then 
runtime will fallback to the original logic using `global_super` and original 
number of arguments that was captured in immediate.

Benchmark results with patch:
4.381768501014449
3.9492998640052974

----------
components: Interpreter Core
messages: 389114
nosy: v2m
priority: normal
severity: normal
status: open
title: Use dedicated opcodes to speed up calls/attribute lookups with super() 
as receiver
versions: Python 3.10

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue43563>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to