GH-129386: Use symbolic constants for specialization tests (GH-129415)

This commit is contained in:
Brandt Bucher 2025-01-29 10:49:58 -08:00 committed by GitHub
parent 99ed3025fe
commit 002c4e2982
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 152 additions and 132 deletions

View file

@ -1,6 +1,6 @@
import unittest
from test.support import (cpython_only, is_wasi, requires_limited_api, Py_DEBUG,
set_recursion_limit, skip_on_s390x, skip_emscripten_stack_overflow)
set_recursion_limit, skip_on_s390x, skip_emscripten_stack_overflow, import_helper)
try:
import _testcapi
except ImportError:
@ -616,9 +616,6 @@ def testfunction_kw(self, *, kw):
return self
ADAPTIVE_WARMUP_DELAY = 2
@unittest.skipIf(_testcapi is None, "requires _testcapi")
class TestPEP590(unittest.TestCase):
@ -802,17 +799,18 @@ class TestPEP590(unittest.TestCase):
def test_setvectorcall(self):
from _testcapi import function_setvectorcall
_testinternalcapi = import_helper.import_module("_testinternalcapi")
def f(num): return num + 1
assert_equal = self.assertEqual
num = 10
assert_equal(11, f(num))
function_setvectorcall(f)
# make sure specializer is triggered by running > 50 times
for _ in range(10 * ADAPTIVE_WARMUP_DELAY):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
assert_equal("overridden", f(num))
def test_setvectorcall_load_attr_specialization_skip(self):
from _testcapi import function_setvectorcall
_testinternalcapi = import_helper.import_module("_testinternalcapi")
class X:
def __getattribute__(self, attr):
@ -824,11 +822,12 @@ class TestPEP590(unittest.TestCase):
function_setvectorcall(X.__getattribute__)
# make sure specialization doesn't trigger
# when vectorcall is overridden
for _ in range(ADAPTIVE_WARMUP_DELAY):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
assert_equal("overridden", x.a)
def test_setvectorcall_load_attr_specialization_deopt(self):
from _testcapi import function_setvectorcall
_testinternalcapi = import_helper.import_module("_testinternalcapi")
class X:
def __getattribute__(self, attr):
@ -840,12 +839,12 @@ class TestPEP590(unittest.TestCase):
assert_equal = self.assertEqual
x = X()
# trigger LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN specialization
for _ in range(ADAPTIVE_WARMUP_DELAY):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
assert_equal("a", get_a(x))
function_setvectorcall(X.__getattribute__)
# make sure specialized LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN
# gets deopted due to overridden vectorcall
for _ in range(ADAPTIVE_WARMUP_DELAY):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
assert_equal("overridden", get_a(x))
@requires_limited_api

View file

@ -931,8 +931,6 @@ dis_extended_arg_quick_code = """\
"""% (extended_arg_quick.__code__.co_firstlineno,
extended_arg_quick.__code__.co_firstlineno + 1,)
ADAPTIVE_WARMUP_DELAY = 2
class DisTestBase(unittest.TestCase):
"Common utilities for DisTests and TestDisTraceback"
@ -1259,8 +1257,9 @@ class DisTests(DisTestBase):
self.assertIsNone(e.__context__)
@staticmethod
def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY):
for _ in range(times):
def code_quicken(f):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
f()
@cpython_only
@ -1306,7 +1305,7 @@ class DisTests(DisTestBase):
@requires_specialization
def test_loop_quicken(self):
# Loop can trigger a quicken where the loop is located
self.code_quicken(loop_test, 4)
self.code_quicken(loop_test)
got = self.get_disassembly(loop_test, adaptive=True)
jit = import_helper.import_module("_testinternalcapi").jit_enabled()
expected = dis_loop_test_quickened_code.format("JIT" if jit else "NO_JIT")
@ -1315,8 +1314,9 @@ class DisTests(DisTestBase):
@cpython_only
@requires_specialization
def test_loop_with_conditional_at_end_is_quickened(self):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
def for_loop_true(x):
for i in range(10):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
if x:
pass
@ -1325,7 +1325,7 @@ class DisTests(DisTestBase):
self.get_disassembly(for_loop_true, adaptive=True))
def for_loop_false(x):
for i in range(10):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
if x:
pass
@ -1335,7 +1335,7 @@ class DisTests(DisTestBase):
def while_loop():
i = 0
while i < 10:
while i < _testinternalcapi.SPECIALIZATION_THRESHOLD:
i += 1
while_loop()

