From: Hanjoung Lee Date: Thu, 10 Sep 2020 04:46:16 +0000 (+0900) Subject: Add logging and test cases for Controlflow ops (#4129) X-Git-Tag: accepted/tizen/6.0/unified/20201030.121029^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_20201012;p=platform%2Fcore%2Fml%2Fnnfw.git Add logging and test cases for Controlflow ops (#4129) - Log subgraph calls during execution so we can trace the execution stack. - Add a OneOp TC for If This is a squashed commit of 465828c0 8aba0221 and 117a4712 . ONE-DCO-1.0-Signed-off-by: Hanjoung Lee Change-Id: Idfa7044145b855222ab8ab382291e2d05af63f78 Signed-off-by: Chunseok Lee --- diff --git a/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc index 8377c71..7ca8224 100644 --- a/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc +++ b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc @@ -63,13 +63,16 @@ void IfLayer::run() }; exec::ExecutorBase *subg_exec = nullptr; - if (getResultCond(_cond_tensor.get())) + bool cond_result = getResultCond(_cond_tensor.get()); + if (cond_result) { + VERBOSE(If) << "Call to $" << _then_subg_index << " (then)" << std::endl; subg_exec = nnfw::misc::polymorphic_downcast( _executor_map->at(_then_subg_index).get()); } else { + VERBOSE(If) << "Call to $" << _else_subg_index << " (else)" << std::endl; subg_exec = nnfw::misc::polymorphic_downcast( _executor_map->at(_else_subg_index).get()); } @@ -120,6 +123,8 @@ void IfLayer::run() // Copy & run subg_exec->execute(_input_tensors, permute_op_input_to_subg_input); permute_subg_output_to_op_output->run(); + VERBOSE(If) << "Return from $" << (cond_result ? _then_subg_index : _else_subg_index) + << std::endl; } } // namespace kernel diff --git a/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc index 50936e5..0d1ae65 100644 --- a/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc +++ b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc @@ -175,7 +175,9 @@ void WhileLayer::run() permute_body_output_to_body_input->prepare(); permute_body_output_to_op_output->prepare(); + VERBOSE(While) << "Call to $" << _cond_subg_index << " (cond)" << std::endl; cond_exec->execute(_input_tensors, permute_op_input_to_cond_input); + VERBOSE(While) << "Return from $" << _cond_subg_index << std::endl; assert(cond_exec->getOutputTensors().size() == 1); auto &cond_output_tensor = cond_exec->getOutputTensors().at(0); @@ -186,16 +188,22 @@ void WhileLayer::run() }; const auto body_execute_with_op_inputs = [&]() { + VERBOSE(While) << "Call to $" << _body_subg_index << " (body)" << std::endl; body_exec->execute(_input_tensors, permute_op_input_to_body_input); + VERBOSE(While) << "Return from $" << _body_subg_index << std::endl; }; const auto body_execute_with_body_outputs = [&]() { + VERBOSE(While) << "Call to $" << _body_subg_index << " (body)" << std::endl; body_exec->execute(body_exec->getOutputTensors(), permute_body_output_to_body_input); + VERBOSE(While) << "Return from $" << _body_subg_index << std::endl; }; std::function body_execute = body_execute_with_op_inputs; const auto cond_execute = [&]() { + VERBOSE(While) << "Call to $" << _cond_subg_index << " (cond)" << std::endl; cond_exec->execute(body_exec->getOutputTensors(), permute_body_output_to_cond_input); + VERBOSE(While) << "Return from $" << _cond_subg_index << std::endl; }; auto permute_to_outputs_fn = permute_op_input_to_op_output; diff --git a/runtime/onert/core/src/exec/IPermuteFunction.h b/runtime/onert/core/src/exec/IPermuteFunction.h index 6b4d153..9bead2f 100644 --- a/runtime/onert/core/src/exec/IPermuteFunction.h +++ b/runtime/onert/core/src/exec/IPermuteFunction.h @@ -50,7 +50,7 @@ private: public: virtual void run() override { - assert(_src_tensors.size() > 0); + // TODO Optimization : Make control does not reach here? when (_src_tensors.size() == 0) assert(_src_tensors.size() == _dst_tensors.size()); auto src_it = _src_tensors.begin(); auto dst_it = _dst_tensors.begin(); diff --git a/tests/nnfw_api/src/CircleGen.cc b/tests/nnfw_api/src/CircleGen.cc index 19cb95f..6ebd5a9 100644 --- a/tests/nnfw_api/src/CircleGen.cc +++ b/tests/nnfw_api/src/CircleGen.cc @@ -183,6 +183,14 @@ uint32_t CircleGen::addOperatorWhile(const OperatorParams ¶ms, uint32_t cond circle::BuiltinOptions_WhileOptions, options); } +uint32_t CircleGen::addOperatorIf(const OperatorParams ¶ms, uint32_t then_subg, + uint32_t else_subg) +{ + auto options = circle::CreateIfOptions(_fbb, then_subg, else_subg).Union(); + return addOperatorWithOptions(params, circle::BuiltinOperator_IF, + circle::BuiltinOptions_IfOptions, options); +} + // NOTE Please add addOperator functions ABOVE this lie // // % How to add a new addOperatorXXX fuction diff --git a/tests/nnfw_api/src/CircleGen.h b/tests/nnfw_api/src/CircleGen.h index 09ca5a5..8cb83bc 100644 --- a/tests/nnfw_api/src/CircleGen.h +++ b/tests/nnfw_api/src/CircleGen.h @@ -108,6 +108,7 @@ public: uint32_t addOperatorRank(const OperatorParams ¶ms); uint32_t addOperatorResizeNearestNeighbor(const OperatorParams ¶ms); uint32_t addOperatorWhile(const OperatorParams ¶ms, uint32_t cond_subg, uint32_t body_subg); + uint32_t addOperatorIf(const OperatorParams ¶ms, uint32_t cond_subg, uint32_t body_subg); // NOTE Please add addOperator functions ABOVE this lie // ===== Add Operator methods end ===== diff --git a/tests/nnfw_api/src/one_op_tests/If.cc b/tests/nnfw_api/src/one_op_tests/If.cc new file mode 100644 index 0000000..2eb1d34 --- /dev/null +++ b/tests/nnfw_api/src/one_op_tests/If.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. 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. + */ + +#include "GenModelTest.h" + +#include + +TEST_F(GenModelTest, OneOp_If) +{ + // The model looks just like the below pseudocode + // + // function model(x) + // { + // if (x < 0.0) + // return -100.0; + // else + // return 100.0; + // } + + CircleGen cgen; + + // constant buffers + std::vector comp_data{0.0}; + uint32_t comp_buf = cgen.addBuffer(comp_data); + std::vector then_data{-100}; + uint32_t then_buf = cgen.addBuffer(then_data); + std::vector else_data{100}; + uint32_t else_buf = cgen.addBuffer(else_data); + + // primary subgraph + { + int x = cgen.addTensor({{1}, circle::TensorType_FLOAT32}); + int comp = cgen.addTensor({{1}, circle::TensorType_FLOAT32, comp_buf}); + int cond = cgen.addTensor({{1}, circle::TensorType_BOOL}); + cgen.addOperatorLess({{x, comp}, {cond}}); + + int ret = cgen.addTensor({{1}, circle::TensorType_FLOAT32}); + cgen.addOperatorIf({{cond}, {ret}}, 1, 2); + + cgen.setInputsAndOutputs({x}, {ret}); + } + + // then subgraph + { + cgen.nextSubgraph(); + int ret = cgen.addTensor({{1}, circle::TensorType_FLOAT32, then_buf}); + cgen.setInputsAndOutputs({}, {ret}); + } + + // else subgraph + { + cgen.nextSubgraph(); + int ret = cgen.addTensor({{1}, circle::TensorType_FLOAT32, else_buf}); + cgen.setInputsAndOutputs({}, {ret}); + } + + _context = std::make_unique(cgen.finish()); + _context->addTestCase({{{-1.0}}, {{-100.0}}}); + _context->addTestCase({{{1.0}}, {{100.0}}}); + _context->setBackends({"cpu"}); + + SUCCEED(); +}