315 lines
7.8 KiB
Python
315 lines
7.8 KiB
Python
# Copyright (c) 2020 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
|
|
|
|
import numpy as np
|
|
from dygraph_to_static_utils import (
|
|
Dy2StTestBase,
|
|
)
|
|
from numpy import append
|
|
|
|
import paddle
|
|
from paddle.jit.dy2static.transformers.utils import FunctionNameLivenessAnalysis
|
|
from paddle.utils import gast
|
|
|
|
global_a = []
|
|
|
|
|
|
class JudgeVisitor(gast.NodeVisitor):
|
|
def __init__(self, ans, mod):
|
|
self.ans = ans
|
|
self.mod = mod
|
|
|
|
def visit_FunctionDef(self, node):
|
|
scope = node.pd_scope
|
|
expected = self.ans.get(node.name, set())
|
|
exp_mod = self.mod.get(node.name, set())
|
|
assert scope.existed_vars() == expected, "Not Equals."
|
|
assert scope.modified_vars() == exp_mod, (
|
|
f"Not Equals in function:{node.name} . expect {exp_mod} , but get {scope.modified_vars()}"
|
|
)
|
|
self.generic_visit(node)
|
|
|
|
|
|
class JudgePushPopVisitor(gast.NodeVisitor):
|
|
def __init__(self, push_pop_vars):
|
|
self.pp_var = push_pop_vars
|
|
|
|
def visit_FunctionDef(self, node):
|
|
scope = node.pd_scope
|
|
expected = self.pp_var.get(node.name, set())
|
|
assert scope.push_pop_vars == expected, (
|
|
f"Not Equals in function:{node.name} . expect {expected} , but get {scope.push_pop_vars}"
|
|
)
|
|
self.generic_visit(node)
|
|
|
|
|
|
def test_normal_0(x):
|
|
def func():
|
|
if True:
|
|
i = 1
|
|
|
|
func()
|
|
return i
|
|
|
|
|
|
def test_normal_argument(x):
|
|
x = 1
|
|
|
|
def func():
|
|
if True:
|
|
print(x)
|
|
i = 1
|
|
|
|
func()
|
|
return x
|
|
|
|
|
|
def test_global(x):
|
|
global t
|
|
t = 10
|
|
|
|
def func():
|
|
if True:
|
|
print(x)
|
|
i = 1
|
|
|
|
func()
|
|
return x
|
|
|
|
|
|
def test_nonlocal(x, *args, **kargs):
|
|
i = 10
|
|
|
|
def func(*args, **kargs):
|
|
nonlocal i
|
|
k = 10
|
|
if True:
|
|
print(x)
|
|
i = 1
|
|
|
|
func(*args, **kargs)
|
|
return x
|
|
|
|
|
|
def test_push_pop_1(x, *args, **kargs):
|
|
"""push_pop_vars in main_function is : `l`, `k`"""
|
|
l = []
|
|
k = []
|
|
for i in range(10):
|
|
l.append(i)
|
|
k.pop(i)
|
|
return l
|
|
|
|
|
|
def test_push_pop_2(x, *args, **kargs):
|
|
"""push_pop_vars in main_function is : `k`"""
|
|
l = []
|
|
k = []
|
|
|
|
def func():
|
|
l.append(0)
|
|
|
|
for i in range(10):
|
|
k.append(i)
|
|
return l, k
|
|
|
|
|
|
def test_push_pop_3(x, *args, **kargs):
|
|
"""push_pop_vars in main_function is : `k`
|
|
NOTE: One may expect `k` and `l` because l
|
|
is nonlocal. Name bind analysis is
|
|
not implemented yet.
|
|
"""
|
|
l = []
|
|
k = []
|
|
|
|
def func():
|
|
nonlocal l
|
|
l.append(0)
|
|
|
|
for i in range(10):
|
|
k.append(i)
|
|
return l, k
|
|
|
|
|
|
def test_push_pop_4(x, *args, **kargs):
|
|
"""push_pop_vars in main_function is : `k`"""
|
|
l = []
|
|
k = []
|
|
for i in range(10):
|
|
for j in range(10):
|
|
if True:
|
|
l.append(j)
|
|
else:
|
|
k.pop()
|
|
return l, k
|
|
|
|
|
|
class TestClosureAnalysis(Dy2StTestBase):
|
|
def setUp(self):
|
|
self.judge_type = "var and w_vars"
|
|
self.init_dygraph_func()
|
|
|
|
def init_dygraph_func(self):
|
|
self.all_dygraph_funcs = [
|
|
test_nonlocal,
|
|
test_global,
|
|
test_normal_0,
|
|
test_normal_argument,
|
|
]
|
|
self.answer = [
|
|
{'func': set('k'), 'test_nonlocal': set('i')},
|
|
{
|
|
'func': set({'i'}),
|
|
},
|
|
{
|
|
'func': set('i'),
|
|
},
|
|
{
|
|
'func': set('i'),
|
|
},
|
|
]
|
|
|
|
self.modified_var = [
|
|
{'func': set('ki'), 'test_nonlocal': set('i')},
|
|
{'func': set({'i'}), 'test_global': set({"t"})},
|
|
{
|
|
'func': set('i'),
|
|
},
|
|
{'func': set('i'), 'test_normal_argument': set('x')},
|
|
]
|
|
|
|
def test_main(self):
|
|
if self.judge_type == 'push_pop_vars':
|
|
for push_pop_vars, func in zip(
|
|
self.push_pop_vars, self.all_dygraph_funcs
|
|
):
|
|
test_func = inspect.getsource(func)
|
|
gast_root = gast.parse(test_func)
|
|
name_visitor = FunctionNameLivenessAnalysis(gast_root)
|
|
JudgePushPopVisitor(push_pop_vars).visit(gast_root)
|
|
else:
|
|
for mod, ans, func in zip(
|
|
self.modified_var, self.answer, self.all_dygraph_funcs
|
|
):
|
|
test_func = inspect.getsource(func)
|
|
gast_root = gast.parse(test_func)
|
|
name_visitor = FunctionNameLivenessAnalysis(gast_root)
|
|
JudgeVisitor(ans, mod).visit(gast_root)
|
|
|
|
|
|
def TestClosureAnalysis_Attribute_func():
|
|
# in this function, only self is a Name, self.current is a Attribute. self is read and self.current.function is store()
|
|
i = 0
|
|
self.current.function = 12
|
|
|
|
|
|
class TestClosureAnalysis_Attribute(TestClosureAnalysis):
|
|
def init_dygraph_func(self):
|
|
self.all_dygraph_funcs = [TestClosureAnalysis_Attribute_func]
|
|
self.answer = [{"TestClosureAnalysis_Attribute_func": set({'i'})}]
|
|
self.modified_var = [
|
|
{
|
|
"TestClosureAnalysis_Attribute_func": set(
|
|
{'i', 'self.current.function'}
|
|
)
|
|
}
|
|
]
|
|
|
|
|
|
class TestClosureAnalysis_PushPop(TestClosureAnalysis):
|
|
def init_dygraph_func(self):
|
|
self.judge_type = "push_pop_vars"
|
|
self.all_dygraph_funcs = [
|
|
test_push_pop_1,
|
|
test_push_pop_2,
|
|
test_push_pop_3,
|
|
test_push_pop_4,
|
|
]
|
|
self.push_pop_vars = [
|
|
{
|
|
"test_push_pop_1": set({'l', 'k'}),
|
|
},
|
|
{
|
|
"test_push_pop_2": set({'k'}),
|
|
"func": set("l"),
|
|
},
|
|
{
|
|
"test_push_pop_3": set({'k'}),
|
|
"func": set("l"),
|
|
},
|
|
{
|
|
"test_push_pop_4": set({'k', 'l'}),
|
|
},
|
|
]
|
|
|
|
|
|
class TestPushPopTrans(Dy2StTestBase):
|
|
def test(self):
|
|
def vlist_of_dict(x):
|
|
ma = {'a': []}
|
|
for i in range(3):
|
|
ma['a'].append(1)
|
|
return ma
|
|
|
|
x = paddle.to_tensor([3])
|
|
print(paddle.jit.to_static(vlist_of_dict)(x))
|
|
|
|
def test2(self):
|
|
def vlist_of_dict(x):
|
|
a = np.array([1, 2, 3])
|
|
for i in range(3):
|
|
np.append(a, 4)
|
|
return a
|
|
|
|
x = paddle.to_tensor([3])
|
|
print(paddle.jit.to_static(vlist_of_dict)(x))
|
|
|
|
def test3(self):
|
|
def vlist_of_dict(x):
|
|
a = np.array([1, 2, 3])
|
|
if True:
|
|
pass
|
|
return a
|
|
|
|
x = paddle.to_tensor([3])
|
|
print(paddle.jit.to_static(vlist_of_dict)(x))
|
|
|
|
def test4(self):
|
|
def vlist_of_dict(x):
|
|
a = np.array([1, 2, 3])
|
|
for i in range(3):
|
|
append(a, 4)
|
|
return a
|
|
|
|
x = paddle.to_tensor([3])
|
|
print(paddle.jit.to_static(vlist_of_dict)(x))
|
|
|
|
def test5(self):
|
|
def vlist_of_dict(x):
|
|
a = np.array([1, 2, 3])
|
|
for i in range(3):
|
|
global_a.append(4)
|
|
return a
|
|
|
|
x = paddle.to_tensor([3])
|
|
print(paddle.jit.to_static(vlist_of_dict)(x))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|