View file

@ -384,7 +384,9 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self):
# https://github.com/python/cpython/issues/92031
code = textwrap.dedent("""\
_testinternalcapi = import_helper.import_module("_testinternalcapi")
code = textwrap.dedent(f"""\
import dis
import importlib._bootstrap
import opcode
@ -411,7 +413,7 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
assert not is_specialized(func), "specialized instructions found"
for i in range(test.test_dis.ADAPTIVE_WARMUP_DELAY):
for _ in range({_testinternalcapi.SPECIALIZATION_THRESHOLD}):
func(importlib._bootstrap, ["x"], lambda *args: None)
assert is_specialized(func), "no specialized instructions found"

View file

@ -14,6 +14,7 @@ import test.support
from test.support import requires_specialization_ft, script_helper
_testcapi = test.support.import_helper.import_module("_testcapi")
_testinternalcapi = test.support.import_helper.import_module("_testinternalcapi")
PAIR = (0,1)
@ -897,13 +898,13 @@ class ExceptionMonitoringTest(CheckEvents):
# re-specialize immediately, so that we can we can test the
# unspecialized version of the loop first.
# Note: this assumes that we don't specialize loops over sets.
implicit_stop_iteration(set(range(100)))
implicit_stop_iteration(set(range(_testinternalcapi.SPECIALIZATION_THRESHOLD)))
# This will record a RAISE event for the StopIteration.
self.check_events(implicit_stop_iteration, expected, recorders=recorders)
# Now specialize, so that we see a STOP_ITERATION event.
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
implicit_stop_iteration()
# This will record a STOP_ITERATION event for the StopIteration.
@ -1057,7 +1058,7 @@ class ExceptionMonitoringTest(CheckEvents):
except ValueError:
pass
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
f()
recorders = (
ReturnRecorder,
@ -2033,8 +2034,8 @@ class TestRegressions(MonitoringTestBase, unittest.TestCase):
sys.monitoring.set_events(TEST_TOOL, E.PY_RESUME)
def make_foo_optimized_then_set_event():
for i in range(100):
Foo(i == 99)
for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 1):
Foo(i == _testinternalcapi.SPECIALIZATION_THRESHOLD)
try:
make_foo_optimized_then_set_event()
@ -2106,9 +2107,9 @@ class TestTier2Optimizer(CheckEvents):
set_events = sys.monitoring.set_events
line = E.LINE
i = 0
for i in range(551):
# Turn on events without branching once i reaches 500.
set_events(TEST_TOOL, line * int(i >= 500))
for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 51):
# Turn on events without branching once i reaches _testinternalcapi.SPECIALIZATION_THRESHOLD.
set_events(TEST_TOOL, line * int(i >= _testinternalcapi.SPECIALIZATION_THRESHOLD))
pass
pass
pass

View file

