Skip to content

Commit 48c50ff

Browse files
authored
GH-126892: Reset warmup counters when JIT compiling code (GH-126893)
1 parent addb225 commit 48c50ff

File tree

6 files changed

+48
-39
lines changed

6 files changed

+48
-39
lines changed

Lib/test/support/strace_helper.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ def _make_error(reason, details):
9191
res, cmd_line = run_python_until_end(
9292
"-c",
9393
textwrap.dedent(code),
94-
__run_using_command=[_strace_binary] + strace_flags)
94+
__run_using_command=[_strace_binary] + strace_flags,
95+
# Don't want to trace our JIT's own mmap and mprotect calls:
96+
PYTHON_JIT="0",
97+
)
9598
except OSError as err:
9699
return _make_error("Caught OSError", err)
97100

Lib/test/test_capi/test_opt.py

+22-28
Original file line numberDiff line numberDiff line change
@@ -1385,20 +1385,17 @@ class Foo:
13851385
guard_type_version_count = opnames.count("_GUARD_TYPE_VERSION")
13861386
self.assertEqual(guard_type_version_count, 1)
13871387

1388-
def test_guard_type_version_not_removed(self):
1389-
"""
1390-
Verify that the guard type version is not removed if we modify the class
1391-
"""
1388+
def test_guard_type_version_removed_invalidation(self):
13921389

13931390
def thing(a):
13941391
x = 0
1395-
for i in range(TIER2_THRESHOLD + 100):
1392+
for i in range(TIER2_THRESHOLD * 2 + 1):
13961393
x += a.attr
1397-
# for the first (TIER2_THRESHOLD + 90) iterations we set the attribute on this dummy function which shouldn't
1398-
# trigger the type watcher
1399-
# then after for the next 10 it should trigger it and stop optimizing
1400-
# Note that the code needs to be in this weird form so it's optimized inline without any control flow
1401-
setattr((Foo, Bar)[i < TIER2_THRESHOLD + 90], "attr", 2)
1394+
# The first TIER2_THRESHOLD iterations we set the attribute on
1395+
# this dummy class, which shouldn't trigger the type watcher.
1396+
# Note that the code needs to be in this weird form so it's
1397+
# optimized inline without any control flow:
1398+
setattr((Bar, Foo)[i == TIER2_THRESHOLD + 1], "attr", 2)
14021399
x += a.attr
14031400
return x
14041401

@@ -1410,24 +1407,21 @@ class Bar:
14101407

14111408
res, ex = self._run_with_optimizer(thing, Foo())
14121409
opnames = list(iter_opnames(ex))
1413-
14141410
self.assertIsNotNone(ex)
1415-
self.assertEqual(res, (TIER2_THRESHOLD * 2) + 219)
1416-
guard_type_version_count = opnames.count("_GUARD_TYPE_VERSION")
1417-
self.assertEqual(guard_type_version_count, 2)
1411+
self.assertEqual(res, TIER2_THRESHOLD * 6 + 1)
1412+
call = opnames.index("_CALL_BUILTIN_FAST")
1413+
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
1414+
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
1415+
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
1416+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
14181417

1419-
1420-
@unittest.expectedFailure
1421-
def test_guard_type_version_not_removed_escaping(self):
1422-
"""
1423-
Verify that the guard type version is not removed if have an escaping function
1424-
"""
1418+
def test_guard_type_version_removed_escaping(self):
14251419

14261420
def thing(a):
14271421
x = 0
1428-
for i in range(100):
1422+
for i in range(TIER2_THRESHOLD):
14291423
x += a.attr
1430-
# eval should be escaping and so should cause optimization to stop and preserve both type versions
1424+
# eval should be escaping
14311425
eval("None")
14321426
x += a.attr
14331427
return x
@@ -1437,12 +1431,12 @@ class Foo:
14371431
res, ex = self._run_with_optimizer(thing, Foo())
14381432
opnames = list(iter_opnames(ex))
14391433
self.assertIsNotNone(ex)
1440-
self.assertEqual(res, 200)
1441-
guard_type_version_count = opnames.count("_GUARD_TYPE_VERSION")
1442-
# Note: This will actually be 1 for noe
1443-
# https://github.com/python/cpython/pull/119365#discussion_r1626220129
1444-
self.assertEqual(guard_type_version_count, 2)
1445-
1434+
self.assertEqual(res, TIER2_THRESHOLD * 2)
1435+
call = opnames.index("_CALL_BUILTIN_FAST_WITH_KEYWORDS")
1436+
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
1437+
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
1438+
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
1439+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
14461440

14471441
def test_guard_type_version_executor_invalidated(self):
14481442
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Require cold or invalidated code to "warm up" before being JIT compiled
2+
again.

Python/bytecodes.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -2624,15 +2624,16 @@ dummy_func(
26242624
}
26252625
_PyExecutorObject *executor;
26262626
int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0);
2627-
ERROR_IF(optimized < 0, error);
2628-
if (optimized) {
2627+
if (optimized <= 0) {
2628+
this_instr[1].counter = restart_backoff_counter(counter);
2629+
ERROR_IF(optimized < 0, error);
2630+
}
2631+
else {
2632+
this_instr[1].counter = initial_jump_backoff_counter();
26292633
assert(tstate->previous_executor == NULL);
26302634
tstate->previous_executor = Py_None;
26312635
GOTO_TIER_TWO(executor);
26322636
}
2633-
else {
2634-
this_instr[1].counter = restart_backoff_counter(counter);
2635-
}
26362637
}
26372638
else {
26382639
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
@@ -4875,6 +4876,9 @@ dummy_func(
48754876
tstate->previous_executor = (PyObject *)current_executor;
48764877
GOTO_TIER_ONE(target);
48774878
}
4879+
else {
4880+
exit->temperature = initial_temperature_backoff_counter();
4881+
}
48784882
}
48794883
exit->executor = executor;
48804884
}

Python/executor_cases.c.h

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

+8-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)