2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <gtest/gtest.h>
22 #include "interp/InterpExecutor.h"
23 #include "exec/Execution.h"
24 #include "ir/operation/BinaryArithmetic.h"
29 using namespace onert::ir;
30 using InterpExecutor = onert::interp::InterpExecutor;
31 using Execution = onert::exec::Execution;
32 using ExecutorMap = onert::exec::ExecutorMap;
34 class InterpExecutorTest : public ::testing::Test
37 virtual void SetUp() {}
38 void CreateSimpleModel()
40 // Model: one elementwise add operation
41 // model input: lhs, rhs
42 // model output: add result
43 // lhs, rhs, result shape: {1, 2, 2, 1}
44 // activation: none (constant)
45 _graph = std::make_unique<Graph>();
49 Shape shape{1, 2, 2, 1};
50 TypeInfo type{DataType::INT32};
51 Shape shape_scalar(0);
52 TypeInfo type_scalar{DataType::INT32};
54 auto operand_lhs = _graph->addOperand(shape, type);
55 auto operand_rhs = _graph->addOperand(shape, type);
56 auto operand_result = _graph->addOperand(shape, type);
60 operation::BinaryArithmetic::Param param;
61 param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
62 param.activation = Activation::NONE;
63 auto input_set = OperandIndexSequence{operand_lhs, operand_rhs};
64 auto output_set = OperandIndexSequence{operand_result};
66 std::make_unique<operation::BinaryArithmetic>(input_set, output_set, param));
68 // Identify model inputs and outputs
70 _graph->getInputs().append(operand_lhs);
71 _graph->getInputs().append(operand_rhs);
72 _graph->getOutputs().append(operand_result);
74 _graph->finishBuilding();
76 auto subgs = std::make_shared<onert::ir::Subgraphs>();
77 subgs->push(onert::ir::SubgraphIndex{0}, _graph);
78 _graph->setSubgraphs(subgs);
80 _executors = std::make_shared<ExecutorMap>();
82 std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
85 void CreateTwoStepModel()
87 // Model: two elementwise add operation
88 // model input: lhs, rhs1
89 // model output: second add result (result2)
91 // result1 <= (lhs + rhs)
92 // result2 <= (result1 + rhs2)
93 // lhs, rhs1, rh2, result1, result2 shape: {1, 2, 2, 1}
94 // activation: none (constant)
95 _graph = std::make_unique<Graph>();
97 // 1st add operands (result1 <= lhs + rhs1)
99 Shape shape{1, 2, 2, 1};
100 TypeInfo type{DataType::INT32};
101 Shape shape_scalar(0);
102 TypeInfo type_scalar{DataType::INT32};
104 static int32_t rhs2_data[4] = {3, 1, -1, 5};
106 auto operand_lhs = _graph->addOperand(shape, type);
107 auto operand_rhs1 = _graph->addOperand(shape, type);
108 auto operand_result1 = _graph->addOperand(shape, type);
109 auto operand_rhs2 = _graph->addOperand(shape, type);
110 auto operand_result2 = _graph->addOperand(shape, type);
113 .data(std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&rhs2_data), 16));
115 // 2nd add operations (result2 <= result1 + rhs2)
117 operation::BinaryArithmetic::Param param1;
118 param1.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
119 param1.activation = Activation::NONE;
120 auto input_set1 = OperandIndexSequence{operand_lhs, operand_rhs1};
121 auto output_set1 = OperandIndexSequence{operand_result1};
122 _graph->addOperation(
123 std::make_unique<operation::BinaryArithmetic>(input_set1, output_set1, param1));
125 operation::BinaryArithmetic::Param param2;
126 param2.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
127 param2.activation = Activation::NONE;
128 auto input_set2 = OperandIndexSequence{operand_result1, operand_rhs2};
129 auto output_set2 = OperandIndexSequence{operand_result2};
130 _graph->addOperation(
131 std::make_unique<operation::BinaryArithmetic>(input_set2, output_set2, param2));
133 // Identify model inputs and outputs
135 _graph->getInputs().append(operand_lhs);
136 _graph->getInputs().append(operand_rhs1);
137 _graph->getOutputs().append(operand_result2);
139 _graph->finishBuilding();
141 auto subgs = std::make_shared<onert::ir::Subgraphs>();
142 subgs->push(onert::ir::SubgraphIndex{0}, _graph);
143 _graph->setSubgraphs(subgs);
145 _executors = std::make_shared<ExecutorMap>();
147 std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
150 void CreateUnspecifiedDimensionsModel()
152 // Model: one elementwise add operation
153 // model input: lhs, rhs
154 // model output: add result
155 // lhs, rhs, result shape: {1, unknown, 2, 1}
156 // activation: none (constant)
157 _graph = std::make_unique<Graph>();
161 Shape shape{1, 0, 2, 1};
162 TypeInfo type{DataType::INT32};
163 Shape shape_scalar(0);
164 TypeInfo type_scalar{DataType::INT32};
166 auto operand_lhs = _graph->addOperand(shape, type);
167 auto operand_rhs = _graph->addOperand(shape, type);
169 auto operand_activation = _graph->addOperand(shape_scalar, type_scalar);
171 .at(operand_activation)
173 std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&_activation_value), 4));
175 auto operand_result = _graph->addOperand(shape, type);
179 operation::BinaryArithmetic::Param param;
180 param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
181 param.activation = Activation::NONE;
182 auto input_set = OperandIndexSequence{operand_lhs, operand_rhs};
183 auto output_set = OperandIndexSequence{operand_result};
184 _graph->addOperation(
185 std::make_unique<operation::BinaryArithmetic>(input_set, output_set, param));
187 // Identify model inputs and outputs
189 _graph->getInputs().append(operand_lhs);
190 _graph->getInputs().append(operand_rhs);
191 _graph->getOutputs().append(operand_result);
193 _graph->finishBuilding();
195 auto subgs = std::make_shared<onert::ir::Subgraphs>();
196 subgs->push(onert::ir::SubgraphIndex{0}, _graph);
197 _graph->setSubgraphs(subgs);
199 _executors = std::make_shared<ExecutorMap>();
201 std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
204 void createExecution() { _execution = std::make_unique<Execution>(_executors); }
206 virtual void TearDown() { _executors = nullptr; }
208 std::shared_ptr<Graph> _graph{nullptr};
209 std::shared_ptr<ExecutorMap> _executors{nullptr};
210 std::unique_ptr<Execution> _execution{nullptr};
211 const int32_t _activation_value{0};
214 TEST_F(InterpExecutorTest, create_empty)
217 graph.finishBuilding();
218 auto executor = std::make_unique<InterpExecutor>(graph);
219 ASSERT_NE(executor, nullptr);
222 TEST_F(InterpExecutorTest, create_simple)
225 ASSERT_NE(_executors, nullptr);
226 ASSERT_NE(_executors->at(onert::ir::SubgraphIndex{0}), nullptr);
229 TEST_F(InterpExecutorTest, neg_setInput)
234 auto input1 = IOIndex{0};
235 const int32_t input1_buffer[4] = {1, 0, -1, -2};
237 EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 4),
239 EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 12),
241 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
244 TEST_F(InterpExecutorTest, neg_setOutput)
249 auto output = IOIndex{0};
250 auto output_idx = _graph->getOutputs().at(output);
252 int32_t output_buffer[4] = {};
254 EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 4),
256 EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 12),
258 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
261 TEST_F(InterpExecutorTest, neg_setInputForUnspecifiedDimensions)
263 CreateUnspecifiedDimensionsModel();
266 auto input1 = IOIndex{0};
267 const int32_t input1_buffer[4] = {1, 0, -1, -2};
269 TypeInfo operand_type{DataType::INT32};
270 Shape operand_shape{1, 2, 2, 1};
272 EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
273 reinterpret_cast<const void *>(input1_buffer), 4),
275 EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
276 reinterpret_cast<const void *>(input1_buffer), 12),
278 EXPECT_NO_THROW(_execution->setInput(input1, operand_type, operand_shape,
279 reinterpret_cast<const void *>(input1_buffer), 16));
282 TEST_F(InterpExecutorTest, neg_setOutputForUnspecifiedDimensions)
284 CreateUnspecifiedDimensionsModel();
287 auto output = IOIndex{0};
288 auto output_idx = _graph->getOutputs().at(output);
290 TypeInfo operand_type{DataType::INT32};
291 Shape operand_shape{1, 2, 2, 1};
293 int32_t output_buffer[4] = {};
295 EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
296 reinterpret_cast<void *>(output_buffer), 4),
298 EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
299 reinterpret_cast<void *>(output_buffer), 12),
301 EXPECT_NO_THROW(_execution->setOutput(output, operand_type, operand_shape,
302 reinterpret_cast<void *>(output_buffer), 16));
305 TEST_F(InterpExecutorTest, execute)
310 auto input1 = IOIndex{0};
311 auto input2 = IOIndex{1};
312 auto input1_idx = _graph->getInputs().at(input1);
313 auto input2_idx = _graph->getInputs().at(input2);
315 const int32_t input1_buffer[4] = {1, 0, -1, -2};
316 const int32_t input2_buffer[4] = {1, -3, 2, -4};
318 auto output = IOIndex{0};
319 auto output_idx = _graph->getOutputs().at(output);
321 int32_t output_buffer[4] = {};
323 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
324 EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
325 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
326 EXPECT_NO_THROW(_execution->execute());
327 EXPECT_EQ(output_buffer[0], 2);
328 EXPECT_EQ(output_buffer[1], -3);
329 EXPECT_EQ(output_buffer[2], 1);
330 EXPECT_EQ(output_buffer[3], -6);
333 TEST_F(InterpExecutorTest, executeTwoStep)
335 CreateTwoStepModel();
338 auto input1 = IOIndex{0};
339 auto input2 = IOIndex{1};
340 auto input1_idx = _graph->getInputs().at(input1);
341 auto input2_idx = _graph->getInputs().at(input2);
343 const int32_t input1_buffer[4] = {1, 0, -1, -2};
344 const int32_t input2_buffer[4] = {1, -3, 2, -4};
346 auto output = IOIndex{0};
347 auto output_idx = _graph->getOutputs().at(output);
349 int32_t output_buffer[4] = {};
351 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
352 EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
353 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
354 EXPECT_NO_THROW(_execution->execute());
355 EXPECT_EQ(output_buffer[0], 5);
356 EXPECT_EQ(output_buffer[1], -2);
357 EXPECT_EQ(output_buffer[2], 0);
358 EXPECT_EQ(output_buffer[3], -1);