@ -45,7 +45,8 @@ class TestLoadSuperAttrCache(unittest.TestCase):
d = D()
self.assertEqual(d.f(), 1) # warmup
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD - 1):
self.assertEqual(d.f(), 1) # warmup
calls.clear()
self.assertEqual(d.f(), 1) # try to specialize
self.assertEqual(calls, [(d, D)])
@ -65,7 +66,7 @@ class TestLoadAttrCache(unittest.TestCase):
return o.x
o = C()
for i in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
assert f(o) == 1
Descriptor.__get__ = lambda self, instance, value: 2
@ -92,13 +93,13 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Descriptor.__get__ = __get__
Descriptor.__set__ = __set__
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_metaclass_descriptor_shadows_class_attribute(self):
@ -113,7 +114,7 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
def test_metaclass_set_descriptor_after_optimization(self):
@ -130,12 +131,12 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Metaclass.attribute = attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_metaclass_del_descriptor_after_optimization(self):
@ -150,12 +151,12 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
del Metaclass.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_type_descriptor_shadows_attribute_method(self):
@ -165,7 +166,7 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.mro
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertIsNone(f())
def test_type_descriptor_shadows_attribute_member(self):
@ -175,7 +176,7 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.__base__
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertIs(f(), object)
def test_type_descriptor_shadows_attribute_getset(self):
@ -185,7 +186,7 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.__name__
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertEqual(f(), "Class")
def test_metaclass_getattribute(self):
@ -199,7 +200,7 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
def test_metaclass_swap(self):
@ -219,12 +220,12 @@ class TestLoadAttrCache(unittest.TestCase):
def f():
return Class.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Class.__class__ = NewMetaclass
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_load_shadowing_slot_should_raise_type_error(self):
@ -241,7 +242,7 @@ class TestLoadAttrCache(unittest.TestCase):
o = Sneaky()
o.shadowed = 42
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
with self.assertRaises(TypeError):
f(o)
@ -258,7 +259,7 @@ class TestLoadAttrCache(unittest.TestCase):
o = Sneaky()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
with self.assertRaises(TypeError):
f(o)
@ -274,7 +275,7 @@ class TestLoadAttrCache(unittest.TestCase):
o = Sneaky()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
with self.assertRaises(TypeError):
f(o)
@ -290,7 +291,7 @@ class TestLoadAttrCache(unittest.TestCase):
o = Sneaky()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
with self.assertRaises(TypeError):
f(o)
@ -318,13 +319,13 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return instance.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Descriptor.__get__ = __get__
Descriptor.__set__ = __set__
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_metaclass_descriptor_added_after_optimization(self):
@ -347,13 +348,13 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Descriptor.__get__ = __get__
Descriptor.__set__ = __set__
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_metaclass_descriptor_shadows_class_attribute(self):
@ -369,7 +370,7 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
def test_metaclass_set_descriptor_after_optimization(self):
@ -387,12 +388,12 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Metaclass.attribute = attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_metaclass_del_descriptor_after_optimization(self):
@ -408,12 +409,12 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
del Metaclass.attribute
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
def test_type_descriptor_shadows_attribute_method(self):
@ -424,7 +425,7 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.mro()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertEqual(f(), ["Spam", "eggs"])
def test_type_descriptor_shadows_attribute_member(self):
@ -435,7 +436,7 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.__base__()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertNotEqual(f(), "Spam")
def test_metaclass_getattribute(self):
@ -450,7 +451,7 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
def test_metaclass_swap(self):
@ -470,12 +471,12 @@ class TestLoadMethodCache(unittest.TestCase):
def f():
return Class.attribute()
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertTrue(f())
Class.__class__ = NewMetaclass
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertFalse(f())
@ -490,7 +491,7 @@ class TestCallCache(TestBase):
pass
f.__defaults__ = (None,)
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
f()
def test_too_many_defaults_1(self):
@ -498,7 +499,7 @@ class TestCallCache(TestBase):
pass
f.__defaults__ = (None, None)
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
f(None)
f()
@ -507,7 +508,7 @@ class TestCallCache(TestBase):
pass
f.__defaults__ = (None, None, None)
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
f(None, None)
f(None)
f()
@ -523,7 +524,7 @@ class TestCallCache(TestBase):
return MyClass()
# Trigger specialization
for _ in range(1025):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
instantiate()
self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT")
@ -541,7 +542,7 @@ class TestCallCache(TestBase):
def instantiate():
return InitTakesArg()
for _ in range(2):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
with self.assertRaises(TypeError):
instantiate()
self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT")
@ -566,7 +567,6 @@ class TestRacesDoNotCrash(TestBase):
# but you can also burn through a *ton* of type/dict/function versions:
ITEMS = 1000
LOOPS = 4
WARMUPS = 2
WRITERS = 2
@requires_jit_disabled
@ -583,7 +583,7 @@ class TestRacesDoNotCrash(TestBase):
else:
read.__code__ = read.__code__.replace()
# Specialize:
for _ in range(self.WARMUPS):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
read(items)
if check_items:
for item in items:
@ -1011,7 +1011,7 @@ class TestRacesDoNotCrash(TestBase):
item = C()
item.a = None
# Resize into a combined unicode dict:
for i in range(29):
for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1):
setattr(item, f"_{i}", None)
items.append(item)
return items
@ -1082,7 +1082,7 @@ class TestRacesDoNotCrash(TestBase):
for _ in range(self.ITEMS):
item = C()
# Resize into a combined unicode dict:
for i in range(29):
for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1):
setattr(item, f"_{i}", None)
items.append(item)
return items
@ -1178,7 +1178,7 @@ class TestInstanceDict(unittest.TestCase):
c.a = 1
c.b = 2
c.__dict__
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
self.assertEqual(
_testinternalcapi.get_object_dict_values(c),
@ -1190,7 +1190,7 @@ class TestInstanceDict(unittest.TestCase):
c.a = 1
c.b = 2
d = c.__dict__
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
self.assertIs(c.__dict__, d)
@ -1199,7 +1199,7 @@ class TestInstanceDict(unittest.TestCase):
c.a = 1
c.b = 2
c2 = copy.copy(c)
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
c2.a
self.assertEqual(
@ -1211,7 +1211,7 @@ class TestInstanceDict(unittest.TestCase):
(1, 2, '<NULL>')
)
c3 = copy.deepcopy(c)
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
c3.a
self.assertEqual(
@ -1225,7 +1225,7 @@ class TestInstanceDict(unittest.TestCase):
c.a = 1
c.b = 2
c2 = pickle.loads(pickle.dumps(c))
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
c2.a
self.assertEqual(
@ -1243,7 +1243,7 @@ class TestInstanceDict(unittest.TestCase):
c.a = 1
c.b = 2
c.__dict__ = D(c.__dict__)
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
c.a
self.assertIs(
_testinternalcapi.get_object_dict_values(c),
@ -1288,7 +1288,7 @@ class TestInstanceDict(unittest.TestCase):
for i in range(n):
o.b = i
# Prime f to store to dict slot 1
f(c, 100)
f(c, _testinternalcapi.SPECIALIZATION_THRESHOLD)
test_obj = NoInlineAorB()
test_obj.__dict__ = make_special_dict()
@ -1305,7 +1305,7 @@ class TestSpecializer(TestBase):
@requires_specialization_ft
def test_binary_op(self):
def binary_op_add_int():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1, 2
c = a + b
self.assertEqual(c, 3)
@ -1315,7 +1315,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(binary_op_add_int, "BINARY_OP")
def binary_op_add_unicode():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = "foo", "bar"
c = a + b
self.assertEqual(c, "foobar")
@ -1325,7 +1325,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(binary_op_add_unicode, "BINARY_OP")
def binary_op_add_extend():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 6, 3.0
c = a + b
self.assertEqual(c, 9.0)
@ -1384,11 +1384,13 @@ class TestSpecializer(TestBase):
arg / 42,
)
nan = float('nan')
self.assertEqual(compactlong_lhs(1.0), (43.0, 41.0, 42.0, 42.0))
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertEqual(compactlong_lhs(1.0), (43.0, 41.0, 42.0, 42.0))
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertTrue(all(filter(lambda x: x is nan, compactlong_lhs(nan))))
self.assertEqual(compactlong_rhs(42.0), (84.0, 0.0, 84.0, 1.0))
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertEqual(compactlong_rhs(42.0), (84.0, 0.0, 84.0, 1.0))
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
self.assertTrue(all(filter(lambda x: x is nan, compactlong_rhs(nan))))
self.assert_no_opcode(compactlong_lhs, "BINARY_OP_EXTEND")
@ -1429,7 +1431,7 @@ class TestSpecializer(TestBase):
meth = super().__init__
super().__init__()
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
A()
self.assert_specialized(A.__init__, "LOAD_SUPER_ATTR_ATTR")
@ -1449,7 +1451,7 @@ class TestSpecializer(TestBase):
globals()['super'] = fake_super
try:
# Should be unspecialized after enough calls.
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN):
A()
finally:
globals()['super'] = real_super
@ -1462,7 +1464,7 @@ class TestSpecializer(TestBase):
@requires_specialization_ft
def test_contain_op(self):
def contains_op_dict():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1, {1: 2, 2: 5}
self.assertTrue(a in b)
self.assertFalse(3 in b)
@ -1472,7 +1474,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(contains_op_dict, "CONTAINS_OP")
def contains_op_set():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1, {1, 2}
self.assertTrue(a in b)
self.assertFalse(3 in b)
@ -1499,7 +1501,7 @@ class TestSpecializer(TestBase):
pass
async def send_with():
for i in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
async with CM():
x = 1
@ -1517,7 +1519,7 @@ class TestSpecializer(TestBase):
def send_yield_from():
yield from g()
for i in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
list(send_yield_from())
self.assert_specialized(send_yield_from, "SEND_GEN")
@ -1529,19 +1531,19 @@ class TestSpecializer(TestBase):
class C:
__slots__ = ['x']
def set_slot():
def set_slot(n):
c = C()
for i in range(100):
for i in range(n):
c.x = i
set_slot()
set_slot(_testinternalcapi.SPECIALIZATION_THRESHOLD)
self.assert_specialized(set_slot, "STORE_ATTR_SLOT")
self.assert_no_opcode(set_slot, "STORE_ATTR")
# Adding a property for 'x' should unspecialize it.
C.x = property(lambda self: None, lambda self, x: None)
set_slot()
set_slot(_testinternalcapi.SPECIALIZATION_COOLDOWN)
self.assert_no_opcode(set_slot, "STORE_ATTR_SLOT")
@cpython_only
@ -1550,19 +1552,19 @@ class TestSpecializer(TestBase):
class C:
pass
def set_value():
def set_value(n):
c = C()
for i in range(100):
for i in range(n):
c.x = i
set_value()
set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD)
self.assert_specialized(set_value, "STORE_ATTR_INSTANCE_VALUE")
self.assert_no_opcode(set_value, "STORE_ATTR")
# Adding a property for 'x' should unspecialize it.
C.x = property(lambda self: None, lambda self, x: None)
set_value()
set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN)
self.assert_no_opcode(set_value, "STORE_ATTR_INSTANCE_VALUE")
@cpython_only
@ -1572,21 +1574,21 @@ class TestSpecializer(TestBase):
pass
c = C()
for i in range(29):
for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1):
setattr(c, f"_{i}", None)
def set_value():
for i in range(100):
def set_value(n):
for i in range(n):
c.x = i
set_value()
set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD)
self.assert_specialized(set_value, "STORE_ATTR_WITH_HINT")
self.assert_no_opcode(set_value, "STORE_ATTR")
# Adding a property for 'x' should unspecialize it.
C.x = property(lambda self: None, lambda self, x: None)
set_value()
set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN)
self.assert_no_opcode(set_value, "STORE_ATTR_WITH_HINT")
@cpython_only
@ -1594,14 +1596,15 @@ class TestSpecializer(TestBase):
def test_to_bool(self):
def to_bool_bool():
true_cnt, false_cnt = 0, 0
elems = [e % 2 == 0 for e in range(100)]
elems = [e % 2 == 0 for e in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)]
for e in elems:
if e:
true_cnt += 1
else:
false_cnt += 1
self.assertEqual(true_cnt, 50)
self.assertEqual(false_cnt, 50)
d, m = divmod(_testinternalcapi.SPECIALIZATION_THRESHOLD, 2)
self.assertEqual(true_cnt, d + m)
self.assertEqual(false_cnt, d)
to_bool_bool()
self.assert_specialized(to_bool_bool, "TO_BOOL_BOOL")
@ -1609,12 +1612,12 @@ class TestSpecializer(TestBase):
def to_bool_int():
count = 0
for i in range(100):
for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
if i:
count += 1
else:
count -= 1
self.assertEqual(count, 98)
self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 2)
to_bool_int()
self.assert_specialized(to_bool_int, "TO_BOOL_INT")
@ -1622,11 +1625,11 @@ class TestSpecializer(TestBase):
def to_bool_list():
count = 0
elems = [1, 2, 3]
elems = list(range(_testinternalcapi.SPECIALIZATION_THRESHOLD))
while elems:
count += elems.pop()
self.assertEqual(elems, [])
self.assertEqual(count, 6)
self.assertEqual(count, sum(range(_testinternalcapi.SPECIALIZATION_THRESHOLD)))
to_bool_list()
self.assert_specialized(to_bool_list, "TO_BOOL_LIST")
@ -1634,11 +1637,11 @@ class TestSpecializer(TestBase):
def to_bool_none():
count = 0
elems = [None, None, None, None]
elems = [None] * _testinternalcapi.SPECIALIZATION_THRESHOLD
for e in elems:
if not e:
count += 1
self.assertEqual(count, len(elems))
self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD)
to_bool_none()
self.assert_specialized(to_bool_none, "TO_BOOL_NONE")
@ -1646,11 +1649,11 @@ class TestSpecializer(TestBase):
def to_bool_str():
count = 0
elems = ["", "foo", ""]
elems = [""] + ["foo"] * (_testinternalcapi.SPECIALIZATION_THRESHOLD - 1)
for e in elems:
if e:
count += 1
self.assertEqual(count, 1)
self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 1)
to_bool_str()
self.assert_specialized(to_bool_str, "TO_BOOL_STR")
@ -1660,7 +1663,7 @@ class TestSpecializer(TestBase):
@requires_specialization_ft
def test_unpack_sequence(self):
def unpack_sequence_two_tuple():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1, 2
self.assertEqual(a, 1)
self.assertEqual(b, 2)
@ -1671,7 +1674,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(unpack_sequence_two_tuple, "UNPACK_SEQUENCE")
def unpack_sequence_tuple():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, = 1,
self.assertEqual(a, 1)
@ -1680,7 +1683,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(unpack_sequence_tuple, "UNPACK_SEQUENCE")
def unpack_sequence_list():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = [1, 2]
self.assertEqual(a, 1)
self.assertEqual(b, 2)
@ -1693,7 +1696,7 @@ class TestSpecializer(TestBase):
@requires_specialization_ft
def test_binary_subscr(self):
def binary_subscr_list_int():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = [1, 2, 3]
for idx, expected in enumerate(a):
self.assertEqual(a[idx], expected)
@ -1704,7 +1707,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(binary_subscr_list_int, "BINARY_SUBSCR")
def binary_subscr_tuple_int():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = (1, 2, 3)
for idx, expected in enumerate(a):
self.assertEqual(a[idx], expected)
@ -1715,7 +1718,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(binary_subscr_tuple_int, "BINARY_SUBSCR")
def binary_subscr_dict():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = {1: 2, 2: 3}
self.assertEqual(a[1], 2)
self.assertEqual(a[2], 3)
@ -1725,7 +1728,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(binary_subscr_dict, "BINARY_SUBSCR")
def binary_subscr_str_int():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = "foobar"
for idx, expected in enumerate(a):
self.assertEqual(a[idx], expected)
@ -1741,8 +1744,8 @@ class TestSpecializer(TestBase):
def __getitem__(self, item):
return self.val
items = [C(i) for i in range(100)]
for i in range(100):
items = [C(i) for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)]
for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
self.assertEqual(items[i][i], i)
binary_subscr_getitems()
@ -1753,7 +1756,7 @@ class TestSpecializer(TestBase):
@requires_specialization_ft
def test_compare_op(self):
def compare_op_int():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1, 2
c = a == b
self.assertFalse(c)
@ -1763,7 +1766,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(compare_op_int, "COMPARE_OP")
def compare_op_float():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = 1.0, 2.0
c = a == b
self.assertFalse(c)
@ -1773,7 +1776,7 @@ class TestSpecializer(TestBase):
self.assert_no_opcode(compare_op_float, "COMPARE_OP")
def compare_op_str():
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a, b = "spam", "ham"
c = a == b
self.assertFalse(c)

