Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-117581: Specialize binary operators by refcount as well as type. #117627

Closed
Closed
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8183250
Experimentally specialize BINARY_OP by refcount
markshannon Mar 27, 2024
198ceb6
Get better type information for stats on binary ops
markshannon Apr 3, 2024
3b3c8ce
Specialize binary op by refcount and type
markshannon Apr 3, 2024
7eefd3e
Merge branch 'main' into specialize-binary-op-refcount
markshannon Apr 4, 2024
4baa860
Use the right version numbers
markshannon Apr 4, 2024
24d57df
Gather better stats
markshannon Apr 4, 2024
accc60a
Add percentages to summary
markshannon Apr 4, 2024
23cf5de
Fix stats again
markshannon Apr 4, 2024
daa2733
Handle errors
markshannon Apr 4, 2024
67bbc52
Improve BINARY_OP specializations
markshannon Apr 5, 2024
2c964fa
Add back BINARY_OP_INPLACE_ADD_UNICODE and fix up dis test
markshannon Apr 5, 2024
4c084f8
Add more BINARY_OP specializations
markshannon Apr 6, 2024
cd8bea7
Add back BINARY_OP_INPLACE_ADD_UNICODE specialization
markshannon Apr 6, 2024
627f373
Merge branch 'main' into specialize-binary-op-refcount
markshannon Apr 8, 2024
a964a49
Restore BINARY_OP_INPLACE_ADD_UNICODE uop code.
markshannon Apr 8, 2024
11ac97f
Fix up test_dis again
markshannon Apr 8, 2024
2d3fa14
Mostly fix test_capi.test_opt
markshannon Apr 8, 2024
a327a4c
Perform tier 2 optimization on type version guards
markshannon Apr 8, 2024
a14d631
Explain _BINARY_OP_TABLE suffixes
markshannon Apr 8, 2024
ffbc9e7
Export symbol for JIT
markshannon Apr 9, 2024
d9acedb
Make things const
markshannon Apr 9, 2024
dc7092b
Merge branch 'main' into specialize-binary-op-refcount
markshannon May 21, 2024
48e287c
Add news
markshannon May 21, 2024
8708306
Merge branch 'main' into specialize-binary-op-refcount
markshannon May 22, 2024
8b4a480
Fix test_dis
markshannon May 22, 2024
28c384c
Restore constant propagation in binary op optimizer
markshannon May 23, 2024
881df50
Workaround false positive in check-c-globals.py
markshannon May 23, 2024
5386b2d
Merge branch 'main' into specialize-binary-op-refcount
markshannon May 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Mostly fix test_capi.test_opt
markshannon committed Apr 8, 2024
commit 2d3fa1454ac04d6dc08e30f5f5228a3be58bcf56
8 changes: 4 additions & 4 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Include/internal/pycore_uop_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 20 additions & 17 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
@@ -131,7 +131,7 @@ def iter_opnames(ex):


def get_opnames(ex):
return set(iter_opnames(ex))
return list(iter_opnames(ex))


@requires_specialization
@@ -230,7 +230,7 @@ def testfunc(x):
ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_SET_IP", uops)
self.assertIn("_CHECK_VALIDITY_AND_SET_IP", uops)
self.assertIn("_LOAD_FAST_0", uops)

def test_extended_arg(self):
@@ -401,7 +401,7 @@ def testfunc(n):
uops = get_opnames(ex)
# Since there is no JUMP_FORWARD instruction,
# look for indirect evidence: the += operator
self.assertIn("_BINARY_OP_ADD_INT", uops)
self.assertIn("_BINARY_OP_TABLE_NN", uops)

def test_for_iter_range(self):
def testfunc(n):
@@ -497,7 +497,7 @@ def dummy(x):
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_PUSH_FRAME", uops)
self.assertIn("_BINARY_OP_ADD_INT", uops)
self.assertIn("_BINARY_OP_TABLE_NN", uops)

def test_branch_taken(self):
def testfunc(n):
@@ -532,16 +532,17 @@ def testfunc(n, m):
x = 0
for i in range(m):
for j in MyIter(n):
x += 1000*i + j
x += 2*i + j
return x

opt = _testinternalcapi.new_uop_optimizer()
with temporary_optimizer(opt):
x = testfunc(10, 10)

self.assertEqual(x, sum(range(10)) * 10010)
self.assertEqual(x, sum(range(10)) * 30)

