Repository: numba/numba
Pull request: Default to turn off `sys.monitoring`
(Base on #9682; pending rebase once it's merged)

As discussed in dev meeting, this patch disables the `sys.monitoring` support by default with two ways to override:

- (public) Use environment variable `NUMBA_SYS_MONITORING_DEFAULT` to process-wide control.
- (internal only) Per dispatcher, there's a `._enable_sysmon` attribute to control whether the dispatcher will invoke the monitoring tools.

Closes https://github.com/numba/numba/issues/9753

Problem statement:
Numba 0.60.0 breaks (VSCode) debugpy (on Windows)
## Reporting a bug

A colleague ran into some problems running a debugger on a script that uses numba inside one of my packages. I noticed the debugger in VSCode on Windows stopped working with the latest release. It takes only a trivial example to trigger:

```python
import numba as nb
import numpy as np


@nb.njit
def f(a):
    out = 0
    for e in a:
        out += e
    return out


def g(a):
    out = a + 1
    return out


a = np.arange(10)
b = f(a)
c = g(a)
```

Just put a breakpoint in function `g` and start debugging the file in VSCode.

It fails with the following stacktrace:

```
PS C:\src\xugrid>  & 'C:\src\xugrid\.pixi\envs\default\python.exe' 'c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher' '59193' '--' 'C:\src\xugrid\examples\test-debug.py'
src\x5cxugrid\x5cexamples\x5ctest-debug.py' ;f5f2a96f-77db-4413-91af-5fd71fc1a282Traceback (most recent call last):
  File "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx", line 555, in _pydevd_sys_monitoring_cython._get_func_code_info
KeyError: (6, 'C:\\src\\xugrid\\examples\\test-debug.py', <code object f at 0x000001FC3A8E5F20, file "C:\src\xugrid\examples\test-debug.py", line 6>)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\src\xugrid\.pixi\envs\default\Lib\runpy.py", line 198, in _run_module_as_main
    return _run_code(code, main_globals, None,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\src\xugrid\.pixi\envs\default\Lib\runpy.py", line 88, in _run_code
    exec(code, run_globals)
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher/../..\debugpy\__main__.py", line 71, in <module>
    cli.main()
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py", line 501, in main
    run()
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py", line 351, in run_file
    runpy.run_path(target, run_name="__main__")
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 310, in run_path
    return _run_module_code(code, init_globals, run_name, pkg_name=pkg_name, script_name=fname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 127, in _run_module_code
    _run_code(code, mod_globals, init_globals, mod_name, mod_spec, pkg_name, script_name)
  File "c:\Users\bootsma\.vscode\extensions\ms-python.debugpy-2024.12.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py", line 118, in _run_code
    exec(code, run_globals)
  File "C:\src\xugrid\examples\test-debug.py", line 20, in <module>
    b = f(a)
        ^^^^
  File "<stringsource>", line 69, in cfunc.to_py.__Pyx_CFunc_893235__29_pydevd_sys_monitoring_cython_object__lParen__etc_to_py_4code_18instruction_offset.wrap
  File "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx", line 1662, in _pydevd_sys_monitoring_cython._start_method_event
  File "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx", line 562, in _pydevd_sys_monitoring_cython._get_func_code_info
AssertionError: <code object <module> at 0x000001FC3A5868E0, file "C:\src\xugrid\examples\test-debug.py", line 1> != <code object f at 0x000001FC3A8E5F20, file "C:\src\xugrid\examples\test-debug.py", line 6>
PS C:\src\xugrid> 
```

I tested the previous version: numba 0.59.1 allows me to debug without problems (and reverting also fixes it for my colleague).

Here's the `numba -s` dump for completeness:

<details>

```
System info:
--------------------------------------------------------------------------------
__Time Stamp__
Report started (local time)                   : 2024-10-16 16:12:47.350235
UTC start time                                : 2024-10-16 14:12:47.350235
Running time (s)                              : 0.651199

__Hardware Information__
Machine                                       : AMD64
CPU Name                                      : alderlake
CPU Count                                     : 24
Number of accessible CPUs                     : 24
List of accessible CPUs cores                 : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
CFS Restrictions (CPUs worth of runtime)      : None

CPU Features                                  : 64bit adx aes avx avx2 bmi bmi2
                                                clflushopt clwb cmov crc32 cx16
                                                cx8 f16c fma fsgsbase fxsr gfni
                                                invpcid lzcnt mmx movbe pclmul
                                                popcnt prfchw ptwrite rdpid rdrnd
                                                rdseed sahf sha shstk sse sse2
                                                sse3 sse4.1 sse4.2 ssse3 vaes
                                                vpclmulqdq xsave xsavec xsaveopt
                                                xsaves

Memory Total (MB)                             : 32368
Memory Available (MB)                         : 16350

__OS Information__
Platform Name                                 : Windows-10-10.0.19045-SP0
Platform Release                              : 10
OS Name                                       : Windows
OS Version                                    : 10.0.19045
OS Specific Version                           : 10 10.0.19045 SP0 Multiprocessor Free
Libc Version                                  : ?

__Python Information__
Python Compiler                               : MSC v.1941 64 bit (AMD64)
Python Implementation                         : CPython
Python Version                                : 3.12.7
Python Locale                                 : en_NL.cp1252

__Numba Toolchain Versions__
Numba Version                                 : 0.60.0
llvmlite Version                              : 0.43.0

__LLVM Information__
LLVM Version                                  : 14.0.6

__CUDA Information__
CUDA Device Initialized                       : True
CUDA Driver Version                           : ?
CUDA Runtime Version                          : ?
CUDA NVIDIA Bindings Available                : ?
CUDA NVIDIA Bindings In Use                   : ?
CUDA Minor Version Compatibility Available    : ?
CUDA Minor Version Compatibility Needed       : ?
CUDA Minor Version Compatibility In Use       : ?
CUDA Detect Output:
Found 1 CUDA devices
id 0    b'NVIDIA RTX A1000 Laptop GPU'                              [SUPPORTED]
                      Compute Capability: 8.6
                           PCI Device ID: 0
                              PCI Bus ID: 1
                                    UUID: GPU-bb86f3ad-7a9f-8a73-eab7-609217f339a2
                                Watchdog: Enabled
                            Compute Mode: WDDM
             FP32/FP64 Performance Ratio: 32
Summary:
        1/1 devices are supported

CUDA Libraries Test Output:
None

__NumPy Information__
NumPy Version                                 : 2.0.2
NumPy Supported SIMD features                 : ('MMX', 'SSE', 'SSE2', 'SSE3', 'SSSE3', 'SSE41', 'POPCNT', 'SSE42', 'AVX', 'F16C', 'FMA3', 'AVX2')
NumPy Supported SIMD dispatch                 : ('SSSE3', 'SSE41', 'POPCNT', 'SSE42', 'AVX', 'F16C', 'FMA3', 'AVX2', 'AVX512F', 'AVX512CD', 'AVX512_SKX', 'AVX512_CLX', 'AVX512_CNL', 'AVX512_ICL')
NumPy Supported SIMD baseline                 : ('SSE', 'SSE2', 'SSE3')
NumPy AVX512_SKX support detected             : False

__SVML Information__
SVML State, config.USING_SVML                 : True
SVML Library Loaded                           : True
llvmlite Using SVML Patched LLVM              : True
SVML Operational                              : True

__Threading Layer Information__
TBB Threading Layer Available                 : True
+-->TBB imported successfully.
OpenMP Threading Layer Available              : True
+-->Vendor: MS
Workqueue Threading Layer Available           : True
+-->Workqueue imported successfully.

__Numba Environment Variable Information__
None found.

__Conda Information__
Conda not available.

__Installed Packages__
Package                       Version     Editable project location
----------------------------- ----------- -------------------------
accessible-pygments           0.0.5
alabaster                     1.0.0
asciitree                     0.3.3
asttokens                     2.4.1
Babel                         2.14.0
backports.tarfile             1.0.0
beautifulsoup4                4.12.3
bokeh                         3.6.0
branca                        0.7.2
Brotli                        1.1.0
build                         1.2.2.post1
certifi                       2024.8.30
cffi                          1.17.1
cfgv                          3.3.1
cftime                        1.6.4
charset-normalizer            3.4.0
click                         8.1.7
cloudpickle                   3.1.0
cmarkgfm                      0.8.0
colorama                      0.4.6
comm                          0.2.2
contourpy                     1.3.0
coverage                      7.6.3
cycler                        0.12.1
cytoolz                       1.0.0
dask                          2024.9.1
dask-expr                     1.1.15
debugpy                       1.8.7
decopatch                     1.4.10
decorator                     5.1.1
distlib                       0.3.9
distributed                   2024.9.1
docutils                      0.21.2
exceptiongroup                1.2.2
executing                     2.1.0
fasteners                     0.17.3
filelock                      3.16.1
folium                        0.17.0
fonttools                     4.54.1
fsspec                        2024.9.0
geopandas                     1.0.1
h2                            4.1.0
hpack                         4.0.0
hyperframe                    6.0.1
identify                      2.6.1
idna                          3.10
imagesize                     1.4.1
importlib_metadata            8.5.0
importlib_resources           6.4.5
iniconfig                     2.0.0
ipykernel                     6.29.5
ipython                       8.28.0
jaraco.classes                3.4.0
jaraco.context                5.3.0
jaraco.functools              4.0.0
jedi                          0.19.1
Jinja2                        3.1.4
joblib                        1.4.2
jupyter_client                8.6.3
jupyter_core                  5.7.2
keyring                       25.4.1
kiwisolver                    1.4.7
llvmlite                      0.43.0
locket                        1.0.0
lz4                           4.3.3
makefun                       1.15.6
mapbox_earcut                 1.0.1
mapclassify                   2.8.1
markdown-it-py                3.0.0
MarkupSafe                    3.0.1
matplotlib                    3.9.2
matplotlib-inline             0.1.7
mdurl                         0.1.2
more-itertools                10.5.0
msgpack                       1.1.0
munkres                       1.1.4
nest_asyncio                  1.6.0
netCDF4                       1.7.1
networkx                      3.4.1
nh3                           0.2.18
nodeenv                       1.9.1
numba                         0.60.0
numba_celltree                0.2.2
numcodecs                     0.13.1
numpy                         2.0.2
packaging                     24.1
pandas                        2.2.3
parso                         0.8.4
partd                         1.4.2
pickleshare                   0.7.5
pillow                        11.0.0
pip                           24.2
pkginfo                       1.10.0
platformdirs                  4.3.6
pluggy                        1.5.0
pooch                         1.8.2
pre_commit                    4.0.1
prompt_toolkit                3.0.48
psutil                        6.0.0
pure_eval                     0.2.3
pyarrow                       17.0.0
pyarrow-hotfix                0.6
pycparser                     2.22
pydata-sphinx-theme           0.15.4
Pygments                      2.18.0
PyMetis                       2023.1.1
pyogrio                       0.10.0
pyparsing                     3.2.0
pyproj                        3.7.0
pyproject_hooks               1.2.0
PySocks                       1.7.1
pytest                        8.3.3
pytest-cases                  3.8.6
pytest-cov                    5.0.0
python-dateutil               2.9.0
pytz                          2024.1
pywin32                       307
pywin32-ctypes                0.2.3
PyYAML                        6.0.2
pyzmq                         26.2.0
readme_renderer               44.0
requests                      2.32.3
requests-toolbelt             1.0.0
rfc3986                       2.0.0
rich                          13.9.2
ruff                          0.6.9
scikit-learn                  1.5.2
scipy                         1.14.1
setuptools                    75.1.0
shapely                       2.0.6
six                           1.16.0
snowballstemmer               2.2.0
sortedcontainers              2.4.0
soupsieve                     2.5
Sphinx                        8.1.3
sphinx-gallery                0.18.0
sphinxcontrib-applehelp       2.0.0
sphinxcontrib-devhelp         2.0.0
sphinxcontrib-htmlhelp        2.1.0
sphinxcontrib-jsmath          1.0.1
sphinxcontrib-qthelp          2.0.0
sphinxcontrib-serializinghtml 1.1.10
stack-data                    0.6.2
tblib                         3.0.0
threadpoolctl                 3.5.0
toml                          0.10.2
tomli                         2.0.2
toolz                         1.0.0
tornado                       6.4.1
traitlets                     5.14.3
twine                         5.1.1
typing_extensions             4.12.2
tzdata                        2024.2
ukkonen                       1.0.1
urllib3                       2.2.3
virtualenv                    20.26.6
wcwidth                       0.2.13
wheel                         0.44.0
win_inet_pton                 1.1.0
xarray                        2024.9.0
xugrid                        0.12.1
xyzservices                   2024.9.0
zarr                          2.18.3
zict                          3.0.0
zipp                          3.20.2
zstandard                     0.23.0

No errors reported.


__Warning log__
Warning (cuda): Probing CUDA failed (device and driver present, runtime problem?)
(cuda) <class 'FileNotFoundError'>: Could not find module 'cudart.dll' (or one of its dependencies). Try using the full path with constructor syntax.
Warning: Conda not available.
 Error was [WinError 2] The system cannot find the file specified

--------------------------------------------------------------------------------
```

<\details>

Hints from issue discussion:
I met the exact same problem today. If no breakpoint set everything is fine otherwise it fails at the first call to a jitted function. It seems that the debugger or numba messed things up.
confirmed vscode python debugger 2024.12.0 breaks thing up, just roll back to 2024.10.0
Thanks for the comment @HIEROT. @Huite, can you confirm the rolling back to a previous version of VSCode fixes the issue?
I can confirm: VSCode Python debugger `v2024.10.0` works.

For completeness:

Python Debugger v2024.10.0 works with numba 0.59.1 ✔️
Python Debugger v2024.10.0 works with numba 0.60.0 ✔️

Python Debugger v2024.12.0 works with numba 0.59.1 ✔️
Python Debugger v2024.12.0 does not work with numba 0.60.0 ❌
Ok, thanks. I'll close this PR as this doesn't seem to be Numba's fault.
> Ok, thanks. I'll close this PR as this doesn't seem to be Numba's fault.

I'm not entirely sure about that? As I mentioned, the older numba (0.59.1) version does work, even with the latest debugger version.
It seems like **both** the VSCode debugger **and** Numba have changed in their latest releases.

But what's probably needed is a better, more minimal example, e.g. running only debugpy, seeing if that triggers it. It's something I'd like to investigate anyway, but I'm somewhat pressed for time until January or so.
Oh, sorry. I misread the part you said Numba 0.58 works with VSCode. Reopening
i can replicate this on main on osx-64. Problematic lines in the cython code is slightly different though:

```
  File "<stringsource>", line 69, in cfunc.to_py.__Pyx_CFunc_893235__29_pydevd_sys_monitoring_cython_object__lParen__etc_to_py_4code_18instruction_offset.wrap
  File "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx", line 1662, in _pydevd_sys_monitoring_cython._start_method_event
  File "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx", line 562, in _pydevd_sys_monitoring_cython._get_func_code_info
AssertionError: <code object <module> at 0x10ad3bb40, file "/Users/path/to/numba/chk.py", line 1> != <code object f at 0x10b371a70, file "/Users/path/to/numba/chk.py", line 5>
```
Summarizing what I found:

- debugpy is expecting new Python frame for the callee but Numba is not setting up callee frames. 
- As of 3.12, CPython `sys.monitoring` code and documentation are assuming the existence of python code object and frame object but that is contradicting the goal of the low-level monitoring tool. See discussion starting at https://github.com/python/cpython/issues/111997#issuecomment-2122895229
- There's a `PyFrame_New()` with ambiguous status: https://github.com/python/cpython/issues/118746#issuecomment-2099800122. Cython only uses it for pre `sys.monitoring` support: https://github.com/cython/cython/blob/a2b9f55670b765d9b482fd7d8533f2df914e7387/Cython/Utility/Profile.c#L616
- As of 3.13, CPython has new C-API that seems to side-step the frame issue (https://docs.python.org/3.13/c-api/monitoring.html#monitoring-c-api and discussion starting at https://github.com/python/cpython/issues/111997#issuecomment-1903698585). But I expect downstream tools will need time to change up to avoid relying on Python frames. Numba also needs to adapt to this new API.

Commit message: Fix build under py3.12

Patch to review:
diff --git a/docs/source/reference/envvars.rst b/docs/source/reference/envvars.rst
index 25104dd665d..eb63f9a1029 100644
--- a/docs/source/reference/envvars.rst
+++ b/docs/source/reference/envvars.rst
@@ -161,6 +161,16 @@ These variables influence what is printed out during compilation of
 
    If set to non-zero, print out debugging information about type inference.
 
+
+.. envvar:: NUMBA_SYS_MONITORING_DEFAULT
+
+   Controls support for Python's ``sys.monitoring`` feature in Numba. 
+   Disabled by default. When enabled, allows profiling tools that use 
+   ``sys.monitoring`` to work with  Numba code. Currently tested with 
+   ``cProfile``, other monitoring tools may work but are not guaranteed.
+   
+   Only available for Python 3.12 and above. Otherwise, it has no effect.
+
 .. envvar:: NUMBA_ENABLE_PROFILING
 
    Enables JIT events of LLVM in order to support profiling of jitted functions.
diff --git a/numba/_dispatcher.cpp b/numba/_dispatcher.cpp
index 39dc2edf949..86558aedcc5 100644
--- a/numba/_dispatcher.cpp
+++ b/numba/_dispatcher.cpp
@@ -403,6 +403,8 @@ class Dispatcher {
     PyObject_HEAD
     /* Whether compilation of new overloads is permitted */
     char can_compile;
+    /* Enable sys.monitoring (since Python 3.12+) */
+    char enable_sysmon;
     /* Whether fallback to object mode is permitted */
     char can_fallback;
     /* Whether types must match exactly when resolving overloads.
@@ -532,6 +534,7 @@ Dispatcher_init(Dispatcher *self, PyObject *args, PyObject *kwds)
     self->tm = static_cast<TypeManager*>(tmaddr);
     self->argct = argct;
     self->can_compile = 1;
+    self->enable_sysmon = 0;  // default to turn off sys.monitoring
     self->can_fallback = can_fallback;
     self->fallbackdef = NULL;
     self->has_stararg = has_stararg;
@@ -894,7 +897,7 @@ static int invoke_monitoring(PyThreadState * tstate, int event, PyObject *self,
     // https://github.com/python/cpython/blob/0ab2384c5f56625e99bb35417cadddfe24d347e1/Python/instrumentation.c#L945-L1008
     // https://github.com/python/cpython/blob/0ab2384c5f56625e99bb35417cadddfe24d347e1/Python/instrumentation.c#L1010-L1026
     // https://github.com/python/cpython/blob/0ab2384c5f56625e99bb35417cadddfe24d347e1/Python/instrumentation.c#L839-L861
-
+    
     // TODO: check this, call_instrumentation_vector has this at the top.
     if (tstate->tracing){
         return 0;
@@ -1043,6 +1046,9 @@ int static inline invoke_monitoring_PY_UNWIND(PyThreadState * tstate, PyObject *
     return invoke_monitoring(tstate, PY_MONITORING_EVENT_PY_UNWIND, self, exception);
 }
 
+/* forward declaration */
+bool static is_sysmon_enabled(PyObject * self); 
+
 /* A custom, fast, inlinable version of PyCFunction_Call() */
 static PyObject *
 call_cfunc(PyObject *self, PyObject *cfunc, PyObject *args, PyObject *kws, PyObject *locals)
@@ -1051,18 +1057,19 @@ call_cfunc(PyObject *self, PyObject *cfunc, PyObject *args, PyObject *kws, PyObj
     PyThreadState *tstate = NULL;
     PyObject * pyresult = NULL;
     PyObject * pyexception = NULL;
+    const bool enabled_sysmon = is_sysmon_enabled(self);
 
     assert(PyCFunction_Check(cfunc));
     assert(PyCFunction_GET_FLAGS(cfunc) == (METH_VARARGS | METH_KEYWORDS));
     fn = (PyCFunctionWithKeywords) PyCFunction_GET_FUNCTION(cfunc);
     tstate = PyThreadState_GET();
     // issue PY_START if event is set
-    if(invoke_monitoring_PY_START(tstate, self) != 0){
+    if(enabled_sysmon && invoke_monitoring_PY_START(tstate, self) != 0){
         return NULL;
     }
     // make call
     pyresult = fn(PyCFunction_GET_SELF(cfunc), args, kws);
-    if (pyresult == NULL) {
+    if (enabled_sysmon && pyresult == NULL) {
         // pyresult == NULL, which means the Numba function raised an exception
         // which is now pending.
         //
@@ -1107,7 +1114,7 @@ call_cfunc(PyObject *self, PyObject *cfunc, PyObject *args, PyObject *kws, PyObj
         return NULL;
     }
     // issue PY_RETURN if event is set
-    if(invoke_monitoring_PY_RETURN(tstate, self, pyresult) != 0){
+    if(enabled_sysmon && invoke_monitoring_PY_RETURN(tstate, self, pyresult) != 0){
         return NULL;
     }
     return pyresult;
@@ -1538,6 +1545,7 @@ static PyMethodDef Dispatcher_methods[] = {
 
 static PyMemberDef Dispatcher_members[] = {
     {(char*)"_can_compile", T_BOOL, offsetof(Dispatcher, can_compile), 0, NULL },
+    {(char*)"_enable_sysmon", T_BOOL, offsetof(Dispatcher, enable_sysmon), 0, NULL },
     {NULL}  /* Sentinel */
 };
 
@@ -1612,6 +1620,17 @@ static PyTypeObject DispatcherType = {
 };
 
 
+#if (PY_MAJOR_VERSION >= 3) && ((PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13))
+static
+bool is_sysmon_enabled(PyObject * self) {
+    if (PyObject_IsInstance(self, (PyObject*)&DispatcherType)) {
+        Dispatcher* disp = (Dispatcher*)self;
+        return disp->enable_sysmon;
+    }
+    return false;
+}
+#endif
+
 static PyObject *compute_fingerprint(PyObject *self, PyObject *args)
 {
     PyObject *val;
diff --git a/numba/core/config.py b/numba/core/config.py
index 1fa72a1e9bd..360b827f032 100644
--- a/numba/core/config.py
+++ b/numba/core/config.py
@@ -514,6 +514,10 @@ def num_threads_default():
         NUMBA_NUM_THREADS = _NUMBA_NUM_THREADS
         del _NUMBA_NUM_THREADS
 
+        # sys.monitoring support
+        SYS_MONITORING_DEFAULT = _readenv("NUMBA_SYS_MONITORING_DEFAULT",
+                                          int, 0)
+
         # Profiling support
 
         # Indicates if a profiler detected. Only VTune can be detected for now
diff --git a/numba/core/dispatcher.py b/numba/core/dispatcher.py
index c6d1fbebd17..76c4e83a7cb 100644
--- a/numba/core/dispatcher.py
+++ b/numba/core/dispatcher.py
@@ -231,6 +231,7 @@ def __init__(self, arg_count, py_func, pysig, can_fallback,
 
         self.doc = py_func.__doc__
         self._compiling_counter = CompilingCounter()
+        self._enable_sysmon = bool(config.SYS_MONITORING_DEFAULT)
         weakref.finalize(self, self._make_finalizer())
 
     def _compilation_chain_init_hook(self):
diff --git a/numba/tests/test_sys_monitoring.py b/numba/tests/test_sys_monitoring.py
index 5b05816fbfe..c5b27ae476a 100644
--- a/numba/tests/test_sys_monitoring.py
+++ b/numba/tests/test_sys_monitoring.py
@@ -10,7 +10,14 @@
 from numba.core.serialize import _numba_unpickle
 
 
+def _enable_sysmon(disp):
+    """Decorator to enable sys.monitoring on the dispatcher"""
+    disp._enable_sysmon = True
+    return disp
+
+
 def generate_usecase():
+    @_enable_sysmon
     @jit('int64(int64)',)
     def foo(x):
         return x + 1
@@ -312,6 +319,7 @@ def objmode_enable_event(switch_on_event):
                 if switch_on_event:
                     sys.monitoring.set_events(tool_id, event)
 
+            @_enable_sysmon
             @jit('int64(int64)')
             def foo(enable):
                 with objmode:
@@ -413,6 +421,7 @@ def test_raising_under_monitoring(self):
 
         msg = 'exception raised'
 
+        @_enable_sysmon
         @jit('()')
         def foo():
             raise ValueError(msg)
@@ -482,6 +491,7 @@ def test_stop_iteration_under_monitoring(self):
 
         msg = 'exception raised'
 
+        @_enable_sysmon
         @jit('()')
         def foo():
             raise StopIteration(msg)
@@ -592,6 +602,7 @@ def test_raising_callback_unwinds_from_jit_on_raising_path(self):
         class LocalException(Exception):
             pass
 
+        @_enable_sysmon
         @jit("()")
         def raising():
             raise LocalException(msg_execution)
@@ -651,6 +662,7 @@ def test_raising_callback_unwinds_from_jit_on_unwind_path(self):
         class LocalException(Exception):
             pass
 
+        @_enable_sysmon
         @jit("()")
         def raising():
             raise LocalException(msg_execution)
@@ -738,5 +750,35 @@ def test_skipping_of_tests_if_monitoring_in_use(self):
         self.assertIn("skipped=1", str(r))
 
 
+@unittest.skipUnless(PYVERSION >= (3, 12), "needs Python 3.12+")
+class TestMonitoringEnvVarControl(TestCase):
+    @TestCase.run_test_in_subprocess(
+        envvars={"NUMBA_SYS_MONITORING_DEFAULT": ''})
+    def test_default_off(self):
+        @jit
+        def foo(x):
+            return x + 1
+
+        self.assertFalse(foo._enable_sysmon)
+
+    @TestCase.run_test_in_subprocess(
+        envvars={"NUMBA_SYS_MONITORING_DEFAULT": '0'})
+    def test_override_off(self):
+        @jit
+        def foo(x):
+            return x + 1
+
+        self.assertFalse(foo._enable_sysmon)
+
+    @TestCase.run_test_in_subprocess(
+        envvars={"NUMBA_SYS_MONITORING_DEFAULT": '1'})
+    def test_override_on(self):
+        @jit
+        def foo(x):
+            return x + 1
+
+        self.assertTrue(foo._enable_sysmon)
+
+
 if __name__ == '__main__':
     unittest.main()


Code review comments:
diff_hunk: @@ -161,6 +161,16 @@ These variables influence what is printed out during compilation of
 
    If set to non-zero, print out debugging information about type inference.
 
+
+.. envvar:: NUMBA_SYS_MONITORING_DEFAULT
path: docs/source/reference/envvars.rst
text: @user1:
```suggestion
.. envvar:: NUMBA_ENABLE_SYS_MONITORING
```
should it be named this to be consistent with other on/off type of env vars, cf. profiling? Default in which case would be `off` == 0.

@author:
Renamed in https://github.com/numba/numba/pull/9780/commits/31c0af021d491fae47c2d276e5db2dab2617a8f4

@user1:
Thanks.