From 04b7e969a23e44d1e4b799e051fcd0af97ceb4c9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 11 Jan 2016 23:55:32 +0100 Subject: [PATCH] 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 --- pep-0510.txt | 86 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/pep-0510.txt b/pep-0510.txt index 758aa0a0d..b26305977 100644 --- a/pep-0510.txt +++ b/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 ==========