From c91b102d8bd25c15d471eca6bfffb45e87296aee Mon Sep 17 00:00:00 2001 From: Stuart Archibald Date: Thu, 27 Jul 2023 11:16:06 +0100 Subject: [PATCH] Respond to review. * Update text to reflect that "max" optimisation is trading potentially longer compilation time for potentially better run-time but without being specific about how this is implemented. * Add `is_opt_max` property to `_OptLevel` to avoid attr access. * Add unit test to ensure that invalid opt level behaves as default. --- docs/upcoming_changes/9094.new_feature.rst | 12 ++++++------ numba/core/codegen.py | 16 ++++++++-------- numba/core/config.py | 15 +++++++++++---- numba/tests/test_config.py | 9 +++++++++ 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/docs/upcoming_changes/9094.new_feature.rst b/docs/upcoming_changes/9094.new_feature.rst index 708f6e97824..0cf7938f229 100644 --- a/docs/upcoming_changes/9094.new_feature.rst +++ b/docs/upcoming_changes/9094.new_feature.rst @@ -5,9 +5,9 @@ Add support for value ``max`` to ``NUMBA_OPT``. The optimisation level that Numba applies when compiling can be set through the environment variable ``NUMBA_OPT``. This has historically been a value between 0 and 3 (inclusive). Support for the value ``max`` has now been added, this is a -Numba-specific optimisation level which will result in Numba running a -O3-like -optimistion before reference counting operations are pruned and then running -another -O3-like optimisation afterwards. This may or may not benefit the -run-time or compile-time performance of user code, but it has been added as it -is similar to the compilation behaviour prior to Numba 0.54 and some users found -it leads to better performance for their programs. +Numba-specific optimisation level which indicates that the user would like Numba +to try running the most optimisation possible, potentially trading a longer +compilation time for better run-time performance. In practice, use of the ``max`` +level of optimisation may or may not benefit the run-time or compile-time +performance of user code, but it has been added to present an easy to access +option for users to try if they so wish. diff --git a/numba/core/codegen.py b/numba/core/codegen.py index 3dc9daa17b9..28ab618a0b0 100644 --- a/numba/core/codegen.py +++ b/numba/core/codegen.py @@ -1188,14 +1188,14 @@ def _init(self, llvm_module): self._target_data = engine.target_data self._data_layout = str(self._target_data) - if config.OPT._raw_value == 'max': - # If the OPT level is set to 'max' then run the cheap pass at O3 - # with loop-vectorize enabled. This _may_ result in more optimised - # code, but it also may have the opposite effect. It may also - # increase compilation time, but also may have the opposite effect. - # This behaviour is present so that users can choose what's - # appropriate for their application if they wish to, but there's a - # reasonable default present. + if config.OPT.is_opt_max: + # If the OPT level is set to 'max' then the user is requesting that + # compilation time is traded for potential performance gain. This + # currently manifests as running the "cheap" pass at -O3 + # optimisation level with loop-vectorization enabled. There's no + # guarantee that this will increase runtime performance, it may + # detriment it, this is here to give the user an easily accessible + # option to try. loopvect = True opt_level = 3 else: diff --git a/numba/core/config.py b/numba/core/config.py index 8a9588ea48a..c2edf63984d 100644 --- a/numba/core/config.py +++ b/numba/core/config.py @@ -82,10 +82,11 @@ def _validate_captured_errors_style(style_str): class _OptLevel(int): """This class holds the "optimisation level" set in `NUMBA_OPT`. As this env - var can be an int or a string, but is almost always interpreted as an int. - This class subclasses int so as to get the common behaviour but stores the - actual value as a `_raw_value` member to make it available for cases where - accounting for the specific string supplied by the user is necessary.""" + var can be an int or a string, but is almost always interpreted as an int, + this class subclasses int so as to get the common behaviour but stores the + actual value as a `_raw_value` member. The value "max" is a special case + and the property `is_opt_max` can be queried to find if the optimisation + level (supplied value at construction time) is "max".""" def __new__(cls, *args, **kwargs): assert len(args) == 1 @@ -97,6 +98,12 @@ def __new__(cls, *args, **kwargs): new._raw_value = value if value == 'max' else _int_value return new + @property + def is_opt_max(self): + """Returns True if the the optimisation level is "max" False + otherwise.""" + return self._raw_value == "max" + def __repr__(self): if isinstance(self._raw_value, str): arg = f"'{self._raw_value}'" diff --git a/numba/tests/test_config.py b/numba/tests/test_config.py index 374253aa8b4..fca7780b057 100644 --- a/numba/tests/test_config.py +++ b/numba/tests/test_config.py @@ -194,6 +194,15 @@ def test_opt_default(self): 'cost': 'cheap'} self.check(expected, 3, 3) + @TestCase.run_test_in_subprocess(envvars={'NUMBA_OPT': 'invalid'}) + def test_opt_invalid(self): + # NUMBA_OPT='invalid' should just proceed as default case + expected = {'loop_vectorize': False, + 'slp_vectorize': False, + 'opt': 0, + 'cost': 'cheap'} + self.check(expected, 3, 3) + if __name__ == '__main__': unittest.main()