View file

@ -9,9 +9,6 @@ from unittest.mock import patch
from test.support import import_helper, threading_helper
ADAPTIVE_WARMUP_DELAY = 2
class A:
def f(self):
return 'A'
@ -466,7 +463,8 @@ class TestSuper(unittest.TestCase):
super(MyType, type(mytype)).__setattr__(mytype, "bar", 1)
self.assertEqual(mytype.bar, 1)
for _ in range(ADAPTIVE_WARMUP_DELAY):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
test("foo1")
def test_reassigned_new(self):
@ -485,7 +483,8 @@ class TestSuper(unittest.TestCase):
def __new__(cls):
return super().__new__(cls)
for _ in range(ADAPTIVE_WARMUP_DELAY):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
C()
def test_mixed_staticmethod_hierarchy(self):
@ -505,7 +504,8 @@ class TestSuper(unittest.TestCase):
def some(cls):
return super().some(cls)
for _ in range(ADAPTIVE_WARMUP_DELAY):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
C.some(C)
@threading_helper.requires_working_threading()

View file

@ -131,7 +131,7 @@ class TypeCacheWithSpecializationTests(unittest.TestCase):
return set(instr.opname for instr in dis.Bytecode(func, adaptive=True))
def _check_specialization(self, func, arg, opname, *, should_specialize):
for _ in range(100):
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
func(arg)
if should_specialize:

View file

@ -2138,6 +2138,21 @@ module_exec(PyObject *module)
return 1;
}
if (PyModule_Add(module, "SPECIALIZATION_THRESHOLD",
PyLong_FromLong(ADAPTIVE_WARMUP_VALUE + 1)) < 0) {
return 1;
}
if (PyModule_Add(module, "SPECIALIZATION_COOLDOWN",
PyLong_FromLong(ADAPTIVE_COOLDOWN_VALUE + 1)) < 0) {
return 1;
}
if (PyModule_Add(module, "SHARED_KEYS_MAX_SIZE",
PyLong_FromLong(SHARED_KEYS_MAX_SIZE)) < 0) {
return 1;
}
return 0;
}