From 21cca475f8f7a62fbb7c5bf42603d47ac7ac0824 Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Mon, 11 Nov 2024 20:06:43 +0800 Subject: [PATCH 1/7] remove `_PyOptimizer_NewCounter` --- Include/internal/pycore_optimizer.h | 1 - Lib/test/test_monitoring.py | 29 ----------------------------- Modules/_testinternalcapi.c | 7 ------- Python/optimizer.c | 12 ------------ 4 files changed, 49 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index bc7cfcde613d65..9aa537497918cb 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -119,7 +119,6 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); // Export for '_testinternalcapi' shared extension. PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); -PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void); PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 32b3a6ac049e28..a0fd161f9ad5fc 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -2003,35 +2003,6 @@ def callback(code, instruction_offset): sys.monitoring.set_events(0, 0) -class TestOptimizer(MonitoringTestBase, unittest.TestCase): - - def setUp(self): - _testinternalcapi = import_module("_testinternalcapi") - if hasattr(_testinternalcapi, "get_optimizer"): - self.old_opt = _testinternalcapi.get_optimizer() - opt = _testinternalcapi.new_counter_optimizer() - _testinternalcapi.set_optimizer(opt) - super(TestOptimizer, self).setUp() - - def tearDown(self): - super(TestOptimizer, self).tearDown() - import _testinternalcapi - if hasattr(_testinternalcapi, "get_optimizer"): - _testinternalcapi.set_optimizer(self.old_opt) - - def test_for_loop(self): - def test_func(x): - i = 0 - while i < x: - i += 1 - - code = test_func.__code__ - sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START) - self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START) - test_func(1000) - sys.monitoring.set_local_events(TEST_TOOL, code, 0) - self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0) - class TestTier2Optimizer(CheckEvents): def test_monitoring_already_opimized_loop(self): diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 150d34d168f5e4..38a8e31f1d105b 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -989,12 +989,6 @@ get_co_framesize(PyObject *self, PyObject *arg) #ifdef _Py_TIER2 -static PyObject * -new_counter_optimizer(PyObject *self, PyObject *arg) -{ - return _PyOptimizer_NewCounter(); -} - static PyObject * new_uop_optimizer(PyObject *self, PyObject *arg) { @@ -2101,7 +2095,6 @@ static PyMethodDef module_functions[] = { #ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, - {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, diff --git a/Python/optimizer.c b/Python/optimizer.c index 6a4d20fad76c15..b17765dfe0b43f 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1404,18 +1404,6 @@ PyTypeObject _PyCounterOptimizer_Type = { .tp_dealloc = (destructor)PyObject_Free, }; -PyObject * -_PyOptimizer_NewCounter(void) -{ - _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type); - if (opt == NULL) { - return NULL; - } - opt->base.optimize = counter_optimize; - opt->count = 0; - return (PyObject *)opt; -} - /***************************************** * Executor management From 3a6ad0226bbb9f9313964664814ccd068724b6ba Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Fri, 15 Nov 2024 11:00:54 +0800 Subject: [PATCH 2/7] remove uop optimize tests --- Lib/test/test_capi/test_opt.py | 6 ++++-- Modules/_testinternalcapi.c | 7 ------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 4cf9b66170c055..0db89dcc83a289 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -140,7 +140,8 @@ def get_opnames(ex): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and + hasattr(_testinternalcapi, "new_uop_optimizer"), "Requires optimizer infrastructure") class TestExecutorInvalidation(unittest.TestCase): @@ -588,7 +589,8 @@ def testfunc(n): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and + hasattr(_testinternalcapi, "new_uop_optimizer"), "Requires optimizer infrastructure") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 38a8e31f1d105b..2e57fbee2fd4fd 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -989,12 +989,6 @@ get_co_framesize(PyObject *self, PyObject *arg) #ifdef _Py_TIER2 -static PyObject * -new_uop_optimizer(PyObject *self, PyObject *arg) -{ - return _PyOptimizer_NewUOpOptimizer(); -} - static PyObject * set_optimizer(PyObject *self, PyObject *opt) { @@ -2095,7 +2089,6 @@ static PyMethodDef module_functions[] = { #ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, - {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, #endif From 2972b06c64c205d9a6a210aa82293bc767e1cb39 Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Fri, 15 Nov 2024 11:33:52 +0800 Subject: [PATCH 3/7] remove `_PyOptimizer_NewUOpOptimizer` --- Include/internal/pycore_optimizer.h | 2 +- Python/optimizer.c | 9 ++------- Python/pylifecycle.c | 3 ++- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 9aa537497918cb..0c238824182c51 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -119,7 +119,7 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); // Export for '_testinternalcapi' shared extension. PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); -PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); +PyAPI_FUNC(void) _Py_SetUOpOptimize(_PyOptimizerObject* opt); #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 #define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6 diff --git a/Python/optimizer.c b/Python/optimizer.c index b17765dfe0b43f..7aa7e6ae63f2f7 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1315,15 +1315,10 @@ PyTypeObject _PyUOpOptimizer_Type = { .tp_dealloc = uop_opt_dealloc, }; -PyObject * -_PyOptimizer_NewUOpOptimizer(void) +void +_Py_SetUOpOptimize(_PyOptimizerObject *opt) { - _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); - if (opt == NULL) { - return NULL; - } opt->optimize = uop_optimize; - return (PyObject *)opt; } static void diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 06418123d6dd9b..5311ae1b9fc6ba 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1334,10 +1334,11 @@ init_interp_main(PyThreadState *tstate) } else #endif { - PyObject *opt = _PyOptimizer_NewUOpOptimizer(); + PyObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); if (opt == NULL) { return _PyStatus_ERR("can't initialize optimizer"); } + _Py_SetUOpOptimize((_PyOptimizerObject *)opt); if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { return _PyStatus_ERR("can't install optimizer"); } From 0c724904ef209c2895e3d04611e6973bd6ff69cc Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Fri, 15 Nov 2024 18:23:47 +0800 Subject: [PATCH 4/7] revert commits --- Include/internal/pycore_optimizer.h | 3 +- Lib/test/test_capi/test_opt.py | 88 +++++++++++++++++++++++++++-- Lib/test/test_monitoring.py | 29 ++++++++++ Modules/_testinternalcapi.c | 14 +++++ Python/optimizer.c | 21 ++++++- Python/pylifecycle.c | 3 +- 6 files changed, 149 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 0c238824182c51..bc7cfcde613d65 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -119,7 +119,8 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); // Export for '_testinternalcapi' shared extension. PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); -PyAPI_FUNC(void) _Py_SetUOpOptimize(_PyOptimizerObject* opt); +PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void); +PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 #define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6 diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0db89dcc83a289..16cba170c52e9a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -140,8 +140,89 @@ def get_opnames(ex): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and - hasattr(_testinternalcapi, "new_uop_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), + "Requires optimizer infrastructure") +class TestExecutorInvalidation(unittest.TestCase): + + def setUp(self): + self.old = _testinternalcapi.get_optimizer() + self.opt = _testinternalcapi.new_counter_optimizer() + _testinternalcapi.set_optimizer(self.opt) + + def tearDown(self): + _testinternalcapi.set_optimizer(self.old) + + def test_invalidate_object(self): + # Generate a new set of functions at each call + ns = {} + func_src = "\n".join( + f""" + def f{n}(): + for _ in range(1000): + pass + """ for n in range(5) + ) + exec(textwrap.dedent(func_src), ns, ns) + funcs = [ ns[f'f{n}'] for n in range(5)] + objects = [object() for _ in range(5)] + + for f in funcs: + f() + executors = [get_first_executor(f) for f in funcs] + # Set things up so each executor depends on the objects + # with an equal or lower index. + for i, exe in enumerate(executors): + self.assertTrue(exe.is_valid()) + for obj in objects[:i+1]: + _testinternalcapi.add_executor_dependency(exe, obj) + self.assertTrue(exe.is_valid()) + # Assert that the correct executors are invalidated + # and check that nothing crashes when we invalidate + # an executor multiple times. + for i in (4,3,2,1,0): + _testinternalcapi.invalidate_executors(objects[i]) + for exe in executors[i:]: + self.assertFalse(exe.is_valid()) + for exe in executors[:i]: + self.assertTrue(exe.is_valid()) + + def test_uop_optimizer_invalidation(self): + # Generate a new function at each call + ns = {} + exec(textwrap.dedent(""" + def f(): + for i in range(1000): + pass + """), ns, ns) + f = ns['f'] + opt = _testinternalcapi.new_uop_optimizer() + with temporary_optimizer(opt): + f() + exe = get_first_executor(f) + self.assertIsNotNone(exe) + self.assertTrue(exe.is_valid()) + _testinternalcapi.invalidate_executors(f.__code__) + self.assertFalse(exe.is_valid()) + + def test_sys__clear_internal_caches(self): + def f(): + for _ in range(1000): + pass + opt = _testinternalcapi.new_uop_optimizer() + with temporary_optimizer(opt): + f() + exe = get_first_executor(f) + self.assertIsNotNone(exe) + self.assertTrue(exe.is_valid()) + sys._clear_internal_caches() + self.assertFalse(exe.is_valid()) + exe = get_first_executor(f) + self.assertIsNone(exe) + + +@requires_specialization +@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), "Requires optimizer infrastructure") class TestExecutorInvalidation(unittest.TestCase): @@ -589,8 +670,7 @@ def testfunc(n): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and - hasattr(_testinternalcapi, "new_uop_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), "Requires optimizer infrastructure") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index a0fd161f9ad5fc..32b3a6ac049e28 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -2003,6 +2003,35 @@ def callback(code, instruction_offset): sys.monitoring.set_events(0, 0) +class TestOptimizer(MonitoringTestBase, unittest.TestCase): + + def setUp(self): + _testinternalcapi = import_module("_testinternalcapi") + if hasattr(_testinternalcapi, "get_optimizer"): + self.old_opt = _testinternalcapi.get_optimizer() + opt = _testinternalcapi.new_counter_optimizer() + _testinternalcapi.set_optimizer(opt) + super(TestOptimizer, self).setUp() + + def tearDown(self): + super(TestOptimizer, self).tearDown() + import _testinternalcapi + if hasattr(_testinternalcapi, "get_optimizer"): + _testinternalcapi.set_optimizer(self.old_opt) + + def test_for_loop(self): + def test_func(x): + i = 0 + while i < x: + i += 1 + + code = test_func.__code__ + sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START) + test_func(1000) + sys.monitoring.set_local_events(TEST_TOOL, code, 0) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0) + class TestTier2Optimizer(CheckEvents): def test_monitoring_already_opimized_loop(self): diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 2e57fbee2fd4fd..150d34d168f5e4 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -989,6 +989,18 @@ get_co_framesize(PyObject *self, PyObject *arg) #ifdef _Py_TIER2 +static PyObject * +new_counter_optimizer(PyObject *self, PyObject *arg) +{ + return _PyOptimizer_NewCounter(); +} + +static PyObject * +new_uop_optimizer(PyObject *self, PyObject *arg) +{ + return _PyOptimizer_NewUOpOptimizer(); +} + static PyObject * set_optimizer(PyObject *self, PyObject *opt) { @@ -2089,6 +2101,8 @@ static PyMethodDef module_functions[] = { #ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, + {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, + {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 7aa7e6ae63f2f7..6a4d20fad76c15 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1315,10 +1315,15 @@ PyTypeObject _PyUOpOptimizer_Type = { .tp_dealloc = uop_opt_dealloc, }; -void -_Py_SetUOpOptimize(_PyOptimizerObject *opt) +PyObject * +_PyOptimizer_NewUOpOptimizer(void) { + _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); + if (opt == NULL) { + return NULL; + } opt->optimize = uop_optimize; + return (PyObject *)opt; } static void @@ -1399,6 +1404,18 @@ PyTypeObject _PyCounterOptimizer_Type = { .tp_dealloc = (destructor)PyObject_Free, }; +PyObject * +_PyOptimizer_NewCounter(void) +{ + _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type); + if (opt == NULL) { + return NULL; + } + opt->base.optimize = counter_optimize; + opt->count = 0; + return (PyObject *)opt; +} + /***************************************** * Executor management diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5311ae1b9fc6ba..06418123d6dd9b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1334,11 +1334,10 @@ init_interp_main(PyThreadState *tstate) } else #endif { - PyObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); + PyObject *opt = _PyOptimizer_NewUOpOptimizer(); if (opt == NULL) { return _PyStatus_ERR("can't initialize optimizer"); } - _Py_SetUOpOptimize((_PyOptimizerObject *)opt); if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { return _PyStatus_ERR("can't install optimizer"); } From 910be983225879d68d6a631b06320791e5cadcb5 Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Fri, 15 Nov 2024 21:10:21 +0800 Subject: [PATCH 5/7] add export explanation --- Include/internal/pycore_optimizer.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index bc7cfcde613d65..684c636f5b6557 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -113,6 +113,8 @@ void _Py_ExecutorInit(_PyExecutorObject *, const _PyBloomFilter *); void _Py_ExecutorDetach(_PyExecutorObject *); void _Py_BloomFilter_Init(_PyBloomFilter *); void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj); + +// Export for '_testinternalcapi' shared extension. PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); // For testing @@ -276,6 +278,7 @@ extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx); PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); +// Export for '_testinternalcapi' shared extension. PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyStackRef *stack_pointer, _PyExecutorObject **exec_ptr, int chain_depth); static inline int is_terminator(const _PyUOpInstruction *uop) From 3f891463f84ae7205bec678b2d6335e25314d3d8 Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Sat, 23 Nov 2024 23:49:16 +0800 Subject: [PATCH 6/7] remove `_PyCounterOptimizer_Type` and `_PyOptimizer_NewCounter` --- Include/internal/pycore_optimizer.h | 2 - Lib/test/test_capi/test_opt.py | 88 ++-------------------------- Lib/test/test_monitoring.py | 4 +- Modules/_testinternalcapi.c | 7 --- Objects/object.c | 1 - Python/optimizer.c | 22 ------- Tools/c-analyzer/cpython/ignored.tsv | 1 - 7 files changed, 7 insertions(+), 118 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 684c636f5b6557..cce19786b44dc6 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -121,7 +121,6 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); // Export for '_testinternalcapi' shared extension. PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); -PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void); PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 @@ -153,7 +152,6 @@ int _Py_uop_analyze_and_optimize(struct _PyInterpreterFrame *frame, _PyBloomFilter *dependencies); extern PyTypeObject _PyCounterExecutor_Type; -extern PyTypeObject _PyCounterOptimizer_Type; extern PyTypeObject _PyDefaultOptimizer_Type; extern PyTypeObject _PyUOpExecutor_Type; extern PyTypeObject _PyUOpOptimizer_Type; diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 16cba170c52e9a..b914b02596a6c1 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -36,7 +36,8 @@ def clear_executors(func): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and + hasattr(_testinternalcapi, "new_counter_optimizer"), "Requires optimizer infrastructure") class TestOptimizerAPI(unittest.TestCase): @@ -140,89 +141,8 @@ def get_opnames(ex): @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), - "Requires optimizer infrastructure") -class TestExecutorInvalidation(unittest.TestCase): - - def setUp(self): - self.old = _testinternalcapi.get_optimizer() - self.opt = _testinternalcapi.new_counter_optimizer() - _testinternalcapi.set_optimizer(self.opt) - - def tearDown(self): - _testinternalcapi.set_optimizer(self.old) - - def test_invalidate_object(self): - # Generate a new set of functions at each call - ns = {} - func_src = "\n".join( - f""" - def f{n}(): - for _ in range(1000): - pass - """ for n in range(5) - ) - exec(textwrap.dedent(func_src), ns, ns) - funcs = [ ns[f'f{n}'] for n in range(5)] - objects = [object() for _ in range(5)] - - for f in funcs: - f() - executors = [get_first_executor(f) for f in funcs] - # Set things up so each executor depends on the objects - # with an equal or lower index. - for i, exe in enumerate(executors): - self.assertTrue(exe.is_valid()) - for obj in objects[:i+1]: - _testinternalcapi.add_executor_dependency(exe, obj) - self.assertTrue(exe.is_valid()) - # Assert that the correct executors are invalidated - # and check that nothing crashes when we invalidate - # an executor multiple times. - for i in (4,3,2,1,0): - _testinternalcapi.invalidate_executors(objects[i]) - for exe in executors[i:]: - self.assertFalse(exe.is_valid()) - for exe in executors[:i]: - self.assertTrue(exe.is_valid()) - - def test_uop_optimizer_invalidation(self): - # Generate a new function at each call - ns = {} - exec(textwrap.dedent(""" - def f(): - for i in range(1000): - pass - """), ns, ns) - f = ns['f'] - opt = _testinternalcapi.new_uop_optimizer() - with temporary_optimizer(opt): - f() - exe = get_first_executor(f) - self.assertIsNotNone(exe) - self.assertTrue(exe.is_valid()) - _testinternalcapi.invalidate_executors(f.__code__) - self.assertFalse(exe.is_valid()) - - def test_sys__clear_internal_caches(self): - def f(): - for _ in range(1000): - pass - opt = _testinternalcapi.new_uop_optimizer() - with temporary_optimizer(opt): - f() - exe = get_first_executor(f) - self.assertIsNotNone(exe) - self.assertTrue(exe.is_valid()) - sys._clear_internal_caches() - self.assertFalse(exe.is_valid()) - exe = get_first_executor(f) - self.assertIsNone(exe) - - -@requires_specialization -@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") -@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and + hasattr(_testinternalcapi, "new_counter_optimizer"), "Requires optimizer infrastructure") class TestExecutorInvalidation(unittest.TestCase): diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 32b3a6ac049e28..e9389de914de6a 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -15,6 +15,7 @@ from test.support.import_helper import import_module _testcapi = test.support.import_helper.import_module("_testcapi") +_testinternalcapi = test.support.import_helper.import_module("_testinternalcapi") PAIR = (0,1) @@ -2003,10 +2004,11 @@ def callback(code, instruction_offset): sys.monitoring.set_events(0, 0) +@unittest.skipUnless(hasattr(_testinternalcapi, "new_counter_optimizer"), + "Requires counter optimizer") class TestOptimizer(MonitoringTestBase, unittest.TestCase): def setUp(self): - _testinternalcapi = import_module("_testinternalcapi") if hasattr(_testinternalcapi, "get_optimizer"): self.old_opt = _testinternalcapi.get_optimizer() opt = _testinternalcapi.new_counter_optimizer() diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 150d34d168f5e4..38a8e31f1d105b 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -989,12 +989,6 @@ get_co_framesize(PyObject *self, PyObject *arg) #ifdef _Py_TIER2 -static PyObject * -new_counter_optimizer(PyObject *self, PyObject *arg) -{ - return _PyOptimizer_NewCounter(); -} - static PyObject * new_uop_optimizer(PyObject *self, PyObject *arg) { @@ -2101,7 +2095,6 @@ static PyMethodDef module_functions[] = { #ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, - {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, diff --git a/Objects/object.c b/Objects/object.c index 4c30257ca26938..8354ae8cfd0cd4 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2380,7 +2380,6 @@ static PyTypeObject* static_types[] = { &_PyCoroWrapper_Type, #ifdef _Py_TIER2 &_PyCounterExecutor_Type, - &_PyCounterOptimizer_Type, &_PyDefaultOptimizer_Type, #endif &_Py_GenericAliasIterType, diff --git a/Python/optimizer.c b/Python/optimizer.c index 6a4d20fad76c15..272eb87752e06a 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1394,28 +1394,6 @@ static PyMethodDef counter_optimizer_methods[] = { { NULL, NULL }, }; -PyTypeObject _PyCounterOptimizer_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - .tp_name = "Counter optimizer", - .tp_basicsize = sizeof(_PyCounterOptimizerObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, - .tp_methods = counter_optimizer_methods, - .tp_dealloc = (destructor)PyObject_Free, -}; - -PyObject * -_PyOptimizer_NewCounter(void) -{ - _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type); - if (opt == NULL) { - return NULL; - } - opt->base.optimize = counter_optimize; - opt->count = 0; - return (PyObject *)opt; -} - /***************************************** * Executor management diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index c8c30a7985aa2e..09bd16acaf1e8b 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -385,7 +385,6 @@ Python/sysmodule.c - _PySys_ImplName - Python/sysmodule.c - whatstrings - Python/optimizer.c - _PyDefaultOptimizer_Type - Python/optimizer.c - _PyCounterExecutor_Type - -Python/optimizer.c - _PyCounterOptimizer_Type - Python/optimizer.c - _PyUOpExecutor_Type - Python/optimizer.c - _PyUOpOptimizer_Type - Python/optimizer.c - _PyOptimizer_Default - From 843d1db99a26fafd6363311248c8b53159a08dcc Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 03:25:39 +0000 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/C_API/2025-01-01-03-25-38.gh-issue-126599.MRCYlH.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/C_API/2025-01-01-03-25-38.gh-issue-126599.MRCYlH.rst diff --git a/Misc/NEWS.d/next/C_API/2025-01-01-03-25-38.gh-issue-126599.MRCYlH.rst b/Misc/NEWS.d/next/C_API/2025-01-01-03-25-38.gh-issue-126599.MRCYlH.rst new file mode 100644 index 00000000000000..d441c95d34d6c9 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-01-01-03-25-38.gh-issue-126599.MRCYlH.rst @@ -0,0 +1 @@ +Remove the internal opmization API ``_PyOptimizer_NewCounter``.