ex = get_first_executor(testfunc)
print_executor(ex)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_FOR_ITER_TIER_TWO", uops)
@@ -603,7 +604,7 @@ def testfunc(loops):
res, ex = self._run_with_optimizer(testfunc, 32)
self.assertIsNotNone(ex)
self.assertEqual(res, 63)
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"]
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"]
guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"]
self.assertGreaterEqual(len(binop_count), 3)
self.assertLessEqual(len(guard_both_int_count), 1)
@@ -627,7 +628,7 @@ def testfunc(loops):
ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
self.assertEqual(res, 124)
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"]
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"]
guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"]
self.assertGreaterEqual(len(binop_count), 3)
self.assertLessEqual(len(guard_both_int_count), 1)
@@ -651,7 +652,7 @@ def testfunc(loops):
ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
self.assertEqual(res, 124)
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"]
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"]
guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"]
self.assertGreaterEqual(len(binop_count), 3)
self.assertLessEqual(len(guard_both_int_count), 1)
@@ -669,7 +670,7 @@ def testfunc(loops):

res, ex = self._run_with_optimizer(testfunc, 64)
self.assertIsNotNone(ex)
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"]
binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"]
self.assertGreaterEqual(len(binop_count), 3)

def test_call_py_exact_args(self):
@@ -683,7 +684,7 @@ def dummy(x):
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_PUSH_FRAME", uops)
self.assertIn("_BINARY_OP_ADD_INT", uops)
self.assertIn("_BINARY_OP_TABLE_NN", uops)
self.assertNotIn("_CHECK_PEP_523", uops)

def test_int_type_propagate_through_range(self):
@@ -699,6 +700,7 @@ def testfunc(n):
uops = get_opnames(ex)
self.assertNotIn("_GUARD_BOTH_INT", uops)

@unittest.skipIf(True, "Needs tier 2 optimizer to be updated to handle new binary ops.")
def test_int_value_numbering(self):
def testfunc(n):

@@ -810,7 +812,7 @@ def testfunc(n):
self.assertLessEqual(len(guard_both_float_count), 1)
# TODO gh-115506: this assertion may change after propagating constants.
# We'll also need to verify that propagation actually occurs.
self.assertIn("_BINARY_OP_ADD_FLOAT", uops)
self.assertIn("_BINARY_OP_TABLE_DD", uops)

def test_float_subtract_constant_propagation(self):
def testfunc(n):
@@ -830,7 +832,7 @@ def testfunc(n):
self.assertLessEqual(len(guard_both_float_count), 1)
# TODO gh-115506: this assertion may change after propagating constants.
# We'll also need to verify that propagation actually occurs.
self.assertIn("_BINARY_OP_SUBTRACT_FLOAT", uops)
self.assertIn("_BINARY_OP_TABLE_DD", uops)

def test_float_multiply_constant_propagation(self):
def testfunc(n):
@@ -850,7 +852,7 @@ def testfunc(n):
self.assertLessEqual(len(guard_both_float_count), 1)
# TODO gh-115506: this assertion may change after propagating constants.
# We'll also need to verify that propagation actually occurs.
self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops)
self.assertIn("_BINARY_OP_TABLE_DD", uops)

def test_add_unicode_propagation(self):
def testfunc(n):
@@ -868,7 +870,7 @@ def testfunc(n):
uops = get_opnames(ex)
guard_both_unicode_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"]
self.assertLessEqual(len(guard_both_unicode_count), 1)
self.assertIn("_BINARY_OP_ADD_UNICODE", uops)
self.assertIn("_BINARY_OP_TABLE_NN", uops)

def test_compare_op_type_propagation_float(self):
def testfunc(n):
@@ -941,7 +943,7 @@ def testfunc(n):
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertNotIn("_GUARD_BOTH_INT", uops)
self.assertIn("_BINARY_OP_ADD_INT", uops)
self.assertIn("_BINARY_OP_TABLE_NN", uops)
# Try again, but between the runs, set the global to a float.
# This should result in no executor the second time.
ns = {}
@@ -950,8 +952,9 @@ def testfunc(n):
ns['_test_global'] = 0
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertIsNone(ex)
ns['_test_global'] = 3.14
ns['_test_global'] = ""
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
print(get_opnames(ex))
self.assertIsNone(ex)

def test_combine_stack_space_checks_sequential(self):
1 change: 1 addition & 0 deletions Tools/cases_generator/analyzer.py
Original file line number Diff line number Diff line change
@@ -402,6 +402,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool:
"CALL_STAT_INC",
"maybe_lltrace_resume_frame",
"_PyUnicode_JoinArray",
"Py_REFCNT",
)

ESCAPING_FUNCTIONS = (