gh-116968: Reimplement Tier 2 counters (#117144)

Introduce a unified 16-bit backoff counter type (``_Py_BackoffCounter``),
shared between the Tier 1 adaptive specializer and the Tier 2 optimizer. The
API used for adaptive specialization counters is changed but the behavior is
(supposed to be) identical.

The behavior of the Tier 2 counters is changed:
- There are no longer dynamic thresholds (we never varied these).
- All counters now use the same exponential backoff.
- The counter for ``JUMP_BACKWARD`` starts counting down from 16.
- The ``temperature`` in side exits starts counting down from 64.
This commit is contained in:
Guido van Rossum 2024-04-04 08:03:27 -07:00 committed by GitHub
parent 63bbe77d9b
commit 060a96f1a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 313 additions and 235 deletions

View file

@ -10,6 +10,7 @@ import _testinternalcapi
from test.support import script_helper, requires_specialization
from _testinternalcapi import TIER2_THRESHOLD
@contextlib.contextmanager
def temporary_optimizer(opt):
@ -69,7 +70,8 @@ class TestOptimizerAPI(unittest.TestCase):
self.assertEqual(opt.get_count(), 0)
with clear_executors(loop):
loop()
self.assertEqual(opt.get_count(), 1000)
# Subtract because optimizer doesn't kick in sooner
self.assertEqual(opt.get_count(), 1000 - TIER2_THRESHOLD)
def test_long_loop(self):
"Check that we aren't confused by EXTENDED_ARG"
@ -81,7 +83,7 @@ class TestOptimizerAPI(unittest.TestCase):
pass
def long_loop():
for _ in range(10):
for _ in range(20):
nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
@ -96,7 +98,7 @@ class TestOptimizerAPI(unittest.TestCase):
with temporary_optimizer(opt):
self.assertEqual(opt.get_count(), 0)
long_loop()
self.assertEqual(opt.get_count(), 10)
self.assertEqual(opt.get_count(), 20 - TIER2_THRESHOLD) # Need iterations to warm up
def test_code_restore_for_ENTER_EXECUTOR(self):
def testfunc(x):
@ -932,10 +934,10 @@ class TestUopsOptimization(unittest.TestCase):
exec(src, ns, ns)
testfunc = ns['testfunc']
ns['_test_global'] = 0
_, ex = self._run_with_optimizer(testfunc, 16)
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertIsNone(ex)
ns['_test_global'] = 1
_, ex = self._run_with_optimizer(testfunc, 16)
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertNotIn("_GUARD_BOTH_INT", uops)
@ -946,10 +948,10 @@ class TestUopsOptimization(unittest.TestCase):
exec(src, ns, ns)
testfunc = ns['testfunc']
ns['_test_global'] = 0
_, ex = self._run_with_optimizer(testfunc, 16)
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertIsNone(ex)
ns['_test_global'] = 3.14
_, ex = self._run_with_optimizer(testfunc, 16)
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertIsNone(ex)
def test_combine_stack_space_checks_sequential(self):