8000 bpo-2506: Add mechanism to disable optimizations by pablogsal · Pull Request #22027 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-2506: Add mechanism to disable optimizations #22027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,14 @@ PyConfig
by the function calculating the :ref:`Path Configuration
<init-path-config>`.

.. c:member:: int optimize

Should the compiler optimize bytecode? If equal to 0, disable the
compiler optimizations and set :c:member:`~PyConfig.optimization_level`
to 0. Set to 0 by :option:`-X noopt <-X>` command line option.

.. versionadded:: 3.10

.. c:member:: int optimization_level

Compilation optimization level:
Expand Down
9 changes: 8 additions & 1 deletion Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ are always available. They are listed here in alphabetical order.
object has ``CO_COROUTINE`` set in ``co_code``, and can be interactively
executed via ``await eval(code_object)``.

If the *ast.PyCF_DISABLE_ALL_OPTIMIZATIONS* bit is set in *flags*, all compiler
optimizations will be disabled and the value of *optimize* will be ignored. If
this bit is not set, the value of ``sys.flags.noopt`` will be used.

The argument *optimize* specifies the optimization level of the compiler; the
default value of ``-1`` selects the optimization level of the interpreter as
given by :option:`-O` options. Explicit levels are ``0`` (no optimization;
Expand Down Expand Up @@ -319,10 +323,13 @@ are always available. They are listed here in alphabetical order.
Previously, :exc:`TypeError` was raised when null bytes were encountered
in *source*.

.. versionadded:: 3.8
.. versionchanged:: 3.8
``ast.PyCF_ALLOW_TOP_LEVEL_AWAIT`` can now be passed in flags to enable
support for top-level ``await``, ``async for``, and ``async with``.

.. versionchanged:: 3.10
New *noopt* optional keyword-only parameter.


.. class:: complex([real[, imag]])

Expand Down
10 changes: 9 additions & 1 deletion Doc/library/importlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ an :term:`importer`.

.. versionadded:: 3.4

.. function:: cache_from_source(path, debug_override=None, *, optimization=None)
.. function:: cache_from_source(path, debug_override=None, *, optimization=None, noopt=None)

Return the :pep:`3147`/:pep:`488` path to the byte-compiled file associated
with the source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
Expand All @@ -1429,6 +1429,11 @@ an :term:`importer`.
``/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc``. The string representation
of *optimization* can only be alphanumeric, else :exc:`ValueError` is raised.

The *noopt* parameter is used to specify if compiler optimization are
disabled. If it is true, disable compiler optimizations, *optimization* is
ignored and ``.noopt`` suffix is used (ex: ``baz.cpython-32.noopt.pyc``). If
it is ``None``, use ``sys.flags.noopt`` value.

The *debug_override* parameter is deprecated and can be used to override
the system's value for ``__debug__``. A ``True`` value is the equivalent of
setting *optimization* to the empty string. A ``False`` value is the same as
Expand All @@ -1444,6 +1449,9 @@ an :term:`importer`.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

.. versionchanged:: 3.10
Added *noopt* parameter.


.. function:: source_from_cache(path)

Expand Down
8 changes: 7 additions & 1 deletion Doc/library/py_compile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ byte-code cache files in the directory containing the source code.
Exception raised when an error occurs while attempting to compile the file.


.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0)
.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0, noopt=None)

Compile a source file to byte-code and write out the byte-code cache file.
The source code is loaded from the file named *file*. The byte-code is
Expand Down Expand Up @@ -60,6 +60,9 @@ byte-code cache files in the directory containing the source code.
:func:`compile` function. The default of ``-1`` selects the optimization
level of the current interpreter.

If *noopt* is true, disable compiler optimizations and ignore *optimize*
argument. If it is ``None``, use ``sys.flags.noopt`` value.

*invalidation_mode* should be a member of the :class:`PycInvalidationMode`
enum and controls how the generated bytecode cache is invalidated at
runtime. The default is :attr:`PycInvalidationMode.CHECKED_HASH` if
Expand Down Expand Up @@ -92,6 +95,9 @@ byte-code cache files in the directory containing the source code.
.. versionchanged:: 3.8
The *quiet* parameter was added.

