* 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:
Victor Stinner 2016-01-11 23:55:32 +01:00
parent 238df5a182
commit 04b7e969a2
1 changed files with 62 additions and 24 deletions

View File

@ -13,8 +13,8 @@ Python-Version: 3.6
Abstract Abstract
======== ========
Add an API to add specialized functions with guards to functions, to Add a private API to CPython to add specialized functions with guards to
support static optimizers respecting the Python semantics. functions, to support static optimizers respecting the Python semantics.
Rationale Rationale
@ -29,10 +29,15 @@ modified at runtime. Implement optimizations respecting the Python
semantics requires to detect when "something changes", we will call these semantics requires to detect when "something changes", we will call these
checks "guards". checks "guards".
This PEP proposes to add a ``specialize()`` method to functions to add a This PEP proposes to add an API to add specialized functions with guards
specialized functions with guards. When the function is called, the to a function. When the function is called, the specialized function is
specialized function is used if nothing changed, otherwise use the used if nothing changed, otherwise use the original bytecode.
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. Writing an optimizer is out of the scope of this PEP.
@ -112,18 +117,18 @@ Replace ``chr(65)`` with ``"A"``::
def fast_func(): def fast_func():
return "A" return "A"
func.specialize(fast_func.__code__, [myoptimizer.GuardBuiltins("chr")]) func._specialize(fast_func.__code__, [myoptimizer.GuardBuiltins("chr")])
del fast_func del fast_func
print("func(): %s" % func()) print("func(): %s" % func())
print("#specialized: %s" % len(func.get_specialized())) print("#specialized: %s" % len(func._get_specialized()))
print() print()
import builtins import builtins
builtins.chr = lambda obj: "mock" builtins.chr = lambda obj: "mock"
print("func(): %s" % func()) print("func(): %s" % func())
print("#specialized: %s" % len(func.get_specialized())) print("#specialized: %s" % len(func._get_specialized()))
Output:: Output::
@ -157,10 +162,10 @@ to the builtin ``chr()`` function::
def func(arg): def func(arg):
return chr(arg) return chr(arg)
func.specialize(chr, [myoptimizer.GuardBuiltins("chr")]) func._specialize(chr, [myoptimizer.GuardBuiltins("chr")])
print("func(65): %s" % func(65)) print("func(65): %s" % func(65))
print("#specialized: %s" % len(func.get_specialized())) print("#specialized: %s" % len(func._get_specialized()))
print() print()
import builtins import builtins
@ -222,24 +227,43 @@ guards::
Changes 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: function with guard. `code` is a code object (ex:
``func2.__code__``) or any callable object (ex: ``len``). ``func2.__code__``) or any callable object (ex: the builtin
The specialization can be ignored if a guard already fails. ``len()`` function). The specialization can be ignored if a guard
- ``get_specialized()``: get the list of specialized functions with already fails or for other reasons (ex: the implementation of Python
guards 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 * ``_get_specialized()``: get the list of specialized functions with
guards. It requires to implement a ``check()`` function, with an guards. Return a list of ``(func, guards)`` tuples where func is the
optional ``first_check()`` function. API: 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)``: * ``int check(PyObject *guard, PyObject **stack, int na, int nk)``:
return 1 on success, 0 if the guard failed temporarely, -1 if the check the guard. Result:
guard will always fail
* 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 Microbenchmark on ``python3.6 -m timeit -s 'def f(): pass' 'f()'`` (best
of 3 runs): of 3 runs):
@ -263,6 +287,20 @@ are not stored in ``.pyc`` files but created and registered at runtime,
when a module is loaded. 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 Discussion
========== ==========