PEP 510
* make new methods private * make Guard type private and rename it to PyFuncGuard * elaborate potential changes on the Python semantics * explain than other implementations of Python are free to not implement new methods, or implement them as no-op
This commit is contained in:
parent
238df5a182
commit
04b7e969a2
86
pep-0510.txt
86
pep-0510.txt
|
@ -13,8 +13,8 @@ Python-Version: 3.6
|
|||
Abstract
|
||||
========
|
||||
|
||||
Add an API to add specialized functions with guards to functions, to
|
||||
support static optimizers respecting the Python semantics.
|
||||
Add a private API to CPython to add specialized functions with guards to
|
||||
functions, to support static optimizers respecting the Python semantics.
|
||||
|
||||
|
||||
Rationale
|
||||
|
@ -29,10 +29,15 @@ modified at runtime. Implement optimizations respecting the Python
|
|||
semantics requires to detect when "something changes", we will call these
|
||||
checks "guards".
|
||||
|
||||
This PEP proposes to add a ``specialize()`` method to functions to add a
|
||||
specialized functions with guards. When the function is called, the
|
||||
specialized function is used if nothing changed, otherwise use the
|
||||
original bytecode.
|
||||
This PEP proposes to add an API to add specialized functions with guards
|
||||
to a function. When the function is called, the specialized function is
|
||||
used if nothing changed, otherwise use the original bytecode.
|
||||
|
||||
Even if guards help to respect most parts of the Python semantics, it's
|
||||
really hard to optimize Python without making subtle changes on the
|
||||
exact behaviour. CPython has a long history and many applications rely
|
||||
on implementation details. A compromise must be found between
|
||||
"everything is mutable" and performance.
|
||||
|
||||
Writing an optimizer is out of the scope of this PEP.
|
||||
|
||||
|
@ -112,18 +117,18 @@ Replace ``chr(65)`` with ``"A"``::
|
|||
def fast_func():
|
||||
return "A"
|
||||
|
||||
func.specialize(fast_func.__code__, [myoptimizer.GuardBuiltins("chr")])
|
||||
func._specialize(fast_func.__code__, [myoptimizer.GuardBuiltins("chr")])
|
||||
del fast_func
|
||||
|
||||
print("func(): %s" % func())
|
||||
print("#specialized: %s" % len(func.get_specialized()))
|
||||
print("#specialized: %s" % len(func._get_specialized()))
|
||||
print()
|
||||
|
||||
import builtins
|
||||
builtins.chr = lambda obj: "mock"
|
||||
|
||||
print("func(): %s" % func())
|
||||
print("#specialized: %s" % len(func.get_specialized()))
|
||||
print("#specialized: %s" % len(func._get_specialized()))
|
||||
|
||||
Output::
|
||||
|
||||
|
@ -157,10 +162,10 @@ to the builtin ``chr()`` function::
|
|||
def func(arg):
|
||||
return chr(arg)
|
||||
|
||||
func.specialize(chr, [myoptimizer.GuardBuiltins("chr")])
|
||||
func._specialize(chr, [myoptimizer.GuardBuiltins("chr")])
|
||||
|
||||
print("func(65): %s" % func(65))
|
||||
print("#specialized: %s" % len(func.get_specialized()))
|
||||
print("#specialized: %s" % len(func._get_specialized()))
|
||||
print()
|
||||
|
||||
import builtins
|
||||
|
@ -222,24 +227,43 @@ guards::
|
|||
Changes
|
||||
=======
|
||||
|
||||
* Add two new methods to functions:
|
||||
* Add two new private methods to functions:
|
||||
|
||||
- ``specialize(code, guards: list)``: add specialized
|
||||
* ``_specialize(code, guards: list)``: add specialized
|
||||
function with guard. `code` is a code object (ex:
|
||||
``func2.__code__``) or any callable object (ex: ``len``).
|
||||
The specialization can be ignored if a guard already fails.
|
||||
- ``get_specialized()``: get the list of specialized functions with
|
||||
guards
|
||||
``func2.__code__``) or any callable object (ex: the builtin
|
||||
``len()`` function). The specialization can be ignored if a guard
|
||||
already fails or for other reasons (ex: the implementation of Python
|
||||
does not implement this feature). Return ``False`` is the
|
||||
specialized function was ignored, return ``True`` otherwise.
|
||||
|
||||
* Base ``Guard`` type which can be used as parent type to implement
|
||||
guards. It requires to implement a ``check()`` function, with an
|
||||
optional ``first_check()`` function. API:
|
||||
* ``_get_specialized()``: get the list of specialized functions with
|
||||
guards. Return a list of ``(func, guards)`` tuples where func is the
|
||||
specialized function and guards is a list of guards. Return an empty
|
||||
list if the function was never specialized.
|
||||
|
||||
* Add a private ``PyFuncGuard`` Python type. It requires to implement a
|
||||
C ``check()`` function, with an optional C ``init()`` function. API:
|
||||
|
||||
* ``int init(PyObject *guard, PyObject *func)``: initialize a guard,
|
||||
*func* is the function to which the specialized function will be
|
||||
attached. Result:
|
||||
|
||||
* return ``1`` on success
|
||||
* return ``0`` if the guard will always fail (the specialization must be
|
||||
ignored)
|
||||
* raise an exception and return ``-1`` on error
|
||||
|
||||
* ``int first_check(PyObject *guard, PyObject *func)``: return 0 on
|
||||
success, -1 if the guard will always fail
|
||||
* ``int check(PyObject *guard, PyObject **stack, int na, int nk)``:
|
||||
return 1 on success, 0 if the guard failed temporarely, -1 if the
|
||||
guard will always fail
|
||||
check the guard. Result:
|
||||
|
||||
* return 2 on success
|
||||
* return 1 if the guard failed temporarely
|
||||
* return 0 if the guard will always fail
|
||||
* raise an exception and return -1 on error
|
||||
|
||||
* A guard can be called in Python with parameters, it returns the
|
||||
result of the guard check.
|
||||
|
||||
Microbenchmark on ``python3.6 -m timeit -s 'def f(): pass' 'f()'`` (best
|
||||
of 3 runs):
|
||||
|
@ -263,6 +287,20 @@ are not stored in ``.pyc`` files but created and registered at runtime,
|
|||
when a module is loaded.
|
||||
|
||||
|
||||
Other implementations of Python
|
||||
===============================
|
||||
|
||||
This PEP is designed to be implemented in C for CPython.
|
||||
|
||||
Other implementations of Python are free to not implement added private
|
||||
function methods.
|
||||
|
||||
Or they can implement a ``_specialize()`` method which always ignores
|
||||
the specialized function (in short, do nothing and always return
|
||||
``False``) and a ``_get_specialized()`` method which always returns an
|
||||
empty list.
|
||||
|
||||
|
||||
Discussion
|
||||
==========
|
||||
|
||||
|
|
Loading…
Reference in New Issue