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)
172 .data(std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&_activation_value), 4));
174 auto operand_result = _graph->addOperand(shape, type);
178 operation::BinaryArithmetic::Param param;
179 param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
180 param.activation = Activation::NONE;
181 auto input_set = OperandIndexSequence{operand_lhs, operand_rhs};
182 auto output_set = OperandIndexSequence{operand_result};
183 _graph->addOperation(
184 std::make_unique<operation::BinaryArithmetic>(input_set, output_set, param));
186 // Identify model inputs and outputs
188 _graph->getInputs().append(operand_lhs);
189 _graph->getInputs().append(operand_rhs);
190 _graph->getOutputs().append(operand_result);
192 _graph->finishBuilding();
194 auto subgs = std::make_shared<onert::ir::Subgraphs>();
195 subgs->push(onert::ir::SubgraphIndex{0}, _graph);
196 _graph->setSubgraphs(subgs);
198 _executors = std::make_shared<ExecutorMap>();
200 std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
203 void createExecution() { _execution = std::make_unique<Execution>(_executors); }
205 virtual void TearDown() { _executors = nullptr; }
207 std::shared_ptr<Graph> _graph{nullptr};
208 std::shared_ptr<ExecutorMap> _executors{nullptr};
209 std::unique_ptr<Execution> _execution{nullptr};
210 const int32_t _activation_value{0};
213 TEST_F(InterpExecutorTest, create_empty)
216 graph.finishBuilding();
217 auto executor = std::make_unique<InterpExecutor>(graph);
218 ASSERT_NE(executor, nullptr);
221 TEST_F(InterpExecutorTest, create_simple)
224 ASSERT_NE(_executors, nullptr);
225 ASSERT_NE(_executors->at(onert::ir::SubgraphIndex{0}), nullptr);
228 TEST_F(InterpExecutorTest, neg_setInput)
233 auto input1 = IOIndex{0};
234 const int32_t input1_buffer[4] = {1, 0, -1, -2};
236 EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 4),
238 EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 12),
240 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
243 TEST_F(InterpExecutorTest, neg_setOutput)
248 auto output = IOIndex{0};
249 auto output_idx = _graph->getOutputs().at(output);
251 int32_t output_buffer[4] = {};
253 EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 4),
255 EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 12),
257 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
260 TEST_F(InterpExecutorTest, neg_setInputForUnspecifiedDimensions)
262 CreateUnspecifiedDimensionsModel();
265 auto input1 = IOIndex{0};
266 const int32_t input1_buffer[4] = {1, 0, -1, -2};
268 TypeInfo operand_type{DataType::INT32};
269 Shape operand_shape{1, 2, 2, 1};
271 EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
272 reinterpret_cast<const void *>(input1_buffer), 4),
274 EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
275 reinterpret_cast<const void *>(input1_buffer), 12),
277 EXPECT_NO_THROW(_execution->setInput(input1, operand_type, operand_shape,
278 reinterpret_cast<const void *>(input1_buffer), 16));
281 TEST_F(InterpExecutorTest, neg_setOutputForUnspecifiedDimensions)
283 CreateUnspecifiedDimensionsModel();
286 auto output = IOIndex{0};
287 auto output_idx = _graph->getOutputs().at(output);
289 TypeInfo operand_type{DataType::INT32};
290 Shape operand_shape{1, 2, 2, 1};
292 int32_t output_buffer[4] = {};
294 EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
295 reinterpret_cast<void *>(output_buffer), 4),
297 EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
298 reinterpret_cast<void *>(output_buffer), 12),
300 EXPECT_NO_THROW(_execution->setOutput(output, operand_type, operand_shape,
301 reinterpret_cast<void *>(output_buffer), 16));
304 TEST_F(InterpExecutorTest, execute)
309 auto input1 = IOIndex{0};
310 auto input2 = IOIndex{1};
311 auto input1_idx = _graph->getInputs().at(input1);
312 auto input2_idx = _graph->getInputs().at(input2);
314 const int32_t input1_buffer[4] = {1, 0, -1, -2};
315 const int32_t input2_buffer[4] = {1, -3, 2, -4};
317 auto output = IOIndex{0};
318 auto output_idx = _graph->getOutputs().at(output);
320 int32_t output_buffer[4] = {};
322 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
323 EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
324 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
325 EXPECT_NO_THROW(_execution->execute());
326 EXPECT_EQ(output_buffer[0], 2);
327 EXPECT_EQ(output_buffer[1], -3);
328 EXPECT_EQ(output_buffer[2], 1);
329 EXPECT_EQ(output_buffer[3], -6);
332 TEST_F(InterpExecutorTest, executeTwoStep)
334 CreateTwoStepModel();
337 auto input1 = IOIndex{0};
338 auto input2 = IOIndex{1};
339 auto input1_idx = _graph->getInputs().at(input1);
340 auto input2_idx = _graph->getInputs().at(input2);
342 const int32_t input1_buffer[4] = {1, 0, -1, -2};
343 const int32_t input2_buffer[4] = {1, -3, 2, -4};
345 auto output = IOIndex{0};
346 auto output_idx = _graph->getOutputs().at(output);
348 int32_t output_buffer[4] = {};
350 EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
351 EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
352 EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
353 EXPECT_NO_THROW(_execution->execute());
354 EXPECT_EQ(output_buffer[0], 5);
355 EXPECT_EQ(output_buffer[1], -2);
356 EXPECT_EQ(output_buffer[2], 0);
357 EXPECT_EQ(output_buffer[3], -1);