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 "nnfw_api_internal.h"
18 #include "CustomKernelRegistry.h"
19 #include "compiler/Compiler.h"
20 #include "util/ConfigSource.h"
21 #include "util/Exceptions.h"
22 #include "util/logging.h"
23 #include "exec/Execution.h"
24 #include "circle_loader.h"
25 #include "tflite_loader.h"
26 #include "json/json.h"
27 #include "ir/OpCode.h"
28 #include "util/TracingCtx.h"
35 #include <misc/string_helpers.h>
38 * API does not accept string argument longer than max length below
40 #define MAX_BACKEND_NAME_LENGTH 32
41 #define MAX_OP_NAME_LENGTH 64
42 #define MAX_PATH_LENGTH 1024
43 #define MAX_TENSOR_NAME_LENGTH 64
48 // Is null-terminating in length ?
49 bool null_terminating(const char *str, uint32_t length)
51 for (uint32_t i = 0; i < length; i++)
53 if (*(str + i) == '\0')
61 onert::ir::Layout convertLayout(NNFW_LAYOUT layout)
63 if (layout == NNFW_LAYOUT_CHANNELS_LAST)
65 return onert::ir::Layout::NHWC;
67 else if (layout == NNFW_LAYOUT_CHANNELS_FIRST)
69 return onert::ir::Layout::NCHW;
71 return onert::ir::Layout::UNKNOWN;
74 NNFW_STATUS getTensorIndexImpl(const onert::ir::Graph &graph, const char *tensorname,
75 uint32_t *index, bool is_input)
77 if (!tensorname || !index)
78 return NNFW_STATUS_UNEXPECTED_NULL;
80 if (!null_terminating(tensorname, MAX_TENSOR_NAME_LENGTH))
82 std::cerr << "nnpackage path is too long" << std::endl;
83 return NNFW_STATUS_ERROR;
86 auto ind_found = is_input ? graph.getInputIndex(tensorname) : graph.getOutputIndex(tensorname);
88 if (ind_found.undefined())
91 return NNFW_STATUS_ERROR;
95 *index = ind_found.value();
96 return NNFW_STATUS_NO_ERROR;
100 std::string trim(const std::string &value)
102 std::string whitespace = " \t";
103 auto begin = value.find_first_not_of(whitespace);
104 if (begin == std::string::npos)
105 return ""; // no content
107 auto end = value.find_last_not_of(whitespace);
108 auto range = end - begin + 1;
109 return value.substr(begin, range);
112 using CfgKeyValues = std::unordered_map<std::string, std::string>;
114 bool loadConfigure(const std::string cfgfile, CfgKeyValues &keyValues)
116 std::ifstream ifs(cfgfile);
120 while (std::getline(ifs, line))
122 auto cmtpos = line.find('#');
123 if (cmtpos != std::string::npos)
125 line = line.substr(0, cmtpos);
127 std::istringstream isline(line);
129 if (std::getline(isline, key, '='))
132 if (std::getline(isline, value))
135 keyValues[key] = trim(value);
145 void setConfigKeyValues(const CfgKeyValues &keyValues)
147 auto configsrc = std::make_unique<onert::util::GeneralConfigSource>();
149 for (auto it = keyValues.begin(); it != keyValues.end(); ++it)
151 VERBOSE(NNPKG_CONFIGS) << "(" << it->first << ") = (" << it->second << ")" << std::endl;
152 configsrc->set(it->first, it->second);
155 onert::util::config_source_ext(std::move(configsrc));
160 nnfw_session::nnfw_session()
161 : _subgraphs{nullptr}, _execution{nullptr},
162 _kernel_registry{std::make_shared<onert::frontend::custom::KernelRegistry>()}, _tracing_ctx{
168 nnfw_session::~nnfw_session() = default;
170 NNFW_STATUS nnfw_session::load_circle_from_buffer(uint8_t *buffer, size_t size)
172 if (!isStateInitialized())
173 return NNFW_STATUS_INVALID_STATE;
176 return NNFW_STATUS_UNEXPECTED_NULL;
179 return NNFW_STATUS_ERROR;
183 _subgraphs = onert::circle_loader::loadModel(buffer, size);
185 catch (const std::exception &e)
187 std::cerr << "Error during model loading : " << e.what() << std::endl;
188 return NNFW_STATUS_ERROR;
191 _tracing_ctx = std::make_unique<onert::util::TracingCtx>(_subgraphs.get());
193 _compiler = std::make_unique<onert::compiler::Compiler>(_subgraphs, _tracing_ctx.get());
195 _state = State::MODEL_LOADED;
196 return NNFW_STATUS_NO_ERROR;
199 NNFW_STATUS nnfw_session::load_model_from_modelfile(const char *model_file_path)
201 if (!isStateInitialized())
202 return NNFW_STATUS_INVALID_STATE;
204 if (!model_file_path)
206 std::cerr << "Model file path is null." << std::endl;
207 return NNFW_STATUS_UNEXPECTED_NULL;
210 std::string filename{model_file_path};
211 if (filename.size() < 8) // .tflite or .circle
213 std::cerr << "Invalid model file path." << std::endl;
214 return NNFW_STATUS_ERROR;
217 std::string model_type = filename.substr(filename.size() - 7, 7);
221 if (model_type == ".tflite")
223 _subgraphs = onert::tflite_loader::loadModel(filename.c_str());
225 else if (model_type == ".circle")
227 _subgraphs = onert::circle_loader::loadModel(filename.c_str());
231 std::cerr << "Unsupported model type" << std::endl;
232 return NNFW_STATUS_ERROR;
235 catch (const std::exception &e)
237 std::cerr << "Error during model loading : " << e.what() << std::endl;
238 return NNFW_STATUS_ERROR;
241 _tracing_ctx = std::make_unique<onert::util::TracingCtx>(_subgraphs.get());
243 _compiler = std::make_unique<onert::compiler::Compiler>(_subgraphs, _tracing_ctx.get());
245 _state = State::MODEL_LOADED;
246 return NNFW_STATUS_NO_ERROR;
249 NNFW_STATUS nnfw_session::load_model_from_nnpackage(const char *package_dir)
251 if (!isStateInitialized())
252 return NNFW_STATUS_INVALID_STATE;
256 std::cerr << "package_dir is null." << std::endl;
257 return NNFW_STATUS_UNEXPECTED_NULL;
260 if (!null_terminating(package_dir, MAX_PATH_LENGTH))
262 std::cerr << "nnpackage path is too long" << std::endl;
263 return NNFW_STATUS_ERROR;
266 // TODO : add support for zipped package file load
268 if (!(dir = opendir(package_dir)))
270 std::cerr << "invalid nnpackge directory: " << package_dir << std::endl;
271 return NNFW_STATUS_ERROR;
277 std::string manifest_file_name(package_dir);
278 manifest_file_name += "/metadata/MANIFEST";
279 std::ifstream mfs(manifest_file_name);
281 // extract the filename of the first(index 0) model
282 // e.g. In MANIFEST file, { "models" : [ "firstmodel.tflite", "2nd.tflite" ] }
285 const Json::Value &models = root["models"];
286 const Json::Value &model_types = root["model-types"];
287 const Json::Value &configs = root["configs"];
289 if (!configs.empty() && !configs[0].empty())
291 auto filepath = package_dir + std::string("/metadata/") + configs[0].asCString();
293 CfgKeyValues keyValues;
294 if (loadConfigure(filepath, keyValues))
296 setConfigKeyValues(keyValues);
300 auto model_file_path = package_dir + std::string("/") + models[0].asString(); // first model
301 auto model_type = model_types[0].asString(); // first model's type
302 if (model_type == "tflite")
304 _subgraphs = onert::tflite_loader::loadModel(model_file_path.c_str());
306 else if (model_type == "circle")
308 _subgraphs = onert::circle_loader::loadModel(model_file_path.c_str());
312 std::cerr << "Unsupported model type in MANIFEST" << std::endl;
313 return NNFW_STATUS_ERROR;
315 _subgraphs->primary()->bindKernelBuilder(_kernel_registry->getBuilder());
317 catch (const std::exception &e)
319 std::cerr << "Error during model loading : " << e.what() << std::endl;
320 return NNFW_STATUS_ERROR;
323 _tracing_ctx = std::make_unique<onert::util::TracingCtx>(_subgraphs.get());
325 _compiler = std::make_unique<onert::compiler::Compiler>(_subgraphs, _tracing_ctx.get());
327 _state = State::MODEL_LOADED;
328 return NNFW_STATUS_NO_ERROR;
331 NNFW_STATUS nnfw_session::prepare()
333 // NOTE. If users want to run prepare() more than one time, this could be removed.
334 if (!isStateModelLoaded())
336 std::cerr << "Error during model prepare : ";
337 if (isStateInitialized())
339 std::cerr << "prepare should be run once";
343 std::cerr << "invalid state";
345 std::cerr << std::endl;
346 return NNFW_STATUS_INVALID_STATE;
349 if (!_subgraphs || !primary_subgraph() || primary_subgraph()->isBuildingPhase())
351 std::cerr << "Error during model prepare : "
352 << "prepare should be run after load_model" << std::endl;
353 return NNFW_STATUS_ERROR;
359 std::shared_ptr<onert::exec::ExecutorMap> executors = _compiler->compile();
360 _execution = std::make_unique<onert::exec::Execution>(executors);
362 catch (const std::exception &e)
364 std::cerr << "Error during model prepare : " << e.what() << std::endl;
365 return NNFW_STATUS_ERROR;
368 _state = State::PREPARED;
369 return NNFW_STATUS_NO_ERROR;
372 NNFW_STATUS nnfw_session::run()
374 if (!isStatePreparedOrFinishedRun())
376 std::cerr << "Error during nnfw_session::run : "
377 << "run should be run after prepare" << std::endl;
378 return NNFW_STATUS_INVALID_STATE;
383 _execution->execute();
385 catch (const onert::InsufficientBufferSizeException &e)
387 // Currently insufficient buffer always means output buffer.
388 std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl;
389 return NNFW_STATUS_INSUFFICIENT_OUTPUT_SIZE;
391 catch (const std::exception &e)
393 std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl;
394 return NNFW_STATUS_ERROR;
397 _state = State::FINISHED_RUN;
398 return NNFW_STATUS_NO_ERROR;
401 NNFW_STATUS nnfw_session::run_async()
403 if (!isStatePreparedOrFinishedRun())
405 std::cerr << "Error during nnfw_session::run_async : "
406 << "run_async should be run after prepare" << std::endl;
407 return NNFW_STATUS_INVALID_STATE;
410 _execution->startExecute();
412 _state = State::RUNNING;
413 return NNFW_STATUS_NO_ERROR;
416 NNFW_STATUS nnfw_session::await()
418 if (!isStateRunning())
420 std::cerr << "Error during nnfw_session::run_await : "
421 << "run_await should be run after run_async" << std::endl;
422 return NNFW_STATUS_ERROR;
425 _execution->waitFinish();
427 _state = State::FINISHED_RUN;
428 return NNFW_STATUS_NO_ERROR;
431 NNFW_STATUS nnfw_session::set_input(uint32_t index, NNFW_TYPE /*type*/, const void *buffer,
434 if (!isStatePreparedOrFinishedRun())
436 std::cerr << "Error during nnfw_session::set_input : invalid state" << std::endl;
437 return NNFW_STATUS_INVALID_STATE;
440 if (!buffer && length != 0)
443 << "Error during nnfw_session::set_input : given buffer is NULL but the length is not 0"
445 return NNFW_STATUS_ERROR;
450 _execution->setInput(onert::ir::IOIndex(index), buffer, length);
452 catch (const std::exception &e)
454 std::cerr << "Error during nnfw_session::set_input : " << e.what() << std::endl;
455 return NNFW_STATUS_ERROR;
457 return NNFW_STATUS_NO_ERROR;
460 NNFW_STATUS nnfw_session::set_output(uint32_t index, NNFW_TYPE /*type*/, void *buffer,
463 if (!isStatePreparedOrFinishedRun())
465 std::cerr << "Error during nnfw_session::set_output : invalid state" << std::endl;
466 return NNFW_STATUS_INVALID_STATE;
469 if (!buffer && length != 0)
472 << "Error during nnfw_session::set_output : given buffer is NULL but the length is not 0"
474 return NNFW_STATUS_ERROR;
479 _execution->setOutput(onert::ir::IOIndex(index), buffer, length);
481 catch (const std::exception &e)
483 std::cerr << "Error during nnfw_session::set_output : " << e.what() << std::endl;
484 return NNFW_STATUS_ERROR;
486 return NNFW_STATUS_NO_ERROR;
489 NNFW_STATUS nnfw_session::input_size(uint32_t *number)
491 if (isStateInitialized()) // Model is not loaded
492 return NNFW_STATUS_INVALID_STATE;
496 if (number == nullptr)
498 std::cerr << "Error during nnfw_session::input_size, number is null pointer." << std::endl;
499 return NNFW_STATUS_UNEXPECTED_NULL;
501 *number = primary_subgraph()->getInputs().size();
503 catch (const std::exception &e)
505 std::cerr << "Error during nnfw_session::input_size : " << e.what() << std::endl;
506 return NNFW_STATUS_ERROR;
508 return NNFW_STATUS_NO_ERROR;
511 NNFW_STATUS nnfw_session::output_size(uint32_t *number)
513 if (isStateInitialized()) // Model is not loaded
514 return NNFW_STATUS_INVALID_STATE;
518 if (number == nullptr)
520 std::cerr << "Error during nnfw_session::output_size, number is null pointer." << std::endl;
521 return NNFW_STATUS_UNEXPECTED_NULL;
523 *number = primary_subgraph()->getOutputs().size();
525 catch (const std::exception &e)
527 std::cerr << "Error during nnfw_session::output_size" << e.what() << std::endl;
528 return NNFW_STATUS_ERROR;
530 return NNFW_STATUS_NO_ERROR;
533 NNFW_STATUS nnfw_session::set_input_layout(uint32_t index, NNFW_LAYOUT layout)
537 if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST &&
538 layout != NNFW_LAYOUT_CHANNELS_LAST)
540 std::cerr << "Error during nnfw_session::set_input_layout, not supported layout" << std::endl;
541 return NNFW_STATUS_ERROR;
543 _execution->setInputLayout(onert::ir::IOIndex(index), convertLayout(layout));
545 catch (const std::exception &e)
547 std::cerr << "Error during nnfw_session::set_input_layout : " << e.what() << std::endl;
548 return NNFW_STATUS_ERROR;
550 return NNFW_STATUS_NO_ERROR;
553 NNFW_STATUS nnfw_session::set_output_layout(uint32_t index, NNFW_LAYOUT layout)
557 if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST &&
558 layout != NNFW_LAYOUT_CHANNELS_LAST)
560 std::cerr << "Error during nnfw_session::set_output_layout, not supported layout"
562 return NNFW_STATUS_ERROR;
564 _execution->setOutputLayout(onert::ir::IOIndex(index), convertLayout(layout));
566 catch (const std::exception &e)
568 std::cerr << "Error during nnfw_session::set_output_layout : " << e.what() << std::endl;
569 return NNFW_STATUS_ERROR;
571 return NNFW_STATUS_NO_ERROR;
574 static NNFW_TYPE datatype_to_nnfw_dtype(onert::ir::DataType dt)
576 using onert::ir::DataType;
579 case DataType::FLOAT32:
580 return NNFW_TYPE_TENSOR_FLOAT32;
581 case DataType::INT32:
582 return NNFW_TYPE_TENSOR_INT32;
583 case DataType::QUANT_UINT8_ASYMM:
584 return NNFW_TYPE_TENSOR_QUANT8_ASYMM;
585 case DataType::BOOL8:
586 return NNFW_TYPE_TENSOR_BOOL;
587 case DataType::UINT8:
588 return NNFW_TYPE_TENSOR_UINT8;
589 case DataType::INT64:
590 return NNFW_TYPE_TENSOR_INT64;
591 case DataType::QUANT_INT8_ASYMM:
592 return NNFW_TYPE_TENSOR_QUANT8_ASYMM_SIGNED;
593 case DataType::UINT32:
594 case DataType::QUANT_INT8_SYMM:
596 throw std::runtime_error("Error: Model has type that runtime API does not support.");
600 NNFW_STATUS nnfw_session::apply_tensorinfo(uint32_t index, nnfw_tensorinfo ti)
604 if (isStateInitialized())
606 std::cerr << "Error during set_input_tensorinfo : should be run after load_model"
608 return NNFW_STATUS_INVALID_STATE;
611 if (ti.rank <= 0 || ti.rank > NNFW_MAX_RANK)
613 std::cerr << "unsupported rank: " << ti.rank << std::endl;
614 return NNFW_STATUS_ERROR;
617 for (int32_t i = 0; i < ti.rank; ++i)
621 std::cerr << "dim must be positive integer but was " << ti.dims[i] << std::endl;
622 return NNFW_STATUS_ERROR;
627 onert::ir::Shape new_shape(ti.rank);
628 for (int32_t i = 0; i < ti.rank; i++)
629 new_shape.dim(i) = ti.dims[i];
631 if (!isStatePreparedOrFinishedRun())
633 // In this case, if we apply input shape in primary_subgraph, it will propagate after
634 // compilation and excution
635 auto ind = primary_subgraph()->getInputs().at(index);
636 auto &input = primary_subgraph()->operands().at(ind);
638 // overwrite input shape with the shape from ti
639 input.info().shape(new_shape);
641 else // when called after nnfw_session::prepare()
643 _execution->changeInputShape(onert::ir::IOIndex(index), new_shape);
646 return NNFW_STATUS_NO_ERROR;
649 NNFW_STATUS nnfw_session::set_input_tensorinfo(uint32_t index, const nnfw_tensorinfo *ti)
651 nnfw_tensorinfo ti_copy = *ti;
652 return apply_tensorinfo(index, ti_copy);
655 NNFW_STATUS nnfw_session::input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti)
657 if (isStateInitialized())
658 return NNFW_STATUS_INVALID_STATE;
664 std::cerr << "Error during nnfw_session::input_tensorinfo, tensorinfo is null pointer."
666 return NNFW_STATUS_UNEXPECTED_NULL;
668 if (index >= primary_subgraph()->getInputs().size())
670 std::cerr << "Error during nnfw_session::input_tensorinfo, index is out of range."
672 return NNFW_STATUS_ERROR;
674 auto opidx = primary_subgraph()->getInputs().at(index);
675 auto shape = primary_subgraph()->operands().at(opidx).shape();
676 if (isStatePreparedOrFinishedRun())
677 shape = _execution->getInputShape(onert::ir::IOIndex{index});
678 ti->rank = shape.rank();
679 for (int j = 0; j < ti->rank; ++j)
681 ti->dims[j] = shape.dim(j);
683 ti->dtype = datatype_to_nnfw_dtype(primary_subgraph()->operands().at(opidx).typeInfo().type());
685 catch (const std::exception &e)
687 std::cerr << "Error during nnfw_session::input_tensorinfo : " << e.what() << std::endl;
688 return NNFW_STATUS_ERROR;
690 return NNFW_STATUS_NO_ERROR;
693 NNFW_STATUS nnfw_session::output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti)
695 if (isStateInitialized())
696 return NNFW_STATUS_INVALID_STATE;
700 std::cerr << "Error during nnfw_session::output_tensorinfo, tensorinfo is null pointer."
702 return NNFW_STATUS_UNEXPECTED_NULL;
705 if (index >= primary_subgraph()->getOutputs().size())
707 std::cerr << "Error during nnfw_session::output_tensorinfo, index is out of range."
709 return NNFW_STATUS_ERROR;
714 auto opidx = primary_subgraph()->getOutputs().at(index);
715 auto shape = primary_subgraph()->operands().at(opidx).shape();
716 // If it is called after `nnfw_run` then get the shape from Execution, not from the graph
717 if (isStateFinishedRun())
718 shape = _execution->getOutputShape(onert::ir::IOIndex{index});
719 ti->rank = shape.rank();
720 for (int j = 0; j < ti->rank; ++j)
722 ti->dims[j] = shape.dim(j);
724 ti->dtype = datatype_to_nnfw_dtype(primary_subgraph()->operands().at(opidx).typeInfo().type());
726 catch (const std::exception &e)
728 std::cerr << "Error during nnfw_session::output_tensorinfo : " << e.what() << std::endl;
729 return NNFW_STATUS_ERROR;
732 return NNFW_STATUS_NO_ERROR;
734 NNFW_STATUS nnfw_session::register_custom_operation(const std::string &id,
735 nnfw_custom_eval eval_func)
737 _kernel_registry->registerKernel(id, eval_func);
738 return NNFW_STATUS_NO_ERROR;
741 static std::string get_op_backend_string(std::string op)
743 #define MAP_MACRO(CircleName, OneRTName) {#CircleName, #OneRTName},
745 static std::unordered_map<std::string, std::string> operation_map = {
751 auto n = operation_map.find(op);
753 if (n == operation_map.end())
755 // this return value is handled by a caller to return error code
756 return std::string("");
764 NNFW_STATUS nnfw_session::set_available_backends(const char *backends)
766 if (!isStateModelLoaded())
767 return NNFW_STATUS_INVALID_STATE;
772 return NNFW_STATUS_UNEXPECTED_NULL;
773 if (null_terminating(backends, MAX_BACKEND_NAME_LENGTH) == false)
774 return NNFW_STATUS_ERROR;
776 auto &options = _compiler->options();
778 using namespace onert::util;
780 options.backend_list = nnfw::misc::split(std::string{backends}, ';');
782 catch (const std::exception &e)
784 std::cerr << "Error during nnfw_session::set_available_backends : " << e.what() << std::endl;
785 return NNFW_STATUS_ERROR;
787 return NNFW_STATUS_NO_ERROR;
790 NNFW_STATUS nnfw_session::set_op_backend(const char *op, const char *backend)
792 if (!isStateModelLoaded())
793 return NNFW_STATUS_INVALID_STATE;
798 return NNFW_STATUS_UNEXPECTED_NULL;
799 if (!null_terminating(op, MAX_OP_NAME_LENGTH) ||
800 !null_terminating(backend, MAX_BACKEND_NAME_LENGTH))
801 return NNFW_STATUS_ERROR;
803 auto key = get_op_backend_string(op);
807 return NNFW_STATUS_ERROR;
810 auto &opcode_to_backend = _compiler->options().manual_scheduler_options.opcode_to_backend;
811 opcode_to_backend.emplace(onert::ir::toOpCode(key), backend);
813 catch (const std::exception &e)
815 std::cerr << "Error during nnfw_session::set_op_backend : " << e.what() << std::endl;
816 return NNFW_STATUS_ERROR;
818 return NNFW_STATUS_NO_ERROR;
821 NNFW_STATUS nnfw_session::set_config(const char *key, const char *value)
823 if (!isStateModelLoaded())
824 return NNFW_STATUS_INVALID_STATE;
827 return NNFW_STATUS_UNEXPECTED_NULL;
829 auto &options = _compiler->options();
831 using namespace onert::util;
833 const std::string skey = key;
835 if (skey == config::TRACE_FILEPATH)
837 options.trace_filepath = value;
839 else if (skey == config::GRAPH_DOT_DUMP)
841 options.graph_dump_level = toInt(value);
843 else if (skey == config::OP_SEQ_MAX_NODE)
845 options.op_seq_max_node = toInt(value);
847 else if (skey == config::EXECUTOR)
849 options.executor = value;
851 else if (skey == config::OP_BACKEND_ALLOPS)
853 options.manual_scheduler_options.backend_for_all = value;
855 else if (skey == config::USE_SCHEDULER)
857 options.he_scheduler = toBool(value);
859 else if (skey == config::PROFILING_MODE)
861 options.he_profiling_mode = toBool(value);
863 else if (skey == config::DISABLE_COMPILE)
865 options.disable_compile = toBool(value);
869 return NNFW_STATUS_ERROR;
871 return NNFW_STATUS_NO_ERROR;
874 onert::ir::Graph *nnfw_session::primary_subgraph()
879 return _subgraphs->primary().get();
884 // TODO Remove const_cast
885 // We assumed the graph will not change after compilation, but shape could change
886 return const_cast<onert::ir::Graph *>(&_execution->primary_subgraph());
890 NNFW_STATUS nnfw_session::get_config(const char *key, char *value, size_t value_size)
892 if (!isStateModelLoaded())
893 return NNFW_STATUS_INVALID_STATE;
896 return NNFW_STATUS_UNEXPECTED_NULL;
898 auto &options = _compiler->options();
900 auto check_boundary = [](size_t dest_size, std::string &src) {
901 if (dest_size < src.length() + 1 /* for '\0' */)
903 std::cerr << "buffer is small to copy config value." << std::endl;
909 const std::string skey = key;
911 if (skey == onert::util::config::BACKENDS)
913 if (options.backend_list.size() == 0)
914 return NNFW_STATUS_NO_ERROR; // no setting backend is not an error of get_config_str()
916 auto str = nnfw::misc::join(options.backend_list.begin(), options.backend_list.end(), ";");
918 if (!check_boundary(value_size, str))
919 return NNFW_STATUS_ERROR;
921 strncpy(value, str.c_str(), value_size);
923 else if (skey == onert::util::config::EXECUTOR)
925 if (!check_boundary(value_size, options.executor))
926 return NNFW_STATUS_ERROR;
928 strncpy(value, options.executor.c_str(), options.executor.length());
932 return NNFW_STATUS_ERROR;
935 return NNFW_STATUS_NO_ERROR;
938 bool nnfw_session::isStateInitialized()
940 if (_state == State::INITIALIZED)
953 bool nnfw_session::isStateModelLoaded()
955 if (_state == State::MODEL_LOADED)
960 assert(!primary_subgraph()->isBuildingPhase());
969 bool nnfw_session::isStatePrepared()
971 if (_state == State::PREPARED)
976 assert(!primary_subgraph()->isBuildingPhase());
985 bool nnfw_session::isStateRunning()
987 if (_state == State::RUNNING)
992 assert(!primary_subgraph()->isBuildingPhase());
998 bool nnfw_session::isStateFinishedRun()
1000 if (_state == State::FINISHED_RUN)
1002 assert(!_subgraphs);
1005 assert(!primary_subgraph()->isBuildingPhase());
1014 bool nnfw_session::isStatePreparedOrFinishedRun()
1016 return isStatePrepared() || isStateFinishedRun();
1019 NNFW_STATUS nnfw_session::input_tensorindex(const char *tensorname, uint32_t *index)
1021 return getTensorIndexImpl(*primary_subgraph(), tensorname, index, true);
1024 NNFW_STATUS nnfw_session::output_tensorindex(const char *tensorname, uint32_t *index)
1026 return getTensorIndexImpl(*primary_subgraph(), tensorname, index, false);