.. versionchanged:: 3.10
The *noopt* parameter was added.


.. class:: PycInvalidationMode

Expand Down
4 changes: 4 additions & 0 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ always available.
:const:`inspect` :option:`-i`
:const:`interactive` :option:`-i`
:const:`isolated` :option:`-I`
:const:`noopt` :option:`-X noopt <-X>`
:const:`optimize` :option:`-O` or :option:`-OO`
:const:`dont_write_bytecode` :option:`-B`
:const:`no_user_site` :option:`-s`
Expand Down Expand Up @@ -469,6 +470,9 @@ always available.
Mode <devmode>` and the ``utf8_mode`` attribute for the new :option:`-X`
``utf8`` flag.

.. versionchanged:: 3.10
Added ``noopt`` attribute for the new :option:`-X noopt <-X>` option.


.. data:: float_info

Expand Down
7 changes: 4 additions & 3 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ Miscellaneous options
* ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel
tree rooted at the given directory instead of to the code tree. See also
:envvar:`PYTHONPYCACHEPREFIX`.
* ``-X noopt`` disables the compiler optimizations.

It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary.
Expand All @@ -477,9 +478,9 @@ Miscellaneous options
The ``-X pycache_prefix`` option. The ``-X dev`` option now logs
``close()`` exceptions in :class:`io.IOBase` destructor.

.. versionchanged:: 3.9
Using ``-X dev`` option, check *encoding* and *errors* arguments on
string encoding and decoding operations.
.. versionadded:: 3.10
The ``-X noopt`` option. Using ``-X dev`` option, check *encoding* and
*errors* arguments on string encoding and decoding operations.

The ``-X showalloccount`` option has been removed.

Expand Down
30 changes: 30 additions & 0 deletions Doc/whatsnew/3.10.rst
< F42D tr data-hunk="82d2c6a725fa6e3af402854063b269d18b745f6b37d3e8319e7840f041aff030" class="show-top-border">
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ Other Language Changes
:meth:`~object.__index__` method).
(Contributed by Serhiy Storchaka in :issue:`37999`.)

* Added :option:`-X noopt <-X>` command line to disable compiler optimizations.
:mod:`importlib` uses ``.noopt.pyc`` suffix for ``.pyc`` filenames if
:data:`sys.flags.noopt` is true.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)


New Modules
===========
Expand All @@ -109,6 +114,12 @@ base64
Add :func:`base64.b32hexencode` and :func:`base64.b32hexdecode` to support the
Base32 Encoding with Extended Hex Alphabet.

builtins
--------

The :func:`compile` function gets a new optional bit in the *flags* argument
(:data:`ast.PyCF_DISABLE_ALL_OPTIMIZATIONS`) to disable all compiler optimizations.

curses
------

Expand All @@ -126,6 +137,20 @@ Added the *root_dir* and *dir_fd* parameters in :func:`~glob.glob` and
:func:`~glob.iglob` which allow to specify the root directory for searching.
(Contributed by Serhiy Storchaka in :issue:`38144`.)

importlib
---------

Add a new *noopt* optional keyword-only parameter to
:func:`importlib.util.cache_from_source` to disable compiler optimizations.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

py_compile
----------

Add a new *noopt* optional keyword-only parameter to :func:`py_compile.compile`
to disable compiler optimizations.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

os
--

Expand All @@ -145,6 +170,11 @@ Add :data:`sys.orig_argv` attribute: the list of the original command line
arguments passed to the Python executable.
(Contributed by Victor Stinner in :issue:`23427`.)


Add new :data:`sys.flags.noopt` flag for the new :option:`-X noopt <-X>` option
(disable compiler optimizations).
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

xml
---

Expand Down
7 changes: 6 additions & 1 deletion Include/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ extern "C" {
#define PyCF_IGNORE_COOKIE 0x0800
#define PyCF_TYPE_COMMENTS 0x1000
#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000
#define PyCF_DISABLE_ALL_OPTIMIZATIONS 0x4000
#define PyCF_COMPILE_MASK (PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | \
PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT)
PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT | \
PyCF_DISABLE_ALL_OPTIMIZATIONS)

#ifndef Py_LIMITED_API
typedef struct {
Expand Down Expand Up @@ -106,4 +108,7 @@ PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, _PyASTOptimizeSta
/* This doesn't need to match anything */
#define Py_fstring_input 800

/* Value of 'optimize' to disable all optimizations */
#define _PyCompiler_disable_all_optimizations -2

#endif /* !Py_COMPILE_H */
11 changes: 11 additions & 0 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,17 @@ typedef struct {

_PyConfig_Write() initializes Py_GetArgcArgv() to this list. */
PyWideStringList orig_argv;

/* Should the compiler optimize bytecode?

If equal to 0, disable compiler optimizations and set optimization_level
to 0.

If equal to 1, enable compiler optimizations.

Set to 0 by -X noopt. It's default value is 1 */
int optimize;

} PyConfig;

PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config);
Expand Down
5 changes: 5 additions & 0 deletions Include/pythonrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ PyAPI_FUNC(PyObject *) Py_CompileStringObject(
PyObject *filename, int start,
PyCompilerFlags *flags,
int optimize);
PyAPI_FUNC(PyObject *) _Py_CompileString(
const char *str,
PyObject *filename, int start,
PyCompilerFlags *flags,
int optimize);
#endif
PyAPI_FUNC(struct symtable *) Py_SymtableString(
const char *str,
Expand Down
4 changes: 2 additions & 2 deletions Lib/distutils/command/build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,10 @@ def get_outputs(self, include_bytecode=1):
if include_bytecode:
if self.compile:
outputs.append(importlib.util.cache_from_source(
filename, optimization=''))
filename, optimization='', noopt=False))
if self.optimize > 0:
outputs.append(importlib.util.cache_from_source(
filename, optimization=self.optimize))
filename, optimization=self.optimize, noopt=False))

outputs += [
os.path.join(build_dir, filename)
Expand Down
4 changes: 2 additions & 2 deletions Lib/distutils/command/install_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ def _bytecode_filenames(self, py_filenames):
continue
if self.compile:
bytecode_files.append(importlib.util.cache_from_source(
py_file, optimization=''))
py_file, optimization='', noopt=False))
if self.optimize > 0:
bytecode_files.append(importlib.util.cache_from_source(
py_file, optimization=self.optimize))
py_file, optimization=self.optimize, noopt=False))

return bytecode_files

Expand Down
6 changes: 4 additions & 2 deletions Lib/distutils/tests/test_install_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ def test_byte_compile(self):
f = os.path.join(project_dir, 'foo.py')
self.write_file(f, '# python file')
cmd.byte_compile([f])
pyc_file = importlib.util.cache_from_source('foo.py', optimization='')
pyc_file = importlib.util.cache_from_source('foo.py', optimization='',
noopt=False)
pyc_opt_file = importlib.util.cache_from_source('foo.py',
optimization=cmd.optimize)
optimization=cmd.optimize,
noopt=False)
self.assertTrue(os.path.exists(pyc_file))
self.assertTrue(os.path.exists(pyc_opt_file))

Expand Down
9 changes: 5 additions & 4 deletions Lib/distutils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,11 @@ def byte_compile (py_files,
# dfile - purported source filename (same as 'file' by default)
if optimize >= 0:
opt = '' if optimize == 0 else optimize
cfile = importlib.util.cache_from_source(
file, optimization=opt)
cfile = importlib.util.cache_from_source(file,
optimization=opt,
noopt=False)
else:
cfile = importlib.util.cache_from_source(file)
cfile = importlib.util.cache_from_source(file, noopt=False)
dfile = file
if prefix:
if file[:len(prefix)] != prefix:
Expand All @@ -462,7 +463,7 @@ def byte_compile (py_files,
if force or newer(file, cfile):
5B3A log.info("byte-compiling %s to %s", file, cfile_base)
if not dry_run:
compile(file, cfile, dfile)
compile(file, cfile, dfile, noopt=False)
else:
log.debug("skipping byte-compilation of %s to %s",
file, cfile_base)
Expand Down
Loading
0