diff --git a/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.cc b/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.cc index 9879616b42f..3e571030327 100644 --- a/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.cc +++ b/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.cc @@ -26,11 +26,14 @@ namespace mindspore { namespace abstract { HealthPointMgr HealthPointMgr::instance_; +void HealthPointMgr::Clear() { point_ = 1; } + void HealthPointMgr::HandleException() { std::lock_guard lock(lock_); for (auto &item : asyncAbstractList_) { item->SetRunable(); } + asyncAbstractList_.clear(); } void HealthPointMgr::SetNextRunable() { std::lock_guard lock(lock_); @@ -43,8 +46,7 @@ void HealthPointMgr::SetNextRunable() { [](const auto &item) { return item->HasResult(); }); if (it == asyncAbstractList_.end()) { // Enter endless loop if there is not ready result. - MS_LOG(EXCEPTION) << "Enter endless loop. Please check the code. point = " - << " point:" << HealthPointMgr::GetInstance().point() + MS_LOG(EXCEPTION) << "Enter endless loop. Please check the code. point = " << HealthPointMgr::GetInstance().point() << " Called times : " << asyncAbstractList_.front()->count(); } asyncAbstractList_.insert(asyncAbstractList_.end(), asyncAbstractList_.begin(), it); @@ -110,13 +112,14 @@ AbstractBasePtr AnalysisResultCacheMgr::GetSwitchValue(const AnfNodeConfigPtr &c // Conf has been visited and set value. if (async_eval_result != nullptr) { // Add to schedule - HealthPointMgr::GetInstance().PushBack(async_eval_result); + HealthPointMgr::GetInstance().Add2Schedule(async_eval_result); // Maybe blocked for waiting. AsyncAbstract maybe null, if time out. auto result = async_eval_result->GetResult(); if (result == nullptr) { result = std::make_shared(); - MS_LOG(ERROR) << "AsyncAbstract for NodeConfig " << conf->node()->ToString() << " is nullptr, maybe timeout."; - MS_LOG(ERROR) << "detail:" << conf->ToString(); + MS_LOG(ERROR) << "AsyncAbstract of NodeConfig " << conf->node()->ToString() + << " is nullptr. There is something wrong."; + StaticAnalysisException::Instance().CheckException(); } return result; } diff --git a/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.h b/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.h index 76280192221..1debf0bdfc2 100644 --- a/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.h +++ b/mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.h @@ -42,7 +42,9 @@ class HealthPointMgr { HealthPointMgr(const HealthPointMgr &) = delete; HealthPointMgr &operator=(const HealthPointMgr &) = delete; static HealthPointMgr &GetInstance() { return instance_; } + void Clear(); void SetNextRunable(); + void HandleException(); void CheckPoint() { MS_LOG(DEBUG) << "The Health Point is " << point_; @@ -59,8 +61,6 @@ class HealthPointMgr { CheckPoint(); } - void HandleException(); - void AddPoint() { std::lock_guard lock(lock_); ++point_; @@ -68,9 +68,9 @@ class HealthPointMgr { int point() { return point_; } - void PushBack(const AsyncAbstractPtr &base) { + void Add2Schedule(const AsyncAbstractPtr &asyncAbastract) { std::lock_guard lock(lock_); - asyncAbstractList_.push_back(base); + asyncAbstractList_.push_back(asyncAbastract); } private: @@ -198,9 +198,9 @@ class AsyncAbstract : public std::enable_shared_from_this { hasDropPoint = true; } - MS_LOG(DEBUG) << this << " ranable: " << runable_ << " result: " << (result_ ? result_.get() : 0); + MS_LOG(DEBUG) << this << " runable: " << runable_ << " result: " << (result_ ? result_.get() : 0); condition_var_.wait(lock, [this] { return runable_; }); - MS_LOG(DEBUG) << this << " continue ranable: " << runable_ << " result: " << (result_ ? result_.get() : 0); + MS_LOG(DEBUG) << this << " continue runable: " << runable_ << " result: " << (result_ ? result_.get() : 0); StaticAnalysisException::Instance().CheckException(); runable_ = false; if (result_ != nullptr) { @@ -211,14 +211,14 @@ class AsyncAbstract : public std::enable_shared_from_this { return result_; } // Push to list - HealthPointMgr::GetInstance().PushBack(shared_from_this()); + HealthPointMgr::GetInstance().Add2Schedule(shared_from_this()); if (hasDropPoint) { HealthPointMgr::GetInstance().AddPoint(); } // Notify the next asyncAbastract to run. HealthPointMgr::GetInstance().SetNextRunable(); MS_LOG(DEBUG) << this << " SetNextRunable " - << " ranable: " << runable_ << " result: " << (result_ ? result_.get() : 0) + << " runable: " << runable_ << " result: " << (result_ ? result_.get() : 0) << " point:" << HealthPointMgr::GetInstance().point(); } return nullptr; diff --git a/mindspore/ccsrc/pipeline/jit/static_analysis/static_analysis.cc b/mindspore/ccsrc/pipeline/jit/static_analysis/static_analysis.cc index 2b91c8fc349..524929ed003 100644 --- a/mindspore/ccsrc/pipeline/jit/static_analysis/static_analysis.cc +++ b/mindspore/ccsrc/pipeline/jit/static_analysis/static_analysis.cc @@ -119,6 +119,7 @@ bool AnfNodeConfigEqual::operator()(const AnfNodeConfigPtr lhs, const AnfNodeCon AnalysisResult AnalysisEngine::Run(const FuncGraphPtr &func_graph, const AbstractBasePtrList &args_spec_list) { StaticAnalysisException::Instance().ClearException(); + HealthPointMgr::GetInstance().Clear(); ConfigPtrList args_conf_list; (void)std::transform(args_spec_list.begin(), args_spec_list.end(), std::back_inserter(args_conf_list), [](const AbstractBasePtr &arg) -> ConfigPtr { return std::make_shared(arg); }); @@ -889,12 +890,12 @@ EvalResultPtr AnalysisEngine::ExecuteMultipleEvaluatorsMultiThread(const std::ve asyncRun0->JoinResult(std::make_shared(0)); asyncRun1->JoinResult(std::make_shared(0)); // Run order - HealthPointMgr::GetInstance().PushBack(asyncRun0); // First order - HealthPointMgr::GetInstance().PushBack(asyncRun1); // Second order + HealthPointMgr::GetInstance().Add2Schedule(asyncRun0); // First order + HealthPointMgr::GetInstance().Add2Schedule(asyncRun1); // Second order MS_LOG(DEBUG) << GetInferThread() << "async : wait for one of async to finish. " << evaluators[0]->ToString() << " or " << evaluators[1]->ToString(); - HealthPointMgr::GetInstance().PushBack(asyncResult_main); // Third order + HealthPointMgr::GetInstance().Add2Schedule(asyncResult_main); // Third order auto branchResult = asyncResult_main->GetResult(); if (branchResult == nullptr || branchResult->isa()) { MS_LOG(EXCEPTION) << "Can't finish " << evaluators[0]->ToString() << " or " << evaluators[1]->ToString() @@ -911,7 +912,7 @@ EvalResultPtr AnalysisEngine::ExecuteMultipleEvaluatorsMultiThread(const std::ve if (NeedWaitForTwoBranches(branchResult)) { MS_LOG(DEBUG) << GetInferThread() << "async waiting for " << evaluators[0]->ToString(); // The asyncRun0 will eval asyncResult0 - HealthPointMgr::GetInstance().PushBack(asyncResult0); + HealthPointMgr::GetInstance().Add2Schedule(asyncResult0); auto result0 = asyncResult0->GetResult(); if (result0 == nullptr || result0->isa()) { MS_LOG(EXCEPTION) << "Eval " << evaluators[0]->ToString() << " is time out." @@ -921,7 +922,7 @@ EvalResultPtr AnalysisEngine::ExecuteMultipleEvaluatorsMultiThread(const std::ve MS_LOG(DEBUG) << GetInferThread() << "async waiting for " << evaluators[1]->ToString(); // The asyncRun1 will eval asyncResult1 - HealthPointMgr::GetInstance().PushBack(asyncResult1); + HealthPointMgr::GetInstance().Add2Schedule(asyncResult1); auto result1 = asyncResult1->GetResult(); if (result1 == nullptr || result1->isa()) { MS_LOG(EXCEPTION) << "Eval " << evaluators[1]->ToString() << " is time out." @@ -930,7 +931,7 @@ EvalResultPtr AnalysisEngine::ExecuteMultipleEvaluatorsMultiThread(const std::ve out_specs.push_back(result1); } else { // Next time to get the result of branches. - HealthPointMgr::GetInstance().PushBack(asyncResult_main); + HealthPointMgr::GetInstance().Add2Schedule(asyncResult_main); (void)asyncResult_main->GetResult(); // Don't use GetResult diff --git a/tests/st/control/test_fun_fun.py b/tests/st/control/test_fun_fun.py new file mode 100644 index 00000000000..59af698c110 --- /dev/null +++ b/tests/st/control/test_fun_fun.py @@ -0,0 +1,46 @@ +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 mindspore.context as context +from mindspore import Tensor, ms_function +from mindspore.common import dtype as mstype + + +@ms_function +def hof(x): + def f(x): + return x + 3 + + def k(x): + return x - 1 + + def g(x): + if x < 5: + return f + return k + + ret = g(x)(x) + return ret + + +def test_fun_fun(): + context.set_context(mode=context.GRAPH_MODE) + x = Tensor([10], mstype.int32) + ret = hof(x) + expect = Tensor([9], mstype.int32) + assert ret == expect + + +if __name__ == "__main__": + test_fun_fun() diff --git a/tests/st/control/test_recrusive_fun.py b/tests/st/control/test_recrusive_fun.py new file mode 100644 index 00000000000..71210a663ba --- /dev/null +++ b/tests/st/control/test_recrusive_fun.py @@ -0,0 +1,67 @@ +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 mindspore.context as context +from mindspore import Tensor, ms_function +from mindspore.common import dtype as mstype +import pytest + +ZERO = Tensor([0], mstype.int32) +ONE = Tensor([1], mstype.int32) + + +@ms_function +def f(x): + y = f(x - 4) + if x < 0: + y = f(x - 3) + elif x < 3: + y = x * f(x - 1) + elif x >= 3: + y = x * f(x - 2) + z = y + 1 + return z + + +@ms_function +def fr(x): + y = ZERO + if x < 0: + y = ONE + elif x < 3: + y = x * fr(x - 1) + elif x >= 3: + y = x * fr(x - 2) + z = y + 1 + return z + + +def test_endless(): + context.set_context(mode=context.GRAPH_MODE) + x = Tensor([5], mstype.int32) + f(x) + with pytest.raises(ValueError): + print("endless.") + + +def test_recrusive_fun(): + context.set_context(mode=context.GRAPH_MODE) + x = Tensor([5], mstype.int32) + ret = fr(x) + expect = Tensor([36], mstype.int32) + assert ret == expect + + +if __name__ == "__main__": + test_recrusive_fun()