/* * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ * * 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. */ //#define ONNX_ML #include #include #include #include using ::google::protobuf::Message; #include #include #include #include #include #include #include #include "onnx/onnx-ml.proto3.pb.h" #include "onnxrt_EP.h" using namespace std; using namespace onnx; TIDL_OnnxrtEPInferOptions * data_ = new TIDL_OnnxrtEPInferOptions; void onnxrt_printf(int32_t debugLevel, char * format, ...) { va_list args; if (debugLevel == 1) { (void)va_start(args, format); (void)vprintf(format, args); va_end(args); } } template T LoadSymbol(void *lib, const char* symbol) { T sym = reinterpret_cast(dlsym(lib, symbol)); assert(sym); return sym; } static bool check_isdir(const char *path) { const char *real = realpath(path, NULL); if(!real) return false; struct stat st; int res = stat(real, &st); if(res) return false; bool ret = false; if ((st.st_mode & S_IFMT) == S_IFDIR) { ret = true; free(const_cast(real)); } return ret; } extern "C" { bool TIDL_populateOptions(std::vector> interface_options) { data_->infer_ops.lib = dlopen("libvx_tidl_rt.so", RTLD_NOW | RTLD_GLOBAL); if(! data_->infer_ops.lib) { printf("Error - %s \n", dlerror()); } data_->infer_ops.TIDLRT_create = LoadSymbolinfer_ops.TIDLRT_create)> (data_->infer_ops.lib, "TIDLRT_create"); data_->infer_ops.TIDLRT_delete = LoadSymbolinfer_ops.TIDLRT_delete)> (data_->infer_ops.lib, "TIDLRT_delete"); data_->infer_ops.TIDLRT_invoke = LoadSymbolinfer_ops.TIDLRT_invoke)> (data_->infer_ops.lib, "TIDLRT_invoke"); data_->infer_ops.TIDLRT_deactivate = LoadSymbolinfer_ops.TIDLRT_deactivate)>(data_->infer_ops.lib, "TIDLRT_deactivate"); data_->infer_ops.TIDLRT_setParamsDefault = LoadSymbolinfer_ops.TIDLRT_setParamsDefault)>(data_->infer_ops.lib, "TIDLRT_setParamsDefault"); data_->infer_ops.TIDLRT_setTensorDefault = LoadSymbolinfer_ops.TIDLRT_setTensorDefault)>(data_->infer_ops.lib, "TIDLRT_setTensorDefault"); data_->infer_ops.TIDLRT_getDdrStats = LoadSymbolinfer_ops.TIDLRT_getDdrStats)>(data_->infer_ops.lib, "TIDLRT_getDdrStats"); TIDL_OnnxrtEPInferOptions * options = data_; for(auto option : interface_options) { auto key = option.first; auto value = option.second; if (!strcmp("debug_level", key.c_str())) { std::stringstream(value) >> options->m_debug_level; // TODO: any invalid values? like negative, or beyond supported range? } if (!strcmp("artifacts_folder", key.c_str())) { options->m_artifacts_folder = value; if(!check_isdir(options->m_artifacts_folder.c_str())) { delete options; printf("ERROR : artifacts_folder not a directory"); return false; } } } if (options->m_artifacts_folder.empty()) { delete options; printf("ERROR : artifacts_folder must be provided"); return false; } onnxrt_printf(data_->m_debug_level, "artifacts_folder = %s \n", data_->m_artifacts_folder.c_str()); onnxrt_printf(data_->m_debug_level, "debug_level = %d \n", data_->m_debug_level); return true; } } //extern "C" int32_t IsNodeSupportedByTIDL(GraphProto& onnxGraph, FILE *fp, int32_t nodeIx, int32_t opsetVersion) { int idx; fseek(fp, 0, SEEK_SET); while (!feof(fp)) { fscanf(fp, "%d\n", &idx); if(nodeIx == idx) { return true; } } return false; } std::vector, std::pair, std::vector>>> getSubgraphInfo(GraphProto& onnxGraph, std::vector> suportedNodeGroups) { std::vector nodeOutputs; std::vector nodeInputs; std::pair, std::vector> nodeInputsOutputs; std::vector, std::pair, std::vector>>> info; //vector( (subgraph1, (inputs_1, outputs_1)), (subgraph2, (inputs_2, outputs_2)) ) for(int i = 0; i < suportedNodeGroups.size(); i++) { std::vector subgraph = suportedNodeGroups[i]; for(int j = 0; j < subgraph.size(); j++) { for(int l = 0; l < onnxGraph.node(subgraph[j]).input_size(); l++) { for (int k = 0; k < onnxGraph.value_info_size(); k++) { if((strcmp(onnxGraph.value_info(k).name().c_str(), onnxGraph.node(subgraph[j]).input(l).c_str()) == 0)) { nodeInputs.push_back(onnxGraph.value_info(k).name()); } } } } for(int j = 0; j < subgraph.size(); j++) { for(int l = 0; l < onnxGraph.node(subgraph[j]).output_size(); l++) { nodeOutputs.push_back(onnxGraph.node(subgraph[j]).output(l)); } } #if 0 std::sort(nodeInputs.begin(), nodeInputs.end()); nodeInputs.erase(std::unique(nodeInputs.begin(), nodeInputs.end()), nodeInputs.end()); std::sort(nodeOutputs.begin(), nodeOutputs.end()); nodeOutputs.erase(std::unique(nodeOutputs.begin(), nodeOutputs.end()), nodeOutputs.end()); bool match; for(int i = 0; i < nodeInputs.size(); i++) { match = false; for(int j = 0; j < nodeOutputs.size(); j++) { if(nodeInputs[i].compare(nodeOutputs[j]) == 0) { match = true; auto itr = std::find(nodeInputs.begin(), nodeInputs.end(), nodeInputs[i]); if (itr != nodeInputs.end()) nodeInputs.erase(itr); itr = std::find(nodeOutputs.begin(), nodeOutputs.end(), nodeOutputs[j]); if (itr != nodeOutputs.end()) nodeOutputs.erase(itr); j--; } } if(match) { i--; } } #endif nodeInputsOutputs = std::make_pair(nodeInputs, nodeOutputs); info.push_back(std::make_pair(subgraph, nodeInputsOutputs)); #if 0 printf("Subgraph inputs \n"); for(int i = 0; i < nodeInputs.size(); i++) { printf("%s \n", nodeInputs[i].c_str()); } printf("Subgraph outputs \n"); for(int i = 0; i < nodeOutputs.size(); i++) { printf("%s \n", nodeOutputs[i].c_str()); } #endif nodeInputs.clear(); nodeOutputs.clear(); } #if 0 printf("info.size() = %d \n", info.size()); for(int i = 0; i < info.size(); i++) { printf("**** Subgraph %d *****\n", i); std::vector subgraph = info[i].first; std::vector inputs = info[i].second.first; std::vector outputs = info[i].second.second; for(int j = 0; j < subgraph.size(); j++) printf("%d ", subgraph[j]); printf("\n"); printf("Inputs --- \n"); for(int j = 0; j < inputs.size(); j++) printf("%s \n ", inputs[j].c_str()); printf("Outputs --- \n"); for(int j = 0; j < outputs.size(); j++) printf("%s \n ", outputs[j].c_str()); } #endif return info; } std::vector> optimizeGraphPartition(GraphProto& onnxGraph, std::vector> suportedNodeGroups) { std::vector, std::pair, std::vector>>> info; std::vector subgraph_i, subgraph_j; std::vector inputs_i, inputs_j; std::vector outputs_i, outputs_j; bool canMergeInput, canMergeSubgraph, mergeDone; mergeDone = false; canMergeSubgraph = false; while(mergeDone == false) { info = getSubgraphInfo(onnxGraph, suportedNodeGroups); for(int i = 0; i < info.size(); i++) { canMergeSubgraph = false; subgraph_i = info[i].first; inputs_i = info[i].second.first; outputs_i = info[i].second.second; for(int j = 0; j < info.size(); j++) { if(j == i) continue; canMergeSubgraph = true; subgraph_j = info[j].first; inputs_j = info[j].second.first; outputs_j = info[j].second.second; for(int k = 0; k < inputs_j.size(); k++) { canMergeInput = false; for(int l = 0; l < outputs_i.size(); l++) { if(inputs_j[k].compare(outputs_i[l]) == 0) { canMergeInput = true; continue; } } if(outputs_j.size() == 0) canMergeInput = false; if(canMergeInput == false) { canMergeSubgraph = false; break; } } if(inputs_j.size() == 0) canMergeSubgraph = false; if(canMergeSubgraph) { suportedNodeGroups.clear(); subgraph_i.insert(subgraph_i.end(), subgraph_j.begin(), subgraph_j.end()); info.erase(std::find(info.begin(), info.end(), info[j])); info[i].first = subgraph_i; for(int m = 0; m < info.size(); m++) { suportedNodeGroups.push_back(info[m].first); } break; } } if(canMergeSubgraph) break; } if(canMergeSubgraph == false) { mergeDone = true; } } return suportedNodeGroups; } extern "C" { std::vector> TIDL_getSupportedNodes(std::string& data, int32_t opsetVersion) { int32_t numSuportedNodes = 0; if (data_->m_debug_level) { printf("Parsing ONNX Model \n"); } ModelProto model_proto; model_proto.ParseFromString(data); auto onnxGraph = model_proto.graph(); std::vector> suportedNodeGroups; std::vector nodeGroup; FILE *fp; char fileName[500]; sprintf((char *)fileName, "%s/allowedNode.txt", data_->m_artifacts_folder.c_str()); fp = fopen(fileName, "r"); if(fp == NULL) { printf("Could not open %s for reading...exiting !\n", fileName); } int32_t i, num_subGraphs = 0; for (i = 0; i < onnxGraph.node_size(); i++) { if (IsNodeSupportedByTIDL(onnxGraph, fp, i, opsetVersion)) { nodeGroup.push_back(i); numSuportedNodes++; } else { if(!nodeGroup.empty()) { suportedNodeGroups.push_back(nodeGroup); nodeGroup.clear(); num_subGraphs++; } } } if(!nodeGroup.empty()) { suportedNodeGroups.push_back(nodeGroup); nodeGroup.clear(); num_subGraphs++; } fclose(fp); printf("\nPreliminary subgraphs created = %ld \n", suportedNodeGroups.size()); std::vector> suportedNodeGroupsOptimized = optimizeGraphPartition(onnxGraph, suportedNodeGroups); printf("Final number of subgraphs created are : %ld, - Offloaded Nodes - %d, Total Nodes - %d \n", suportedNodeGroupsOptimized.size(), numSuportedNodes, onnxGraph.node_size()); if(suportedNodeGroupsOptimized.empty()) { return {{}}; } else { return suportedNodeGroupsOptimized; } } int32_t TIDL_isInputConstInGraph(GraphProto& onnGraph, const string name) { int i; for (i = 0; i < onnGraph.initializer_size(); i++) { if ((strcmp(onnGraph.initializer(i).name().c_str(), name.c_str()) == 0)) { return(1); } } for (i = 0; i < onnGraph.node_size(); i++) { if ((strcmp(onnGraph.node(i).output(0).c_str(), name.c_str()) == 0) && (strcmp(onnGraph.node(i).op_type().c_str(), "Constant") == 0)) { return(1); } } return (0); } int32_t TIDL_isInputConst(std::string * string_buf, const string name) { ModelProto model_proto; model_proto.ParseFromString(*string_buf); auto onnxGraph = model_proto.graph(); return (TIDL_isInputConstInGraph(onnxGraph, name)); } } //extern C int32_t onnxProto_PrintProps(GraphProto& onnxGraph) { int32_t i; for (i = 0; i < onnxGraph.node_size(); i++) { printf("%3d, %15s, %d, %d, %s, %s\n", i, onnxGraph.node(i).op_type().c_str(), onnxGraph.node(i).input_size(), onnxGraph.node(i).output_size(), onnxGraph.node(i).input(0).c_str(), onnxGraph.node(i).output(0).c_str()); } return 0; } char* replaceChar(char* string, char c1, char c2, int length) { for (int32_t i = 0; i < length; i++) { if (string[i] == c1) string[i] = c2; } return string; } int32_t tidl_onnxrtFindOnnxOutputNames(GraphProto& onnxGraph, char * outList) { int i, j, k, l; char tensorName[500]; char inTensorName[500]; int outPutSize = 0; int node_idx = 0; for (i = 0; i < onnxGraph.node_size(); i++) { outPutSize = onnxGraph.node(i).output_size(); for (j = 0; j < outPutSize; j++) { int outDataUsed = 0; strcpy((char *)tensorName, onnxGraph.node(i).output(j).c_str()); for (k = 0; k < onnxGraph.node_size(); k++) { for (l = 0; l < onnxGraph.node(k).input_size(); l++) { strcpy((char *)inTensorName, onnxGraph.node(k).input(l).c_str()); if (strcmp(tensorName, inTensorName) == 0) { outDataUsed = 1; break; } } if (outDataUsed) break; } if (outDataUsed == 0) { node_idx = i; strcat(outList, tensorName); //strcat(outList, ","); } } } return (node_idx); } extern "C" { std::vector TIDL_getOutputShape(void * ioBufDescVPtr, int8_t onnxName[]) { sTIDL_IOBufDesc_t *ioBufDescPtr = (sTIDL_IOBufDesc_t *)ioBufDescVPtr; std::vector nchw_shape; for(int i = 0; i < ioBufDescPtr->numOutputBuf; i++) { if(strcmp((char *)ioBufDescPtr->outDataName[i], (char *)onnxName) == 0) { nchw_shape = { 1, ioBufDescPtr->outNumChannels[i], ioBufDescPtr->outHeight[i], ioBufDescPtr->outWidth[i]}; } } if(nchw_shape.size() == 0) { printf("Warning : Couldn't find corresponding ioBuf tensor for onnx tensor with matching name \n"); } return nchw_shape; } int32_t TIDLEP_getSubGraphStats(OnnxTIDLSubGraphParams * state_subGraph, char **node_name, void **node_data) { sTIDLRT_PerfStats_t * stats = (sTIDLRT_PerfStats_t*)state_subGraph->stats; std::vector *v = new std::vector(); v->push_back(uint64_t(stats->cpIn_time_start)); v->push_back(uint64_t(stats->cpIn_time_end)); v->push_back(uint64_t(stats->proc_time_start)); v->push_back(uint64_t(stats->proc_time_end)); v->push_back(uint64_t(stats->cpOut_time_start)); v->push_back(uint64_t(stats->cpOut_time_end)); *node_data = static_cast(v); *node_name = const_cast(state_subGraph->subGraphName_); return 0; } void TIDL_computeImportFunc(OnnxTIDLSubGraphParams * state_subGraph, std::string * string_buf,int32_t opSetVersion) { printf("Error : This Fucntion call is not expected for infernce flow \n"); } } //extern C int32_t TIDLRT_ReadBinFromFile(const char * fileName, void * addr, int32_t size) { FILE * fptr = NULL; fptr = fopen((const char *)fileName, "rb"); int status = 0; if(fptr) { status = fread(addr, size, 1, fptr); fclose(fptr); return status; } else { printf("Could not open %s file for reading \n",fileName); } return status; } int32_t tidl_subgraph_rt_create(TIDL_OnnxrtEPInferOptions* options, char* subGraphName, sTIDL_IOBufDesc_t *ioBufDescPtr, OnnxTIDLSubGraphParams * subgraphParams) { //tfldelegate_printf(options->debug_level, "************ in tidl_subgraph_rt_create ************ \n "); int status = 0; sTIDLRT_Params_t prms; FILE *fp_network; FILE *fp_config; char network_file[512]; char config_file[512]; void *handle = NULL; status = data_->infer_ops.TIDLRT_setParamsDefault(&prms); snprintf(network_file, MAX_FILE_PATH, "%s/%s_tidl_net.bin", options->m_artifacts_folder.c_str(), subGraphName); snprintf(config_file, MAX_FILE_PATH, "%s/%s_tidl_io_1.bin", options->m_artifacts_folder.c_str(), subGraphName); fp_network = fopen(&network_file[0], "rb"); if (fp_network == NULL) { printf("Invoke : ERROR: Unable to open network file %s \n", network_file); return -1; } prms.stats = (sTIDLRT_PerfStats_t*)malloc(sizeof(sTIDLRT_PerfStats_t)); fseek(fp_network, 0, SEEK_END); prms.net_capacity = ftell(fp_network); fseek(fp_network, 0, SEEK_SET); fclose(fp_network); prms.netPtr = malloc(prms.net_capacity); prms.TIDLReadBinFromFile = TIDLRT_ReadBinFromFile; status = prms.TIDLReadBinFromFile(&network_file[0], prms.netPtr, prms.net_capacity); fp_config = fopen(&config_file[0], "rb"); if (fp_config == NULL) { printf("Invoke : ERROR: Unable to open IO config file %s \n", config_file); return -1; } fseek(fp_config, 0, SEEK_END); prms.io_capacity = ftell(fp_config); fseek(fp_config, 0, SEEK_SET); fclose(fp_config); prms.ioBufDescPtr = malloc(prms.io_capacity); status = prms.TIDLReadBinFromFile(&config_file[0], prms.ioBufDescPtr, prms.io_capacity); if(options->m_debug_level >= 2) { prms.traceLogLevel = options->m_debug_level; prms.traceWriteLevel = 3; } status = data_->infer_ops.TIDLRT_create(&prms, &handle); sTIDL_IOBufDesc_t *ioBufDesc = (sTIDL_IOBufDesc_t *)prms.ioBufDescPtr; memcpy(ioBufDescPtr, ioBufDesc, sizeof(sTIDL_IOBufDesc_t)); subgraphParams->rtInList = (void *)malloc(ioBufDesc->numInputBuf * sizeof(sTIDLRT_Tensor_t)); subgraphParams->rtOutList = (void *)malloc(ioBufDesc->numOutputBuf * sizeof(sTIDLRT_Tensor_t)); subgraphParams->rtHandle = handle; subgraphParams->stats = prms.stats; return status; } int32_t tidl_subgraph_rt_delete(TIDL_OnnxrtEPInferOptions* options, OnnxTIDLSubGraphParams * subgraphParams) { //tfldelegate_printf(options->debug_level, "************ in tidl_subgraph_rt_delete ************ \n "); int status = 0; if(subgraphParams->rtHandle) { status = data_->infer_ops.TIDLRT_deactivate(subgraphParams->rtHandle); status = data_->infer_ops.TIDLRT_delete(subgraphParams->rtHandle); } free(subgraphParams->rtInList); free(subgraphParams->rtOutList); return status; } int32_t tidl_subgraph_rt_invoke(TIDL_OnnxrtEPInferOptions* options, sTIDL_IOBufDesc_t *ioBufDescPtr, OnnxTIDLSubGraphParams * subgraphParams) { int status = 0; int j = 0; onnxRtParams_t * onnxRtParams = &subgraphParams->onnxRtParams; void *handle = subgraphParams->rtHandle; sTIDLRT_PerfStats_t *stats = (sTIDLRT_PerfStats_t *)subgraphParams->stats; sTIDLRT_Tensor_t *in[128]; sTIDLRT_Tensor_t *out[128]; sTIDLRT_Tensor_t *ins; sTIDLRT_Tensor_t *outs; ins = (sTIDLRT_Tensor_t *)subgraphParams->rtInList; outs = (sTIDLRT_Tensor_t *)subgraphParams->rtOutList; if ((ins == NULL) || (outs == NULL)) { printf("Invoke : ERROR: Unable to allocate memory for TIDL RT in[] out [] tensor struct\n"); return -1; } else { int32_t currInIdx = 0; /* Input tesnsors property set up */ for (j = 0; j < onnxRtParams->numNetInData; j++) { int64_t inElementType = onnxRtParams->inputTensorElementType[currInIdx]; void * input = onnxRtParams->inputTensorData[currInIdx]; if (inElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8) { in[j] = &(ins[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(in[j]); in[j]->ptr = (uint8_t *)(input); in[j]->zeroPoint = 0; //quantization->zero_point->data[0]; in[j]->elementType = TIDLRT_Uint8; in[j]->scale = 1.0; //1 / quantization->scale->data[0]; in[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)in[j]->name, (char *)onnxRtParams->inDataNames[j]); } else if (inElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32) { in[j] = &(ins[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(in[j]); in[j]->ptr = (int32_t *)(input); in[j]->zeroPoint = 0; in[j]->elementType = TIDLRT_Int32; in[j]->scale = 1.0; in[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)in[j]->name, (char *)onnxRtParams->inDataNames[j]); } else if (inElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) { in[j] = &(ins[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(in[j]); in[j]->ptr = (int64_t *)(input); in[j]->zeroPoint = 0; in[j]->elementType = TIDLRT_Int64; in[j]->scale = 1.0; in[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)in[j]->name, (char *)onnxRtParams->inDataNames[j]); } else if (inElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { in[j] = &(ins[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(in[j]); in[j]->ptr = (float *)(input); in[j]->zeroPoint = 0; in[j]->elementType = TIDLRT_Float32; in[j]->scale = 1.0; in[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)in[j]->name, (char *)onnxRtParams->inDataNames[j]); } else { printf("Invoke : Unsupported input Tensor element type %ld \n", inElementType); } currInIdx++; } /* Output tesnsors property set up */ for (j = 0; j < onnxRtParams->numNetOutData; j++) { void* output = onnxRtParams->outputTensorData[j]; int64_t outElementType = onnxRtParams->outputTensorElementType[j]; if (outElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8) { out[j] = &(outs[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(out[j]); out[j]->ptr = (uint8_t *)(output); out[j]->zeroPoint = 0; //quantization->zero_point->data[0]; out[j]->elementType = TIDLRT_Uint8; out[j]->scale = 1.0; //1 / quantization->scale->data[0]; out[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)out[j]->name, (char *)onnxRtParams->outDataNames[j]); } else if (outElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32) { out[j] = &(outs[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(out[j]); out[j]->ptr = (int32_t *)(output); out[j]->zeroPoint = 0; out[j]->elementType = TIDLRT_Int32; out[j]->scale = 1.0; out[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)out[j]->name, (char *)onnxRtParams->outDataNames[j]); } else if (outElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) { out[j] = &(outs[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(out[j]); out[j]->ptr = (int64_t *)(output); out[j]->zeroPoint = 0; out[j]->elementType = TIDLRT_Int64; out[j]->scale = 1.0; out[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)out[j]->name, (char *)onnxRtParams->outDataNames[j]); } else if (outElementType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { out[j] = &(outs[j]); status = data_->infer_ops.TIDLRT_setTensorDefault(out[j]); out[j]->ptr = (float *)(output); out[j]->zeroPoint = 0; out[j]->elementType = TIDLRT_Float32; out[j]->scale = 1.0; out[j]->layout = TIDLRT_LT_NCHW; strcpy((char *)out[j]->name, (char *)onnxRtParams->outDataNames[j]); } else { printf("ERROR : Unsupported output tensor element type %ld \n", outElementType); } } } status = data_->infer_ops.TIDLRT_invoke(handle, in, out); if(options->m_debug_level > 0) { double proc_time = (stats->proc_time_end - stats->proc_time_start) / 1000; double cp_in_time = (stats->cpIn_time_end - stats->cpIn_time_start) / 1000; double cp_out_time = (stats->cpOut_time_end - stats->cpOut_time_start)/ 1000; printf("Sub Graph Stats %f %f %f \n", cp_in_time, proc_time, cp_out_time); } return status; } extern "C" { int32_t TIDLEP_getDdrStats(uint64_t * read, uint64_t * write) { return(data_->infer_ops.TIDLRT_getDdrStats(read, write)); } void TIDL_createStateFunc(OnnxTIDLSubGraphParams * state_subGraph, std::string * string_buf, const std::string node_name) { onnxRtParams_t * onnxRtParams = &state_subGraph->onnxRtParams; state_subGraph->currFrameIdx_ = 0; state_subGraph->subGraphPtr_ = NULL; state_subGraph->string_buf = string_buf; ModelProto model_proto; model_proto.ParseFromString(*string_buf); auto onnxGraph = model_proto.graph(); if(data_->m_debug_level) { printf("Compile %s\n", node_name.c_str()); printf("Compiling Sub ONNX Model \n"); onnxProto_PrintProps(onnxGraph); } state_subGraph->ioBuffDesc = (void*)malloc(sizeof(sTIDL_IOBufDesc_t)); assert(state_subGraph->ioBuffDesc); int status = 0; char outDataNamesList[500] = ""; tidl_onnxrtFindOnnxOutputNames(onnxGraph, (char*)outDataNamesList); strcpy((char*)state_subGraph->subGraphName_, (char*)outDataNamesList); strcpy((char*)state_subGraph->subGraphName_, replaceChar((char*)state_subGraph->subGraphName_, '/', '_', strlen((const char*)state_subGraph->subGraphName_))); status = tidl_subgraph_rt_create(data_, state_subGraph->subGraphName_, (sTIDL_IOBufDesc_t*)state_subGraph->ioBuffDesc, state_subGraph); int32_t currIdx = 0; for (int i = 0; i < onnxGraph.input_size(); i++) { if (TIDL_isInputConst(string_buf, onnxGraph.input(i).name())) { continue; } state_subGraph->inputIdx[currIdx++] = i; } state_subGraph->numInputs = currIdx; state_subGraph->numOutputs = onnxGraph.output_size(); for (int i = 0; i < state_subGraph->numInputs; i++) { onnxrt_printf(data_->m_debug_level, "\nInput tensor name - %s \n", onnxGraph.input(state_subGraph->inputIdx[i]).name().c_str()); strcpy((char *)onnxRtParams->inDataNames[i], (char*)onnxGraph.input(state_subGraph->inputIdx[i]).name().c_str()); } for (int i = 0; i < state_subGraph->numOutputs; i++) { onnxrt_printf(data_->m_debug_level, "Output tensor name - %s \n", onnxGraph.output(i).name().c_str()); strcpy((char *)onnxRtParams->outDataNames[i], onnxGraph.output(i).name().c_str()); } onnxrt_printf(data_->m_debug_level, "Compute status : %d \n", status); } void TIDL_computeInvokeFunc(OnnxTIDLSubGraphParams * state_subGraph) { int32_t status; status = tidl_subgraph_rt_invoke(data_, (sTIDL_IOBufDesc_t*)state_subGraph->ioBuffDesc, state_subGraph); //TODO: call subgraph_rt_delete in destructor for infer } } //extern C