chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
file(
GLOB TEST_OPS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"test_*.py")
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
set(SOT_ENVS SOT_LOG_LEVEL=0 MIN_GRAPH_SIZE=0 STRICT_MODE=True
SOT_ENABLE_STRICT_GUARD_CHECK=True FLAGS_cudnn_deterministic=True)
foreach(TEST_OP ${TEST_OPS})
py_test_modules(${TEST_OP} MODULES ${TEST_OP} ENVS ${SOT_ENVS})
endforeach()
if(WIN32)
set_tests_properties(test_sot_resnet50_backward PROPERTIES TIMEOUT 420)
set_tests_properties(test_sot_resnet PROPERTIES TIMEOUT 200)
endif()
+42
View File
@@ -0,0 +1,42 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
def foo(x: int, y: paddle.Tensor):
return x + y
class TestBasic(TestCaseBase):
def test_simple(self):
self.assert_results(foo, 1, paddle.to_tensor(2))
if __name__ == "__main__":
unittest.main()
# Instructions:
# LOAD_FAST
# BINARY_ADD
# RETURN_VALUE
# Variables:
# ConstantVariable
# TensorVariable
+47
View File
@@ -0,0 +1,47 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
def foo(x: int, y: paddle.Tensor):
x = x + 1
y = y + 1
x += y
return x
class TestStoreInplace(TestCaseBase):
def test_simple(self):
self.assert_results(foo, 1, paddle.to_tensor(2))
if __name__ == "__main__":
unittest.main()
# Instructions:
# LOAD_FAST
# BINARY_ADD
# STORE_FAST (new)
# INPLACE_ADD (new)
# RETURN_VALUE
# Variables:
# ConstantVariable
# TensorVariable
+127
View File
@@ -0,0 +1,127 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# New Supported Instructions:
# BUILD_TUPLE
# BINARY_SUBSCR
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import with_control_flow_guard
@check_no_breakgraph
def build_tuple(x: int, y: paddle.Tensor):
x = (x, y)
return x[1] + 1
@check_no_breakgraph
def build_tuple_with_slice_subscript(x: int, y: paddle.Tensor):
z = (x, y, 3, 4)
return z[0:5:1]
@check_no_breakgraph
def build_tuple_with_int_subscript(x: int, y: paddle.Tensor):
z = (x, y)
return z[0]
@check_no_breakgraph
def tuple_count_int(x: int, y: paddle.Tensor):
z = (x, x, 2, 1)
return z.count(x)
def tuple_count_tensor(x: paddle.Tensor, y: tuple[paddle.Tensor]):
return y.count(x)
@check_no_breakgraph
def tuple_index_int(x: int, y: paddle.Tensor):
z = (x, y, x, y, y)
return z.index(x)
def tuple_index_tensor(x: paddle.Tensor, y: tuple[paddle.Tensor]):
return y.index(x)
@check_no_breakgraph
def tuple_compare():
# TODO(SigureMo): support gt, ge, lt, le
l1 = (1, 2, 3)
l2 = (1, 2, 3)
l3 = (1, 2, 4)
return l1 == l2, l1 == l3, l1 != l2, l1 != l3
@check_no_breakgraph
def tuple_add():
l0 = (1, 2, 3)
l1 = (4, 5, 6)
return l0 + l1
@check_no_breakgraph
def tuple_inplace_add():
l0 = (1, 2, 3)
l1 = l0
l2 = (4, 5, 6)
l0 += l2
return l0, l1
class TestBuildTuple(TestCaseBase):
def test_build_tuple(self):
self.assert_results(build_tuple, 1, paddle.to_tensor(2))
self.assert_results(
build_tuple_with_slice_subscript, 1, paddle.to_tensor(2)
)
self.assert_results(
build_tuple_with_int_subscript, 1, paddle.to_tensor(2)
)
class TestTupleMethods(TestCaseBase):
def test_tuple_methods_int(self):
self.assert_results(tuple_count_int, 1, paddle.to_tensor(2))
self.assert_results(tuple_index_int, 1, paddle.to_tensor(2))
@with_control_flow_guard(False)
def test_tuple_methods_tensor(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
self.assert_results(tuple_count_tensor, a, (a, b, a, b))
self.assert_results(tuple_index_tensor, b, (b, b, b, a))
def test_tuple_compare(self):
self.assert_results(tuple_compare)
def test_tuple_add(self):
self.assert_results(tuple_add)
def test_tuple_inplace_add(self):
self.assert_results(tuple_inplace_add)
if __name__ == "__main__":
unittest.main()
+379
View File
@@ -0,0 +1,379 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# New Supported Instructions:
# BUILD_LIST (new)
# BINARY_SUBSCR
# DELETE_SUBSCR
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@check_no_breakgraph
def list_getitem_int(x: int, y: paddle.Tensor):
x = [x, y]
return x[0] + 1
@check_no_breakgraph
def list_getitem_tensor(x: int, y: paddle.Tensor):
x = [x, y]
return x[1] + 1
@check_no_breakgraph
def list_setitem_int(x: int, y: paddle.Tensor):
z = [x, y]
z[0] = 3
return z
def list_setitem_tensor(x: int, y: paddle.Tensor):
z = [x, y]
z[1] = paddle.to_tensor(3)
return z
@check_no_breakgraph
def list_delitem_int(x: int, y: paddle.Tensor):
z = [x, y]
del z[0]
return z
@check_no_breakgraph
def list_delitem_tensor(x: int, y: paddle.Tensor):
z = [x, y]
del z[1]
return z
@check_no_breakgraph
def list_construct_from_list(x: int, y: paddle.Tensor):
z = [x, y]
return z
@check_no_breakgraph
def list_append_int(x: int, y: paddle.Tensor):
z = [x, y]
z.append(3)
return z
@check_no_breakgraph
def list_append_tensor(x: int, y: paddle.Tensor):
z = [x, y]
z.append(y)
return z
@check_no_breakgraph
def list_clear(x: int, y: paddle.Tensor):
z = [x, y]
z.clear()
return z
@check_no_breakgraph
def list_copy(x: int, y: paddle.Tensor):
z = [x, y]
a = z.copy()
z[0] = 3
z[1] = y + 1
return (a, z)
@check_no_breakgraph
def list_count_int(x: int, y: paddle.Tensor):
z = [x, x, 2, 3, 1]
return z.count(x)
def list_count_tensor(x: paddle.Tensor, y: list[paddle.Tensor]):
return y.count(x)
@check_no_breakgraph
def list_extend(x: int, y: paddle.Tensor):
z = [x, y]
a = [y, x]
b = (x, y)
z.extend(a)
z.extend(b)
return z
@check_no_breakgraph
def list_index_int(x: int, y: paddle.Tensor):
z = [x, x, 1, 2]
return z.index(x)
def list_index_tensor(x: paddle.Tensor, y: list[paddle.Tensor]):
return y.index(x)
@check_no_breakgraph
def list_insert(x: int, y: paddle.Tensor):
z = [x, y]
z.insert(0, x)
z.insert(3, y)
return z
@check_no_breakgraph
def list_pop(x: int, y: paddle.Tensor):
z = [x, y]
a = z.pop()
b = z.pop()
return (z, a, b)
@check_no_breakgraph
def list_remove(x: int, y: paddle.Tensor):
z = [x, x, y, y]
z.remove(x)
z.remove(y)
return z
@check_no_breakgraph
def list_reverse(x: int, y: paddle.Tensor):
z = [x, x, y, y]
z.reverse()
return z
@check_no_breakgraph
def list_default_sort(x: int, y: paddle.Tensor):
z = [x + 2, x, x + 1]
z.sort()
return z
@check_no_breakgraph
def list_key_sort(x: int, y: paddle.Tensor):
z = [x + 2, x, x + 1]
z.sort(lambda x: x)
return z
@check_no_breakgraph
def list_reverse_sort(x: int, y: paddle.Tensor):
z = [x + 2, x, x + 1]
z.sort(reverse=True)
return z
@check_no_breakgraph
def list_tensor_sort(x: int, y: paddle.Tensor):
z = [y + 2, y, y + 1]
z.sort()
return z
@check_no_breakgraph
def list_max(x: paddle.Tensor | int, y: paddle.Tensor | int):
z = [x, x, y]
return max(z)
@check_no_breakgraph
def list_tensor_max_api(x: paddle.Tensor):
return x.max()
@check_no_breakgraph
def list_min(x: paddle.Tensor | int, y: paddle.Tensor | int):
z = [x, x, y]
return min(z)
@check_no_breakgraph
def list_tensor_min_api(x: paddle.Tensor):
return x.min()
@check_no_breakgraph
def list_no_arguments():
l1 = list() # noqa: C408
l1.append(1)
l2 = list() # noqa: C408
l2.append(2)
return l1[0] + l2[0]
@check_no_breakgraph
def list_compare():
# TODO(SigureMo): support gt, ge, lt, le
l1 = [1, 2, 3]
l2 = [1, 2, 3]
l3 = [1, 2, 4]
return l1 == l2, l1 == l3, l1 != l2, l1 != l3
@check_no_breakgraph
def list_add():
l0 = [1, 2, 3]
l1 = [4, 5, 6]
return l0 + l1
@check_no_breakgraph
def list_inplace_add():
l0 = [1, 2, 3]
l1 = l0
l2 = [4, 5, 6]
l0 += l2
return l0, l1
@check_no_breakgraph
def list_extend_range(x):
return [1, *range(0, len(x.shape))]
@check_no_breakgraph
def list_extend_dict():
l1 = []
l1.extend({1: 2, 2: 3, 3: 4})
return l1
class TestListBasic(TestCaseBase):
def test_list_basic(self):
self.assert_results(list_getitem_int, 1, paddle.to_tensor(2))
self.assert_results(list_getitem_tensor, 1, paddle.to_tensor(2))
self.assert_results_with_side_effects(
list_setitem_int, 1, paddle.to_tensor(2)
)
class TestListMethods(TestCaseBase):
def test_list_setitem(self):
self.assert_results_with_side_effects(
list_setitem_tensor, 1, paddle.to_tensor(2)
)
def test_list_count_and_index(self):
self.assert_results(list_count_int, 1, paddle.to_tensor(2))
self.assert_results(list_index_int, 1, paddle.to_tensor(2))
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
self.assert_results(list_count_tensor, a, [a, b, a, b, a, b])
self.assert_results(list_index_tensor, b, [a, b, a, b, a, b])
def test_list_delitem(self):
self.assert_results_with_side_effects(
list_delitem_int, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
list_delitem_tensor, 1, paddle.to_tensor(2)
)
def test_list_append(self):
self.assert_results_with_side_effects(
list_append_int, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
list_append_tensor, 1, paddle.to_tensor(2)
)
def test_list_clear(self):
self.assert_results_with_side_effects(
list_clear, 1, paddle.to_tensor(2)
)
def test_list_copy(self):
self.assert_results_with_side_effects(list_copy, 1, paddle.to_tensor(2))
def test_list_extend(self):
self.assert_results_with_side_effects(
list_extend, 1, paddle.to_tensor(2)
)
def test_list_insert(self):
self.assert_results_with_side_effects(
list_insert, 1, paddle.to_tensor(2)
)
def test_list_pop(self):
self.assert_results_with_side_effects(list_pop, 1, paddle.to_tensor(2))
def test_list_remove(self):
self.assert_results_with_side_effects(
list_remove, 1, paddle.to_tensor(2)
)
def test_list_reverse(self):
self.assert_results_with_side_effects(
list_reverse, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
list_reverse, 1, paddle.to_tensor(2)
)
def test_list_sort(self):
self.assert_results_with_side_effects(
list_default_sort, 1, paddle.to_tensor(2)
)
# TODO: Not currently supported
# self.assert_results_with_side_effects(
# list_tensor_sort, 1, paddle.to_tensor(2)
# )
# self.assert_results_with_side_effects(
# list_key_sort, 1, paddle.to_tensor(2)
# )
# self.assert_results_with_side_effects(
# list_reverse_sort, 1, paddle.to_tensor(2)
# )
def test_list_construct_from_list(self):
self.assert_results(list_construct_from_list, 1, paddle.to_tensor(2))
def test_list_max_min(self):
self.assert_results(list_max, 1, 2)
self.assert_results(list_min, 1, 2)
self.assert_results(list_tensor_max_api, paddle.to_tensor([1, 2, 3]))
self.assert_results(list_tensor_min_api, paddle.to_tensor([1, 2, 3]))
def test_list_noargs(self):
self.assert_results(list_no_arguments)
def test_list_compare(self):
self.assert_results(list_compare)
def test_list_add(self):
self.assert_results(list_add)
def test_list_inplace_add(self):
self.assert_results(list_inplace_add)
def test_list_extend_range(self):
self.assert_results(list_extend_range, paddle.to_tensor([1, 2]))
def test_list_extend_dict(self):
self.assert_results(list_extend_dict)
if __name__ == "__main__":
unittest.main()
+325
View File
@@ -0,0 +1,325 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# New Supported Instructions:
# BUILD_MAP (new)
# BUILD_CONST_KEY_MAP (new)
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import strict_mode_guard
@check_no_breakgraph
def build_map(x: int, y: paddle.Tensor):
z = {x: y}
return z[x] + 1
@check_no_breakgraph
def build_const_key_map(x: int, y: paddle.Tensor):
z = {1: y, 2: y + 1}
return z[x] + 1
@check_no_breakgraph
def dict_get_item(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
return (z.get(1), z.get(2))
@check_no_breakgraph
def dict_get_item_default(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
return (z.get(3, 2), z.get(4, y))
@check_no_breakgraph
def dict_set_item_int(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z[1] = x * 2
return z[1]
@check_no_breakgraph
def dict_set_item_tensor(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z[2] = y
return z[1]
@check_no_breakgraph
def dict_update_item1(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z.update({1: x * 2, 2: y, 3: y + 2})
return z
@check_no_breakgraph
def dict_update_item2(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z.update({1: x * 2, 2: y, 3: z[2] + 2})
return z
@check_no_breakgraph
def dict_del_item_int(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
del z[1]
return z
@check_no_breakgraph
def dict_del_item_tensor(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
del z[2]
return z
@check_no_breakgraph
def dict_clear(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z.clear()
return z
@check_no_breakgraph
def dict_copy(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
z2 = z.copy()
z[1] = 2
return z2
@check_no_breakgraph
def dict_setdefault_int(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
a = z.setdefault(4)
b = z.setdefault(1, 2)
c = z.setdefault(3, 4)
return (z, a, b, c)
@check_no_breakgraph
def dict_pop(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1, 3: y}
a = z.pop(1)
b = z.pop(2, 3)
c = z.pop(4, 3)
d = z.pop(5, y)
return (z, a, b, c, d)
@check_no_breakgraph
def dict_popitem(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1, 3: y}
a = z.popitem()
return (z, a)
@check_no_breakgraph
def dict_construct_from_dict():
x = {1: 2, 3: 4}
d = dict(x)
return d
@check_no_breakgraph
def dict_construct_from_list():
x = [[1, 2], [3, 4]]
d = dict(x)
return d
@check_no_breakgraph
def dict_construct_from_tuple():
x = ((1, 2), (3, 4))
d = dict(x)
return d
@check_no_breakgraph
def dict_construct_from_comprehension():
z = {1: 2, 3: 4}
d = {k: v + 1 for k, v in z.items()}
return d
@check_no_breakgraph
def dict_no_arguments():
d1 = dict() # noqa: C408
d1.update({1: 2})
d2 = dict() # noqa: C408
d2.update({3: 4})
return d1[1] + d2[3]
@check_no_breakgraph
def dict_test_fromkeys(x):
d = dict.fromkeys(x)
return d
@check_no_breakgraph
def dict_test_fromkeys_default(x, y):
d = dict.fromkeys(x, y)
return d
@check_no_breakgraph
def dict_keyword_init():
d = dict(x=1, y=2) # noqa: C408
return d["x"] + d["y"]
@strict_mode_guard(False)
@check_no_breakgraph
def raise_keyerror_with_number(x):
x += 1
a = {}
a[8]
x /= 3
@strict_mode_guard(False)
@check_no_breakgraph
def raise_keyerror_with_str(x):
x += 1
a = {}
a["8"]
x /= 3
class TestDict:
def __init__(self, data) -> None:
self.data = data
def __getitem__(self, key):
try:
return self.data[key]
except KeyError:
raise
@check_no_breakgraph
def raise_keyerror_with_custom_obj(x):
x += 1
data = TestDict({})
try:
x *= 3
data['a']
x -= 3
except KeyError:
x /= 3
return x
class TestBuildDict(TestCaseBase):
def test_build_map(self):
self.assert_results(build_map, 1, paddle.to_tensor(2))
def test_build_const_key_map(self):
self.assert_results(build_const_key_map, 1, paddle.to_tensor(2))
class TestDictMethods(TestCaseBase):
def test_dict_get_item(self):
self.assert_results(dict_get_item, 1, paddle.to_tensor(2))
self.assert_results(dict_get_item_default, 1, paddle.to_tensor(2))
def test_dict_set_item(self):
self.assert_results_with_side_effects(
dict_set_item_int, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
dict_set_item_tensor, 1, paddle.to_tensor(2)
)
def test_dict_copy(self):
self.assert_results_with_side_effects(dict_copy, 1, paddle.to_tensor(2))
def test_dict_update(self):
self.assert_results_with_side_effects(
dict_update_item1, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
dict_update_item2, 1, paddle.to_tensor(2)
)
def test_dict_setdefault(self):
self.assert_results_with_side_effects(
dict_setdefault_int, 1, paddle.to_tensor(2)
)
def test_dict_del_item(self):
self.assert_results_with_side_effects(
dict_del_item_int, 1, paddle.to_tensor(2)
)
self.assert_results_with_side_effects(
dict_del_item_tensor, 1, paddle.to_tensor(2)
)
def test_dict_clear(self):
self.assert_results_with_side_effects(
dict_clear, 1, paddle.to_tensor(2)
)
def test_dict_pop(self):
self.assert_results_with_side_effects(dict_pop, 1, paddle.to_tensor(2))
def test_dict_popitem(self):
self.assert_results_with_side_effects(
dict_popitem, 1, paddle.to_tensor(2)
)
def test_construct(self):
self.assert_results(dict_construct_from_dict)
self.assert_results(dict_construct_from_list)
self.assert_results(dict_construct_from_tuple)
self.assert_results(dict_construct_from_comprehension)
def test_dict_noargs(self):
self.assert_results(dict_no_arguments)
def test_dict_fromkeys(self):
self.assert_results(dict_test_fromkeys, (1, 2, 3, 4))
self.assert_results(dict_test_fromkeys, [1, 2, 3, 4])
self.assert_results(dict_test_fromkeys_default, (1, 2, 3, 4), 1)
self.assert_results(
dict_test_fromkeys_default, (1, 2, 3, 4), paddle.to_tensor(1)
)
self.assert_results(dict_test_fromkeys_default, [1, 2, 3, 4], 1)
self.assert_results(
dict_test_fromkeys_default, [1, 2, 3, 4], paddle.to_tensor(1)
)
def test_dict_keyword_init(self):
self.assert_results(dict_keyword_init)
class TestDictKeyError(TestCaseBase):
def test_dict_keyerror(self):
with self.assertRaisesRegex(KeyError, "^8$"):
self.assert_results(raise_keyerror_with_number, paddle.to_tensor(5))
with self.assertRaisesRegex(KeyError, "^'8'$"):
self.assert_results(raise_keyerror_with_str, paddle.to_tensor(5))
self.assert_results(raise_keyerror_with_custom_obj, paddle.ones([3]))
if __name__ == "__main__":
unittest.main()
+221
View File
@@ -0,0 +1,221 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
def add(x, y):
return x + y
def sub(x, y):
return x - y
def foo_1(x: paddle.Tensor):
m = x + 1
y = add(m * 3, m * 2)
return y
def foo_2(x: paddle.Tensor):
m = x + 1
y = sub(m * 3, m * 2)
return y
def foo_3(x: paddle.Tensor):
m = x + 1
y = sub(m * 3, m * 2)
y = sub(y, y)
y = sub(y, y)
return y
def nest_2(x):
return x + 1
def nest_1(x):
return (x - 1) * 2
def foo_4(x: paddle.Tensor):
m = x + 1
m = nest_1(m)
return m
def fn_with_varargs_and_kwargs(x, *args, **kwargs):
return (
x
+ args[0]
+ args[1]
- args[2]
+ kwargs['a'] * kwargs['b']
+ kwargs['c']
)
def foo_5(x: paddle.Tensor):
m = x + 1
m = fn_with_varargs_and_kwargs(
m, x + 1, x + 2, x + 3, a=x + 4, b=x + 5, c=x + 6
)
return m
def fn_with_default_value(x, y=1, z=2):
return x + y + z
def foo_6(x: paddle.Tensor):
m = x + 1
m = fn_with_default_value(m, m + 10)
m = fn_with_default_value(m + 42)
return m
def fn_with_default_value_and_varargs_kwargs(x, y=1, *args, **kwargs):
return x + y + args[0] + kwargs['a']
def foo_7(x: paddle.Tensor):
m = x + 1
m = fn_with_default_value_and_varargs_kwargs(m, m + 1, m + 2, a=m + 3)
return m
def fn_with_default_value_and_varargs_kwargs_kwonly_1(
x, y=1, *args, z, **kwargs
):
return x + y + args[0] + kwargs['a'] + z
def fn_with_default_value_and_varargs_kwargs_kwonly_2(
x, y=1, *args, z=10, **kwargs
):
return x + y + args[0] + kwargs['a'] + z
def foo_8(x: paddle.Tensor):
m = x + 1
m = fn_with_default_value_and_varargs_kwargs_kwonly_1(
m, m + 1, m + 2, a=m + 3, z=m + 4
)
m = fn_with_default_value_and_varargs_kwargs_kwonly_2(
m, m + 1, m + 2, a=m + 3
)
return m
class TestCall(TestCaseBase):
def test_call1(self):
self.assert_results(foo_1, paddle.to_tensor(2))
def test_call2(self):
self.assert_results(foo_2, paddle.to_tensor(3))
def test_call3(self):
self.assert_results(foo_3, paddle.to_tensor(4))
def test_call4(self):
self.assert_results(foo_4, paddle.to_tensor(5))
def test_call5(self):
self.assert_results(foo_5, paddle.to_tensor(6))
def test_call6(self):
self.assert_results(foo_6, paddle.to_tensor(7))
def test_call7(self):
self.assert_results(foo_7, paddle.to_tensor(8))
def test_call8(self):
self.assert_results(foo_8, paddle.to_tensor(9))
def apply_fn(fn, x):
return fn(x)
def fn1(x):
return x + 1
def fn2(x):
return x - 1
class TestApplyDifferentFunctions(TestCaseBase):
def test_apply_fn(self):
x = 1
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(apply_fn, fn1, x)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(apply_fn, fn2, x)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(apply_fn, fn1, x)
self.assertEqual(ctx.translate_count, 2)
@check_no_breakgraph
def positional_only_basic(x, /, y):
z = x + y
return x + z
def positional_only_breakgraph(x, /, y):
z = x + y
paddle.jit.sot.psdb.breakgraph()
return x + z
@check_no_breakgraph
def keyword_only_basic(x, *, y):
z = x + y
return x + z
def keyword_only_breakgraph(x, *, y):
z = x + y
paddle.jit.sot.psdb.breakgraph()
return x + z
class TestPositionalKeywordOnly(TestCaseBase):
def test_positional_only_basic(self):
self.assert_results(positional_only_basic, 1, 2)
def test_positional_only_breakgraph(self):
self.assert_results(positional_only_breakgraph, 1, 2)
def test_keyword_only_basic(self):
self.assert_results(keyword_only_basic, x=1, y=2)
def test_keyword_only_breakgraph(self):
self.assert_results(keyword_only_breakgraph, x=1, y=2)
if __name__ == "__main__":
unittest.main()
+70
View File
@@ -0,0 +1,70 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# New Supported Instructions:
# UNPACK_SEQUENCE (new)
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def unpack_tuple(x: tuple[int, paddle.Tensor]):
y, z = x
return z + 1
def unpack_tensor(x: paddle.Tensor):
a, b = x
return (a, b)
def unpack_ex_tuple(x: tuple[int, int, paddle.Tensor]):
*y, z = x
return z + 1
def unpack_ex_tensor(x: paddle.Tensor):
a, b, *c = x
return (a, b)
def unpack_ex_tensor_2(x: paddle.Tensor):
a, *b, c, d = x
return (a, c)
class TestUnpack(TestCaseBase):
def test_unpack_tuple(self):
self.assert_results(unpack_tuple, (1, paddle.to_tensor(2)))
def test_unpack_tensor(self):
self.assert_results(unpack_tensor, paddle.to_tensor([2, 3]))
def test_unpack_ex_tuple(self):
self.assert_results(unpack_ex_tuple, (1, 1, paddle.to_tensor(2)))
def test_unpack_ex_tensor(self):
self.assert_results(unpack_ex_tensor, paddle.to_tensor([2, 3, 3, 3]))
def test_unpack_ex_tensor_2(self):
self.assert_results(unpack_ex_tensor_2, paddle.to_tensor([2, 3, 3, 3]))
if __name__ == "__main__":
unittest.main()
+97
View File
@@ -0,0 +1,97 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def rot_two_return_a(a: paddle.Tensor, b: paddle.Tensor):
b, a = a, b
return a + 1
def rot_two_return_b(a: paddle.Tensor, b: paddle.Tensor):
b, a = a, b
return b + 2
def rot_three_return_a(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
a, b, c = c, b, a
return a + 1
def rot_three_return_b(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
a, b, c = c, b, a
return b + 1
def rot_three_return_c(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
a, b, c = c, b, a
return c + 1
def rot_four_return_a(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
a, b, c, d = d, c, b, a
return a + 1
def rot_four_return_b(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
a, b, c, d = d, c, b, a
return b + 1
def rot_four_return_c(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
a, b, c, d = d, c, b, a
return c + 1
def rot_four_return_d(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
a, b, c, d = d, c, b, a
return d + 1
class TestRot(TestCaseBase):
def test_simple(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
c = paddle.to_tensor(3)
d = paddle.to_tensor(4)
self.assert_results(rot_two_return_a, a, b)
self.assert_results(rot_two_return_b, a, b)
self.assert_results(rot_three_return_a, a, b, c)
self.assert_results(rot_three_return_b, a, b, c)
self.assert_results(rot_three_return_c, a, b, c)
self.assert_results(rot_four_return_a, a, b, c, d)
self.assert_results(rot_four_return_b, a, b, c, d)
self.assert_results(rot_four_return_c, a, b, c, d)
self.assert_results(rot_four_return_d, a, b, c, d)
if __name__ == "__main__":
unittest.main()
+64
View File
@@ -0,0 +1,64 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# FORMAT_VALUE (new)
# BUILD_STRING (new)
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import assert_true
def foo(x: paddle.Tensor):
whilespace = 123
hello_world = f"Hello {whilespace} World"
z = assert_true(hello_world == "Hello 123 World")
x = x + 1
return x
def fstring_with_convert_test(x: paddle.Tensor):
obj = 42
formatted_string = f"{obj!r}"
z = assert_true(formatted_string == "42")
x = x + 1
return x
def fstring_with_spec(x: paddle.Tensor):
int_num = 42
float_num = 3.1415
formatted_string = f"{int_num} and {float_num:.2f}"
z = assert_true(formatted_string == "42 and 3.14")
x = x + 1
return x
class TestFString(TestCaseBase):
def test_f_string(self):
self.assert_results(foo, paddle.to_tensor(1))
def test_f_string_with_spec(self):
self.assert_results(fstring_with_spec, paddle.to_tensor(1))
def test_f_string_with_convert_test(self):
self.assert_results(fstring_with_convert_test, paddle.to_tensor(1))
if __name__ == "__main__":
unittest.main()
+97
View File
@@ -0,0 +1,97 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# BUILD_TUPLE_UNPACK (new)
# BUILD_LIST_UNPACK (new)
# BUILD_TUPLE_UNPACK_WITH_CALL (new)
# CALL_FUNCTION_EX (new)
# BUILD_MAP_UNPACK (new)
# LIST_EXTEND (new)
# LIST_TO_TUPLE (new)
# DICT_UPDATE (new)
# DICT_MERGE (new)
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def build_tuple_unpack(x: tuple[paddle.Tensor], y: tuple[paddle.Tensor]):
z = (*x, *y)
return z[0] + 1
def build_list_unpack(x: list[paddle.Tensor], y: list[paddle.Tensor]):
z = [*x, *y]
return z[0] + 1
def build_tuple_unpack_with_call(
x: tuple[paddle.Tensor], y: tuple[paddle.Tensor]
):
z = build_tuple_unpack_with_call_inner(*x, *y)
return z[0] + 1
def build_tuple_unpack_with_call_inner(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
z = (a, b, c, d)
return z
def build_map_unpack(x: dict[str, paddle.Tensor], y: dict[str, paddle.Tensor]):
z = {**x, **y}
return z["a"] + 1
def build_map_unpack_with_call_inner(
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
):
z = {"a": a, "b": b, "c": c, "d": d}
return z
def build_map_unpack_with_call(
x: dict[str, paddle.Tensor], y: dict[str, paddle.Tensor]
):
z = build_map_unpack_with_call_inner(**x, **y)
return z["a"] + 1
class TestBuildUnpack(TestCaseBase):
def test_simple(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
c = paddle.to_tensor(3)
d = paddle.to_tensor(4)
self.assert_results(build_tuple_unpack, (a, b), (c, d))
self.assert_results(build_list_unpack, [a, b], [c, d])
self.assert_results(build_tuple_unpack_with_call, (a, b), (c, d))
self.assert_results(
build_map_unpack, {"a": a, "b": b}, {"c": c, "d": d}
)
self.assert_results(
build_map_unpack_with_call, {"a": a, "b": b}, {"c": c, "d": d}
)
if __name__ == "__main__":
unittest.main()
+125
View File
@@ -0,0 +1,125 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
def pop_jump_if_false(x: bool, y: paddle.Tensor):
if x:
y += 1
else:
y -= 1
return y
def pop_jump_if_true(x: bool, y: bool, z: paddle.Tensor):
return (x or y) and z
def jump_if_false_or_pop(x: bool, y: paddle.Tensor):
return x and (y + 1)
def jump_if_true_or_pop(x: bool, y: paddle.Tensor):
return x or (y + 1)
def jump_absolute(x: int, y: paddle.Tensor):
while x > 0:
y += 1
x -= 1
return y
@check_no_breakgraph
def pop_jump_if_none(x: bool, y: paddle.Tensor):
if x is not None:
y += 1
else:
y -= 1
return y
@check_no_breakgraph
def pop_jump_if_not_none(x: bool, y: paddle.Tensor):
if x is None:
y += 1
else:
y -= 1
return y
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
c = paddle.to_tensor(3)
d = paddle.to_tensor(4)
true_tensor = paddle.to_tensor(True)
false_tensor = paddle.to_tensor(False)
class TestJump(TestCaseBase):
def test_simple(self):
self.assert_results(jump_absolute, 5, a)
self.assert_results(pop_jump_if_false, True, a)
self.assert_results(pop_jump_if_false, False, a)
self.assert_results(jump_if_false_or_pop, True, a)
self.assert_results(jump_if_false_or_pop, False, a)
self.assert_results(jump_if_true_or_pop, True, a)
self.assert_results(jump_if_true_or_pop, False, a)
self.assert_results(pop_jump_if_true, True, False, a)
self.assert_results(pop_jump_if_true, False, False, a)
self.assert_results(pop_jump_if_none, None, a)
self.assert_results(pop_jump_if_none, True, a)
self.assert_results(pop_jump_if_not_none, None, a)
self.assert_results(pop_jump_if_not_none, True, a)
def test_breakgraph(self):
self.assert_results(pop_jump_if_false, true_tensor, a)
self.assert_results(jump_if_false_or_pop, true_tensor, a)
self.assert_results(jump_if_true_or_pop, false_tensor, a)
self.assert_results(pop_jump_if_true, true_tensor, false_tensor, a)
self.assert_results(jump_absolute, 5, a)
self.assert_results(pop_jump_if_false, false_tensor, a)
self.assert_results(jump_if_false_or_pop, false_tensor, a)
self.assert_results(jump_if_true_or_pop, false_tensor, a)
self.assert_results(pop_jump_if_true, true_tensor, false_tensor, a)
self.assert_results(pop_jump_if_none, true_tensor, a)
self.assert_results(pop_jump_if_not_none, true_tensor, a)
def new_var_in_if():
x = paddle.to_tensor(1)
if x > 0:
y = 1
return y
class TestCreateVarInIf(TestCaseBase):
def test_case(self):
self.assert_results(new_var_in_if)
if __name__ == "__main__":
unittest.main()
+363
View File
@@ -0,0 +1,363 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# GET_ITER (new)
# FOR_ITER (new)
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit import sot
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.utils import strict_mode_guard
def gener():
yield 1
yield 2
yield 3
def for_list_1(x: paddle.Tensor):
for i in [1, 2, 3]:
x += i
if x > 2:
x += 1
else:
x -= 1
return x
def for_list_2(x: paddle.Tensor):
for i in [1, 2, 3]:
x += i
if i > 2:
x += 1
else:
x -= 1
return x
def for_dict(x: paddle.Tensor):
map = {1: 2, 3: 4}
for k in map.keys():
x += k
for v in map.values():
x += v
for k, v in map.items():
x += k
x += v
return x
def for_iter(x, it):
for item in it:
x += item
return x
def for_for_fallback(x, it):
for i in [1, 2, 3]:
for item in it:
x += item
return x
def for_break(x: paddle.Tensor, it):
for i in [1, 2, 3]:
x += i
if i == 2:
break
for i in it:
x += i
if i == 2:
break
return x
def for_continue(x: paddle.Tensor, it):
for i in [1, 2, 3]:
if i == 2:
continue
x += i
for i in it:
if i == 2:
continue
x += i
return x
def for_enumerate_var_with_nested_range(x_array):
x = paddle.tensor.fill_constant([1], 'int32', 0)
x_array = paddle.to_tensor(x_array)
for i, num in enumerate(x_array):
for idx in range(num):
x = x + num
return x
def for_create_tmp_in_loop(x, it):
s = x
for i in it:
tmp = i
s += tmp
return s, tmp
def for_without_zero_iter(self_res_dict, output):
res_dict = {"logits": output}
for res_key in list(self_res_dict):
res_dict[res_key] = self_res_dict.pop(res_key)
return res_dict
def for_reconstruct_range_iter():
for i in range(3):
sot.psdb.breakgraph()
global_var_name = None
def for_tmp_var_with_same_name_as_global_var():
total = 0
for i in range(3):
global_var_name = i + 3
sot.psdb.breakgraph()
total += global_var_name
return total
def for_layer_list(layer_list, x):
for net in layer_list:
x = net(x)
return x
class TestForLoop(TestCaseBase):
@strict_mode_guard(False)
def test_list(self):
a = paddle.to_tensor(1)
self.assert_results(for_list_1, a)
def test_list_with_fallback(self):
a = paddle.to_tensor(1)
self.assert_results(for_list_2, a)
def test_dict(self):
a = paddle.to_tensor(1)
self.assert_results(for_dict, a)
@strict_mode_guard(False)
def test_fallback(self):
a = paddle.to_tensor(1)
sym_output = symbolic_translate(for_iter)(a, gener())
paddle_output = for_iter(a, gener())
self.assert_nest_match(sym_output, paddle_output)
@strict_mode_guard(False)
def test_for_iter_fallback(self):
a = paddle.to_tensor(1)
sym_output = symbolic_translate(for_iter)(a, gener())
paddle_output = for_iter(a, gener())
self.assert_nest_match(sym_output, paddle_output)
@strict_mode_guard(False)
def test_for_break(self):
a = paddle.to_tensor(1)
sym_output = symbolic_translate(for_break)(a, gener())
paddle_output = for_break(a, gener())
self.assert_nest_match(sym_output, paddle_output)
@strict_mode_guard(False)
def test_for_continue(self):
a = paddle.to_tensor(1)
sym_output = symbolic_translate(for_continue)(a, gener())
paddle_output = for_continue(a, gener())
self.assert_nest_match(sym_output, paddle_output)
@strict_mode_guard(False)
def test_create_var_in_loop(self):
x = paddle.to_tensor(1, dtype="float32")
a = [1, 2, 3]
self.assert_results(for_create_tmp_in_loop, x, a)
sym_output = symbolic_translate(for_create_tmp_in_loop)(x, iter(a))
paddle_output = for_create_tmp_in_loop(x, iter(a))
self.assert_nest_match(sym_output, paddle_output)
@strict_mode_guard(False)
def test_create_var_in_loop_with_same_name_as_global(self):
self.assert_results(for_tmp_var_with_same_name_as_global_var)
def test_for_without_zero_iter(self):
self_res_dict = {}
output = paddle.to_tensor(2)
self.assert_results(for_without_zero_iter, self_res_dict, output)
@strict_mode_guard(False)
def test_reconstruct_range_iter(self):
self.assert_results(for_reconstruct_range_iter)
def test_layer_list(self):
layers = paddle.nn.LayerList()
for i in range(5):
layers.append(paddle.nn.Linear(5, 5))
x = paddle.rand([5], dtype="float32")
self.assert_results(for_layer_list, layers, x)
def run_list_comp(x):
out = [s.chunk(2, axis=1) for s in x]
return out
class TestListComp(TestCaseBase):
def test_list_comp(self):
x = [paddle.randn([1, 4]), paddle.randn([1, 4])]
self.assert_results(run_list_comp, x)
def for_enumerate_cache(func_list, x):
out = None
for idx, func in enumerate(func_list):
out = func(x[idx])
return out
class TestEnumerateCache(TestCaseBase):
def test_run(self):
func_list = [
paddle.nn.Linear(10, 10),
]
x = [
paddle.randn([5, 10]),
]
with test_instruction_translator_cache_context() as ctx:
out = symbolic_translate(for_enumerate_cache)(func_list, x)
out = symbolic_translate(for_enumerate_cache)(func_list, x)
self.assertEqual(ctx.translate_count, 1)
# after_loop_fn need zzz, and zzz is created as UndefinedVar when generating loop body
# do not set zzz as UndefinedVar again
def undefined_var_case_0():
for i in [1, 2]:
sot.psdb.breakgraph()
zzz = i
zzz = zzz + 1
return zzz
# after_loop_fn need create zzz as UndefinedVar
def undefined_var_case_1():
for i in [1, 2]:
sot.psdb.breakgraph()
aaa = i
for i in [1, 3]:
zzz = i
zzz = zzz + 1
return zzz
class TestUndefinedVarInRiskyCodes(TestCaseBase):
@strict_mode_guard(False)
def test_undefined_var_case_0(self):
self.assert_results(undefined_var_case_0)
@strict_mode_guard(False)
def test_undefined_var_case_1(self):
self.assert_results(undefined_var_case_1)
def comp_with_fallback(x):
paddle.jit.sot.psdb.fallback()
y = [len(t) for t in x]
return paddle.to_tensor(y)
class TestListCompWithFallback(TestCaseBase):
@strict_mode_guard(False)
def test_list_comp_with_fallback(self):
x = [paddle.randn([4, 6])]
self.assert_results(comp_with_fallback, x)
def for_arange(x):
for i in paddle.arange(0, 5):
x = x + i
return x
class TestArange(TestCaseBase):
def test_arange(self):
x = paddle.to_tensor(1)
self.assert_results(for_arange, x)
def for_break_with_load_same_consts(x: paddle.Tensor):
y = None
z = None
for i in [1, 2, 3]:
if y is None:
y = i
if z is None:
z = i
x += y + z
sot.psdb.breakgraph()
return x
class TestForBreakWithLoadSameConsts(TestCaseBase):
@strict_mode_guard(False)
def test_for_break_with_load_same_consts(self):
x = paddle.to_tensor(1)
self.assert_results(for_break_with_load_same_consts, x)
def for_break_with_write_pre_defined_name(x: paddle.Tensor):
y = None
for i in [1, 2, 3]:
y = i
sot.psdb.breakgraph()
return x + 1
class TestForBreakWithWritePreDefinedName(TestCaseBase):
@strict_mode_guard(False)
def test_for_break_with_write_pre_defined_name(self):
x = paddle.to_tensor(1)
self.assert_results(for_break_with_write_pre_defined_name, x)
if __name__ == "__main__":
unittest.main()
+103
View File
@@ -0,0 +1,103 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# MAKE_FUNCTION
# CALL_FUNCTION_KW
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def make_fn_simple(x: paddle.Tensor):
def fn(a, b, c, d):
return a + b + c + d
return fn(1, 2, 3, 4) + x
def make_fn_default(x: paddle.Tensor):
def fn(a, b, c=5, d=3):
return a + b + c + d
return fn(1, 2) + fn(1, 2, c=3) + x
def make_fn_annotation(x: paddle.Tensor):
def fn(a, b: int, c: int, d):
return a + b + c + d
return fn(1, 2, 3, 4) + x
def make_fn_kwdefault(x: paddle.Tensor):
def fn(a, b, *, c=3, d=4):
return a + b + c + d
return fn(1, 2) + fn(3, 4, c=1, d=2) + x
def make_fn_closure(x: paddle.Tensor):
def fn(a, b, c, d):
y = x
return a + b + c + d
return fn(1, 2, 3, 4) + x
def make_fn_mix(x: paddle.Tensor):
def fn(a: int = 1, b: float = 2.0, /, *, c: int = 4, d: float = 5):
# y = x
return a + b + c + d
return fn(2, 3, c=1, d=2.0) + x
def make_fn_tensor_default(x: paddle.Tensor):
tensor = paddle.to_tensor(1.0)
def fn(a, b, c=tensor):
return a + b + c
return fn(1, 2) + x
def make_fn_tensor_kwdefault(x: paddle.Tensor):
tensor = paddle.to_tensor(1.0)
def fn(*args, c=tensor):
return args[0] + args[1] + c
return fn(1, 2, c=3) + x
class TestMakeFunction(TestCaseBase):
def test_simple(self):
self.assert_results(make_fn_simple, paddle.to_tensor(1))
self.assert_results(make_fn_default, paddle.to_tensor(1))
self.assert_results(make_fn_annotation, paddle.to_tensor(1))
self.assert_results(make_fn_kwdefault, paddle.to_tensor(1))
self.assert_results(make_fn_closure, paddle.to_tensor(1))
self.assert_results(make_fn_mix, paddle.to_tensor(1))
def test_tensor_default(self):
self.assert_results(make_fn_tensor_default, paddle.to_tensor(1))
self.assert_results(make_fn_tensor_kwdefault, paddle.to_tensor(1))
if __name__ == "__main__":
unittest.main()
+387
View File
@@ -0,0 +1,387 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import operator
import unittest
from test_case_base import TestCaseBase
import paddle
def unary_positive(x: int):
y = +x
return y
def unary_negative(x: paddle.Tensor):
y = -x
return y
def unary_not(x: paddle.Tensor):
y = not x
return y
def unary_invert(x: paddle.Tensor):
y = ~x
return y
def binary_power(x: paddle.Tensor, y: paddle.Tensor):
z = x**y
return z
def binary_multiply(x: paddle.Tensor, y: paddle.Tensor):
z = x * y
return z
def binary_matrix_multiply(x: paddle.Tensor, y: paddle.Tensor):
z = x @ y
return z
def binary_floor_divide(x: paddle.Tensor, y: paddle.Tensor):
z = x // y
return z
def binary_true_divide(x: paddle.Tensor, y: paddle.Tensor):
z = x / y
return z
def binary_modulo(x: paddle.Tensor, y: paddle.Tensor):
z = x % y
return z
def binary_add(x: paddle.Tensor, y: paddle.Tensor):
z = x + y
return z
def binary_subtract(x: paddle.Tensor, y: paddle.Tensor):
z = x - y
return z
def binary_lshift(x: int, y: int):
z = x << y
return z
def binary_rshift(x: int, y: int):
z = x >> y
return z
def binary_and(x: paddle.Tensor, y: paddle.Tensor):
z = x & y
return z
def binary_or(x: paddle.Tensor, y: paddle.Tensor):
z = x | y
return z
def binary_xor(x: paddle.Tensor, y: paddle.Tensor):
z = x ^ y
return z
def inplace_power(x: paddle.Tensor, y: paddle.Tensor):
x **= y
return x
def inplace_multiply(x: paddle.Tensor, y: paddle.Tensor):
x *= y
return x
def inplace_matrix_multiply(x: paddle.Tensor, y: paddle.Tensor):
x @= y
return x
def inplace_floor_divide(x: paddle.Tensor, y: paddle.Tensor):
x //= y
return x
def inplace_true_divide(x: paddle.Tensor, y: paddle.Tensor):
x /= y
return x
def inplace_modulo(x: paddle.Tensor, y: paddle.Tensor):
x %= y
return x
def inplace_add(x: paddle.Tensor, y: paddle.Tensor):
x += y
return x
def inplace_subtract(x: paddle.Tensor, y: paddle.Tensor):
x -= y
return x
def inplace_lshift(x: paddle.Tensor, y: int):
x <<= y
return x
def inplace_rshift(x: paddle.Tensor, y: int):
x >>= y
return x
def inplace_and(x: paddle.Tensor, y: paddle.Tensor):
x &= y
return x
def inplace_or(x: paddle.Tensor, y: paddle.Tensor):
x |= y
return x
def inplace_xor(x: paddle.Tensor, y: paddle.Tensor):
x ^= y
return x
def list_getitem(x: int, y: paddle.Tensor):
z = [x, y]
return operator.getitem(z, 1) + 1
def list_getitem_slice(x: int, y: paddle.Tensor):
z = [x, y]
return operator.getitem(z, slice(0, 2))
def list_setitem_int(x: int, y: paddle.Tensor):
z = [x, y]
operator.setitem(z, 0, 3)
return z
def list_setitem_tensor(x: int, y: paddle.Tensor):
z = [x, y]
operator.setitem(z, 1, paddle.to_tensor(3))
return z
def list_delitem_int(x: int, y: paddle.Tensor):
z = [x, y]
operator.delitem(z, 0)
return z
def list_delitem_tensor(x: int, y: paddle.Tensor):
z = [x, y]
operator.delitem(z, 1)
return z
def dict_getitem_int(x: int, y: paddle.Tensor):
z = {1: y, 2: y + 1}
return operator.getitem(z, 1)
def dict_getitem_tensor(x: int, y: paddle.Tensor):
z = {1: y, 2: y + 1}
return operator.getitem(z, 2)
def dict_setitem_int(x: int, y: paddle.Tensor):
z = {'x': x, 'y': y}
operator.setitem(z, 'x', 2)
return z
def dict_setitem_tensor(x: int, y: paddle.Tensor):
z = {'x': x, 'y': y}
operator.setitem(z, 'y', paddle.to_tensor(3))
return z
def dict_delitem_int(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
operator.delitem(z, 1)
return z
def dict_delitem_tensor(x: int, y: paddle.Tensor):
z = {1: x, 2: y + 1}
operator.delitem(z, 2)
return z
def tuple_getitem_int(x: int, y: paddle.Tensor):
x = (x, y)
return operator.getitem(x, 0)
def tuple_getitem_tensor(x: int, y: paddle.Tensor):
x = (x, y)
return operator.getitem(x, 1)
def tuple_getitem_slice(x: int, y: paddle.Tensor):
x = (x, y, 1)
return operator.getitem(x, slice(0, 2))
def operator_add(x: int, y: paddle.Tensor):
return operator.add(x, y)
def operator_mul(x: int, y: paddle.Tensor):
return operator.mul(x, y)
def operator_truth(y: paddle.Tensor):
return operator.truth(y)
def operator_is_(x: paddle.Tensor, y: paddle.Tensor):
return (operator.is_(x, x), operator.is_(x, y))
def operator_in_(x: int, y: list):
return x in y
def operator_not_in_(x: int, y: list):
return x not in y
def operator_is_not(x: paddle.Tensor, y: paddle.Tensor):
return (operator.is_not(x, x), operator.is_not(x, y))
def operator_pos(y: int):
return operator.pos(+y)
class TestOperators(TestCaseBase):
def test_simple(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(True)
c = paddle.to_tensor(3)
d = paddle.to_tensor(4)
e = paddle.to_tensor([[1, 2], [3, 4], [5, 6]], dtype='float32')
f = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], dtype='float32')
g = paddle.to_tensor(False)
self.assert_results(unary_positive, 1)
self.assert_results(unary_negative, a)
self.assert_results(unary_not, b)
self.assert_results(unary_invert, b)
self.assert_results(binary_power, c, d)
self.assert_results(binary_multiply, c, d)
self.assert_results(binary_matrix_multiply, e, f)
self.assert_results(binary_floor_divide, c, d)
self.assert_results(binary_true_divide, c, d)
self.assert_results(binary_modulo, c, d)
self.assert_results(binary_add, c, d)
self.assert_results(binary_subtract, c, d)
self.assert_results(binary_lshift, 10, 2)
self.assert_results(binary_rshift, 10, 1)
self.assert_results(binary_and, b, g)
self.assert_results(binary_or, b, g)
self.assert_results(binary_xor, b, g)
self.assert_results(inplace_power, c, d)
self.assert_results(inplace_multiply, c, d)
self.assert_results(inplace_matrix_multiply, e, f)
self.assert_results(inplace_floor_divide, c, d)
self.assert_results(inplace_true_divide, c, d)
self.assert_results(inplace_modulo, c, d)
self.assert_results(inplace_add, c, d)
self.assert_results(inplace_subtract, c, d)
self.assert_results(inplace_lshift, 10, 2)
self.assert_results(inplace_rshift, 10, 1)
self.assert_results(inplace_and, b, g)
self.assert_results(inplace_or, b, g)
self.assert_results(inplace_xor, b, g)
def test_operator_simple(self):
self.assert_results(operator_add, 1, paddle.to_tensor(2))
self.assert_results(operator_mul, 1, paddle.to_tensor(2))
self.assert_results(operator_truth, paddle.to_tensor(2))
self.assert_results(
operator_is_, paddle.to_tensor(2), paddle.to_tensor(3)
)
self.assert_results(
operator_is_not, paddle.to_tensor(2), paddle.to_tensor(3)
)
self.assert_results(operator_pos, 1)
self.assert_results(operator_in_, 12, [1, 2, 12])
self.assert_results(operator_in_, 12, [1, 2, 3])
self.assert_results(operator_not_in_, 12, [1, 2, 3])
self.assert_results(operator_not_in_, 12, [1, 2, 3])
def test_operator_list(self):
self.assert_results(list_getitem, 1, paddle.to_tensor(2))
self.assert_results(list_getitem_slice, 1, paddle.to_tensor(2))
self.assert_results(list_setitem_int, 1, paddle.to_tensor(2))
self.assert_results_with_side_effects(
list_setitem_tensor, 1, paddle.to_tensor(2)
)
self.assert_results(list_delitem_int, 1, paddle.to_tensor(2))
self.assert_results(list_delitem_tensor, 1, paddle.to_tensor(2))
def test_operator_dict(self):
self.assert_results(dict_getitem_int, 1, paddle.to_tensor(2))
self.assert_results(dict_getitem_tensor, 1, paddle.to_tensor(2))
self.assert_results(dict_setitem_int, 1, paddle.to_tensor(2))
self.assert_results_with_side_effects(
dict_setitem_tensor, 1, paddle.to_tensor(2)
)
self.assert_results(dict_delitem_int, 1, paddle.to_tensor(2))
self.assert_results(dict_delitem_tensor, 1, paddle.to_tensor(2))
def test_operator_tuple(self):
self.assert_results(tuple_getitem_int, 1, paddle.to_tensor(2))
self.assert_results(tuple_getitem_tensor, 1, paddle.to_tensor(2))
self.assert_results(tuple_getitem_slice, 1, paddle.to_tensor(2))
def run_not_eq(x: paddle.Tensor, y: int):
out = paddle.reshape(x, [1, -1]) != y
out = out.astype('float32')
return out
class TestNotEq(TestCaseBase):
def test_not_eq(self):
x = paddle.to_tensor([2])
y = 3
self.assert_results(run_not_eq, x, y)
if __name__ == "__main__":
unittest.main()
+160
View File
@@ -0,0 +1,160 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# BUILD_SLICE (new)
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
def build_list_slice(x: list, y: paddle.Tensor):
x[2:4] = [0, 1]
return x[0] + y
def build_list_slice_with_step(x: list, y: paddle.Tensor):
x[1:5:2] = [0, 1]
return x[0] + y
def build_tuple_slice(x: list, y: paddle.Tensor):
x[2:4] = (0, 1)
return x[0] + y
def build_tuple_slice_with_step(x: list, y: paddle.Tensor):
x[1:5:2] = (0, 1)
return x[0] + y
def tensor_subscript_ellipsis(x: paddle.Tensor, y: paddle.Tensor):
return x[...] + y[...]
@check_no_breakgraph
def tensor_subscript_tensor(x: paddle.Tensor):
d0, d1 = paddle.shape(x)
return x[: d0 // 2, d1 // 2 : d1]
class TestSlice(TestCaseBase):
def test_simple(self):
x = list(range(10))
y = paddle.arange(10)
self.assert_results_with_side_effects(build_list_slice, x, y)
self.assert_results_with_side_effects(build_list_slice_with_step, x, y)
self.assert_results_with_side_effects(build_tuple_slice, x, y)
self.assert_results_with_side_effects(build_tuple_slice_with_step, x, y)
class MyLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linears = paddle.nn.LayerList(
[paddle.nn.Linear(10, 10) for i in range(10)]
)
def forward(self, x):
for i, l in enumerate(self.linears):
x = self.linears[i // 2](x) + l(x)
return x
def layer_list_slice(layer, x):
out = layer(x)
return out
class TestLayerList(TestCaseBase):
def test_layer_list_slice(self):
layer = MyLayer()
x = paddle.randn([5, 10])
self.assert_results(layer_list_slice, layer, x)
def tensor_slice(x: paddle.Tensor):
return x[1, 1, 1] + 1
class TestTensorSlice(TestCaseBase):
def test_tensor_slice(self):
x = paddle.randn([4, 3, 10])
self.assert_results(tensor_slice, x)
class TestTensorEllipsis(TestCaseBase):
def test_tensor_subscript_ellipsis(self):
x = paddle.rand((10,))
y = paddle.rand((10, 10))
self.assert_results(tensor_subscript_ellipsis, x, y)
class TestTensorSubscriptTensor(TestCaseBase):
def test_tensor_subscript_tensor(self):
x = paddle.rand((10, 10))
self.assert_results(tensor_subscript_tensor, x)
class LayerListNet(paddle.nn.Layer):
def __init__(self) -> None:
super().__init__()
self.layer_list = paddle.nn.LayerList(
[paddle.nn.Linear(5, 5), paddle.nn.Linear(5, 5)]
)
def forward(self, x):
out = self.layer_list[0](x)
for layer in self.layer_list[1:]:
out = layer(out)
return out
class TestLayerListSlice(TestCaseBase):
def test_layer_list_slice(self):
x = paddle.randn([2, 5])
net = LayerListNet()
self.assert_results(layer_list_slice, net, x)
@check_no_breakgraph
def string_slice(x: str):
return x[2:7:2] + x[1:5] + x[4]
class TestStringSlice(TestCaseBase):
def test_string_slice(self):
x = "1234567"
self.assert_results(string_slice, x)
@check_no_breakgraph
def tensor_slice_as_input(x: slice):
tensor = paddle.to_tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
return tensor[x]
class TestSliceAsInput(TestCaseBase):
def test_slice_as_input(self):
x = slice(2, 7, 2)
self.assert_results(tensor_slice_as_input, x)
if __name__ == "__main__":
unittest.main()
+73
View File
@@ -0,0 +1,73 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.nn.functional import relu
def paddle_api_method_call(x: paddle.Tensor):
m = x + 2
m = paddle.nn.functional.relu(m)
return m
def paddle_api_function_call(x: paddle.Tensor):
m = x + 2
m = relu(m)
return m
def paddle_api_function_call_concat(
x: paddle.Tensor, y: paddle.Tensor, axis: int
):
return paddle.concat([x, y], axis=axis)
def paddle_api_function_breakgraph_when_type_error(
x: paddle.Tensor, axis: paddle.Tensor
):
return paddle.nn.functional.softmax(x, axis=axis)
class TestPaddleApiCall(TestCaseBase):
def test_paddle_api_method_call(self):
self.assert_results(paddle_api_method_call, paddle.to_tensor(2.0))
self.assert_results(paddle_api_method_call, paddle.to_tensor(-5.0))
self.assert_results(paddle_api_method_call, paddle.to_tensor(0.0))
def test_paddle_api_function_call(self):
self.assert_results(paddle_api_function_call, paddle.to_tensor(2.0))
self.assert_results(paddle_api_function_call, paddle.to_tensor(-5.0))
self.assert_results(paddle_api_function_call, paddle.to_tensor(0.0))
def test_paddle_api_function_call_concat(self):
a = paddle.to_tensor([[1, 2], [3, 4]])
b = paddle.to_tensor([[5, 6], [7, 8]])
self.assert_results(paddle_api_function_call_concat, a, b, 0)
self.assert_results(paddle_api_function_call_concat, a, b, 1)
def test_paddle_api_function_breakgraph_when_type_error(self):
x = paddle.to_tensor([[1, 2], [3, 4]], dtype=paddle.float32)
axis = paddle.to_tensor(1)
self.assert_results(
paddle_api_function_breakgraph_when_type_error, x, axis
)
if __name__ == "__main__":
unittest.main()
+94
View File
@@ -0,0 +1,94 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
class SimpleNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear1 = paddle.nn.Linear(10, 1)
def forward(self, x):
out1 = self.linear1(x)
return out1
class SimpleNet_bound(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear1 = paddle.nn.Linear(10, 1)
def add(self, x):
return x + 1
def forward(self, x):
x = self.add(x)
out1 = self.linear1(x)
return out1
def net_call(x: paddle.Tensor, net):
return net(x)
def net_call_passed_by_user(x: paddle.Tensor, net_forward):
return net_forward(x)
class SimpleNetWithSequenital(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.seq = paddle.nn.Sequential(
paddle.nn.Linear(10, 10),
paddle.nn.Linear(10, 10),
paddle.nn.Linear(10, 1),
)
def forward(self, x):
out1 = self.seq(x)
return out1
class TestLayer(TestCaseBase):
def test_layer(self):
x = paddle.rand((10,))
y = paddle.rand((10, 10))
net = SimpleNet()
self.assert_results(net_call, x, net)
self.assert_results(net_call, y, net)
self.assert_results(net_call_passed_by_user, x, net.forward)
def test_layer_with_sequential(self):
x = paddle.rand((10,))
y = paddle.rand((10, 10))
net = SimpleNetWithSequenital()
self.assert_results(net_call, x, net)
self.assert_results(net_call, y, net)
self.assert_results(net_call_passed_by_user, x, net.forward)
def test_bound(self):
x = paddle.rand((10,))
y = paddle.rand((10, 10))
net = SimpleNet_bound()
self.assert_results(net_call, x, net)
self.assert_results(net_call, y, net)
if __name__ == "__main__":
unittest.main()
+154
View File
@@ -0,0 +1,154 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@check_no_breakgraph
def tensor_method_call_1(x: paddle.Tensor):
y = x + 1
return y.mean()
@check_no_breakgraph
def tensor_method_call_2(a: paddle.Tensor, b: paddle.Tensor):
c = a.add(b)
d = c.multiply(a)
e = d.subtract(b)
f = e.divide(a)
g = f.pow(2) + f.abs().sqrt()
h = (g.abs() + 1).log() - (g / g.max()).exp()
i = h.sin() + h.cos()
return i
def tensor_method_passed_by_user(a: paddle.Tensor, func: paddle.Tensor):
return func(a)
@check_no_breakgraph
def tensor_method_property_without_breakgraph(
a: paddle.Tensor, b: paddle.Tensor
):
return (
a.name,
a.persistable,
a.dtype,
a.is_tensor(),
a @ b.T.astype(a.dtype)
+ len(a.shape)
+ b.size
+ a.ndim
+ a.dim()
+ a.rank(),
a.element_size(),
)
def tensor_method_property_with_breakgraph(a: paddle.Tensor, b: paddle.Tensor):
return (
a.type,
a.numpy(),
a.tolist(),
str(a.place),
a.clear_gradient(),
a.is_dense(),
)
@check_no_breakgraph
def tensor_method_property_mT(a: paddle.Tensor):
return a.mT
@check_no_breakgraph
def middle_tensor_name(a: paddle.Tensor, b: paddle.Tensor):
c = a + b
return c.name
@check_no_breakgraph
def tensor_numel(x: paddle.Tensor):
return x.numel(), int(x.size)
@check_no_breakgraph
def tensor_dim(x: paddle.Tensor):
return x.dim(), x.ndimension(), x.ndim, x.rank()
@check_no_breakgraph
def tensor_len(x: paddle.Tensor):
return len(x)
class TestTensorMethod(TestCaseBase):
def test_tensor_method_1(self):
x = paddle.rand([10])
y = paddle.rand([2, 4, 6])
self.assert_results(tensor_method_call_1, x)
self.assert_results(tensor_method_call_1, y)
def test_tensor_method_2(self):
x = paddle.rand([42])
y = paddle.rand([42])
self.assert_results(tensor_method_call_2, x, y)
def test_tensor_method_passed_by_user(self):
x = paddle.rand([42])
y = paddle.rand([42])
self.assert_results(tensor_method_passed_by_user, x, y.add)
def test_tensor_method_property(self):
x = paddle.rand([42, 24], dtype='float64')
y = paddle.rand([42, 24], dtype='float32')
self.assert_results(tensor_method_property_without_breakgraph, x, y)
self.assert_results(tensor_method_property_with_breakgraph, x, y)
@unittest.skip("TODO: dynamic tensor name is different")
def test_middle_tensor_name(self):
x = paddle.rand([42, 24])
y = paddle.rand([42, 24])
self.assert_results(middle_tensor_name, x, y)
def test_tensor_method_property_mT(self):
x = paddle.rand([42, 24, 2, 2, 3, 2], dtype='float64')
y = paddle.rand([42, 24, 2, 3, 3, 2], dtype='float32')
self.assert_results(tensor_method_property_mT, x)
self.assert_results(tensor_method_property_mT, y)
def test_tensor_numel(self):
x = paddle.rand([2, 3], dtype='float32')
self.assert_results(tensor_numel, x)
x = paddle.rand([3, 3], dtype='float32')
self.assert_results(tensor_numel, x) # test dynamic shape
def test_tensor_dim(self):
x = paddle.rand([2, 3], dtype='float32')
self.assert_results(tensor_dim, x)
def test_tensor_len(self):
x = paddle.rand([2, 3], dtype='float32')
self.assert_results(tensor_len, x)
x = paddle.rand([3, 3], dtype='float32')
self.assert_results(tensor_len, x) # test dynamic shape
if __name__ == "__main__":
unittest.main()
+261
View File
@@ -0,0 +1,261 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import inspect
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils import strict_mode_guard
def foo(x: int, y: paddle.Tensor):
z = 3
def local(a, b=5):
return a + x + z + b + y
return local(4) + z
def foo2(y: paddle.Tensor, x=1):
"""
Test strip default value
"""
z = 3
def local(a, b=5):
return a + x + z + b + y
return local(4)
def foo3(y: paddle.Tensor, x=1):
"""
Test Closure Band Default
"""
z = 3
def local(a, b=5):
nonlocal z
z = 4
return a + x + z + b + y
return local(4)
global_z = 3
def test_global(y: paddle.Tensor):
"""
Test Global variable
"""
def local(a, b=5):
global global_z
global_z += 1
return a + global_z + b + y
return local(1)
def multi(c):
return c + 2
def wrapper_function(func):
a = 2
def inner():
return func(a)
return inner
wrapped_multi = wrapper_function(multi)
def foo5(y: paddle.Tensor):
"""
Test incoming closures
"""
a = wrapped_multi()
return a
def outwrapper(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
def foo6(y: paddle.Tensor):
"""
Test Decorator
"""
@outwrapper
def load_1(a, b=5):
return a + b
return load_1(1)
import numpy as np
def numpy_sum(m):
"""
Test loop call
Example: a->b->c->a
"""
a = np.array([1, 2, 3])
tmp = np.sum(a)
return m + 1
def lambda_closure(x, m):
"""
lambda closure.
"""
def break_graph_closure():
print("yes")
return x + m
return break_graph_closure()
# motivated by python builtin decorator
def kwargs_wrapper(func):
sig = inspect.signature(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
inner.__signature__ = sig
return inner
@kwargs_wrapper
def func7(a, b):
return a + b
def foo7():
return func7(3, 5)
def create_closure():
x = 1
def closure():
return x + 1
return closure
class TestClosure(TestCaseBase):
def test_closure(self):
self.assert_results(foo, 1, paddle.to_tensor(2))
self.assert_results(foo2, paddle.to_tensor(2))
self.assert_results(foo3, paddle.to_tensor(2))
self.assert_results_with_global_check(
test_global, ["global_z"], paddle.to_tensor(2)
)
self.assert_results(foo5, paddle.to_tensor(2))
self.assert_results(foo6, paddle.to_tensor(2))
self.assert_results(numpy_sum, paddle.to_tensor(1))
with strict_mode_guard(False):
self.assert_results(
lambda_closure, paddle.to_tensor(2), paddle.to_tensor(1)
)
class TestClosure2(TestCaseBase):
def test_closure(self):
self.assert_results(foo7)
# Side Effect.
def test_slice_in_for_loop(x, iter_num=3):
x = paddle.to_tensor(x)
a = []
# Use `paddle.full` so that static analysis can analyze the type of iter_num is Tensor
iter_num = paddle.full(
shape=[1], fill_value=iter_num, dtype="int32"
) # TODO(liym27): Delete it if the type of parameter iter_num can be resolved
for i in range(iter_num):
a.append(x)
for i in range(iter_num):
a[i] = x
out = a[2]
return out
class TestClosure3(TestCaseBase):
def test_closure(self):
tx = paddle.to_tensor([1.0, 2.0, 3.0])
# need side effect of list.
# self.assert_results(test_slice_in_for_loop, tx)
def non_local_test(t: paddle.Tensor):
a = 1
def func1():
nonlocal a
t = a
a = 2
return t
def func2():
nonlocal a
a = 1
return a
t += func1() # add 2
t += func2() # add 1
t += a # add 1
return t
class TestClosure4(TestCaseBase):
def test_closure(self):
tx = paddle.to_tensor([1.0])
self.assert_results(non_local_test, tx)
class TestCreateClosure(TestCaseBase):
def test_create_closure(self):
closure = create_closure()
self.assert_results(closure)
if __name__ == "__main__":
unittest.main()
# Instructions:
# LOAD_CLOSURE
# LOAD_DEREF
# LOAD_CLASSDEREF
# STORE_DEREF
# DELETE_DEREF
# STORE_GLOBAL
+83
View File
@@ -0,0 +1,83 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import assert_true, check_no_breakgraph
def string_format(x: paddle.Tensor):
whilespace = 123
hello_world = f"Hello {whilespace} World"
z = assert_true(hello_world == "Hello 123 World")
hello_world2 = f"Hello {whilespace}{whilespace} World"
z = assert_true(hello_world2 == "Hello 123123 World")
hello_world_lower = "Hello World".lower()
z = assert_true(hello_world_lower == "hello world")
return x + 1
def string_lower(x: paddle.Tensor):
hello_world_lower = "Hello World".lower()
z = assert_true(hello_world_lower == "hello world")
return x + 1
@check_no_breakgraph
def str_startswith():
s = "Hello World"
a1 = s.startswith("Hello")
a2 = s.startswith("World")
a3 = s.startswith("Hello World")
a4 = s.startswith("Hello World!")
a5 = s.startswith("Hello", 5)
a6 = s.startswith("Hello", 1, 4)
a7 = s.startswith("Hello", 0, 11)
return (a1, a2, a3, a4, a5, a6, a7)
@check_no_breakgraph
def str_endswith():
s = "Hello World"
a1 = s.endswith("Hello")
a2 = s.endswith("World")
a3 = s.endswith("Hello World")
a4 = s.endswith("Hello World!")
a5 = s.endswith("Hello", 5)
a6 = s.endswith("Hello", 0, 4)
a7 = s.endswith("Hello", 1, 11)
return (a1, a2, a3, a4, a5, a6, a7)
class TestString(TestCaseBase):
def test_string_format(self):
self.assert_results(string_format, paddle.to_tensor(1))
def test_string_lower(self):
self.assert_results(string_lower, paddle.to_tensor(1))
def test_str_startswith(self):
self.assert_results(str_startswith)
def test_str_endswith(self):
self.assert_results(str_endswith)
if __name__ == "__main__":
unittest.main()
+175
View File
@@ -0,0 +1,175 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit import sot
global_x = 1
global_y = paddle.to_tensor(2)
global_z = None
global_del_val = 1
global_dict = {}
global_list = [1, 2]
global_inline = 0
def global_func_int():
global global_x
global_x = global_x + 1
return global_x
def global_func_int_add():
global global_x
global_x = global_x + global_x
return global_x + global_x
def global_func_tensor_int_add(tensor_y: paddle.Tensor):
global global_x
global_x += 1
return global_x + tensor_y
def global_multiple_update():
global global_x
global_x = 999
global_x = 888
global_x = 777
return global_x - 1
def global_func_tensor():
global global_y
global_y = global_y + global_y
return global_y
def global_func_tensor_add():
global global_y
global_y = global_y + global_y
return global_y + global_y
def global_func():
global global_x
global global_y
global global_z
global_z = global_x + global_y
return global_z
def global_del_global():
global global_del_val
del global_del_val
def global_func_dict():
global global_dict
global_dict["key"] = "value"
global_dict.update({"test_key1": "test_value2"})
return global_dict
def global_func_control1():
global global_dict
if "key" in global_dict:
del global_dict["key"]
return global_dict
def global_func_control2():
global global_list
for i in range(len(global_list)):
global_list[i] = global_list[i] + 1
return global_list
def global_func_inline_inner_1():
global global_inline
global_func_inline_inner_2()
global_inline += 1
def global_func_inline_inner_2():
global global_inline
global_inline += 1
def global_func_inline():
global_func_inline_inner_1()
global global_inline
return global_inline
class TestGlobal(TestCaseBase):
def test_global_func_int(self):
global global_x
self.assert_results_with_global_check(global_func_int, ["global_x"])
global_x += 1
self.assert_results_with_global_check(global_func_int, ["global_x"])
self.assert_results_with_global_check(global_func_int_add, ["global_x"])
def test_global_multiple_update(self):
self.assert_results_with_global_check(
global_multiple_update, ["global_x"]
)
def test_global_func_tensor_int_add(self):
self.assert_results_with_global_check(
global_func_tensor_int_add, ["global_x"], paddle.to_tensor(1)
)
def test_global_func_tensor(self):
self.assert_results_with_global_check(global_func_tensor, ["global_y"])
self.assert_results_with_global_check(
global_func_tensor_add, ["global_y"]
)
def test_global_func(self):
self.assert_results_with_global_check(global_func, ["global_z"])
self.assertIn("global_del_val", global_del_global.__globals__)
sot.symbolic_translate(global_del_global)()
self.assertNotIn("global_del_val", global_del_global.__globals__)
def test_global_func_dict(self):
self.assert_results_with_global_check(global_func_dict, ["global_dict"])
self.assert_results_with_global_check(
global_func_control1, ["global_dict"]
)
def test_global_func_list(self):
self.assert_results_with_global_check(
global_func_control2, ["global_list"]
)
def test_global_func_inline(self):
global global_inline
global_inline = 0
sot.symbolic_translate(global_func_inline)()
self.assertEqual(global_inline, 2)
sot.symbolic_translate(global_func_inline)()
self.assertEqual(global_inline, 4)
if __name__ == "__main__":
unittest.main()
+190
View File
@@ -0,0 +1,190 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import operator
import unittest
from functools import reduce
from test_case_base import TestCaseBase
from paddle.jit import sot
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils.envs import strict_mode_guard
def create_simple_generator(a, b):
yield a
yield b
@check_no_breakgraph
def simple_generator_user():
gen = create_simple_generator(1, 2)
x = next(gen)
y = next(gen)
return x, y
@check_no_breakgraph
def genexpr_user():
gen = (i for i in range(2))
x = next(gen)
y = next(gen)
return x, y
def echo():
recv = None
recv = yield recv
recv = yield recv
recv = yield recv
@check_no_breakgraph
def generator_send():
s = echo()
init = next(s)
recv_1 = s.send(2)
recv_2 = s.send(3)
return init, recv_1, recv_2
def yield_from_generator():
yield from create_simple_generator(1, 2)
@check_no_breakgraph
def generator_yield_from_generator_user():
s = yield_from_generator()
x = next(s)
y = next(s)
return x, y
def yield_from_iterable():
yield from [1, 2]
def generator_yield_from_iterable_user():
s = yield_from_iterable()
x = next(s)
y = next(s)
return x, y
def for_iterate_generator():
out = 0
for i in create_simple_generator(1, 2):
out += i
return out
def create_simple_generator_with_breakgraph():
yield 1
sot.psdb.breakgraph()
yield 2
def simple_generator_user_with_breakgraph():
gen = create_simple_generator_with_breakgraph()
x = next(gen)
y = next(gen)
return x + y
def create_simple_generator_with_outer_breakgraph():
yield 1
yield 2
def simple_generator_user_with_outer_breakgraph():
gen = create_simple_generator_with_outer_breakgraph()
x = next(gen)
sot.psdb.breakgraph()
y = next(gen)
return x + y
class TestGeneratorCommon(TestCaseBase):
def test_generator_simple(self):
self.assert_results(simple_generator_user)
def test_generator_send(self):
self.assert_results(generator_send)
def test_genexpr(self):
self.assert_results(genexpr_user)
def test_generator_yield_from_generator(self):
self.assert_results(generator_yield_from_generator_user)
def test_generator_yield_from_iterable(self):
self.assert_results(generator_yield_from_iterable_user)
def test_for_iterate_generator(self):
self.assert_results(for_iterate_generator)
@strict_mode_guard(False)
def test_generator_simple_with_breakgraph(self):
self.assert_results(simple_generator_user_with_breakgraph)
@strict_mode_guard(False)
def test_generator_simple_with_outer_breakgraph(self):
self.assert_results(simple_generator_user_with_outer_breakgraph)
@check_no_breakgraph
def generator_sum():
return sum(i for i in range(10))
@check_no_breakgraph
def generator_max():
return max((-2) ** i for i in range(10))
@check_no_breakgraph
def generator_min():
return min((-2) ** i for i in range(10))
@check_no_breakgraph
def generator_reduce():
return reduce(operator.add, (i for i in range(10)))
@check_no_breakgraph
def generator_map():
return list(map(lambda x: x**2, (i for i in range(10)))) # noqa: C417
class TestGeneratorDispatch(TestCaseBase):
def test_generator_sum(self):
self.assert_results(generator_sum)
def test_generator_max(self):
self.assert_results(generator_max)
def test_generator_min(self):
self.assert_results(generator_min)
def test_generator_reduce(self):
self.assert_results(generator_reduce)
def test_generator_map(self):
self.assert_results(generator_map)
if __name__ == "__main__":
unittest.main()
+426
View File
@@ -0,0 +1,426 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import types
import unittest
import numpy as np
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils.exceptions import InnerError
sot_test_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(f'{sot_test_dir}/../dygraph_to_static'))
from dygraph_to_static_utils import Dy2StTestBase, test_default_mode_only
# ---------------------- test single inheritance case ----------------------
class A:
@check_no_breakgraph
def add2(self, x):
return x + 2
@check_no_breakgraph
def add3(self, x):
return x + 3
class B(A):
@check_no_breakgraph
def test_super_no_args_add2(self, x):
y = super().add2(x)
return y
@check_no_breakgraph
def test_super_with_args_add3(self, x):
y = super(B, self).add3(x) # noqa: UP008
return y
@check_no_breakgraph
def test_super_both_add5(self, x):
return super().add2(x) + super(B, self).add3(x) # noqa: UP008
@check_no_breakgraph
def test_self_name_me(me, x):
# Test case where the instance is referred to as 'me' instead of 'self'
return super(B, me).add2(x) # noqa: UP008
@check_no_breakgraph
def test_self_name_this(this, x):
# Test case where the instance is referred to as 'this' instead of 'self'
return super(B, this).add2(x) # noqa: UP008
class TestSingleInheritance(TestCaseBase):
def test_super_no_args(self):
self.assert_results(B().test_super_no_args_add2, paddle.to_tensor(33))
def test_super_with_args(self):
self.assert_results(B().test_super_with_args_add3, paddle.to_tensor(33))
def test_super_both(self):
self.assert_results(B().test_super_both_add5, paddle.to_tensor(33))
def test_super_self_name(self):
self.assert_results(B().test_self_name_me, paddle.to_tensor(33))
self.assert_results(B().test_self_name_this, paddle.to_tensor(33))
def test_guard_run(self): # test guard
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(
B().test_super_no_args_add2, paddle.to_tensor(1)
)
self.assert_results(
B().test_super_no_args_add2, paddle.to_tensor(2)
)
self.assertEqual(ctx.translate_count, 1)
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(
B().test_super_no_args_add2, paddle.to_tensor(1)
)
self.assert_results(
B().test_super_no_args_add2, paddle.to_tensor(2)
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
B().test_super_with_args_add3, paddle.to_tensor(3)
)
self.assert_results(
B().test_super_with_args_add3, paddle.to_tensor(4)
)
self.assertEqual(ctx.translate_count, 2)
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(B().test_super_both_add5, paddle.to_tensor(5))
self.assert_results(B().test_super_both_add5, paddle.to_tensor(6))
self.assertEqual(ctx.translate_count, 1)
# ---------------------- test multiple inheritance case ----------------------
class X:
@check_no_breakgraph
def addx(self, x):
return 1 + x
class Y:
@check_no_breakgraph
def addx(self, x):
return 2 + x
class Z(X, Y):
@check_no_breakgraph
def addx(self, x):
return super().addx(x) + 3 + x
class P(Y):
@check_no_breakgraph
def addx(self, x):
return super(P, self).addx(x) + 4 + x # noqa: UP008
class Q(Z, P):
@check_no_breakgraph
def addx(self, x):
return super(Q, self).addx(x) + 5 + x # noqa: UP008
@check_no_breakgraph
def addxP(self, x):
return super(P, self).addx(x) + 5 + x
@check_no_breakgraph
def addxZ(self, x):
return super(Z, self).addx(x) + 5 + x
# Inheritance diagram
# X Y
# \ / \
# \ / \
# Z P
# \ /
# \ /
# Q
class TestMultipleInheritance(TestCaseBase):
def test_with_args(self):
x = paddle.to_tensor([1.0])
self.assert_results(Q().addx, x)
self.assert_results(Q().addxP, x)
self.assert_results(Q().addxZ, x)
def test_guard_run(self): # test guard
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(Q().addx, paddle.to_tensor(1))
self.assert_results(Q().addx, paddle.to_tensor(2))
self.assert_results(Q().addx, paddle.to_tensor(3))
self.assertEqual(ctx.translate_count, 1)
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(Q().addxP, paddle.to_tensor(4))
self.assert_results(Q().addxP, paddle.to_tensor(5))
self.assert_results(Q().addxP, paddle.to_tensor(6))
self.assertEqual(ctx.translate_count, 1)
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(Q().addxZ, paddle.to_tensor(7))
self.assert_results(Q().addxZ, paddle.to_tensor(8))
self.assert_results(Q().addxZ, paddle.to_tensor(9))
self.assertEqual(ctx.translate_count, 1)
self.assert_results(Q().addxP, paddle.to_tensor(4))
self.assert_results(Q().addxP, paddle.to_tensor(5))
self.assert_results(Q().addxP, paddle.to_tensor(6))
self.assertEqual(ctx.translate_count, 2)
# ---------------------- test `super()` as input ----------------------
class ClassSuperAsInput:
@check_no_breakgraph
def fn(self, x):
return x + 1
@check_no_breakgraph
def super_as_input(spr):
return spr.fn(2)
class TestSuperAsInput1(TestCaseBase, ClassSuperAsInput):
def test_super_as_input(self):
self.assert_results(super_as_input, super())
def test_guard_run(self): # test guard
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(super_as_input, super())
self.assert_results(super_as_input, super())
self.assert_results(super_as_input, super())
self.assertEqual(ctx.translate_count, 1)
class ClassSuperAsInputA:
@check_no_breakgraph
def test_fn(self, x):
return x + 1
class ClassSuperAsInputB(ClassSuperAsInputA):
@check_no_breakgraph
def test_fn(self, x):
return x + 4
class ClassSuperAsInputC(ClassSuperAsInputB):
@check_no_breakgraph
def super_as_input(self, spr, x):
return spr.test_fn(x)
@check_no_breakgraph
def test_super_as_input(self, x, cls):
return self.super_as_input(super(cls, self), x)
class TestSuperAsInput2(TestCaseBase):
def test_super_as_input(self):
x = paddle.to_tensor(3)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
)
def test_guard_run(self): # test guard
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
x = paddle.to_tensor(3)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
)
self.assertEqual(ctx.translate_count, 1)
x = paddle.to_tensor(4)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
)
self.assert_results(
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
)
self.assertEqual(ctx.translate_count, 2)
# ---------------------- test case which has no functions ----------------------
class ClassWithAttributionA:
a = 1
class ClassWithAttributionB(ClassWithAttributionA):
a = 111
class ClassWithAttributionC(ClassWithAttributionB):
@check_no_breakgraph
def foo(self, x):
return (
super().a + x,
super(ClassWithAttributionC, self).a + x, # noqa: UP008
super(ClassWithAttributionB, self).a + x,
)
class TestSuperAttr(TestCaseBase):
def test_attr_equal(self):
x = paddle.to_tensor([4.0])
self.assert_results(ClassWithAttributionC().foo, x)
def test_guard_run(self): # test guard
x = paddle.to_tensor([4.0])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(ClassWithAttributionC().foo, x)
self.assert_results(ClassWithAttributionC().foo, x)
self.assert_results(ClassWithAttributionC().foo, x)
self.assertEqual(ctx.translate_count, 1)
# ---------------------- test case which has fake super ----------------------
class Toy:
@check_no_breakgraph
def get(self, x):
return x + 1
class FakeSuperBase:
@check_no_breakgraph
def put(self, x):
return x + 1
class FakeSuperClass(FakeSuperBase):
@check_no_breakgraph
def fake_super_function(self, x):
return super(1, 2).get(x)
def super_function_as_input(self, fn, x):
return fn().put(x)
# We create a fake `super` and inject it to `__globals__` of the function
new_globals = FakeSuperClass.fake_super_function.__globals__.copy()
new_globals["super"] = lambda x, y: Toy()
FakeSuperClass.fake_super_function = types.FunctionType(
FakeSuperClass.fake_super_function.__code__,
new_globals,
name=FakeSuperClass.fake_super_function.__name__,
argdefs=FakeSuperClass.fake_super_function.__defaults__,
closure=FakeSuperClass.fake_super_function.__closure__,
)
class TestCustomSuper(TestCaseBase):
def test_fake_super(self):
self.assert_results(
FakeSuperClass().fake_super_function, paddle.to_tensor(3.0)
)
def test_super_function_as_input(self):
if sys.version_info >= (3, 13):
self.assert_exceptions(
RuntimeError,
r"super\(\): __class__ cell not found",
FakeSuperClass().super_function_as_input,
super,
paddle.to_tensor(3.0),
)
if sys.version_info < (3, 13):
self.assert_exceptions(
InnerError,
"KeyError: '__class__'",
FakeSuperClass().super_function_as_input,
super,
paddle.to_tensor(3.0),
)
# ------ test SuperVariable setattr + getattr ------
class LrClassBase:
def __init__(self, last_lr, last_epoch):
self.last_lr = last_lr
self.last_epoch = last_epoch
self.step()
def step(self):
self.last_epoch += 1
self.last_lr = self.get_lr()
def get_lr(self):
return self.last_lr + 0.0001
def __call__(self) -> float:
return self.last_lr
class LrClassSub(LrClassBase):
def __init__(self, **kwargs):
super().__init__(
kwargs.get("last_lr", 0.01), kwargs.get("last_epoch", 0)
)
class TestSuperSetattrGetattr(Dy2StTestBase):
def setUp(self):
def dyfunc(lr_decay):
lr = lr_decay()
return paddle.to_tensor(lr)
lr_decay = LrClassSub(
base_lr=0.1, verbose=True, last_lr=0.3, last_epoch=3
)
self.dygraph_func = lambda: dyfunc(lr_decay)
def get_dygraph_output(self):
res = self.dygraph_func()
return res
def get_static_output(self):
static_res = paddle.jit.to_static(self.dygraph_func)()
return static_res
@test_default_mode_only
def test_transformed_static_result(self):
dygraph_res = self.get_dygraph_output()
static_res = self.get_static_output()
np.testing.assert_allclose(dygraph_res, static_res, rtol=1e-05)
if __name__ == "__main__":
unittest.main()
+978
View File
@@ -0,0 +1,978 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import unittest
from test_case_base import (
TestCaseBase,
)
import paddle
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.opcode_translator.executor.opcode_executor import (
ALREADY_SUPPORTED_EXCEPTION,
)
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import strict_mode_guard
NOT_ALLOW_FALLBACK = ALREADY_SUPPORTED_EXCEPTION
class TestRaiseVarargs(TestCaseBase):
# test `RAISE_VARARGS`
@staticmethod
@check_no_breakgraph
def argc_equal_to_0_wo_exception(x):
try:
x += 1
# In CPython, `RuntimeError` will be triggered at this point.
# SOT have setup the exception stack and raise the exception manually.
# This function is designed to test scenarios involving only the `raise` statement.
raise # Bare `raise` statement is not inside an exception handler # noqa: PLE0704
x /= 2
except RuntimeError:
x -= 3
x *= 4
return x
@staticmethod
@check_no_breakgraph
def argc_equal_to_0_zero_div_err(x):
x += 1
try:
try:
x += 2
result = 10 / 0
except ZeroDivisionError:
x += 3
raise # RAISE_VARARGS(0)
except:
x += 4
return x + 5
@staticmethod
@check_no_breakgraph
def argc_equal_to_0_simulating_zero_div_err(x):
x += 1
try:
try:
x += 2
raise ZeroDivisionError("")
except ZeroDivisionError:
x += 3
raise # RAISE_VARARGS(0)
except:
x += 4
return x + 5
@staticmethod
@check_no_breakgraph
def argc_equal_to_1(x):
x += 1
try:
try:
x += 2
except:
x += 3
else:
x += 4
raise NotImplementedError # RAISE_VARARGS(1)
x += 5
except:
x += 6
return x + 7
@staticmethod
@check_no_breakgraph
def argc_equal_to_2(x):
x -= 10
try:
try:
x -= 300
finally:
x -= 400
raise ValueError from None # RAISE_VARARGS(2)
except ValueError:
x -= 500
return x - 600
@staticmethod
@check_no_breakgraph
def argc_equal_to_1_2(x):
try:
x += 1
try:
x /= 2
raise NameError # RAISE_VARARGS(1)
x *= 3
except NameError as e:
x -= 4
raise TimeoutError("TESTING") from e # RAISE_VARARGS(2)
except:
x /= 5
return x + 6
@staticmethod
@check_no_breakgraph
def argc_equal_to_1_0(x):
try:
try:
x -= 1
raise ValueError("TESTING") # RAISE_VARARGS(1)
x += 2
except NotImplementedError:
x /= 3
raise # RAISE_VARARGS(0)
except (KeyError, IndexError):
x *= 4
except ValueError:
x += 5
return x
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_RAISE_VARARGS_argc(self):
self.assert_results(
self.argc_equal_to_0_wo_exception, paddle.to_tensor(0.01)
)
self.assert_results(
self.argc_equal_to_0_zero_div_err, paddle.to_tensor(0.02)
)
self.assert_results(
self.argc_equal_to_0_simulating_zero_div_err, paddle.to_tensor(0.03)
)
self.assert_results(self.argc_equal_to_1, paddle.to_tensor(0.04))
self.assert_results(self.argc_equal_to_2, paddle.to_tensor(0.05))
self.assert_results(self.argc_equal_to_1_2, paddle.to_tensor(0.06))
self.assert_results(self.argc_equal_to_1_0, paddle.to_tensor(0.07))
class TestException(TestCaseBase):
@staticmethod
def create_builtin_exception(x):
def identity(e):
return e
x += 1
value_error = ValueError()
identity(value_error)
x += 2
type_error = TypeError("")
identity(type_error)
x += 3
key_error = KeyError("")
identity(key_error)
x += 4
exception = Exception("")
identity(exception)
x += 5
unicode_translate_error = UnicodeTranslateError("", -1, -1, "")
identity(unicode_translate_error)
x += 6
return x
@staticmethod
def create_user_defined_exception(x):
# TODO: Need to support user-defined exception
return x
@check_no_breakgraph
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_dispatch(self):
self.assert_results(
self.create_builtin_exception, paddle.to_tensor(111.0)
)
self.assert_results(
self.create_user_defined_exception, paddle.to_tensor(222.0)
)
class TestTryExcept(TestCaseBase):
# try ... except ...
# ---------------- test raising exception directly ----------------
@staticmethod
def raise_value_error_obj():
raise ValueError("Test whether raising `ValueError`")
@staticmethod
def raise_value_error_cls():
raise ValueError
@staticmethod
def raise_asserterror(x):
assert x, "Test AssertionError"
# Since the exceptions are not handled, fallback is permitted.
@strict_mode_guard(False)
def test_exception_raising(self):
with self.assertRaisesRegex(
ValueError, "Test whether raising `ValueError`"
):
symbolic_translate(self.raise_value_error_obj)()
with self.assertRaisesRegex(ValueError, ""):
symbolic_translate(self.raise_value_error_cls)()
with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
symbolic_translate(self.raise_asserterror)(False)
with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
symbolic_translate(self.raise_asserterror)(paddle.to_tensor(0))
# ---------------- without error ----------------
@staticmethod
@check_no_breakgraph
def try_except_wo_error(x):
try:
x = x + 1
except:
x = x * 2
return x
@staticmethod
@check_no_breakgraph
def try_except_exception_wo_error(x):
try:
x = x + 1
except Exception:
x = x * 2
return x
@staticmethod
@check_no_breakgraph
def try_except_exception_as_e_wo_error(x):
try:
x = x + 1
except Exception as e:
x = x * 2
return x
# ---------------- with error ----------------
@staticmethod
@check_no_breakgraph
def try_except_with_error_obj(x):
y = x + 3
try:
x = x + 1
raise ValueError(f"{__class__.__name__}")
x = x * 3
except:
y = x * 2
return y
@staticmethod
@check_no_breakgraph
def try_except_with_error_cls(x):
y = x + 3
try:
x = x + 1
raise ValueError
x = x * 3
except:
y = x * 2
return y
@staticmethod
@check_no_breakgraph
def try_except_exception_with_error(x):
# test `JUMP_IF_NOT_EXC_MATCH`
x = x + 3
try:
x = x + 1
raise ValueError("TESTING!")
x = x * 3
except Exception:
x = x * 2
return x
@staticmethod
@check_no_breakgraph
def try_except_exception_as_e_with_error(x):
# test `JUMP_IF_NOT_EXC_MATCH`
y = x + 3
try:
x = x + 1
raise ValueError("TESTING!")
x = x * 3
except ValueError as e:
y = x * 2
return y
@staticmethod
@check_no_breakgraph
def try_except_exception_as_e_with_error_tuple(x):
# test `JUMP_IF_NOT_EXC_MATCH`
y = x + 3
try:
x = x + 1
raise ValueError("TESTING!")
x = x * 3
except (ValueError, KeyError, NotImplementedError) as e:
y = x * 2
return y
@staticmethod
@check_no_breakgraph
def try_except_exception_as_e_with_unmatched_error(x):
# test `JUMP_IF_NOT_EXC_MATCH`
y = x + 3
try:
x = x + 1
raise ValueError("TESTING!")
x = x * 3
except KeyError as e:
y = x * 2
return y + 3
@staticmethod
@check_no_breakgraph
def try_except_exception_as_e_with_matched_error_reraise(x):
# test `JUMP_IF_NOT_EXC_MATCH`
y = x + 3
try:
x = x + 1
raise IndexError("TESTING!")
x = x * 3
except IndexError as e:
y = x * 2
raise LookupError("TESTING!")
return y + 3
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_try_except(self):
self.assert_results(self.try_except_wo_error, paddle.to_tensor(2))
self.assert_results(
self.try_except_exception_wo_error, paddle.to_tensor(3)
)
self.assert_results(
self.try_except_exception_as_e_wo_error, paddle.to_tensor(4)
)
self.assert_results(self.try_except_with_error_obj, paddle.to_tensor(5))
self.assert_results(self.try_except_with_error_cls, paddle.to_tensor(6))
self.assert_results(
self.try_except_exception_with_error, paddle.to_tensor(7)
)
self.assert_results(
self.try_except_exception_as_e_with_error, paddle.to_tensor(8)
)
self.assert_results(
self.try_except_exception_as_e_with_error_tuple, paddle.to_tensor(9)
)
@strict_mode_guard(False)
def test_error(self):
# RERAISE
self.assert_exceptions(
ValueError,
"TESTING!",
self.try_except_exception_as_e_with_unmatched_error,
paddle.to_tensor(0.001),
)
self.assert_exceptions(
LookupError,
"TESTING!",
self.try_except_exception_as_e_with_matched_error_reraise,
paddle.to_tensor(0.001),
)
class TestTryFinally(TestCaseBase):
# try ... finally ...
# ---------------- without error ----------------
@staticmethod
@check_no_breakgraph
def try_finally_wo_error(x):
try:
x = 1 + x
finally:
x *= 2
return x
# ---------------- with error ----------------
@staticmethod
@check_no_breakgraph
def try_finally_with_error_but_return_in_finally(x):
# RERAISE
try:
x = 3 + x
raise NotImplementedError("TESTING!")
x = 300 + x
finally:
x *= 2
# `return` inside `finally` blocks cause exceptions to be silenced
return x # noqa: B012
@staticmethod
def try_finally_with_error(x):
# RERAISE
try:
x = 3 + x
raise NotImplementedError("TESTING!")
x = 300 + x
finally:
x *= 2
return x
@staticmethod
def try_finally_with_error_in_finally(x):
# RERAISE
try:
x = 3 + x
return x
finally:
x *= 2
raise TimeoutError("TESTING!")
x = 300 + x
return x
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_try_finally(self):
self.assert_results(self.try_finally_wo_error, paddle.to_tensor(14))
self.assert_results(
self.try_finally_with_error_but_return_in_finally,
paddle.to_tensor(15),
)
@strict_mode_guard(False)
def test_error(self):
# RERAISE
self.assert_exceptions(
NotImplementedError,
"TESTING!",
self.try_finally_with_error,
paddle.to_tensor(16),
)
self.assert_exceptions(
TimeoutError,
"TESTING!",
self.try_finally_with_error_in_finally,
paddle.to_tensor(17),
)
class TestTryExceptElse(TestCaseBase):
# try ... except ... else
# `else` is useful for code that must be executed if the try clause does not raise an exception.
# ---------------- without error ----------------
@staticmethod
def try_except_else(x):
try:
x += 1
except:
x += 2
else:
x += 3
return x
# ---------------- with error ----------------
@staticmethod
def try_except_else_except_with_matched_error(x):
try:
x += 4
raise ValueError
except ValueError:
x += 5
else:
x += 6
return x
@staticmethod
@strict_mode_guard(False)
def try_except_else_except_with_mismatched_error(x):
try:
x += 4
raise TimeoutError
except KeyError:
x += 5
else:
x += 6
return x
@staticmethod
def try_except_else_error_in_except(x):
try:
x += 4
except KeyError:
x += 5
raise ValueError
else:
x += 6
return x
@staticmethod
@strict_mode_guard(False)
def try_except_else_error_in_else(x):
try:
x += 4
except KeyError:
x += 5
else:
x += 6
raise ValueError("Testing!")
return x
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_try_except_else(self):
# self.assert_results(self.try_except_else, paddle.to_tensor(14))
self.assert_results(
self.try_except_else_except_with_matched_error, paddle.to_tensor(15)
)
# self.assert_results(
# self.try_except_else_error_in_except, paddle.to_tensor(16)
# )
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_error(self):
# RERAISE
self.assert_exceptions(
TimeoutError,
"",
self.try_except_else_except_with_mismatched_error,
paddle.to_tensor(0.001),
)
self.assert_exceptions(
ValueError,
"Testing!",
self.try_except_else_error_in_else,
paddle.to_tensor(0.002),
)
class TestTryExceptFinally(TestCaseBase):
# try ... except ... finally
# ---------------- without error ----------------
@staticmethod
def try_except_finally(x):
try:
x -= 1
except:
x -= 2
finally:
x -= 3
return x
# ---------------- without error ----------------
@staticmethod
def try_except_finally_with_matched_exception(x):
try:
x -= 1
raise ValueError
except:
x -= 2
finally:
x -= 3
return x
@staticmethod
@strict_mode_guard(False)
def try_except_finally_with_mismatched_exception(x):
try:
x -= 1
raise ValueError("TESTING")
except AttributeError:
x -= 2
finally:
x -= 3
return x
@staticmethod
def try_except_finally_in_except(x):
try:
x -= 1
except AttributeError:
x -= 2
raise ValueError
finally:
x -= 3
return x
@staticmethod
@strict_mode_guard(False)
def try_except_finally_in_finally(x):
try:
x -= 1
except AttributeError:
x -= 2
finally:
x -= 3
raise ValueError
return x
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_try_except_finally(self):
self.assert_results(self.try_except_finally, paddle.to_tensor([0.11]))
self.assert_results(
self.try_except_finally_with_matched_exception,
paddle.to_tensor([0.22]),
)
self.assert_results(
self.try_except_finally_in_except,
paddle.to_tensor([0.33]),
)
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_error(self):
# RERAISE
self.assert_exceptions(
ValueError,
"TESTING",
self.try_except_finally_with_mismatched_exception,
paddle.to_tensor(0.001),
)
self.assert_exceptions(
ValueError,
"",
self.try_except_finally_in_finally,
paddle.to_tensor(0.001),
)
class TestTryExceptElseFinally(TestCaseBase):
# try ... except ... else ... finally
# ---------------- without error ----------------
@staticmethod
def try_except_else_finally(x):
try:
x -= 1
except:
x -= 2
else:
x -= 3
finally:
x -= 4
return x
# ---------------- with error ----------------
@staticmethod
def try_except_else_finally_with_matched_exception(x):
try:
x -= 1
raise ValueError
except ValueError:
x -= 2
else:
x -= 3
finally:
x -= 4
return x
@staticmethod
@strict_mode_guard(False)
def try_except_else_finally_with_mismatched_exception(x):
try:
x -= 1
raise SystemError("TESTING")
except NotImplementedError:
x -= 2
else:
x -= 3
finally:
x -= 4
return x
@staticmethod
@strict_mode_guard(False)
def try_except_else_finally_with_exception_in_else(x):
try:
x -= 1
except NotImplementedError:
x -= 2
else:
x -= 3
raise ModuleNotFoundError("TESTING")
finally:
x -= 4
return x
@staticmethod
@strict_mode_guard(False)
def try_except_else_finally_with_exception_in_finally(x):
try:
x -= 1
except NotImplementedError:
x -= 2
else:
x -= 3
finally:
x -= 4
raise SyntaxError("TESTING")
return x
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_try_except_finally(self):
self.assert_results(
self.try_except_else_finally, paddle.to_tensor([0.11])
)
self.assert_results(
self.try_except_else_finally_with_matched_exception,
paddle.to_tensor([0.22]),
)
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_error(self):
# RERAISE
self.assert_exceptions(
SystemError,
"TESTING",
self.try_except_else_finally_with_mismatched_exception,
paddle.to_tensor(0.001),
)
self.assert_exceptions(
ModuleNotFoundError,
"TESTING",
self.try_except_else_finally_with_exception_in_else,
paddle.to_tensor(0.001),
)
self.assert_exceptions(
SyntaxError,
"TESTING",
self.try_except_else_finally_with_exception_in_finally,
paddle.to_tensor(0.001),
)
class TestNestingCase(TestCaseBase):
@strict_mode_guard(NOT_ALLOW_FALLBACK)
@check_no_breakgraph
def test_try_nesting(self):
def try_nesting_wo_error(x):
try:
try:
try:
try:
try:
try:
x -= 1
raise ValueError(
"TESTING"
) # RAISE_VARARGS(1)
x += 2
except NotImplementedError:
x /= 3
raise # RAISE_VARARGS(0)
except (KeyError, IndexError):
x *= 4
except ValueError:
x += 5
raise NameError # RAISE_VARARGS(1)
except SyntaxError:
x /= 6
except (TypeError, FileNotFoundError, NameError) as e:
x -= 7
raise TimeoutError(
"TESTING"
) from e # RAISE_VARARGS(2)
except:
x /= 8
raise AssertionError
except IndentationError as e:
x *= 9
except AssertionError as e:
x += 10
raise # RAISE_VARARGS(0)
except Exception as e:
x /= 11
return x + 12
self.assert_results(try_nesting_wo_error, paddle.to_tensor(0.5))
@strict_mode_guard(NOT_ALLOW_FALLBACK)
@check_no_breakgraph
def test_function_nesting(self):
def raise_value_error_obj(x):
x += 1
raise ValueError("")
def raise_value_error_cls(x):
x += 2
raise ValueError
def raise_zero_div_error(x):
x += 3
return 19.0 / 0
def raise_assert_error(x):
x += 4
assert []
def raise_not_implemented_error(x):
x += 5
raise NotImplementedError
def one_nesting(x, func):
x *= 6
func(x)
def two_nesting(x, func):
x /= 7
one_nesting(x, func)
def three_nesting(x, func):
x -= 8
two_nesting(x, func)
def get_test_func(x, func=None):
try:
x += 1
try:
x /= 2
three_nesting(x, func)
x -= 3
except ValueError:
x *= 4
except:
x += 5
return x # / 6
self.assert_results(
get_test_func, paddle.to_tensor(0.3), raise_value_error_obj
)
self.assert_results(
get_test_func, paddle.to_tensor(0.4), raise_value_error_cls
)
self.assert_results(
get_test_func, paddle.to_tensor(0.5), raise_zero_div_error
)
self.assert_results(
get_test_func, paddle.to_tensor(0.6), raise_assert_error
)
self.assert_results(
get_test_func, paddle.to_tensor(0.7), raise_not_implemented_error
)
class TestAssertException(TestCaseBase):
@staticmethod
def try_assert(x, condition):
# test py value or paddle tensor value as condition
try:
x += 1
try:
x /= 2
raise TimeoutError("TESTING")
except:
x -= 3
assert condition
except:
x *= 4
return x / 5
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_assert_with_py_var_as_condition(self):
# Test the case where `condition` is Python variable
self.assert_results(self.try_assert, paddle.to_tensor(1), False)
self.assert_results(self.try_assert, paddle.to_tensor(2), True)
self.assert_results(self.try_assert, paddle.to_tensor(3), [])
self.assert_results(self.try_assert, paddle.to_tensor(4), [1])
self.assert_results(self.try_assert, paddle.to_tensor(5), "")
self.assert_results(self.try_assert, paddle.to_tensor(6), "QAQ")
# TODO(DrRyanHuang): The following two cases are not supported yet.
# self.assert_results(self.try_assert, paddle.to_tensor(7), ValueError)
# self.assert_results(self.try_assert, paddle.to_tensor(8), ValueError())
# Currently, since the assert statement is essentially an if statement and can cause breakgraph,
# using a Tensor as a condition is not supported. Therefore, fallback is allowed.
@strict_mode_guard(False)
def test_assert_with_tensor_as_condition(self):
# Test the case where `condition` is Paddle Tensor
self.assert_results(
self.try_assert, paddle.to_tensor(8), paddle.to_tensor(1)
)
self.assert_results(
self.try_assert, paddle.to_tensor(9), paddle.to_tensor(0)
)
self.assert_results(
self.try_assert, paddle.to_tensor(10), paddle.to_tensor(-1)
)
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_assert_true(self):
@check_no_breakgraph
def try_assert_except(x, y):
x += 1
try:
x += 2
assert y > -10000
x += 3
except:
x += 4
self.assert_results(try_assert_except, paddle.to_tensor(10), 10)
@strict_mode_guard(NOT_ALLOW_FALLBACK)
def test_assert_false(self):
@check_no_breakgraph
def try_assert_except(x, y):
try:
x += 5
assert y < -10000
except AssertionError:
x += 6
return x
self.assert_results(try_assert_except, paddle.to_tensor(10), 10)
class TestGuard(TestCaseBase):
@strict_mode_guard(False)
@check_no_breakgraph
def test_guard_run(self):
def fn():
try:
paddle.jit.sot.psdb.breakgraph()
raise ValueError
except ValueError:
return True
return False
self.assert_results(fn)
class TestBuiltinFunctionRaiseExceptionGuard(TestCaseBase):
@strict_mode_guard(False)
def test_guard_run(self):
def foo_floordiv(x):
1 / x
def foo_mod(x):
2 % x
self.assert_results(foo_floordiv, 1)
self.assert_exceptions(
ZeroDivisionError,
"division by zero",
foo_floordiv,
0,
)
self.assert_results(foo_mod, 10)
if sys.version_info >= (3, 14):
zero_mod_msg = "division by zero"
else:
zero_mod_msg = "integer (.)*modulo by zero"
self.assert_exceptions(
ZeroDivisionError,
zero_mod_msg,
foo_mod,
0,
)
if __name__ == "__main__":
unittest.main()
+138
View File
@@ -0,0 +1,138 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils.exceptions import FallbackError
@check_no_breakgraph
def import_math_model():
import math
return math.sqrt(4)
def import_relative():
from . import test_case_base
return test_case_base
@check_no_breakgraph
def import_paddle_model(x: int):
import paddle
return paddle.zeros([2, 3]) + x
@check_no_breakgraph
def import_os_model():
import os
return os.name
@check_no_breakgraph
def import_sys_version():
from sys import version
return version[:5] # Return first 5 chars to check import
@check_no_breakgraph
def import_paddle_nn():
import paddle.nn
return paddle.nn.Layer.__name__
@check_no_breakgraph
def import_paddle_nn_from():
from paddle import nn
return nn.Layer.__name__
@check_no_breakgraph
def import_paddle_nn_functional():
import paddle.nn.functional as F
return F.relu.__name__
@check_no_breakgraph
def import_paddle_nn_linear():
from paddle.nn import Linear
return Linear.__name__
@check_no_breakgraph
def import_collections():
import collections
return collections.defaultdict.__name__
@check_no_breakgraph
def import_collections_defaultdict():
from collections import defaultdict
return defaultdict.__name__
@check_no_breakgraph
def import_multiple_modules():
import os
import sys
return os.name + sys.version[:3]
@check_no_breakgraph
def import_paddle_nn_linear_as():
from paddle.nn import Linear as Lin
return Lin.__name__
class TestImportModel(TestCaseBase):
def test_import_model(self):
self.assert_results(import_math_model)
self.assert_results(import_paddle_model, 1)
self.assert_results(import_os_model)
self.assert_results(import_sys_version)
self.assert_results(import_paddle_nn)
self.assert_results(import_paddle_nn_from)
self.assert_results(import_paddle_nn_functional)
self.assert_results(import_paddle_nn_linear)
self.assert_results(import_collections)
self.assert_results(import_collections_defaultdict)
self.assert_results(import_multiple_modules)
self.assert_results(import_paddle_nn_linear_as)
def test_relative_import_error(self):
self.assert_exceptions(
FallbackError,
"relative import with no known parent package",
import_relative,
)
if __name__ == "__main__":
unittest.main()
+248
View File
@@ -0,0 +1,248 @@
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
from paddle.jit.sot import psdb, symbolic_translate # noqa: F401
from paddle.jit.sot.psdb import check_no_breakgraph # noqa: F401
from paddle.jit.sot.utils.envs import strict_mode_guard
from paddle.jit.sot.utils.exceptions import InnerError
try:
from string.templatelib import Interpolation, Template
except Exception: # pragma: no cover - env without t-string support
Interpolation = None
Template = None
def _tstring_supported():
if Template is None or Interpolation is None:
return False
try:
compile("x = t'hello'", "<tstring>", "exec")
except SyntaxError:
return False
return True
def _tstring_skip(*_args, **_kwargs):
pass
if _tstring_supported():
_tstring_ns = {}
exec(
"""
@check_no_breakgraph
def test_t_literal():
name = "world"
return t"hello, {name}!"
@check_no_breakgraph
def test_t_with_expression():
left = 2
right = 5
return t"{left} + {right} = {left + right}"
@check_no_breakgraph
def test_t_with_conversion_and_format():
value = 3.14159
return t"value={value!r:.2f}"
@check_no_breakgraph
def test_t_in_containers():
prefix = "id"
first = t"{prefix}-{1}"
second = t"{prefix}-{2!a}"
return [first, {"second": second}]
@check_no_breakgraph
def test_t_with_no_interpolation():
return t"plain literal"
@check_no_breakgraph
def test_t_multiple_interpolations():
a = 1
b = 2
c = 3
return t"{a},{b},{c}"
@check_no_breakgraph
def test_t_with_format_spec_expression():
value = 12.3456
precision = 3
return t"value={value:.{precision}f}"
@check_no_breakgraph
def test_t_with_ascii_conversion():
text = "中文"
return t"ascii={text!a}"
@check_no_breakgraph
def test_t_with_str_conversion():
value = "hello"
return t"str={value!s}"
def test_t_with_fallback_not_recursive():
psdb.fallback(recursive=False)
value = "hello"
return t"fallback={value!s}"
def test_t_with_fallback_recursive():
psdb.fallback(recursive=True)
value = "hello"
return t"fallback={value!s}"
@psdb.check_no_fallback
def test_t_with_forbidden_fallback():
psdb.fallback(recursive=False)
value = "hello"
return t"fallback={value!s}"
""",
globals(),
_tstring_ns,
)
test_t_literal = _tstring_ns["test_t_literal"]
test_t_with_expression = _tstring_ns["test_t_with_expression"]
test_t_with_conversion_and_format = _tstring_ns[
"test_t_with_conversion_and_format"
]
test_t_in_containers = _tstring_ns["test_t_in_containers"]
test_t_with_no_interpolation = _tstring_ns["test_t_with_no_interpolation"]
test_t_multiple_interpolations = _tstring_ns[
"test_t_multiple_interpolations"
]
test_t_with_format_spec_expression = _tstring_ns[
"test_t_with_format_spec_expression"
]
test_t_with_ascii_conversion = _tstring_ns["test_t_with_ascii_conversion"]
test_t_with_str_conversion = _tstring_ns["test_t_with_str_conversion"]
test_t_with_fallback_not_recursive = _tstring_ns[
"test_t_with_fallback_not_recursive"
]
test_t_with_fallback_recursive = _tstring_ns[
"test_t_with_fallback_recursive"
]
test_t_with_forbidden_fallback = _tstring_ns[
"test_t_with_forbidden_fallback"
]
else:
test_t_literal = _tstring_skip
test_t_with_expression = _tstring_skip
test_t_with_conversion_and_format = _tstring_skip
test_t_in_containers = _tstring_skip
test_t_with_no_interpolation = _tstring_skip
test_t_multiple_interpolations = _tstring_skip
test_t_with_format_spec_expression = _tstring_skip
test_t_with_ascii_conversion = _tstring_skip
test_t_with_str_conversion = _tstring_skip
test_t_with_fallback_not_recursive = _tstring_skip
test_t_with_fallback_recursive = _tstring_skip
test_t_with_forbidden_fallback = _tstring_skip
class TestTString(TestCaseBase):
def _assert_tstring_like(self, actual, expected):
if Template is None or Interpolation is None:
self.skipTest(
"Template strings are not supported by this interpreter."
)
self.assertIs(type(actual), type(expected))
if isinstance(actual, Template):
self._assert_tstring_like(actual.strings, expected.strings)
self._assert_tstring_like(
actual.interpolations, expected.interpolations
)
return
if isinstance(actual, Interpolation):
self._assert_tstring_like(actual.value, expected.value)
self._assert_tstring_like(actual.expression, expected.expression)
self.assertEqual(actual.conversion, expected.conversion)
self.assertEqual(actual.format_spec, expected.format_spec)
return
if isinstance(actual, (list, tuple)):
self.assertEqual(len(actual), len(expected))
for a_item, e_item in zip(actual, expected):
self._assert_tstring_like(a_item, e_item)
return
if isinstance(actual, dict):
self.assertEqual(set(actual.keys()), set(expected.keys()))
for key in actual:
self._assert_tstring_like(actual[key], expected[key])
return
if isinstance(actual, set):
self.assertEqual(actual, expected)
return
# Fallback to the generic nested matcher for tensors / arrays / scalars.
self.assert_nest_match(actual, expected)
def assert_tstring_results(self, func, *args, **kwargs):
sym_output = symbolic_translate(func)(*args, **kwargs)
paddle_output = func(*args, **kwargs)
self._assert_tstring_like(sym_output, paddle_output)
def test_symbolic_translate_handles_t_string(self):
self.assert_tstring_results(test_t_literal)
def test_symbolic_translate_handles_formats_and_containers(self):
self.assert_tstring_results(test_t_with_expression)
self.assert_tstring_results(test_t_with_conversion_and_format)
self.assert_tstring_results(test_t_in_containers)
def test_symbolic_translate_handles_more_cases(self):
self.assert_tstring_results(test_t_with_no_interpolation)
self.assert_tstring_results(test_t_multiple_interpolations)
self.assert_tstring_results(test_t_with_format_spec_expression)
self.assert_tstring_results(test_t_with_ascii_conversion)
self.assert_tstring_results(test_t_with_str_conversion)
@strict_mode_guard(False)
def test_tstring_fallback_not_recursive(self):
self.assert_tstring_results(test_t_with_fallback_not_recursive)
@strict_mode_guard(False)
def test_tstring_fallback_recursive(self):
self.assert_tstring_results(test_t_with_fallback_recursive)
def test_tstring_check_no_fallback(self):
if not _tstring_supported():
self.skipTest(
"Template strings are not supported by this interpreter."
)
with self.assertRaises(InnerError):
symbolic_translate(test_t_with_forbidden_fallback)()
if __name__ == "__main__":
unittest.main()
+259
View File
@@ -0,0 +1,259 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import inspect
import sys
import unittest
import paddle
from paddle.jit.sot.opcode_translator.instruction_utils import (
analysis_used_names,
calc_offset_from_bytecode_offset,
get_instructions,
)
from paddle.jit.sot.opcode_translator.instruction_utils.opcode_info import (
PYOPCODE_CACHE_SIZE,
)
def assert_inputs_equals(instruction_offset: int, expected_inputs: set[str]):
current_frame = inspect.currentframe()
assert current_frame is not None
test_frame = current_frame.f_back
assert test_frame is not None
instructions = get_instructions(test_frame.f_code)
current_offset = test_frame.f_lasti
if sys.version_info >= (3, 13):
current_offset += PYOPCODE_CACHE_SIZE.get("CALL") * 2
current_instr_idx = calc_offset_from_bytecode_offset(
current_offset + 2, instructions
)
reads, writes = analysis_used_names(
instructions, current_instr_idx + instruction_offset
)
assert set(reads) == expected_inputs, (
f"actual_inputs: {reads}, expected_inputs: {expected_inputs}"
)
def case1(x):
m = x + 1
n = x + 2
assert_inputs_equals(0, {"x", "n"})
y = x + 2
assert_inputs_equals(0, {"n"})
return n
def case2(x):
x = x + 1
assert_inputs_equals(0, {"x"})
y = x + 3
z = x + y
assert_inputs_equals(0, {"x"})
x += 1
m = x + 1
n = x + m
assert_inputs_equals(0, set())
return 1
def case3(x):
y = x + 1
assert_inputs_equals(0, {"x"})
if x:
z = 1
else:
z = 2
return z
def case4(x):
y = x + 1
assert_inputs_equals(0, {"x", "y"})
if x:
z = y
else:
z = x
return z
def case5(x):
y = x + 1
z = x + 2
assert_inputs_equals(0, {"z"})
if z:
a = 1
else:
b = 2
return z
def case6(x):
y = x + 1
z = x + 2
assert_inputs_equals(0, {"a", "z"})
if z:
a = 1
else:
a += 1
return z
def case7(x):
y = x + 1
z = x + 2
assert_inputs_equals(0, {"a", "z"})
if not z:
a += 1 # noqa: F821
else:
a = 1
return z
def breakgraph_api(x):
return x
def normal_api(x):
return x
def case8(x):
x = normal_api(x)
assert_inputs_equals(0, {"x"})
for i in range(10):
x += 1
if i > 5:
continue
x += 10086
x += i
return x
# NOTE(SigureMo): The offset should be between index of CALL instruction of assert_inputs_equals
# and the index of the CALL instruction of breakgraph_api
case9_offset = -7
case9_offset = -9 if sys.version_info >= (3, 11) else case9_offset
case9_offset = -6 if sys.version_info >= (3, 12) else case9_offset
def case9(x):
x = breakgraph_api(x)
assert_inputs_equals(
case9_offset, set()
) # analysis when call breakgraph api (CALL_FUNCTION)
for i in range(10):
x += 1
if i > 5:
continue
x += 10086
x += i
return x
def case10(x):
assert_inputs_equals(0, {"x", "y"})
# if x == 0, y will be read before assignment
for i in range(x):
y = i
z = y
return y + 1
def case11(x):
y = x + 1
z = x + 2
assert_inputs_equals(0, {"a", "y", "z"})
if z:
if not y:
a += 1 # noqa: F821
else:
a = 2
else:
if y:
a = 1
else:
a += 1
return z
def case12(x):
y = x + 1
z = x + 2
assert_inputs_equals(0, {"a", "y", "z"})
if z:
if y:
a = 2
else:
a += 2
else:
if y:
a += 1
else:
a = 1
return z
class TestAnalysisInputs(unittest.TestCase):
def test_case1(self):
case1(paddle.to_tensor([1]))
def test_case2(self):
case2(paddle.to_tensor([2]))
def test_case3(self):
case3(paddle.to_tensor([3]))
def test_case4(self):
case4(paddle.to_tensor([4]))
def test_case5(self):
case5(paddle.to_tensor([5]))
def test_case6(self):
case6(paddle.to_tensor([6]))
def test_case7(self):
case7(paddle.to_tensor([7]))
def test_case8(self):
case8(paddle.to_tensor([8]))
def test_case9(self):
case9(paddle.to_tensor([9]))
def test_case10(self):
case10(paddle.to_tensor([10]))
def test_case11(self):
case11(paddle.to_tensor([11]))
def test_case12(self):
case12(paddle.to_tensor([12]))
if __name__ == "__main__":
unittest.main()
+214
View File
@@ -0,0 +1,214 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils.paddle_api_config import add_break_graph_function
def ifelse_func(x, y):
if x > 0:
y = y + 1
else:
y = y + 2
return y
class TestIfElse(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor([1.0])
y = paddle.to_tensor([2.0])
self.assert_results(ifelse_func, x, y)
def multi_output(x: paddle.Tensor):
m = x + 1
if x > 0:
return m
else:
return 2 * m
class TestBreakgraph(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor(2)
self.assert_results(multi_output, x)
x = paddle.to_tensor(-2)
self.assert_results(multi_output, x)
def print_break_graph(x, y):
z = x + y
print(x, z)
out = y * z * 2
return out
class TestPrint(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor(2)
y = paddle.to_tensor(3)
self.assert_results(print_break_graph, x, y)
def to_tensor_break_graph(x, y):
z = x + y
out = y * paddle.to_tensor(2) * z
return out
class TestToTensor(TestCaseBase):
def test_simple(self):
add_break_graph_function(paddle.to_tensor)
x = paddle.to_tensor(2)
y = paddle.to_tensor(3)
self.assert_results(to_tensor_break_graph, x, y)
def tensor_clear_gradient(x):
x = paddle.to_tensor(x)
x.clear_gradient()
return x
class TestBreakGraphInResumeFn(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor(2)
self.assert_results(tensor_clear_gradient, x)
def inner_fn(a, b, c, d):
return a + b * c - d
def multi_stack_args(a, b, c):
out = inner_fn(a, b, c, paddle.to_tensor(4))
return out
class TestMultiStackArgs(TestCaseBase):
def test_simple(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
c = paddle.to_tensor(3)
self.assert_results(multi_stack_args, a, b, c)
def break_graph_in_call_method(x):
out = paddle.nn.functional.relu(paddle.to_tensor([4.0]))
return x + out
def numpy_break_graph():
a = paddle.to_tensor([1, 2])
b = np.sum(a.numpy())
print(b)
return b
class TestBreakGraphInCallMethod(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor([1.0])
break_graph_in_call_method(x)
x = paddle.to_tensor([2.0])
break_graph_in_call_method(x)
x = paddle.to_tensor([3.0])
self.assert_results(break_graph_in_call_method, x)
def test_numpy(self):
self.assert_results(numpy_break_graph)
def test_break_graph_repeat(x):
out = paddle.to_tensor(
paddle.to_tensor(paddle.to_tensor(paddle.to_tensor([1.0])))
)
return x + out
class TestBreakGraphRepeat(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor([1.0])
test_break_graph_repeat(x)
x = paddle.to_tensor([2.0])
test_break_graph_repeat(x)
x = paddle.to_tensor([3.0])
self.assert_results(test_break_graph_repeat, x)
def break_graph_resume_pass_null(x, y):
return paddle.add(x, y[0:50] if y is not None else None)
class TestBreakGraphResumePassNull(TestCaseBase):
def test_break_graph_resume_pass_null(self):
x = paddle.rand([50, 50], dtype=paddle.float32)
y = paddle.rand([100, 50], dtype=paddle.float32)
self.assert_results(break_graph_resume_pass_null, x, y)
class MyLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.head = paddle.nn.Linear(3, 10)
def forward_features(self, x):
paddle.jit.sot.psdb.breakgraph()
return x
def forward(self, x):
x = self.forward_features(x)
return self.head(x)
class TestBreakGraphInLayer(TestCaseBase):
def test_break_graph_in_layer(self):
x = paddle.rand([2, 3], dtype=paddle.float32)
net = MyLayer()
self.assert_results(net.forward, x)
def dummy(*args):
return None
def break_graph_call_generator_function(x):
return dummy(y for y in x)
class TestBreakGraphCallGeneratorFunction(TestCaseBase):
def test_break_graph_when_call_generator_function(self):
x = paddle.rand([1], dtype=paddle.float32)
y = paddle.rand([1], dtype=paddle.float32)
self.assert_results(break_graph_call_generator_function, [x, y])
def unary_not_break_graph(x):
return not x
class TestUnaryNot(TestCaseBase):
def test_unary_not_break_graph(self):
x = paddle.to_tensor(0)
self.assert_results(unary_not_break_graph, x)
if __name__ == "__main__":
unittest.main()
+129
View File
@@ -0,0 +1,129 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import operator
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import strict_mode_guard
class TestObject:
pass
class TestObjectWithBool:
def __bool__(self):
return False
class TestObjectWithLen:
def __init__(self, list):
self.list = list
def __len__(self):
return len(self.list)
class TestObjectWithBoolAndLen:
def __init__(self, list):
self.list = list
def __bool__(self):
return False
def __len__(self):
return len(self.list)
def call_bool_in_cond(obj):
if obj:
return True
else:
return False
def call_bool_by_bool(obj):
return bool(obj)
def call_bool_by_operator_truth(obj):
return operator.truth(obj)
class TestBuiltinBool(TestCaseBase):
def test_object_disallow_breakgraph(self):
call_bool_in_cond_no_breakgraph = check_no_breakgraph(call_bool_in_cond)
call_bool_by_bool_no_breakgraph = check_no_breakgraph(call_bool_by_bool)
call_bool_by_operator_truth_no_breakgraph = check_no_breakgraph(
call_bool_by_operator_truth
)
with test_instruction_translator_cache_context():
obj = TestObject()
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
with test_instruction_translator_cache_context():
obj = TestObjectWithBool()
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
with test_instruction_translator_cache_context():
obj = TestObjectWithBoolAndLen([1, 2, 3])
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
with test_instruction_translator_cache_context():
obj = TestObjectWithBoolAndLen([])
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
with test_instruction_translator_cache_context():
layer = paddle.nn.Linear(10, 1)
self.assert_results(call_bool_in_cond_no_breakgraph, layer)
self.assert_results(call_bool_by_bool_no_breakgraph, layer)
self.assert_results(
call_bool_by_operator_truth_no_breakgraph, layer
)
def test_object_allow_breakgraph(self):
with test_instruction_translator_cache_context():
obj = TestObjectWithLen([1, 2, 3])
with strict_mode_guard(False):
self.assert_results(call_bool_in_cond, obj)
self.assert_results(call_bool_by_bool, obj)
self.assert_results(call_bool_by_operator_truth, obj)
with test_instruction_translator_cache_context():
obj = TestObjectWithLen([])
with strict_mode_guard(False):
self.assert_results(call_bool_in_cond, obj)
self.assert_results(call_bool_by_bool, obj)
self.assert_results(call_bool_by_operator_truth, obj)
if __name__ == "__main__":
unittest.main()
+518
View File
@@ -0,0 +1,518 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import math
import operator
import unittest
import weakref
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
def dispatch_len(x: paddle.Tensor):
return len(x.shape)
def dispatch_tensor_len(x: paddle.Tensor):
return len(x)
def dispatch_reversed(x: paddle.Tensor | int, y: paddle.Tensor | int):
return list(reversed([x + 1, y - 1, x * 10, y + 1000]))
def dispatch_bool(x: paddle.Tensor):
return operator.truth(x.shape) and bool(x.shape)
def dispatch_ceil(x: paddle.Tensor | float):
return math.ceil(x) + 1
def dispatch_floor(x: paddle.Tensor | float):
return math.floor(x) + 1
def test_sum_tuple(x: paddle.Tensor | int, y: paddle.Tensor | int):
return sum((x, y))
def test_sum_tuple2(
x: paddle.Tensor | int | list[int] | list[paddle.Tensor],
y: paddle.Tensor | int | list[int] | list[paddle.Tensor],
):
return sum((x, y), x)
def test_sum_tuple3(x):
return sum((), x)
def test_sum_list(x: paddle.Tensor | int, y: paddle.Tensor | int):
return sum([x, y])
def test_sum_list2(
x: paddle.Tensor | int | list[int] | list[paddle.Tensor],
y: paddle.Tensor | int | list[int] | list[paddle.Tensor],
):
return sum([x, y], x)
def test_sum_list3(x):
return sum([], x)
def test_tensor_sum(x: paddle.Tensor):
return sum(x)
def test_tensor_sum_api(x: paddle.Tensor):
return x.sum()
def test_pow(x: paddle.Tensor | int, y: paddle.Tensor | int):
return pow(x, y)
def test_pow2(x: paddle.Tensor | int, y: paddle.Tensor | int):
return pow(x, y, 1)
def test_tensor_pow_api(x: paddle.Tensor, y: paddle.Tensor | int):
return x.pow(y)
def test_math_pow(x: int, y: int):
return math.pow(x, y)
def test_chr(x: int | hex | paddle.Tensor):
return chr(x)
def test_ord(x: str):
return ord(x)
@check_no_breakgraph
def test_min():
return min(9, 8, 2, 4, 1, 7, 3, 5, 6)
@check_no_breakgraph
def test_max():
return max(9, 8, 2, 4, 1, 7, 3, 5, 6)
@check_no_breakgraph
def test_sqrt(x: int):
return math.sqrt(x)
@check_no_breakgraph
def test_log(x: int):
return math.log(x)
@check_no_breakgraph
def test_any(var):
return any(var)
@check_no_breakgraph
def test_any_iter(var):
return any(iter(var))
@check_no_breakgraph
def test_all(var):
return all(var)
@check_no_breakgraph
def test_all_iter(var):
return all(iter(var))
@check_no_breakgraph
def test_builtin_type_check_eq():
a = 1
b = []
c = ()
d = {}
eq_results = (
a == b, a == c, a == d,
b == a, b == c, b == d,
c == a, c == b, c == d,
) # fmt: skip
ne_results = (
a != b, a != c, a != d,
b != a, b != c, b != d,
c != a, c != b, c != d,
) # fmt: skip
return eq_results, ne_results
@check_no_breakgraph
def test_is(x, y):
return x is y
class TestBuiltinDispatch(TestCaseBase):
def test_dispatch_len(self):
self.assert_results(dispatch_len, paddle.to_tensor([1, 2, 3]))
def test_dispatch_bool(self):
self.assert_results(dispatch_bool, paddle.to_tensor([1, 2, 3]))
def test_dispatch_tensor_len(self):
with test_instruction_translator_cache_context() as ctx:
self.assert_results(
dispatch_tensor_len, paddle.to_tensor([1, 2, 3])
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
dispatch_tensor_len, paddle.to_tensor([4, 5, 6])
)
self.assertEqual(ctx.translate_count, 1)
def test_dispatch_list_reversed(self):
self.assert_results(dispatch_reversed, paddle.to_tensor(1), 2)
self.assert_results(dispatch_reversed, 2, paddle.to_tensor(1))
def test_dispatch_tensor_reversed(self):
self.assert_results(
dispatch_reversed,
paddle.to_tensor([1, 2]),
paddle.to_tensor([3, 4]),
)
def test_not_dispatch_tensor_ceil(self):
# ceil should break graph, since it returns a int rather than a tensor
self.assert_results(dispatch_ceil, paddle.to_tensor(1.2))
def test_dispatch_float_ceil(self):
self.assert_results(dispatch_ceil, 1.2)
def test_not_dispatch_tensor_floor(self):
# floor should break graph, since it returns a int rather than a tensor
self.assert_results(dispatch_floor, paddle.to_tensor(1.2))
def test_dispatch_float_floor(self):
self.assert_results(dispatch_floor, 1.2)
def test_dispatch_sum(self):
self.assert_results(test_sum_tuple, 1, 1)
self.assert_results(test_sum_tuple, paddle.to_tensor(1), 1)
self.assert_results(
test_sum_tuple, paddle.to_tensor(1), paddle.to_tensor(1)
)
self.assert_results(
test_sum_tuple, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
)
self.assert_results(
test_sum_tuple, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
)
self.assert_results(test_sum_tuple2, 1, 1)
self.assert_results(test_sum_tuple2, [1, 2], [3, 4])
self.assert_results(test_sum_tuple2, paddle.to_tensor(1), 1)
self.assert_results(
test_sum_tuple2, paddle.to_tensor(1), paddle.to_tensor(1)
)
self.assert_results(
test_sum_tuple2,
[paddle.to_tensor(1), paddle.to_tensor(2)],
[paddle.to_tensor(3), paddle.to_tensor(4)],
)
self.assert_results(
test_sum_tuple2, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
)
self.assert_results(
test_sum_tuple2, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
)
self.assert_results(test_sum_tuple3, 1)
self.assert_results(test_sum_tuple3, paddle.to_tensor(1))
self.assert_results(test_sum_list, 1, 1)
self.assert_results(test_sum_list, paddle.to_tensor(1), 1)
self.assert_results(
test_sum_list, paddle.to_tensor(1), paddle.to_tensor(1)
)
self.assert_results(
test_sum_list, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
)
self.assert_results(
test_sum_list, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
)
self.assert_results(test_sum_list2, 1, 1)
self.assert_results(test_sum_list2, [1, 2], [3, 4])
self.assert_results(test_sum_list2, paddle.to_tensor(1), 1)
self.assert_results(
test_sum_list2, paddle.to_tensor(1), paddle.to_tensor(1)
)
self.assert_results(
test_sum_list2,
[paddle.to_tensor(1), paddle.to_tensor(2)],
[paddle.to_tensor(3), paddle.to_tensor(4)],
)
self.assert_results(
test_sum_list2, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
)
self.assert_results(
test_sum_list2, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
)
self.assert_results(test_sum_list3, 1)
self.assert_results(test_sum_list3, paddle.to_tensor(1))
self.assert_results(test_tensor_sum, paddle.to_tensor([1, 2]))
self.assert_results(test_tensor_sum, paddle.to_tensor((1, 2)))
self.assert_results(test_tensor_sum_api, paddle.to_tensor([1, 2]))
self.assert_results(test_tensor_sum_api, paddle.to_tensor((1, 2)))
def test_dispatch_pow(self):
self.assert_results(test_pow, 2, 3)
self.assert_results(test_pow, paddle.to_tensor(2), 3)
self.assert_results(test_pow, paddle.to_tensor(2), paddle.to_tensor(3))
self.assert_results(test_pow2, 2, 3)
self.assert_results(test_math_pow, 2, 3)
self.assert_results(test_tensor_pow_api, paddle.to_tensor(2), 3)
self.assert_results(
test_tensor_pow_api, paddle.to_tensor(2), paddle.to_tensor(3)
)
def test_dispatch_chr(self):
self.assert_results(test_chr, 65)
self.assert_results(test_chr, 0x41)
self.assert_results(test_chr, paddle.to_tensor(65))
self.assert_results(test_chr, paddle.to_tensor(0x41))
def test_dispatch_ord(self):
self.assert_results(test_ord, "a")
def test_dispatch_sqrt(self):
self.assert_results(test_sqrt, 9)
def test_dispatch_log(self):
self.assert_results(test_log, math.e)
def test_dispatch_min(self):
self.assert_results(test_min)
def test_dispatch_max(self):
self.assert_results(test_max)
def test_dispatch_builtin_type_check_eq(self):
self.assert_results(test_builtin_type_check_eq)
def test_dispatch_any(self):
l_pure_true = [1, True, 5, 6]
l_pure_false = [False, 0, 0]
l_true_and_false = [1, False, 0, 3]
d_true = {"a": 1}
d_false = {}
self.assert_results(test_any, l_pure_true)
self.assert_results(test_any, l_pure_false)
self.assert_results(test_any, l_true_and_false)
self.assert_results(test_any, d_true)
self.assert_results(test_any, d_false)
self.assert_results(test_any_iter, l_true_and_false)
def test_dispatch_all(self):
l_pure_true = [1, True, 5, 6]
l_pure_false = [False, 0, 0]
l_true_and_false = [1, False, 0, 3]
d_true = {"a": 1}
d_false = {}
self.assert_results(test_all, l_pure_true)
self.assert_results(test_all, l_pure_false)
self.assert_results(test_all, l_true_and_false)
self.assert_results(test_all, d_true)
self.assert_results(test_all, d_false)
self.assert_results(test_all_iter, l_true_and_false)
def test_dispatch_is(self):
x = paddle.ones(shape=[1, 2])
y = paddle.ones(shape=[1, 2])
# TODO(wangmingkai02): support comparison of same tensor object
# self.assert_results(test_is, x, x)
# self.assert_results(test_is, [x], [x])
self.assert_results(test_is, x, y)
self.assert_results(test_is, x, None)
self.assert_results(test_is, [x], x)
self.assert_results(test_is, None, x)
self.assert_results(test_is, [x], None)
self.assert_results(test_is, None, [x])
self.assert_results(test_is, None, None)
def run_getattr(x: paddle.Tensor):
attr = 'dtype'
out = getattr(x, attr)
return out
class TestGetattr(TestCaseBase):
def test_getattr(self):
x = paddle.to_tensor(4)
self.assert_results(run_getattr, x)
def tensor_hasattr(x: paddle.Tensor):
return (
hasattr(x, "dtype"),
hasattr(x, "stop_gradient"),
hasattr(x, "abs"),
hasattr(x, "non_tensor_attr"),
)
class ObjectHasattr:
def __init__(self):
attr1 = 1
attr2 = "2"
attr3 = [3]
def object_hasattr(x: ObjectHasattr):
return (
hasattr(x, "attr1"),
hasattr(x, "attr2"),
hasattr(x, "attr3"),
hasattr(x, "non_obj_attr"),
)
def layer_hasattr(layer: paddle.nn.Layer):
return (
hasattr(layer, "parameters"),
hasattr(layer, "sublayers"),
hasattr(layer, "non_layer_attr"),
)
class TestHasattr(TestCaseBase):
def test_tensor_hasattr(self):
x = paddle.to_tensor(4)
self.assert_results(tensor_hasattr, x)
def test_object_hasattr(self):
x = ObjectHasattr()
self.assert_results(object_hasattr, x)
def test_layer_hasattr(self):
x = paddle.nn.Layer()
self.assert_results(layer_hasattr, x)
class WeakrefableObject: ...
def weakref_breakgraph(obj):
return weakref.ref(obj)
class TestWeakref(TestCaseBase):
def test_weakref_breakgraph(self):
obj = WeakrefableObject()
self.assert_results(weakref_breakgraph, obj)
def test_builtin_type_conversion_breakgraph(x):
return int(x), bool(x), float(x)
class TestBuiltinTypeConversion(TestCaseBase):
def test_builtin_type_conversion_breakgraph(self):
self.assert_results(
test_builtin_type_conversion_breakgraph, paddle.to_tensor(1.2)
)
self.assert_results(
test_builtin_type_conversion_breakgraph, paddle.to_tensor(0)
)
@check_no_breakgraph
def test_native_code_function():
res1 = paddle.base.libpaddle.is_compiled_with_avx()
res2 = paddle.base.libpaddle.is_compiled_with_cuda()
res3 = paddle.base.libpaddle.is_compiled_with_cudnn_frontend()
res4 = paddle.base.libpaddle.is_compiled_with_rocm()
res5 = paddle.base.libpaddle.is_compiled_with_custom_device("npu")
res6 = paddle.base.libpaddle.is_compiled_with_ipu()
res7 = paddle.base.libpaddle.is_compiled_with_xpu()
res8_deprecated = (
paddle.base.libpaddle.is_compiled_with_mkldnn()
) # Paddle 3.3 deprecated
res8 = paddle.base.libpaddle.is_compiled_with_onednn()
res9 = paddle.base.libpaddle.is_compiled_with_nccl()
res10 = paddle.base.libpaddle.is_compiled_with_mpi()
res11 = paddle.base.libpaddle.is_compiled_with_mpi_aware()
res12 = paddle.base.libpaddle.is_compiled_with_cinn()
res13 = paddle.base.libpaddle.is_compiled_with_distribute()
res14 = paddle.base.libpaddle.is_compiled_with_brpc()
res15 = paddle.base.libpaddle.is_compiled_with_dist()
return (
res1,
res2,
res3,
res4,
res5,
res6,
res7,
res8_deprecated,
res8,
res9,
res10,
res11,
res12,
res13,
res14,
res15,
)
@check_no_breakgraph
def test_native_code_function_gpu_only():
# Directly returning device_properties causes BreakGraph due to FallbackError:
# "ObjectVariable does not implement '_reconstruct' method"
# Therefore, we return individual properties as primitive types instead
device_properties = paddle.device.cuda.get_device_properties()
return (
device_properties.name,
device_properties.major,
device_properties.minor,
device_properties.total_memory,
device_properties.multi_processor_count,
)
class TestNativeCodeFunction(TestCaseBase):
def test_native_code_function(self):
self.assert_results(test_native_code_function)
@unittest.skipUnless(paddle.device.is_compiled_with_cuda(), "requires CUDA")
def test_native_code_function_gpu_only(self):
self.assert_results(test_native_code_function_gpu_only)
if __name__ == "__main__":
unittest.main()
+154
View File
@@ -0,0 +1,154 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from typing import TYPE_CHECKING
from test_case_base import TestCaseBase
from paddle import Tensor, to_tensor
from paddle.jit import sot
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import strict_mode_guard
if TYPE_CHECKING:
from collections.abc import Iterable
def double_num(num: float):
return num * 2
def double_num_with_breakgraph(num: float):
sot.psdb.breakgraph()
return num * 2
@check_no_breakgraph
def test_map_list(x: list):
return list(map(double_num, x))
@check_no_breakgraph
def test_map_list_comprehension(x: list):
return [i for i in map(double_num, x)] # noqa: C416
@check_no_breakgraph
def test_map_tuple(x: tuple):
return tuple(map(double_num, x))
@check_no_breakgraph
def test_map_tuple_comprehension(x: tuple):
return [i for i in map(double_num, x)] # noqa: C416
@check_no_breakgraph
def test_map_range(x: Iterable):
return list(map(double_num, x))
@check_no_breakgraph
def test_map_range_comprehension(x: Iterable):
return [i for i in map(double_num, x)] # noqa: C416
def add_dict_prefix(key: str):
return f"dict_{key}"
@check_no_breakgraph
def test_map_dict(x: dict):
return list(map(add_dict_prefix, x))
@check_no_breakgraph
def test_map_dict_comprehension(x: dict):
return [i for i in map(add_dict_prefix, x)] # noqa: C416
def test_map_list_with_breakgraph(x: list):
return list(map(double_num_with_breakgraph, x))
@check_no_breakgraph
def test_map_unpack(x: list):
a, b, c, d = map(double_num, x)
return a, b, c, d
@check_no_breakgraph
def test_map_for_loop(x: list):
res = 0
for i in map(double_num, x):
res += i
return res
@check_no_breakgraph
def test_map_multi_input(func, a: Tensor, b: tuple[int, ...]):
x, y, z = map(func, a, b)
return x, y, z
@check_no_breakgraph
def test_map_with_zip_and_call_fn_ex(x: list[tuple[int, int]]):
fn = lambda x: (0,) + x # noqa: RUF005
map_results = map(fn, x)
res = tuple(map(list, zip(*map_results)))
return res
class TestMap(TestCaseBase):
def test_map(self):
self.assert_results(test_map_list, [1, 2, 3, 4])
self.assert_results(test_map_tuple, (1, 2, 3, 4))
self.assert_results(test_map_range, range(5))
self.assert_results(test_map_dict, {"a": 1, "b": 2, "c": 3})
def test_map_comprehension(self):
self.assert_results(test_map_list_comprehension, [1, 2, 3, 4])
self.assert_results(test_map_tuple_comprehension, (1, 2, 3, 4))
self.assert_results(test_map_range_comprehension, range(5))
self.assert_results(
test_map_dict_comprehension, {"a": 1, "b": 2, "c": 3}
)
def test_map_with_breakgraph(self):
with strict_mode_guard(False):
self.assert_results(test_map_list_with_breakgraph, [1, 2, 3, 4])
def test_map_unpack(self):
self.assert_results(test_map_unpack, [1, 2, 3, 4])
self.assert_results(
test_map_multi_input,
lambda x, y: x + y,
to_tensor([1, 2, 3]),
(2, 4, 6),
)
def test_map_for_loop(self):
self.assert_results(test_map_for_loop, [7, 8, 9, 10])
def test_map_with_zip_and_call_fn_ex(self):
self.assert_results(
test_map_with_zip_and_call_fn_ex, [(1, 2), (3, 4), (5, 6)]
)
if __name__ == "__main__":
unittest.main()
+92
View File
@@ -0,0 +1,92 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
def test_range_1(stop: int):
return range(stop)
def test_range_2(start: int, stop: int):
return range(start, stop)
def test_range_3(start: int, stop: int, step: int):
return range(start, stop, step)
def test_range_4(stop: int, index: int):
return range(stop)[index]
def test_range_5(stop: int):
return list(range(stop))
def test_range_6(stop: int, index: int):
return list(range(stop))[index]
def test_range_7(index: int, tensor: paddle.Tensor):
return list(range(len(tensor.shape)))[index]
def test_range_8(stop: int):
sum = 0
for i in range(stop):
sum += i
return sum
def test_range_9(stop: int, tensor: paddle.Tensor):
for i in range(stop):
tensor += i
return tensor
def test_range_10(stop: int, tensor: paddle.Tensor):
for i in range(stop):
for j in range(stop + 1):
tensor += j
return tensor
class TestRange(TestCaseBase):
def test_cases(self):
start = 3
stop = 10
step = 2
index = 1
tensor = paddle.randn((10, 10))
self.assert_results(test_range_1, stop)
self.assert_results(test_range_2, start, stop)
self.assert_results(test_range_3, start, stop, step)
self.assert_results(test_range_4, stop, index)
self.assert_results(test_range_5, stop)
self.assert_results(test_range_6, stop, index)
self.assert_results(test_range_7, index, tensor)
self.assert_results(test_range_8, stop)
self.assert_results(test_range_9, stop, paddle.randn((10,)))
self.assert_results(test_range_10, stop, paddle.randn((10,)))
if __name__ == "__main__":
unittest.main()
+109
View File
@@ -0,0 +1,109 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot import psdb, symbolic_translate
from paddle.jit.sot.utils import min_graph_size_guard, strict_mode_guard
def test_zip_1(x: int, y: int):
for (id, val), val_ in zip(enumerate(range(x)), range(x)):
if id % 2 == 0:
y += val_
return y
def test_zip_2(x: list):
return list(zip(x, range(len(x))))
def test_zip_3(x: list):
return tuple(zip(x, range(len(x))))
def test_zip_4(x: paddle.Tensor):
sum = 0
for idx, val in zip(range(len(x)), x):
sum += val
return sum
def test_zip_5(x: paddle.Tensor):
sum = 0
for idx, val in zip(range(len(x)), x):
for i in range(idx):
sum += val
return sum
def test_zip_6(x: paddle.Tensor):
sum = 0
x = x.flatten()
for idx, val in zip(range(len(x)), x):
sum += val
return sum
def test_zip_7(layer_list, x):
sum = 0
for idx, layer in zip(range(len(layer_list)), layer_list):
sum += layer(x)
return sum
def test_zip_8(iter_1, iter_2):
sum = 0
for a, b in zip(iter_1, iter_2):
psdb.breakgraph()
sum += a
sum += b
return sum
class TestZip(TestCaseBase):
def test_simple_cases(self):
x = 8
y = 5
ty = paddle.randn((10, 10))
layer_list = paddle.nn.LayerList(
[paddle.nn.Linear(10, 10) for _ in range(3)]
)
self.assert_results(test_zip_1, x, y)
self.assert_results(test_zip_2, [2, 4, 6, 8, 10])
self.assert_results(test_zip_3, [2, 4, 6, 8, 10])
self.assert_results(test_zip_4, ty)
self.assert_results(test_zip_5, paddle.to_tensor([1, 2, 3]))
self.assert_results(test_zip_6, ty)
self.assert_results(test_zip_7, layer_list, paddle.randn((10,)))
@min_graph_size_guard(0)
@strict_mode_guard(False)
def test_reconstruct(self):
self.assert_results(test_zip_8, [1, 2, 3], [4, 5, 6])
@strict_mode_guard(False)
@min_graph_size_guard(0)
def test_zip_user_defined_iter(self):
sym_output = symbolic_translate(test_zip_8)(iter([1, 2, 3]), [4, 5, 6])
paddle_output = test_zip_8(iter([1, 2, 3]), [4, 5, 6])
self.assert_nest_match(sym_output, paddle_output)
if __name__ == "__main__":
unittest.main()
+61
View File
@@ -0,0 +1,61 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils import try_ast_func, with_control_flow_guard
@try_ast_func
def calc(x, y, z):
if x < 5:
a = x + y
b = y - z
c = a * b
return c
else:
a = x - y
b = y + z
c = a * b
return c
def inline_call_ast(x, y):
a = x - y + 3
b = x + y
c = x * y
z = calc(a, b, c)
return z + a
class TestNumPyAdd(TestCaseBase):
@with_control_flow_guard(True)
def test_full_graph_ast(self):
x = paddle.to_tensor([2])
y = paddle.to_tensor([3])
z = paddle.to_tensor([4])
self.assert_results(calc, x, y, z)
@with_control_flow_guard(True)
def test_inline_ast(self):
x = paddle.to_tensor([2])
y = paddle.to_tensor([3])
self.assert_results(inline_call_ast, x, y)
if __name__ == "__main__":
unittest.main()
+83
View File
@@ -0,0 +1,83 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
patched = lambda self, x: x * self.a
patched2 = lambda self, x: x * self.a + 3
class A:
def __init__(self, a):
self.a = a
def __call__(self, x):
return self.add(x)
def add(self, x):
return x + self.a
multi = patched
class B:
def __init__(self, a):
self.a = A(a)
def __call__(self, x, func):
return getattr(self.a, func)(x)
def self_call(self, x, func):
return getattr(self.a, func)(self.a, x)
def foo_1(a, x):
return a(x)
def foo_2(a, x):
return a.multi(x)
def foo_3(b, x):
return b(x, "multi")
def foo_4(b, x):
return b(x, "add")
def foo_5(b, x):
return b.self_call(x, "multi")
class TestCallObject(TestCaseBase):
def test_simple(self):
c = B(13)
c.a.multi = patched2
self.assert_results(foo_1, A(13), paddle.to_tensor(2))
self.assert_results(foo_2, A(13), paddle.to_tensor(2))
self.assert_results(foo_3, B(13), paddle.to_tensor(2))
self.assert_results(foo_4, B(13), paddle.to_tensor(2))
self.assert_results(foo_5, c, paddle.to_tensor(2))
self.assert_results(foo_4, c, paddle.to_tensor(2))
if __name__ == "__main__":
unittest.main()
+106
View File
@@ -0,0 +1,106 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle import nn
@paddle.jit.marker.capture_control_flow
def inner_fn_with_control_flow_explicit_capture(x):
if x.sum() > 0:
x += 1
else:
x -= 1
return x
def fn_with_control_flow_explicit_capture(x):
x = inner_fn_with_control_flow_explicit_capture(x)
return x + 1
def fn_without_capture(x):
if x.sum() > 0:
x += 1
else:
x -= 1
return x + 1
class TestCaptureControlFlow(TestCaseBase):
def test_case_without_capture_control_flow(self):
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
x = paddle.full([3, 3], 1)
self.assert_results(fn_without_capture, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.full([3, 3], -1)
self.assert_results(fn_without_capture, x)
self.assertEqual(ctx.translate_count, 3)
def test_case_capture_control_flow(self):
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
x = paddle.full([3, 3], 1)
self.assert_results(fn_with_control_flow_explicit_capture, x)
self.assertEqual(ctx.translate_count, 1)
x = paddle.full([3, 3], -1)
self.assert_results(fn_with_control_flow_explicit_capture, x)
self.assertEqual(ctx.translate_count, 1)
class NetWithCaptureControlFlow(nn.Layer):
def __init__(self):
super().__init__()
self.layer = nn.Linear(8, 8)
@paddle.jit.marker.capture_control_flow
def fn(self, x):
x = self.layer(x)
if x.sum() > 0:
x += paddle.ones_like(x)
else:
x -= paddle.zeros_like(x)
return x
def forward(self, x):
return self.fn(x) + 1
def model_call(x: paddle.Tensor, net: paddle.nn.Layer):
return net(x)
class TestEagerParamsToPirValue(TestCaseBase):
def test_case_without_capture_control_flow(self):
model = NetWithCaptureControlFlow()
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
x = paddle.randn([4, 8])
self.assert_results(model_call, x, model)
self.assertEqual(ctx.translate_count, 1)
x = paddle.randn([4, 8])
self.assert_results(model_call, x, model)
self.assertEqual(ctx.translate_count, 1)
if __name__ == "__main__":
unittest.main()
+156
View File
@@ -0,0 +1,156 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import contextlib
import copy
import types
import unittest
import numpy as np
import paddle
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
OpcodeExecutorCache,
)
@contextlib.contextmanager
def test_instruction_translator_cache_context():
cache = OpcodeExecutorCache()
cache.clear()
yield cache
cache.clear()
class TestCaseBase(unittest.TestCase):
def assert_nest_match(self, actual, expected):
cls_actual = type(actual)
cls_expected = type(expected)
msg = (
f"type mismatch, actual is {cls_actual}, expected is {cls_expected}"
)
self.assertIs(cls_actual, cls_expected, msg=msg)
container_types = (tuple, list, dict, set)
if cls_actual in container_types:
msg = f"length mismatch, actual is {len(actual)}, expected is {len(expected)}"
self.assertEqual(
len(actual),
len(expected),
msg=msg,
)
if cls_actual in (tuple, list):
for actual_item, expected_item in zip(actual, expected):
self.assert_nest_match(actual_item, expected_item)
elif cls_actual is dict:
for actual_key, expected_key in zip(
actual.keys(), expected.keys()
):
self.assert_nest_match(actual_key, expected_key)
self.assert_nest_match(
actual[actual_key], expected[expected_key]
)
elif cls_actual is set:
# TODO: Nested set is not supported yet
self.assertEqual(actual, expected)
elif cls_actual in (np.ndarray, paddle.Tensor):
# TODO: support assert_allclose github error log
np.testing.assert_allclose(actual, expected, rtol=1e-6, atol=1e-8)
else:
self.assertEqual(actual, expected)
def assert_results(self, func, *args, **kwargs):
sym_output = symbolic_translate(func)(*args, **kwargs)
paddle_output = func(*args, **kwargs)
self.assert_nest_match(sym_output, paddle_output)
def assert_results_with_grad(self, inputs, func, *args, **kwargs):
def _find_all_tensors(obj):
ret = []
container_types = (tuple, list, set)
if isinstance(obj, container_types):
for item in obj:
ret.extend(_find_all_tensors(item))
elif isinstance(obj, dict):
for value in obj.values():
ret.extend(_find_all_tensors(value))
elif isinstance(obj, paddle.Tensor):
ret.append(obj)
return ret
def _accumulate(tensors: list):
out = paddle.empty(shape=[], dtype='float64')
for tensor in tensors:
out += paddle.mean(tensor.astype('float64'))
return out
def _cal_input_grads(outputs):
tensor_outs = _find_all_tensors(outputs)
acc = _accumulate(tensor_outs)
acc.backward()
tensor_inputs = _find_all_tensors(inputs)
input_grads = []
for input in tensor_inputs:
input_grads.append(
None if input.grad is None else input.grad.clone()
)
input.clear_gradient()
return input_grads
sym_output = symbolic_translate(func)(*args, **kwargs)
paddle_output = func(*args, **kwargs)
sym_input_grads = _cal_input_grads(sym_output)
paddle_input_grads = _cal_input_grads(paddle_output)
self.assert_nest_match(sym_input_grads, paddle_input_grads)
self.assert_nest_match(sym_output, paddle_output)
def assert_exceptions(self, exec, info, func, *args, **kwargs):
self.assertRaisesRegex(
exec, info, symbolic_translate(func), *args, **kwargs
)
def assert_results_with_side_effects(self, func, *args, **kwargs):
sym_args, sym_kwargs = copy.deepcopy((args, kwargs))
sym_output = symbolic_translate(func)(*sym_args, **sym_kwargs)
paddle_args, paddle_kwargs = copy.deepcopy((args, kwargs))
paddle_output = func(*paddle_args, **paddle_kwargs)
self.assert_nest_match(sym_args, paddle_args)
self.assert_nest_match(sym_kwargs, paddle_kwargs)
self.assert_nest_match(sym_output, paddle_output)
def assert_results_with_global_check(
self, func, global_keys: list[str], *args, **kwargs
):
def copy_fn(fn):
return types.FunctionType(
code=fn.__code__,
globals=copy.copy(fn.__globals__),
name=fn.__name__,
argdefs=fn.__defaults__,
closure=fn.__closure__,
)
sym_copied_fn = copy_fn(func)
sym_fn = symbolic_translate(sym_copied_fn)
paddle_fn = copy_fn(func)
sym_output = sym_fn(*args, **kwargs)
paddle_output = paddle_fn(*args, **kwargs)
for key in global_keys:
self.assert_nest_match(
sym_copied_fn.__globals__[key], paddle_fn.__globals__[key]
)
self.assert_nest_match(sym_output, paddle_output)
+97
View File
@@ -0,0 +1,97 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from collections import namedtuple
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot import psdb
Singleton = namedtuple("Singleton", ["a"])
Pair = namedtuple("Pair", ["a", "b"])
Triplet = namedtuple("Triple", ["a", "b", "c"])
Quartet = namedtuple("Quartet", ["a", "b", "c", "d"])
QuartetWithDefault = namedtuple(
"QuartetWithDefault", ["a", "b", "c", "d"], defaults=[1, 2, 3]
)
@psdb.check_no_breakgraph
def create_namedtuple():
x = Singleton(1)
y = Singleton(2)
z = Singleton(3)
return x.a + y.a + z.a
@psdb.check_no_breakgraph
def create_namedtuple_with_tensor(x):
y = Pair(x + 1, x + 2)
z = Pair(x + 3, x + 4)
return y.a + y.b + z.a + z.b
@psdb.check_no_breakgraph
def load_namedtuple(x, y):
return x.a + y.a + y.b
@psdb.check_no_breakgraph
def create_namedtuple_with_default():
u = QuartetWithDefault(1, 2, 3, 4)
v = QuartetWithDefault(5, 6, 7)
w = QuartetWithDefault(8, 9)
x = QuartetWithDefault(10)
return (
(u.a + u.b + u.c + u.d)
+ (v.a + v.b + v.c + v.d)
+ (w.a + w.b + w.c + w.d)
+ (x.a + x.b + x.c + x.d)
)
@psdb.check_no_breakgraph
def get_fields():
x = Singleton(1)
y = Pair(2, 3)
z = Triplet(4, 5, 6)
return x._fields + y._fields + z._fields
class TestNamedTuple(TestCaseBase):
def test_create_namedtuple(self):
self.assert_results(create_namedtuple)
def test_create_namedtuple_with_tensor(self):
x = paddle.to_tensor(1)
self.assert_results(create_namedtuple_with_tensor, x)
def test_load_namedtuple(self):
x = Singleton(paddle.to_tensor(1))
y = Pair(paddle.to_tensor(2), paddle.to_tensor(3))
self.assert_results(load_namedtuple, x, y)
def test_create_namedtuple_with_default(self):
self.assert_results(create_namedtuple_with_default)
def test_get_fields(self):
self.assert_results(get_fields)
if __name__ == "__main__":
unittest.main()
+54
View File
@@ -0,0 +1,54 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# New Supported Instructions:
# BUILD_MAP (new)
# BUILD_CONST_KEY_MAP (new)
import unittest
from test_case_base import TestCaseBase
import paddle
def func_1(format_str, tensor):
str = format_str.format(xx=12)
a = "{xx} = 12".format
ttt = f"{10} = 12"
a(xx=12)
tensor = tensor + 1
return str, tensor
def func_2(format_str, tensor):
str = format_str % 10
tensor = tensor + 1
return str, tensor
class TestConstantGraph(TestCaseBase):
def test_case_1(self):
x = "{xx} is xx"
tensor = paddle.to_tensor(1)
self.assert_results(func_1, x, tensor)
def test_case_2(self):
x = "%s is xx"
tensor = paddle.to_tensor(1)
self.assert_results(func_2, x, tensor)
if __name__ == "__main__":
unittest.main()
+197
View File
@@ -0,0 +1,197 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from dataclasses import dataclass, field
from test_case_base import (
TestCaseBase,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@dataclass
class DataTensor:
x: paddle.Tensor
@dataclass
class DataInt:
x: int
@dataclass
class DataTensorWithPostInit:
x: paddle.Tensor
def __post_init__(self):
self.x += 1
@dataclass
class MultiInheritDataTensor(DataTensorWithPostInit):
place: str
@dataclass
class MultiInheritDataTensorWithIdx(MultiInheritDataTensor):
idx: int
def return_dataclass(x):
return DataTensor(x + 1)
def return_dataclass_with_post_init(x):
return DataTensorWithPostInit(x)
def return_dataclass_with_multi_inherit(x, place="gpu", idx=-1):
return MultiInheritDataTensorWithIdx(x, place, idx)
class TestDataclassBasic(TestCaseBase):
def test_dtype_reconstruct(self):
x = paddle.to_tensor(1)
self.assert_results(return_dataclass, x)
def test_dtype_reconstruct_with_post_init(self):
x = paddle.to_tensor(1)
self.assert_results(return_dataclass_with_post_init, x)
def test_dtype_reconstruct_with_multi_inherit(self):
x = paddle.to_tensor(1)
self.assert_results(return_dataclass_with_multi_inherit, x, "nyapu", 1)
@dataclass
class DataMeta:
x: paddle.Tensor
y: paddle.Tensor | None = None
m: list[list[paddle.Tensor]] = field(default_factory=list)
n: int = 0
def __post_init__(self):
self.x += 1
@check_no_breakgraph
def is_data_int_eq(data1: DataInt, data2: DataInt):
return data1 == data2
def is_data_tensor_eq(data1: DataTensor, data2: DataTensor):
return data1 == data2
def is_any_eq(data1, data2):
return data1 == data2
@check_no_breakgraph
def get_attr(data: DataMeta):
return data.x + data.y
@check_no_breakgraph
def set_attr(data: DataMeta):
ori_x = data.x
data.x = data.x + data.n
res = data.x
data.x = ori_x
return res
@check_no_breakgraph
def get__dataclass_fields__(data: DataMeta):
return list(data.__dataclass_fields__), list(
data.__class__.__dataclass_fields__
)
class TestDataClassInstance(TestCaseBase):
def test_get_attr(self):
dm = DataMeta(x=paddle.randn([1, 2]), y=paddle.randn([1]))
self.assert_results(get_attr, dm)
self.assert_results(get__dataclass_fields__, dm)
def test_set_attr(self):
dm = DataMeta(x=paddle.ones([1, 2]), n=2)
self.assert_results(set_attr, dm)
def test_eq_int(self):
di1 = DataInt(x=1)
di2 = DataInt(x=1)
di3 = DataInt(x=2)
self.assert_results(is_data_int_eq, di1, di2)
self.assert_results(is_data_int_eq, di1, di3)
def test_eq_tensor(self):
t = paddle.randn([1])
dt1 = DataTensor(x=t)
dt2 = DataTensor(x=t)
dt3 = DataTensor(x=paddle.zeros([1]))
self.assert_results(is_data_tensor_eq, dt1, dt2)
self.assert_results(is_data_tensor_eq, dt1, dt3)
def test_eq_diff_dataclass(self):
di = DataInt(x=1)
dt = DataTensor(x=1) # type: ignore
self.assert_results(is_data_int_eq, di, dt)
@dataclass
class ComplexDataClass:
a: int
b: int = 0
c: int = field(default=1)
d: int = field(default_factory=lambda: 2, kw_only=True)
def create_dataclass_with_a():
return ComplexDataClass(0)
def create_dataclass_with_kwarg_a():
return ComplexDataClass(a=1)
def create_dataclass_with_a_b_c():
return ComplexDataClass(1, 2, 3)
def create_dataclass_with_kwarg_a_b_c():
return ComplexDataClass(1, 2, 3)
class TestDataClassConstruction(TestCaseBase):
def test_create_dataclass_with_a(self):
self.assert_results(create_dataclass_with_a)
def test_create_dataclass_with_kwarg_a(self):
self.assert_results(create_dataclass_with_kwarg_a)
def test_create_dataclass_with_a_b_c(self):
self.assert_results(create_dataclass_with_a_b_c)
def test_create_dataclass_with_kwarg_a_b_c(self):
self.assert_results(create_dataclass_with_kwarg_a_b_c)
if __name__ == "__main__":
unittest.main()
+61
View File
@@ -0,0 +1,61 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import breakgraph
def test_delete_fast(a):
a = a + 2
t = a * 3
del t
return a
def inner_call_with_breakgraph(a):
breakgraph()
return a + 1
def test_delete_fast_with_breakgraph(a):
a = a + 2
t1 = a * 3
out1 = inner_call_with_breakgraph(a + t1)
t2 = a - 4
t3 = a / 5
out2 = inner_call_with_breakgraph(t1 + t2)
del t1, t2, t3
return a + out1 + out2
class TestDeleteFast(TestCaseBase):
def test_simple(self):
a = paddle.to_tensor(1)
self.assert_results(test_delete_fast, a)
class TestDeleteFastWithBreakGraph(TestCaseBase):
def test_delete_fast_with_break_graph(self):
a = paddle.to_tensor(1)
self.assert_results(test_delete_fast_with_breakgraph, a)
if __name__ == "__main__":
unittest.main()
+82
View File
@@ -0,0 +1,82 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
def tensor_astype(x, y):
z = x.astype(y.dtype)
return z
def tensor_dtype_guard(x):
return x + 1
def reconstruct_dtype():
x = paddle.to_tensor(1)
z = x.dtype
if x > 0:
y = paddle.to_tensor(1, dtype=z)
else:
y = 1
return y
def dtype_guard(x, cast_map):
out = paddle.cast(x, cast_map[x.dtype])
return out, out.dtype
class TestTensorAstype(TestCaseBase):
def test_tensor_astype(self):
x = paddle.ones([2, 3], dtype="float32")
y = paddle.ones([2, 3], dtype="int32")
self.assert_results(tensor_astype, x, y)
class TestTensorDtypeGuard(TestCaseBase):
def test_tensor_dtype_guard(self):
x = paddle.ones([2, 3], dtype="float32")
y = paddle.ones([2, 3], dtype="int32")
with test_instruction_translator_cache_context() as ctx:
self.assert_results(tensor_dtype_guard, x)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(tensor_dtype_guard, y)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(tensor_dtype_guard, x)
self.assertEqual(ctx.translate_count, 2)
class TestDtypeReconstruct(TestCaseBase):
def test_dtype_reconstruct(self):
self.assert_results(reconstruct_dtype)
class TestDtypeGuard(TestCaseBase):
def test_dtype_guard(self):
dtype_map = {paddle.float32: paddle.float64}
x = paddle.ones([2, 3], dtype="float32")
self.assert_results(dtype_guard, x, dtype_map)
if __name__ == "__main__":
unittest.main()
+49
View File
@@ -0,0 +1,49 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def func_dup_top_1():
return True == True != False
def func_dup_top_2(x):
y = x + 1
return True == True != False
def func_dup_top_two(x: list[paddle.Tensor]):
x[0] += x[1]
return x
class TestDupTop(TestCaseBase):
def test_dup_top(self):
self.assert_results(func_dup_top_1)
self.assert_results(func_dup_top_2, paddle.to_tensor(1.0))
# TODO: fix this after we support side effect
# self.assert_results(
# func_dup_top_two, [paddle.to_tensor(1.0), paddle.to_tensor(2.0)]
# )
if __name__ == "__main__":
unittest.main()
+118
View File
@@ -0,0 +1,118 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from enum import IntEnum
from typing import Any
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
from paddle.jit.sot.psdb import check_no_breakgraph
class Direction(IntEnum):
UP = 1
RIGHT = 2
DOWN = 3
LEFT = 4
class Direction2(IntEnum):
EAST = 1
WEST = 2
NORTH = 3
SOUTH = 4
@check_no_breakgraph
def eq_func(x: IntEnum, y: IntEnum):
return x == y
def eq_func_2(x: IntEnum, y: Any):
return x == y
@check_no_breakgraph
def not_eq_func(x: IntEnum, y: IntEnum):
return x != y
def not_eq_func_2(x: IntEnum, y: Any):
return x != y
@check_no_breakgraph
def name_func(x: IntEnum):
return x.name
@check_no_breakgraph
def is_func(x: IntEnum, y: IntEnum):
return x is y
def get_func(x: int):
return Direction(x)
@check_no_breakgraph
def get_func_2(x: str):
return Direction[x]
class TestEnumMethod(TestCaseBase):
def test_guard(self):
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(eq_func, Direction.UP, Direction.UP)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(eq_func, Direction.UP, Direction.DOWN)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(eq_func, Direction.UP, Direction.UP)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(eq_func, Direction.UP, Direction2.EAST)
self.assertEqual(ctx.translate_count, 3)
def test_eq(self):
self.assert_results(eq_func, Direction.UP, Direction.UP)
self.assert_results(eq_func, Direction.RIGHT, Direction.LEFT)
self.assert_results(eq_func, Direction.UP, Direction2.EAST)
self.assert_results(eq_func_2, Direction.UP, 1)
def test_not_eq(self):
self.assert_results(not_eq_func, Direction.UP, Direction.UP)
self.assert_results(not_eq_func, Direction.UP, Direction.DOWN)
self.assert_results(not_eq_func, Direction.UP, Direction2.EAST)
self.assert_results(not_eq_func_2, Direction.UP, 0)
def test_name(self):
self.assert_results(name_func, Direction.UP)
def test_is(self):
self.assert_results(is_func, Direction.UP, Direction.UP)
self.assert_results(is_func, Direction.RIGHT, Direction.LEFT)
self.assert_results(is_func, Direction.UP, Direction2.EAST)
def test_get(self):
# TODO(wangmingkai): implement “_reconstruct” for EnumVariable
# self.assert_results(get_func, 1)
self.assert_results(get_func_2, 'UP')
if __name__ == "__main__":
unittest.main()
+117
View File
@@ -0,0 +1,117 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils import strict_mode_guard
def test_enumerate_1(x: int, y: int):
for id, val in enumerate(range(x)):
if id % 2 == 0:
y += val
return y
def test_enumerate_2(x: list):
return list(enumerate(x))
def test_enumerate_3(x: list):
return tuple(enumerate(x))
def test_enumerate_4(x: paddle.Tensor):
sum = 0
for idx, val in enumerate(x):
sum += val
return sum
# TODO(zmh): support range for tensor
def test_enumerate_5(x: paddle.Tensor):
sum = 0
for idx, val in enumerate(x):
for i in range(val):
sum += val
return sum
def test_enumerate_6(x: paddle.Tensor):
sum = 0
for idx, val in enumerate(x):
for i in range(idx):
sum += val
return sum
def test_enumerate_7(x: paddle.Tensor):
sum = 0
x = x.flatten()
for idx, val in enumerate(x):
sum += val
return sum
# TODO(zmh): support -1
def test_enumerate_8(x: paddle.Tensor):
sum = 0
x = paddle.nonzero(x, as_tuple=False)
for idx, val in enumerate(x):
sum += val
return sum
def test_enumerate_10(layer_list, x):
sum = 0
for idx, layer in enumerate(layer_list):
sum += layer(x)
return sum
class TestEnumerate(TestCaseBase):
def test_cases(self):
x = 8
y = 5
ty = paddle.randn((10, 10))
layer_list = paddle.nn.LayerList(
[paddle.nn.Linear(10, 10) for _ in range(3)]
)
self.assert_results(test_enumerate_1, x, y)
self.assert_results(test_enumerate_2, [2, 4, 6, 8, 10])
self.assert_results(test_enumerate_3, [2, 4, 6, 8, 10])
self.assert_results(test_enumerate_4, ty)
# TODO(zmh): support range for tensor
with strict_mode_guard(False):
self.assert_results(test_enumerate_5, paddle.to_tensor([1, 2, 3]))
self.assert_results(test_enumerate_6, paddle.to_tensor([1, 2, 3]))
self.assert_results(test_enumerate_7, ty)
# TODO(zmh): support -1
with strict_mode_guard(False):
self.assert_results(test_enumerate_8, ty)
self.assert_results(test_enumerate_10, layer_list, paddle.randn((10,)))
if __name__ == "__main__":
unittest.main()
+258
View File
@@ -0,0 +1,258 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import os
import unittest
from paddle.jit.sot.utils import PEP508LikeEnvironmentVariable
from paddle.utils.environments import (
BooleanEnvironmentVariable,
EnvironmentVariableGuard,
IntegerEnvironmentVariable,
StringEnvironmentVariable,
)
class TestBooleanEnvironmentVariable(unittest.TestCase):
def test_bool_env_get(self):
env_name = "___TEST_ENV_BOOL_GET"
env_bool = BooleanEnvironmentVariable(env_name, False)
self.assertIs(env_bool.get(), False)
os.environ[env_name] = "False"
self.assertIs(env_bool.get(), False)
os.environ[env_name] = "OFF"
self.assertIs(env_bool.get(), False)
os.environ[env_name] = "0"
self.assertIs(env_bool.get(), False)
os.environ[env_name] = "True"
self.assertIs(env_bool.get(), True)
os.environ[env_name] = "ON"
self.assertIs(env_bool.get(), True)
os.environ[env_name] = "1"
self.assertIs(env_bool.get(), True)
def test_bool_env_set(self):
env_name = "___TEST_ENV_BOOL_SET"
env_bool = BooleanEnvironmentVariable(env_name, False)
env_bool.set(True)
self.assertIs(env_bool.get(), True)
env_bool.set(False)
self.assertIs(env_bool.get(), False)
with self.assertRaises(AssertionError):
env_bool.set("True")
with self.assertRaises(AssertionError):
env_bool.set("False")
with self.assertRaises(AssertionError):
env_bool.set(0)
with self.assertRaises(AssertionError):
env_bool.set(1)
def test_bool_env_guard(self):
env_name = "___TEST_ENV_BOOL_GUARD"
env_bool = BooleanEnvironmentVariable(env_name, False)
with EnvironmentVariableGuard(env_bool, True):
self.assertIs(env_bool.get(), True)
with EnvironmentVariableGuard(env_bool, False):
self.assertIs(env_bool.get(), False)
class TestStringEnvironmentVariable(unittest.TestCase):
def test_str_env_get(self):
env_name = "___TEST_ENV_STR_GET"
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
self.assertEqual(env_str.get(), "DEFAULT")
os.environ[env_name] = "CASE1"
self.assertEqual(env_str.get(), "CASE1")
os.environ[env_name] = "CASE2"
self.assertEqual(env_str.get(), "CASE2")
def test_str_env_set(self):
env_name = "___TEST_ENV_STR_SET"
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
self.assertEqual(env_str.get(), "DEFAULT")
env_str.set("CASE1")
self.assertEqual(env_str.get(), "CASE1")
env_str.set("CASE2")
self.assertEqual(env_str.get(), "CASE2")
with self.assertRaises(AssertionError):
env_str.set(True)
with self.assertRaises(AssertionError):
env_str.set(False)
with self.assertRaises(AssertionError):
env_str.set(0)
with self.assertRaises(AssertionError):
env_str.set(1)
def test_str_env_guard(self):
env_name = "___TEST_ENV_STR_GUARD"
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
with EnvironmentVariableGuard(env_str, "CASE1"):
self.assertEqual(env_str.get(), "CASE1")
with EnvironmentVariableGuard(env_str, "CASE2"):
self.assertEqual(env_str.get(), "CASE2")
class TestIntegerEnvironmentVariable(unittest.TestCase):
def test_int_env_get(self):
env_name = "___TEST_ENV_INT_GET"
env_int = IntegerEnvironmentVariable(env_name, 42)
self.assertEqual(env_int.get(), 42)
os.environ[env_name] = "10"
self.assertEqual(env_int.get(), 10)
os.environ[env_name] = "99999"
self.assertEqual(env_int.get(), 99999)
def test_int_env_set(self):
env_name = "___TEST_ENV_INT_SET"
env_int = IntegerEnvironmentVariable(env_name, 42)
self.assertEqual(env_int.get(), 42)
env_int.set(99)
self.assertEqual(env_int.get(), 99)
env_int.set(1000)
self.assertEqual(env_int.get(), 1000)
with self.assertRaises(AssertionError):
env_int.set(True)
with self.assertRaises(AssertionError):
env_int.set(False)
with self.assertRaises(AssertionError):
env_int.set("10")
with self.assertRaises(AssertionError):
env_int.set("42")
def test_int_env_guard(self):
env_name = "___TEST_ENV_INT_GUARD"
env_int = IntegerEnvironmentVariable(env_name, 42)
with EnvironmentVariableGuard(env_int, 99):
self.assertEqual(env_int.get(), 99)
with EnvironmentVariableGuard(env_int, 1000):
self.assertEqual(env_int.get(), 1000)
class TestPEP508LikeEnvironmentVariable(unittest.TestCase):
def test_PEP508_like_env_get(self):
env_name = "___TEST_ENV_PEP508LikeDict_GET"
env_PEP508_like = PEP508LikeEnvironmentVariable(env_name, {})
if env_name in os.environ:
del os.environ[env_name]
self.assertEqual(env_PEP508_like.get(), {})
os.environ[env_name] = "subgraph_info"
self.assertEqual(env_PEP508_like.get(), {"subgraph_info": []})
os.environ[env_name] = ""
self.assertEqual(env_PEP508_like.get(), {})
os.environ[env_name] = "subgraph_info[ops, data, relationships]"
self.assertEqual(
env_PEP508_like.get(),
{"subgraph_info": ["ops", "data", "relationships"]},
)
os.environ[env_name] = (
"subgraph_info[ops, data, relationships], breakgraph_reason[inlinecall, others]"
)
self.assertEqual(
env_PEP508_like.get(),
{
"subgraph_info": ["ops", "data", "relationships"],
"breakgraph_reason": ["inlinecall", "others"],
},
)
os.environ[env_name] = "subgraph_info[ops, [[[[[[[[]], relationships], "
self.assertEqual(
env_PEP508_like.get(),
{
"subgraph_info": ["ops", "[[[[[[[[]]", "relationships"],
},
)
os.environ[env_name] = "subgraph_info[ops, , , relationships], "
self.assertEqual(
env_PEP508_like.get(),
{
"subgraph_info": ["ops", "relationships"],
},
)
def test_PEP508_like_env_set(self):
env_name = "___TEST_ENV_PEP508LikeDict_GET"
env_PEP508_like = PEP508LikeEnvironmentVariable(env_name, {})
env_PEP508_like.set(
{
"subgraph_info": ["ops", "data", "relationships"],
"breakgraph_reason": ["inlinecall", "others"],
}
)
self.assertEqual(
os.environ[env_name],
"subgraph_info[ops,data,relationships],breakgraph_reason[inlinecall,others]",
)
env_PEP508_like.set({"subgraph_info": []})
self.assertEqual(os.environ[env_name], "subgraph_info")
env_PEP508_like.set({})
self.assertEqual(
os.environ[env_name],
"",
)
if __name__ == "__main__":
unittest.main()
+40
View File
@@ -0,0 +1,40 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
from paddle.jit import sot
from paddle.jit.sot.utils import strict_mode_guard
def fn_with_try_except():
sot.psdb.breakgraph()
sot.psdb.fallback()
try:
raise ValueError("ValueError")
except ValueError:
print("catch ValueError")
return True
class TestErrorHandling(TestCaseBase):
@strict_mode_guard(False)
def test_fn_with_try_except(self):
self.assert_results(fn_with_try_except)
if __name__ == "__main__":
unittest.main()
+65
View File
@@ -0,0 +1,65 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot import symbolic_translate
from paddle.static import BuildStrategy
def func(x, y):
ret = 2 * x
ret = paddle.nn.functional.relu(ret)
ret = ret + y
return ret
def simple(x):
ret = 2 * x
return ret
class TestExecutionBase(TestCaseBase):
def test_simple(self):
x = paddle.to_tensor([1.0])
y = paddle.to_tensor([2.0])
self.assert_results(simple, x)
self.assert_results(simple, y)
def foo(x):
out = x + 1
out = out * 2
out = paddle.nn.functional.relu(out)
return out
class TestBackend(TestCaseBase):
def test_backend(self):
x = paddle.randn([2, 3])
dy_out = foo(x)
# TODO(SigureMo): Find a better way to test the CINN backend.
if not paddle.is_compiled_with_cinn():
return
sot_out = symbolic_translate(
foo, build_strategy=BuildStrategy(), backend='CINN'
)(x)
self.assert_nest_match(dy_out, sot_out)
if __name__ == "__main__":
unittest.main()
+279
View File
@@ -0,0 +1,279 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from collections import OrderedDict
import numpy as np
import paddle
class TestBasicFasterGuard(unittest.TestCase):
def test_lambda_guard(self):
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
self.assertTrue(guard_lambda.check(1))
self.assertFalse(guard_lambda.check(2))
def test_type_match_guard(self):
guard_int = paddle.framework.core.TypeMatchGuard(int)
guard_str = paddle.framework.core.TypeMatchGuard(str)
guard_list = paddle.framework.core.TypeMatchGuard(list)
self.assertTrue(guard_int.check(1))
self.assertFalse(guard_int.check("1"))
self.assertTrue(guard_str.check("1"))
self.assertFalse(guard_str.check(1))
self.assertTrue(guard_list.check([1]))
self.assertFalse(guard_list.check(1))
def test_isinstance_match_guard(self):
guard_int = paddle.framework.core.InstanceCheckGuard(int)
guard_str = paddle.framework.core.InstanceCheckGuard(str)
guard_list = paddle.framework.core.InstanceCheckGuard(list)
guard_int_bool = paddle.framework.core.InstanceCheckGuard((int, bool))
guard_int_str = paddle.framework.core.InstanceCheckGuard((int, str))
self.assertTrue(guard_int.check(1))
self.assertFalse(guard_int.check("1"))
self.assertTrue(guard_str.check("1"))
self.assertFalse(guard_str.check(1))
self.assertTrue(guard_list.check([1]))
self.assertFalse(guard_list.check(1))
self.assertTrue(guard_int_bool.check(1))
self.assertTrue(guard_int_bool.check(True))
self.assertFalse(guard_int_bool.check("1"))
self.assertTrue(guard_int_str.check(1))
self.assertTrue(guard_int_str.check("1"))
self.assertTrue(guard_int_str.check(True))
self.assertFalse(guard_int_str.check([1]))
def test_value_match_guard(self):
guard_value = paddle.framework.core.ValueMatchGuard(1)
guard_container_value = paddle.framework.core.ValueMatchGuard([1])
self.assertTrue(guard_value.check(1))
self.assertFalse(guard_value.check(2))
self.assertTrue(guard_container_value.check([1]))
self.assertFalse(guard_container_value.check([2]))
def test_length_match_guard(self):
guard_length = paddle.framework.core.LengthMatchGuard(1)
# list
self.assertTrue(guard_length.check([1]))
self.assertFalse(guard_length.check([1, 2]))
# dict
order_dict = OrderedDict()
order_dict[1] = 2
self.assertTrue(guard_length.check(order_dict))
self.assertTrue(guard_length.check({1: 2}))
# tuple
self.assertTrue(guard_length.check((1,)))
self.assertFalse(guard_length.check((1, 2)))
def test_dtype_match_guard(self):
guard_dtype = paddle.framework.core.DtypeMatchGuard(paddle.int32)
self.assertTrue(
guard_dtype.check(paddle.to_tensor(1, dtype=paddle.int32))
)
self.assertFalse(
guard_dtype.check(paddle.to_tensor(1, dtype=paddle.float32))
)
def test_shape_match_guard(self):
tensor = paddle.randn([2, 3])
guard_shape = paddle.framework.core.ShapeMatchGuard([2, 3], 0)
self.assertTrue(guard_shape.check(tensor))
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 0)
self.assertTrue(guard_shape.check(tensor))
guard_shape = paddle.framework.core.ShapeMatchGuard([3, 2], 0)
self.assertFalse(guard_shape.check(tensor))
guard_shape = paddle.framework.core.ShapeMatchGuard([2, 3, 1], 0)
self.assertFalse(guard_shape.check(tensor))
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 2)
self.assertTrue(guard_shape.check(paddle.randn([2, 2])))
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 2)
self.assertFalse(guard_shape.check(paddle.randn([2, 1])))
def test_attribute_match_guard(self):
a = range(1, 10, 2)
guard_attribute = paddle.framework.core.AttributeMatchGuard(a, "start")
self.assertTrue(guard_attribute.check(a))
self.assertFalse(guard_attribute.check(range(10)))
def test_layer_match_guard(self):
layer = paddle.nn.Linear(10, 10)
guard_layer = paddle.framework.core.LayerMatchGuard(layer)
self.assertTrue(guard_layer.check(layer))
self.assertFalse(guard_layer.check(paddle.nn.Linear(10, 10)))
layer.eval()
self.assertFalse(guard_layer.check(layer))
layer.train()
self.assertTrue(guard_layer.check(layer))
def test_id_match_guard(self):
layer = paddle.nn.Linear(10, 10)
guard_id = paddle.framework.core.IdMatchGuard(layer)
self.assertTrue(guard_id.check(layer))
layer.eval()
self.assertTrue(guard_id.check(layer))
self.assertFalse(guard_id.check(paddle.nn.Linear(10, 10)))
def test_numpy_dtype_match_guard(self):
np_array = np.array(1, dtype=np.int32)
guard_numpy_dtype = paddle.framework.core.NumPyDtypeMatchGuard(
np_array.dtype
)
self.assertTrue(guard_numpy_dtype.check(np_array))
self.assertTrue(guard_numpy_dtype.check(np.array(1, dtype=np.int32)))
self.assertTrue(guard_numpy_dtype.check(np.int32()))
self.assertFalse(guard_numpy_dtype.check(np.array(1, dtype=np.int64)))
self.assertFalse(guard_numpy_dtype.check(np.float32()))
self.assertFalse(guard_numpy_dtype.check(np.bool_()))
np_bool = np.bool_(1)
guard_numpy_bool_dtype = paddle.framework.core.NumPyDtypeMatchGuard(
np_bool.dtype
)
self.assertTrue(guard_numpy_bool_dtype.check(np.bool_()))
self.assertTrue(
guard_numpy_bool_dtype.check(np.array(1, dtype=np.bool_))
)
def test_numpu_array_shape_match_guard(self):
np_array = np.array([1, 2])
guard_numpy_array_shape = (
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
)
self.assertTrue(guard_numpy_array_shape.check(np_array))
self.assertTrue(
guard_numpy_array_shape.check(np.array([1, 2], dtype=np.int32))
)
self.assertTrue(guard_numpy_array_shape.check(np.array([3, 4])))
self.assertTrue(
guard_numpy_array_shape.check(np.array([3, 4], dtype=np.float32))
)
self.assertFalse(guard_numpy_array_shape.check(np.array([[1], [2]])))
self.assertFalse(guard_numpy_array_shape.check(np.array([1, 2, 3])))
np_array = np.array([1, None])
guard_numpy_array_shape = (
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
)
self.assertTrue(guard_numpy_array_shape.check(np_array))
self.assertTrue(guard_numpy_array_shape.check(np.array([2, 3])))
self.assertFalse(guard_numpy_array_shape.check(np.array([2, 3, 4])))
np_array = np.array(1)
guard_numpy_array_shape = (
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
)
self.assertTrue(guard_numpy_array_shape.check(np_array))
self.assertTrue(
guard_numpy_array_shape.check(np.array(2, dtype=np.int32))
)
self.assertTrue(
guard_numpy_array_shape.check(np.array(3, dtype=np.float32))
)
self.assertFalse(guard_numpy_array_shape.check(np.array([1])))
def test_numpy_array_match_guard(self):
np_array = paddle.framework.core.NumPyArrayValueMatchGuard(
np.array([1, 2, 3])
)
self.assertTrue(np_array.check(np.array([1, 2, 3])))
self.assertFalse(np_array.check(np.array([4, 5, 6])))
np_array_all_one = paddle.framework.core.NumPyArrayValueMatchGuard(
np.array([1, 1, 1])
)
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1])))
self.assertFalse(np_array_all_one.check(np.array([1, 2, 3])))
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1], dtype=bool)))
self.assertTrue(np_array_all_one.check(np.array([True, True, True])))
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1], dtype=int)))
np_bool_array = paddle.framework.core.NumPyArrayValueMatchGuard(
np.array([True, False, True])
)
self.assertTrue(np_bool_array.check(np.array([True, False, True])))
self.assertFalse(np_bool_array.check(np.array([True, True, True])))
self.assertFalse(np_bool_array.check(np.array([False, False, False])))
self.assertFalse(np_bool_array.check(np.array([1, 2, 3])))
self.assertTrue(np_bool_array.check(np.array([True, False, 1])))
self.assertFalse(np_bool_array.check(np.array([1, 2, 3], dtype=bool)))
self.assertFalse(np_bool_array.check(np.array([1, 2, 3], dtype=int)))
np_bool_array_all_true = (
paddle.framework.core.NumPyArrayValueMatchGuard(
np.array([True, True, True])
)
)
self.assertTrue(
np_bool_array_all_true.check(np.array([True, True, True]))
)
self.assertFalse(
np_bool_array_all_true.check(np.array([True, False, True]))
)
self.assertFalse(
np_bool_array_all_true.check(np.array([False, False, False]))
)
self.assertFalse(np_bool_array_all_true.check(np.array([1, 2, 3])))
self.assertTrue(np_bool_array_all_true.check(np.array([True, True, 1])))
def test_object_match_guard(self):
def test_func():
return 1 + 1
guard_object = paddle.framework.core.WeakRefMatchGuard(test_func)
self.assertTrue(guard_object.check(test_func))
self.assertFalse(guard_object.check(lambda x: x == 1))
self.assertFalse(guard_object.check(1))
self.assertFalse(guard_object.check("1"))
def test_is_dense_tensor_hold_allocation(self):
tensor = paddle.to_tensor([1, 2, 3])
guard = paddle.framework.core.IsNotDenseTensorHoldAllocationMatchGuard()
self.assertEqual(
guard.check(tensor), not tensor._is_dense_tensor_hold_allocation()
)
class TestFasterGuardGroup(unittest.TestCase):
def test_guard_group(self):
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
guard_type_match = paddle.framework.core.TypeMatchGuard(int)
guard_group = paddle.framework.core.GuardGroup(
[guard_type_match, guard_lambda] * 10
)
self.assertTrue(guard_group.check(1))
self.assertFalse(guard_group.check(2))
def test_nested_guard_group(self):
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
guard_type_match = paddle.framework.core.TypeMatchGuard(int)
guard_group = paddle.framework.core.GuardGroup(
[guard_type_match, guard_lambda]
)
for _ in range(10):
guard_group = paddle.framework.core.GuardGroup(
[guard_group, guard_type_match, guard_lambda]
)
self.assertTrue(guard_group.check(1))
self.assertFalse(guard_group.check(2))
if __name__ == "__main__":
unittest.main()
+63
View File
@@ -0,0 +1,63 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import random
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot import symbolic_translate
def fn_randint(x):
x = x + 1
x = x + random.randint(0, 100)
x = x + 2
return x
def fn_random(x):
x = x + 3
x = x + random.random()
x = x + 4
return x
class TestRandom(TestCaseBase):
def test_random_randint(self):
x = paddle.to_tensor(2024)
random.seed(2025)
sym_output = symbolic_translate(fn_randint)(x)
random.seed(2025)
paddle_output = fn_randint(x)
self.assertEqual(sym_output, paddle_output)
def test_random_random(self):
x = paddle.to_tensor(2025)
random.seed(2025)
sym_output = symbolic_translate(fn_random)(x)
random.seed(2025)
paddle_output = fn_random(x)
self.assertEqual(sym_output, paddle_output)
if __name__ == "__main__":
unittest.main()
+77
View File
@@ -0,0 +1,77 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit import sot
class EmbeddingLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.embedding = paddle.nn.Embedding(10, 10)
def forward(self, x):
x = x + 1 - 1
x = self.embedding(x)
return x + 1
def call_embedding_layer(x: paddle.Tensor, layer: paddle.nn.Layer):
return layer(x)
def call_functional_embedding(x: paddle.Tensor, weight: paddle.Tensor):
x = x + 1 - 1
x = paddle.nn.functional.embedding(x, weight)
return x + 1
class TestForceDynamic(TestCaseBase):
def test_embedding_layer(self):
paddle.jit.marker.force_dynamic(paddle.nn.Embedding)
layer = EmbeddingLayer()
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(
call_embedding_layer,
paddle.randint(0, 10, [1, 3, 224, 224], dtype='int64'),
layer,
)
self.assertGreater(ctx.translate_count, 1)
sot.utils.paddle_api_config.break_graph_layer_classes.clear()
def test_functional_embedding(self):
paddle.jit.marker.force_dynamic(paddle.nn.functional.embedding)
weight = paddle.randn([10, 10])
x = paddle.randint(0, 10, [1, 3, 224, 224], dtype='int64')
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(call_functional_embedding, x, weight)
self.assertGreater(ctx.translate_count, 1)
sot.utils.paddle_api_config.break_graph_functions.clear()
if __name__ == "__main__":
unittest.main()
+171
View File
@@ -0,0 +1,171 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import operator
import unittest
from test_case_base import (
TestCaseBase,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils.exceptions import InnerError
@functools.lru_cache
def fn_with_cache(x):
return x + 1
@check_no_breakgraph
def fn_with_lru_cache(x: paddle.Tensor):
a1 = fn_with_cache(1)
b1 = fn_with_cache(x)
b2 = fn_with_cache(x)
a2 = fn_with_cache(1)
c1 = fn_with_cache(2)
c2 = fn_with_cache(2)
return a1, a2, b1, b2, c1, c2
@check_no_breakgraph
def try_reduce(fn, var, init=None):
if init:
ans = functools.reduce(fn, var, init)
else:
ans = functools.reduce(fn, var)
return ans
@check_no_breakgraph
def try_reduce_iter(fn, var, init=None):
ans = functools.reduce(fn, iter(var))
return ans
def add(a, b, c, d=2, e=3, f=4):
return a, b, c, d, e, f
@check_no_breakgraph
def simple_partial(x=1):
partial_func = functools.partial(add, x)
out = partial_func(2, 3)
return out
@check_no_breakgraph
def simple_partial_with_two_args(x=1):
partial_func = functools.partial(add, x, 2)
out = partial_func(3)
return out
@check_no_breakgraph
def simple_partial_with_n_args(x=1):
partial_func = functools.partial(add, x, 2, 3, 4, 5, 6)
out = partial_func()
return out
@check_no_breakgraph
def simple_partial_with_n_args_kwargs():
partial_func = functools.partial(add, 1, 2, d=2)
out = partial_func(paddle.to_tensor(3), e=7)
return out
@check_no_breakgraph
def simple_partial_with_n_args_same_kwargs():
partial_func = functools.partial(add, 1, 2, e=2)
out = partial_func(3, e=7)
return out
# NOTE(DrRyanHuang): Currently, SOT does not support tensor bind yet
# because this case is not common enough.
# We could create a PartialClassVariable to prevent breakgraph.
def simple_partial_with_tensor_bind():
partial_func = functools.partial(add, 1, paddle.to_tensor(2.0), e=2)
out = partial_func(3, e=7)
return out
@check_no_breakgraph
def try_reduce_iter_failed(fn, var):
it = iter(var)
for _ in it:
pass
ans = functools.reduce(fn, it)
return ans
class TestFunctools(TestCaseBase):
def test_lru_cache(self):
x = paddle.rand([2, 3, 4])
self.assert_results(fn_with_lru_cache, x)
def test_reduce_list(self):
self.assert_results(try_reduce, lambda acc, x: acc + x, [1, 3, 4])
def test_reduce_dict(self):
d1 = {"a": 1, "b": 2}
d2 = {"a": 3, "c": 4}
self.assert_results(try_reduce, lambda a, b: {**a, **b}, [d1, d2])
def test_reduce_tuple(self):
self.assert_results(try_reduce, lambda acc, x: acc * x, (1, 3, 4))
def test_reduce_iter(self):
f = lambda acc, x: acc + x
l = [1, 2, 3]
self.assert_results(try_reduce_iter, f, l)
self.assert_exceptions(
InnerError,
r".*reduce\(\) of empty iterable with no initial value.*",
try_reduce_iter_failed,
f,
l,
)
def test_reduce_with_init_value(self):
self.assert_results(try_reduce, lambda acc, x: acc + x, [1, 3, 4], -2)
def test_reduce_with_builtin_fn(self):
self.assert_results(try_reduce, operator.add, [2, 5, 8])
def test_simple_partial(self):
self.assert_results(simple_partial, 1)
self.assert_results(simple_partial, 2)
def test_simple_partial_with_two_argsn(self):
self.assert_results(simple_partial_with_two_args)
def test_simple_partial_with_n_args(self):
self.assert_results(simple_partial_with_n_args)
def test_simple_partial_with_n_args_kwargs(self):
self.assert_results(simple_partial_with_n_args_kwargs)
def test_simple_partial_with_n_args_same_kwargs(self):
self.assert_results(simple_partial_with_n_args_same_kwargs)
def test_simple_partial_with_tensor_bind(self):
self.assert_results(simple_partial_with_tensor_bind)
if __name__ == "__main__":
unittest.main()
+97
View File
@@ -0,0 +1,97 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
)
import paddle
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
OpcodeExecutorCache,
)
from paddle.jit.sot.utils import ENV_SOT_UNSAFE_CACHE_FASTPATH
from paddle.utils.environments import (
EnvironmentVariableGuard,
)
def add(x, y):
return x + y
def subtract(x, y):
return x - y
class TestUnsafeCacheFastPath(TestCaseBase):
def test_guard(self):
# NOTE: When UNSAFE CACHE FASTPATH is enabled, if the same cache entry is hit consecutively
# for 32 times (this threshold is configurable), the cache is considered stable and
# subsequent guard checks will be skipped to improve performance.
# The related logic is implemented in the OpcodeExecutorCache class.
with EnvironmentVariableGuard(ENV_SOT_UNSAFE_CACHE_FASTPATH, True):
self.assertTrue(ENV_SOT_UNSAFE_CACHE_FASTPATH.get())
self.assertFalse(
OpcodeExecutorCache().is_fastpath_threshold_reached(
add.__code__
)
)
# The test needs to consider the issue of dynamic shapes: when the input shape changes,
# the previous cache may become invalid.
self.assert_results(add, 1, paddle.ones([32, 4]))
for _ in range(34):
self.assert_results(add, 1, paddle.ones([4]))
self.assertTrue(
OpcodeExecutorCache().is_fastpath_threshold_reached(
add.__code__
)
)
# NOTE: Once fastpath is enabled, the cache will not be rebuilt even if the shape changes again afterwards.
# This is the "UNSAFE" aspect of the environment variable `ENV_SOT_UNSAFE_CACHE_FASTPATH`.
self.assert_results(add, 1, paddle.ones([31, 4]))
self.assertTrue(
OpcodeExecutorCache().is_fastpath_threshold_reached(
add.__code__
)
)
self.assertFalse(
OpcodeExecutorCache().is_fastpath_threshold_reached(
subtract.__code__
)
)
with EnvironmentVariableGuard(ENV_SOT_UNSAFE_CACHE_FASTPATH, False):
self.assertFalse(ENV_SOT_UNSAFE_CACHE_FASTPATH.get())
self.assertFalse(
OpcodeExecutorCache().is_fastpath_threshold_reached(
subtract.__code__
)
)
for _ in range(35):
self.assert_results(add, 1, 2)
self.assertFalse(
OpcodeExecutorCache().is_fastpath_threshold_reached(
subtract.__code__
)
)
if __name__ == '__main__':
unittest.main()
+43
View File
@@ -0,0 +1,43 @@
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
class TestGuardIsGradEnabled(TestCaseBase):
def test_switch_is_grad_enabled(self):
def fn(x):
return x + 1
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
with paddle.no_grad():
self.assert_results(fn, 1)
self.assertEqual(ctx.translate_count, 1)
with paddle.enable_grad():
self.assert_results(fn, 1)
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+78
View File
@@ -0,0 +1,78 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
def non_operator_related_fn(x: int, y: int):
return x + y
def partial_non_operator_related_fn(x: paddle.Tensor, y: paddle.Tensor, z: int):
a = x + y
return [a, z + z]
def guard_inputs(x: int, y: int, z: int):
return x + y + z
class TestGuardOutputs(TestCaseBase):
def test_non_operator_related_fn(self):
with test_instruction_translator_cache_context() as ctx:
self.assert_results(non_operator_related_fn, 1, 2)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(non_operator_related_fn, 3, 4)
self.assertEqual(ctx.translate_count, 2)
def test_partial_non_operator_related_fn(self):
with test_instruction_translator_cache_context() as ctx:
self.assert_results(
partial_non_operator_related_fn,
paddle.to_tensor(1),
paddle.to_tensor(2),
3,
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
partial_non_operator_related_fn,
paddle.to_tensor(4),
paddle.to_tensor(5),
6,
)
self.assertEqual(ctx.translate_count, 2)
def test_guard_inputs(self):
with test_instruction_translator_cache_context() as ctx:
self.assert_results(guard_inputs, 1, 2, 3)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(guard_inputs, 0, 2, 3)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(guard_inputs, 1, 0, 3)
self.assertEqual(ctx.translate_count, 3)
self.assert_results(guard_inputs, 1, 2, 0)
self.assertEqual(ctx.translate_count, 4)
if __name__ == "__main__":
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from typing import TYPE_CHECKING
import paddle
from paddle.jit.sot.opcode_translator.custom_code import CustomCode
if TYPE_CHECKING:
import types
from collections.abc import Callable
z = paddle.to_tensor(1)
def guard_tree(
callback: Callable[[types.FrameType], CustomCode],
):
def foo(x, y):
return x, y, z
def inner(x, y):
paddle.framework.core.set_eval_frame(callback)
try:
return foo(x, y)
finally:
paddle.framework.core.set_eval_frame(None)
return inner
class TestGuardTree(unittest.TestCase):
def test_guard_tree(self):
def callback(frame, **kwargs):
guard_int = paddle.framework.core.TypeMatchGuard(int)
guard_tensor = paddle.framework.core.TypeMatchGuard(
type(paddle.to_tensor(1))
)
guard_tensor_shape_eq = paddle.framework.core.ValueMatchGuard(
paddle.to_tensor([1]).shape
)
guard_eq = paddle.framework.core.ValueMatchGuard(1)
node_expr_x = paddle.framework.core.LocalVarExprNode("x")
node_expr_y = paddle.framework.core.LocalVarExprNode("y")
node_expr_z = paddle.framework.core.GlobalVarExprNode("z")
node_expr_y_shape = paddle.framework.core.AttributeExprNode(
node_expr_y, "shape"
)
node_expr_const_1 = paddle.framework.core.ConstantExprNode(1)
node_guard_x_type_match_int = paddle.framework.core.GuardNode(
guard_int, [node_expr_x]
)
node_guard_x_eq_1 = paddle.framework.core.GuardNode(
guard_eq, [node_expr_x]
)
node_guard_y_type_match_int = paddle.framework.core.GuardNode(
guard_int, [node_expr_y]
)
node_guard_y_type_match_tensor = paddle.framework.core.GuardNode(
guard_tensor, [node_expr_y]
)
node_guard_y_tensor_shape = paddle.framework.core.GuardNode(
guard_tensor_shape_eq, [node_expr_y_shape]
)
node_guard_z_type_match_tensor = paddle.framework.core.GuardNode(
guard_tensor, [node_expr_z]
)
node_guard_1_eq_1 = paddle.framework.core.GuardNode(
guard_eq, [node_expr_const_1]
)
guard_tree = paddle.framework.core.GuardTree(
[
[node_guard_x_eq_1],
[node_guard_x_type_match_int, node_guard_y_type_match_int],
[
node_guard_x_type_match_int,
node_guard_y_type_match_tensor,
node_guard_y_tensor_shape,
],
[node_guard_z_type_match_tensor],
[node_guard_1_eq_1],
]
)
self.assertEqual(guard_tree.lookup(frame), target)
return CustomCode(frame.f_code, False)
global z
foo = guard_tree(callback)
target = 0
foo(1, 1)
target = 1
foo(2, 2)
target = 2
foo(2, paddle.to_tensor([2]))
target = 3
foo(2, 1.0)
z = 1
target = 4
foo(2, 1.0)
if __name__ == "__main__":
unittest.main()
+88
View File
@@ -0,0 +1,88 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
def test_guard_fn(fn, inp):
if fn is None:
return 0
else:
return fn(inp)
class TestGuardOutputs(TestCaseBase):
def test_non_operator_related_fn(self):
with test_instruction_translator_cache_context() as ctx:
self.assert_results(
test_guard_fn,
paddle.nn.functional.relu,
paddle.to_tensor([1.0, -1.0]),
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
test_guard_fn,
paddle.nn.functional.gelu,
paddle.to_tensor([1.0, -1.0]),
)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(
test_guard_fn,
paddle.nn.functional.relu,
paddle.to_tensor([-1.0, -1.0]),
)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(
test_guard_fn, None, paddle.to_tensor([-1.0, -1.0])
)
self.assertEqual(ctx.translate_count, 3)
deleted_cnt = 0
class Callable:
def __call__(self, var):
return paddle.nn.functional.relu(var)
def __del__(self):
nonlocal deleted_cnt
deleted_cnt += 1
fn1 = Callable()
fn2 = Callable()
with test_instruction_translator_cache_context() as ctx:
self.assert_results(
test_guard_fn, fn1, paddle.to_tensor([1.0, -1.0])
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
test_guard_fn, fn2, paddle.to_tensor([1.0, -1.0])
)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(
test_guard_fn, fn2, paddle.to_tensor([1.0, -1.0])
)
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+121
View File
@@ -0,0 +1,121 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import random
import string
import unittest
from test_case_base import TestCaseBase
from paddle.jit.sot.utils.exceptions import (
BuiltinFunctionBreak,
DataDependencyControlFlowBreak,
DataDependencyDynamicShapeBreak,
DataDependencyOperationBreak,
DygraphInconsistentWithStaticBreak,
FallbackInlineCallBreak,
InferMetaBreak,
InlineCallBreak,
OtherInlineCallBreak,
PsdbBreakReason,
SideEffectBreak,
UnsupportedIteratorBreak,
UnsupportedPaddleAPIBreak,
)
from paddle.jit.sot.utils.info_collector import (
BreakGraphReasonInfo,
InfoBase,
SubGraphInfo,
)
generate_random_string = lambda N: ''.join(
random.choices(string.ascii_uppercase + string.digits, k=N)
)
class TestSerialize(TestCaseBase):
def test_case(self):
x_dict = {
'a': 'b',
'c': 'd',
}
x_str = InfoBase.serialize(x_dict)
y_dict = InfoBase.deserialize(x_str)
self.assertEqual(x_dict, y_dict)
class TestBreakGraphReasonInfo(TestCaseBase):
def test_case(self):
history = [
BreakGraphReasonInfo(
BreakReasonClass(
reason_str=generate_random_string(random.randint(1, 5))
)
)
for BreakReasonClass in [
FallbackInlineCallBreak,
DataDependencyControlFlowBreak,
DataDependencyDynamicShapeBreak,
DataDependencyOperationBreak,
UnsupportedPaddleAPIBreak,
BuiltinFunctionBreak,
SideEffectBreak,
UnsupportedIteratorBreak,
InlineCallBreak,
OtherInlineCallBreak,
DygraphInconsistentWithStaticBreak,
PsdbBreakReason,
InferMetaBreak,
]
]
serialized = BreakGraphReasonInfo.json_report(history)
deserialized = BreakGraphReasonInfo.restore_from_string(
serialized.removeprefix("<sot>").removesuffix("</sot>")
)
origin_reasons_dict, _ = BreakGraphReasonInfo.classify(history)
origin_reasons2count = {
k: len(v) for k, v in origin_reasons_dict.items()
}
new_reasons_dict, _ = BreakGraphReasonInfo.classify(deserialized)
new_reasons2count = {k: len(v) for k, v in new_reasons_dict.items()}
self.assertEqual(origin_reasons2count, new_reasons2count)
class TestSubGraphInfo(TestCaseBase):
def test_case(self):
history = [
SubGraphInfo(
generate_random_string(random.randint(1, 5)),
random.randint(0, 20),
generate_random_string(random.randint(1, 5)),
),
] * 10
serialized = SubGraphInfo.json_report(history)
deserialized = SubGraphInfo.restore_from_string(
serialized.removeprefix("<sot>").removesuffix("</sot>")
)
self.assertEqual(history, deserialized)
if __name__ == "__main__":
unittest.main()
+149
View File
@@ -0,0 +1,149 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.utils import strict_mode_guard
def simple(x, y):
x[0] = 3.0
z = [y]
y[1] = 5.0
return x[0] + x[1] + z[0][1] + y[0] + y[1]
def inplace_in_if(x, y, z):
if z:
x[0] = 3.0
z = [y]
y[1] = 5.0
ret = x[0] + x[1] + z[0][1] + y[0] + y[1]
return ret
else:
return None
def inplace_in_if_fallback(x, y, z):
if z > 0:
x[0] = 3.0
z = [y]
y[1] = 5.0
ret = x[0] + x[1] + z[0][1] + y[0] + y[1]
return ret
else:
return None
def inplace_in_loop(x, y):
ret = 0
for i in range(10):
x[0] = 1
z = [y]
y[1] = 2 * i + 1
ret += x[0] + x[1] + z[0][1] + y[0] + y[1]
return ret
def inplace_in_loop_fallback(x, y, it):
ret = 0
for i in it:
x[0] = 1
z = [y]
y[1] = 2 * i + 1
ret += x[0] + x[1] + z[0][1] + y[0] + y[1]
return ret
def inplace_case_0(x):
x[:] = 1.0
return x
def inplace_case_1(x):
x[0][0, 0::2] = 1.0
return x
def inplace_case_2(x):
t = x[0]
t[:, 0::2] = t[:, 0::2] * 0
t[:, 1::2] = t[:, 1::2] + 2
return x
class TestInplaceApi(TestCaseBase):
def test_case(self):
self.assert_results(inplace_case_0, paddle.randn((1, 4)))
self.assert_results(inplace_case_1, [paddle.randn((1, 4))])
self.assert_results(inplace_case_2, [paddle.randn((1, 4))])
def test_backward(self):
@symbolic_translate
def func(x):
m = x * 2
n = x * 3
y = m
y[:] = n
return y
x = paddle.ones((1, 4)) * 4
x.stop_gradient = False
y = func(x)
y.sum().backward()
assert (x.grad.numpy() == 3).all()
def test_simple(self):
self.assert_results(
simple, paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0])
)
def test_if(self):
self.assert_results(
inplace_in_if,
paddle.to_tensor([1.0, 2.0]),
paddle.to_tensor([3.0, 4.0]),
True,
)
self.assert_results(
inplace_in_if_fallback,
paddle.to_tensor([1.0, 2.0]),
paddle.to_tensor([3.0, 4.0]),
paddle.to_tensor(1),
)
@strict_mode_guard(False)
def test_loop(self):
self.assert_results(
inplace_in_loop,
paddle.to_tensor([1.0, 2.0]),
paddle.to_tensor([3.0, 4.0]),
)
a = range(10)
sym_output = symbolic_translate(inplace_in_loop_fallback)(
paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0]), iter(a)
)
paddle_output = inplace_in_loop_fallback(
paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0]), iter(a)
)
self.assert_nest_match(sym_output, paddle_output)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,188 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import inspect
import random
import unittest
from typing import TYPE_CHECKING
from unittest.mock import patch
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.opcode_translator.custom_code import CustomCode
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
OpcodeExecutorCache,
)
if TYPE_CHECKING:
from types import FrameType
def fake_frames() -> tuple[
FrameType,
FrameType,
FrameType,
FrameType,
FrameType,
]:
def fake_inner_fn_1():
frame = inspect.currentframe()
assert frame is not None
return frame
def fake_inner_fn_2():
frame = inspect.currentframe()
assert frame is not None
return frame
def fake_inner_fn_3():
frame = inspect.currentframe()
assert frame is not None
return frame
def fake_inner_fn_4():
frame = inspect.currentframe()
assert frame is not None
return frame
def fake_inner_fn_5():
frame = inspect.currentframe()
assert frame is not None
return frame
return (
fake_inner_fn_1(),
fake_inner_fn_2(),
fake_inner_fn_3(),
fake_inner_fn_4(),
fake_inner_fn_5(),
)
(
FRAME_1,
FRAME_2,
FRAME_3,
FRAME_4,
FRAME_5,
) = fake_frames()
class GuardCode:
def __init__(self, recompile):
self.func = lambda frame: recompile
self.mirror_guard = self.func
self.expr = f"lambda frame: {recompile}"
self.inlined_expr = f"lambda frame: {recompile}"
self.__globals__ = {}
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def mock_start_translate(frame: FrameType, **kwargs):
translate_map = {
FRAME_1: (
CustomCode(FRAME_2.f_code, False),
GuardCode(True),
[paddle.framework.core.DummyGuardNode()],
),
FRAME_3: (
CustomCode(FRAME_4.f_code, False),
GuardCode(False),
[paddle.framework.core.DummyGuardNode(False)],
), # Always re-compile
FRAME_5: (
CustomCode(None, False),
lambda frame: True,
[paddle.framework.core.DummyGuardNode()],
),
}
return translate_map[frame]
class TestOpcodeExecutorCache(unittest.TestCase):
def reset(self):
global translate_count
translate_count = 0
OpcodeExecutorCache().clear()
@patch(
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
mock_start_translate,
)
def test_cache_hit(self):
with test_instruction_translator_cache_context() as ctx:
translated_code_1 = OpcodeExecutorCache()(FRAME_1)
assert translated_code_1 is not None
self.assertEqual(translated_code_1.code, FRAME_2.f_code)
self.assertEqual(ctx.translate_count, 1)
# cache hit
translated_code_2 = OpcodeExecutorCache()(FRAME_1)
assert translated_code_2 is not None
self.assertEqual(translated_code_2.code, FRAME_2.f_code)
self.assertEqual(ctx.translate_count, 1)
@patch(
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
mock_start_translate,
)
def test_cache_miss_due_to_unknown_code(self):
with test_instruction_translator_cache_context() as ctx:
translated_code_1 = OpcodeExecutorCache()(FRAME_1)
assert translated_code_1 is not None
self.assertEqual(translated_code_1.code, FRAME_2.f_code)
self.assertEqual(ctx.translate_count, 1)
# cache miss
translated_code_2 = OpcodeExecutorCache()(FRAME_3)
assert translated_code_2 is not None
self.assertEqual(translated_code_2.code, FRAME_4.f_code)
self.assertEqual(ctx.translate_count, 2)
@patch(
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
mock_start_translate,
)
def test_cache_miss_due_to_check_failed(self):
with test_instruction_translator_cache_context() as ctx:
translated_code_1 = OpcodeExecutorCache()(FRAME_3)
assert translated_code_1 is not None
self.assertEqual(translated_code_1.code, FRAME_4.f_code)
self.assertEqual(ctx.translate_count, 1)
# cache miss
translated_code_2 = OpcodeExecutorCache()(FRAME_3)
assert translated_code_2 is not None
self.assertEqual(translated_code_2.code, FRAME_4.f_code)
self.assertEqual(ctx.translate_count, 2)
def foo(x):
return x + 1
class TestCacheExceedLimit(TestCaseBase):
def test_cache_exceed_limit(self):
for _ in range(30):
input = random.random()
self.assert_results(foo, input)
if __name__ == '__main__':
unittest.main()
+104
View File
@@ -0,0 +1,104 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
class ListIterable:
def __init__(self):
self._list = [1, 2, 3]
def __iter__(self):
return iter(self._list)
@check_no_breakgraph
def list_iterable(x: paddle.Tensor):
iterable = ListIterable()
for i in iterable:
x += i
return x
class TupleIterable:
def __init__(self):
self._tuple = (1, 2, 3)
def __iter__(self):
return iter(self._tuple)
@check_no_breakgraph
def tuple_iterable(x: paddle.Tensor):
iterable = TupleIterable()
for i in iterable:
x += i
return x
class DictIterable:
def __init__(self):
self._dict = {0: 1, 1: 2, 2: 3}
def __iter__(self):
return iter(self._dict)
@check_no_breakgraph
def dict_iterable(x: paddle.Tensor):
iterable = DictIterable()
for i in iterable:
x += i
return x
class RangeIterable:
def __init__(self):
pass
def __iter__(self):
return iter(range(5))
@check_no_breakgraph
def range_iterable(x: paddle.Tensor):
iterable = RangeIterable()
for i in iterable:
x += i
return x
class TestIterable(TestCaseBase):
def test_list_iterable(self):
self.assert_results(list_iterable, paddle.to_tensor(0))
def test_tuple_iterable(self):
self.assert_results(tuple_iterable, paddle.to_tensor(0))
def test_dict_iterable(self):
self.assert_results(dict_iterable, paddle.to_tensor(0))
def test_range_iterable(self):
self.assert_results(range_iterable, paddle.to_tensor(0))
if __name__ == "__main__":
unittest.main()
+163
View File
@@ -0,0 +1,163 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit import sot
from paddle.jit.sot.utils import min_graph_size_guard, strict_mode_guard
def case_for(x, vars):
x = x + 1
sot.psdb.breakgraph()
for y in vars:
x += y
return x
def case_if(x):
x = x + 1
if x > 5:
x += 3
else:
x += 4
return x
def case_call(x):
y = paddle.to_tensor(x.numpy())
x += y
return x
def call_with_kwargs_inner(x):
return paddle.to_tensor(x.numpy())
def call_with_kwargs(x):
y = call_with_kwargs_inner(x=x)
x += y
return x
def case_all(x, vars):
x = x + 1
for y in vars:
z = paddle.to_tensor(x.numpy())
x += z
x += y
if x > 5:
x += y
else:
x += 3
return x
class CustomLayer(paddle.nn.Layer):
def forward(self, x):
return self.forward_features(x)
def forward_features(self, x):
return x.numpy()
def get_arg_from_kwargs(x, **kwargs):
x = x if x is not None else None
y = kwargs.get("y", None)
paddle.jit.sot.psdb.breakgraph()
return x, y
def add_with_breakgraph(x, y):
sot.psdb.breakgraph()
return x + y
def restore_same_arg_when_fallback(x):
return add_with_breakgraph(x, x)
def trim_trailing_to_bool(x, y):
return x and y
def always_use_load_fast_with_strong_ref(x):
y = x + 1
# In this case, originally y will be load with LOAD_FAST_BORROW
# When breakgraph, the y on the stack, it will be stored and loaded with LOAD_FAST
# But since y is not a strong ref, it may be GCed before loaded again
# We add a pass to make sure y is a strong ref, so it will not be GCed
# when loaded again.
_stack_ref = (y, paddle.jit.sot.psdb.breakgraph())
x = y + 1
return x
class TestMinGraphSize(TestCaseBase):
@strict_mode_guard(False)
@min_graph_size_guard(10)
def test_cases(self):
x = paddle.to_tensor(1)
self.assert_results(case_for, x, [1, 2, 3])
self.assert_results(case_if, x)
self.assert_results(case_call, x)
self.assert_results(case_all, x, [4, 5, 6])
@min_graph_size_guard(10)
def test_layer(self):
x = paddle.to_tensor(1)
layer = CustomLayer()
self.assert_results(layer.forward, x)
@min_graph_size_guard(10)
def test_layer_multiple_times(self):
x = paddle.to_tensor(1)
layer = CustomLayer()
for _ in range(8):
self.assert_results(layer.forward, x)
@min_graph_size_guard(10)
def test_call_with_kwargs(self):
x = paddle.to_tensor(1)
self.assert_results(call_with_kwargs, x)
@min_graph_size_guard(10)
def test_get_arg_from_kwargs(self):
self.assert_results(get_arg_from_kwargs, None)
self.assert_results(get_arg_from_kwargs, None, y=1)
@min_graph_size_guard(10)
def test_restore_same_arg_when_fallback(self):
x = paddle.to_tensor(1)
self.assert_results(restore_same_arg_when_fallback, x)
@min_graph_size_guard(10)
def test_trim_trailing_to_bool(self):
x = paddle.to_tensor(False)
y = paddle.to_tensor(False)
self.assert_results(trim_trailing_to_bool, x, y)
@min_graph_size_guard(10)
def test_always_use_load_fast_with_strong_ref(self):
x = paddle.to_tensor(1)
self.assert_results(always_use_load_fast_with_strong_ref, x)
if __name__ == "__main__":
unittest.main()
+82
View File
@@ -0,0 +1,82 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
import paddle
from paddle.jit.sot.symbolic.compile_cache import CompileSIRCache
class SimpleNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.dropout = paddle.nn.Dropout(p=0.5)
def forward(self, x):
if self.training:
out1 = paddle.nn.functional.dropout(x, p=0.5, training=True)
else:
out1 = paddle.nn.functional.dropout(x, p=0.5, training=False)
out1 = self.dropout(out1)
return out1
class TestModelSwitchTraining(unittest.TestCase):
def setUp(self):
self.seed = 1127
self.net = SimpleNet()
# singleton
self.compile_cache = CompileSIRCache()
def check_mode(self, is_train):
self.assertEqual(len(self.compile_cache.cache), 1)
mode = next(
iter(self.compile_cache.cache.values())
).partial_program.training
self.assertEqual(mode, is_train)
def get_dygraph_out(self, input):
paddle.seed(self.seed)
self.net.eval()
eval_result = self.net(input)
self.net.train()
train_result = self.net(input)
return eval_result, train_result
def get_static_out(self, input):
paddle.seed(self.seed)
self.compile_cache.clear()
static_net = paddle.jit.to_static(self.net, full_graph=False)
static_net.eval()
eval_result = static_net(input)
self.check_mode(is_train=False)
self.compile_cache.clear()
static_net.train()
train_result = static_net(input)
self.check_mode(is_train=True)
return eval_result, train_result
def test_model_switch_training(self):
input = paddle.rand((10, 10))
dygraph_eval, dygraph_train = self.get_dygraph_out(input)
static_eval, static_train = self.get_static_out(input)
np.testing.assert_allclose(dygraph_eval.numpy(), static_eval.numpy())
np.testing.assert_allclose(dygraph_train.numpy(), static_train.numpy())
if __name__ == "__main__":
unittest.main()
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
def foo(x, y):
ret = x + y
return ret
class TestMultipleArgs(TestCaseBase):
def test_multiple_args(self):
x = paddle.to_tensor([1.0])
y = paddle.to_tensor([2.0])
self.assert_results(foo, x, y)
if __name__ == "__main__":
unittest.main()
+353
View File
@@ -0,0 +1,353 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from paddle.jit.sot.opcode_translator.executor.mutable_data import (
MutableData,
MutableDictLikeData,
MutableListLikeData,
)
class VariableBase:
def __init__(self): ...
class ConstVariable(VariableBase):
def __init__(self, value):
self.value = value
def __repr__(self):
return f"ConstVariable({self.value})"
def __eq__(self, other):
if not isinstance(other, ConstVariable):
return False
return self.value == other.value
class DictVariable(VariableBase):
def __init__(self, data):
self.data = data
self.proxy = MutableDictLikeData(data, DictVariable.proxy_getter)
@staticmethod
def proxy_getter(proxy, key):
if key not in proxy.original_data:
return MutableData.Empty()
return ConstVariable(proxy.original_data[key])
def getitem(self, key):
res = self.proxy.get(key)
if isinstance(res, MutableData.Empty):
raise KeyError(f"Key {key} not found")
return res
def setitem(self, key, value):
self.proxy.set(key, value)
def delitem(self, key):
self.proxy.delete(key)
class ListVariable(VariableBase):
def __init__(self, data):
self.data = data
self.proxy = MutableListLikeData(data, ListVariable.proxy_getter)
@staticmethod
def proxy_getter(proxy, key):
if key < 0 or key >= len(proxy.original_data):
return MutableData.Empty()
return ConstVariable(proxy.original_data[key])
def getitem(self, key):
if isinstance(key, int):
res = self.proxy.get(key)
if isinstance(res, MutableData.Empty):
raise IndexError(f"Index {key} out of range")
return res
elif isinstance(key, slice):
return self.proxy.get_all()[key]
else:
raise TypeError(f"Invalid key type {type(key)}")
def __getitem__(self, key):
return self.getitem(key)
def setitem(self, key, value):
if isinstance(key, int):
self.proxy.set(key, value)
elif isinstance(key, slice):
start, end, step = key.indices(self.proxy.length)
indices = list(range(start, end, step))
if step == 1:
# replace a continuous range
for i, idx in enumerate(indices):
self.proxy.delete(idx - i)
for i, item in enumerate(value):
self.proxy.insert(start + i, item)
else:
# replace some elements
if len(indices) != len(value):
raise ValueError(
f"Attempt to replace {len(indices)} items with {len(value)}"
)
for i, idx in enumerate(indices):
self.proxy.set(idx, value[i])
def delitem(self, key):
self.proxy.delete(key)
def insert(self, index, value):
self.proxy.insert(index, value)
def append(self, value):
self.proxy.insert(self.proxy.length, value)
def extend(self, value):
for item in value:
self.append(item)
def pop(self, index=-1):
res = self.getitem(index)
self.delitem(index)
return res
def clear(self):
for i in range(self.proxy.length):
self.delitem(0)
def remove(self, value):
for i in range(self.proxy.length):
if self.getitem(i) == value:
self.delitem(i)
return
raise ValueError(f"Value {value} not found")
def sort(self, key=None, reverse=False):
if key is None:
key = lambda x: x
permutation = list(range(self.proxy.length))
permutation.sort(
key=lambda x: key(self.getitem(x).value), reverse=reverse
)
self.proxy.permutate(permutation)
def reverse(self):
permutation = list(range(self.proxy.length))
permutation.reverse()
self.proxy.permutate(permutation)
class TestMutableDictLikeVariable(unittest.TestCase):
def test_getitem(self):
data = {"a": 1, "b": 2}
var = DictVariable(data)
self.assertEqual(var.getitem("a"), ConstVariable(1))
self.assertEqual(var.getitem("b"), ConstVariable(2))
def test_setitem(self):
data = {"a": 1, "b": 2}
var = DictVariable(data)
var.setitem("a", ConstVariable(3))
self.assertEqual(var.getitem("a"), ConstVariable(3))
var.setitem("c", ConstVariable(4))
self.assertEqual(var.getitem("c"), ConstVariable(4))
def test_delitem(self):
data = {"a": 1, "b": 2}
var = DictVariable(data)
var.delitem("a")
with self.assertRaises(KeyError):
var.getitem("a")
def test_keys(self):
data = {"a": 1, "b": 2}
var = DictVariable(data)
self.assertEqual(list(var.proxy.get_all().keys()), ["a", "b"])
class TestMutableListLikeVariable(unittest.TestCase):
def test_getitem(self):
data = [1, 2, 3]
var = ListVariable(data)
self.assertEqual(var.getitem(0), ConstVariable(1))
self.assertEqual(var.getitem(1), ConstVariable(2))
self.assertEqual(var.getitem(2), ConstVariable(3))
def test_getitem_slice_1(self):
data = [1, 2, 3, 4, 5, 6, 7]
var = ListVariable(data)
self.assertEqual(
var.getitem(slice(0, 3)),
[ConstVariable(1), ConstVariable(2), ConstVariable(3)],
)
self.assertEqual(
var.getitem(slice(4, 1, -1)),
[ConstVariable(5), ConstVariable(4), ConstVariable(3)],
)
self.assertEqual(
var.getitem(slice(1, 5, 2)),
[ConstVariable(2), ConstVariable(4)],
)
def test_getitem_slice_2(self):
data = [1, 2, 3, 4, 5, 6, 7]
var = ListVariable(data)
self.assertEqual(
var[0:3],
[ConstVariable(1), ConstVariable(2), ConstVariable(3)],
)
self.assertEqual(
var[4:1:-1],
[ConstVariable(5), ConstVariable(4), ConstVariable(3)],
)
self.assertEqual(
var[1:5:2],
[ConstVariable(2), ConstVariable(4)],
)
def test_setitem(self):
data = [1, 2, 3]
var = ListVariable(data)
var.setitem(0, ConstVariable(4))
self.assertEqual(var.getitem(0), ConstVariable(4))
var.append(ConstVariable(5))
self.assertEqual(var.getitem(3), ConstVariable(5))
def test_setitem_slice_1(self):
data = [1, 2, 3, 4, 5, 6, 7]
var = ListVariable(data)
var.setitem(slice(0, 3), [ConstVariable(4), ConstVariable(5)])
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [4, 5, 4, 5, 6, 7]],
)
var.setitem(
slice(4, 1, -1),
[ConstVariable(8), ConstVariable(9), ConstVariable(10)],
)
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [4, 5, 10, 9, 8, 7]],
)
def test_setitem_slice_2(self):
data = [1, 2, 3, 4, 5, 6, 7]
var = ListVariable(data)
var.setitem(slice(2, 5, 2), [ConstVariable(8), ConstVariable(9)])
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [1, 2, 8, 4, 9, 6, 7]],
)
def test_delitem(self):
data = [1, 2, 3]
var = ListVariable(data)
var.delitem(0)
with self.assertRaises(IndexError):
var.getitem(2)
var.pop()
with self.assertRaises(IndexError):
var.getitem(1)
def test_insert(self):
data = [1, 2, 3]
var = ListVariable(data)
var.insert(0, ConstVariable(4))
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [4, 1, 2, 3]],
)
var.insert(2, ConstVariable(5))
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [4, 1, 5, 2, 3]],
)
def test_append(self):
data = [1, 2, 3]
var = ListVariable(data)
var.append(ConstVariable(4))
self.assertEqual(var.getitem(3), ConstVariable(4))
def test_extend(self):
data = [1, 2, 3]
var = ListVariable(data)
var.extend([ConstVariable(4), ConstVariable(5)])
self.assertEqual(var.getitem(3), ConstVariable(4))
self.assertEqual(var.getitem(4), ConstVariable(5))
def test_pop(self):
data = [1, 2, 3]
var = ListVariable(data)
self.assertEqual(var.pop(), ConstVariable(3))
self.assertEqual(var.pop(0), ConstVariable(1))
def test_clear(self):
data = [1, 2, 3]
var = ListVariable(data)
var.clear()
self.assertEqual(var.proxy.length, 0)
def test_remove(self):
data = [1, 2, 3]
var = ListVariable(data)
var.remove(ConstVariable(2))
self.assertEqual(var.getitem(0), ConstVariable(1))
self.assertEqual(var.getitem(1), ConstVariable(3))
with self.assertRaises(ValueError):
var.remove(ConstVariable(2))
def test_sort(self):
data = [2, 3, 0, 4, 1, 5]
var = ListVariable(data)
var.sort()
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [0, 1, 2, 3, 4, 5]],
)
def test_sort_with_key(self):
data = [-1, -4, 2, 0, 5, -3]
var = ListVariable(data)
var.sort(key=lambda x: x**2)
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [0, -1, 2, -3, -4, 5]],
)
def test_sort_reverse(self):
data = [2, 3, 0, 4, 1, 5]
var = ListVariable(data)
var.sort(reverse=True)
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [5, 4, 3, 2, 1, 0]],
)
def test_reverse(self):
data = [2, 3, 0, 4, 1, 5]
var = ListVariable(data)
var.reverse()
self.assertEqual(
[var.getitem(i) for i in range(var.proxy.length)],
[ConstVariable(n) for n in [5, 1, 4, 0, 3, 2]],
)
if __name__ == "__main__":
unittest.main()
+70
View File
@@ -0,0 +1,70 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@paddle.no_grad()
def inner_no_grad_fn(x, y):
return x * y + x**2
@check_no_breakgraph
def no_grad_fn_caller(x, y):
z = inner_no_grad_fn(x * y, y)
a = x * y + x**3 - 1
return z + a
@check_no_breakgraph
@paddle.no_grad()
def outer_no_grad_fn(x, y):
z = x * y + x**2
a = inner_no_grad_fn(x, y)
return z + a
class TestNoGrad(TestCaseBase):
def test_inner_no_grad(self):
x = paddle.randn([10, 3])
y = paddle.randn([10, 3])
x.stop_gradient = False
y.stop_gradient = False
self.assert_results_with_grad(
[x, y],
no_grad_fn_caller,
x,
y,
)
def test_outer_no_grad(self):
x = paddle.randn([1, 3])
y = paddle.randn([1, 3])
x.stop_gradient = False
y.stop_gradient = False
self.assert_results_with_grad(
[x, y],
outer_no_grad_fn,
x,
y,
)
if __name__ == "__main__":
unittest.main()
+113
View File
@@ -0,0 +1,113 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import strict_mode_guard
def numpy_add(x, y):
out = paddle.to_tensor(x.numpy() + y.numpy())
return out
def tensor_add_numpy(x, y):
ret = x + y
return ret
def large_numpy_array_to_tensor(x):
return paddle.to_tensor(x)
def normal_numpy_array_to_tensor(x):
return paddle.to_tensor(x)
@check_no_breakgraph
def numpy_api_with_number_calculation(t):
a = np.log(2)
b = np.exp(3)
c = np.sqrt(4)
d = np.ceil(5.1)
e = np.add(1, 2)
f = a + 1
g = 1 - b
h = c * 2
i = int(a)
j = float(b)
k = c.item()
l = t + d
return a, b, c, d, e, f, g, h, i, j, k, l
@check_no_breakgraph
def numpy_bool(x: np.number):
return bool(x == 1)
class TestNumPy(TestCaseBase):
@strict_mode_guard(False)
def test_numpy_add(self):
x = paddle.to_tensor([2])
y = paddle.to_tensor([3])
self.assert_results(numpy_add, x, y)
def test_tensor_add_numpy_number(self):
x = paddle.to_tensor([1.0])
y = np.int64(2)
self.assert_results(tensor_add_numpy, x, y)
self.assert_results(tensor_add_numpy, y, x)
@strict_mode_guard(False)
def test_tensor_add_numpy_array(self):
x = paddle.to_tensor([1.0])
y = np.array(2.0)
self.assert_results(tensor_add_numpy, x, y)
self.assert_results(tensor_add_numpy, y, x)
def test_large_numpy_array_to_tensor(self):
# size should be larger than 1024*1024, because we throw an exception
# when the size is larger than 1024*1024 in assign API (to_tensor static branch)
x = np.random.rand(1024, 1024, 2).astype(np.float32)
self.assert_results(large_numpy_array_to_tensor, x)
def test_numpy_array_guard(self):
x = np.array([1.0, 2.0])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(normal_numpy_array_to_tensor, x)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(normal_numpy_array_to_tensor, x)
self.assertEqual(ctx.translate_count, 1)
def test_numpy_api_with_number_calculation(self):
t = paddle.to_tensor([1.0])
self.assert_results(numpy_api_with_number_calculation, t)
def test_numpy_bool(self):
x = np.float32(1.0)
self.assert_results(numpy_bool, x)
if __name__ == "__main__":
unittest.main()
+218
View File
@@ -0,0 +1,218 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
import numpy as np
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@check_no_breakgraph
def unary_api(func, x: np.ndarray, *args, **kwargs):
return func(x, *args, **kwargs)
@check_no_breakgraph
def binary_api(
func: np.ufunc,
x: np.ndarray | list,
y: np.ndarray | list,
*args,
**kwargs,
):
return func(x, y, *args, **kwargs)
@check_no_breakgraph
def binary_operator(op: str, x: np.ndarray, y: np.ndarray):
if op == "+":
return x + y
elif op == "-":
return x - y
elif op == "*":
return x * y
elif op == "/":
return x / y
@check_no_breakgraph
def get_item(x: np.ndarray, index: int | tuple | np.ndarray):
return x[index]
@check_no_breakgraph
def set_item(
x: np.ndarray,
index: int | list | np.ndarray,
value: int | list | np.ndarray,
):
x[index] = value
return x
@check_no_breakgraph
def grad_fn(pd_x, np_y, np_y2):
pd_y = paddle.to_tensor(np_y)
pd_z = paddle.add(pd_x, pd_y)
pd_y2 = paddle.to_tensor(np_y2).astype("float32")
pd_z2 = paddle.matmul(pd_z, pd_y2)
return pd_z2
@check_no_breakgraph
def demo(pd_x):
np_y = np.array([[1, 2, 3], [4, 5, 6]])
np_y2 = np.transpose(np_y)
pd_y2 = paddle.to_tensor(np_y2)
pd_z = paddle.matmul(pd_x, pd_y2)
np_z = pd_z.numpy()
np_z2 = np.mean(np_z)
np_z3 = np.add(pd_x.numpy(), np_z2)
np_z4 = np_z * np_z3[:, :2]
pd_z2 = paddle.subtract(pd_z, paddle.to_tensor(np_z4))
return pd_z2
def absolute(x):
return np.absolute(x)
class TestNumPyArray(TestCaseBase):
def test_guard(self):
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(
binary_api, np.add, np.array([1, 2]), np.array([3, 4])
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
binary_api,
np.add,
np.array([1, 2], dtype=np.int32),
np.array([3, 4], dtype=np.int32),
)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(
binary_api, np.add, np.array([1]), np.array([3])
)
self.assertEqual(ctx.translate_count, 3)
self.assert_results(
binary_api, np.add, np.array([4, 3]), np.array([2, 1])
)
self.assertEqual(ctx.translate_count, 3)
def test_gradient(self):
pd_x = paddle.randn([2, 3], dtype="float32")
pd_x.stop_gradient = False
self.assert_results_with_grad(
pd_x,
grad_fn,
pd_x,
np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32),
np.ones(shape=(3, 2)),
)
def test_add_01(self):
x = np.array([1, 2])
y = np.array([3, 4])
self.assert_results(binary_api, np.add, x, y)
@unittest.skip("Not supported yet")
def test_add_02(self):
x = [1, 2]
y = [3, 4]
self.assert_results(binary_api, np.add, x, y)
@unittest.skip("Not supported yet")
def test_sub(self):
x = np.array([1, 2])
y = np.array([3, 4])
self.assert_results(binary_api, np.subtract, x, y)
self.assert_results(binary_api, np.subtract, [1, 2], [3, 4])
@unittest.skip("Not supported yet")
def test_mul(self):
x = np.array([1, 2])
y = np.array([3, 4])
self.assert_results(binary_api, np.multiply, x, y)
self.assert_results(binary_api, np.multiply, [1, 2], [3, 4])
self.assert_results_with_grad(binary_api, np.multiply, [1, 2], [3, 4])
@unittest.skip("Not supported yet")
def test_div(self):
x = np.array([1, 2])
y = np.array([3, 4])
self.assert_results(binary_api, np.divide, x, y)
self.assert_results(binary_api, np.divide, [1, 2], [3, 4])
@unittest.skip("Not supported yet")
def test_operator(self):
x = np.array([1, 2])
y = np.array([3, 4])
self.assert_results(binary_operator, '+', x, y)
self.assert_results(binary_operator, '-', x, y)
self.assert_results(binary_operator, '*', x, y)
self.assert_results(binary_operator, '/', x, y)
@unittest.skip("Not supported yet")
def test_argmax(self):
x = np.array([[1, 2], [3, 4]])
self.assert_results(unary_api, np.argmax, x)
self.assert_results(unary_api, np.argmax, x, axis=0)
@unittest.skip("Not supported yet")
def test_sum(self):
x = np.array([[1, 2], [3, 4]])
self.assert_results(unary_api, np.sum, x)
self.assert_results(unary_api, np.sum, x, axis=0)
@unittest.skip("Not supported yet")
def test_getitem(self):
x = np.array([[1, 2], [3, 4]])
self.assert_results(get_item, x, 0)
i = tuple(0, 0)
self.assert_results(get_item, x, i)
i2 = np.array([0, 1])
self.assert_results(get_item, x, i2)
@unittest.skip("Not supported yet")
def test_setitem(self):
x = np.array([[1, 2], [3, 4]])
y = np.array([5, 6])
self.assert_results(set_item, x, 0, y)
i = np.array([0])
self.assert_results(set_item, x, i, y)
self.assert_results(set_item, x, [0], [5, 6])
@unittest.skip("Not supported yet")
def test_demo(self):
pd_x = paddle.randn([2, 3], dtype="float32")
pd_x.stop_gradient = False
self.assert_results_with_grad(pd_x, demo, pd_x)
def test_absolute(self):
x = np.array([[1, -2], [-3, 4]])
self.assert_results(absolute, x)
if __name__ == "__main__":
unittest.main()
+51
View File
@@ -0,0 +1,51 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_fallback
from paddle.jit.sot.utils import ENV_MIN_GRAPH_SIZE
ENV_MIN_GRAPH_SIZE.set(-1)
@check_no_fallback
def forward(x, y):
if x == 0:
return y + 2
else:
return y * 2
@check_no_fallback
def forward2(x, y):
if x == x: # numpy == numpy
return y + 2
else:
return y * 2
class TestJumpWithNumPy(TestCaseBase):
def test_jump(self):
self.assert_results(forward, np.array([1]), paddle.to_tensor(2))
self.assert_results(forward, np.array([0]), paddle.to_tensor(2))
self.assert_results(forward2, np.array([0]), paddle.to_tensor(2))
if __name__ == "__main__":
unittest.main()
+95
View File
@@ -0,0 +1,95 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
def output_identity(x):
return x
def output_const():
return 42
def output_list(x: paddle.Tensor, y: paddle.Tensor, z: int):
a = x + 1
b = z + 1
l = [1, a, b, y]
return l
def output_dict(x: paddle.Tensor, y: paddle.Tensor, z: int):
a = x + 1
b = z + 1
l = {1: a, b: y}
return l
def output_dict_const_key(x: paddle.Tensor, y: paddle.Tensor, z: int):
a = x + 1
b = z + 1
l = {1: a, 2: y}
return l
def output_nest_struct(x: paddle.Tensor, y: paddle.Tensor, z: int):
a = x + y + z
b = z + 1
l = [1 + 1, (z, a), [b]]
return l
class TestOutputRestoration(TestCaseBase):
def test_output_identity(self):
self.assert_results(output_identity, 1)
self.assert_results(output_identity, 2)
self.assert_results(output_identity, paddle.to_tensor(1))
def test_output_const(self):
self.assert_results(output_const)
def test_output_list(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
self.assert_results(output_list, a, b, 3)
def test_output_dict(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
self.assert_results(output_dict, a, b, 3)
def test_output_dict_const_key(self):
a = paddle.to_tensor(2)
b = paddle.to_tensor(3)
self.assert_results(output_dict_const_key, a, b, 4)
def test_output_nest_struct(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
self.assert_results(output_nest_struct, a, b, 3)
if __name__ == "__main__":
unittest.main()
+57
View File
@@ -0,0 +1,57 @@
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import types
import unittest
from test_case_base import (
TestCaseBase,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
class ScaleOp:
def __init__(self, weight, bias):
self.weight = weight
self.bias = bias
def apply(self, x):
return x * self.weight + self.bias
class Module(types.ModuleType):
def __init__(self):
super().__init__("module")
_scale = ScaleOp(2, 3)
self.scale = _scale.apply
mod = Module()
@check_no_breakgraph
def call_patched_fn(x):
return mod.scale(x)
class TestCallPatchedFn(TestCaseBase):
def test_call_patched_fn(self):
x = paddle.randn([16, 72])
self.assert_results(call_patched_fn, x)
if __name__ == "__main__":
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import test_instruction_translator_cache_context
import paddle
from paddle.jit.sot import (
psdb,
symbolic_translate,
)
from paddle.jit.sot.utils.envs import strict_mode_guard
from paddle.jit.sot.utils.exceptions import InnerError
def assert_true_case(input: bool):
psdb.assert_true(input)
def breakgraph_case(x):
x = x + 1
psdb.breakgraph()
x = x + 1
return x
def fallback_not_recursive_inner(x):
x = x + 1
x = x + 1
return x
def fallback_not_recursive_case(x):
psdb.fallback(recursive=False)
x = fallback_not_recursive_inner(x)
return x
def fallback_recursive_case(x):
psdb.fallback(recursive=True)
x = fallback_not_recursive_inner(x)
return x
@psdb.check_no_breakgraph
def check_no_breakgraph_case(x):
x = x + 1
psdb.breakgraph()
x = x + 1
return x
@psdb.check_no_fallback
def check_no_fallback_case(x):
x = x + 1
psdb.fallback(recursive=False)
x = x + 1
return x
class TestPsdb(unittest.TestCase):
def test_assert_true(self):
# Test with True
symbolic_translate(assert_true_case)(True)
# Test with False
with self.assertRaises(InnerError):
symbolic_translate(assert_true_case)(False)
def test_breakgraph(self):
x = paddle.to_tensor([1.0])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
symbolic_translate(breakgraph_case)(x)
self.assertEqual(ctx.translate_count, 2)
@strict_mode_guard(False)
def test_fallback_not_recursive(self):
x = paddle.to_tensor([1.0])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
symbolic_translate(fallback_not_recursive_case)(x)
self.assertEqual(ctx.translate_count, 2)
@strict_mode_guard(False)
def test_fallback_recursive(self):
x = paddle.to_tensor([1.0])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
symbolic_translate(fallback_recursive_case)(x)
self.assertEqual(ctx.translate_count, 1)
def test_check_no_breakgraph(self):
x = paddle.to_tensor([1.0])
with self.assertRaises(InnerError):
symbolic_translate(check_no_breakgraph_case)(x)
@strict_mode_guard(False)
def test_check_no_fallback(self):
x = paddle.to_tensor([1.0])
with self.assertRaises(InnerError):
symbolic_translate(check_no_fallback_case)(x)
if __name__ == "__main__":
unittest.main()
+36
View File
@@ -0,0 +1,36 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle.distributed as dist
from paddle.jit.sot.psdb import check_no_breakgraph, check_no_fallback
@check_no_breakgraph
@check_no_fallback
def forward():
mesh = dist.ProcessMesh([[0, 1], [2, 3]], dim_names=['x', 'y'])
placement = [dist.Shard(0), dist.Replicate(), dist.Partial()]
class TestPureClass(TestCaseBase):
def test_class(self):
self.assert_results(forward)
if __name__ == "__main__":
unittest.main()
+46
View File
@@ -0,0 +1,46 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
def if_breakgraph(x, y):
z = x + y
if x:
z = z + 1
else:
z = z - 1
return z
class TestResumeCache(TestCaseBase):
def test_resume_cache_in_if_breakgraph(self):
x = paddle.to_tensor(0)
with test_instruction_translator_cache_context() as cache:
self.assertEqual(cache.translate_count, 0)
self.assert_results(if_breakgraph, x, 1)
self.assertEqual(cache.translate_count, 2)
self.assert_results(if_breakgraph, x, 2)
self.assertEqual(cache.translate_count, 3)
if __name__ == "__main__":
unittest.main()
+73
View File
@@ -0,0 +1,73 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle import nn
from paddle.jit import sot
from paddle.jit.sot.utils import strict_mode_guard
class Head(nn.Layer):
def __init__(self):
super().__init__()
self.head = nn.Linear(10, 150)
def forward(self, x, patch_embed_size):
masks = self.head(x)
# [b, (h w), c] -> [b, c, h, w]
h, w = patch_embed_size[0], patch_embed_size[1]
masks = masks.reshape((1, h, w, paddle.shape(masks)[-1]))
masks = masks.transpose((0, 3, 1, 2))
return masks
class SimpleNet(nn.Layer):
def __init__(self):
super().__init__()
self.tmp = nn.Linear(1, 1024 * 10)
self.tmp2 = nn.Linear(1, 1 * 10 * 32 * 32)
self.head = Head()
def getshape(self, x):
x = self.tmp2(x.mean().reshape([1])).reshape([1, 10, 32, 32])
x = paddle.shape(x)
return x
def forward(self, x):
sot.psdb.fallback()
shape = self.getshape(x)
feat = self.tmp(x.mean().reshape([1])).reshape([1, 1024, 10])
logits = self.head(feat, shape[2:])
return logits
class TestSegmentLinear(TestCaseBase):
@strict_mode_guard(False)
def test_simple(self):
x = paddle.randn((1, 8, 8))
net = SimpleNet()
net = paddle.jit.to_static(
net, full_graph=False
) # dont make effect. we need fetch sot PR in paddle.
loss = net(x)
loss = loss.sum()
loss.backward()
if __name__ == "__main__":
unittest.main()
+363
View File
@@ -0,0 +1,363 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit import sot
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.utils import InnerError, strict_mode_guard
def dict_setitem(x):
x[0] = 1
return x[0]
def dict_delitem(x):
del x[0]
return x
def dict_delitem_getitem(a):
b = a[0]
del a[0]
b[0] = 1
return a, b
def dict_nested_1(x):
x[0][0] = 42
x[1][0] = x[0][0] + x[0][1]
x[2] = {1: 2}
return x
def dict_nested_2(x):
a = x[0]
b = x[1]
del a[0]
a[1] = b[0]
a[2] = b[1]
x[1][0] = 42
del a[1]
return a, b
def list_append_int(tensor_x, list_a):
tensor_x = tensor_x + 1
list_a.append(12)
return tensor_x, list_a
def list_append_tensor(tensor_x, list_a):
tensor_x = tensor_x + 1
list_a.append(tensor_x)
return tensor_x, list_a
def list_delitem(list_a):
del list_a[0]
return list_a[0]
def list_extend(list_a):
list_a.extend([1, 2, 3])
return list_a[0]
def list_nested(list_a):
inner_list = []
inner_list.append(list_a)
inner_list[-1].append(12)
return 12
def list_insert(list_a):
list_a.insert(0, 1)
return list_a[0]
def list_remove(list_a):
list_a.remove(1)
return list_a[0]
def list_pop(list_a):
list_a.pop(0)
list_a.pop()
list_a.pop(1)
return list_a[0]
def list_clear(list_a):
list_a.clear()
return list_a
def list_sort(list_a):
list_a.sort()
return list_a
def list_reverse(list_a):
list_a.reverse()
return list_a
def slice_in_for_loop(x, iter_num=3):
x = paddle.to_tensor(x)
a = []
iter_num = paddle.full(shape=[1], fill_value=iter_num, dtype="int32")
for i in range(iter_num):
a.append(x)
for i in range(iter_num):
a[i] = x
out = a[2]
return out
# TODO: Object SideEffect
class CustomObject:
def __init__(self):
self.x = 2
self.y = paddle.to_tensor(1)
def object_attr_set2(self, x):
self.outputs = []
self.outputs.append(x)
return self.outputs
@sot.psdb.check_no_breakgraph
def object_attr_set(cus_obj, t):
"""object side effect."""
t = t + 1
cus_obj.x = t
return t, cus_obj.x
def object_attr_breakgraph(cus_obj, t):
t = t + 1
sot.psdb.breakgraph()
cus_obj.x = t
sot.psdb.breakgraph()
return t, cus_obj.x
@sot.psdb.check_no_breakgraph
def object_attr_tensor_del(cus_obj):
del cus_obj.y
@sot.psdb.check_no_breakgraph
def object_attr_int_del(cus_obj):
del cus_obj.x
def slice_list_after_change(l):
l.reverse()
sum = 0
for i, v in zip(range(2), l[2:]):
sum += v
return sum
class ReadBufferAfterChanged(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.buffer1 = paddle.to_tensor(1)
self.buffer2 = paddle.to_tensor(2)
def forward(self, x):
self.buffer1 += 1
return x + self.buffer1 + self.buffer2
def __eq__(self, other):
if not isinstance(other, ReadBufferAfterChanged):
return False
return paddle.equal(self.buffer1, other.buffer1) and paddle.equal(
self.buffer2, other.buffer2
)
class TestDictSideEffect(TestCaseBase):
def test_dict_setitem(self):
self.assert_results_with_side_effects(
dict_setitem, {0: paddle.to_tensor(0)}
)
self.assert_results_with_side_effects(
dict_setitem, {0: paddle.to_tensor(1)}
)
def test_dict_delitem(self):
self.assert_results_with_side_effects(
dict_delitem, {0: paddle.to_tensor(0), 1: paddle.to_tensor(1)}
)
self.assert_results_with_side_effects(
dict_delitem, {0: paddle.to_tensor(1), 2: paddle.to_tensor(2)}
)
def test_dict_delitem_getitem(self):
self.assert_results_with_side_effects(
dict_delitem_getitem, {0: {0: 1, 1: 2}}
)
def test_dict_nested_1(self):
self.assert_results_with_side_effects(
dict_nested_1, {0: {0: 1, 1: 2}, 1: {0: 1, 1: 2}}
)
self.assert_results_with_side_effects(
dict_nested_1, {0: {0: 123, 1: 2}, 1: {0: 1, 1: 2}}
)
def test_dict_nested_2(self):
self.assert_results_with_side_effects(
dict_nested_2, {0: {0: 1, 1: 2}, 1: {0: 1, 1: 2}}
)
self.assert_results_with_side_effects(
dict_nested_2, {0: {0: 123, 1: 2}, 1: {0: 1, 1: 2}}
)
class TestListSideEffect(TestCaseBase):
def test_list_append(self):
self.assert_results_with_side_effects(
list_append_int, paddle.to_tensor(1), [1, 2, 3]
)
self.assert_results_with_side_effects(
list_append_tensor, paddle.to_tensor(2), [1, 2, 3]
)
def test_list_delitem(self):
self.assert_results_with_side_effects(list_delitem, [1, 2, 3])
def test_list_extend(self):
self.assert_results_with_side_effects(
list_extend, [1, 2, 3, 4, 5, 6, 7, 8, 9]
)
def test_list_insert(self):
self.assert_results_with_side_effects(list_insert, [1, 2, 3])
self.assert_results_with_side_effects(
list_insert, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
)
def test_list_remove(self):
self.assert_results_with_side_effects(list_remove, [1, 1, 1])
self.assert_results_with_side_effects(list_remove, [0, 1, 2])
# TODO(DrRyanHuang): change this to ValueError
with self.assertRaises(InnerError):
symbolic_translate(list_remove)([0, 2, 4])
def test_list_pop(self):
self.assert_results_with_side_effects(list_pop, [1, 2, 3, 4, 5])
self.assert_results_with_side_effects(
list_pop, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
)
def test_list_clear(self):
self.assert_results_with_side_effects(list_clear, [1, 2, 3, 4, 5])
self.assert_results_with_side_effects(
list_clear, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
)
def test_list_sort(self):
self.assert_results_with_side_effects(list_sort, [2, 1, 7, 3, 4, 6])
self.assert_results_with_side_effects(
list_sort, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
)
def test_list_reverse(self):
self.assert_results_with_side_effects(list_reverse, [1, 2, 3, 4, 5])
self.assert_results_with_side_effects(
list_reverse, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
)
def test_slice_in_for_loop(self):
x = 2
with strict_mode_guard(False):
self.assert_results_with_side_effects(slice_in_for_loop, x)
def test_list_nested(self):
self.assert_results_with_side_effects(list_nested, [1, 2, 3])
class TestSliceAfterChange(TestCaseBase):
def test_slice_list_after_change(self):
self.assert_results_with_side_effects(
slice_list_after_change, [1, 2, 3, 4]
)
self.assert_results_with_side_effects(
slice_list_after_change, [7, 8, 9, 10]
)
class TestAttrSideEffect(TestCaseBase):
def attr_check(self, func, attr_keys: list[str], cls, *inputs):
cus_obj1 = cls()
cus_obj2 = cls()
sym_output = symbolic_translate(func)(cus_obj1, *inputs)
paddle_output = func(cus_obj2, *inputs)
for key in attr_keys:
self.assert_nest_match(
getattr(cus_obj1, key, f"__MISS_KEY__{key}"),
getattr(cus_obj2, key, f"__MISS_KEY__{key}"),
)
self.assert_nest_match(sym_output, paddle_output)
def test_attr_set(self):
self.attr_check(object_attr_set, ["x"], CustomObject, 5)
self.attr_check(
CustomObject.object_attr_set2, ["outputs"], CustomObject, 6
)
self.attr_check(
CustomObject.object_attr_set2,
["outputs"],
CustomObject,
paddle.to_tensor(5),
)
self.attr_check(
object_attr_set, ["x"], CustomObject, paddle.to_tensor(5)
)
def test_attr_del(self):
self.attr_check(object_attr_tensor_del, ["y"], CustomObject)
self.attr_check(object_attr_int_del, ["x"], CustomObject)
def test_attr_set_breakgraph(self):
self.attr_check(object_attr_breakgraph, ["x"], CustomObject, 100)
self.attr_check(object_attr_breakgraph, ["x"], CustomObject, 1000)
class TestReadBufferAfterChanged(TestCaseBase):
def test_read_buffer_after_change(self):
layer = ReadBufferAfterChanged()
x = paddle.randn([1, 2, 3])
self.assert_results_with_side_effects(
layer.__class__.forward,
layer,
x,
)
if __name__ == "__main__":
unittest.main()
+90
View File
@@ -0,0 +1,90 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle import nn
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.utils import strict_mode_guard
class A:
def __init__(self, vals):
vals.append(1)
def foo(x, y):
out = nn.Softmax()(paddle.to_tensor([x, y], dtype="float32"))
return out
def foo2(x, y):
t = nn.Softmax()
out1 = t(paddle.to_tensor([x, y], dtype="float32"))
out2 = t(paddle.to_tensor([x, y], dtype="float32"))
return out1 + out2
def error_foo(x):
t = nn.Linear(10, 10)
return t(x)
class NopLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.weight = None
def created_layer_reconstruct():
x = paddle.to_tensor([1, 2], dtype="float32")
weight = NopLayer().weight
if weight is not None:
x += 1
return x
def bar(x):
a = A(x)
t = paddle.to_tensor(x)
return t.mean()
class TestInit(TestCaseBase):
def test_init_paddle_layer(self):
self.assert_results(foo, 1, 2)
self.assert_results(foo2, 1, 2)
def test_init_python_object(self):
sot_output = symbolic_translate(bar)([1.0, 2.0])
dyn_output = bar([1.0, 2.0])
self.assert_nest_match(sot_output, dyn_output)
def test_error(self):
def run():
inputs = paddle.randn((10, 10))
symbolic_translate(error_foo)(inputs)
self.assertRaises(paddle.jit.sot.utils.exceptions.InnerError, run)
@strict_mode_guard(False)
def test_created_layer_reconstruct(self):
self.assert_results(created_layer_reconstruct)
if __name__ == "__main__":
unittest.main()
+89
View File
@@ -0,0 +1,89 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import inspect
import operator
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.opcode_translator.executor.function_graph import (
FunctionGraph,
)
from paddle.jit.sot.opcode_translator.executor.tracker import (
DanglingTracker,
LocalTracker,
)
from paddle.jit.sot.opcode_translator.executor.variables import (
BuiltinVariable,
VariableFactory,
)
def compute(x, y):
ret = BuiltinVariable(operator.add, x.graph, DanglingTracker())(x, y)
return BuiltinVariable(operator.mul, x.graph, DanglingTracker())(ret, x)
def try_add(x, y):
return BuiltinVariable(operator.add, x.graph, DanglingTracker())(x, y)
class TestRollback(TestCaseBase):
def test_rollback(self):
frame = inspect.currentframe()
assert frame is not None
graph = FunctionGraph(frame.f_code, frame.f_globals)
a = paddle.to_tensor(1.0)
b = paddle.to_tensor(2.0)
a = VariableFactory().from_value(a, graph, LocalTracker("a"))
b = VariableFactory().from_value(b, graph, LocalTracker("b"))
out = compute(a, b)
original_length = len(graph.sir_builder.current_sir.statements)
memo = graph.save_memo()
try_add(out, out)
assert len(graph.sir_builder.current_sir.statements) != len(
memo.stmt_ir.statements
), "After add, we must statement IR."
graph.restore_memo(memo)
assert len(graph.sir_builder.current_sir.statements) == original_length
def fn_with_side_effects_inner(x, y):
x[0] += 10
x[1] += 20
x[2] -= 10
print(y) # print will cause breakgraph
def fn_with_side_effects(x, y):
x[0] += 1
fn_with_side_effects_inner(x, y)
return x[0] + y
class TestSideEffectRollback(TestCaseBase):
def test_side_effect_rollback(self):
self.assert_results_with_side_effects(
fn_with_side_effects, [1, 2, 3], paddle.to_tensor(42)
)
if __name__ == "__main__":
unittest.main()
+51
View File
@@ -0,0 +1,51 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from paddle.jit.sot.utils import Cache
class CustomCache(Cache):
def key_fn(self, x):
return x
def value_fn(self, x):
return x
class TestCache(unittest.TestCase):
def test_basic(self):
cache = CustomCache()
self.assertEqual(cache(1), 1)
self.assertEqual(cache(1), 1)
def test_int_collision(self):
cache = CustomCache()
# -1 and -2 hash to the same value
self.assertEqual(cache(-1), -1)
self.assertEqual(cache(-2), -2)
def test_bool_and_int_collision(self):
cache = CustomCache()
# 1 and True hash to the same value
self.assertEqual(cache(True), True)
self.assertEqual(cache(1), 1)
# 0 and False hash to the same value
self.assertEqual(cache(False), False)
self.assertEqual(cache(0), 0)
if __name__ == "__main__":
unittest.main()
+50
View File
@@ -0,0 +1,50 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils import min_graph_size_guard
def simple_case(x, y):
a = x[0]
b = x[1]
c = paddle.reshape(y, [a, b])
# This case use full graph mode, we need to return a list to keep same as SOT
return [c]
class TestSotCall(TestCaseBase):
@min_graph_size_guard(0)
def test_input_with_different_places(self):
if paddle.device.is_compiled_with_cuda():
a = paddle.to_tensor(
[2, 3], dtype='int32', place=paddle.CUDAPlace(0)
)
b = paddle.ones([3, 2], dtype='int32')
_, pp = paddle.jit.to_static(
simple_case, full_graph=True
).get_concrete_program(a, b)
c = paddle.to_tensor([2, 3], dtype='int32', place=paddle.CPUPlace())
result1 = pp.sot_call([a, b])
result2 = pp.sot_call([c, b])
self.assert_nest_match(result1, result2)
if __name__ == "__main__":
unittest.main()
+66
View File
@@ -0,0 +1,66 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
import paddle.distributed as dist
from paddle.jit.sot.psdb import check_no_breakgraph
@check_no_breakgraph
def fn(x, y):
return x + y
@unittest.skipIf(
not paddle.is_compiled_with_distribute(),
reason='Not compiled with distribute.',
)
class TestGuardForDistInfo(TestCaseBase):
def test_fn(self):
x = paddle.ones([2, 2])
x.stop_gradient = False
y = paddle.zeros([2, 2])
y.stop_gradient = False
mesh1 = dist.ProcessMesh([0, 1], dim_names=['x'])
mesh2 = dist.ProcessMesh([0, 1], dim_names=['y'])
mesh3 = dist.ProcessMesh([0, 2], dim_names=['x'])
dist_x1 = dist.shard_tensor(
x, mesh1, [dist.Replicate()], stop_gradient=False
)
dist_y1 = dist.shard_tensor(
y, mesh1, [dist.Replicate()], stop_gradient=False
)
dist_x2 = dist.shard_tensor(x, mesh2, [dist.Replicate()])
dist_y2 = dist.shard_tensor(y, mesh2, [dist.Replicate()])
dist_x3 = dist.shard_tensor(x, mesh3, [dist.Replicate()])
dist_y3 = dist.shard_tensor(y, mesh3, [dist.Replicate()])
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
self.assert_results(fn, dist_x1, dist_y1)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(fn, dist_x2, dist_y2)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(fn, dist_x3, dist_y3)
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+593
View File
@@ -0,0 +1,593 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import math
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
from paddle.jit.sot.utils import (
ConditionalFallbackError,
allow_dynamic_shape_guard,
enable_0_size_fallback_guard,
specialized_dim_numbers_guard,
)
def dynamic_shape_input_func1(x):
s = x.shape[0]
return x + s
def dynamic_int_input_func1(x, n):
x = paddle.reshape(x, [n, -1])
return (x + n) * 2 - 1, (-n + 1) * 2 - 1, type(n) is int
def dynamic_shape_with_constraints(x, n):
return (x + n) * 2
def dynamic_int_input_func2(x, n):
return x + n[1]
def dynamic_int_input_func3(x, n):
if n < 4:
return 1
x = paddle.reshape(x, [n, -1])
return (x + n) * 2 - 1, (-n + 1) * 2 - 1
def dynamic_shape_access_inner_var_shape(x):
y = x + 1
return y.shape[0]
def dynamic_shape_in_list(x, shape):
return x.reshape(shape)
def dynamic_shape_int_mul_float(x):
y = x * 0.5
z = math.sin(y) # Trigger get_py_value
return z
def dynamic_shape_constraint(x):
s0, s1, *_ = x.shape
if s0 < 5:
return s0 + x
elif s0 < s1:
return s0 + x + 1
elif 2 * (s0 + s1 - 2) <= 30:
return s0 + x + 2
else:
return s0 + x + 3
class CustomConv(paddle.nn.Conv2D):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@paddle.jit.to_static(full_graph=False)
def forward(self, x):
return paddle.nn.functional.conv2d(
x,
self.weight,
self.bias,
[self._stride[0] + 1, self._stride[1]],
self._padding,
self._dilation,
self._groups,
self._data_format,
)
def pool2d_fallback(x, kernel_size):
return paddle.nn.functional.max_pool2d(x, kernel_size=kernel_size)
class TestOpcodeExecutorDynamicShapeCache(TestCaseBase):
def test_dynamic_int_input_cache_hit_case1(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_int_input_func1, paddle.randn([4, 5, 6]), 2
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_int_input_func1, paddle.randn([4, 5, 6]), i
)
self.assertEqual(ctx.translate_count, 2)
def test_dynamic_int_input_cache_hit_case2(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_int_input_func2, paddle.randn([4, 5, 6]), {1: 2}
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_int_input_func2, paddle.randn([4, 5, 6]), {1: i}
)
self.assertEqual(ctx.translate_count, 2)
def test_dynamic_int_input_cache_hit_case3(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
translate_count_map = {
0: 1,
1: 2, # 1 is dynamic dim
2: 2, # 2 hit cache, no recompile
3: 2, # 3 hit cache, no recompile
4: 3, # 4 is dynamic dim, but it not hit cache
5: 3, # 5 hit cache, no recompile
}
for i in range(0, 6):
self.assert_results(
dynamic_int_input_func3, paddle.randn([4, 5, 6]), i
)
self.assertEqual(ctx.translate_count, translate_count_map[i])
def test_dynamic_shape_input_cache_hit_case1(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_input_func1, paddle.randn([2, 4, 5])
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_shape_input_func1, paddle.randn([i, 4, 5])
)
self.assertEqual(ctx.translate_count, 2)
def test_dynamic_shape_input_cache_hit_case2(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_access_inner_var_shape, paddle.randn([2, 4, 5])
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_shape_access_inner_var_shape,
paddle.randn([i, 4, 5]),
)
self.assertEqual(ctx.translate_count, 2)
def test_dynamic_shape_cast(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
func1 = check_no_breakgraph(lambda n: bool(n))
# TODO(SigureMo): Open these cases
# func2 = check_no_breakgraph(lambda n: int(n))
# func3 = check_no_breakgraph(lambda n: float(n))
for func in [func1]:
self.assert_results(func, 1)
self.assert_results(func, 2)
def test_dynamic_shape_in_list(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_in_list,
paddle.randn([2, 2, 5]),
[4, 5],
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_shape_in_list,
paddle.randn([i, 2, 5]),
[i * 2, 5],
)
self.assertEqual(ctx.translate_count, 2)
def test_conv_dynamic_shape_stride_fallback(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
for i in range(1, 5):
conv = CustomConv(3, 3, 3, stride=i)
conv(paddle.randn([1, 3, 224, 224]))
self.assertEqual(ctx.translate_count, i)
def test_conv_dynamic_shape_kernel_size_fallback(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
for i in range(1, 5):
x = paddle.randn([1, 3, 224, 224])
self.assert_results(pool2d_fallback, x, i)
self.assertEqual(ctx.translate_count, i)
def test_pad_dynamic_shape_fallback(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
pad_func = check_no_breakgraph(
lambda x, n: paddle.nn.functional.pad(x, [0, n, 0, 0])
)
for i in range(1, 5):
self.assert_results(pad_func, paddle.randn([1, 3, 224, 224]), i)
self.assertEqual(ctx.translate_count, 1 if i == 1 else 2)
def test_dynamic_shape_int_mul_float(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
for i in range(1, 6):
self.assert_results(dynamic_shape_int_mul_float, i)
def test_dynamic_shape_constraint(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
const_dim = 6
self.assert_results(
dynamic_shape_constraint, paddle.randn([1, 1, const_dim])
)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(
dynamic_shape_constraint, paddle.randn([2, 2, const_dim])
)
self.assertEqual(ctx.translate_count, 2) # add constraint s0 < 5
self.assert_results(
dynamic_shape_constraint, paddle.randn([3, 3, const_dim])
)
self.assertEqual(ctx.translate_count, 2) # hit constraint s0 < 5
self.assert_results(
dynamic_shape_constraint, paddle.randn([4, 4, const_dim])
)
self.assertEqual(ctx.translate_count, 2) # hit constraint s0 < 5
self.assert_results(
dynamic_shape_constraint, paddle.randn([5, 6, const_dim])
)
self.assertEqual(ctx.translate_count, 3) # add constraint s0 < s1
self.assert_results(
dynamic_shape_constraint, paddle.randn([6, 7, const_dim])
)
self.assertEqual(ctx.translate_count, 3) # hit constraint s0 < s1
self.assert_results(
dynamic_shape_constraint, paddle.randn([7, 8, const_dim])
)
self.assertEqual(ctx.translate_count, 3) # hit constraint s0 < s1
self.assert_results(
dynamic_shape_constraint, paddle.randn([8, 7, const_dim])
)
self.assertEqual(
ctx.translate_count,
4, # add constraint 2 * (s0 + s1 - 2) <= 30
)
self.assert_results(
dynamic_shape_constraint, paddle.randn([9, 8, const_dim])
)
self.assertEqual(
ctx.translate_count,
4, # hit constraint 2 * (s0 + s1 - 2) <= 30
)
self.assert_results(
dynamic_shape_constraint, paddle.randn([10, 9, const_dim])
)
self.assertEqual(ctx.translate_count, 5) # add constraint else
self.assert_results(
dynamic_shape_constraint, paddle.randn([11, 10, const_dim])
)
self.assertEqual(ctx.translate_count, 5) # hit constraint else
self.assert_results(
dynamic_shape_constraint, paddle.randn([4, 3, const_dim])
)
self.assertEqual(ctx.translate_count, 5) # hit constraint s0 < 5
self.assert_results(
dynamic_shape_constraint, paddle.randn([5, 8, const_dim])
)
self.assertEqual(ctx.translate_count, 5) # hit constraint s0 < s1
self.assert_results(
dynamic_shape_constraint, paddle.randn([8, 8, const_dim])
)
self.assertEqual(
ctx.translate_count,
5, # hit 2 * (s0 + s1 - 2) <= 30
)
with self.assertRaises(ConditionalFallbackError):
self.assert_results(
dynamic_shape_constraint, paddle.randn([0, 1, const_dim])
)
def test_mixed_dynamic_and_static(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
a = paddle.randn([4, 5, 6])
self.assert_results(dynamic_int_input_func1, a, 1)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(dynamic_int_input_func1, a, 0)
self.assertEqual(ctx.translate_count, 2)
for i in range(2, 6):
self.assert_results(dynamic_int_input_func1, a, i)
self.assertEqual(ctx.translate_count, 3)
def test_mixed_static_after_dynamic(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
a = paddle.randn([4, 5, 6])
self.assert_results(dynamic_int_input_func1, a, 2)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 6):
self.assert_results(dynamic_int_input_func1, a, i)
self.assertEqual(ctx.translate_count, 2)
self.assert_results(dynamic_int_input_func1, a, 0)
self.assertEqual(ctx.translate_count, 3)
self.assert_results(dynamic_int_input_func1, a, 1)
self.assertEqual(ctx.translate_count, 3)
def test_dynamic_shape_with_constraints(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_with_constraints, paddle.randn([4, 5, 6]), 2
)
self.assertEqual(ctx.translate_count, 1)
for i in range(3, 7):
self.assert_results(
dynamic_shape_with_constraints,
paddle.randn([4 + i, 5, 6]),
i,
)
self.assertEqual(ctx.translate_count, 2)
@check_no_breakgraph
def dynamic_shape_non_break_non_inplace_ops(x):
s0 = x.shape[0]
s1 = s0 + 1
s2 = 1 + s0
s3 = s1 + s2
s4 = s1 * s2
s5 = s1 - s2
s6 = s1 / s2
s7 = s1 // s2
s8 = s1 % s2
s9 = s1**s2
s10 = s1 & s2
s11 = s1 | s2
s12 = s1 ^ s2
s13 = s1 << s2
s14 = s1 >> s2
s15 = s1 == s2
s16 = s1 != s2
s17 = s1 < s2
s18 = s1 <= s2
s19 = s1 > s2
s20 = s1 >= s2
s21 = bool(s1)
s22 = not s2
return (
s0,
s1,
s2,
s3,
s4,
s5,
s6,
s7,
s8,
s9,
s10,
s11,
s12,
s13,
s14,
s15,
s16,
s17,
s18,
s19,
s20,
s21,
s22,
)
@check_no_breakgraph
def dynamic_shape_non_break_inplace_ops(x):
s0 = x.shape[0]
s1 = s0 + 1
s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = s10 = s11 = s12 = s13 = s0
s2 += s1
s3 *= s1
s4 -= s1
# TODO(SigureMo): Open this case, currently the compute result between Python and C++ (Paddle Kernel)
# has a small difference (0.8333333134651184 and 0.8333333333333334)
# s5 /= s1
s6 //= s1
s7 %= s1
s8 **= s1
s9 &= s1
s10 |= s1
s11 ^= s1
s12 <<= s1
s13 >>= s1
return (
s0,
s1,
s2,
s3,
s4,
# s5,
s6,
s7,
s8,
s9,
s10,
s11,
s12,
s13,
)
class TestDynamicShapeNonBreakOps(TestCaseBase):
def test_dynamic_shape_non_break_non_inplace_ops(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_non_break_non_inplace_ops, paddle.randn([4, 5, 6])
)
self.assertEqual(ctx.translate_count, 1)
for i in range(5, 9):
self.assert_results(
dynamic_shape_non_break_non_inplace_ops,
paddle.randn([i, 5, 6]),
)
self.assertEqual(ctx.translate_count, 2)
def test_dynamic_shape_non_break_inplace_ops(self):
with (
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
):
self.assert_results(
dynamic_shape_non_break_inplace_ops, paddle.randn([4, 5, 6])
)
self.assertEqual(ctx.translate_count, 1)
for i in range(5, 9):
self.assert_results(
dynamic_shape_non_break_inplace_ops,
paddle.randn([i, 5, 6]),
)
self.assertEqual(ctx.translate_count, 2)
def dynamic_shape_for_specialized_dim_numbers(x):
return x + 1
class TestSpecializedDimNumbers(TestCaseBase):
def test_specialized_dim_numbers_01(self):
with (
specialized_dim_numbers_guard("01"),
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
enable_0_size_fallback_guard(False),
):
x = paddle.randn([0, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 1)
x = paddle.randn([1, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([2, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 3)
x = paddle.randn([3, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 3)
def test_specialized_dim_numbers_0(self):
with (
specialized_dim_numbers_guard("0"),
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
enable_0_size_fallback_guard(False),
):
x = paddle.randn([0, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 1)
x = paddle.randn([1, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([2, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([3, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
def test_specialized_dim_numbers_no(self):
with (
specialized_dim_numbers_guard("no"),
allow_dynamic_shape_guard(True),
test_instruction_translator_cache_context() as ctx,
enable_0_size_fallback_guard(False),
):
x = paddle.randn([10, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 1)
x = paddle.randn([0, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([1, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([2, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
x = paddle.randn([3, 5, 6])
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
self.assertEqual(ctx.translate_count, 2)
if __name__ == '__main__':
unittest.main()
+94
View File
@@ -0,0 +1,94 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import re
import unittest
import paddle
from paddle.jit.sot import symbolic_translate
def case1(x):
return undefined_var # noqa: F821
def case2(x):
x = x + 1
return x @ x
def case3(x):
y = undefined_var # noqa: F821
return y
def case4_inner(x):
y = x * 2
print()
y = y + 1
return undefined_var # noqa: F821
def case4(x):
return case4_inner(x)
def case5_inner3(x):
x += 1
print(x)
z = x + 1
return z
def case5_inner2(x):
x += 1
z = case5_inner3(y) # noqa: F821
return z + 1
def case5_inner1(x):
return case5_inner2(x)
def case5(x):
y = case5_inner3(x)
return case5_inner1(y) + 1
class TestException(unittest.TestCase):
def catch_error(self, func, inputs, error_lines: int | list[int]):
if isinstance(error_lines, int):
error_lines = [error_lines]
try:
symbolic_translate(func)(inputs)
except Exception as e:
match_results = re.compile(r'File ".*", line (\d+)').findall(str(e))
match_results = list(map(int, match_results))
assert match_results == error_lines, (
f"{match_results} is not equal {error_lines}"
)
def test_all_case(self):
self.catch_error(case1, paddle.rand([2, 1]), 25)
# TODO: support runtime error, such as x[111], x@x
# self.catch_error(case2, paddle.rand([2, 1]), 30)
self.catch_error(case3, paddle.rand([2, 1]), 34)
self.catch_error(case4, paddle.rand([2, 1]), 42)
self.catch_error(case5, paddle.rand([3, 1]), [68, 63, 58])
if __name__ == "__main__":
unittest.main()
+53
View File
@@ -0,0 +1,53 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import tempfile
import unittest
import paddle
from paddle.jit.sot.utils import export_guard, min_graph_size_guard
class Net(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear = paddle.nn.Linear(2, 2)
self.bias = self.create_parameter(
shape=[2],
attr=None,
dtype="float32",
is_bias=True,
)
def forward(self, x):
a = self.linear(x)
return a + self.bias
class TestSotExport(unittest.TestCase):
@min_graph_size_guard(0)
def test_basic(self):
temp_dir = tempfile.TemporaryDirectory()
temp_dir_name = temp_dir.name
net = Net()
x = paddle.to_tensor([2, 3], dtype="float32", stop_gradient=True)
with export_guard(temp_dir_name):
y = paddle.jit.to_static(net)(x)
assert os.path.exists(os.path.join(temp_dir_name, "SIR_0.py"))
temp_dir.cleanup()
if __name__ == "__main__":
unittest.main()
+208
View File
@@ -0,0 +1,208 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@check_no_breakgraph
def size_construct_from_list(x: int, y: int):
s = paddle.Size([x, y, 3])
return s
@check_no_breakgraph
def size_construct_from_tuple(x: int, y: int):
s = paddle.Size((x, y, 3))
return s
@check_no_breakgraph
def size_getitem_int(x: int, y: int):
s = paddle.Size([x, y, 10])
return s[1]
@check_no_breakgraph
def size_getitem_slice(x: int, y: int):
s = paddle.Size([x, y, 10, 20])
# Slice of Size should return Size
return s[1:3]
@check_no_breakgraph
def size_numel(x: int, y: int):
s = paddle.Size([x, y, 2])
return s.numel()
# --- Add Operations ---
@check_no_breakgraph
def size_add_list(x: int):
s = paddle.Size([x, 2])
l = [3, 4]
return s + l, l + s
@check_no_breakgraph
def size_add_tuple(x: int):
s = paddle.Size([x, 2])
t = (3, 4)
return s + t, t + s
@check_no_breakgraph
def size_add_size(x: int):
s1 = paddle.Size([x, 2])
s2 = paddle.Size([3, 4])
res = s1 + s2
return res
# --- Mul Operations ---
@check_no_breakgraph
def size_mul(x: int):
s = paddle.Size([x, 2])
res = s * 2
return res
@check_no_breakgraph
def size_rmul(x: int):
s = paddle.Size([x, 2])
res = 2 * s
return res
# --- Compare Operations ---
@check_no_breakgraph
def size_compare_tuple(x: int):
s = paddle.Size([x, 2])
t = (x, 2)
t_diff = (x, 3, 4)
return (
s == t,
s == t_diff,
s != t,
s != t_diff,
t == s,
t_diff == s,
t != s,
t_diff != s,
)
@check_no_breakgraph
def size_compare_list(x: int):
s = paddle.Size([x, 2])
l = [x, 2]
return s == l, s != l, l == s, l != s
# --- Common Methods ---
@check_no_breakgraph
def size_count(x: int):
s = paddle.Size([x, x, 2, 3])
return s.count(x)
@check_no_breakgraph
def size_index(x: int):
s = paddle.Size([2, x, 3])
return s.index(x)
@check_no_breakgraph
def size_len(x: int):
s = paddle.Size([x, x, 2])
return len(s)
@check_no_breakgraph
def size_iter(x: int):
s = paddle.Size([x, 2, 3])
res = 0
for dim in s:
res += dim
return res
@check_no_breakgraph
def size_contains(x: int):
s = paddle.Size([x, 2, 3])
return x in s, 99 in s
# --- Symbolic shape---
@check_no_breakgraph
def symbolic_shape(x: int):
s = paddle.zeros(shape=[x, 2, 3])
s[0] = 1
res = s.unique(return_inverse=False)
return res.shape, res.shape.numel()
class TestSizeBasic(TestCaseBase):
def test_construct(self):
self.assert_results(size_construct_from_list, 1, 2)
self.assert_results(size_construct_from_tuple, 1, 2)
def test_getitem(self):
self.assert_results(size_getitem_int, 5, 6)
self.assert_results(size_getitem_slice, 5, 6)
def test_numel(self):
self.assert_results(size_numel, 3, 4)
self.assert_results(size_numel, 0, 4)
def test_add(self):
self.assert_results(size_add_list, 1)
self.assert_results(size_add_tuple, 1)
self.assert_results(size_add_size, 1)
def test_mul(self):
self.assert_results(size_mul, 1)
self.assert_results(size_rmul, 1)
def test_compare(self):
self.assert_results(size_compare_tuple, 1)
self.assert_results(size_compare_list, 1)
def test_methods(self):
self.assert_results(size_count, 1)
self.assert_results(size_index, 1)
self.assert_results(size_len, 5)
self.assert_results(size_iter, 4)
self.assert_results(size_contains, 1)
def test_symbolic_shape(self):
self.assert_results(symbolic_shape, 3)
if __name__ == "__main__":
unittest.main()
+104
View File
@@ -0,0 +1,104 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from contextlib import contextmanager
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.psdb import check_no_breakgraph
@contextmanager
def device_guard(place: str):
original_place = paddle.get_device()
try:
paddle.set_device(place)
yield
finally:
paddle.set_device(original_place)
@check_no_breakgraph
def run_diff_logic_by_check_expected_place(x: paddle.Tensor):
expected_place_str = paddle.get_device()
if "cpu" in expected_place_str:
return x + 1
elif expected_place_str.startswith("gpu"):
return x + 2
elif "xpu" in expected_place_str:
return x + 3
elif "npu" in expected_place_str:
return x + 4
return x
class TestCheckExpectedPlace(TestCaseBase):
def test_check_cpu(self):
x = paddle.to_tensor(0.0)
with device_guard("cpu"):
self.assert_results(run_diff_logic_by_check_expected_place, x.cpu())
@unittest.skipUnless(
paddle.is_compiled_with_cuda(),
"This test case needs to be compiled with CUDA",
)
def test_check_gpu(self):
x = paddle.to_tensor(0.0)
with device_guard("gpu"):
self.assert_results(
run_diff_logic_by_check_expected_place, x.cuda()
)
@unittest.skipUnless(
paddle.is_compiled_with_xpu(),
"This test case needs to be compiled with XPU",
)
def test_check_xpu(self):
x = paddle.to_tensor(0.0)
with device_guard("xpu"):
self.assert_results(
run_diff_logic_by_check_expected_place, x.to("xpu")
)
class TestExpectedPlaceGuard(TestCaseBase):
@unittest.skipUnless(
paddle.is_compiled_with_cuda(),
"This test case needs to be compiled with cuda",
)
def test_expected_place_guard(self):
x = paddle.to_tensor(0.0)
with test_instruction_translator_cache_context() as ctx:
self.assertEqual(ctx.translate_count, 0)
with device_guard("cpu"):
self.assert_results(
run_diff_logic_by_check_expected_place, x.cpu()
)
self.assertEqual(ctx.translate_count, 1)
with device_guard("gpu"):
self.assert_results(
run_diff_logic_by_check_expected_place, x.cuda()
)
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+59
View File
@@ -0,0 +1,59 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.vision.models.resnet import resnet18
def resnet_call(x: paddle.Tensor, net: paddle.nn.Layer):
return net(x)
class TestResNet(TestCaseBase):
def test_resnet_eval(self):
x = paddle.rand((10, 3, 224, 224))
net = resnet18(pretrained=False)
net.eval()
with test_instruction_translator_cache_context() as ctx:
self.assert_results(resnet_call, x, net)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(resnet_call, x, net) # cache hit
self.assertEqual(ctx.translate_count, 1)
net.train()
self.assert_results(resnet_call, x, net) # cache miss
self.assertEqual(ctx.translate_count, 2)
def test_resnet_train(self):
x = paddle.rand((10, 3, 224, 224))
net = resnet18(pretrained=False)
net.train()
with test_instruction_translator_cache_context() as ctx:
self.assert_results(resnet_call, x, net)
self.assertEqual(ctx.translate_count, 1)
self.assert_results(resnet_call, x, net) # cache hit
self.assertEqual(ctx.translate_count, 1)
net.eval()
self.assert_results(resnet_call, x, net) # cache miss
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+81
View File
@@ -0,0 +1,81 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import random
import unittest
import numpy as np
from numpy.testing import assert_array_equal
import paddle
from paddle.jit.sot import symbolic_translate
from paddle.jit.sot.utils.utils import execute_time
from paddle.vision import resnet50
def resnet_call(net: paddle.nn.Layer, x: paddle.Tensor):
return net(x)
def run_dygraph_optimizer(inp):
"""dygraph train + SGD optimizer"""
paddle.seed(2021)
np.random.seed(2021)
random.seed(2021)
net = resnet50()
optimizer = paddle.optimizer.SGD(
learning_rate=0.03, parameters=net.parameters()
)
for i in range(5):
optimizer.clear_grad()
loss = execute_time(net)(inp)
loss.backward()
optimizer.step()
return loss
def run_symbolic_optimizer(inp):
"""dygraph train + SGD optimizer"""
paddle.seed(2021)
np.random.seed(2021)
random.seed(2021)
net = resnet50()
net_wrapper = symbolic_translate(resnet_call)
optimizer = paddle.optimizer.SGD(
learning_rate=0.03, parameters=net.parameters()
)
for i in range(5):
optimizer.clear_grad()
loss = execute_time(net_wrapper)(net, inp)
loss.backward()
optimizer.step()
return loss
class TestBackward(unittest.TestCase):
def test(self):
# TODO(xiongkun) add cache to speedup !
paddle.seed(2021)
np.random.seed(2021)
random.seed(2021)
inp = paddle.rand((3, 3, 255, 255))
out2 = run_symbolic_optimizer(inp)[0].numpy()
out1 = run_dygraph_optimizer(inp)[0].numpy()
assert_array_equal(
out1, out2, "Not Equal in dygraph and static graph", True
)
if __name__ == "__main__":
unittest.main()
+46
View File
@@ -0,0 +1,46 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
import paddle
from paddle.jit.sot import symbolic_translate
def api_with_set_stop_gradient(x):
y = x + x
y.stop_gradient = True
return y
class TestApiWithSetStopGradient(unittest.TestCase):
def test_api_with_set_stop_gradient(self):
x_dy = paddle.to_tensor(1.0, stop_gradient=False)
y_dy = api_with_set_stop_gradient(x_dy)
y_dy.backward()
x_st = paddle.to_tensor(1.0, stop_gradient=False)
y_st = symbolic_translate(api_with_set_stop_gradient)(x_st)
y_st.backward()
self.assertTrue(y_dy.stop_gradient)
self.assertTrue(y_st.stop_gradient)
self.assertIsNone(x_dy.grad)
self.assertIsNone(x_st.grad)
if __name__ == "__main__":
unittest.main()
+42
View File
@@ -0,0 +1,42 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit import sot
class TestArrayWrite(TestCaseBase):
def test_array_write(self):
def call_array_api():
arr = paddle.tensor.create_array(dtype="float32")
x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32")
i = paddle.zeros(shape=[1], dtype="int32")
# The `breakgraph` here is used to document that the `create_array` function has a dynamic-static inconsistency issue.
# In SOT, it cannot be directly handled as a PaddleApiVariable; instead, it requires internal function simulation for execution.
# Thus, a manual breakpoint is marked to flag this issue.
sot.psdb.breakgraph()
# The presence of the `item` method within `array_write` / `array_read` can cause breakgraph.
arr = paddle.tensor.array_write(x, i, array=arr)
item = paddle.tensor.array_read(arr, i)
return item
self.assert_results(call_array_api)
if __name__ == "__main__":
unittest.main()
+45
View File
@@ -0,0 +1,45 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.opcode_translator.executor.dispatcher import Dispatcher
from paddle.jit.sot.utils.envs import min_graph_size_guard
# 8 will trigger the warmup in RESUME instruction and cause a segmentation fault
# RUN_N_TIMES should be larger than 8
RUN_N_TIMES = 20
builtin_fn = str.split
# Remove builtin_fn from Dispatcher to ensure that trigger a BreakGraph Error
if builtin_fn in Dispatcher.handlers:
del Dispatcher.handlers[builtin_fn]
def builtin_fn_with_breakgraph():
str.split("1,2,3,4,5", ",")
class TestSpecialization(TestCaseBase):
@min_graph_size_guard(10)
def test_specialization(self):
for _ in range(RUN_N_TIMES):
paddle.jit.to_static(builtin_fn_with_breakgraph)()
if __name__ == "__main__":
unittest.main()
+56
View File
@@ -0,0 +1,56 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from paddle.jit.sot.opcode_translator.executor.variable_stack import (
VariableStack,
)
class TestVariableStack(unittest.TestCase):
def test_basic(self):
stack = VariableStack([1, 2, 3])
self.assertEqual(str(stack), "[1, 2, 3]")
self.assertEqual(len(stack), 3)
self.assertEqual(str(stack.copy()), str(stack))
def test_peek(self):
stack = VariableStack([1, 2, 3])
self.assertEqual(stack.peek(), 3)
self.assertEqual(stack.top, 3)
self.assertEqual(stack.peek(1), 3)
stack.peek[1] = 4
stack.peek[2] = 3
self.assertEqual(stack.peek[1], 4)
self.assertEqual(stack.peek[:1], [4])
self.assertEqual(stack.peek[:2], [3, 4])
stack.top = 5
self.assertEqual(stack.peek[:2], [3, 5])
def test_push_pop(self):
stack = VariableStack()
stack.push(1)
stack.push(2)
self.assertEqual(stack.pop(), 2)
self.assertEqual(stack.pop(), 1)
def test_pop_n(self):
stack = VariableStack([1, 2, 3, 4])
self.assertEqual(stack.pop_n(2), [3, 4])
self.assertEqual(stack.pop_n(2), [1, 2])
if __name__ == "__main__":
unittest.main()
+57
View File
@@ -0,0 +1,57 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
import paddle
from paddle.jit import sot
from paddle.jit.sot.utils import strict_mode_guard
class SimpleModel(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.conv1 = paddle.nn.Conv2D(3, 2, 3)
self.conv2 = paddle.nn.Conv2D(2, 3, 3)
def inner_fn(self, x):
sot.psdb.fallback()
x = self.conv1(x)
x = self.conv2(x)
return x
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
self.inner_fn(x)
return x
class TestStepProfilerSmokeTest(unittest.TestCase):
# Temporarily disable this test
# @sot_step_profiler_guard(True)
@strict_mode_guard(False)
def test_step_profiler_smoke(self):
model = SimpleModel()
model = paddle.jit.to_static(model, full_graph=False)
x = paddle.randn([1, 3, 32, 32])
model(x)
if __name__ == "__main__":
unittest.main()
+37
View File
@@ -0,0 +1,37 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import TestCaseBase
# copy from python library _distutils_hack/__init__.py
def find_spec(self, fullname, path, target=None):
method_name = 'spec_for_{fullname}'.format(
**{'self': self, 'fullname': fullname}
)
method = getattr(self, method_name, lambda: None)
return method()
class TestExecutor(TestCaseBase):
def test_simple(self):
self.assert_results(find_spec, "self", "fullname", "path", None)
if __name__ == "__main__":
unittest.main()
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
from test_case_base import TestCaseBase
import paddle
def shape_div(x):
return int(np.ceil(x.shape[0] / 7))
class TestSymbolicOperation(TestCaseBase):
def test_symbolic_truediv(self):
x = paddle.rand([168, 1])
paddle.jit.marker.dynamic_dims(x, [0])
self.assert_results(shape_div, x)
if __name__ == "__main__":
unittest.main()
+88
View File
@@ -0,0 +1,88 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit import sot
from paddle.jit.sot.utils import strict_mode_guard
def foo(x, y):
if x.dtype == paddle.float32:
out = x + y
else:
out = x - y
return out
def dtype_in_guard(x, y):
sot.psdb.fallback()
with paddle.amp.auto_cast(level='O2'):
for i in range(10):
z = foo(x, y)
x = z
return x
def bar(x, y):
if x == paddle.float32:
return y + 1
else:
return y - 1
def dtype_as_input(x, y):
sot.psdb.fallback()
with paddle.amp.auto_cast(level='O2'):
for i in range(10):
z = bar(x, y)
y = z
return y
class TestDtypeInGuard(TestCaseBase):
@strict_mode_guard(False)
def test_dtype_in_guard(self):
with test_instruction_translator_cache_context() as ctx:
x = paddle.to_tensor([2], dtype="float32")
y = paddle.to_tensor([3], dtype="float32")
self.assert_results(dtype_in_guard, x, y)
if sys.version_info >= (3, 11):
# skipped with co_exceptiontable flag
self.assertEqual(ctx.translate_count, 1)
else:
self.assertEqual(ctx.translate_count, 2)
@strict_mode_guard(False)
def test_input_dtype_in_guard(self):
with test_instruction_translator_cache_context() as ctx:
x = paddle.float32
y = paddle.to_tensor([3], dtype="float32")
self.assert_results(dtype_as_input, x, y)
if sys.version_info >= (3, 11):
# skipped with co_exceptiontable flag
self.assertEqual(ctx.translate_count, 1)
else:
self.assertEqual(ctx.translate_count, 2)
if __name__ == "__main__":
unittest.main()
+33
View File
@@ -0,0 +1,33 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
def foo(x: paddle.Tensor):
return x[:, 0]
class TestExecutor(TestCaseBase):
def test_tensor_slice(self):
x = paddle.randn((10, 10))
self.assert_results(foo, x)
if __name__ == "__main__":
unittest.main()
+84
View File
@@ -0,0 +1,84 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import unittest
from test_case_base import (
TestCaseBase,
test_instruction_translator_cache_context,
)
import paddle
from paddle.jit.sot.utils.envs import allow_dynamic_shape_guard
def foo(x: list[paddle.Tensor], y: list[paddle.Tensor]):
return x[0] + y[0]
def bar(x: list[paddle.Tensor], y: int, z: int):
return x[y + z] + 1
class TestTraceListArg(TestCaseBase):
def test_foo(self):
a = paddle.to_tensor(1)
b = paddle.to_tensor(2)
c = paddle.to_tensor([3, 4])
with test_instruction_translator_cache_context() as cache:
self.assert_results(foo, [a], [b])
self.assertEqual(cache.translate_count, 1)
self.assert_results(foo, [b], [a]) # Cache hit
self.assertEqual(cache.translate_count, 1)
self.assert_results(foo, [a], [c]) # Cache miss
self.assertEqual(cache.translate_count, 2)
@allow_dynamic_shape_guard(False)
def test_bar_static_shape(self):
a = [paddle.to_tensor(1), paddle.to_tensor(2), paddle.to_tensor(3)]
b = [paddle.to_tensor([2, 3]), paddle.to_tensor(4), paddle.to_tensor(5)]
with test_instruction_translator_cache_context() as cache:
self.assert_results(bar, a, 1, 1)
self.assertEqual(cache.translate_count, 1)
self.assert_results(bar, a, 2, 0) # Cache miss
self.assertEqual(cache.translate_count, 2)
self.assert_results(bar, b, 1, 1) # Cache hit
self.assertEqual(cache.translate_count, 2)
@allow_dynamic_shape_guard(True)
def test_bar_dynamic_shape(self):
# TODO(zrr1999): mv to dynamic shape test
a = [paddle.to_tensor(1), paddle.to_tensor(2), paddle.to_tensor(3)]
b = [paddle.to_tensor([2, 3]), paddle.to_tensor(4), paddle.to_tensor(5)]
with test_instruction_translator_cache_context() as cache:
self.assert_results(bar, a, 1, 1)
self.assertEqual(cache.translate_count, 1)
self.assert_results(bar, a, 2, 0) # Cache miss
self.assertEqual(cache.translate_count, 2)
self.assert_results(bar, b, 2, 0) # Cache hit
self.assertEqual(cache.translate_count, 3)
self.assert_results(bar, b, 2, 0) # Cache hit
self.assertEqual(cache.translate_count, 3)
self.assert_results(bar, b, 1, 1) # Cache hit
self.assertEqual(cache.translate_count, 3)
self.assert_results(bar, b, 0, 2) # Cache miss
self.assertEqual(cache.translate_count, 4)
if __name__ == "__main__":
unittest.main()
+37
View File
@@ -0,0 +1,37 @@
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from test_case_base import TestCaseBase
import paddle
from paddle.jit.sot.utils import strict_mode_guard
def call_locals(x: int, y: paddle.Tensor):
tmp = locals()
return x + y + len(list(tmp.keys())), list(tmp.keys())
class TestUnsupportedFunction(TestCaseBase):
@strict_mode_guard(False)
def test_locals(self):
x = paddle.to_tensor([2])
y = paddle.to_tensor([3])
self.assert_results(call_locals, x, y)
if __name__ == "__main__":
unittest.main()

Some files were not shown because too many files have changed in this diff Show More